src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-arabic.cc
changeset 48274 51772bf1fb0c
parent 47216 71c04702a3d5
child 50352 25db2c8f3cf8
equal deleted inserted replaced
48273:e2065f7505eb 48274:51772bf1fb0c
    22  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
    22  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
    23  *
    23  *
    24  * Google Author(s): Behdad Esfahbod
    24  * Google Author(s): Behdad Esfahbod
    25  */
    25  */
    26 
    26 
       
    27 #include "hb-private.hh"
       
    28 #include "hb-debug.hh"
    27 #include "hb-ot-shape-complex-arabic-private.hh"
    29 #include "hb-ot-shape-complex-arabic-private.hh"
    28 #include "hb-ot-shape-private.hh"
    30 #include "hb-ot-shape-private.hh"
    29 
       
    30 
       
    31 #ifndef HB_DEBUG_ARABIC
       
    32 #define HB_DEBUG_ARABIC (HB_DEBUG+0)
       
    33 #endif
       
    34 
    31 
    35 
    32 
    36 /* buffer var allocations */
    33 /* buffer var allocations */
    37 #define arabic_shaping_action() complex_var_u8_0() /* arabic shaping action */
    34 #define arabic_shaping_action() complex_var_u8_0() /* arabic shaping action */
    38 
    35 
    39 #define HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH HB_BUFFER_SCRATCH_FLAG_COMPLEX0
    36 #define HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH HB_BUFFER_SCRATCH_FLAG_COMPLEX0
    40 
    37 
    41 /* See:
    38 /* See:
    42  * https://github.com/behdad/harfbuzz/commit/6e6f82b6f3dde0fc6c3c7d991d9ec6cfff57823d#commitcomment-14248516 */
    39  * https://github.com/behdad/harfbuzz/commit/6e6f82b6f3dde0fc6c3c7d991d9ec6cfff57823d#commitcomment-14248516 */
    43 #define HB_ARABIC_GENERAL_CATEGORY_IS_WORD(gen_cat) \
    40 #define HB_ARABIC_GENERAL_CATEGORY_IS_WORD(gen_cat) \
    44         (FLAG_SAFE (gen_cat) & \
    41         (FLAG_UNSAFE (gen_cat) & \
    45          (FLAG (HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED) | \
    42          (FLAG (HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED) | \
    46           FLAG (HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE) | \
    43           FLAG (HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE) | \
    47           /*FLAG (HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER) |*/ \
    44           /*FLAG (HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER) |*/ \
    48           FLAG (HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER) | \
    45           FLAG (HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER) | \
    49           FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER) | \
    46           FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER) | \
    88 {
    85 {
    89   unsigned int j_type = joining_type(u);
    86   unsigned int j_type = joining_type(u);
    90   if (likely (j_type != JOINING_TYPE_X))
    87   if (likely (j_type != JOINING_TYPE_X))
    91     return j_type;
    88     return j_type;
    92 
    89 
    93   return (FLAG_SAFE(gen_cat) &
    90   return (FLAG_UNSAFE(gen_cat) &
    94           (FLAG(HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) |
    91           (FLAG(HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) |
    95            FLAG(HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) |
    92            FLAG(HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) |
    96            FLAG(HB_UNICODE_GENERAL_CATEGORY_FORMAT))
    93            FLAG(HB_UNICODE_GENERAL_CATEGORY_FORMAT))
    97          ) ?  JOINING_TYPE_T : JOINING_TYPE_U;
    94          ) ?  JOINING_TYPE_T : JOINING_TYPE_U;
    98 }
    95 }
   197    * At least for Arabic, looks like Uniscribe has a pause between
   194    * At least for Arabic, looks like Uniscribe has a pause between
   198    * rlig and calt.  Otherwise the IranNastaliq's ALLAH ligature won't
   195    * rlig and calt.  Otherwise the IranNastaliq's ALLAH ligature won't
   199    * work.  However, testing shows that rlig and calt are applied
   196    * work.  However, testing shows that rlig and calt are applied
   200    * together for Mongolian in Uniscribe.  As such, we only add a
   197    * together for Mongolian in Uniscribe.  As such, we only add a
   201    * pause for Arabic, not other scripts.
   198    * pause for Arabic, not other scripts.
       
   199    *
       
   200    * A pause after calt is required to make KFGQPC Uthmanic Script HAFS
       
   201    * work correctly.  See https://github.com/behdad/harfbuzz/issues/505
   202    */
   202    */
   203 
   203 
   204   map->add_gsub_pause (nuke_joiners);
   204   map->add_gsub_pause (nuke_joiners);
   205 
   205 
   206   map->add_global_bool_feature (HB_TAG('s','t','c','h'));
   206   map->add_global_bool_feature (HB_TAG('s','t','c','h'));
   207   map->add_gsub_pause (record_stch);
   207   map->add_gsub_pause (record_stch);
   208 
   208 
   209   map->add_global_bool_feature (HB_TAG('c','c','m','p'));
   209   map->add_global_bool_feature (HB_TAG('c','c','m','p'));
   210   map->add_global_bool_feature (HB_TAG('l','o','c','l'));
   210   map->add_global_bool_feature (HB_TAG('l','o','c','l'));
   211 
   211 
   212   map->add_gsub_pause (NULL);
   212   map->add_gsub_pause (nullptr);
   213 
   213 
   214   for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++)
   214   for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++)
   215   {
   215   {
   216     bool has_fallback = plan->props.script == HB_SCRIPT_ARABIC && !FEATURE_IS_SYRIAC (arabic_features[i]);
   216     bool has_fallback = plan->props.script == HB_SCRIPT_ARABIC && !FEATURE_IS_SYRIAC (arabic_features[i]);
   217     map->add_feature (arabic_features[i], 1, has_fallback ? F_HAS_FALLBACK : F_NONE);
   217     map->add_feature (arabic_features[i], 1, has_fallback ? F_HAS_FALLBACK : F_NONE);
   218     map->add_gsub_pause (NULL);
   218     map->add_gsub_pause (nullptr);
   219   }
   219   }
   220 
   220 
   221   map->add_feature (HB_TAG('r','l','i','g'), 1, F_GLOBAL|F_HAS_FALLBACK);
   221   map->add_feature (HB_TAG('r','l','i','g'), 1, F_GLOBAL|F_HAS_FALLBACK);
   222   if (plan->props.script == HB_SCRIPT_ARABIC)
   222   if (plan->props.script == HB_SCRIPT_ARABIC)
   223     map->add_gsub_pause (arabic_fallback_shape);
   223     map->add_gsub_pause (arabic_fallback_shape);
   224 
   224 
       
   225   /* No pause after rclt.  See 98460779bae19e4d64d29461ff154b3527bf8420. */
       
   226   map->add_global_bool_feature (HB_TAG('r','c','l','t'));
   225   map->add_global_bool_feature (HB_TAG('c','a','l','t'));
   227   map->add_global_bool_feature (HB_TAG('c','a','l','t'));
       
   228   map->add_gsub_pause (nullptr);
   226 
   229 
   227   /* The spec includes 'cswh'.  Earlier versions of Windows
   230   /* The spec includes 'cswh'.  Earlier versions of Windows
   228    * used to enable this by default, but testing suggests
   231    * used to enable this by default, but testing suggests
   229    * that Windows 8 and later do not enable it by default,
   232    * that Windows 8 and later do not enable it by default,
   230    * and spec now says 'Off by default'.
   233    * and spec now says 'Off by default'.
   231    * We disabled this in ae23c24c32.
   234    * We disabled this in ae23c24c32.
   232    * Note that IranNastaliq uses this feature extensively
   235    * Note that IranNastaliq uses this feature extensively
   233    * to fixup broken glyph sequences.  Oh well...
   236    * to fixup broken glyph sequences.  Oh well...
   234    * Test case: U+0643,U+0640,U+0631. */
   237    * Test case: U+0643,U+0640,U+0631. */
   235   //map->add_gsub_pause (NULL);
       
   236   //map->add_global_bool_feature (HB_TAG('c','s','w','h'));
   238   //map->add_global_bool_feature (HB_TAG('c','s','w','h'));
   237   map->add_global_bool_feature (HB_TAG('m','s','e','t'));
   239   map->add_global_bool_feature (HB_TAG('m','s','e','t'));
   238 }
   240 }
   239 
   241 
   240 #include "hb-ot-shape-complex-arabic-fallback.hh"
   242 #include "hb-ot-shape-complex-arabic-fallback.hh"
   258 void *
   260 void *
   259 data_create_arabic (const hb_ot_shape_plan_t *plan)
   261 data_create_arabic (const hb_ot_shape_plan_t *plan)
   260 {
   262 {
   261   arabic_shape_plan_t *arabic_plan = (arabic_shape_plan_t *) calloc (1, sizeof (arabic_shape_plan_t));
   263   arabic_shape_plan_t *arabic_plan = (arabic_shape_plan_t *) calloc (1, sizeof (arabic_shape_plan_t));
   262   if (unlikely (!arabic_plan))
   264   if (unlikely (!arabic_plan))
   263     return NULL;
   265     return nullptr;
   264 
   266 
   265   arabic_plan->do_fallback = plan->props.script == HB_SCRIPT_ARABIC;
   267   arabic_plan->do_fallback = plan->props.script == HB_SCRIPT_ARABIC;
   266   arabic_plan->has_stch = !!plan->map.get_1_mask (HB_TAG ('s','t','c','h'));
   268   arabic_plan->has_stch = !!plan->map.get_1_mask (HB_TAG ('s','t','c','h'));
   267   for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++) {
   269   for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++) {
   268     arabic_plan->mask_array[i] = plan->map.get_1_mask (arabic_features[i]);
   270     arabic_plan->mask_array[i] = plan->map.get_1_mask (arabic_features[i]);
   314     }
   316     }
   315 
   317 
   316     const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
   318     const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
   317 
   319 
   318     if (entry->prev_action != NONE && prev != (unsigned int) -1)
   320     if (entry->prev_action != NONE && prev != (unsigned int) -1)
       
   321     {
   319       info[prev].arabic_shaping_action() = entry->prev_action;
   322       info[prev].arabic_shaping_action() = entry->prev_action;
       
   323       buffer->unsafe_to_break (prev, i + 1);
       
   324     }
   320 
   325 
   321     info[i].arabic_shaping_action() = entry->curr_action;
   326     info[i].arabic_shaping_action() = entry->curr_action;
   322 
   327 
   323     prev = i;
   328     prev = i;
   324     state = entry->next_state;
   329     state = entry->next_state;
   343 {
   348 {
   344   /* Copy arabic_shaping_action() from base to Mongolian variation selectors. */
   349   /* Copy arabic_shaping_action() from base to Mongolian variation selectors. */
   345   unsigned int count = buffer->len;
   350   unsigned int count = buffer->len;
   346   hb_glyph_info_t *info = buffer->info;
   351   hb_glyph_info_t *info = buffer->info;
   347   for (unsigned int i = 1; i < count; i++)
   352   for (unsigned int i = 1; i < count; i++)
   348     if (unlikely (hb_in_range (info[i].codepoint, 0x180Bu, 0x180Du)))
   353     if (unlikely (hb_in_range<hb_codepoint_t> (info[i].codepoint, 0x180Bu, 0x180Du)))
   349       info[i].arabic_shaping_action() = info[i - 1].arabic_shaping_action();
   354       info[i].arabic_shaping_action() = info[i - 1].arabic_shaping_action();
   350 }
   355 }
   351 
   356 
   352 void
   357 void
   353 setup_masks_arabic_plan (const arabic_shape_plan_t *arabic_plan,
   358 setup_masks_arabic_plan (const arabic_shape_plan_t *arabic_plan,
   402   arabic_fallback_plan_t *fallback_plan = (arabic_fallback_plan_t *) hb_atomic_ptr_get (&arabic_plan->fallback_plan);
   407   arabic_fallback_plan_t *fallback_plan = (arabic_fallback_plan_t *) hb_atomic_ptr_get (&arabic_plan->fallback_plan);
   403   if (unlikely (!fallback_plan))
   408   if (unlikely (!fallback_plan))
   404   {
   409   {
   405     /* This sucks.  We need a font to build the fallback plan... */
   410     /* This sucks.  We need a font to build the fallback plan... */
   406     fallback_plan = arabic_fallback_plan_create (plan, font);
   411     fallback_plan = arabic_fallback_plan_create (plan, font);
   407     if (unlikely (!hb_atomic_ptr_cmpexch (&(const_cast<arabic_shape_plan_t *> (arabic_plan))->fallback_plan, NULL, fallback_plan))) {
   412     if (unlikely (!hb_atomic_ptr_cmpexch (&(const_cast<arabic_shape_plan_t *> (arabic_plan))->fallback_plan, nullptr, fallback_plan))) {
   408       arabic_fallback_plan_destroy (fallback_plan);
   413       arabic_fallback_plan_destroy (fallback_plan);
   409       goto retry;
   414       goto retry;
   410     }
   415     }
   411   }
   416   }
   412 
   417 
   522         context--;
   527         context--;
   523         w_total += pos[context].x_advance;
   528         w_total += pos[context].x_advance;
   524       }
   529       }
   525       i++; // Don't touch i again.
   530       i++; // Don't touch i again.
   526 
   531 
   527       DEBUG_MSG (ARABIC, NULL, "%s stretch at (%d,%d,%d)",
   532       DEBUG_MSG (ARABIC, nullptr, "%s stretch at (%d,%d,%d)",
   528                  step == MEASURE ? "measuring" : "cutting", context, start, end);
   533                  step == MEASURE ? "measuring" : "cutting", context, start, end);
   529       DEBUG_MSG (ARABIC, NULL, "rest of word:    count=%d width %d", start - context, w_total);
   534       DEBUG_MSG (ARABIC, nullptr, "rest of word:    count=%d width %d", start - context, w_total);
   530       DEBUG_MSG (ARABIC, NULL, "fixed tiles:     count=%d width=%d", n_fixed, w_fixed);
   535       DEBUG_MSG (ARABIC, nullptr, "fixed tiles:     count=%d width=%d", n_fixed, w_fixed);
   531       DEBUG_MSG (ARABIC, NULL, "repeating tiles: count=%d width=%d", n_repeating, w_repeating);
   536       DEBUG_MSG (ARABIC, nullptr, "repeating tiles: count=%d width=%d", n_repeating, w_repeating);
   532 
   537 
   533       /* Number of additional times to repeat each repeating tile. */
   538       /* Number of additional times to repeat each repeating tile. */
   534       int n_copies = 0;
   539       int n_copies = 0;
   535 
   540 
   536       hb_position_t w_remaining = w_total - w_fixed;
   541       hb_position_t w_remaining = w_total - w_fixed;
   538         n_copies = (sign * w_remaining) / (sign * w_repeating) - 1;
   543         n_copies = (sign * w_remaining) / (sign * w_repeating) - 1;
   539 
   544 
   540       /* See if we can improve the fit by adding an extra repeat and squeezing them together a bit. */
   545       /* See if we can improve the fit by adding an extra repeat and squeezing them together a bit. */
   541       hb_position_t extra_repeat_overlap = 0;
   546       hb_position_t extra_repeat_overlap = 0;
   542       hb_position_t shortfall = sign * w_remaining - sign * w_repeating * (n_copies + 1);
   547       hb_position_t shortfall = sign * w_remaining - sign * w_repeating * (n_copies + 1);
   543       if (shortfall > 0)
   548       if (shortfall > 0 && n_repeating > 0)
   544       {
   549       {
   545         ++n_copies;
   550         ++n_copies;
   546         hb_position_t excess = (n_copies + 1) * sign * w_repeating - sign * w_remaining;
   551         hb_position_t excess = (n_copies + 1) * sign * w_repeating - sign * w_remaining;
   547         if (excess > 0)
   552         if (excess > 0)
   548           extra_repeat_overlap = excess / (n_copies * n_repeating);
   553           extra_repeat_overlap = excess / (n_copies * n_repeating);
   549       }
   554       }
   550 
   555 
   551       if (step == MEASURE)
   556       if (step == MEASURE)
   552       {
   557       {
   553         extra_glyphs_needed += n_copies * n_repeating;
   558         extra_glyphs_needed += n_copies * n_repeating;
   554         DEBUG_MSG (ARABIC, NULL, "will add extra %d copies of repeating tiles", n_copies);
   559         DEBUG_MSG (ARABIC, nullptr, "will add extra %d copies of repeating tiles", n_copies);
   555       }
   560       }
   556       else
   561       else
   557       {
   562       {
       
   563         buffer->unsafe_to_break (context, end);
   558         hb_position_t x_offset = 0;
   564         hb_position_t x_offset = 0;
   559         for (unsigned int k = end; k > start; k--)
   565         for (unsigned int k = end; k > start; k--)
   560         {
   566         {
   561           hb_position_t width = font->get_glyph_h_advance (info[k - 1].codepoint);
   567           hb_position_t width = font->get_glyph_h_advance (info[k - 1].codepoint);
   562 
   568 
   563           unsigned int repeat = 1;
   569           unsigned int repeat = 1;
   564           if (info[k - 1].arabic_shaping_action() == STCH_REPEATING)
   570           if (info[k - 1].arabic_shaping_action() == STCH_REPEATING)
   565             repeat += n_copies;
   571             repeat += n_copies;
   566 
   572 
   567           DEBUG_MSG (ARABIC, NULL, "appending %d copies of glyph %d; j=%d",
   573           DEBUG_MSG (ARABIC, nullptr, "appending %d copies of glyph %d; j=%d",
   568                      repeat, info[k - 1].codepoint, j);
   574                      repeat, info[k - 1].codepoint, j);
   569           for (unsigned int n = 0; n < repeat; n++)
   575           for (unsigned int n = 0; n < repeat; n++)
   570           {
   576           {
   571             x_offset -= width;
   577             x_offset -= width;
   572             if (n > 0)
   578             if (n > 0)
   603   apply_stch (plan, buffer, font);
   609   apply_stch (plan, buffer, font);
   604 
   610 
   605   HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action);
   611   HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action);
   606 }
   612 }
   607 
   613 
       
   614 /* http://www.unicode.org/reports/tr53/tr53-1.pdf */
       
   615 
       
   616 static hb_codepoint_t
       
   617 modifier_combining_marks[] =
       
   618 {
       
   619   0x0654u, /* ARABIC HAMZA ABOVE */
       
   620   0x0655u, /* ARABIC HAMZA BELOW */
       
   621   0x0658u, /* ARABIC MARK NOON GHUNNA */
       
   622   0x06DCu, /* ARABIC SMALL HIGH SEEN */
       
   623   0x06E3u, /* ARABIC SMALL LOW SEEN */
       
   624   0x06E7u, /* ARABIC SMALL HIGH YEH */
       
   625   0x06E8u, /* ARABIC SMALL HIGH NOON */
       
   626   0x08F3u, /* ARABIC SMALL HIGH WAW */
       
   627 };
       
   628 
       
   629 static inline bool
       
   630 info_is_mcm (const hb_glyph_info_t &info)
       
   631 {
       
   632   hb_codepoint_t u = info.codepoint;
       
   633   for (unsigned int i = 0; i < ARRAY_LENGTH (modifier_combining_marks); i++)
       
   634     if (u == modifier_combining_marks[i])
       
   635       return true;
       
   636   return false;
       
   637 }
       
   638 
       
   639 static void
       
   640 reorder_marks_arabic (const hb_ot_shape_plan_t *plan,
       
   641                       hb_buffer_t              *buffer,
       
   642                       unsigned int              start,
       
   643                       unsigned int              end)
       
   644 {
       
   645   hb_glyph_info_t *info = buffer->info;
       
   646 
       
   647   unsigned int i = start;
       
   648   for (unsigned int cc = 220; cc <= 230; cc += 10)
       
   649   {
       
   650     DEBUG_MSG (ARABIC, buffer, "Looking for %d's starting at %d\n", cc, i);
       
   651     while (i < end && info_cc(info[i]) < cc)
       
   652       i++;
       
   653     DEBUG_MSG (ARABIC, buffer, "Looking for %d's stopped at %d\n", cc, i);
       
   654 
       
   655     if (i == end)
       
   656       break;
       
   657 
       
   658     if (info_cc(info[i]) > cc)
       
   659       continue;
       
   660 
       
   661     /* Technically we should also check "info_cc(info[j]) == cc"
       
   662      * in the following loop.  But not doing it is safe; we might
       
   663      * end up moving all the 220 MCMs and 230 MCMs together in one
       
   664      * move and be done. */
       
   665     unsigned int j = i;
       
   666     while (j < end && info_is_mcm (info[j]))
       
   667       j++;
       
   668     DEBUG_MSG (ARABIC, buffer, "Found %d's from %d to %d\n", cc, i, j);
       
   669 
       
   670     if (i == j)
       
   671       continue;
       
   672 
       
   673     /* Shift it! */
       
   674     DEBUG_MSG (ARABIC, buffer, "Shifting %d's: %d %d\n", cc, i, j);
       
   675     hb_glyph_info_t temp[HB_OT_SHAPE_COMPLEX_MAX_COMBINING_MARKS];
       
   676     assert (j - i <= ARRAY_LENGTH (temp));
       
   677     buffer->merge_clusters (start, j);
       
   678     memmove (temp, &info[i], (j - i) * sizeof (hb_glyph_info_t));
       
   679     memmove (&info[start + j - i], &info[start], (i - start) * sizeof (hb_glyph_info_t));
       
   680     memmove (&info[start], temp, (j - i) * sizeof (hb_glyph_info_t));
       
   681 
       
   682     start += j - i;
       
   683 
       
   684     i = j;
       
   685   }
       
   686 }
       
   687 
   608 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic =
   688 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic =
   609 {
   689 {
   610   "arabic",
       
   611   collect_features_arabic,
   690   collect_features_arabic,
   612   NULL, /* override_features */
   691   nullptr, /* override_features */
   613   data_create_arabic,
   692   data_create_arabic,
   614   data_destroy_arabic,
   693   data_destroy_arabic,
   615   NULL, /* preprocess_text */
   694   nullptr, /* preprocess_text */
   616   postprocess_glyphs_arabic,
   695   postprocess_glyphs_arabic,
   617   HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
   696   HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
   618   NULL, /* decompose */
   697   nullptr, /* decompose */
   619   NULL, /* compose */
   698   nullptr, /* compose */
   620   setup_masks_arabic,
   699   setup_masks_arabic,
   621   NULL, /* disable_otl */
   700   nullptr, /* disable_otl */
       
   701   reorder_marks_arabic,
   622   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
   702   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
   623   true, /* fallback_position */
   703   true, /* fallback_position */
   624 };
   704 };