LCOV - code coverage report
Current view: directory - gfx/harfbuzz/src - hb-ot-shape.cc (source / functions) Found Hit Coverage
Test: app.info Lines: 186 0 0.0 %
Date: 2012-06-02 Functions: 19 0 0.0 %

       1                 : /*
       2                 :  * Copyright © 2009,2010  Red Hat, Inc.
       3                 :  * Copyright © 2010,2011  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                 : #include "hb-ot-shape-private.hh"
      30                 : #include "hb-ot-shape-complex-private.hh"
      31                 : 
      32                 : #include "hb-font-private.hh"
      33                 : 
      34                 : 
      35                 : 
      36                 : hb_tag_t common_features[] = {
      37                 :   HB_TAG('c','c','m','p'),
      38                 :   HB_TAG('l','o','c','l'),
      39                 :   HB_TAG('m','a','r','k'),
      40                 :   HB_TAG('m','k','m','k'),
      41                 :   HB_TAG('r','l','i','g'),
      42                 : };
      43                 : 
      44                 : hb_tag_t horizontal_features[] = {
      45                 :   HB_TAG('c','a','l','t'),
      46                 :   HB_TAG('c','l','i','g'),
      47                 :   HB_TAG('c','u','r','s'),
      48                 :   HB_TAG('k','e','r','n'),
      49                 :   HB_TAG('l','i','g','a'),
      50                 : };
      51                 : 
      52                 : /* Note:
      53                 :  * Technically speaking, vrt2 and vert are mutually exclusive.
      54                 :  * According to the spec, valt and vpal are also mutually exclusive.
      55                 :  * But we apply them all for now.
      56                 :  */
      57                 : hb_tag_t vertical_features[] = {
      58                 :   HB_TAG('v','a','l','t'),
      59                 :   HB_TAG('v','e','r','t'),
      60                 :   HB_TAG('v','k','r','n'),
      61                 :   HB_TAG('v','p','a','l'),
      62                 :   HB_TAG('v','r','t','2'),
      63                 : };
      64                 : 
      65                 : static void
      66               0 : hb_ot_shape_collect_features (hb_ot_shape_planner_t          *planner,
      67                 :                               const hb_segment_properties_t  *props,
      68                 :                               const hb_feature_t             *user_features,
      69                 :                               unsigned int                    num_user_features)
      70                 : {
      71               0 :   switch (props->direction) {
      72                 :     case HB_DIRECTION_LTR:
      73               0 :       planner->map.add_bool_feature (HB_TAG ('l','t','r','a'));
      74               0 :       planner->map.add_bool_feature (HB_TAG ('l','t','r','m'));
      75               0 :       break;
      76                 :     case HB_DIRECTION_RTL:
      77               0 :       planner->map.add_bool_feature (HB_TAG ('r','t','l','a'));
      78               0 :       planner->map.add_bool_feature (HB_TAG ('r','t','l','m'), false);
      79               0 :       break;
      80                 :     case HB_DIRECTION_TTB:
      81                 :     case HB_DIRECTION_BTT:
      82                 :     case HB_DIRECTION_INVALID:
      83                 :     default:
      84               0 :       break;
      85                 :   }
      86                 : 
      87                 : #define ADD_FEATURES(array) \
      88                 :   HB_STMT_START { \
      89                 :     for (unsigned int i = 0; i < ARRAY_LENGTH (array); i++) \
      90                 :       planner->map.add_bool_feature (array[i]); \
      91                 :   } HB_STMT_END
      92                 : 
      93               0 :   hb_ot_shape_complex_collect_features (planner->shaper, &planner->map, props);
      94                 : 
      95               0 :   ADD_FEATURES (common_features);
      96                 : 
      97               0 :   if (HB_DIRECTION_IS_HORIZONTAL (props->direction))
      98               0 :     ADD_FEATURES (horizontal_features);
      99                 :   else
     100               0 :     ADD_FEATURES (vertical_features);
     101                 : 
     102                 : #undef ADD_FEATURES
     103                 : 
     104               0 :   for (unsigned int i = 0; i < num_user_features; i++) {
     105               0 :     const hb_feature_t *feature = &user_features[i];
     106               0 :     planner->map.add_feature (feature->tag, feature->value, (feature->start == 0 && feature->end == (unsigned int) -1));
     107                 :   }
     108               0 : }
     109                 : 
     110                 : 
     111                 : static void
     112               0 : hb_ot_shape_setup_masks (hb_ot_shape_context_t *c)
     113                 : {
     114               0 :   hb_mask_t global_mask = c->plan->map.get_global_mask ();
     115               0 :   c->buffer->reset_masks (global_mask);
     116                 : 
     117               0 :   hb_ot_shape_complex_setup_masks (c->plan->shaper, &c->plan->map, c->buffer);
     118                 : 
     119               0 :   for (unsigned int i = 0; i < c->num_user_features; i++)
     120                 :   {
     121               0 :     const hb_feature_t *feature = &c->user_features[i];
     122               0 :     if (!(feature->start == 0 && feature->end == (unsigned int)-1)) {
     123                 :       unsigned int shift;
     124               0 :       hb_mask_t mask = c->plan->map.get_mask (feature->tag, &shift);
     125               0 :       c->buffer->set_masks (feature->value << shift, mask, feature->start, feature->end);
     126                 :     }
     127                 :   }
     128               0 : }
     129                 : 
     130                 : 
     131                 : /* Main shaper */
     132                 : 
     133                 : /* Prepare */
     134                 : 
     135                 : void
     136               0 : _hb_set_unicode_props (hb_buffer_t *buffer)
     137                 : {
     138               0 :   unsigned int count = buffer->len;
     139               0 :   for (unsigned int i = 1; i < count; i++)
     140               0 :     hb_glyph_info_set_unicode_props (&buffer->info[i], buffer->unicode);
     141               0 : }
     142                 : 
     143                 : static void
     144               0 : hb_form_clusters (hb_buffer_t *buffer)
     145                 : {
     146               0 :   unsigned int count = buffer->len;
     147               0 :   for (unsigned int i = 1; i < count; i++)
     148               0 :     if (FLAG (buffer->info[i].general_category()) &
     149                 :         (FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) |
     150                 :          FLAG (HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) |
     151                 :          FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)))
     152               0 :       buffer->info[i].cluster = buffer->info[i - 1].cluster;
     153               0 : }
     154                 : 
     155                 : static void
     156               0 : hb_ensure_native_direction (hb_buffer_t *buffer)
     157                 : {
     158               0 :   hb_direction_t direction = buffer->props.direction;
     159                 : 
     160                 :   /* TODO vertical:
     161                 :    * The only BTT vertical script is Ogham, but it's not clear to me whether OpenType
     162                 :    * Ogham fonts are supposed to be implemented BTT or not.  Need to research that
     163                 :    * first. */
     164               0 :   if ((HB_DIRECTION_IS_HORIZONTAL (direction) && direction != hb_script_get_horizontal_direction (buffer->props.script)) ||
     165                 :       (HB_DIRECTION_IS_VERTICAL   (direction) && direction != HB_DIRECTION_TTB))
     166                 :   {
     167               0 :     hb_buffer_reverse_clusters (buffer);
     168               0 :     buffer->props.direction = HB_DIRECTION_REVERSE (buffer->props.direction);
     169                 :   }
     170               0 : }
     171                 : 
     172                 : 
     173                 : /* Substitute */
     174                 : 
     175                 : static void
     176               0 : hb_mirror_chars (hb_ot_shape_context_t *c)
     177                 : {
     178               0 :   hb_unicode_funcs_t *unicode = c->buffer->unicode;
     179                 : 
     180               0 :   if (HB_DIRECTION_IS_FORWARD (c->target_direction))
     181               0 :     return;
     182                 : 
     183               0 :   hb_mask_t rtlm_mask = c->plan->map.get_1_mask (HB_TAG ('r','t','l','m'));
     184                 : 
     185               0 :   unsigned int count = c->buffer->len;
     186               0 :   for (unsigned int i = 0; i < count; i++) {
     187               0 :     hb_codepoint_t codepoint = hb_unicode_mirroring (unicode, c->buffer->info[i].codepoint);
     188               0 :     if (likely (codepoint == c->buffer->info[i].codepoint))
     189               0 :       c->buffer->info[i].mask |= rtlm_mask; /* XXX this should be moved to before setting user-feature masks */
     190                 :     else
     191               0 :       c->buffer->info[i].codepoint = codepoint;
     192                 :   }
     193                 : }
     194                 : 
     195                 : static void
     196               0 : hb_map_glyphs (hb_font_t    *font,
     197                 :                hb_buffer_t  *buffer)
     198                 : {
     199                 :   hb_codepoint_t glyph;
     200                 : 
     201               0 :   if (unlikely (!buffer->len))
     202               0 :     return;
     203                 : 
     204               0 :   buffer->clear_output ();
     205                 : 
     206               0 :   unsigned int count = buffer->len - 1;
     207               0 :   for (buffer->idx = 0; buffer->idx < count;) {
     208               0 :     if (unlikely (is_variation_selector (buffer->info[buffer->idx + 1].codepoint))) {
     209               0 :       hb_font_get_glyph (font, buffer->info[buffer->idx].codepoint, buffer->info[buffer->idx + 1].codepoint, &glyph);
     210               0 :       buffer->replace_glyph (glyph);
     211               0 :       buffer->skip_glyph ();
     212                 :     } else {
     213               0 :       hb_font_get_glyph (font, buffer->info[buffer->idx].codepoint, 0, &glyph);
     214               0 :       buffer->replace_glyph (glyph);
     215                 :     }
     216                 :   }
     217               0 :   if (likely (buffer->idx < buffer->len)) {
     218               0 :     hb_font_get_glyph (font, buffer->info[buffer->idx].codepoint, 0, &glyph);
     219               0 :     buffer->replace_glyph (glyph);
     220                 :   }
     221               0 :   buffer->swap_buffers ();
     222                 : }
     223                 : 
     224                 : static void
     225               0 : hb_substitute_default (hb_ot_shape_context_t *c)
     226                 : {
     227               0 :   hb_ot_layout_substitute_start (c->buffer);
     228                 : 
     229               0 :   hb_mirror_chars (c);
     230                 : 
     231               0 :   hb_map_glyphs (c->font, c->buffer);
     232               0 : }
     233                 : 
     234                 : static void
     235               0 : hb_ot_substitute_complex (hb_ot_shape_context_t *c)
     236                 : {
     237               0 :   if (hb_ot_layout_has_substitution (c->face)) {
     238               0 :     c->plan->map.substitute (c->face, c->buffer);
     239               0 :     c->applied_substitute_complex = TRUE;
     240                 :   }
     241                 : 
     242               0 :   hb_ot_layout_substitute_finish (c->buffer);
     243                 : 
     244                 :   return;
     245                 : }
     246                 : 
     247                 : static void
     248               0 : hb_substitute_complex_fallback (hb_ot_shape_context_t *c HB_UNUSED)
     249                 : {
     250                 :   /* TODO Arabic */
     251               0 : }
     252                 : 
     253                 : 
     254                 : /* Position */
     255                 : 
     256                 : static void
     257               0 : hb_position_default (hb_ot_shape_context_t *c)
     258                 : {
     259               0 :   hb_ot_layout_position_start (c->buffer);
     260                 : 
     261               0 :   unsigned int count = c->buffer->len;
     262               0 :   for (unsigned int i = 0; i < count; i++) {
     263               0 :     hb_font_get_glyph_advance_for_direction (c->font, c->buffer->info[i].codepoint,
     264                 :                                              c->buffer->props.direction,
     265               0 :                                              &c->buffer->pos[i].x_advance,
     266               0 :                                              &c->buffer->pos[i].y_advance);
     267               0 :     hb_font_subtract_glyph_origin_for_direction (c->font, c->buffer->info[i].codepoint,
     268                 :                                                  c->buffer->props.direction,
     269               0 :                                                  &c->buffer->pos[i].x_offset,
     270               0 :                                                  &c->buffer->pos[i].y_offset);
     271                 :   }
     272               0 : }
     273                 : 
     274                 : static void
     275               0 : hb_ot_position_complex (hb_ot_shape_context_t *c)
     276                 : {
     277                 : 
     278               0 :   if (hb_ot_layout_has_positioning (c->face))
     279                 :   {
     280                 :     /* Change glyph origin to what GPOS expects, apply GPOS, change it back. */
     281                 : 
     282               0 :     unsigned int count = c->buffer->len;
     283               0 :     for (unsigned int i = 0; i < count; i++) {
     284               0 :       hb_font_add_glyph_origin_for_direction (c->font, c->buffer->info[i].codepoint,
     285                 :                                               HB_DIRECTION_LTR,
     286               0 :                                               &c->buffer->pos[i].x_offset,
     287               0 :                                               &c->buffer->pos[i].y_offset);
     288                 :     }
     289                 : 
     290               0 :     c->plan->map.position (c->font, c->buffer);
     291                 : 
     292               0 :     for (unsigned int i = 0; i < count; i++) {
     293               0 :       hb_font_subtract_glyph_origin_for_direction (c->font, c->buffer->info[i].codepoint,
     294                 :                                                    HB_DIRECTION_LTR,
     295               0 :                                                    &c->buffer->pos[i].x_offset,
     296               0 :                                                    &c->buffer->pos[i].y_offset);
     297                 :     }
     298                 : 
     299               0 :     c->applied_position_complex = TRUE;
     300                 :   }
     301                 : 
     302               0 :   hb_ot_layout_position_finish (c->face, c->buffer);
     303                 : 
     304                 :   return;
     305                 : }
     306                 : 
     307                 : static void
     308               0 : hb_position_complex_fallback (hb_ot_shape_context_t *c)
     309                 : {
     310               0 :   unsigned int count = c->buffer->len;
     311               0 :   if (c->buffer->props.direction == HB_DIRECTION_RTL) {
     312               0 :     for (unsigned int i = 1; i < count; i++) {
     313               0 :       unsigned int gen_cat = c->buffer->info[i].general_category();
     314               0 :       if ((1<<gen_cat) & ((1<<HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)|
     315                 :                           (1<<HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK)|
     316                 :                           (1<<HB_UNICODE_GENERAL_CATEGORY_FORMAT))) {
     317               0 :         c->buffer->pos[i].x_advance = 0;
     318                 :       }
     319                 :     }
     320                 :   } else {
     321               0 :     for (unsigned int i = 1; i < count; i++) {
     322               0 :       unsigned int gen_cat = c->buffer->info[i].general_category();
     323               0 :       if ((1<<gen_cat) & ((1<<HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)|
     324                 :                           (1<<HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK)|
     325                 :                           (1<<HB_UNICODE_GENERAL_CATEGORY_FORMAT))) {
     326               0 :         hb_glyph_position_t& pos = c->buffer->pos[i];
     327               0 :         pos.x_offset = -pos.x_advance;
     328               0 :         pos.x_advance = 0;
     329                 :       }
     330                 :     }
     331                 :   }
     332               0 : }
     333                 : 
     334                 : static void
     335               0 : hb_truetype_kern (hb_ot_shape_context_t *c)
     336                 : {
     337                 :   /* TODO Check for kern=0 */
     338               0 :   unsigned int count = c->buffer->len;
     339               0 :   for (unsigned int i = 1; i < count; i++) {
     340                 :     hb_position_t x_kern, y_kern, kern1, kern2;
     341                 :     hb_font_get_glyph_kerning_for_direction (c->font,
     342               0 :                                              c->buffer->info[i - 1].codepoint, c->buffer->info[i].codepoint,
     343                 :                                              c->buffer->props.direction,
     344               0 :                                              &x_kern, &y_kern);
     345                 : 
     346               0 :     kern1 = x_kern >> 1;
     347               0 :     kern2 = x_kern - kern1;
     348               0 :     c->buffer->pos[i - 1].x_advance += kern1;
     349               0 :     c->buffer->pos[i].x_advance += kern2;
     350               0 :     c->buffer->pos[i].x_offset += kern2;
     351                 : 
     352               0 :     kern1 = y_kern >> 1;
     353               0 :     kern2 = y_kern - kern1;
     354               0 :     c->buffer->pos[i - 1].y_advance += kern1;
     355               0 :     c->buffer->pos[i].y_advance += kern2;
     356               0 :     c->buffer->pos[i].y_offset += kern2;
     357                 :   }
     358               0 : }
     359                 : 
     360                 : static void
     361               0 : hb_position_complex_fallback_visual (hb_ot_shape_context_t *c)
     362                 : {
     363               0 :   hb_truetype_kern (c);
     364               0 : }
     365                 : 
     366                 : 
     367                 : /* Do it! */
     368                 : 
     369                 : static void
     370               0 : hb_ot_shape_execute_internal (hb_ot_shape_context_t *c)
     371                 : {
     372               0 :   c->buffer->deallocate_var_all ();
     373                 : 
     374                 :   /* Save the original direction, we use it later. */
     375               0 :   c->target_direction = c->buffer->props.direction;
     376                 : 
     377               0 :   HB_BUFFER_ALLOCATE_VAR (c->buffer, general_category);
     378               0 :   HB_BUFFER_ALLOCATE_VAR (c->buffer, combining_class);
     379                 : 
     380               0 :   _hb_set_unicode_props (c->buffer); /* BUFFER: Set general_category and combining_class */
     381                 : 
     382               0 :   hb_form_clusters (c->buffer);
     383                 : 
     384               0 :   hb_ensure_native_direction (c->buffer);
     385                 : 
     386               0 :   _hb_ot_shape_normalize (c);
     387                 : 
     388               0 :   hb_ot_shape_setup_masks (c);
     389                 : 
     390                 :   /* SUBSTITUTE */
     391                 :   {
     392               0 :     hb_substitute_default (c);
     393                 : 
     394               0 :     hb_ot_substitute_complex (c);
     395                 : 
     396               0 :     if (!c->applied_substitute_complex)
     397               0 :       hb_substitute_complex_fallback (c);
     398                 :   }
     399                 : 
     400                 :   /* POSITION */
     401                 :   {
     402               0 :     hb_position_default (c);
     403                 : 
     404               0 :     hb_ot_position_complex (c);
     405                 : 
     406               0 :     hb_bool_t position_fallback = !c->applied_position_complex;
     407               0 :     if (position_fallback)
     408               0 :       hb_position_complex_fallback (c);
     409                 : 
     410               0 :     if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction))
     411               0 :       hb_buffer_reverse (c->buffer);
     412                 : 
     413               0 :     if (position_fallback)
     414               0 :       hb_position_complex_fallback_visual (c);
     415                 :   }
     416                 : 
     417               0 :   HB_BUFFER_DEALLOCATE_VAR (c->buffer, combining_class);
     418               0 :   HB_BUFFER_DEALLOCATE_VAR (c->buffer, general_category);
     419                 : 
     420               0 :   c->buffer->props.direction = c->target_direction;
     421                 : 
     422               0 :   c->buffer->deallocate_var_all ();
     423               0 : }
     424                 : 
     425                 : static void
     426               0 : hb_ot_shape_plan_internal (hb_ot_shape_plan_t       *plan,
     427                 :                            hb_face_t                *face,
     428                 :                            const hb_segment_properties_t  *props,
     429                 :                            const hb_feature_t       *user_features,
     430                 :                            unsigned int              num_user_features)
     431                 : {
     432               0 :   hb_ot_shape_planner_t planner;
     433                 : 
     434               0 :   planner.shaper = hb_ot_shape_complex_categorize (props);
     435                 : 
     436               0 :   hb_ot_shape_collect_features (&planner, props, user_features, num_user_features);
     437                 : 
     438               0 :   planner.compile (face, props, *plan);
     439               0 : }
     440                 : 
     441                 : static void
     442               0 : hb_ot_shape_execute (hb_ot_shape_plan_t *plan,
     443                 :                      hb_font_t          *font,
     444                 :                      hb_buffer_t        *buffer,
     445                 :                      const hb_feature_t *user_features,
     446                 :                      unsigned int        num_user_features)
     447                 : {
     448               0 :   hb_ot_shape_context_t c = {plan, font, font->face, buffer, user_features, num_user_features};
     449               0 :   hb_ot_shape_execute_internal (&c);
     450               0 : }
     451                 : 
     452                 : hb_bool_t
     453               0 : hb_ot_shape (hb_font_t          *font,
     454                 :              hb_buffer_t        *buffer,
     455                 :              const hb_feature_t *features,
     456                 :              unsigned int        num_features,
     457                 :              const char * const *shaper_options)
     458                 : {
     459               0 :   hb_ot_shape_plan_t plan;
     460                 : 
     461               0 :   buffer->guess_properties ();
     462                 : 
     463               0 :   hb_ot_shape_plan_internal (&plan, font->face, &buffer->props, features, num_features);
     464               0 :   hb_ot_shape_execute (&plan, font, buffer, features, num_features);
     465                 : 
     466               0 :   return TRUE;
     467                 : }
     468                 : 
     469                 : 

Generated by: LCOV version 1.7