LCOV - code coverage report
Current view: top level - gfx/harfbuzz/src - hb-ot-shape.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 210 412 51.0 %
Date: 2017-07-14 16:53:18 Functions: 28 35 80.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13