13eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod/*
2e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod * Copyright © 2010,2012  Google, Inc.
33eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod *
43eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod *  This is part of HarfBuzz, a text shaping library.
53eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod *
63eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod * Permission is hereby granted, without written agreement and without
73eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod * license or royalty fees, to use, copy, modify, and distribute this
83eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod * software and its documentation for any purpose, provided that the
93eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod * above copyright notice and the following two paragraphs appear in
103eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod * all copies of this software.
113eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod *
123eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
133eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
143eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
153eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
163eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod * DAMAGE.
173eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod *
183eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
193eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
203eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
213eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
223eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
233eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod *
243eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod * Google Author(s): Behdad Esfahbod
253eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod */
263eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod
2713403bc67a01e0d4908fb964093fd02ddd11c580Behdad Esfahbod#include "hb-ot-shape-complex-private.hh"
28d1deaa2f5bd028e8076265cba92cffa4fa2834acBehdad Esfahbod#include "hb-ot-shape-private.hh"
293eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod
303a852ae7fe6edfaadd75625d27515a3689503395Behdad Esfahbod
313a852ae7fe6edfaadd75625d27515a3689503395Behdad Esfahbod/* buffer var allocations */
32cd0c6e148f6d078b364370cb2f808b793b921be2Behdad Esfahbod#define arabic_shaping_action() complex_var_u8_0() /* arabic shaping action */
333a852ae7fe6edfaadd75625d27515a3689503395Behdad Esfahbod
343a852ae7fe6edfaadd75625d27515a3689503395Behdad Esfahbod
353eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod/*
363eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod * Bits used in the joining tables
373eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod */
383eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbodenum {
393eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod  JOINING_TYPE_U		= 0,
40c2a1cdc4c4cc51f4680ebc4ec2c462cb660f9492Behdad Esfahbod  JOINING_TYPE_L		= 1,
41c2a1cdc4c4cc51f4680ebc4ec2c462cb660f9492Behdad Esfahbod  JOINING_TYPE_R		= 2,
42c2a1cdc4c4cc51f4680ebc4ec2c462cb660f9492Behdad Esfahbod  JOINING_TYPE_D		= 3,
433eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod  JOINING_TYPE_C		= JOINING_TYPE_D,
44c2a1cdc4c4cc51f4680ebc4ec2c462cb660f9492Behdad Esfahbod  JOINING_GROUP_ALAPH		= 4,
45c2a1cdc4c4cc51f4680ebc4ec2c462cb660f9492Behdad Esfahbod  JOINING_GROUP_DALATH_RISH	= 5,
46c2a1cdc4c4cc51f4680ebc4ec2c462cb660f9492Behdad Esfahbod  NUM_STATE_MACHINE_COLS	= 6,
473eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod
48c2a1cdc4c4cc51f4680ebc4ec2c462cb660f9492Behdad Esfahbod  JOINING_TYPE_T = 7,
49c2a1cdc4c4cc51f4680ebc4ec2c462cb660f9492Behdad Esfahbod  JOINING_TYPE_X = 8  /* means: use general-category to choose between U or T. */
503eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod};
513eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod
523eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod/*
533eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod * Joining types:
543eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod */
553eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod
56c57d454accff66e5f2c58006e8fb40bc020b6182Behdad Esfahbod#include "hb-ot-shape-complex-arabic-table.hh"
573eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod
5899b74760a4cddc798ab44b5ca897486bbb9c76d6Behdad Esfahbodstatic unsigned int get_joining_type (hb_codepoint_t u, hb_unicode_general_category_t gen_cat)
593eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod{
60b900fa2c8cc088dbcbdbf90bfdf8764f9ee1c96aBehdad Esfahbod  unsigned int j_type = joining_type(u);
61b900fa2c8cc088dbcbdbf90bfdf8764f9ee1c96aBehdad Esfahbod  if (likely (j_type != JOINING_TYPE_X))
62b900fa2c8cc088dbcbdbf90bfdf8764f9ee1c96aBehdad Esfahbod    return j_type;
633eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod
645d4d7384efa97a30893ad28b9ad9a994722de12cBehdad Esfahbod  return (FLAG(gen_cat) &
655d4d7384efa97a30893ad28b9ad9a994722de12cBehdad Esfahbod	  (FLAG(HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) |
665d4d7384efa97a30893ad28b9ad9a994722de12cBehdad Esfahbod	   FLAG(HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) |
675d4d7384efa97a30893ad28b9ad9a994722de12cBehdad Esfahbod	   FLAG(HB_UNICODE_GENERAL_CATEGORY_FORMAT))
685d4d7384efa97a30893ad28b9ad9a994722de12cBehdad Esfahbod	 ) ?  JOINING_TYPE_T : JOINING_TYPE_U;
693eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod}
703eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod
71615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod#define FEATURE_IS_SYRIAC(tag) hb_in_range<unsigned char> ((unsigned char) (tag), '2', '3')
72615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod
73e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbodstatic const hb_tag_t arabic_features[] =
743eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod{
753eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod  HB_TAG('i','s','o','l'),
76615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod  HB_TAG('f','i','n','a'),
773eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod  HB_TAG('f','i','n','2'),
783eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod  HB_TAG('f','i','n','3'),
79615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod  HB_TAG('m','e','d','i'),
80615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod  HB_TAG('m','e','d','2'),
81615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod  HB_TAG('i','n','i','t'),
823eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod  HB_TAG_NONE
833eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod};
843eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod
853eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod
863eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod/* Same order as the feature array */
873eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbodenum {
883eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod  ISOL,
89615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod  FINA,
903eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod  FIN2,
913eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod  FIN3,
92615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod  MEDI,
93615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod  MED2,
94615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod  INIT,
953eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod
963eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod  NONE,
973eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod
98e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod  ARABIC_NUM_FEATURES = NONE
993eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod};
1003eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod
1013eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbodstatic const struct arabic_state_table_entry {
1023eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod	uint8_t prev_action;
1033eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod	uint8_t curr_action;
10431f18abecb149f8888a72510f2660328dd6de16dBehdad Esfahbod	uint16_t next_state;
1053eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod} arabic_state_table[][NUM_STATE_MACHINE_COLS] =
1063eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod{
107c2a1cdc4c4cc51f4680ebc4ec2c462cb660f9492Behdad Esfahbod  /*   jt_U,          jt_L,          jt_R,          jt_D,          jg_ALAPH,      jg_DALATH_RISH */
1083eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod
1093eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod  /* State 0: prev was U, not willing to join. */
110c2a1cdc4c4cc51f4680ebc4ec2c462cb660f9492Behdad Esfahbod  { {NONE,NONE,0}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,6}, },
1113eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod
1123eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod  /* State 1: prev was R or ISOL/ALAPH, not willing to join. */
113c2a1cdc4c4cc51f4680ebc4ec2c462cb660f9492Behdad Esfahbod  { {NONE,NONE,0}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,FIN2,5}, {NONE,ISOL,6}, },
1143eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod
115c2a1cdc4c4cc51f4680ebc4ec2c462cb660f9492Behdad Esfahbod  /* State 2: prev was D/L in ISOL form, willing to join. */
116c2a1cdc4c4cc51f4680ebc4ec2c462cb660f9492Behdad Esfahbod  { {NONE,NONE,0}, {NONE,ISOL,2}, {INIT,FINA,1}, {INIT,FINA,3}, {INIT,FINA,4}, {INIT,FINA,6}, },
1173eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod
118c2a1cdc4c4cc51f4680ebc4ec2c462cb660f9492Behdad Esfahbod  /* State 3: prev was D in FINA form, willing to join. */
119c2a1cdc4c4cc51f4680ebc4ec2c462cb660f9492Behdad Esfahbod  { {NONE,NONE,0}, {NONE,ISOL,2}, {MEDI,FINA,1}, {MEDI,FINA,3}, {MEDI,FINA,4}, {MEDI,FINA,6}, },
1203eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod
1213eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod  /* State 4: prev was FINA ALAPH, not willing to join. */
122c2a1cdc4c4cc51f4680ebc4ec2c462cb660f9492Behdad Esfahbod  { {NONE,NONE,0}, {NONE,ISOL,2}, {MED2,ISOL,1}, {MED2,ISOL,2}, {MED2,FIN2,5}, {MED2,ISOL,6}, },
1233eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod
1243eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod  /* State 5: prev was FIN2/FIN3 ALAPH, not willing to join. */
125c2a1cdc4c4cc51f4680ebc4ec2c462cb660f9492Behdad Esfahbod  { {NONE,NONE,0}, {NONE,ISOL,2}, {ISOL,ISOL,1}, {ISOL,ISOL,2}, {ISOL,FIN2,5}, {ISOL,ISOL,6}, },
1263eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod
1273eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod  /* State 6: prev was DALATH/RISH, not willing to join. */
128c2a1cdc4c4cc51f4680ebc4ec2c462cb660f9492Behdad Esfahbod  { {NONE,NONE,0}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,FIN3,5}, {NONE,ISOL,6}, }
1293eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod};
1303eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod
1313eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod
132fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbodstatic void
133c52ddab72e025d1bee8274c8f3416208b12f68f1Behdad Esfahbodnuke_joiners (const hb_ot_shape_plan_t *plan,
134c52ddab72e025d1bee8274c8f3416208b12f68f1Behdad Esfahbod	      hb_font_t *font,
135c52ddab72e025d1bee8274c8f3416208b12f68f1Behdad Esfahbod	      hb_buffer_t *buffer);
136c52ddab72e025d1bee8274c8f3416208b12f68f1Behdad Esfahbod
137c52ddab72e025d1bee8274c8f3416208b12f68f1Behdad Esfahbodstatic void
138fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbodarabic_fallback_shape (const hb_ot_shape_plan_t *plan,
139fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod		       hb_font_t *font,
140fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod		       hb_buffer_t *buffer);
14149baa1f69efb0e3c62e45bd59dd88459a84bf390Behdad Esfahbod
142693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodstatic void
14316c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbodcollect_features_arabic (hb_ot_shape_planner_t *plan)
14449baa1f69efb0e3c62e45bd59dd88459a84bf390Behdad Esfahbod{
14516c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod  hb_ot_map_builder_t *map = &plan->map;
14616c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod
147615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod  /* We apply features according to the Arabic spec, with pauses
148615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod   * in between most.
149b70c96dbe41d6512b80fe3d966a1942e1ef64a4bBehdad Esfahbod   *
150615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod   * The pause between init/medi/... and rlig is required.  See eg:
151b70c96dbe41d6512b80fe3d966a1942e1ef64a4bBehdad Esfahbod   * https://bugzilla.mozilla.org/show_bug.cgi?id=644184
15271b4c999a511bf018acaf48a45e070470c0daf12Behdad Esfahbod   *
153615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod   * The pauses between init/medi/... themselves are not necessarily
154615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod   * needed as only one of those features is applied to any character.
155615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod   * The only difference it makes is when fonts have contextual
156615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod   * substitutions.  We now follow the order of the spec, which makes
157615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod   * for better experience if that's what Uniscribe is doing.
158615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod   *
159615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod   * At least for Arabic, looks like Uniscribe has a pause between
160615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod   * rlig and calt.  Otherwise the IranNastaliq's ALLAH ligature won't
161615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod   * work.  However, testing shows that rlig and calt are applied
162615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod   * together for Mongolian in Uniscribe.  As such, we only add a
163615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod   * pause for Arabic, not other scripts.
164b70c96dbe41d6512b80fe3d966a1942e1ef64a4bBehdad Esfahbod   */
165b70c96dbe41d6512b80fe3d966a1942e1ef64a4bBehdad Esfahbod
166c52ddab72e025d1bee8274c8f3416208b12f68f1Behdad Esfahbod  map->add_gsub_pause (nuke_joiners);
167c52ddab72e025d1bee8274c8f3416208b12f68f1Behdad Esfahbod
168e7ffcfafb1108801ac504f18f820e497226bf07fBehdad Esfahbod  map->add_global_bool_feature (HB_TAG('c','c','m','p'));
169e7ffcfafb1108801ac504f18f820e497226bf07fBehdad Esfahbod  map->add_global_bool_feature (HB_TAG('l','o','c','l'));
170f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbod
1713e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod  map->add_gsub_pause (NULL);
172a71b9c8579d73aea4549f12524bbc2e89f43b5c5Behdad Esfahbod
173e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod  for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++)
174615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod  {
175615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod    bool has_fallback = plan->props.script == HB_SCRIPT_ARABIC && !FEATURE_IS_SYRIAC (arabic_features[i]);
176615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod    map->add_feature (arabic_features[i], 1, has_fallback ? F_HAS_FALLBACK : F_NONE);
177615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod    map->add_gsub_pause (NULL);
178615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod  }
179b70c96dbe41d6512b80fe3d966a1942e1ef64a4bBehdad Esfahbod
180ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod  map->add_feature (HB_TAG('r','l','i','g'), 1, F_GLOBAL|F_HAS_FALLBACK);
181615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod  if (plan->props.script == HB_SCRIPT_ARABIC)
182615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod    map->add_gsub_pause (arabic_fallback_shape);
183b70c96dbe41d6512b80fe3d966a1942e1ef64a4bBehdad Esfahbod
184e7ffcfafb1108801ac504f18f820e497226bf07fBehdad Esfahbod  map->add_global_bool_feature (HB_TAG('c','a','l','t'));
1853e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod  map->add_gsub_pause (NULL);
186b70c96dbe41d6512b80fe3d966a1942e1ef64a4bBehdad Esfahbod
18782f4d9d53f348f41b14b877c1ac77c0372c49caaBehdad Esfahbod  /* The spec includes 'cswh'.  Earlier versions of Windows
18882f4d9d53f348f41b14b877c1ac77c0372c49caaBehdad Esfahbod   * used to enable this by default, but testing suggests
18982f4d9d53f348f41b14b877c1ac77c0372c49caaBehdad Esfahbod   * that Windows 8 and later do not enable it by default,
19082f4d9d53f348f41b14b877c1ac77c0372c49caaBehdad Esfahbod   * and spec now says 'Off by default'.
19182f4d9d53f348f41b14b877c1ac77c0372c49caaBehdad Esfahbod   * We disabled this in ae23c24c32.
19282f4d9d53f348f41b14b877c1ac77c0372c49caaBehdad Esfahbod   * Note that IranNastaliq uses this feature extensively
19382f4d9d53f348f41b14b877c1ac77c0372c49caaBehdad Esfahbod   * to fixup broken glyph sequences.  Oh well...
19482f4d9d53f348f41b14b877c1ac77c0372c49caaBehdad Esfahbod   * Test case: U+0643,U+0640,U+0631. */
195e3b42f1af409c073b819bfc696024ccb1f1da63fBehdad Esfahbod  //map->add_global_bool_feature (HB_TAG('c','s','w','h'));
196e7ffcfafb1108801ac504f18f820e497226bf07fBehdad Esfahbod  map->add_global_bool_feature (HB_TAG('m','s','e','t'));
19749baa1f69efb0e3c62e45bd59dd88459a84bf390Behdad Esfahbod}
19849baa1f69efb0e3c62e45bd59dd88459a84bf390Behdad Esfahbod
199fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod#include "hb-ot-shape-complex-arabic-fallback.hh"
200fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod
201e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbodstruct arabic_shape_plan_t
202e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod{
203e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod  ASSERT_POD ();
204e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod
2052f1747ed7d28148807ad07eb8e22db3ab5c54966Behdad Esfahbod  /* The "+ 1" in the next array is to accommodate for the "NONE" command,
2062f1747ed7d28148807ad07eb8e22db3ab5c54966Behdad Esfahbod   * which is not an OpenType feature, but this simplifies the code by not
2072f1747ed7d28148807ad07eb8e22db3ab5c54966Behdad Esfahbod   * having to do a "if (... < NONE) ..." and just rely on the fact that
2082f1747ed7d28148807ad07eb8e22db3ab5c54966Behdad Esfahbod   * mask_array[NONE] == 0. */
209bd08d5d126aa878d1dbf7bfd4b1a764c170cd9adBehdad Esfahbod  hb_mask_t mask_array[ARABIC_NUM_FEATURES + 1];
210fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod
211fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod  bool do_fallback;
212fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod  arabic_fallback_plan_t *fallback_plan;
213e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod};
214e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod
215e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbodstatic void *
216e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahboddata_create_arabic (const hb_ot_shape_plan_t *plan)
217e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod{
218e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod  arabic_shape_plan_t *arabic_plan = (arabic_shape_plan_t *) calloc (1, sizeof (arabic_shape_plan_t));
219e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod  if (unlikely (!arabic_plan))
220e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod    return NULL;
221e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod
222fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod  arabic_plan->do_fallback = plan->props.script == HB_SCRIPT_ARABIC;
223e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod  for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++) {
224e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod    arabic_plan->mask_array[i] = plan->map.get_1_mask (arabic_features[i]);
225615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod    arabic_plan->do_fallback = arabic_plan->do_fallback &&
226615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod			       !FEATURE_IS_SYRIAC (arabic_features[i]) &&
227615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod			       plan->map.needs_fallback (arabic_features[i]);
228e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod  }
229e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod
230e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod  return arabic_plan;
231e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod}
232e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod
233e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbodstatic void
234e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahboddata_destroy_arabic (void *data)
235e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod{
236fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod  arabic_shape_plan_t *arabic_plan = (arabic_shape_plan_t *) data;
237939c010211b063f78874a3b72b032c1ed9a13b87Behdad Esfahbod
238fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod  arabic_fallback_plan_destroy (arabic_plan->fallback_plan);
2392fcbbdb41a322f54b61d9ce983ab54434504c5edBehdad Esfahbod
240fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod  free (data);
241b7d04eb606800100faa11100d2adf559e297a4eeBehdad Esfahbod}
242b7d04eb606800100faa11100d2adf559e297a4eeBehdad Esfahbod
243693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodstatic void
2449f9f04c2229227bb0712166e824157bbbf5cef80Behdad Esfahbodarabic_joining (hb_buffer_t *buffer)
2453eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod{
24676f76812ac7cca8ac6935952a2360d5e151480faBehdad Esfahbod  unsigned int count = buffer->len;
2477cd33f230441093dbfb1fec48f8c580ee8d9ef71Behdad Esfahbod  hb_glyph_info_t *info = buffer->info;
248bdc2fc8294da7f374701aafe9f5a82d60633946fBehdad Esfahbod  unsigned int prev = (unsigned int) -1, state = 0;
2493eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod
250bdc2fc8294da7f374701aafe9f5a82d60633946fBehdad Esfahbod  /* Check pre-context */
2510c7df2222862122ebbdc8665a21d6771ef5e0252Behdad Esfahbod  if (!(buffer->flags & HB_BUFFER_FLAG_BOT))
2520c7df2222862122ebbdc8665a21d6771ef5e0252Behdad Esfahbod    for (unsigned int i = 0; i < buffer->context_len[0]; i++)
2530c7df2222862122ebbdc8665a21d6771ef5e0252Behdad Esfahbod    {
2540c7df2222862122ebbdc8665a21d6771ef5e0252Behdad Esfahbod      unsigned int this_type = get_joining_type (buffer->context[0][i], buffer->unicode->general_category (buffer->context[0][i]));
255bdc2fc8294da7f374701aafe9f5a82d60633946fBehdad Esfahbod
2560c7df2222862122ebbdc8665a21d6771ef5e0252Behdad Esfahbod      if (unlikely (this_type == JOINING_TYPE_T))
2570c7df2222862122ebbdc8665a21d6771ef5e0252Behdad Esfahbod	continue;
258bdc2fc8294da7f374701aafe9f5a82d60633946fBehdad Esfahbod
2590c7df2222862122ebbdc8665a21d6771ef5e0252Behdad Esfahbod      const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
2600c7df2222862122ebbdc8665a21d6771ef5e0252Behdad Esfahbod      state = entry->next_state;
2610c7df2222862122ebbdc8665a21d6771ef5e0252Behdad Esfahbod      break;
2620c7df2222862122ebbdc8665a21d6771ef5e0252Behdad Esfahbod    }
263bdc2fc8294da7f374701aafe9f5a82d60633946fBehdad Esfahbod
264758f68b860b44b5a04eb3dde5cb40b1b04cf634aBehdad Esfahbod  for (unsigned int i = 0; i < count; i++)
265758f68b860b44b5a04eb3dde5cb40b1b04cf634aBehdad Esfahbod  {
2667cd33f230441093dbfb1fec48f8c580ee8d9ef71Behdad Esfahbod    unsigned int this_type = get_joining_type (info[i].codepoint, _hb_glyph_info_get_general_category (&info[i]));
2673eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod
268aefdb64689aab19df76590a36c4a04052a8bffdbBehdad Esfahbod    if (unlikely (this_type == JOINING_TYPE_T)) {
2697cd33f230441093dbfb1fec48f8c580ee8d9ef71Behdad Esfahbod      info[i].arabic_shaping_action() = NONE;
2703eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod      continue;
271aefdb64689aab19df76590a36c4a04052a8bffdbBehdad Esfahbod    }
2723eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod
273758f68b860b44b5a04eb3dde5cb40b1b04cf634aBehdad Esfahbod    const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
2743eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod
275bdc2fc8294da7f374701aafe9f5a82d60633946fBehdad Esfahbod    if (entry->prev_action != NONE && prev != (unsigned int) -1)
2767cd33f230441093dbfb1fec48f8c580ee8d9ef71Behdad Esfahbod      info[prev].arabic_shaping_action() = entry->prev_action;
2773eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod
2787cd33f230441093dbfb1fec48f8c580ee8d9ef71Behdad Esfahbod    info[i].arabic_shaping_action() = entry->curr_action;
2793eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod
2803eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod    prev = i;
2813eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod    state = entry->next_state;
2823eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod  }
2833eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod
2840c7df2222862122ebbdc8665a21d6771ef5e0252Behdad Esfahbod  if (!(buffer->flags & HB_BUFFER_FLAG_EOT))
2850c7df2222862122ebbdc8665a21d6771ef5e0252Behdad Esfahbod    for (unsigned int i = 0; i < buffer->context_len[1]; i++)
2860c7df2222862122ebbdc8665a21d6771ef5e0252Behdad Esfahbod    {
2875669a6cf418f3a8b9281c36e9d662d843be80433Behdad Esfahbod      unsigned int this_type = get_joining_type (buffer->context[1][i], buffer->unicode->general_category (buffer->context[1][i]));
288bdc2fc8294da7f374701aafe9f5a82d60633946fBehdad Esfahbod
2890c7df2222862122ebbdc8665a21d6771ef5e0252Behdad Esfahbod      if (unlikely (this_type == JOINING_TYPE_T))
2900c7df2222862122ebbdc8665a21d6771ef5e0252Behdad Esfahbod	continue;
291bdc2fc8294da7f374701aafe9f5a82d60633946fBehdad Esfahbod
2920c7df2222862122ebbdc8665a21d6771ef5e0252Behdad Esfahbod      const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
2930c7df2222862122ebbdc8665a21d6771ef5e0252Behdad Esfahbod      if (entry->prev_action != NONE && prev != (unsigned int) -1)
2947cd33f230441093dbfb1fec48f8c580ee8d9ef71Behdad Esfahbod	info[prev].arabic_shaping_action() = entry->prev_action;
2950c7df2222862122ebbdc8665a21d6771ef5e0252Behdad Esfahbod      break;
2960c7df2222862122ebbdc8665a21d6771ef5e0252Behdad Esfahbod    }
297164c13d73f67fdddba28e6409d76b4903e8ffab3Behdad Esfahbod}
298bdc2fc8294da7f374701aafe9f5a82d60633946fBehdad Esfahbod
299164c13d73f67fdddba28e6409d76b4903e8ffab3Behdad Esfahbodstatic void
300164c13d73f67fdddba28e6409d76b4903e8ffab3Behdad Esfahbodmongolian_variation_selectors (hb_buffer_t *buffer)
301164c13d73f67fdddba28e6409d76b4903e8ffab3Behdad Esfahbod{
302164c13d73f67fdddba28e6409d76b4903e8ffab3Behdad Esfahbod  /* Copy arabic_shaping_action() from base to Mongolian variation selectors. */
303164c13d73f67fdddba28e6409d76b4903e8ffab3Behdad Esfahbod  unsigned int count = buffer->len;
304164c13d73f67fdddba28e6409d76b4903e8ffab3Behdad Esfahbod  hb_glyph_info_t *info = buffer->info;
305164c13d73f67fdddba28e6409d76b4903e8ffab3Behdad Esfahbod  for (unsigned int i = 1; i < count; i++)
306164c13d73f67fdddba28e6409d76b4903e8ffab3Behdad Esfahbod    if (unlikely (hb_in_range (info[i].codepoint, 0x180Bu, 0x180Du)))
307164c13d73f67fdddba28e6409d76b4903e8ffab3Behdad Esfahbod      info[i].arabic_shaping_action() = info[i - 1].arabic_shaping_action();
3089f9f04c2229227bb0712166e824157bbbf5cef80Behdad Esfahbod}
3099f9f04c2229227bb0712166e824157bbbf5cef80Behdad Esfahbod
3109f9f04c2229227bb0712166e824157bbbf5cef80Behdad Esfahbodstatic void
311fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbodsetup_masks_arabic (const hb_ot_shape_plan_t *plan,
312fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod		    hb_buffer_t              *buffer,
3130beb66e3a61ae8bb1fa66e54b1ff1abb2f8711e9Behdad Esfahbod		    hb_font_t                *font HB_UNUSED)
3149f9f04c2229227bb0712166e824157bbbf5cef80Behdad Esfahbod{
315164c13d73f67fdddba28e6409d76b4903e8ffab3Behdad Esfahbod  HB_BUFFER_ALLOCATE_VAR (buffer, arabic_shaping_action);
316164c13d73f67fdddba28e6409d76b4903e8ffab3Behdad Esfahbod
3179f9f04c2229227bb0712166e824157bbbf5cef80Behdad Esfahbod  const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
3189f9f04c2229227bb0712166e824157bbbf5cef80Behdad Esfahbod
319fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod  arabic_joining (buffer);
320164c13d73f67fdddba28e6409d76b4903e8ffab3Behdad Esfahbod  if (plan->props.script == HB_SCRIPT_MONGOLIAN)
321164c13d73f67fdddba28e6409d76b4903e8ffab3Behdad Esfahbod    mongolian_variation_selectors (buffer);
322164c13d73f67fdddba28e6409d76b4903e8ffab3Behdad Esfahbod
323fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod  unsigned int count = buffer->len;
3247cd33f230441093dbfb1fec48f8c580ee8d9ef71Behdad Esfahbod  hb_glyph_info_t *info = buffer->info;
325fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod  for (unsigned int i = 0; i < count; i++)
3267cd33f230441093dbfb1fec48f8c580ee8d9ef71Behdad Esfahbod    info[i].mask |= arabic_plan->mask_array[info[i].arabic_shaping_action()];
327164c13d73f67fdddba28e6409d76b4903e8ffab3Behdad Esfahbod
328164c13d73f67fdddba28e6409d76b4903e8ffab3Behdad Esfahbod  HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action);
3299f9f04c2229227bb0712166e824157bbbf5cef80Behdad Esfahbod}
330b65c06025d2b54a44f716e030d4b10072c65bea8Behdad Esfahbod
331fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod
3329f9f04c2229227bb0712166e824157bbbf5cef80Behdad Esfahbodstatic void
333c52ddab72e025d1bee8274c8f3416208b12f68f1Behdad Esfahbodnuke_joiners (const hb_ot_shape_plan_t *plan HB_UNUSED,
334c52ddab72e025d1bee8274c8f3416208b12f68f1Behdad Esfahbod	      hb_font_t *font HB_UNUSED,
335c52ddab72e025d1bee8274c8f3416208b12f68f1Behdad Esfahbod	      hb_buffer_t *buffer)
336c52ddab72e025d1bee8274c8f3416208b12f68f1Behdad Esfahbod{
337c52ddab72e025d1bee8274c8f3416208b12f68f1Behdad Esfahbod  unsigned int count = buffer->len;
3387cd33f230441093dbfb1fec48f8c580ee8d9ef71Behdad Esfahbod  hb_glyph_info_t *info = buffer->info;
339c52ddab72e025d1bee8274c8f3416208b12f68f1Behdad Esfahbod  for (unsigned int i = 0; i < count; i++)
3407cd33f230441093dbfb1fec48f8c580ee8d9ef71Behdad Esfahbod    if (_hb_glyph_info_is_zwj (&info[i]))
3417cd33f230441093dbfb1fec48f8c580ee8d9ef71Behdad Esfahbod      _hb_glyph_info_flip_joiners (&info[i]);
342c52ddab72e025d1bee8274c8f3416208b12f68f1Behdad Esfahbod}
343c52ddab72e025d1bee8274c8f3416208b12f68f1Behdad Esfahbod
344c52ddab72e025d1bee8274c8f3416208b12f68f1Behdad Esfahbodstatic void
345fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbodarabic_fallback_shape (const hb_ot_shape_plan_t *plan,
346fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod		       hb_font_t *font,
347fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod		       hb_buffer_t *buffer)
3489f9f04c2229227bb0712166e824157bbbf5cef80Behdad Esfahbod{
3499f9f04c2229227bb0712166e824157bbbf5cef80Behdad Esfahbod  const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
3509f9f04c2229227bb0712166e824157bbbf5cef80Behdad Esfahbod
351fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod  if (!arabic_plan->do_fallback)
352fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod    return;
353fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod
354fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbodretry:
355fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod  arabic_fallback_plan_t *fallback_plan = (arabic_fallback_plan_t *) hb_atomic_ptr_get (&arabic_plan->fallback_plan);
356fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod  if (unlikely (!fallback_plan))
3579f9f04c2229227bb0712166e824157bbbf5cef80Behdad Esfahbod  {
358fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod    /* This sucks.  We need a font to build the fallback plan... */
359fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod    fallback_plan = arabic_fallback_plan_create (plan, font);
360fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod    if (unlikely (!hb_atomic_ptr_cmpexch (&(const_cast<arabic_shape_plan_t *> (arabic_plan))->fallback_plan, NULL, fallback_plan))) {
361fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod      arabic_fallback_plan_destroy (fallback_plan);
362fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod      goto retry;
363fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod    }
3649f9f04c2229227bb0712166e824157bbbf5cef80Behdad Esfahbod  }
365fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod
366fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod  arabic_fallback_plan_shape (fallback_plan, font, buffer);
3673eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod}
3683eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod
369fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod
370693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodconst hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic =
371693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod{
372693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod  "arabic",
373693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod  collect_features_arabic,
374693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod  NULL, /* override_features */
375e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod  data_create_arabic,
376e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod  data_destroy_arabic,
377fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod  NULL, /* preprocess_text_arabic */
3783d6ca0d32e5c6597acfcf59301cb1905586ddb52Behdad Esfahbod  HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
3790736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod  NULL, /* decompose */
3800736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod  NULL, /* compose */
381693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod  setup_masks_arabic,
38271b4c999a511bf018acaf48a45e070470c0daf12Behdad Esfahbod  HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
383865745b5b87236651f5663cae3461db9cb505eedBehdad Esfahbod  true, /* fallback_position */
384693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod};
385