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-set-private.hh"
     41 
     42 
     43 static hb_tag_t common_features[] = {
     44   HB_TAG('c','c','m','p'),
     45   HB_TAG('l','i','g','a'),
     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('r','c','l','t'),
     59 };
     60 
     61 static hb_tag_t vertical_features[] = {
     62   HB_TAG('v','e','r','t'),
     63 };
     64 
     65 
     66 
     67 static void
     68 hb_ot_shape_collect_features (hb_ot_shape_planner_t          *planner,
     69 			      const hb_segment_properties_t  *props,
     70 			      const hb_feature_t             *user_features,
     71 			      unsigned int                    num_user_features)
     72 {
     73   hb_ot_map_builder_t *map = &planner->map;
     74 
     75   switch (props->direction) {
     76     case HB_DIRECTION_LTR:
     77       map->add_global_bool_feature (HB_TAG ('l','t','r','a'));
     78       map->add_global_bool_feature (HB_TAG ('l','t','r','m'));
     79       break;
     80     case HB_DIRECTION_RTL:
     81       map->add_global_bool_feature (HB_TAG ('r','t','l','a'));
     82       map->add_feature (HB_TAG ('r','t','l','m'), 1, F_NONE);
     83       break;
     84     case HB_DIRECTION_TTB:
     85     case HB_DIRECTION_BTT:
     86     case HB_DIRECTION_INVALID:
     87     default:
     88       break;
     89   }
     90 
     91   map->add_feature (HB_TAG ('f','r','a','c'), 1, F_NONE);
     92   map->add_feature (HB_TAG ('n','u','m','r'), 1, F_NONE);
     93   map->add_feature (HB_TAG ('d','n','o','m'), 1, F_NONE);
     94 
     95   if (planner->shaper->collect_features)
     96     planner->shaper->collect_features (planner);
     97 
     98   for (unsigned int i = 0; i < ARRAY_LENGTH (common_features); i++)
     99     map->add_global_bool_feature (common_features[i]);
    100 
    101   if (HB_DIRECTION_IS_HORIZONTAL (props->direction))
    102     for (unsigned int i = 0; i < ARRAY_LENGTH (horizontal_features); i++)
    103       map->add_feature (horizontal_features[i], 1, F_GLOBAL |
    104 			(horizontal_features[i] == HB_TAG('k','e','r','n') ?
    105 			 F_HAS_FALLBACK : F_NONE));
    106   else
    107     for (unsigned int i = 0; i < ARRAY_LENGTH (vertical_features); i++)
    108       map->add_feature (vertical_features[i], 1, F_GLOBAL |
    109 			(vertical_features[i] == HB_TAG('v','k','r','n') ?
    110 			 F_HAS_FALLBACK : F_NONE));
    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)
    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   for (unsigned int i = 0; i < count; i++)
    230     _hb_glyph_info_set_unicode_props (&buffer->info[i], buffer->unicode);
    231 }
    232 
    233 static void
    234 hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font)
    235 {
    236   if (!(buffer->flags & HB_BUFFER_FLAG_BOT) ||
    237       _hb_glyph_info_get_general_category (&buffer->info[0]) !=
    238       HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
    239     return;
    240 
    241   if (!font->has_glyph (0x25CC))
    242     return;
    243 
    244   hb_glyph_info_t dottedcircle;
    245   dottedcircle.codepoint = 0x25CC;
    246   _hb_glyph_info_set_unicode_props (&dottedcircle, buffer->unicode);
    247 
    248   buffer->clear_output ();
    249 
    250   buffer->idx = 0;
    251   hb_glyph_info_t info = dottedcircle;
    252   info.cluster = buffer->cur().cluster;
    253   info.mask = buffer->cur().mask;
    254   buffer->output_info (info);
    255   while (buffer->idx < buffer->len)
    256     buffer->next_glyph ();
    257 
    258   buffer->swap_buffers ();
    259 }
    260 
    261 static void
    262 hb_form_clusters (hb_buffer_t *buffer)
    263 {
    264   unsigned int count = buffer->len;
    265   for (unsigned int i = 1; i < count; i++)
    266     if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[i])))
    267       buffer->merge_clusters (i - 1, i + 1);
    268 }
    269 
    270 static void
    271 hb_ensure_native_direction (hb_buffer_t *buffer)
    272 {
    273   hb_direction_t direction = buffer->props.direction;
    274 
    275   /* TODO vertical:
    276    * The only BTT vertical script is Ogham, but it's not clear to me whether OpenType
    277    * Ogham fonts are supposed to be implemented BTT or not.  Need to research that
    278    * first. */
    279   if ((HB_DIRECTION_IS_HORIZONTAL (direction) && direction != hb_script_get_horizontal_direction (buffer->props.script)) ||
    280       (HB_DIRECTION_IS_VERTICAL   (direction) && direction != HB_DIRECTION_TTB))
    281   {
    282     hb_buffer_reverse_clusters (buffer);
    283     buffer->props.direction = HB_DIRECTION_REVERSE (buffer->props.direction);
    284   }
    285 }
    286 
    287 
    288 /* Substitute */
    289 
    290 static inline void
    291 hb_ot_mirror_chars (hb_ot_shape_context_t *c)
    292 {
    293   if (HB_DIRECTION_IS_FORWARD (c->target_direction))
    294     return;
    295 
    296   hb_buffer_t *buffer = c->buffer;
    297   hb_unicode_funcs_t *unicode = buffer->unicode;
    298   hb_mask_t rtlm_mask = c->plan->rtlm_mask;
    299 
    300   unsigned int count = buffer->len;
    301   hb_glyph_info_t *info = buffer->info;
    302   for (unsigned int i = 0; i < count; i++) {
    303     hb_codepoint_t codepoint = unicode->mirroring (info[i].codepoint);
    304     if (likely (codepoint == info[i].codepoint))
    305       info[i].mask |= rtlm_mask;
    306     else
    307       info[i].codepoint = codepoint;
    308   }
    309 }
    310 
    311 static inline void
    312 hb_ot_shape_setup_masks_fraction (hb_ot_shape_context_t *c)
    313 {
    314   if (!c->plan->has_frac)
    315     return;
    316 
    317   hb_buffer_t *buffer = c->buffer;
    318 
    319   /* TODO look in pre/post context text also. */
    320   unsigned int count = buffer->len;
    321   hb_glyph_info_t *info = buffer->info;
    322   for (unsigned int i = 0; i < count; i++)
    323   {
    324     if (info[i].codepoint == 0x2044) /* FRACTION SLASH */
    325     {
    326       unsigned int start = i, end = i + 1;
    327       while (start &&
    328 	     _hb_glyph_info_get_general_category (&info[start - 1]) ==
    329 	     HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER)
    330         start--;
    331       while (end < count &&
    332 	     _hb_glyph_info_get_general_category (&info[end]) ==
    333 	     HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER)
    334         end++;
    335 
    336       for (unsigned int j = start; j < i; j++)
    337         info[j].mask |= c->plan->numr_mask | c->plan->frac_mask;
    338       info[i].mask |= c->plan->frac_mask;
    339       for (unsigned int j = i + 1; j < end; j++)
    340         info[j].mask |= c->plan->frac_mask | c->plan->dnom_mask;
    341 
    342       i = end - 1;
    343     }
    344   }
    345 }
    346 
    347 static inline void
    348 hb_ot_shape_initialize_masks (hb_ot_shape_context_t *c)
    349 {
    350   hb_ot_map_t *map = &c->plan->map;
    351   hb_buffer_t *buffer = c->buffer;
    352 
    353   hb_mask_t global_mask = map->get_global_mask ();
    354   buffer->reset_masks (global_mask);
    355 }
    356 
    357 static inline void
    358 hb_ot_shape_setup_masks (hb_ot_shape_context_t *c)
    359 {
    360   hb_ot_map_t *map = &c->plan->map;
    361   hb_buffer_t *buffer = c->buffer;
    362 
    363   hb_ot_shape_setup_masks_fraction (c);
    364 
    365   if (c->plan->shaper->setup_masks)
    366     c->plan->shaper->setup_masks (c->plan, buffer, c->font);
    367 
    368   for (unsigned int i = 0; i < c->num_user_features; i++)
    369   {
    370     const hb_feature_t *feature = &c->user_features[i];
    371     if (!(feature->start == 0 && feature->end == (unsigned int)-1)) {
    372       unsigned int shift;
    373       hb_mask_t mask = map->get_mask (feature->tag, &shift);
    374       buffer->set_masks (feature->value << shift, mask, feature->start, feature->end);
    375     }
    376   }
    377 }
    378 
    379 static inline void
    380 hb_ot_map_glyphs_fast (hb_buffer_t  *buffer)
    381 {
    382   /* Normalization process sets up glyph_index(), we just copy it. */
    383   unsigned int count = buffer->len;
    384   for (unsigned int i = 0; i < count; i++)
    385     buffer->info[i].codepoint = buffer->info[i].glyph_index();
    386 }
    387 
    388 static inline void
    389 hb_synthesize_glyph_classes (hb_ot_shape_context_t *c)
    390 {
    391   unsigned int count = c->buffer->len;
    392   hb_glyph_info_t *info = c->buffer->info;
    393   for (unsigned int i = 0; i < count; i++)
    394     _hb_glyph_info_set_glyph_props (&info[i],
    395 				    _hb_glyph_info_get_general_category (&info[i])
    396 				    == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ?
    397 				    HB_OT_LAYOUT_GLYPH_PROPS_MARK :
    398 				    HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH);
    399 }
    400 
    401 static inline void
    402 hb_ot_substitute_default (hb_ot_shape_context_t *c)
    403 {
    404   hb_buffer_t *buffer = c->buffer;
    405 
    406   if (c->plan->shaper->preprocess_text)
    407     c->plan->shaper->preprocess_text (c->plan, buffer, c->font);
    408 
    409   hb_ot_shape_initialize_masks (c);
    410 
    411   hb_ot_mirror_chars (c);
    412 
    413   HB_BUFFER_ALLOCATE_VAR (buffer, glyph_index);
    414 
    415   _hb_ot_shape_normalize (c->plan, buffer, c->font);
    416 
    417   hb_ot_shape_setup_masks (c);
    418 
    419   /* This is unfortunate to go here, but necessary... */
    420   if (!hb_ot_layout_has_positioning (c->face))
    421     _hb_ot_shape_fallback_position_recategorize_marks (c->plan, c->font, buffer);
    422 
    423   hb_ot_map_glyphs_fast (buffer);
    424 
    425   HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_index);
    426 }
    427 
    428 static inline void
    429 hb_ot_substitute_complex (hb_ot_shape_context_t *c)
    430 {
    431   hb_buffer_t *buffer = c->buffer;
    432 
    433   hb_ot_layout_substitute_start (c->font, buffer);
    434 
    435   if (!hb_ot_layout_has_glyph_classes (c->face))
    436     hb_synthesize_glyph_classes (c);
    437 
    438   c->plan->substitute (c->font, buffer);
    439 
    440   hb_ot_layout_substitute_finish (c->font, buffer);
    441 
    442   return;
    443 }
    444 
    445 static inline void
    446 hb_ot_substitute (hb_ot_shape_context_t *c)
    447 {
    448   hb_ot_substitute_default (c);
    449   hb_ot_substitute_complex (c);
    450 }
    451 
    452 /* Position */
    453 
    454 static inline void
    455 zero_mark_widths_by_unicode (hb_buffer_t *buffer)
    456 {
    457   unsigned int count = buffer->len;
    458   for (unsigned int i = 0; i < count; i++)
    459     if (_hb_glyph_info_get_general_category (&buffer->info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
    460     {
    461       buffer->pos[i].x_advance = 0;
    462       buffer->pos[i].y_advance = 0;
    463     }
    464 }
    465 
    466 static inline void
    467 zero_mark_widths_by_gdef (hb_buffer_t *buffer)
    468 {
    469   unsigned int count = buffer->len;
    470   for (unsigned int i = 0; i < count; i++)
    471     if (_hb_glyph_info_is_mark (&buffer->info[i]))
    472     {
    473       buffer->pos[i].x_advance = 0;
    474       buffer->pos[i].y_advance = 0;
    475     }
    476 }
    477 
    478 static inline void
    479 hb_ot_position_default (hb_ot_shape_context_t *c)
    480 {
    481   hb_direction_t direction = c->buffer->props.direction;
    482   unsigned int count = c->buffer->len;
    483   hb_glyph_info_t *info = c->buffer->info;
    484   hb_glyph_position_t *pos = c->buffer->pos;
    485   for (unsigned int i = 0; i < count; i++)
    486   {
    487     c->font->get_glyph_advance_for_direction (info[i].codepoint,
    488 					      direction,
    489 					      &pos[i].x_advance,
    490 					      &pos[i].y_advance);
    491     c->font->subtract_glyph_origin_for_direction (info[i].codepoint,
    492 						  direction,
    493 						  &pos[i].x_offset,
    494 						  &pos[i].y_offset);
    495 
    496   }
    497 }
    498 
    499 static inline bool
    500 hb_ot_position_complex (hb_ot_shape_context_t *c)
    501 {
    502   bool ret = false;
    503   unsigned int count = c->buffer->len;
    504 
    505   switch (c->plan->shaper->zero_width_marks)
    506   {
    507     case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY:
    508       zero_mark_widths_by_gdef (c->buffer);
    509       break;
    510 
    511     /* Not currently used for any shaper:
    512     case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY:
    513       zero_mark_widths_by_unicode (c->buffer);
    514       break;
    515     */
    516 
    517     default:
    518     case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE:
    519     case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE:
    520     case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE:
    521       break;
    522   }
    523 
    524   if (hb_ot_layout_has_positioning (c->face))
    525   {
    526     hb_glyph_info_t *info = c->buffer->info;
    527     hb_glyph_position_t *pos = c->buffer->pos;
    528 
    529     /* Change glyph origin to what GPOS expects, apply GPOS, change it back. */
    530 
    531     for (unsigned int i = 0; i < count; i++) {
    532       c->font->add_glyph_origin_for_direction (info[i].codepoint,
    533 					       HB_DIRECTION_LTR,
    534 					       &pos[i].x_offset,
    535 					       &pos[i].y_offset);
    536     }
    537 
    538     c->plan->position (c->font, c->buffer);
    539 
    540     for (unsigned int i = 0; i < count; i++) {
    541       c->font->subtract_glyph_origin_for_direction (info[i].codepoint,
    542 						    HB_DIRECTION_LTR,
    543 						    &pos[i].x_offset,
    544 						    &pos[i].y_offset);
    545     }
    546 
    547     ret = true;
    548   }
    549 
    550   switch (c->plan->shaper->zero_width_marks)
    551   {
    552     case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE:
    553       zero_mark_widths_by_unicode (c->buffer);
    554       break;
    555 
    556     case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE:
    557       zero_mark_widths_by_gdef (c->buffer);
    558       break;
    559 
    560     default:
    561     case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE:
    562     //case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY:
    563     case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY:
    564       break;
    565   }
    566 
    567   return ret;
    568 }
    569 
    570 static inline void
    571 hb_ot_position (hb_ot_shape_context_t *c)
    572 {
    573   hb_ot_layout_position_start (c->font, c->buffer);
    574 
    575   hb_ot_position_default (c);
    576 
    577   hb_bool_t fallback = !hb_ot_position_complex (c);
    578 
    579   hb_ot_layout_position_finish (c->font, c->buffer);
    580 
    581   if (fallback && c->plan->shaper->fallback_position)
    582     _hb_ot_shape_fallback_position (c->plan, c->font, c->buffer);
    583 
    584   if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction))
    585     hb_buffer_reverse (c->buffer);
    586 
    587   /* Visual fallback goes here. */
    588 
    589   if (fallback)
    590     _hb_ot_shape_fallback_kern (c->plan, c->font, c->buffer);
    591 }
    592 
    593 
    594 /* Post-process */
    595 
    596 static void
    597 hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c)
    598 {
    599   if (c->buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES)
    600     return;
    601 
    602   hb_codepoint_t space;
    603   enum {
    604     SPACE_DONT_KNOW,
    605     SPACE_AVAILABLE,
    606     SPACE_UNAVAILABLE
    607   } space_status = SPACE_DONT_KNOW;
    608 
    609   unsigned int count = c->buffer->len;
    610   hb_glyph_info_t *info = c->buffer->info;
    611   hb_glyph_position_t *pos = c->buffer->pos;
    612   unsigned int j = 0;
    613   for (unsigned int i = 0; i < count; i++)
    614   {
    615     if (unlikely (!_hb_glyph_info_ligated (&info[i]) &&
    616 		  _hb_glyph_info_is_default_ignorable (&info[i])))
    617     {
    618       if (space_status == SPACE_DONT_KNOW)
    619 	space_status = c->font->get_glyph (' ', 0, &space) ? SPACE_AVAILABLE : SPACE_UNAVAILABLE;
    620 
    621       if (space_status == SPACE_AVAILABLE)
    622       {
    623 	info[i].codepoint = space;
    624 	pos[i].x_advance = 0;
    625 	pos[i].y_advance = 0;
    626       }
    627       else
    628 	continue; /* Delete it. */
    629     }
    630     if (j != i)
    631     {
    632       info[j] = info[i];
    633       pos[j] = pos[i];
    634     }
    635     j++;
    636   }
    637   c->buffer->len = j;
    638 }
    639 
    640 
    641 /* Pull it all together! */
    642 
    643 static void
    644 hb_ot_shape_internal (hb_ot_shape_context_t *c)
    645 {
    646   c->buffer->deallocate_var_all ();
    647 
    648   /* Save the original direction, we use it later. */
    649   c->target_direction = c->buffer->props.direction;
    650 
    651   _hb_buffer_allocate_unicode_vars (c->buffer);
    652 
    653   c->buffer->clear_output ();
    654 
    655   hb_set_unicode_props (c->buffer);
    656   hb_insert_dotted_circle (c->buffer, c->font);
    657   hb_form_clusters (c->buffer);
    658 
    659   hb_ensure_native_direction (c->buffer);
    660 
    661   hb_ot_substitute (c);
    662   hb_ot_position (c);
    663 
    664   hb_ot_hide_default_ignorables (c);
    665 
    666   _hb_buffer_deallocate_unicode_vars (c->buffer);
    667 
    668   c->buffer->props.direction = c->target_direction;
    669 
    670   c->buffer->deallocate_var_all ();
    671 }
    672 
    673 
    674 hb_bool_t
    675 _hb_ot_shape (hb_shape_plan_t    *shape_plan,
    676 	      hb_font_t          *font,
    677 	      hb_buffer_t        *buffer,
    678 	      const hb_feature_t *features,
    679 	      unsigned int        num_features)
    680 {
    681   hb_ot_shape_context_t c = {HB_SHAPER_DATA_GET (shape_plan), font, font->face, buffer, features, num_features};
    682   hb_ot_shape_internal (&c);
    683 
    684   return true;
    685 }
    686 
    687 
    688 void
    689 hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan,
    690 				  hb_tag_t         table_tag,
    691 				  hb_set_t        *lookup_indexes /* OUT */)
    692 {
    693   /* XXX Does the first part always succeed? */
    694   HB_SHAPER_DATA_GET (shape_plan)->collect_lookups (table_tag, lookup_indexes);
    695 }
    696 
    697 
    698 /* TODO Move this to hb-ot-shape-normalize, make it do decompose, and make it public. */
    699 static void
    700 add_char (hb_font_t          *font,
    701 	  hb_unicode_funcs_t *unicode,
    702 	  hb_bool_t           mirror,
    703 	  hb_codepoint_t      u,
    704 	  hb_set_t           *glyphs)
    705 {
    706   hb_codepoint_t glyph;
    707   if (font->get_glyph (u, 0, &glyph))
    708     glyphs->add (glyph);
    709   if (mirror)
    710   {
    711     hb_codepoint_t m = unicode->mirroring (u);
    712     if (m != u && font->get_glyph (m, 0, &glyph))
    713       glyphs->add (glyph);
    714   }
    715 }
    716 
    717 
    718 void
    719 hb_ot_shape_glyphs_closure (hb_font_t          *font,
    720 			    hb_buffer_t        *buffer,
    721 			    const hb_feature_t *features,
    722 			    unsigned int        num_features,
    723 			    hb_set_t           *glyphs)
    724 {
    725   hb_ot_shape_plan_t plan;
    726 
    727   const char *shapers[] = {"ot", NULL};
    728   hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props,
    729 							     features, num_features, shapers);
    730 
    731   bool mirror = hb_script_get_horizontal_direction (buffer->props.script) == HB_DIRECTION_RTL;
    732 
    733   unsigned int count = buffer->len;
    734   for (unsigned int i = 0; i < count; i++)
    735     add_char (font, buffer->unicode, mirror, buffer->info[i].codepoint, glyphs);
    736 
    737   hb_set_t lookups;
    738   lookups.init ();
    739   hb_ot_shape_plan_collect_lookups (shape_plan, HB_OT_TAG_GSUB, &lookups);
    740 
    741   /* And find transitive closure. */
    742   hb_set_t copy;
    743   copy.init ();
    744   do {
    745     copy.set (glyphs);
    746     for (hb_codepoint_t lookup_index = -1; hb_set_next (&lookups, &lookup_index);)
    747       hb_ot_layout_lookup_substitute_closure (font->face, lookup_index, glyphs);
    748   } while (!copy.is_equal (glyphs));
    749 
    750   hb_shape_plan_destroy (shape_plan);
    751 }
    752