Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright  2009,2010  Red Hat, Inc.
      3  * Copyright  2010,2011,2012  Google, Inc.
      4  *
      5  *  This is part of HarfBuzz, a text shaping library.
      6  *
      7  * Permission is hereby granted, without written agreement and without
      8  * license or royalty fees, to use, copy, modify, and distribute this
      9  * software and its documentation for any purpose, provided that the
     10  * above copyright notice and the following two paragraphs appear in
     11  * all copies of this software.
     12  *
     13  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
     14  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
     15  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
     16  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
     17  * DAMAGE.
     18  *
     19  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
     20  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
     21  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
     22  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
     23  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
     24  *
     25  * Red Hat Author(s): Behdad Esfahbod
     26  * Google Author(s): Behdad Esfahbod
     27  */
     28 
     29 #define HB_SHAPER ot
     30 #define hb_ot_shaper_face_data_t hb_ot_layout_t
     31 #define hb_ot_shaper_shape_plan_data_t hb_ot_shape_plan_t
     32 #include "hb-shaper-impl-private.hh"
     33 
     34 #include "hb-ot-shape-private.hh"
     35 #include "hb-ot-shape-complex-private.hh"
     36 #include "hb-ot-shape-fallback-private.hh"
     37 #include "hb-ot-shape-normalize-private.hh"
     38 
     39 #include "hb-ot-layout-private.hh"
     40 #include "hb-unicode-private.hh"
     41 #include "hb-set-private.hh"
     42 
     43 
     44 static hb_tag_t common_features[] = {
     45   HB_TAG('c','c','m','p'),
     46   HB_TAG('l','o','c','l'),
     47   HB_TAG('m','a','r','k'),
     48   HB_TAG('m','k','m','k'),
     49   HB_TAG('r','l','i','g'),
     50 };
     51 
     52 
     53 static hb_tag_t horizontal_features[] = {
     54   HB_TAG('c','a','l','t'),
     55   HB_TAG('c','l','i','g'),
     56   HB_TAG('c','u','r','s'),
     57   HB_TAG('k','e','r','n'),
     58   HB_TAG('l','i','g','a'),
     59   HB_TAG('r','c','l','t'),
     60 };
     61 
     62 
     63 
     64 static void
     65 hb_ot_shape_collect_features (hb_ot_shape_planner_t          *planner,
     66 			      const hb_segment_properties_t  *props,
     67 			      const hb_feature_t             *user_features,
     68 			      unsigned int                    num_user_features)
     69 {
     70   hb_ot_map_builder_t *map = &planner->map;
     71 
     72   switch (props->direction) {
     73     case HB_DIRECTION_LTR:
     74       map->add_global_bool_feature (HB_TAG ('l','t','r','a'));
     75       map->add_global_bool_feature (HB_TAG ('l','t','r','m'));
     76       break;
     77     case HB_DIRECTION_RTL:
     78       map->add_global_bool_feature (HB_TAG ('r','t','l','a'));
     79       map->add_feature (HB_TAG ('r','t','l','m'), 1, F_NONE);
     80       break;
     81     case HB_DIRECTION_TTB:
     82     case HB_DIRECTION_BTT:
     83     case HB_DIRECTION_INVALID:
     84     default:
     85       break;
     86   }
     87 
     88   map->add_feature (HB_TAG ('f','r','a','c'), 1, F_NONE);
     89   map->add_feature (HB_TAG ('n','u','m','r'), 1, F_NONE);
     90   map->add_feature (HB_TAG ('d','n','o','m'), 1, F_NONE);
     91 
     92   if (planner->shaper->collect_features)
     93     planner->shaper->collect_features (planner);
     94 
     95   for (unsigned int i = 0; i < ARRAY_LENGTH (common_features); i++)
     96     map->add_global_bool_feature (common_features[i]);
     97 
     98   if (HB_DIRECTION_IS_HORIZONTAL (props->direction))
     99     for (unsigned int i = 0; i < ARRAY_LENGTH (horizontal_features); i++)
    100       map->add_feature (horizontal_features[i], 1, F_GLOBAL |
    101 			(horizontal_features[i] == HB_TAG('k','e','r','n') ?
    102 			 F_HAS_FALLBACK : F_NONE));
    103   else
    104   {
    105     /* We really want to find a 'vert' feature if there's any in the font, no
    106      * matter which script/langsys it is listed (or not) under.
    107      * See various bugs referenced from:
    108      * https://github.com/behdad/harfbuzz/issues/63 */
    109     map->add_feature (HB_TAG ('v','e','r','t'), 1, F_GLOBAL | F_GLOBAL_SEARCH);
    110   }
    111 
    112   if (planner->shaper->override_features)
    113     planner->shaper->override_features (planner);
    114 
    115   for (unsigned int i = 0; i < num_user_features; i++) {
    116     const hb_feature_t *feature = &user_features[i];
    117     map->add_feature (feature->tag, feature->value,
    118 		      (feature->start == 0 && feature->end == (unsigned int) -1) ?
    119 		       F_GLOBAL : F_NONE);
    120   }
    121 }
    122 
    123 
    124 /*
    125  * shaper face data
    126  */
    127 
    128 hb_ot_shaper_face_data_t *
    129 _hb_ot_shaper_face_data_create (hb_face_t *face)
    130 {
    131   return _hb_ot_layout_create (face);
    132 }
    133 
    134 void
    135 _hb_ot_shaper_face_data_destroy (hb_ot_shaper_face_data_t *data)
    136 {
    137   _hb_ot_layout_destroy (data);
    138 }
    139 
    140 
    141 /*
    142  * shaper font data
    143  */
    144 
    145 struct hb_ot_shaper_font_data_t {};
    146 
    147 hb_ot_shaper_font_data_t *
    148 _hb_ot_shaper_font_data_create (hb_font_t *font HB_UNUSED)
    149 {
    150   return (hb_ot_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
    151 }
    152 
    153 void
    154 _hb_ot_shaper_font_data_destroy (hb_ot_shaper_font_data_t *data)
    155 {
    156 }
    157 
    158 
    159 /*
    160  * shaper shape_plan data
    161  */
    162 
    163 hb_ot_shaper_shape_plan_data_t *
    164 _hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan,
    165 				      const hb_feature_t *user_features,
    166 				      unsigned int        num_user_features)
    167 {
    168   hb_ot_shape_plan_t *plan = (hb_ot_shape_plan_t *) calloc (1, sizeof (hb_ot_shape_plan_t));
    169   if (unlikely (!plan))
    170     return NULL;
    171 
    172   hb_ot_shape_planner_t planner (shape_plan);
    173 
    174   planner.shaper = hb_ot_shape_complex_categorize (&planner);
    175 
    176   hb_ot_shape_collect_features (&planner, &shape_plan->props, user_features, num_user_features);
    177 
    178   planner.compile (*plan);
    179 
    180   if (plan->shaper->data_create) {
    181     plan->data = plan->shaper->data_create (plan);
    182     if (unlikely (!plan->data))
    183       return NULL;
    184   }
    185 
    186   return plan;
    187 }
    188 
    189 void
    190 _hb_ot_shaper_shape_plan_data_destroy (hb_ot_shaper_shape_plan_data_t *plan)
    191 {
    192   if (plan->shaper->data_destroy)
    193     plan->shaper->data_destroy (const_cast<void *> (plan->data));
    194 
    195   plan->finish ();
    196 
    197   free (plan);
    198 }
    199 
    200 
    201 /*
    202  * shaper
    203  */
    204 
    205 struct hb_ot_shape_context_t
    206 {
    207   hb_ot_shape_plan_t *plan;
    208   hb_font_t *font;
    209   hb_face_t *face;
    210   hb_buffer_t  *buffer;
    211   const hb_feature_t *user_features;
    212   unsigned int        num_user_features;
    213 
    214   /* Transient stuff */
    215   hb_direction_t target_direction;
    216 };
    217 
    218 
    219 
    220 /* Main shaper */
    221 
    222 
    223 /* Prepare */
    224 
    225 static void
    226 hb_set_unicode_props (hb_buffer_t *buffer)
    227 {
    228   unsigned int count = buffer->len;
    229   hb_glyph_info_t *info = buffer->info;
    230   for (unsigned int i = 0; i < count; i++)
    231     _hb_glyph_info_set_unicode_props (&info[i], buffer);
    232 }
    233 
    234 static void
    235 hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font)
    236 {
    237   if (!(buffer->flags & HB_BUFFER_FLAG_BOT) ||
    238       buffer->context_len[0] ||
    239       _hb_glyph_info_get_general_category (&buffer->info[0]) !=
    240       HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
    241     return;
    242 
    243   if (!font->has_glyph (0x25CCu))
    244     return;
    245 
    246   hb_glyph_info_t dottedcircle = {0};
    247   dottedcircle.codepoint = 0x25CCu;
    248   _hb_glyph_info_set_unicode_props (&dottedcircle, buffer);
    249 
    250   buffer->clear_output ();
    251 
    252   buffer->idx = 0;
    253   hb_glyph_info_t info = dottedcircle;
    254   info.cluster = buffer->cur().cluster;
    255   info.mask = buffer->cur().mask;
    256   buffer->output_info (info);
    257   while (buffer->idx < buffer->len && !buffer->in_error)
    258     buffer->next_glyph ();
    259 
    260   buffer->swap_buffers ();
    261 }
    262 
    263 static void
    264 hb_form_clusters (hb_buffer_t *buffer)
    265 {
    266   if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII) ||
    267       buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
    268     return;
    269 
    270   /* Loop duplicated in hb_ensure_native_direction(), and in _hb-coretext.cc */
    271   unsigned int base = 0;
    272   unsigned int count = buffer->len;
    273   hb_glyph_info_t *info = buffer->info;
    274   for (unsigned int i = 1; i < count; i++)
    275   {
    276     if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])) &&
    277 		!_hb_glyph_info_is_joiner (&info[i])))
    278     {
    279       buffer->merge_clusters (base, i);
    280       base = i;
    281     }
    282   }
    283   buffer->merge_clusters (base, count);
    284 }
    285 
    286 static void
    287 hb_ensure_native_direction (hb_buffer_t *buffer)
    288 {
    289   hb_direction_t direction = buffer->props.direction;
    290 
    291   /* TODO vertical:
    292    * The only BTT vertical script is Ogham, but it's not clear to me whether OpenType
    293    * Ogham fonts are supposed to be implemented BTT or not.  Need to research that
    294    * first. */
    295   if ((HB_DIRECTION_IS_HORIZONTAL (direction) && direction != hb_script_get_horizontal_direction (buffer->props.script)) ||
    296       (HB_DIRECTION_IS_VERTICAL   (direction) && direction != HB_DIRECTION_TTB))
    297   {
    298     /* Same loop as hb_form_clusters().
    299      * Since form_clusters() merged clusters already, we don't merge. */
    300     unsigned int base = 0;
    301     unsigned int count = buffer->len;
    302     hb_glyph_info_t *info = buffer->info;
    303     for (unsigned int i = 1; i < count; i++)
    304     {
    305       if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i]))))
    306       {
    307 	if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
    308 	  buffer->merge_clusters (base, i);
    309 	buffer->reverse_range (base, i);
    310 
    311 	base = i;
    312       }
    313     }
    314     if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
    315       buffer->merge_clusters (base, count);
    316     buffer->reverse_range (base, count);
    317 
    318     buffer->reverse ();
    319 
    320     buffer->props.direction = HB_DIRECTION_REVERSE (buffer->props.direction);
    321   }
    322 }
    323 
    324 
    325 /* Substitute */
    326 
    327 static inline void
    328 hb_ot_mirror_chars (hb_ot_shape_context_t *c)
    329 {
    330   if (HB_DIRECTION_IS_FORWARD (c->target_direction))
    331     return;
    332 
    333   hb_buffer_t *buffer = c->buffer;
    334   hb_unicode_funcs_t *unicode = buffer->unicode;
    335   hb_mask_t rtlm_mask = c->plan->rtlm_mask;
    336 
    337   unsigned int count = buffer->len;
    338   hb_glyph_info_t *info = buffer->info;
    339   for (unsigned int i = 0; i < count; i++) {
    340     hb_codepoint_t codepoint = unicode->mirroring (info[i].codepoint);
    341     if (likely (codepoint == info[i].codepoint || !c->font->has_glyph (codepoint)))
    342       info[i].mask |= rtlm_mask;
    343     else
    344       info[i].codepoint = codepoint;
    345   }
    346 }
    347 
    348 static inline void
    349 hb_ot_shape_setup_masks_fraction (hb_ot_shape_context_t *c)
    350 {
    351   if (!(c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII) ||
    352       !c->plan->has_frac)
    353     return;
    354 
    355   hb_buffer_t *buffer = c->buffer;
    356 
    357   /* TODO look in pre/post context text also. */
    358   unsigned int count = buffer->len;
    359   hb_glyph_info_t *info = buffer->info;
    360   for (unsigned int i = 0; i < count; i++)
    361   {
    362     if (info[i].codepoint == 0x2044u) /* FRACTION SLASH */
    363     {
    364       unsigned int start = i, end = i + 1;
    365       while (start &&
    366 	     _hb_glyph_info_get_general_category (&info[start - 1]) ==
    367 	     HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER)
    368         start--;
    369       while (end < count &&
    370 	     _hb_glyph_info_get_general_category (&info[end]) ==
    371 	     HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER)
    372         end++;
    373 
    374       for (unsigned int j = start; j < i; j++)
    375         info[j].mask |= c->plan->numr_mask | c->plan->frac_mask;
    376       info[i].mask |= c->plan->frac_mask;
    377       for (unsigned int j = i + 1; j < end; j++)
    378         info[j].mask |= c->plan->frac_mask | c->plan->dnom_mask;
    379 
    380       i = end - 1;
    381     }
    382   }
    383 }
    384 
    385 static inline void
    386 hb_ot_shape_initialize_masks (hb_ot_shape_context_t *c)
    387 {
    388   hb_ot_map_t *map = &c->plan->map;
    389   hb_buffer_t *buffer = c->buffer;
    390 
    391   hb_mask_t global_mask = map->get_global_mask ();
    392   buffer->reset_masks (global_mask);
    393 }
    394 
    395 static inline void
    396 hb_ot_shape_setup_masks (hb_ot_shape_context_t *c)
    397 {
    398   hb_ot_map_t *map = &c->plan->map;
    399   hb_buffer_t *buffer = c->buffer;
    400 
    401   hb_ot_shape_setup_masks_fraction (c);
    402 
    403   if (c->plan->shaper->setup_masks)
    404     c->plan->shaper->setup_masks (c->plan, buffer, c->font);
    405 
    406   for (unsigned int i = 0; i < c->num_user_features; i++)
    407   {
    408     const hb_feature_t *feature = &c->user_features[i];
    409     if (!(feature->start == 0 && feature->end == (unsigned int)-1)) {
    410       unsigned int shift;
    411       hb_mask_t mask = map->get_mask (feature->tag, &shift);
    412       buffer->set_masks (feature->value << shift, mask, feature->start, feature->end);
    413     }
    414   }
    415 }
    416 
    417 static void
    418 hb_ot_zero_width_default_ignorables (hb_ot_shape_context_t *c)
    419 {
    420   hb_buffer_t *buffer = c->buffer;
    421 
    422   if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES) ||
    423       (buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES))
    424     return;
    425 
    426   unsigned int count = buffer->len;
    427   hb_glyph_info_t *info = buffer->info;
    428   hb_glyph_position_t *pos = buffer->pos;
    429   unsigned int i = 0;
    430   for (i = 0; i < count; i++)
    431     if (unlikely (_hb_glyph_info_is_default_ignorable (&info[i])))
    432       pos[i].x_advance = pos[i].y_advance = pos[i].x_offset = pos[i].y_offset = 0;
    433 }
    434 
    435 static void
    436 hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c)
    437 {
    438   hb_buffer_t *buffer = c->buffer;
    439 
    440   if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES) ||
    441       (buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES))
    442     return;
    443 
    444   unsigned int count = buffer->len;
    445   hb_glyph_info_t *info = buffer->info;
    446   hb_glyph_position_t *pos = buffer->pos;
    447   unsigned int i = 0;
    448   for (i = 0; i < count; i++)
    449   {
    450     if (unlikely (_hb_glyph_info_is_default_ignorable (&info[i])))
    451       break;
    452   }
    453 
    454   /* No default-ignorables found; return. */
    455   if (i == count)
    456     return;
    457 
    458   hb_codepoint_t space;
    459   if (c->font->get_nominal_glyph (' ', &space))
    460   {
    461     /* Replace default-ignorables with a zero-advance space glyph. */
    462     for (/*continue*/; i < count; i++)
    463     {
    464       if (_hb_glyph_info_is_default_ignorable (&info[i]))
    465 	info[i].codepoint = space;
    466     }
    467   }
    468   else
    469   {
    470     /* Merge clusters and delete default-ignorables.
    471      * NOTE! We can't use out-buffer as we have positioning data. */
    472     unsigned int j = i;
    473     for (; i < count; i++)
    474     {
    475       if (_hb_glyph_info_is_default_ignorable (&info[i]))
    476       {
    477 	/* Merge clusters.
    478 	 * Same logic as buffer->delete_glyph(), but for in-place removal. */
    479 
    480 	unsigned int cluster = info[i].cluster;
    481 	if (i + 1 < count && cluster == info[i + 1].cluster)
    482 	  continue; /* Cluster survives; do nothing. */
    483 
    484 	if (j)
    485 	{
    486 	  /* Merge cluster backward. */
    487 	  if (cluster < info[j - 1].cluster)
    488 	  {
    489 	    unsigned int old_cluster = info[j - 1].cluster;
    490 	    for (unsigned k = j; k && info[k - 1].cluster == old_cluster; k--)
    491 	      info[k - 1].cluster = cluster;
    492 	  }
    493 	  continue;
    494 	}
    495 
    496 	if (i + 1 < count)
    497 	  buffer->merge_clusters (i, i + 2); /* Merge cluster forward. */
    498 
    499 	continue;
    500       }
    501 
    502       if (j != i)
    503       {
    504 	info[j] = info[i];
    505 	pos[j] = pos[i];
    506       }
    507       j++;
    508     }
    509     buffer->len = j;
    510   }
    511 }
    512 
    513 
    514 static inline void
    515 hb_ot_map_glyphs_fast (hb_buffer_t  *buffer)
    516 {
    517   /* Normalization process sets up glyph_index(), we just copy it. */
    518   unsigned int count = buffer->len;
    519   hb_glyph_info_t *info = buffer->info;
    520   for (unsigned int i = 0; i < count; i++)
    521     info[i].codepoint = info[i].glyph_index();
    522 
    523   buffer->content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS;
    524 }
    525 
    526 static inline void
    527 hb_ot_substitute_default (hb_ot_shape_context_t *c)
    528 {
    529   hb_buffer_t *buffer = c->buffer;
    530 
    531   hb_ot_shape_initialize_masks (c);
    532 
    533   hb_ot_mirror_chars (c);
    534 
    535   HB_BUFFER_ALLOCATE_VAR (buffer, glyph_index);
    536 
    537   _hb_ot_shape_normalize (c->plan, buffer, c->font);
    538 
    539   hb_ot_shape_setup_masks (c);
    540 
    541   /* This is unfortunate to go here, but necessary... */
    542   if (!hb_ot_layout_has_positioning (c->face))
    543     _hb_ot_shape_fallback_position_recategorize_marks (c->plan, c->font, buffer);
    544 
    545   hb_ot_map_glyphs_fast (buffer);
    546 
    547   HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_index);
    548 }
    549 
    550 static inline void
    551 hb_ot_substitute_complex (hb_ot_shape_context_t *c)
    552 {
    553   hb_buffer_t *buffer = c->buffer;
    554 
    555   hb_ot_layout_substitute_start (c->font, buffer);
    556 
    557   c->plan->substitute (c->font, buffer);
    558 
    559   return;
    560 }
    561 
    562 static inline void
    563 hb_ot_substitute (hb_ot_shape_context_t *c)
    564 {
    565   hb_ot_substitute_default (c);
    566 
    567   _hb_buffer_allocate_gsubgpos_vars (c->buffer);
    568 
    569   hb_ot_substitute_complex (c);
    570 }
    571 
    572 /* Position */
    573 
    574 static inline void
    575 adjust_mark_offsets (hb_glyph_position_t *pos)
    576 {
    577   pos->x_offset -= pos->x_advance;
    578   pos->y_offset -= pos->y_advance;
    579 }
    580 
    581 static inline void
    582 zero_mark_width (hb_glyph_position_t *pos)
    583 {
    584   pos->x_advance = 0;
    585   pos->y_advance = 0;
    586 }
    587 
    588 static inline void
    589 zero_mark_widths_by_gdef (hb_buffer_t *buffer, bool adjust_offsets)
    590 {
    591   unsigned int count = buffer->len;
    592   hb_glyph_info_t *info = buffer->info;
    593   for (unsigned int i = 0; i < count; i++)
    594     if (_hb_glyph_info_is_mark (&info[i]))
    595     {
    596       if (adjust_offsets)
    597         adjust_mark_offsets (&buffer->pos[i]);
    598       zero_mark_width (&buffer->pos[i]);
    599     }
    600 }
    601 
    602 static inline void
    603 hb_ot_position_default (hb_ot_shape_context_t *c)
    604 {
    605   hb_direction_t direction = c->buffer->props.direction;
    606   unsigned int count = c->buffer->len;
    607   hb_glyph_info_t *info = c->buffer->info;
    608   hb_glyph_position_t *pos = c->buffer->pos;
    609 
    610   if (HB_DIRECTION_IS_HORIZONTAL (direction))
    611   {
    612     for (unsigned int i = 0; i < count; i++)
    613       pos[i].x_advance = c->font->get_glyph_h_advance (info[i].codepoint);
    614     /* The nil glyph_h_origin() func returns 0, so no need to apply it. */
    615     if (c->font->has_glyph_h_origin_func ())
    616       for (unsigned int i = 0; i < count; i++)
    617 	c->font->subtract_glyph_h_origin (info[i].codepoint,
    618 					  &pos[i].x_offset,
    619 					  &pos[i].y_offset);
    620   }
    621   else
    622   {
    623     for (unsigned int i = 0; i < count; i++)
    624     {
    625       pos[i].y_advance = c->font->get_glyph_v_advance (info[i].codepoint);
    626       c->font->subtract_glyph_v_origin (info[i].codepoint,
    627 					&pos[i].x_offset,
    628 					&pos[i].y_offset);
    629     }
    630   }
    631   if (c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK)
    632     _hb_ot_shape_fallback_spaces (c->plan, c->font, c->buffer);
    633 }
    634 
    635 static inline bool
    636 hb_ot_position_complex (hb_ot_shape_context_t *c)
    637 {
    638   hb_ot_layout_position_start (c->font, c->buffer);
    639 
    640   bool ret = false;
    641   unsigned int count = c->buffer->len;
    642   bool has_positioning = (bool) hb_ot_layout_has_positioning (c->face);
    643 
    644   /* If the font has no GPOS, AND, no fallback positioning will
    645    * happen, AND, direction is forward, then when zeroing mark
    646    * widths, we shift the mark with it, such that the mark
    647    * is positioned hanging over the previous glyph.  When
    648    * direction is backward we don't shift and it will end up
    649    * hanging over the next glyph after the final reordering.
    650    * If fallback positinoing happens or GPOS is present, we don't
    651    * care.
    652    */
    653   bool adjust_offsets_when_zeroing = !(has_positioning || c->plan->shaper->fallback_position ||
    654                                        HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction));
    655 
    656   switch (c->plan->shaper->zero_width_marks)
    657   {
    658     case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY:
    659       zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing);
    660       break;
    661 
    662     default:
    663     case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE:
    664     case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE:
    665       break;
    666   }
    667 
    668   if (has_positioning)
    669   {
    670     hb_glyph_info_t *info = c->buffer->info;
    671     hb_glyph_position_t *pos = c->buffer->pos;
    672 
    673     /* Change glyph origin to what GPOS expects (horizontal), apply GPOS, change it back. */
    674 
    675     /* The nil glyph_h_origin() func returns 0, so no need to apply it. */
    676     if (c->font->has_glyph_h_origin_func ())
    677       for (unsigned int i = 0; i < count; i++)
    678 	c->font->add_glyph_h_origin (info[i].codepoint,
    679 				     &pos[i].x_offset,
    680 				     &pos[i].y_offset);
    681 
    682     c->plan->position (c->font, c->buffer);
    683 
    684     /* The nil glyph_h_origin() func returns 0, so no need to apply it. */
    685     if (c->font->has_glyph_h_origin_func ())
    686       for (unsigned int i = 0; i < count; i++)
    687 	c->font->subtract_glyph_h_origin (info[i].codepoint,
    688 					  &pos[i].x_offset,
    689 					  &pos[i].y_offset);
    690 
    691     ret = true;
    692   }
    693 
    694   switch (c->plan->shaper->zero_width_marks)
    695   {
    696     case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE:
    697       zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing);
    698       break;
    699 
    700     default:
    701     case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE:
    702     case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY:
    703       break;
    704   }
    705 
    706   /* Finishing off GPOS has to follow a certain order. */
    707   hb_ot_layout_position_finish_advances (c->font, c->buffer);
    708   hb_ot_zero_width_default_ignorables (c);
    709   hb_ot_layout_position_finish_offsets (c->font, c->buffer);
    710 
    711   return ret;
    712 }
    713 
    714 static inline void
    715 hb_ot_position (hb_ot_shape_context_t *c)
    716 {
    717   c->buffer->clear_positions ();
    718 
    719   hb_ot_position_default (c);
    720 
    721   hb_bool_t fallback = !hb_ot_position_complex (c);
    722 
    723   if (fallback && c->plan->shaper->fallback_position)
    724     _hb_ot_shape_fallback_position (c->plan, c->font, c->buffer);
    725 
    726   if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction))
    727     hb_buffer_reverse (c->buffer);
    728 
    729   /* Visual fallback goes here. */
    730 
    731   if (fallback)
    732     _hb_ot_shape_fallback_kern (c->plan, c->font, c->buffer);
    733 
    734   _hb_buffer_deallocate_gsubgpos_vars (c->buffer);
    735 }
    736 
    737 
    738 /* Pull it all together! */
    739 
    740 static void
    741 hb_ot_shape_internal (hb_ot_shape_context_t *c)
    742 {
    743   c->buffer->deallocate_var_all ();
    744   c->buffer->scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
    745   if (likely (!_hb_unsigned_int_mul_overflows (c->buffer->len, HB_BUFFER_MAX_EXPANSION_FACTOR)))
    746   {
    747     c->buffer->max_len = MAX (c->buffer->len * HB_BUFFER_MAX_EXPANSION_FACTOR,
    748 			      (unsigned) HB_BUFFER_MAX_LEN_MIN);
    749   }
    750 
    751   /* Save the original direction, we use it later. */
    752   c->target_direction = c->buffer->props.direction;
    753 
    754   _hb_buffer_allocate_unicode_vars (c->buffer);
    755 
    756   c->buffer->clear_output ();
    757 
    758   hb_set_unicode_props (c->buffer);
    759   hb_insert_dotted_circle (c->buffer, c->font);
    760   hb_form_clusters (c->buffer);
    761 
    762   hb_ensure_native_direction (c->buffer);
    763 
    764   if (c->plan->shaper->preprocess_text)
    765     c->plan->shaper->preprocess_text (c->plan, c->buffer, c->font);
    766 
    767   hb_ot_substitute (c);
    768   hb_ot_position (c);
    769 
    770   hb_ot_hide_default_ignorables (c);
    771 
    772   if (c->plan->shaper->postprocess_glyphs)
    773     c->plan->shaper->postprocess_glyphs (c->plan, c->buffer, c->font);
    774 
    775   _hb_buffer_deallocate_unicode_vars (c->buffer);
    776 
    777   c->buffer->props.direction = c->target_direction;
    778 
    779   c->buffer->max_len = HB_BUFFER_MAX_LEN_DEFAULT;
    780   c->buffer->deallocate_var_all ();
    781 }
    782 
    783 
    784 hb_bool_t
    785 _hb_ot_shape (hb_shape_plan_t    *shape_plan,
    786 	      hb_font_t          *font,
    787 	      hb_buffer_t        *buffer,
    788 	      const hb_feature_t *features,
    789 	      unsigned int        num_features)
    790 {
    791   hb_ot_shape_context_t c = {HB_SHAPER_DATA_GET (shape_plan), font, font->face, buffer, features, num_features};
    792   hb_ot_shape_internal (&c);
    793 
    794   return true;
    795 }
    796 
    797 
    798 /**
    799  * hb_ot_shape_plan_collect_lookups:
    800  *
    801  * Since: 0.9.7
    802  **/
    803 void
    804 hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan,
    805 				  hb_tag_t         table_tag,
    806 				  hb_set_t        *lookup_indexes /* OUT */)
    807 {
    808   /* XXX Does the first part always succeed? */
    809   HB_SHAPER_DATA_GET (shape_plan)->collect_lookups (table_tag, lookup_indexes);
    810 }
    811 
    812 
    813 /* TODO Move this to hb-ot-shape-normalize, make it do decompose, and make it public. */
    814 static void
    815 add_char (hb_font_t          *font,
    816 	  hb_unicode_funcs_t *unicode,
    817 	  hb_bool_t           mirror,
    818 	  hb_codepoint_t      u,
    819 	  hb_set_t           *glyphs)
    820 {
    821   hb_codepoint_t glyph;
    822   if (font->get_nominal_glyph (u, &glyph))
    823     glyphs->add (glyph);
    824   if (mirror)
    825   {
    826     hb_codepoint_t m = unicode->mirroring (u);
    827     if (m != u && font->get_nominal_glyph (m, &glyph))
    828       glyphs->add (glyph);
    829   }
    830 }
    831 
    832 
    833 /**
    834  * hb_ot_shape_glyphs_closure:
    835  *
    836  * Since: 0.9.2
    837  **/
    838 void
    839 hb_ot_shape_glyphs_closure (hb_font_t          *font,
    840 			    hb_buffer_t        *buffer,
    841 			    const hb_feature_t *features,
    842 			    unsigned int        num_features,
    843 			    hb_set_t           *glyphs)
    844 {
    845   hb_ot_shape_plan_t plan;
    846 
    847   const char *shapers[] = {"ot", NULL};
    848   hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props,
    849 							     features, num_features, shapers);
    850 
    851   bool mirror = hb_script_get_horizontal_direction (buffer->props.script) == HB_DIRECTION_RTL;
    852 
    853   unsigned int count = buffer->len;
    854   hb_glyph_info_t *info = buffer->info;
    855   for (unsigned int i = 0; i < count; i++)
    856     add_char (font, buffer->unicode, mirror, info[i].codepoint, glyphs);
    857 
    858   hb_set_t lookups;
    859   lookups.init ();
    860   hb_ot_shape_plan_collect_lookups (shape_plan, HB_OT_TAG_GSUB, &lookups);
    861 
    862   /* And find transitive closure. */
    863   hb_set_t copy;
    864   copy.init ();
    865   do {
    866     copy.set (glyphs);
    867     for (hb_codepoint_t lookup_index = -1; hb_set_next (&lookups, &lookup_index);)
    868       hb_ot_layout_lookup_substitute_closure (font->face, lookup_index, glyphs);
    869   } while (!copy.is_equal (glyphs));
    870 
    871   hb_shape_plan_destroy (shape_plan);
    872 }
    873