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)
 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->unicode);
 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->unicode);
 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)
 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->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
 267     return;
 268 
 269   /* Loop duplicated in hb_ensure_native_direction(). */
 270   unsigned int base = 0;
 271   unsigned int count = buffer->len;
 272   hb_glyph_info_t *info = buffer->info;
 273   for (unsigned int i = 1; i < count; i++)
 274   {
 275     if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i]))))
 276     {
 277       buffer->merge_clusters (base, i);
 278       base = i;
 279     }
 280   }
 281   buffer->merge_clusters (base, count);
 282 }
 283 
 284 static void
 285 hb_ensure_native_direction (hb_buffer_t *buffer)
 286 {
 287   hb_direction_t direction = buffer->props.direction;
 288 
 289   /* TODO vertical:
 290    * The only BTT vertical script is Ogham, but it's not clear to me whether OpenType
 291    * Ogham fonts are supposed to be implemented BTT or not.  Need to research that
 292    * first. */
 293   if ((HB_DIRECTION_IS_HORIZONTAL (direction) && direction != hb_script_get_horizontal_direction (buffer->props.script)) ||
 294       (HB_DIRECTION_IS_VERTICAL   (direction) && direction != HB_DIRECTION_TTB))
 295   {
 296     /* Same loop as hb_form_clusters().
 297      * Since form_clusters() merged clusters already, we don't merge. */
 298     unsigned int base = 0;
 299     unsigned int count = buffer->len;
 300     hb_glyph_info_t *info = buffer->info;
 301     for (unsigned int i = 1; i < count; i++)
 302     {
 303       if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i]))))
 304       {
 305         if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
 306           buffer->merge_clusters (base, i);
 307         buffer->reverse_range (base, i);
 308 
 309         base = i;
 310       }
 311     }
 312     if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
 313       buffer->merge_clusters (base, count);
 314     buffer->reverse_range (base, count);
 315 
 316     buffer->reverse ();
 317 
 318     buffer->props.direction = HB_DIRECTION_REVERSE (buffer->props.direction);
 319   }
 320 }
 321 
 322 
 323 /* Substitute */
 324 
 325 static inline void
 326 hb_ot_mirror_chars (hb_ot_shape_context_t *c)
 327 {
 328   if (HB_DIRECTION_IS_FORWARD (c->target_direction))
 329     return;
 330 
 331   hb_buffer_t *buffer = c->buffer;
 332   hb_unicode_funcs_t *unicode = buffer->unicode;
 333   hb_mask_t rtlm_mask = c->plan->rtlm_mask;
 334 
 335   unsigned int count = buffer->len;
 336   hb_glyph_info_t *info = buffer->info;
 337   for (unsigned int i = 0; i < count; i++) {
 338     hb_codepoint_t codepoint = unicode->mirroring (info[i].codepoint);
 339     if (likely (codepoint == info[i].codepoint || !c->font->has_glyph (codepoint)))
 340       info[i].mask |= rtlm_mask;
 341     else
 342       info[i].codepoint = codepoint;
 343   }
 344 }
 345 
 346 static inline void
 347 hb_ot_shape_setup_masks_fraction (hb_ot_shape_context_t *c)
 348 {
 349   if (!c->plan->has_frac)
 350     return;
 351 
 352   hb_buffer_t *buffer = c->buffer;
 353 
 354   /* TODO look in pre/post context text also. */
 355   unsigned int count = buffer->len;
 356   hb_glyph_info_t *info = buffer->info;
 357   for (unsigned int i = 0; i < count; i++)
 358   {
 359     if (info[i].codepoint == 0x2044u) /* FRACTION SLASH */
 360     {
 361       unsigned int start = i, end = i + 1;
 362       while (start &&
 363              _hb_glyph_info_get_general_category (&info[start - 1]) ==
 364              HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER)
 365         start--;
 366       while (end < count &&
 367              _hb_glyph_info_get_general_category (&info[end]) ==
 368              HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER)
 369         end++;
 370 
 371       for (unsigned int j = start; j < i; j++)
 372         info[j].mask |= c->plan->numr_mask | c->plan->frac_mask;
 373       info[i].mask |= c->plan->frac_mask;
 374       for (unsigned int j = i + 1; j < end; j++)
 375         info[j].mask |= c->plan->frac_mask | c->plan->dnom_mask;
 376 
 377       i = end - 1;
 378     }
 379   }
 380 }
 381 
 382 static inline void
 383 hb_ot_shape_initialize_masks (hb_ot_shape_context_t *c)
 384 {
 385   hb_ot_map_t *map = &c->plan->map;
 386   hb_buffer_t *buffer = c->buffer;
 387 
 388   hb_mask_t global_mask = map->get_global_mask ();
 389   buffer->reset_masks (global_mask);
 390 }
 391 
 392 static inline void
 393 hb_ot_shape_setup_masks (hb_ot_shape_context_t *c)
 394 {
 395   hb_ot_map_t *map = &c->plan->map;
 396   hb_buffer_t *buffer = c->buffer;
 397 
 398   hb_ot_shape_setup_masks_fraction (c);
 399 
 400   if (c->plan->shaper->setup_masks)
 401     c->plan->shaper->setup_masks (c->plan, buffer, c->font);
 402 
 403   for (unsigned int i = 0; i < c->num_user_features; i++)
 404   {
 405     const hb_feature_t *feature = &c->user_features[i];
 406     if (!(feature->start == 0 && feature->end == (unsigned int)-1)) {
 407       unsigned int shift;
 408       hb_mask_t mask = map->get_mask (feature->tag, &shift);
 409       buffer->set_masks (feature->value << shift, mask, feature->start, feature->end);
 410     }
 411   }
 412 }
 413 
 414 static void
 415 hb_ot_zero_width_default_ignorables (hb_ot_shape_context_t *c)
 416 {
 417   hb_buffer_t *buffer = c->buffer;
 418 
 419   if (buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES)
 420     return;
 421 
 422   unsigned int count = buffer->len;
 423   hb_glyph_info_t *info = buffer->info;
 424   hb_glyph_position_t *pos = buffer->pos;
 425   unsigned int i = 0;
 426   for (i = 0; i < count; i++)
 427     if (unlikely (_hb_glyph_info_is_default_ignorable (&info[i])))
 428       pos[i].x_advance = pos[i].y_advance = pos[i].x_offset = pos[i].y_offset = 0;
 429 }
 430 
 431 static void
 432 hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c)
 433 {
 434   hb_buffer_t *buffer = c->buffer;
 435 
 436   if (buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES)
 437     return;
 438 
 439   unsigned int count = buffer->len;
 440   hb_glyph_info_t *info = buffer->info;
 441   hb_glyph_position_t *pos = buffer->pos;
 442   unsigned int i = 0;
 443   for (i = 0; i < count; i++)
 444   {
 445     if (unlikely (_hb_glyph_info_is_default_ignorable (&info[i])))
 446       break;
 447   }
 448 
 449   /* No default-ignorables found; return. */
 450   if (i == count)
 451     return;
 452 
 453   hb_codepoint_t space;
 454   if (c->font->get_glyph (' ', 0, &space))
 455   {
 456     /* Replace default-ignorables with a zero-advance space glyph. */
 457     for (/*continue*/; i < count; i++)
 458     {
 459       if (_hb_glyph_info_is_default_ignorable (&info[i]))
 460         info[i].codepoint = space;
 461     }
 462   }
 463   else
 464   {
 465     /* Merge clusters and delete default-ignorables.
 466      * NOTE! We can't use out-buffer as we have positioning data. */
 467     unsigned int j = i;
 468     for (; i < count; i++)
 469     {
 470       if (_hb_glyph_info_is_default_ignorable (&info[i]))
 471       {
 472         /* Merge clusters.
 473          * Same logic as buffer->delete_glyph(), but for in-place removal. */
 474 
 475         unsigned int cluster = info[i].cluster;
 476         if (i + 1 < count && cluster == info[i + 1].cluster)
 477           continue; /* Cluster survives; do nothing. */
 478 
 479         if (j)
 480         {
 481           /* Merge cluster backward. */
 482           if (cluster < info[j - 1].cluster)
 483           {
 484             unsigned int old_cluster = info[j - 1].cluster;
 485             for (unsigned k = j; k && info[k - 1].cluster == old_cluster; k--)
 486               info[k - 1].cluster = cluster;
 487           }
 488           continue;
 489         }
 490 
 491         if (i + 1 < count)
 492           buffer->merge_clusters (i, i + 2); /* Merge cluster forward. */
 493 
 494         continue;
 495       }
 496 
 497       if (j != i)
 498       {
 499         info[j] = info[i];
 500         pos[j] = pos[i];
 501       }
 502       j++;
 503     }
 504     buffer->len = j;
 505   }
 506 }
 507 
 508 
 509 static inline void
 510 hb_ot_map_glyphs_fast (hb_buffer_t  *buffer)
 511 {
 512   /* Normalization process sets up glyph_index(), we just copy it. */
 513   unsigned int count = buffer->len;
 514   hb_glyph_info_t *info = buffer->info;
 515   for (unsigned int i = 0; i < count; i++)
 516     info[i].codepoint = info[i].glyph_index();
 517 
 518   buffer->content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS;
 519 }
 520 
 521 static inline void
 522 hb_synthesize_glyph_classes (hb_ot_shape_context_t *c)
 523 {
 524   unsigned int count = c->buffer->len;
 525   hb_glyph_info_t *info = c->buffer->info;
 526   for (unsigned int i = 0; i < count; i++)
 527   {
 528     hb_ot_layout_glyph_class_mask_t klass;
 529 
 530     /* Never mark default-ignorables as marks.
 531      * They won't get in the way of lookups anyway,
 532      * but having them as mark will cause them to be skipped
 533      * over if the lookup-flag says so, but at least for the
 534      * Mongolian variation selectors, looks like Uniscribe
 535      * marks them as non-mark.  Some Mongolian fonts without
 536      * GDEF rely on this.  Another notable character that
 537      * this applies to is COMBINING GRAPHEME JOINER. */
 538     klass = (_hb_glyph_info_get_general_category (&info[i]) !=
 539              HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ||
 540              _hb_glyph_info_is_default_ignorable (&info[i])) ?
 541             HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH :
 542             HB_OT_LAYOUT_GLYPH_PROPS_MARK;
 543     _hb_glyph_info_set_glyph_props (&info[i], klass);
 544   }
 545 }
 546 
 547 static inline void
 548 hb_ot_substitute_default (hb_ot_shape_context_t *c)
 549 {
 550   hb_buffer_t *buffer = c->buffer;
 551 
 552   if (c->plan->shaper->preprocess_text)
 553     c->plan->shaper->preprocess_text (c->plan, buffer, c->font);
 554 
 555   hb_ot_shape_initialize_masks (c);
 556 
 557   hb_ot_mirror_chars (c);
 558 
 559   HB_BUFFER_ALLOCATE_VAR (buffer, glyph_index);
 560 
 561   _hb_ot_shape_normalize (c->plan, buffer, c->font);
 562 
 563   hb_ot_shape_setup_masks (c);
 564 
 565   /* This is unfortunate to go here, but necessary... */
 566   if (!hb_ot_layout_has_positioning (c->face))
 567     _hb_ot_shape_fallback_position_recategorize_marks (c->plan, c->font, buffer);
 568 
 569   hb_ot_map_glyphs_fast (buffer);
 570 
 571   HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_index);
 572 }
 573 
 574 static inline void
 575 hb_ot_substitute_complex (hb_ot_shape_context_t *c)
 576 {
 577   hb_buffer_t *buffer = c->buffer;
 578 
 579   _hb_buffer_allocate_gsubgpos_vars (buffer);
 580   hb_ot_layout_substitute_start (c->font, buffer);
 581 
 582   if (!hb_ot_layout_has_glyph_classes (c->face))
 583     hb_synthesize_glyph_classes (c);
 584 
 585   c->plan->substitute (c->font, buffer);
 586 
 587   hb_ot_layout_substitute_finish (c->font, buffer);
 588 
 589   return;
 590 }
 591 
 592 static inline void
 593 hb_ot_substitute (hb_ot_shape_context_t *c)
 594 {
 595   hb_ot_substitute_default (c);
 596   hb_ot_substitute_complex (c);
 597 }
 598 
 599 /* Position */
 600 
 601 static inline void
 602 adjust_mark_offsets (hb_glyph_position_t *pos)
 603 {
 604   pos->x_offset -= pos->x_advance;
 605   pos->y_offset -= pos->y_advance;
 606 }
 607 
 608 static inline void
 609 zero_mark_width (hb_glyph_position_t *pos)
 610 {
 611   pos->x_advance = 0;
 612   pos->y_advance = 0;
 613 }
 614 
 615 static inline void
 616 zero_mark_widths_by_unicode (hb_buffer_t *buffer, bool adjust_offsets)
 617 {
 618   unsigned int count = buffer->len;
 619   hb_glyph_info_t *info = buffer->info;
 620   for (unsigned int i = 0; i < count; i++)
 621     if (_hb_glyph_info_get_general_category (&info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
 622     {
 623       if (adjust_offsets)
 624         adjust_mark_offsets (&buffer->pos[i]);
 625       zero_mark_width (&buffer->pos[i]);
 626     }
 627 }
 628 
 629 static inline void
 630 zero_mark_widths_by_gdef (hb_buffer_t *buffer, bool adjust_offsets)
 631 {
 632   unsigned int count = buffer->len;
 633   hb_glyph_info_t *info = buffer->info;
 634   for (unsigned int i = 0; i < count; i++)
 635     if (_hb_glyph_info_is_mark (&info[i]))
 636     {
 637       if (adjust_offsets)
 638         adjust_mark_offsets (&buffer->pos[i]);
 639       zero_mark_width (&buffer->pos[i]);
 640     }
 641 }
 642 
 643 static inline void
 644 hb_ot_position_default (hb_ot_shape_context_t *c)
 645 {
 646   hb_direction_t direction = c->buffer->props.direction;
 647   unsigned int count = c->buffer->len;
 648   hb_glyph_info_t *info = c->buffer->info;
 649   hb_glyph_position_t *pos = c->buffer->pos;
 650   for (unsigned int i = 0; i < count; i++)
 651   {
 652     c->font->get_glyph_advance_for_direction (info[i].codepoint,
 653                                               direction,
 654                                               &pos[i].x_advance,
 655                                               &pos[i].y_advance);
 656     c->font->subtract_glyph_origin_for_direction (info[i].codepoint,
 657                                                   direction,
 658                                                   &pos[i].x_offset,
 659                                                   &pos[i].y_offset);
 660 
 661   }
 662 }
 663 
 664 static inline bool
 665 hb_ot_position_complex (hb_ot_shape_context_t *c)
 666 {
 667   bool ret = false;
 668   unsigned int count = c->buffer->len;
 669   bool has_positioning = hb_ot_layout_has_positioning (c->face);
 670   /* If the font has no GPOS, AND, no fallback positioning will
 671    * happen, AND, direction is forward, then when zeroing mark
 672    * widths, we shift the mark with it, such that the mark
 673    * is positioned hanging over the previous glyph.  When
 674    * direction is backward we don't shift and it will end up
 675    * hanging over the next glyph after the final reordering.
 676    * If fallback positinoing happens or GPOS is present, we don't
 677    * care.
 678    */
 679   bool adjust_offsets_when_zeroing = !(has_positioning || c->plan->shaper->fallback_position ||
 680                                        HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction));
 681 
 682   switch (c->plan->shaper->zero_width_marks)
 683   {
 684     case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY:
 685       zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing);
 686       break;
 687 
 688     /* Not currently used for any shaper:
 689     case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY:
 690       zero_mark_widths_by_unicode (c->buffer, adjust_offsets_when_zeroing);
 691       break;
 692     */
 693 
 694     default:
 695     case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE:
 696     case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE:
 697     case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE:
 698       break;
 699   }
 700 
 701   if (has_positioning)
 702   {
 703     hb_glyph_info_t *info = c->buffer->info;
 704     hb_glyph_position_t *pos = c->buffer->pos;
 705 
 706     /* Change glyph origin to what GPOS expects, apply GPOS, change it back. */
 707 
 708     for (unsigned int i = 0; i < count; i++) {
 709       c->font->add_glyph_origin_for_direction (info[i].codepoint,
 710                                                HB_DIRECTION_LTR,
 711                                                &pos[i].x_offset,
 712                                                &pos[i].y_offset);
 713     }
 714 
 715     c->plan->position (c->font, c->buffer);
 716 
 717     for (unsigned int i = 0; i < count; i++) {
 718       c->font->subtract_glyph_origin_for_direction (info[i].codepoint,
 719                                                     HB_DIRECTION_LTR,
 720                                                     &pos[i].x_offset,
 721                                                     &pos[i].y_offset);
 722     }
 723 
 724     ret = true;
 725   }
 726 
 727   switch (c->plan->shaper->zero_width_marks)
 728   {
 729     case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE:
 730       zero_mark_widths_by_unicode (c->buffer, adjust_offsets_when_zeroing);
 731       break;
 732 
 733     case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE:
 734       zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing);
 735       break;
 736 
 737     default:
 738     case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE:
 739     //case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY:
 740     case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY:
 741       break;
 742   }
 743 
 744   return ret;
 745 }
 746 
 747 static inline void
 748 hb_ot_position (hb_ot_shape_context_t *c)
 749 {
 750   hb_ot_layout_position_start (c->font, c->buffer);
 751 
 752   hb_ot_position_default (c);
 753 
 754   hb_bool_t fallback = !hb_ot_position_complex (c);
 755 
 756   hb_ot_zero_width_default_ignorables (c);
 757 
 758   hb_ot_layout_position_finish (c->font, c->buffer);
 759 
 760   if (fallback && c->plan->shaper->fallback_position)
 761     _hb_ot_shape_fallback_position (c->plan, c->font, c->buffer);
 762 
 763   if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction))
 764     hb_buffer_reverse (c->buffer);
 765 
 766   /* Visual fallback goes here. */
 767 
 768   if (fallback)
 769     _hb_ot_shape_fallback_kern (c->plan, c->font, c->buffer);
 770 
 771   _hb_buffer_deallocate_gsubgpos_vars (c->buffer);
 772 }
 773 
 774 
 775 /* Pull it all together! */
 776 
 777 static void
 778 hb_ot_shape_internal (hb_ot_shape_context_t *c)
 779 {
 780   c->buffer->deallocate_var_all ();
 781 
 782   /* Save the original direction, we use it later. */
 783   c->target_direction = c->buffer->props.direction;
 784 
 785   _hb_buffer_allocate_unicode_vars (c->buffer);
 786 
 787   c->buffer->clear_output ();
 788 
 789   hb_set_unicode_props (c->buffer);
 790   hb_insert_dotted_circle (c->buffer, c->font);
 791   hb_form_clusters (c->buffer);
 792 
 793   hb_ensure_native_direction (c->buffer);
 794 
 795   hb_ot_substitute (c);
 796   hb_ot_position (c);
 797 
 798   hb_ot_hide_default_ignorables (c);
 799 
 800   _hb_buffer_deallocate_unicode_vars (c->buffer);
 801 
 802   c->buffer->props.direction = c->target_direction;
 803 
 804   c->buffer->deallocate_var_all ();
 805 }
 806 
 807 
 808 hb_bool_t
 809 _hb_ot_shape (hb_shape_plan_t    *shape_plan,
 810               hb_font_t          *font,
 811               hb_buffer_t        *buffer,
 812               const hb_feature_t *features,
 813               unsigned int        num_features)
 814 {
 815   hb_ot_shape_context_t c = {HB_SHAPER_DATA_GET (shape_plan), font, font->face, buffer, features, num_features};
 816   hb_ot_shape_internal (&c);
 817 
 818   return true;
 819 }
 820 
 821 
 822 /**
 823  * Since: 0.9.7
 824  **/
 825 void
 826 hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan,
 827                                   hb_tag_t         table_tag,
 828                                   hb_set_t        *lookup_indexes /* OUT */)
 829 {
 830   /* XXX Does the first part always succeed? */
 831   HB_SHAPER_DATA_GET (shape_plan)->collect_lookups (table_tag, lookup_indexes);
 832 }
 833 
 834 
 835 /* TODO Move this to hb-ot-shape-normalize, make it do decompose, and make it public. */
 836 static void
 837 add_char (hb_font_t          *font,
 838           hb_unicode_funcs_t *unicode,
 839           hb_bool_t           mirror,
 840           hb_codepoint_t      u,
 841           hb_set_t           *glyphs)
 842 {
 843   hb_codepoint_t glyph;
 844   if (font->get_glyph (u, 0, &glyph))
 845     glyphs->add (glyph);
 846   if (mirror)
 847   {
 848     hb_codepoint_t m = unicode->mirroring (u);
 849     if (m != u && font->get_glyph (m, 0, &glyph))
 850       glyphs->add (glyph);
 851   }
 852 }
 853 
 854 
 855 /**
 856  * Since: 0.9.2
 857  **/
 858 void
 859 hb_ot_shape_glyphs_closure (hb_font_t          *font,
 860                             hb_buffer_t        *buffer,
 861                             const hb_feature_t *features,
 862                             unsigned int        num_features,
 863                             hb_set_t           *glyphs)
 864 {
 865   hb_ot_shape_plan_t plan;
 866 
 867   const char *shapers[] = {"ot", NULL};
 868   hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props,
 869                                                              features, num_features, shapers);
 870 
 871   bool mirror = hb_script_get_horizontal_direction (buffer->props.script) == HB_DIRECTION_RTL;
 872 
 873   unsigned int count = buffer->len;
 874   hb_glyph_info_t *info = buffer->info;
 875   for (unsigned int i = 0; i < count; i++)
 876     add_char (font, buffer->unicode, mirror, info[i].codepoint, glyphs);
 877 
 878   hb_set_t lookups;
 879   lookups.init ();
 880   hb_ot_shape_plan_collect_lookups (shape_plan, HB_OT_TAG_GSUB, &lookups);
 881 
 882   /* And find transitive closure. */
 883   hb_set_t copy;
 884   copy.init ();
 885   do {
 886     copy.set (glyphs);
 887     for (hb_codepoint_t lookup_index = -1; hb_set_next (&lookups, &lookup_index);)
 888       hb_ot_layout_lookup_substitute_closure (font->face, lookup_index, glyphs);
 889   } while (!copy.is_equal (glyphs));
 890 
 891   hb_shape_plan_destroy (shape_plan);
 892 }