blob: b7aa694cb6bed86dfd2d52ea0f17047451dbcf75 [file] [log] [blame]
Behdad Esfahbod3eb936f2010-10-05 18:36:58 -04001/*
Behdad Esfahbode9f28a32012-08-11 18:20:28 -04002 * Copyright © 2010,2012 Google, Inc.
Behdad Esfahbod3eb936f2010-10-05 18:36:58 -04003 *
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
Behdad Esfahbod13403bc2010-10-12 17:23:54 -040027#include "hb-ot-shape-complex-private.hh"
Behdad Esfahbodd1deaa22012-05-09 15:04:13 +020028#include "hb-ot-shape-private.hh"
Behdad Esfahbod3eb936f2010-10-05 18:36:58 -040029
Behdad Esfahbod3a852ae2010-11-03 16:37:24 -040030
31/* buffer var allocations */
Behdad Esfahbodcd0c6e12012-08-09 21:48:55 -040032#define arabic_shaping_action() complex_var_u8_0() /* arabic shaping action */
Behdad Esfahbod3a852ae2010-11-03 16:37:24 -040033
34
Behdad Esfahbod3eb936f2010-10-05 18:36:58 -040035/*
36 * Bits used in the joining tables
37 */
38enum {
39 JOINING_TYPE_U = 0,
Behdad Esfahbodc2a1cdc2013-02-15 09:27:02 -050040 JOINING_TYPE_L = 1,
41 JOINING_TYPE_R = 2,
42 JOINING_TYPE_D = 3,
Behdad Esfahbod3eb936f2010-10-05 18:36:58 -040043 JOINING_TYPE_C = JOINING_TYPE_D,
Behdad Esfahbodc2a1cdc2013-02-15 09:27:02 -050044 JOINING_GROUP_ALAPH = 4,
45 JOINING_GROUP_DALATH_RISH = 5,
46 NUM_STATE_MACHINE_COLS = 6,
Behdad Esfahbod3eb936f2010-10-05 18:36:58 -040047
Behdad Esfahbodc2a1cdc2013-02-15 09:27:02 -050048 JOINING_TYPE_T = 7,
49 JOINING_TYPE_X = 8 /* means: use general-category to choose between U or T. */
Behdad Esfahbod3eb936f2010-10-05 18:36:58 -040050};
51
52/*
53 * Joining types:
54 */
55
Behdad Esfahbodc57d4542011-04-20 18:50:27 -040056#include "hb-ot-shape-complex-arabic-table.hh"
Behdad Esfahbod3eb936f2010-10-05 18:36:58 -040057
Behdad Esfahbod99b74762011-04-11 15:47:40 -040058static unsigned int get_joining_type (hb_codepoint_t u, hb_unicode_general_category_t gen_cat)
Behdad Esfahbod3eb936f2010-10-05 18:36:58 -040059{
Behdad Esfahbodb900fa22014-06-20 17:59:43 -040060 unsigned int j_type = joining_type(u);
61 if (likely (j_type != JOINING_TYPE_X))
62 return j_type;
Behdad Esfahbod3eb936f2010-10-05 18:36:58 -040063
Behdad Esfahbod5d4d7382014-06-21 14:53:21 -060064 return (FLAG(gen_cat) &
65 (FLAG(HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) |
66 FLAG(HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) |
67 FLAG(HB_UNICODE_GENERAL_CATEGORY_FORMAT))
68 ) ? JOINING_TYPE_T : JOINING_TYPE_U;
Behdad Esfahbod3eb936f2010-10-05 18:36:58 -040069}
70
Behdad Esfahbode9f28a32012-08-11 18:20:28 -040071static const hb_tag_t arabic_features[] =
Behdad Esfahbod3eb936f2010-10-05 18:36:58 -040072{
73 HB_TAG('i','n','i','t'),
74 HB_TAG('m','e','d','i'),
75 HB_TAG('f','i','n','a'),
76 HB_TAG('i','s','o','l'),
77 /* Syriac */
78 HB_TAG('m','e','d','2'),
79 HB_TAG('f','i','n','2'),
80 HB_TAG('f','i','n','3'),
81 HB_TAG_NONE
82};
83
84
85/* Same order as the feature array */
86enum {
87 INIT,
88 MEDI,
89 FINA,
90 ISOL,
91
92 /* Syriac */
93 MED2,
94 FIN2,
95 FIN3,
96
97 NONE,
98
Behdad Esfahbode9f28a32012-08-11 18:20:28 -040099 ARABIC_NUM_FEATURES = NONE
Behdad Esfahbod3eb936f2010-10-05 18:36:58 -0400100};
101
102static const struct arabic_state_table_entry {
103 uint8_t prev_action;
104 uint8_t curr_action;
Behdad Esfahbod31f18ab2011-06-15 09:49:58 -0400105 uint16_t next_state;
Behdad Esfahbod3eb936f2010-10-05 18:36:58 -0400106} arabic_state_table[][NUM_STATE_MACHINE_COLS] =
107{
Behdad Esfahbodc2a1cdc2013-02-15 09:27:02 -0500108 /* jt_U, jt_L, jt_R, jt_D, jg_ALAPH, jg_DALATH_RISH */
Behdad Esfahbod3eb936f2010-10-05 18:36:58 -0400109
110 /* State 0: prev was U, not willing to join. */
Behdad Esfahbodc2a1cdc2013-02-15 09:27:02 -0500111 { {NONE,NONE,0}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,6}, },
Behdad Esfahbod3eb936f2010-10-05 18:36:58 -0400112
113 /* State 1: prev was R or ISOL/ALAPH, not willing to join. */
Behdad Esfahbodc2a1cdc2013-02-15 09:27:02 -0500114 { {NONE,NONE,0}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,FIN2,5}, {NONE,ISOL,6}, },
Behdad Esfahbod3eb936f2010-10-05 18:36:58 -0400115
Behdad Esfahbodc2a1cdc2013-02-15 09:27:02 -0500116 /* State 2: prev was D/L in ISOL form, willing to join. */
117 { {NONE,NONE,0}, {NONE,ISOL,2}, {INIT,FINA,1}, {INIT,FINA,3}, {INIT,FINA,4}, {INIT,FINA,6}, },
Behdad Esfahbod3eb936f2010-10-05 18:36:58 -0400118
Behdad Esfahbodc2a1cdc2013-02-15 09:27:02 -0500119 /* State 3: prev was D in FINA form, willing to join. */
120 { {NONE,NONE,0}, {NONE,ISOL,2}, {MEDI,FINA,1}, {MEDI,FINA,3}, {MEDI,FINA,4}, {MEDI,FINA,6}, },
Behdad Esfahbod3eb936f2010-10-05 18:36:58 -0400121
122 /* State 4: prev was FINA ALAPH, not willing to join. */
Behdad Esfahbodc2a1cdc2013-02-15 09:27:02 -0500123 { {NONE,NONE,0}, {NONE,ISOL,2}, {MED2,ISOL,1}, {MED2,ISOL,2}, {MED2,FIN2,5}, {MED2,ISOL,6}, },
Behdad Esfahbod3eb936f2010-10-05 18:36:58 -0400124
125 /* State 5: prev was FIN2/FIN3 ALAPH, not willing to join. */
Behdad Esfahbodc2a1cdc2013-02-15 09:27:02 -0500126 { {NONE,NONE,0}, {NONE,ISOL,2}, {ISOL,ISOL,1}, {ISOL,ISOL,2}, {ISOL,FIN2,5}, {ISOL,ISOL,6}, },
Behdad Esfahbod3eb936f2010-10-05 18:36:58 -0400127
128 /* State 6: prev was DALATH/RISH, not willing to join. */
Behdad Esfahbodc2a1cdc2013-02-15 09:27:02 -0500129 { {NONE,NONE,0}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,FIN3,5}, {NONE,ISOL,6}, }
Behdad Esfahbod3eb936f2010-10-05 18:36:58 -0400130};
131
132
Behdad Esfahbodfabd3112012-09-05 22:19:28 -0400133static void
Behdad Esfahbodc52ddab2013-10-16 13:42:38 +0200134nuke_joiners (const hb_ot_shape_plan_t *plan,
135 hb_font_t *font,
136 hb_buffer_t *buffer);
137
138static void
Behdad Esfahbodfabd3112012-09-05 22:19:28 -0400139arabic_fallback_shape (const hb_ot_shape_plan_t *plan,
140 hb_font_t *font,
141 hb_buffer_t *buffer);
Behdad Esfahbod49baa1f2010-10-12 16:50:36 -0400142
Behdad Esfahbod693918e2012-07-30 21:08:51 -0400143static void
Behdad Esfahbod16c6a272012-08-02 09:38:28 -0400144collect_features_arabic (hb_ot_shape_planner_t *plan)
Behdad Esfahbod49baa1f2010-10-12 16:50:36 -0400145{
Behdad Esfahbod16c6a272012-08-02 09:38:28 -0400146 hb_ot_map_builder_t *map = &plan->map;
147
Behdad Esfahbodb70c96d2011-07-07 21:07:41 -0400148 /* For Language forms (in ArabicOT speak), we do the iso/fina/medi/init together,
149 * then rlig and calt each in their own stage. This makes IranNastaliq's ALLAH
150 * ligature work correctly. It's unfortunate though...
151 *
152 * This also makes Arial Bold in Windows7 work. See:
153 * https://bugzilla.mozilla.org/show_bug.cgi?id=644184
Behdad Esfahbod71b4c992013-10-28 00:20:59 +0100154 *
155 * TODO: Add test cases for these two.
Behdad Esfahbodb70c96d2011-07-07 21:07:41 -0400156 */
157
Behdad Esfahbodc52ddab2013-10-16 13:42:38 +0200158 map->add_gsub_pause (nuke_joiners);
159
Behdad Esfahbode7ffcfa2013-02-14 11:05:56 -0500160 map->add_global_bool_feature (HB_TAG('c','c','m','p'));
161 map->add_global_bool_feature (HB_TAG('l','o','c','l'));
Behdad Esfahbodf6fd3782011-07-08 00:22:40 -0400162
Behdad Esfahbod3e38c0f2012-08-02 09:44:18 -0400163 map->add_gsub_pause (NULL);
Behdad Esfahboda71b9c82011-04-06 14:04:56 -0400164
Behdad Esfahbode9f28a32012-08-11 18:20:28 -0400165 for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++)
Behdad Esfahbodec544862013-02-14 11:25:10 -0500166 map->add_feature (arabic_features[i], 1, i < 4 ? F_HAS_FALLBACK : F_NONE); /* The first four features have fallback. */
Behdad Esfahbodb70c96d2011-07-07 21:07:41 -0400167
Behdad Esfahbod3e38c0f2012-08-02 09:44:18 -0400168 map->add_gsub_pause (NULL);
Behdad Esfahbodb70c96d2011-07-07 21:07:41 -0400169
Behdad Esfahbodec544862013-02-14 11:25:10 -0500170 map->add_feature (HB_TAG('r','l','i','g'), 1, F_GLOBAL|F_HAS_FALLBACK);
Behdad Esfahbodfabd3112012-09-05 22:19:28 -0400171 map->add_gsub_pause (arabic_fallback_shape);
Behdad Esfahbodb70c96d2011-07-07 21:07:41 -0400172
Behdad Esfahbode7ffcfa2013-02-14 11:05:56 -0500173 map->add_global_bool_feature (HB_TAG('c','a','l','t'));
Behdad Esfahbod3e38c0f2012-08-02 09:44:18 -0400174 map->add_gsub_pause (NULL);
Behdad Esfahbodb70c96d2011-07-07 21:07:41 -0400175
Behdad Esfahbode7ffcfa2013-02-14 11:05:56 -0500176 map->add_global_bool_feature (HB_TAG('m','s','e','t'));
Behdad Esfahbod49baa1f2010-10-12 16:50:36 -0400177}
178
Behdad Esfahbodfabd3112012-09-05 22:19:28 -0400179#include "hb-ot-shape-complex-arabic-fallback.hh"
180
Behdad Esfahbode9f28a32012-08-11 18:20:28 -0400181struct arabic_shape_plan_t
182{
183 ASSERT_POD ();
184
Behdad Esfahbod2f1747e2012-08-16 11:46:46 -0400185 /* The "+ 1" in the next array is to accommodate for the "NONE" command,
186 * which is not an OpenType feature, but this simplifies the code by not
187 * having to do a "if (... < NONE) ..." and just rely on the fact that
188 * mask_array[NONE] == 0. */
Behdad Esfahbodbd08d5d2012-08-16 11:35:50 -0400189 hb_mask_t mask_array[ARABIC_NUM_FEATURES + 1];
Behdad Esfahbodfabd3112012-09-05 22:19:28 -0400190
191 bool do_fallback;
192 arabic_fallback_plan_t *fallback_plan;
Behdad Esfahbode9f28a32012-08-11 18:20:28 -0400193};
194
195static void *
196data_create_arabic (const hb_ot_shape_plan_t *plan)
197{
198 arabic_shape_plan_t *arabic_plan = (arabic_shape_plan_t *) calloc (1, sizeof (arabic_shape_plan_t));
199 if (unlikely (!arabic_plan))
200 return NULL;
201
Behdad Esfahbodfabd3112012-09-05 22:19:28 -0400202 arabic_plan->do_fallback = plan->props.script == HB_SCRIPT_ARABIC;
Behdad Esfahbode9f28a32012-08-11 18:20:28 -0400203 for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++) {
204 arabic_plan->mask_array[i] = plan->map.get_1_mask (arabic_features[i]);
Behdad Esfahbodfabd3112012-09-05 22:19:28 -0400205 if (i < 4)
206 arabic_plan->do_fallback = arabic_plan->do_fallback && plan->map.needs_fallback (arabic_features[i]);
Behdad Esfahbode9f28a32012-08-11 18:20:28 -0400207 }
208
Behdad Esfahbode9f28a32012-08-11 18:20:28 -0400209 return arabic_plan;
210}
211
212static void
213data_destroy_arabic (void *data)
214{
Behdad Esfahbodfabd3112012-09-05 22:19:28 -0400215 arabic_shape_plan_t *arabic_plan = (arabic_shape_plan_t *) data;
216
217 arabic_fallback_plan_destroy (arabic_plan->fallback_plan);
218
Behdad Esfahbode9f28a32012-08-11 18:20:28 -0400219 free (data);
220}
Behdad Esfahbodb7d04eb2012-04-10 16:44:38 -0400221
222static void
Behdad Esfahbod9f9f04c2012-08-11 18:34:13 -0400223arabic_joining (hb_buffer_t *buffer)
Behdad Esfahbod3eb936f2010-10-05 18:36:58 -0400224{
Behdad Esfahbod76f76812011-07-07 22:25:25 -0400225 unsigned int count = buffer->len;
Behdad Esfahbodbdc2fc82012-09-25 21:32:35 -0400226 unsigned int prev = (unsigned int) -1, state = 0;
Behdad Esfahbod3eb936f2010-10-05 18:36:58 -0400227
Behdad Esfahbodb65c0602011-07-28 16:48:43 -0400228 HB_BUFFER_ALLOCATE_VAR (buffer, arabic_shaping_action);
229
Behdad Esfahbodbdc2fc82012-09-25 21:32:35 -0400230 /* Check pre-context */
Behdad Esfahbod0c7df222012-11-13 14:42:35 -0800231 if (!(buffer->flags & HB_BUFFER_FLAG_BOT))
232 for (unsigned int i = 0; i < buffer->context_len[0]; i++)
233 {
234 unsigned int this_type = get_joining_type (buffer->context[0][i], buffer->unicode->general_category (buffer->context[0][i]));
Behdad Esfahbodbdc2fc82012-09-25 21:32:35 -0400235
Behdad Esfahbod0c7df222012-11-13 14:42:35 -0800236 if (unlikely (this_type == JOINING_TYPE_T))
237 continue;
Behdad Esfahbodbdc2fc82012-09-25 21:32:35 -0400238
Behdad Esfahbod0c7df222012-11-13 14:42:35 -0800239 const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
240 state = entry->next_state;
241 break;
242 }
Behdad Esfahbodbdc2fc82012-09-25 21:32:35 -0400243
Behdad Esfahbod758f68b2010-10-12 17:37:44 -0400244 for (unsigned int i = 0; i < count; i++)
245 {
Behdad Esfahbodd1deaa22012-05-09 15:04:13 +0200246 unsigned int this_type = get_joining_type (buffer->info[i].codepoint, _hb_glyph_info_get_general_category (&buffer->info[i]));
Behdad Esfahbod3eb936f2010-10-05 18:36:58 -0400247
Behdad Esfahbodaefdb642010-10-27 10:40:39 -0400248 if (unlikely (this_type == JOINING_TYPE_T)) {
Behdad Esfahbod76f76812011-07-07 22:25:25 -0400249 buffer->info[i].arabic_shaping_action() = NONE;
Behdad Esfahbod3eb936f2010-10-05 18:36:58 -0400250 continue;
Behdad Esfahbodaefdb642010-10-27 10:40:39 -0400251 }
Behdad Esfahbod3eb936f2010-10-05 18:36:58 -0400252
Behdad Esfahbod758f68b2010-10-12 17:37:44 -0400253 const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
Behdad Esfahbod3eb936f2010-10-05 18:36:58 -0400254
Behdad Esfahbodbdc2fc82012-09-25 21:32:35 -0400255 if (entry->prev_action != NONE && prev != (unsigned int) -1)
Behdad Esfahbodbf029282013-10-18 16:20:13 +0200256 for (; prev < i; prev++)
257 buffer->info[prev].arabic_shaping_action() = entry->prev_action;
Behdad Esfahbod3eb936f2010-10-05 18:36:58 -0400258
Behdad Esfahbod76f76812011-07-07 22:25:25 -0400259 buffer->info[i].arabic_shaping_action() = entry->curr_action;
Behdad Esfahbod3eb936f2010-10-05 18:36:58 -0400260
261 prev = i;
262 state = entry->next_state;
263 }
264
Behdad Esfahbod0c7df222012-11-13 14:42:35 -0800265 if (!(buffer->flags & HB_BUFFER_FLAG_EOT))
266 for (unsigned int i = 0; i < buffer->context_len[1]; i++)
267 {
Behdad Esfahbod5669a6c2012-11-13 15:11:51 -0800268 unsigned int this_type = get_joining_type (buffer->context[1][i], buffer->unicode->general_category (buffer->context[1][i]));
Behdad Esfahbodbdc2fc82012-09-25 21:32:35 -0400269
Behdad Esfahbod0c7df222012-11-13 14:42:35 -0800270 if (unlikely (this_type == JOINING_TYPE_T))
271 continue;
Behdad Esfahbodbdc2fc82012-09-25 21:32:35 -0400272
Behdad Esfahbod0c7df222012-11-13 14:42:35 -0800273 const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
274 if (entry->prev_action != NONE && prev != (unsigned int) -1)
275 buffer->info[prev].arabic_shaping_action() = entry->prev_action;
276 break;
277 }
Behdad Esfahbodbdc2fc82012-09-25 21:32:35 -0400278
279
Behdad Esfahbod9f9f04c2012-08-11 18:34:13 -0400280 HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action);
281}
282
283static void
Behdad Esfahbod9f9f04c2012-08-11 18:34:13 -0400284setup_masks_arabic (const hb_ot_shape_plan_t *plan,
285 hb_buffer_t *buffer,
Behdad Esfahbod0beb66e2012-12-05 18:46:04 -0500286 hb_font_t *font HB_UNUSED)
Behdad Esfahbod9f9f04c2012-08-11 18:34:13 -0400287{
288 const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
289
Behdad Esfahbodfabd3112012-09-05 22:19:28 -0400290 arabic_joining (buffer);
291 unsigned int count = buffer->len;
292 for (unsigned int i = 0; i < count; i++)
293 buffer->info[i].mask |= arabic_plan->mask_array[buffer->info[i].arabic_shaping_action()];
Behdad Esfahbod3eb936f2010-10-05 18:36:58 -0400294}
295
Behdad Esfahbodfabd3112012-09-05 22:19:28 -0400296
297static void
Behdad Esfahbodc52ddab2013-10-16 13:42:38 +0200298nuke_joiners (const hb_ot_shape_plan_t *plan HB_UNUSED,
299 hb_font_t *font HB_UNUSED,
300 hb_buffer_t *buffer)
301{
302 unsigned int count = buffer->len;
303 for (unsigned int i = 0; i < count; i++)
304 if (_hb_glyph_info_is_zwj (&buffer->info[i]))
305 _hb_glyph_info_flip_joiners (&buffer->info[i]);
306}
307
308static void
Behdad Esfahbodfabd3112012-09-05 22:19:28 -0400309arabic_fallback_shape (const hb_ot_shape_plan_t *plan,
310 hb_font_t *font,
311 hb_buffer_t *buffer)
312{
313 const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
314
315 if (!arabic_plan->do_fallback)
316 return;
317
318retry:
319 arabic_fallback_plan_t *fallback_plan = (arabic_fallback_plan_t *) hb_atomic_ptr_get (&arabic_plan->fallback_plan);
320 if (unlikely (!fallback_plan))
321 {
322 /* This sucks. We need a font to build the fallback plan... */
323 fallback_plan = arabic_fallback_plan_create (plan, font);
324 if (unlikely (!hb_atomic_ptr_cmpexch (&(const_cast<arabic_shape_plan_t *> (arabic_plan))->fallback_plan, NULL, fallback_plan))) {
325 arabic_fallback_plan_destroy (fallback_plan);
326 goto retry;
327 }
328 }
329
330 arabic_fallback_plan_shape (fallback_plan, font, buffer);
331}
332
333
Behdad Esfahbod693918e2012-07-30 21:08:51 -0400334const hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic =
335{
336 "arabic",
337 collect_features_arabic,
338 NULL, /* override_features */
Behdad Esfahbode9f28a32012-08-11 18:20:28 -0400339 data_create_arabic,
340 data_destroy_arabic,
Behdad Esfahbodfabd3112012-09-05 22:19:28 -0400341 NULL, /* preprocess_text_arabic */
Behdad Esfahbod3d6ca0d2013-12-31 16:04:35 +0800342 HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
Behdad Esfahbod07369152012-11-13 12:35:35 -0800343 NULL, /* decompose */
344 NULL, /* compose */
Behdad Esfahbod693918e2012-07-30 21:08:51 -0400345 setup_masks_arabic,
Behdad Esfahbod71b4c992013-10-28 00:20:59 +0100346 HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
Behdad Esfahbod865745b2012-11-14 13:48:26 -0800347 true, /* fallback_position */
Behdad Esfahbod693918e2012-07-30 21:08:51 -0400348};