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/* buffer var allocations */
31#define indic_category() complex_var_u8_0() /* indic_category_t */
32#define indic_position() complex_var_u8_1() /* indic_position_t */
33
34
35/*
36 * Indic shaper.
37 */
38
39
40#define IN_HALF_BLOCK(u, Base) (((u) & ~0x7Fu) == (Base))
41
42#define IS_DEVA(u) (IN_HALF_BLOCK (u, 0x0900u))
43#define IS_BENG(u) (IN_HALF_BLOCK (u, 0x0980u))
44#define IS_GURU(u) (IN_HALF_BLOCK (u, 0x0A00u))
45#define IS_GUJR(u) (IN_HALF_BLOCK (u, 0x0A80u))
46#define IS_ORYA(u) (IN_HALF_BLOCK (u, 0x0B00u))
47#define IS_TAML(u) (IN_HALF_BLOCK (u, 0x0B80u))
48#define IS_TELU(u) (IN_HALF_BLOCK (u, 0x0C00u))
49#define IS_KNDA(u) (IN_HALF_BLOCK (u, 0x0C80u))
50#define IS_MLYM(u) (IN_HALF_BLOCK (u, 0x0D00u))
51#define IS_SINH(u) (IN_HALF_BLOCK (u, 0x0D80u))
52#define IS_KHMR(u) (IN_HALF_BLOCK (u, 0x1780u))
53
54
55#define MATRA_POS_LEFT(u)       POS_PRE_M
56#define MATRA_POS_RIGHT(u)      ( \
57                                  IS_DEVA(u) ? POS_AFTER_SUB  : \
58                                  IS_BENG(u) ? POS_AFTER_POST : \
59                                  IS_GURU(u) ? POS_AFTER_POST : \
60                                  IS_GUJR(u) ? POS_AFTER_POST : \
61                                  IS_ORYA(u) ? POS_AFTER_POST : \
62                                  IS_TAML(u) ? POS_AFTER_POST : \
63                                  IS_TELU(u) ? (u <= 0x0C42u ? POS_BEFORE_SUB : POS_AFTER_SUB) : \
64                                  IS_KNDA(u) ? (u < 0x0CC3u || u > 0xCD6u ? POS_BEFORE_SUB : POS_AFTER_SUB) : \
65                                  IS_MLYM(u) ? POS_AFTER_POST : \
66                                  IS_SINH(u) ? POS_AFTER_SUB  : \
67                                  IS_KHMR(u) ? POS_AFTER_POST : \
68                                  /*default*/  POS_AFTER_SUB    \
69                                )
70#define MATRA_POS_TOP(u)        ( /* BENG and MLYM don't have top matras. */ \
71                                  IS_DEVA(u) ? POS_AFTER_SUB  : \
72                                  IS_GURU(u) ? POS_AFTER_POST : /* Deviate from spec */ \
73                                  IS_GUJR(u) ? POS_AFTER_SUB  : \
74                                  IS_ORYA(u) ? POS_AFTER_MAIN : \
75                                  IS_TAML(u) ? POS_AFTER_SUB  : \
76                                  IS_TELU(u) ? POS_BEFORE_SUB : \
77                                  IS_KNDA(u) ? POS_BEFORE_SUB : \
78                                  IS_SINH(u) ? POS_AFTER_SUB  : \
79                                  IS_KHMR(u) ? POS_AFTER_POST : \
80                                  /*default*/  POS_AFTER_SUB    \
81                                )
82#define MATRA_POS_BOTTOM(u)     ( \
83                                  IS_DEVA(u) ? POS_AFTER_SUB  : \
84                                  IS_BENG(u) ? POS_AFTER_SUB  : \
85                                  IS_GURU(u) ? POS_AFTER_POST : \
86                                  IS_GUJR(u) ? POS_AFTER_POST : \
87                                  IS_ORYA(u) ? POS_AFTER_SUB  : \
88                                  IS_TAML(u) ? POS_AFTER_POST : \
89                                  IS_TELU(u) ? POS_BEFORE_SUB : \
90                                  IS_KNDA(u) ? POS_BEFORE_SUB : \
91                                  IS_MLYM(u) ? POS_AFTER_POST : \
92                                  IS_SINH(u) ? POS_AFTER_SUB  : \
93                                  IS_KHMR(u) ? POS_AFTER_POST : \
94                                  /*default*/  POS_AFTER_SUB    \
95                                )
96
97static inline indic_position_t
98matra_position (hb_codepoint_t u, indic_position_t side)
99{
100  switch ((int) side)
101  {
102    case POS_PRE_C:     return MATRA_POS_LEFT (u);
103    case POS_POST_C:    return MATRA_POS_RIGHT (u);
104    case POS_ABOVE_C:   return MATRA_POS_TOP (u);
105    case POS_BELOW_C:   return MATRA_POS_BOTTOM (u);
106  };
107  return side;
108}
109
110/* XXX
111 * This is a hack for now.  We should move this data into the main Indic table.
112 * Or completely remove it and just check in the tables.
113 */
114static const hb_codepoint_t ra_chars[] = {
115  0x0930u, /* Devanagari */
116  0x09B0u, /* Bengali */
117  0x09F0u, /* Bengali */
118  0x0A30u, /* Gurmukhi */       /* No Reph */
119  0x0AB0u, /* Gujarati */
120  0x0B30u, /* Oriya */
121  0x0BB0u, /* Tamil */          /* No Reph */
122  0x0C30u, /* Telugu */         /* Reph formed only with ZWJ */
123  0x0CB0u, /* Kannada */
124  0x0D30u, /* Malayalam */      /* No Reph, Logical Repha */
125
126  0x0DBBu, /* Sinhala */                /* Reph formed only with ZWJ */
127
128  0x179Au, /* Khmer */          /* No Reph, Visual Repha */
129};
130
131static inline bool
132is_ra (hb_codepoint_t u)
133{
134  for (unsigned int i = 0; i < ARRAY_LENGTH (ra_chars); i++)
135    if (u == ra_chars[i])
136      return true;
137  return false;
138}
139
140static inline bool
141is_one_of (const hb_glyph_info_t &info, unsigned int flags)
142{
143  /* If it ligated, all bets are off. */
144  if (_hb_glyph_info_ligated (&info)) return false;
145  return !!(FLAG_SAFE (info.indic_category()) & flags);
146}
147
148static inline bool
149is_joiner (const hb_glyph_info_t &info)
150{
151  return is_one_of (info, JOINER_FLAGS);
152}
153
154static inline bool
155is_consonant (const hb_glyph_info_t &info)
156{
157  return is_one_of (info, CONSONANT_FLAGS);
158}
159
160static inline bool
161is_halant_or_coeng (const hb_glyph_info_t &info)
162{
163  return is_one_of (info, HALANT_OR_COENG_FLAGS);
164}
165
166static inline void
167set_indic_properties (hb_glyph_info_t &info)
168{
169  hb_codepoint_t u = info.codepoint;
170  unsigned int type = hb_indic_get_categories (u);
171  indic_category_t cat = (indic_category_t) (type & 0x7Fu);
172  indic_position_t pos = (indic_position_t) (type >> 8);
173
174
175  /*
176   * Re-assign category
177   */
178
179  /* The following act more like the Bindus. */
180  if (unlikely (hb_in_range (u, 0x0953u, 0x0954u)))
181    cat = OT_SM;
182  /* The following act like consonants. */
183  else if (unlikely (hb_in_ranges (u, 0x0A72u, 0x0A73u,
184                                      0x1CF5u, 0x1CF6u)))
185    cat = OT_C;
186  /* TODO: The following should only be allowed after a Visarga.
187   * For now, just treat them like regular tone marks. */
188  else if (unlikely (hb_in_range (u, 0x1CE2u, 0x1CE8u)))
189    cat = OT_A;
190  /* TODO: The following should only be allowed after some of
191   * the nasalization marks, maybe only for U+1CE9..U+1CF1.
192   * For now, just treat them like tone marks. */
193  else if (unlikely (u == 0x1CEDu))
194    cat = OT_A;
195  /* The following take marks in standalone clusters, similar to Avagraha. */
196  else if (unlikely (hb_in_ranges (u, 0xA8F2u, 0xA8F7u,
197                                      0x1CE9u, 0x1CECu,
198                                      0x1CEEu, 0x1CF1u)))
199  {
200    cat = OT_Symbol;
201    ASSERT_STATIC ((int) INDIC_SYLLABIC_CATEGORY_AVAGRAHA == OT_Symbol);
202  }
203  else if (unlikely (u == 0x17C6u)) cat = OT_N; /* Khmer Bindu doesn't like to be repositioned. */
204  else if (unlikely (hb_in_range (u, 0x2010u, 0x2011u)))
205                                    cat = OT_PLACEHOLDER;
206  else if (unlikely (u == 0x25CCu)) cat = OT_DOTTEDCIRCLE;
207
208
209  /*
210   * Re-assign position.
211   */
212
213  if ((FLAG_SAFE (cat) & CONSONANT_FLAGS))
214  {
215    pos = POS_BASE_C;
216    if (is_ra (u))
217      cat = OT_Ra;
218  }
219  else if (cat == OT_M)
220  {
221    pos = matra_position (u, pos);
222  }
223  else if ((FLAG_SAFE (cat) & (FLAG (OT_SM) | FLAG (OT_VD) | FLAG (OT_A) | FLAG (OT_Symbol))))
224  {
225    pos = POS_SMVD;
226  }
227
228  if (unlikely (u == 0x0B01u)) pos = POS_BEFORE_SUB; /* Oriya Bindu is BeforeSub in the spec. */
229
230
231
232  info.indic_category() = cat;
233  info.indic_position() = pos;
234}
235
236/*
237 * Things above this line should ideally be moved to the Indic table itself.
238 */
239
240
241/*
242 * Indic configurations.  Note that we do not want to keep every single script-specific
243 * behavior in these tables necessarily.  This should mainly be used for per-script
244 * properties that are cheaper keeping here, than in the code.  Ie. if, say, one and
245 * only one script has an exception, that one script can be if'ed directly in the code,
246 * instead of adding a new flag in these structs.
247 */
248
249enum base_position_t {
250  BASE_POS_FIRST,
251  BASE_POS_LAST_SINHALA,
252  BASE_POS_LAST
253};
254enum reph_position_t {
255  REPH_POS_AFTER_MAIN  = POS_AFTER_MAIN,
256  REPH_POS_BEFORE_SUB  = POS_BEFORE_SUB,
257  REPH_POS_AFTER_SUB   = POS_AFTER_SUB,
258  REPH_POS_BEFORE_POST = POS_BEFORE_POST,
259  REPH_POS_AFTER_POST  = POS_AFTER_POST,
260  REPH_POS_DONT_CARE   = POS_RA_TO_BECOME_REPH
261};
262enum reph_mode_t {
263  REPH_MODE_IMPLICIT,  /* Reph formed out of initial Ra,H sequence. */
264  REPH_MODE_EXPLICIT,  /* Reph formed out of initial Ra,H,ZWJ sequence. */
265  REPH_MODE_VIS_REPHA, /* Encoded Repha character, no reordering needed. */
266  REPH_MODE_LOG_REPHA  /* Encoded Repha character, needs reordering. */
267};
268enum blwf_mode_t {
269  BLWF_MODE_PRE_AND_POST, /* Below-forms feature applied to pre-base and post-base. */
270  BLWF_MODE_POST_ONLY     /* Below-forms feature applied to post-base only. */
271};
272struct indic_config_t
273{
274  hb_script_t     script;
275  bool            has_old_spec;
276  hb_codepoint_t  virama;
277  base_position_t base_pos;
278  reph_position_t reph_pos;
279  reph_mode_t     reph_mode;
280  blwf_mode_t     blwf_mode;
281};
282
283static const indic_config_t indic_configs[] =
284{
285  /* Default.  Should be first. */
286  {HB_SCRIPT_INVALID,   false,      0,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
287  {HB_SCRIPT_DEVANAGARI,true, 0x094Du,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
288  {HB_SCRIPT_BENGALI,   true, 0x09CDu,BASE_POS_LAST, REPH_POS_AFTER_SUB,  REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
289  {HB_SCRIPT_GURMUKHI,  true, 0x0A4Du,BASE_POS_LAST, REPH_POS_BEFORE_SUB, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
290  {HB_SCRIPT_GUJARATI,  true, 0x0ACDu,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
291  {HB_SCRIPT_ORIYA,     true, 0x0B4Du,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
292  {HB_SCRIPT_TAMIL,     true, 0x0BCDu,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
293  {HB_SCRIPT_TELUGU,    true, 0x0C4Du,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_EXPLICIT, BLWF_MODE_POST_ONLY},
294  {HB_SCRIPT_KANNADA,   true, 0x0CCDu,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_POST_ONLY},
295  {HB_SCRIPT_MALAYALAM, true, 0x0D4Du,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_LOG_REPHA,BLWF_MODE_PRE_AND_POST},
296  {HB_SCRIPT_SINHALA,   false,0x0DCAu,BASE_POS_LAST_SINHALA,
297                                                     REPH_POS_AFTER_MAIN, REPH_MODE_EXPLICIT, BLWF_MODE_PRE_AND_POST},
298  {HB_SCRIPT_KHMER,     false,0x17D2u,BASE_POS_FIRST,REPH_POS_DONT_CARE,  REPH_MODE_VIS_REPHA,BLWF_MODE_PRE_AND_POST},
299};
300
301
302
303/*
304 * Indic shaper.
305 */
306
307struct feature_list_t {
308  hb_tag_t tag;
309  hb_ot_map_feature_flags_t flags;
310};
311
312static const feature_list_t
313indic_features[] =
314{
315  /*
316   * Basic features.
317   * These features are applied in order, one at a time, after initial_reordering.
318   */
319  {HB_TAG('n','u','k','t'), F_GLOBAL},
320  {HB_TAG('a','k','h','n'), F_GLOBAL},
321  {HB_TAG('r','p','h','f'), F_NONE},
322  {HB_TAG('r','k','r','f'), F_GLOBAL},
323  {HB_TAG('p','r','e','f'), F_NONE},
324  {HB_TAG('b','l','w','f'), F_NONE},
325  {HB_TAG('a','b','v','f'), F_NONE},
326  {HB_TAG('h','a','l','f'), F_NONE},
327  {HB_TAG('p','s','t','f'), F_NONE},
328  {HB_TAG('v','a','t','u'), F_GLOBAL},
329  {HB_TAG('c','j','c','t'), F_GLOBAL},
330  {HB_TAG('c','f','a','r'), F_NONE},
331  /*
332   * Other features.
333   * These features are applied all at once, after final_reordering.
334   * Default Bengali font in Windows for example has intermixed
335   * lookups for init,pres,abvs,blws features.
336   */
337  {HB_TAG('i','n','i','t'), F_NONE},
338  {HB_TAG('p','r','e','s'), F_GLOBAL},
339  {HB_TAG('a','b','v','s'), F_GLOBAL},
340  {HB_TAG('b','l','w','s'), F_GLOBAL},
341  {HB_TAG('p','s','t','s'), F_GLOBAL},
342  {HB_TAG('h','a','l','n'), F_GLOBAL},
343  /* Positioning features, though we don't care about the types. */
344  {HB_TAG('d','i','s','t'), F_GLOBAL},
345  {HB_TAG('a','b','v','m'), F_GLOBAL},
346  {HB_TAG('b','l','w','m'), F_GLOBAL},
347};
348
349/*
350 * Must be in the same order as the indic_features array.
351 */
352enum {
353  _NUKT,
354  _AKHN,
355  RPHF,
356  _RKRF,
357  PREF,
358  BLWF,
359  ABVF,
360  HALF,
361  PSTF,
362  _VATU,
363  _CJCT,
364  CFAR,
365
366  INIT,
367  _PRES,
368  _ABVS,
369  _BLWS,
370  _PSTS,
371  _HALN,
372  _DIST,
373  _ABVM,
374  _BLWM,
375
376  INDIC_NUM_FEATURES,
377  INDIC_BASIC_FEATURES = INIT /* Don't forget to update this! */
378};
379
380static void
381setup_syllables (const hb_ot_shape_plan_t *plan,
382                 hb_font_t *font,
383                 hb_buffer_t *buffer);
384static void
385initial_reordering (const hb_ot_shape_plan_t *plan,
386                    hb_font_t *font,
387                    hb_buffer_t *buffer);
388static void
389final_reordering (const hb_ot_shape_plan_t *plan,
390                  hb_font_t *font,
391                  hb_buffer_t *buffer);
392static void
393clear_syllables (const hb_ot_shape_plan_t *plan,
394                 hb_font_t *font,
395                 hb_buffer_t *buffer);
396
397static void
398collect_features_indic (hb_ot_shape_planner_t *plan)
399{
400  hb_ot_map_builder_t *map = &plan->map;
401
402  /* Do this before any lookups have been applied. */
403  map->add_gsub_pause (setup_syllables);
404
405  map->add_global_bool_feature (HB_TAG('l','o','c','l'));
406  /* The Indic specs do not require ccmp, but we apply it here since if
407   * there is a use of it, it's typically at the beginning. */
408  map->add_global_bool_feature (HB_TAG('c','c','m','p'));
409
410
411  unsigned int i = 0;
412  map->add_gsub_pause (initial_reordering);
413  for (; i < INDIC_BASIC_FEATURES; i++) {
414    map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANUAL_ZWJ);
415    map->add_gsub_pause (NULL);
416  }
417  map->add_gsub_pause (final_reordering);
418  for (; i < INDIC_NUM_FEATURES; i++) {
419    map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANUAL_ZWJ);
420  }
421
422  map->add_global_bool_feature (HB_TAG('c','a','l','t'));
423  map->add_global_bool_feature (HB_TAG('c','l','i','g'));
424
425  map->add_gsub_pause (clear_syllables);
426}
427
428static void
429override_features_indic (hb_ot_shape_planner_t *plan)
430{
431  /* Uniscribe does not apply 'kern' in Khmer. */
432  if (hb_options ().uniscribe_bug_compatible)
433  {
434    switch ((hb_tag_t) plan->props.script)
435    {
436      case HB_SCRIPT_KHMER:
437        plan->map.add_feature (HB_TAG('k','e','r','n'), 0, F_GLOBAL);
438        break;
439    }
440  }
441
442  plan->map.add_feature (HB_TAG('l','i','g','a'), 0, F_GLOBAL);
443}
444
445
446struct would_substitute_feature_t
447{
448  inline void init (const hb_ot_map_t *map, hb_tag_t feature_tag, bool zero_context_)
449  {
450    zero_context = zero_context_;
451    map->get_stage_lookups (0/*GSUB*/,
452                            map->get_feature_stage (0/*GSUB*/, feature_tag),
453                            &lookups, &count);
454  }
455
456  inline bool would_substitute (const hb_codepoint_t *glyphs,
457                                unsigned int          glyphs_count,
458                                hb_face_t            *face) const
459  {
460    for (unsigned int i = 0; i < count; i++)
461      if (hb_ot_layout_lookup_would_substitute_fast (face, lookups[i].index, glyphs, glyphs_count, zero_context))
462        return true;
463    return false;
464  }
465
466  private:
467  const hb_ot_map_t::lookup_map_t *lookups;
468  unsigned int count;
469  bool zero_context;
470};
471
472struct indic_shape_plan_t
473{
474  ASSERT_POD ();
475
476  inline bool get_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const
477  {
478    hb_codepoint_t glyph = virama_glyph;
479    if (unlikely (virama_glyph == (hb_codepoint_t) -1))
480    {
481      if (!config->virama || !font->get_nominal_glyph (config->virama, &glyph))
482        glyph = 0;
483      /* Technically speaking, the spec says we should apply 'locl' to virama too.
484       * Maybe one day... */
485
486      /* Our get_nominal_glyph() function needs a font, so we can't get the virama glyph
487       * during shape planning...  Instead, overwrite it here.  It's safe.  Don't worry! */
488      (const_cast<indic_shape_plan_t *> (this))->virama_glyph = glyph;
489    }
490
491    *pglyph = glyph;
492    return glyph != 0;
493  }
494
495  const indic_config_t *config;
496
497  bool is_old_spec;
498  hb_codepoint_t virama_glyph;
499
500  would_substitute_feature_t rphf;
501  would_substitute_feature_t pref;
502  would_substitute_feature_t blwf;
503  would_substitute_feature_t pstf;
504
505  hb_mask_t mask_array[INDIC_NUM_FEATURES];
506};
507
508static void *
509data_create_indic (const hb_ot_shape_plan_t *plan)
510{
511  indic_shape_plan_t *indic_plan = (indic_shape_plan_t *) calloc (1, sizeof (indic_shape_plan_t));
512  if (unlikely (!indic_plan))
513    return NULL;
514
515  indic_plan->config = &indic_configs[0];
516  for (unsigned int i = 1; i < ARRAY_LENGTH (indic_configs); i++)
517    if (plan->props.script == indic_configs[i].script) {
518      indic_plan->config = &indic_configs[i];
519      break;
520    }
521
522  indic_plan->is_old_spec = indic_plan->config->has_old_spec && ((plan->map.chosen_script[0] & 0x000000FFu) != '2');
523  indic_plan->virama_glyph = (hb_codepoint_t) -1;
524
525  /* Use zero-context would_substitute() matching for new-spec of the main
526   * Indic scripts, and scripts with one spec only, but not for old-specs.
527   * The new-spec for all dual-spec scripts says zero-context matching happens.
528   *
529   * However, testing with Malayalam shows that old and new spec both allow
530   * context.  Testing with Bengali new-spec however shows that it doesn't.
531   * So, the heuristic here is the way it is.  It should *only* be changed,
532   * as we discover more cases of what Windows does.  DON'T TOUCH OTHERWISE.
533   */
534  bool zero_context = !indic_plan->is_old_spec && plan->props.script != HB_SCRIPT_MALAYALAM;
535  indic_plan->rphf.init (&plan->map, HB_TAG('r','p','h','f'), zero_context);
536  indic_plan->pref.init (&plan->map, HB_TAG('p','r','e','f'), zero_context);
537  indic_plan->blwf.init (&plan->map, HB_TAG('b','l','w','f'), zero_context);
538  indic_plan->pstf.init (&plan->map, HB_TAG('p','s','t','f'), zero_context);
539
540  for (unsigned int i = 0; i < ARRAY_LENGTH (indic_plan->mask_array); i++)
541    indic_plan->mask_array[i] = (indic_features[i].flags & F_GLOBAL) ?
542                                 0 : plan->map.get_1_mask (indic_features[i].tag);
543
544  return indic_plan;
545}
546
547static void
548data_destroy_indic (void *data)
549{
550  free (data);
551}
552
553static indic_position_t
554consonant_position_from_face (const indic_shape_plan_t *indic_plan,
555                              const hb_codepoint_t consonant,
556                              const hb_codepoint_t virama,
557                              hb_face_t *face)
558{
559  /* For old-spec, the order of glyphs is Consonant,Virama,
560   * whereas for new-spec, it's Virama,Consonant.  However,
561   * some broken fonts (like Free Sans) simply copied lookups
562   * from old-spec to new-spec without modification.
563   * And oddly enough, Uniscribe seems to respect those lookups.
564   * Eg. in the sequence U+0924,U+094D,U+0930, Uniscribe finds
565   * base at 0.  The font however, only has lookups matching
566   * 930,94D in 'blwf', not the expected 94D,930 (with new-spec
567   * table).  As such, we simply match both sequences.  Seems
568   * to work. */
569  hb_codepoint_t glyphs[3] = {virama, consonant, virama};
570  if (indic_plan->blwf.would_substitute (glyphs  , 2, face) ||
571      indic_plan->blwf.would_substitute (glyphs+1, 2, face))
572    return POS_BELOW_C;
573  if (indic_plan->pstf.would_substitute (glyphs  , 2, face) ||
574      indic_plan->pstf.would_substitute (glyphs+1, 2, face))
575    return POS_POST_C;
576  if (indic_plan->pref.would_substitute (glyphs  , 2, face) ||
577      indic_plan->pref.would_substitute (glyphs+1, 2, face))
578    return POS_POST_C;
579  return POS_BASE_C;
580}
581
582
583enum syllable_type_t {
584  consonant_syllable,
585  vowel_syllable,
586  standalone_cluster,
587  symbol_cluster,
588  broken_cluster,
589  non_indic_cluster,
590};
591
592#include "hb-ot-shape-complex-indic-machine.hh"
593
594
595static void
596setup_masks_indic (const hb_ot_shape_plan_t *plan HB_UNUSED,
597                   hb_buffer_t              *buffer,
598                   hb_font_t                *font HB_UNUSED)
599{
600  HB_BUFFER_ALLOCATE_VAR (buffer, indic_category);
601  HB_BUFFER_ALLOCATE_VAR (buffer, indic_position);
602
603  /* We cannot setup masks here.  We save information about characters
604   * and setup masks later on in a pause-callback. */
605
606  unsigned int count = buffer->len;
607  hb_glyph_info_t *info = buffer->info;
608  for (unsigned int i = 0; i < count; i++)
609    set_indic_properties (info[i]);
610}
611
612static void
613setup_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
614                 hb_font_t *font HB_UNUSED,
615                 hb_buffer_t *buffer)
616{
617  find_syllables (buffer);
618}
619
620static int
621compare_indic_order (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb)
622{
623  int a = pa->indic_position();
624  int b = pb->indic_position();
625
626  return a < b ? -1 : a == b ? 0 : +1;
627}
628
629
630
631static void
632update_consonant_positions (const hb_ot_shape_plan_t *plan,
633                            hb_font_t         *font,
634                            hb_buffer_t       *buffer)
635{
636  const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
637
638  if (indic_plan->config->base_pos != BASE_POS_LAST)
639    return;
640
641  hb_codepoint_t virama;
642  if (indic_plan->get_virama_glyph (font, &virama))
643  {
644    hb_face_t *face = font->face;
645    unsigned int count = buffer->len;
646    hb_glyph_info_t *info = buffer->info;
647    for (unsigned int i = 0; i < count; i++)
648      if (info[i].indic_position() == POS_BASE_C)
649      {
650        hb_codepoint_t consonant = info[i].codepoint;
651        info[i].indic_position() = consonant_position_from_face (indic_plan, consonant, virama, face);
652      }
653  }
654}
655
656
657/* Rules from:
658 * https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx */
659
660static void
661initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
662                                       hb_face_t *face,
663                                       hb_buffer_t *buffer,
664                                       unsigned int start, unsigned int end)
665{
666  const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
667  hb_glyph_info_t *info = buffer->info;
668
669
670  /* 1. Find base consonant:
671   *
672   * The shaping engine finds the base consonant of the syllable, using the
673   * following algorithm: starting from the end of the syllable, move backwards
674   * until a consonant is found that does not have a below-base or post-base
675   * form (post-base forms have to follow below-base forms), or that is not a
676   * pre-base reordering Ra, or arrive at the first consonant. The consonant
677   * stopped at will be the base.
678   *
679   *   o If the syllable starts with Ra + Halant (in a script that has Reph)
680   *     and has more than one consonant, Ra is excluded from candidates for
681   *     base consonants.
682   */
683
684  unsigned int base = end;
685  bool has_reph = false;
686
687  {
688    /* -> If the syllable starts with Ra + Halant (in a script that has Reph)
689     *    and has more than one consonant, Ra is excluded from candidates for
690     *    base consonants. */
691    unsigned int limit = start;
692    if (indic_plan->config->reph_pos != REPH_POS_DONT_CARE &&
693        indic_plan->mask_array[RPHF] &&
694        start + 3 <= end &&
695        (
696         (indic_plan->config->reph_mode == REPH_MODE_IMPLICIT && !is_joiner (info[start + 2])) ||
697         (indic_plan->config->reph_mode == REPH_MODE_EXPLICIT && info[start + 2].indic_category() == OT_ZWJ)
698        ))
699    {
700      /* See if it matches the 'rphf' feature. */
701      hb_codepoint_t glyphs[3] = {info[start].codepoint,
702                                  info[start + 1].codepoint,
703                                  indic_plan->config->reph_mode == REPH_MODE_EXPLICIT ?
704                                    info[start + 2].codepoint : 0};
705      if (indic_plan->rphf.would_substitute (glyphs, 2, face) ||
706          (indic_plan->config->reph_mode == REPH_MODE_EXPLICIT &&
707           indic_plan->rphf.would_substitute (glyphs, 3, face)))
708      {
709        limit += 2;
710        while (limit < end && is_joiner (info[limit]))
711          limit++;
712        base = start;
713        has_reph = true;
714      }
715    } else if (indic_plan->config->reph_mode == REPH_MODE_LOG_REPHA && info[start].indic_category() == OT_Repha)
716    {
717        limit += 1;
718        while (limit < end && is_joiner (info[limit]))
719          limit++;
720        base = start;
721        has_reph = true;
722    }
723
724    switch (indic_plan->config->base_pos)
725    {
726      case BASE_POS_LAST:
727      {
728        /* -> starting from the end of the syllable, move backwards */
729        unsigned int i = end;
730        bool seen_below = false;
731        do {
732          i--;
733          /* -> until a consonant is found */
734          if (is_consonant (info[i]))
735          {
736            /* -> that does not have a below-base or post-base form
737             * (post-base forms have to follow below-base forms), */
738            if (info[i].indic_position() != POS_BELOW_C &&
739                (info[i].indic_position() != POS_POST_C || seen_below))
740            {
741              base = i;
742              break;
743            }
744            if (info[i].indic_position() == POS_BELOW_C)
745              seen_below = true;
746
747            /* -> or that is not a pre-base reordering Ra,
748             *
749             * IMPLEMENTATION NOTES:
750             *
751             * Our pre-base reordering Ra's are marked POS_POST_C, so will be skipped
752             * by the logic above already.
753             */
754
755            /* -> or arrive at the first consonant. The consonant stopped at will
756             * be the base. */
757            base = i;
758          }
759          else
760          {
761            /* A ZWJ after a Halant stops the base search, and requests an explicit
762             * half form.
763             * A ZWJ before a Halant, requests a subjoined form instead, and hence
764             * search continues.  This is particularly important for Bengali
765             * sequence Ra,H,Ya that should form Ya-Phalaa by subjoining Ya. */
766            if (start < i &&
767                info[i].indic_category() == OT_ZWJ &&
768                info[i - 1].indic_category() == OT_H)
769              break;
770          }
771        } while (i > limit);
772      }
773      break;
774
775      case BASE_POS_LAST_SINHALA:
776      {
777        /* Sinhala base positioning is slightly different from main Indic, in that:
778         * 1. Its ZWJ behavior is different,
779         * 2. We don't need to look into the font for consonant positions.
780         */
781
782        if (!has_reph)
783          base = limit;
784
785        /* Find the last base consonant that is not blocked by ZWJ.  If there is
786         * a ZWJ right before a base consonant, that would request a subjoined form. */
787        for (unsigned int i = limit; i < end; i++)
788          if (is_consonant (info[i]))
789          {
790            if (limit < i && info[i - 1].indic_category() == OT_ZWJ)
791              break;
792            else
793              base = i;
794          }
795
796        /* Mark all subsequent consonants as below. */
797        for (unsigned int i = base + 1; i < end; i++)
798          if (is_consonant (info[i]))
799            info[i].indic_position() = POS_BELOW_C;
800      }
801      break;
802
803      case BASE_POS_FIRST:
804      {
805        /* The first consonant is always the base. */
806
807        assert (indic_plan->config->reph_mode == REPH_MODE_VIS_REPHA);
808        assert (!has_reph);
809
810        base = start;
811
812        /* Mark all subsequent consonants as below. */
813        for (unsigned int i = base + 1; i < end; i++)
814          if (is_consonant (info[i]))
815            info[i].indic_position() = POS_BELOW_C;
816      }
817      break;
818    }
819
820    /* -> If the syllable starts with Ra + Halant (in a script that has Reph)
821     *    and has more than one consonant, Ra is excluded from candidates for
822     *    base consonants.
823     *
824     *  Only do this for unforced Reph. (ie. not for Ra,H,ZWJ. */
825    if (has_reph && base == start && limit - base <= 2) {
826      /* Have no other consonant, so Reph is not formed and Ra becomes base. */
827      has_reph = false;
828    }
829  }
830
831
832  /* 2. Decompose and reorder Matras:
833   *
834   * Each matra and any syllable modifier sign in the cluster are moved to the
835   * appropriate position relative to the consonant(s) in the cluster. The
836   * shaping engine decomposes two- or three-part matras into their constituent
837   * parts before any repositioning. Matra characters are classified by which
838   * consonant in a conjunct they have affinity for and are reordered to the
839   * following positions:
840   *
841   *   o Before first half form in the syllable
842   *   o After subjoined consonants
843   *   o After post-form consonant
844   *   o After main consonant (for above marks)
845   *
846   * IMPLEMENTATION NOTES:
847   *
848   * The normalize() routine has already decomposed matras for us, so we don't
849   * need to worry about that.
850   */
851
852
853  /* 3.  Reorder marks to canonical order:
854   *
855   * Adjacent nukta and halant or nukta and vedic sign are always repositioned
856   * if necessary, so that the nukta is first.
857   *
858   * IMPLEMENTATION NOTES:
859   *
860   * We don't need to do this: the normalize() routine already did this for us.
861   */
862
863
864  /* Reorder characters */
865
866  for (unsigned int i = start; i < base; i++)
867    info[i].indic_position() = MIN (POS_PRE_C, (indic_position_t) info[i].indic_position());
868
869  if (base < end)
870    info[base].indic_position() = POS_BASE_C;
871
872  /* Mark final consonants.  A final consonant is one appearing after a matra,
873   * like in Khmer. */
874  for (unsigned int i = base + 1; i < end; i++)
875    if (info[i].indic_category() == OT_M) {
876      for (unsigned int j = i + 1; j < end; j++)
877        if (is_consonant (info[j])) {
878          info[j].indic_position() = POS_FINAL_C;
879          break;
880        }
881      break;
882    }
883
884  /* Handle beginning Ra */
885  if (has_reph)
886    info[start].indic_position() = POS_RA_TO_BECOME_REPH;
887
888  /* For old-style Indic script tags, move the first post-base Halant after
889   * last consonant.
890   *
891   * Reports suggest that in some scripts Uniscribe does this only if there
892   * is *not* a Halant after last consonant already (eg. Kannada), while it
893   * does it unconditionally in other scripts (eg. Malayalam).  We don't
894   * currently know about other scripts, so we single out Malayalam for now.
895   *
896   * Kannada test case:
897   * U+0C9A,U+0CCD,U+0C9A,U+0CCD
898   * With some versions of Lohit Kannada.
899   * https://bugs.freedesktop.org/show_bug.cgi?id=59118
900   *
901   * Malayalam test case:
902   * U+0D38,U+0D4D,U+0D31,U+0D4D,U+0D31,U+0D4D
903   * With lohit-ttf-20121122/Lohit-Malayalam.ttf
904   */
905  if (indic_plan->is_old_spec)
906  {
907    bool disallow_double_halants = buffer->props.script != HB_SCRIPT_MALAYALAM;
908    for (unsigned int i = base + 1; i < end; i++)
909      if (info[i].indic_category() == OT_H)
910      {
911        unsigned int j;
912        for (j = end - 1; j > i; j--)
913          if (is_consonant (info[j]) ||
914              (disallow_double_halants && info[j].indic_category() == OT_H))
915            break;
916        if (info[j].indic_category() != OT_H && j > i) {
917          /* Move Halant to after last consonant. */
918          hb_glyph_info_t t = info[i];
919          memmove (&info[i], &info[i + 1], (j - i) * sizeof (info[0]));
920          info[j] = t;
921        }
922        break;
923      }
924  }
925
926  /* Attach misc marks to previous char to move with them. */
927  {
928    indic_position_t last_pos = POS_START;
929    for (unsigned int i = start; i < end; i++)
930    {
931      if ((FLAG_SAFE (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | MEDIAL_FLAGS | HALANT_OR_COENG_FLAGS)))
932      {
933        info[i].indic_position() = last_pos;
934        if (unlikely (info[i].indic_category() == OT_H &&
935                      info[i].indic_position() == POS_PRE_M))
936        {
937          /*
938           * Uniscribe doesn't move the Halant with Left Matra.
939           * TEST: U+092B,U+093F,U+094DE
940           * We follow.  This is important for the Sinhala
941           * U+0DDA split matra since it decomposes to U+0DD9,U+0DCA
942           * where U+0DD9 is a left matra and U+0DCA is the virama.
943           * We don't want to move the virama with the left matra.
944           * TEST: U+0D9A,U+0DDA
945           */
946          for (unsigned int j = i; j > start; j--)
947            if (info[j - 1].indic_position() != POS_PRE_M) {
948              info[i].indic_position() = info[j - 1].indic_position();
949              break;
950            }
951        }
952      } else if (info[i].indic_position() != POS_SMVD) {
953        last_pos = (indic_position_t) info[i].indic_position();
954      }
955    }
956  }
957  /* For post-base consonants let them own anything before them
958   * since the last consonant or matra. */
959  {
960    unsigned int last = base;
961    for (unsigned int i = base + 1; i < end; i++)
962      if (is_consonant (info[i]))
963      {
964        for (unsigned int j = last + 1; j < i; j++)
965          if (info[j].indic_position() < POS_SMVD)
966            info[j].indic_position() = info[i].indic_position();
967        last = i;
968      } else if (info[i].indic_category() == OT_M)
969        last = i;
970  }
971
972
973  {
974    /* Use syllable() for sort accounting temporarily. */
975    unsigned int syllable = info[start].syllable();
976    for (unsigned int i = start; i < end; i++)
977      info[i].syllable() = i - start;
978
979    /* Sit tight, rock 'n roll! */
980    hb_stable_sort (info + start, end - start, compare_indic_order);
981    /* Find base again */
982    base = end;
983    for (unsigned int i = start; i < end; i++)
984      if (info[i].indic_position() == POS_BASE_C)
985      {
986        base = i;
987        break;
988      }
989    /* Things are out-of-control for post base positions, they may shuffle
990     * around like crazy.  In old-spec mode, we move halants around, so in
991     * that case merge all clusters after base.  Otherwise, check the sort
992     * order and merge as needed.
993     * For pre-base stuff, we handle cluster issues in final reordering.
994     *
995     * We could use buffer->sort() for this, if there was no special
996     * reordering of pre-base stuff happening later...
997     */
998    if (indic_plan->is_old_spec || end - base > 127)
999      buffer->merge_clusters (base, end);
1000    else
1001    {
1002      /* Note!  syllable() is a one-byte field. */
1003      for (unsigned int i = base; i < end; i++)
1004        if (info[i].syllable() != 255)
1005        {
1006          unsigned int max = i;
1007          unsigned int j = start + info[i].syllable();
1008          while (j != i)
1009          {
1010            max = MAX (max, j);
1011            unsigned int next = start + info[j].syllable();
1012            info[j].syllable() = 255; /* So we don't process j later again. */
1013            j = next;
1014          }
1015          if (i != max)
1016            buffer->merge_clusters (i, max + 1);
1017        }
1018    }
1019
1020    /* Put syllable back in. */
1021    for (unsigned int i = start; i < end; i++)
1022      info[i].syllable() = syllable;
1023  }
1024
1025  /* Setup masks now */
1026
1027  {
1028    hb_mask_t mask;
1029
1030    /* Reph */
1031    for (unsigned int i = start; i < end && info[i].indic_position() == POS_RA_TO_BECOME_REPH; i++)
1032      info[i].mask |= indic_plan->mask_array[RPHF];
1033
1034    /* Pre-base */
1035    mask = indic_plan->mask_array[HALF];
1036    if (!indic_plan->is_old_spec &&
1037        indic_plan->config->blwf_mode == BLWF_MODE_PRE_AND_POST)
1038      mask |= indic_plan->mask_array[BLWF];
1039    for (unsigned int i = start; i < base; i++)
1040      info[i].mask  |= mask;
1041    /* Base */
1042    mask = 0;
1043    if (base < end)
1044      info[base].mask |= mask;
1045    /* Post-base */
1046    mask = indic_plan->mask_array[BLWF] | indic_plan->mask_array[ABVF] | indic_plan->mask_array[PSTF];
1047    for (unsigned int i = base + 1; i < end; i++)
1048      info[i].mask  |= mask;
1049  }
1050
1051  if (indic_plan->is_old_spec &&
1052      buffer->props.script == HB_SCRIPT_DEVANAGARI)
1053  {
1054    /* Old-spec eye-lash Ra needs special handling.  From the
1055     * spec:
1056     *
1057     * "The feature 'below-base form' is applied to consonants
1058     * having below-base forms and following the base consonant.
1059     * The exception is vattu, which may appear below half forms
1060     * as well as below the base glyph. The feature 'below-base
1061     * form' will be applied to all such occurrences of Ra as well."
1062     *
1063     * Test case: U+0924,U+094D,U+0930,U+094d,U+0915
1064     * with Sanskrit 2003 font.
1065     *
1066     * However, note that Ra,Halant,ZWJ is the correct way to
1067     * request eyelash form of Ra, so we wouldbn't inhibit it
1068     * in that sequence.
1069     *
1070     * Test case: U+0924,U+094D,U+0930,U+094d,U+200D,U+0915
1071     */
1072    for (unsigned int i = start; i + 1 < base; i++)
1073      if (info[i  ].indic_category() == OT_Ra &&
1074          info[i+1].indic_category() == OT_H  &&
1075          (i + 2 == base ||
1076           info[i+2].indic_category() != OT_ZWJ))
1077      {
1078        info[i  ].mask |= indic_plan->mask_array[BLWF];
1079        info[i+1].mask |= indic_plan->mask_array[BLWF];
1080      }
1081  }
1082
1083  unsigned int pref_len = 2;
1084  if (indic_plan->mask_array[PREF] && base + pref_len < end)
1085  {
1086    /* Find a Halant,Ra sequence and mark it for pre-base reordering processing. */
1087    for (unsigned int i = base + 1; i + pref_len - 1 < end; i++) {
1088      hb_codepoint_t glyphs[2];
1089      for (unsigned int j = 0; j < pref_len; j++)
1090        glyphs[j] = info[i + j].codepoint;
1091      if (indic_plan->pref.would_substitute (glyphs, pref_len, face))
1092      {
1093        for (unsigned int j = 0; j < pref_len; j++)
1094          info[i++].mask |= indic_plan->mask_array[PREF];
1095
1096        /* Mark the subsequent stuff with 'cfar'.  Used in Khmer.
1097         * Read the feature spec.
1098         * This allows distinguishing the following cases with MS Khmer fonts:
1099         * U+1784,U+17D2,U+179A,U+17D2,U+1782
1100         * U+1784,U+17D2,U+1782,U+17D2,U+179A
1101         */
1102        if (indic_plan->mask_array[CFAR])
1103          for (; i < end; i++)
1104            info[i].mask |= indic_plan->mask_array[CFAR];
1105
1106        break;
1107      }
1108    }
1109  }
1110
1111  /* Apply ZWJ/ZWNJ effects */
1112  for (unsigned int i = start + 1; i < end; i++)
1113    if (is_joiner (info[i])) {
1114      bool non_joiner = info[i].indic_category() == OT_ZWNJ;
1115      unsigned int j = i;
1116
1117      do {
1118        j--;
1119
1120        /* ZWJ/ZWNJ should disable CJCT.  They do that by simply
1121         * being there, since we don't skip them for the CJCT
1122         * feature (ie. F_MANUAL_ZWJ) */
1123
1124        /* A ZWNJ disables HALF. */
1125        if (non_joiner)
1126          info[j].mask &= ~indic_plan->mask_array[HALF];
1127
1128      } while (j > start && !is_consonant (info[j]));
1129    }
1130}
1131
1132static void
1133initial_reordering_standalone_cluster (const hb_ot_shape_plan_t *plan,
1134                                       hb_face_t *face,
1135                                       hb_buffer_t *buffer,
1136                                       unsigned int start, unsigned int end)
1137{
1138  /* We treat placeholder/dotted-circle as if they are consonants, so we
1139   * should just chain.  Only if not in compatibility mode that is... */
1140
1141  if (hb_options ().uniscribe_bug_compatible)
1142  {
1143    /* For dotted-circle, this is what Uniscribe does:
1144     * If dotted-circle is the last glyph, it just does nothing.
1145     * Ie. It doesn't form Reph. */
1146    if (buffer->info[end - 1].indic_category() == OT_DOTTEDCIRCLE)
1147      return;
1148  }
1149
1150  initial_reordering_consonant_syllable (plan, face, buffer, start, end);
1151}
1152
1153static void
1154initial_reordering_syllable (const hb_ot_shape_plan_t *plan,
1155                             hb_face_t *face,
1156                             hb_buffer_t *buffer,
1157                             unsigned int start, unsigned int end)
1158{
1159  syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F);
1160  switch (syllable_type)
1161  {
1162    case vowel_syllable: /* We made the vowels look like consonants.  So let's call the consonant logic! */
1163    case consonant_syllable:
1164     initial_reordering_consonant_syllable (plan, face, buffer, start, end);
1165     break;
1166
1167    case broken_cluster: /* We already inserted dotted-circles, so just call the standalone_cluster. */
1168    case standalone_cluster:
1169     initial_reordering_standalone_cluster (plan, face, buffer, start, end);
1170     break;
1171
1172    case symbol_cluster:
1173    case non_indic_cluster:
1174      break;
1175  }
1176}
1177
1178static inline void
1179insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
1180                       hb_font_t *font,
1181                       hb_buffer_t *buffer)
1182{
1183  /* Note: This loop is extra overhead, but should not be measurable. */
1184  bool has_broken_syllables = false;
1185  unsigned int count = buffer->len;
1186  hb_glyph_info_t *info = buffer->info;
1187  for (unsigned int i = 0; i < count; i++)
1188    if ((info[i].syllable() & 0x0F) == broken_cluster)
1189    {
1190      has_broken_syllables = true;
1191      break;
1192    }
1193  if (likely (!has_broken_syllables))
1194    return;
1195
1196
1197  hb_codepoint_t dottedcircle_glyph;
1198  if (!font->get_nominal_glyph (0x25CCu, &dottedcircle_glyph))
1199    return;
1200
1201  hb_glyph_info_t dottedcircle = {0};
1202  dottedcircle.codepoint = 0x25CCu;
1203  set_indic_properties (dottedcircle);
1204  dottedcircle.codepoint = dottedcircle_glyph;
1205
1206  buffer->clear_output ();
1207
1208  buffer->idx = 0;
1209  unsigned int last_syllable = 0;
1210  while (buffer->idx < buffer->len && !buffer->in_error)
1211  {
1212    unsigned int syllable = buffer->cur().syllable();
1213    syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F);
1214    if (unlikely (last_syllable != syllable && syllable_type == broken_cluster))
1215    {
1216      last_syllable = syllable;
1217
1218      hb_glyph_info_t ginfo = dottedcircle;
1219      ginfo.cluster = buffer->cur().cluster;
1220      ginfo.mask = buffer->cur().mask;
1221      ginfo.syllable() = buffer->cur().syllable();
1222      /* TODO Set glyph_props? */
1223
1224      /* Insert dottedcircle after possible Repha. */
1225      while (buffer->idx < buffer->len && !buffer->in_error &&
1226             last_syllable == buffer->cur().syllable() &&
1227             buffer->cur().indic_category() == OT_Repha)
1228        buffer->next_glyph ();
1229
1230      buffer->output_info (ginfo);
1231    }
1232    else
1233      buffer->next_glyph ();
1234  }
1235
1236  buffer->swap_buffers ();
1237}
1238
1239static void
1240initial_reordering (const hb_ot_shape_plan_t *plan,
1241                    hb_font_t *font,
1242                    hb_buffer_t *buffer)
1243{
1244  update_consonant_positions (plan, font, buffer);
1245  insert_dotted_circles (plan, font, buffer);
1246
1247  foreach_syllable (buffer, start, end)
1248    initial_reordering_syllable (plan, font->face, buffer, start, end);
1249}
1250
1251static void
1252final_reordering_syllable (const hb_ot_shape_plan_t *plan,
1253                           hb_buffer_t *buffer,
1254                           unsigned int start, unsigned int end)
1255{
1256  const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
1257  hb_glyph_info_t *info = buffer->info;
1258
1259
1260  /* This function relies heavily on halant glyphs.  Lots of ligation
1261   * and possibly multiplication substitutions happened prior to this
1262   * phase, and that might have messed up our properties.  Recover
1263   * from a particular case of that where we're fairly sure that a
1264   * class of OT_H is desired but has been lost. */
1265  if (indic_plan->virama_glyph)
1266  {
1267    unsigned int virama_glyph = indic_plan->virama_glyph;
1268    for (unsigned int i = start; i < end; i++)
1269      if (info[i].codepoint == virama_glyph &&
1270          _hb_glyph_info_ligated (&info[i]) &&
1271          _hb_glyph_info_multiplied (&info[i]))
1272      {
1273        /* This will make sure that this glyph passes is_halant_or_coeng() test. */
1274        info[i].indic_category() = OT_H;
1275        _hb_glyph_info_clear_ligated_and_multiplied (&info[i]);
1276      }
1277  }
1278
1279
1280  /* 4. Final reordering:
1281   *
1282   * After the localized forms and basic shaping forms GSUB features have been
1283   * applied (see below), the shaping engine performs some final glyph
1284   * reordering before applying all the remaining font features to the entire
1285   * cluster.
1286   */
1287
1288  bool try_pref = !!indic_plan->mask_array[PREF];
1289
1290  /* Find base again */
1291  unsigned int base;
1292  for (base = start; base < end; base++)
1293    if (info[base].indic_position() >= POS_BASE_C)
1294    {
1295      if (try_pref && base + 1 < end)
1296      {
1297        for (unsigned int i = base + 1; i < end; i++)
1298          if ((info[i].mask & indic_plan->mask_array[PREF]) != 0)
1299          {
1300            if (!(_hb_glyph_info_substituted (&info[i]) &&
1301                  _hb_glyph_info_ligated_and_didnt_multiply (&info[i])))
1302            {
1303              /* Ok, this was a 'pref' candidate but didn't form any.
1304               * Base is around here... */
1305              base = i;
1306              while (base < end && is_halant_or_coeng (info[base]))
1307                base++;
1308              info[base].indic_position() = POS_BASE_C;
1309
1310              try_pref = false;
1311            }
1312            break;
1313          }
1314      }
1315      /* For Malayalam, skip over unformed below- (but NOT post-) forms. */
1316      if (buffer->props.script == HB_SCRIPT_MALAYALAM)
1317      {
1318        for (unsigned int i = base + 1; i < end; i++)
1319        {
1320          while (i < end && is_joiner (info[i]))
1321            i++;
1322          if (i == end || !is_halant_or_coeng (info[i]))
1323            break;
1324          i++; /* Skip halant. */
1325          while (i < end && is_joiner (info[i]))
1326            i++;
1327          if (i < end && is_consonant (info[i]) && info[i].indic_position() == POS_BELOW_C)
1328          {
1329            base = i;
1330            info[base].indic_position() = POS_BASE_C;
1331          }
1332        }
1333      }
1334
1335      if (start < base && info[base].indic_position() > POS_BASE_C)
1336        base--;
1337      break;
1338    }
1339  if (base == end && start < base &&
1340      is_one_of (info[base - 1], FLAG (OT_ZWJ)))
1341    base--;
1342  if (base < end)
1343    while (start < base &&
1344           is_one_of (info[base], (FLAG (OT_N) | HALANT_OR_COENG_FLAGS)))
1345      base--;
1346
1347
1348  /*   o Reorder matras:
1349   *
1350   *     If a pre-base matra character had been reordered before applying basic
1351   *     features, the glyph can be moved closer to the main consonant based on
1352   *     whether half-forms had been formed. Actual position for the matra is
1353   *     defined as ���after last standalone halant glyph, after initial matra
1354   *     position and before the main consonant���. If ZWJ or ZWNJ follow this
1355   *     halant, position is moved after it.
1356   */
1357
1358  if (start + 1 < end && start < base) /* Otherwise there can't be any pre-base matra characters. */
1359  {
1360    /* If we lost track of base, alas, position before last thingy. */
1361    unsigned int new_pos = base == end ? base - 2 : base - 1;
1362
1363    /* Malayalam / Tamil do not have "half" forms or explicit virama forms.
1364     * The glyphs formed by 'half' are Chillus or ligated explicit viramas.
1365     * We want to position matra after them.
1366     */
1367    if (buffer->props.script != HB_SCRIPT_MALAYALAM && buffer->props.script != HB_SCRIPT_TAMIL)
1368    {
1369      while (new_pos > start &&
1370             !(is_one_of (info[new_pos], (FLAG (OT_M) | HALANT_OR_COENG_FLAGS))))
1371        new_pos--;
1372
1373      /* If we found no Halant we are done.
1374       * Otherwise only proceed if the Halant does
1375       * not belong to the Matra itself! */
1376      if (is_halant_or_coeng (info[new_pos]) &&
1377          info[new_pos].indic_position() != POS_PRE_M)
1378      {
1379        /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */
1380        if (new_pos + 1 < end && is_joiner (info[new_pos + 1]))
1381          new_pos++;
1382      }
1383      else
1384        new_pos = start; /* No move. */
1385    }
1386
1387    if (start < new_pos && info[new_pos].indic_position () != POS_PRE_M)
1388    {
1389      /* Now go see if there's actually any matras... */
1390      for (unsigned int i = new_pos; i > start; i--)
1391        if (info[i - 1].indic_position () == POS_PRE_M)
1392        {
1393          unsigned int old_pos = i - 1;
1394          if (old_pos < base && base <= new_pos) /* Shouldn't actually happen. */
1395            base--;
1396
1397          hb_glyph_info_t tmp = info[old_pos];
1398          memmove (&info[old_pos], &info[old_pos + 1], (new_pos - old_pos) * sizeof (info[0]));
1399          info[new_pos] = tmp;
1400
1401          /* Note: this merge_clusters() is intentionally *after* the reordering.
1402           * Indic matra reordering is special and tricky... */
1403          buffer->merge_clusters (new_pos, MIN (end, base + 1));
1404
1405          new_pos--;
1406        }
1407    } else {
1408      for (unsigned int i = start; i < base; i++)
1409        if (info[i].indic_position () == POS_PRE_M) {
1410          buffer->merge_clusters (i, MIN (end, base + 1));
1411          break;
1412        }
1413    }
1414  }
1415
1416
1417  /*   o Reorder reph:
1418   *
1419   *     Reph���s original position is always at the beginning of the syllable,
1420   *     (i.e. it is not reordered at the character reordering stage). However,
1421   *     it will be reordered according to the basic-forms shaping results.
1422   *     Possible positions for reph, depending on the script, are; after main,
1423   *     before post-base consonant forms, and after post-base consonant forms.
1424   */
1425
1426  /* Two cases:
1427   *
1428   * - If repha is encoded as a sequence of characters (Ra,H or Ra,H,ZWJ), then
1429   *   we should only move it if the sequence ligated to the repha form.
1430   *
1431   * - If repha is encoded separately and in the logical position, we should only
1432   *   move it if it did NOT ligate.  If it ligated, it's probably the font trying
1433   *   to make it work without the reordering.
1434   */
1435  if (start + 1 < end &&
1436      info[start].indic_position() == POS_RA_TO_BECOME_REPH &&
1437      ((info[start].indic_category() == OT_Repha) ^
1438       _hb_glyph_info_ligated_and_didnt_multiply (&info[start])))
1439  {
1440    unsigned int new_reph_pos;
1441    reph_position_t reph_pos = indic_plan->config->reph_pos;
1442
1443    assert (reph_pos != REPH_POS_DONT_CARE);
1444
1445    /*       1. If reph should be positioned after post-base consonant forms,
1446     *          proceed to step 5.
1447     */
1448    if (reph_pos == REPH_POS_AFTER_POST)
1449    {
1450      goto reph_step_5;
1451    }
1452
1453    /*       2. If the reph repositioning class is not after post-base: target
1454     *          position is after the first explicit halant glyph between the
1455     *          first post-reph consonant and last main consonant. If ZWJ or ZWNJ
1456     *          are following this halant, position is moved after it. If such
1457     *          position is found, this is the target position. Otherwise,
1458     *          proceed to the next step.
1459     *
1460     *          Note: in old-implementation fonts, where classifications were
1461     *          fixed in shaping engine, there was no case where reph position
1462     *          will be found on this step.
1463     */
1464    {
1465      new_reph_pos = start + 1;
1466      while (new_reph_pos < base && !is_halant_or_coeng (info[new_reph_pos]))
1467        new_reph_pos++;
1468
1469      if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos]))
1470      {
1471        /* ->If ZWJ or ZWNJ are following this halant, position is moved after it. */
1472        if (new_reph_pos + 1 < base && is_joiner (info[new_reph_pos + 1]))
1473          new_reph_pos++;
1474        goto reph_move;
1475      }
1476    }
1477
1478    /*       3. If reph should be repositioned after the main consonant: find the
1479     *          first consonant not ligated with main, or find the first
1480     *          consonant that is not a potential pre-base reordering Ra.
1481     */
1482    if (reph_pos == REPH_POS_AFTER_MAIN)
1483    {
1484      new_reph_pos = base;
1485      while (new_reph_pos + 1 < end && info[new_reph_pos + 1].indic_position() <= POS_AFTER_MAIN)
1486        new_reph_pos++;
1487      if (new_reph_pos < end)
1488        goto reph_move;
1489    }
1490
1491    /*       4. If reph should be positioned before post-base consonant, find
1492     *          first post-base classified consonant not ligated with main. If no
1493     *          consonant is found, the target position should be before the
1494     *          first matra, syllable modifier sign or vedic sign.
1495     */
1496    /* This is our take on what step 4 is trying to say (and failing, BADLY). */
1497    if (reph_pos == REPH_POS_AFTER_SUB)
1498    {
1499      new_reph_pos = base;
1500      while (new_reph_pos < end &&
1501             !( FLAG_SAFE (info[new_reph_pos + 1].indic_position()) & (FLAG (POS_POST_C) | FLAG (POS_AFTER_POST) | FLAG (POS_SMVD))))
1502        new_reph_pos++;
1503      if (new_reph_pos < end)
1504        goto reph_move;
1505    }
1506
1507    /*       5. If no consonant is found in steps 3 or 4, move reph to a position
1508     *          immediately before the first post-base matra, syllable modifier
1509     *          sign or vedic sign that has a reordering class after the intended
1510     *          reph position. For example, if the reordering position for reph
1511     *          is post-main, it will skip above-base matras that also have a
1512     *          post-main position.
1513     */
1514    reph_step_5:
1515    {
1516      /* Copied from step 2. */
1517      new_reph_pos = start + 1;
1518      while (new_reph_pos < base && !is_halant_or_coeng (info[new_reph_pos]))
1519        new_reph_pos++;
1520
1521      if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos]))
1522      {
1523        /* ->If ZWJ or ZWNJ are following this halant, position is moved after it. */
1524        if (new_reph_pos + 1 < base && is_joiner (info[new_reph_pos + 1]))
1525          new_reph_pos++;
1526        goto reph_move;
1527      }
1528    }
1529
1530    /*       6. Otherwise, reorder reph to the end of the syllable.
1531     */
1532    {
1533      new_reph_pos = end - 1;
1534      while (new_reph_pos > start && info[new_reph_pos].indic_position() == POS_SMVD)
1535        new_reph_pos--;
1536
1537      /*
1538       * If the Reph is to be ending up after a Matra,Halant sequence,
1539       * position it before that Halant so it can interact with the Matra.
1540       * However, if it's a plain Consonant,Halant we shouldn't do that.
1541       * Uniscribe doesn't do this.
1542       * TEST: U+0930,U+094D,U+0915,U+094B,U+094D
1543       */
1544      if (!hb_options ().uniscribe_bug_compatible &&
1545          unlikely (is_halant_or_coeng (info[new_reph_pos]))) {
1546        for (unsigned int i = base + 1; i < new_reph_pos; i++)
1547          if (info[i].indic_category() == OT_M) {
1548            /* Ok, got it. */
1549            new_reph_pos--;
1550          }
1551      }
1552      goto reph_move;
1553    }
1554
1555    reph_move:
1556    {
1557      /* Move */
1558      buffer->merge_clusters (start, new_reph_pos + 1);
1559      hb_glyph_info_t reph = info[start];
1560      memmove (&info[start], &info[start + 1], (new_reph_pos - start) * sizeof (info[0]));
1561      info[new_reph_pos] = reph;
1562
1563      if (start < base && base <= new_reph_pos)
1564        base--;
1565    }
1566  }
1567
1568
1569  /*   o Reorder pre-base reordering consonants:
1570   *
1571   *     If a pre-base reordering consonant is found, reorder it according to
1572   *     the following rules:
1573   */
1574
1575  if (try_pref && base + 1 < end) /* Otherwise there can't be any pre-base reordering Ra. */
1576  {
1577    for (unsigned int i = base + 1; i < end; i++)
1578      if ((info[i].mask & indic_plan->mask_array[PREF]) != 0)
1579      {
1580        /*       1. Only reorder a glyph produced by substitution during application
1581         *          of the <pref> feature. (Note that a font may shape a Ra consonant with
1582         *          the feature generally but block it in certain contexts.)
1583         */
1584        /* Note: We just check that something got substituted.  We don't check that
1585         * the <pref> feature actually did it...
1586         *
1587         * Reorder pref only if it ligated. */
1588        if (_hb_glyph_info_ligated_and_didnt_multiply (&info[i]))
1589        {
1590          /*
1591           *       2. Try to find a target position the same way as for pre-base matra.
1592           *          If it is found, reorder pre-base consonant glyph.
1593           *
1594           *       3. If position is not found, reorder immediately before main
1595           *          consonant.
1596           */
1597
1598          unsigned int new_pos = base;
1599          /* Malayalam / Tamil do not have "half" forms or explicit virama forms.
1600           * The glyphs formed by 'half' are Chillus or ligated explicit viramas.
1601           * We want to position matra after them.
1602           */
1603          if (buffer->props.script != HB_SCRIPT_MALAYALAM && buffer->props.script != HB_SCRIPT_TAMIL)
1604          {
1605            while (new_pos > start &&
1606                   !(is_one_of (info[new_pos - 1], FLAG(OT_M) | HALANT_OR_COENG_FLAGS)))
1607              new_pos--;
1608
1609            /* In Khmer coeng model, a H,Ra can go *after* matras.  If it goes after a
1610             * split matra, it should be reordered to *before* the left part of such matra. */
1611            if (new_pos > start && info[new_pos - 1].indic_category() == OT_M)
1612            {
1613              unsigned int old_pos = i;
1614              for (unsigned int j = base + 1; j < old_pos; j++)
1615                if (info[j].indic_category() == OT_M)
1616                {
1617                  new_pos--;
1618                  break;
1619                }
1620            }
1621          }
1622
1623          if (new_pos > start && is_halant_or_coeng (info[new_pos - 1]))
1624          {
1625            /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */
1626            if (new_pos < end && is_joiner (info[new_pos]))
1627              new_pos++;
1628          }
1629
1630          {
1631            unsigned int old_pos = i;
1632
1633            buffer->merge_clusters (new_pos, old_pos + 1);
1634            hb_glyph_info_t tmp = info[old_pos];
1635            memmove (&info[new_pos + 1], &info[new_pos], (old_pos - new_pos) * sizeof (info[0]));
1636            info[new_pos] = tmp;
1637
1638            if (new_pos <= base && base < old_pos)
1639              base++;
1640          }
1641        }
1642
1643        break;
1644      }
1645  }
1646
1647
1648  /* Apply 'init' to the Left Matra if it's a word start. */
1649  if (info[start].indic_position () == POS_PRE_M &&
1650      (!start ||
1651       !(FLAG_SAFE (_hb_glyph_info_get_general_category (&info[start - 1])) &
1652         FLAG_RANGE (HB_UNICODE_GENERAL_CATEGORY_FORMAT, HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK))))
1653    info[start].mask |= indic_plan->mask_array[INIT];
1654
1655
1656  /*
1657   * Finish off the clusters and go home!
1658   */
1659  if (hb_options ().uniscribe_bug_compatible)
1660  {
1661    switch ((hb_tag_t) plan->props.script)
1662    {
1663      case HB_SCRIPT_TAMIL:
1664      case HB_SCRIPT_SINHALA:
1665        break;
1666
1667      default:
1668        /* Uniscribe merges the entire cluster... Except for Tamil & Sinhala.
1669         * This means, half forms are submerged into the main consonants cluster.
1670         * This is unnecessary, and makes cursor positioning harder, but that's what
1671         * Uniscribe does. */
1672        buffer->merge_clusters (start, end);
1673        break;
1674    }
1675  }
1676}
1677
1678
1679static void
1680final_reordering (const hb_ot_shape_plan_t *plan,
1681                  hb_font_t *font HB_UNUSED,
1682                  hb_buffer_t *buffer)
1683{
1684  unsigned int count = buffer->len;
1685  if (unlikely (!count)) return;
1686
1687  foreach_syllable (buffer, start, end)
1688    final_reordering_syllable (plan, buffer, start, end);
1689
1690  HB_BUFFER_DEALLOCATE_VAR (buffer, indic_category);
1691  HB_BUFFER_DEALLOCATE_VAR (buffer, indic_position);
1692}
1693
1694
1695static void
1696clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
1697                 hb_font_t *font HB_UNUSED,
1698                 hb_buffer_t *buffer)
1699{
1700  hb_glyph_info_t *info = buffer->info;
1701  unsigned int count = buffer->len;
1702  for (unsigned int i = 0; i < count; i++)
1703    info[i].syllable() = 0;
1704}
1705
1706
1707static bool
1708decompose_indic (const hb_ot_shape_normalize_context_t *c,
1709                 hb_codepoint_t  ab,
1710                 hb_codepoint_t *a,
1711                 hb_codepoint_t *b)
1712{
1713  switch (ab)
1714  {
1715    /* Don't decompose these. */
1716    case 0x0931u  : return false; /* DEVANAGARI LETTER RRA */
1717    case 0x0B94u  : return false; /* TAMIL LETTER AU */
1718
1719
1720    /*
1721     * Decompose split matras that don't have Unicode decompositions.
1722     */
1723
1724    /* Khmer */
1725    case 0x17BEu  : *a = 0x17C1u; *b= 0x17BEu; return true;
1726    case 0x17BFu  : *a = 0x17C1u; *b= 0x17BFu; return true;
1727    case 0x17C0u  : *a = 0x17C1u; *b= 0x17C0u; return true;
1728    case 0x17C4u  : *a = 0x17C1u; *b= 0x17C4u; return true;
1729    case 0x17C5u  : *a = 0x17C1u; *b= 0x17C5u; return true;
1730
1731#if 0
1732    /* Gujarati */
1733    /* This one has no decomposition in Unicode, but needs no decomposition either. */
1734    /* case 0x0AC9u  : return false; */
1735
1736    /* Oriya */
1737    case 0x0B57u  : *a = no decomp, -> RIGHT; return true;
1738#endif
1739  }
1740
1741  if ((ab == 0x0DDAu || hb_in_range (ab, 0x0DDCu, 0x0DDEu)))
1742  {
1743    /*
1744     * Sinhala split matras...  Let the fun begin.
1745     *
1746     * These four characters have Unicode decompositions.  However, Uniscribe
1747     * decomposes them "Khmer-style", that is, it uses the character itself to
1748     * get the second half.  The first half of all four decompositions is always
1749     * U+0DD9.
1750     *
1751     * Now, there are buggy fonts, namely, the widely used lklug.ttf, that are
1752     * broken with Uniscribe.  But we need to support them.  As such, we only
1753     * do the Uniscribe-style decomposition if the character is transformed into
1754     * its "sec.half" form by the 'pstf' feature.  Otherwise, we fall back to
1755     * Unicode decomposition.
1756     *
1757     * Note that we can't unconditionally use Unicode decomposition.  That would
1758     * break some other fonts, that are designed to work with Uniscribe, and
1759     * don't have positioning features for the Unicode-style decomposition.
1760     *
1761     * Argh...
1762     *
1763     * The Uniscribe behavior is now documented in the newly published Sinhala
1764     * spec in 2012:
1765     *
1766     *   http://www.microsoft.com/typography/OpenTypeDev/sinhala/intro.htm#shaping
1767     */
1768
1769    const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) c->plan->data;
1770
1771    hb_codepoint_t glyph;
1772
1773    if (hb_options ().uniscribe_bug_compatible ||
1774        (c->font->get_nominal_glyph (ab, &glyph) &&
1775         indic_plan->pstf.would_substitute (&glyph, 1, c->font->face)))
1776    {
1777      /* Ok, safe to use Uniscribe-style decomposition. */
1778      *a = 0x0DD9u;
1779      *b = ab;
1780      return true;
1781    }
1782  }
1783
1784  return (bool) c->unicode->decompose (ab, a, b);
1785}
1786
1787static bool
1788compose_indic (const hb_ot_shape_normalize_context_t *c,
1789               hb_codepoint_t  a,
1790               hb_codepoint_t  b,
1791               hb_codepoint_t *ab)
1792{
1793  /* Avoid recomposing split matras. */
1794  if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (c->unicode->general_category (a)))
1795    return false;
1796
1797  /* Composition-exclusion exceptions that we want to recompose. */
1798  if (a == 0x09AFu && b == 0x09BCu) { *ab = 0x09DFu; return true; }
1799
1800  return (bool) c->unicode->compose (a, b, ab);
1801}
1802
1803
1804const hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic =
1805{
1806  "indic",
1807  collect_features_indic,
1808  override_features_indic,
1809  data_create_indic,
1810  data_destroy_indic,
1811  NULL, /* preprocess_text */
1812  NULL, /* postprocess_glyphs */
1813  HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
1814  decompose_indic,
1815  compose_indic,
1816  setup_masks_indic,
1817  NULL, /* disable_otl */
1818  HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
1819  false, /* fallback_position */
1820};
1821