| OLD | NEW | 
| (Empty) |  | 
 |    1 /* | 
 |    2  * Copyright (C) 2009,2010  Red Hat, Inc. | 
 |    3  * Copyright (C) 2010  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 HB_BEGIN_DECLS | 
 |   33  | 
 |   34  | 
 |   35 /* XXX vertical */ | 
 |   36 hb_tag_t default_features[] = { | 
 |   37   HB_TAG('c','a','l','t'), | 
 |   38   HB_TAG('c','c','m','p'), | 
 |   39   HB_TAG('c','l','i','g'), | 
 |   40   HB_TAG('c','s','w','h'), | 
 |   41   HB_TAG('c','u','r','s'), | 
 |   42   HB_TAG('k','e','r','n'), | 
 |   43   HB_TAG('l','i','g','a'), | 
 |   44   HB_TAG('l','o','c','l'), | 
 |   45   HB_TAG('m','a','r','k'), | 
 |   46   HB_TAG('m','k','m','k'), | 
 |   47   HB_TAG('r','l','i','g') | 
 |   48 }; | 
 |   49  | 
 |   50 static void | 
 |   51 hb_ot_shape_collect_features (hb_ot_shape_plan_t       *plan, | 
 |   52                               const hb_segment_properties_t  *props, | 
 |   53                               const hb_feature_t       *user_features, | 
 |   54                               unsigned int              num_user_features) | 
 |   55 { | 
 |   56   switch (props->direction) { | 
 |   57     case HB_DIRECTION_LTR: | 
 |   58       plan->map.add_bool_feature (HB_TAG ('l','t','r','a')); | 
 |   59       plan->map.add_bool_feature (HB_TAG ('l','t','r','m')); | 
 |   60       break; | 
 |   61     case HB_DIRECTION_RTL: | 
 |   62       plan->map.add_bool_feature (HB_TAG ('r','t','l','a')); | 
 |   63       plan->map.add_bool_feature (HB_TAG ('r','t','l','m'), false); | 
 |   64       break; | 
 |   65     case HB_DIRECTION_TTB: | 
 |   66     case HB_DIRECTION_BTT: | 
 |   67     default: | 
 |   68       break; | 
 |   69   } | 
 |   70  | 
 |   71   for (unsigned int i = 0; i < ARRAY_LENGTH (default_features); i++) | 
 |   72     plan->map.add_bool_feature (default_features[i]); | 
 |   73  | 
 |   74   hb_ot_shape_complex_collect_features (plan, props); | 
 |   75  | 
 |   76   for (unsigned int i = 0; i < num_user_features; i++) { | 
 |   77     const hb_feature_t *feature = &user_features[i]; | 
 |   78     plan->map.add_feature (feature->tag, feature->value, (feature->start == 0 &&
      feature->end == (unsigned int) -1)); | 
 |   79   } | 
 |   80 } | 
 |   81  | 
 |   82  | 
 |   83 static void | 
 |   84 hb_ot_shape_setup_masks (hb_ot_shape_context_t *c) | 
 |   85 { | 
 |   86   hb_mask_t global_mask = c->plan->map.get_global_mask (); | 
 |   87   c->buffer->reset_masks (global_mask); | 
 |   88  | 
 |   89   hb_ot_shape_complex_setup_masks (c); /* BUFFER: Clobbers var2 */ | 
 |   90  | 
 |   91   for (unsigned int i = 0; i < c->num_user_features; i++) | 
 |   92   { | 
 |   93     const hb_feature_t *feature = &c->user_features[i]; | 
 |   94     if (!(feature->start == 0 && feature->end == (unsigned int)-1)) { | 
 |   95       unsigned int shift; | 
 |   96       hb_mask_t mask = c->plan->map.get_mask (feature->tag, &shift); | 
 |   97       c->buffer->set_masks (feature->value << shift, mask, feature->start, featu
     re->end); | 
 |   98     } | 
 |   99   } | 
 |  100 } | 
 |  101  | 
 |  102  | 
 |  103 static void | 
 |  104 hb_ot_substitute_complex (hb_ot_shape_context_t *c) | 
 |  105 { | 
 |  106   if (!hb_ot_layout_has_substitution (c->face)) | 
 |  107     return; | 
 |  108  | 
 |  109   c->plan->map.substitute (c->face, c->buffer); | 
 |  110  | 
 |  111   c->applied_substitute_complex = TRUE; | 
 |  112   return; | 
 |  113 } | 
 |  114  | 
 |  115 static void | 
 |  116 hb_ot_position_complex (hb_ot_shape_context_t *c) | 
 |  117 { | 
 |  118  | 
 |  119   if (!hb_ot_layout_has_positioning (c->face)) | 
 |  120     return; | 
 |  121  | 
 |  122   c->plan->map.position (c->font, c->face, c->buffer); | 
 |  123  | 
 |  124   hb_ot_layout_position_finish (c->buffer); | 
 |  125  | 
 |  126   c->applied_position_complex = TRUE; | 
 |  127   return; | 
 |  128 } | 
 |  129  | 
 |  130  | 
 |  131 /* Main shaper */ | 
 |  132  | 
 |  133 /* Prepare */ | 
 |  134  | 
 |  135 static inline hb_bool_t | 
 |  136 is_variation_selector (hb_codepoint_t unicode) | 
 |  137 { | 
 |  138   return unlikely ((unicode >=  0x180B && unicode <=  0x180D) || /* MONGOLIAN FR
     EE VARIATION SELECTOR ONE..THREE */ | 
 |  139                    (unicode >=  0xFE00 && unicode <=  0xFE0F) || /* VARIATION SE
     LECTOR-1..16 */ | 
 |  140                    (unicode >= 0xE0100 && unicode <= 0xE01EF));  /* VARIATION SE
     LECTOR-17..256 */ | 
 |  141 } | 
 |  142  | 
 |  143 static void | 
 |  144 hb_set_unicode_props (hb_ot_shape_context_t *c) | 
 |  145 { | 
 |  146   hb_unicode_get_general_category_func_t get_general_category = c->buffer->unico
     de->v.get_general_category; | 
 |  147   hb_unicode_get_combining_class_func_t get_combining_class = c->buffer->unicode
     ->v.get_combining_class; | 
 |  148   hb_glyph_info_t *info = c->buffer->info; | 
 |  149  | 
 |  150   unsigned int count = c->buffer->len; | 
 |  151   for (unsigned int i = 1; i < count; i++) { | 
 |  152     info[i].general_category() = get_general_category (info[i].codepoint); | 
 |  153     info[i].combining_class() = get_combining_class (info[i].codepoint); | 
 |  154   } | 
 |  155 } | 
 |  156  | 
 |  157 static void | 
 |  158 hb_form_clusters (hb_ot_shape_context_t *c) | 
 |  159 { | 
 |  160   unsigned int count = c->buffer->len; | 
 |  161   for (unsigned int i = 1; i < count; i++) | 
 |  162     if (c->buffer->info[i].general_category() == HB_CATEGORY_NON_SPACING_MARK) | 
 |  163       c->buffer->info[i].cluster = c->buffer->info[i - 1].cluster; | 
 |  164 } | 
 |  165  | 
 |  166 static void | 
 |  167 hb_ensure_native_direction (hb_ot_shape_context_t *c) | 
 |  168 { | 
 |  169   hb_direction_t direction = c->buffer->props.direction; | 
 |  170  | 
 |  171   /* TODO vertical */ | 
 |  172   if (HB_DIRECTION_IS_HORIZONTAL (direction) && | 
 |  173       direction != _hb_script_get_horizontal_direction (c->buffer->props.script)
     ) | 
 |  174   { | 
 |  175     hb_buffer_reverse_clusters (c->buffer); | 
 |  176     c->buffer->props.direction = HB_DIRECTION_REVERSE (c->buffer->props.directio
     n); | 
 |  177   } | 
 |  178 } | 
 |  179  | 
 |  180 static void | 
 |  181 hb_reset_glyph_infos (hb_ot_shape_context_t *c) | 
 |  182 { | 
 |  183   unsigned int count = c->buffer->len; | 
 |  184   for (unsigned int i = 0; i < count; i++) | 
 |  185     c->buffer->info[i].var1.u32 = c->buffer->info[i].var2.u32 = 0; | 
 |  186 } | 
 |  187  | 
 |  188  | 
 |  189 /* Substitute */ | 
 |  190  | 
 |  191 static void | 
 |  192 hb_mirror_chars (hb_ot_shape_context_t *c) | 
 |  193 { | 
 |  194   hb_unicode_get_mirroring_func_t get_mirroring = c->buffer->unicode->v.get_mirr
     oring; | 
 |  195  | 
 |  196   if (HB_DIRECTION_IS_FORWARD (c->target_direction)) | 
 |  197     return; | 
 |  198  | 
 |  199   hb_mask_t rtlm_mask = c->plan->map.get_1_mask (HB_TAG ('r','t','l','m')); | 
 |  200  | 
 |  201   unsigned int count = c->buffer->len; | 
 |  202   for (unsigned int i = 0; i < count; i++) { | 
 |  203     hb_codepoint_t codepoint = get_mirroring (c->buffer->info[i].codepoint); | 
 |  204     if (likely (codepoint == c->buffer->info[i].codepoint)) | 
 |  205       c->buffer->info[i].mask |= rtlm_mask; /* XXX this should be moved to befor
     e setting user-feature masks */ | 
 |  206     else | 
 |  207       c->buffer->info[i].codepoint = codepoint; | 
 |  208   } | 
 |  209 } | 
 |  210  | 
 |  211 static void | 
 |  212 hb_map_glyphs (hb_font_t    *font, | 
 |  213                hb_face_t    *face, | 
 |  214                hb_buffer_t  *buffer) | 
 |  215 { | 
 |  216   if (unlikely (!buffer->len)) | 
 |  217     return; | 
 |  218  | 
 |  219   buffer->clear_output (); | 
 |  220   unsigned int count = buffer->len - 1; | 
 |  221   for (buffer->i = 0; buffer->i < count;) { | 
 |  222     if (unlikely (is_variation_selector (buffer->info[buffer->i + 1].codepoint))
     ) { | 
 |  223       buffer->replace_glyph (hb_font_get_glyph (font, face, buffer->info[buffer-
     >i].codepoint, buffer->info[buffer->i + 1].codepoint)); | 
 |  224       buffer->i++; | 
 |  225     } else { | 
 |  226       buffer->replace_glyph (hb_font_get_glyph (font, face, buffer->info[buffer-
     >i].codepoint, 0)); | 
 |  227     } | 
 |  228   } | 
 |  229   if (likely (buffer->i < buffer->len)) | 
 |  230     buffer->replace_glyph (hb_font_get_glyph (font, face, buffer->info[buffer->i
     ].codepoint, 0)); | 
 |  231   buffer->swap (); | 
 |  232 } | 
 |  233  | 
 |  234 static void | 
 |  235 hb_substitute_default (hb_ot_shape_context_t *c) | 
 |  236 { | 
 |  237   hb_map_glyphs (c->font, c->face, c->buffer); | 
 |  238 } | 
 |  239  | 
 |  240 static void | 
 |  241 hb_substitute_complex_fallback (hb_ot_shape_context_t *c HB_UNUSED) | 
 |  242 { | 
 |  243   /* TODO Arabic */ | 
 |  244 } | 
 |  245  | 
 |  246  | 
 |  247 /* Position */ | 
 |  248  | 
 |  249 static void | 
 |  250 hb_position_default (hb_ot_shape_context_t *c) | 
 |  251 { | 
 |  252   hb_buffer_clear_positions (c->buffer); | 
 |  253  | 
 |  254   unsigned int count = c->buffer->len; | 
 |  255   for (unsigned int i = 0; i < count; i++) { | 
 |  256     hb_font_get_glyph_advance (c->font, c->face, c->buffer->info[i].codepoint, | 
 |  257                                &c->buffer->pos[i].x_advance, | 
 |  258                                &c->buffer->pos[i].y_advance); | 
 |  259   } | 
 |  260 } | 
 |  261  | 
 |  262 static void | 
 |  263 hb_position_complex_fallback (hb_ot_shape_context_t *c HB_UNUSED) | 
 |  264 { | 
 |  265   /* TODO Mark pos */ | 
 |  266 } | 
 |  267  | 
 |  268 static void | 
 |  269 hb_truetype_kern (hb_ot_shape_context_t *c) | 
 |  270 { | 
 |  271   /* TODO Check for kern=0 */ | 
 |  272   unsigned int count = c->buffer->len; | 
 |  273   for (unsigned int i = 1; i < count; i++) { | 
 |  274     hb_position_t kern, kern1, kern2; | 
 |  275     kern = hb_font_get_kerning (c->font, c->face, c->buffer->info[i - 1].codepoi
     nt, c->buffer->info[i].codepoint); | 
 |  276     kern1 = kern >> 1; | 
 |  277     kern2 = kern - kern1; | 
 |  278     c->buffer->pos[i - 1].x_advance += kern1; | 
 |  279     c->buffer->pos[i].x_advance += kern2; | 
 |  280     c->buffer->pos[i].x_offset += kern2; | 
 |  281   } | 
 |  282 } | 
 |  283  | 
 |  284 static void | 
 |  285 hb_position_complex_fallback_visual (hb_ot_shape_context_t *c) | 
 |  286 { | 
 |  287   hb_truetype_kern (c); | 
 |  288 } | 
 |  289  | 
 |  290  | 
 |  291 /* Do it! */ | 
 |  292  | 
 |  293 static void | 
 |  294 hb_ot_shape_execute_internal (hb_ot_shape_context_t *c) | 
 |  295 { | 
 |  296   /* Save the original direction, we use it later. */ | 
 |  297   c->target_direction = c->buffer->props.direction; | 
 |  298  | 
 |  299   hb_reset_glyph_infos (c); /* BUFFER: Clear buffer var1 and var2 */ | 
 |  300  | 
 |  301   hb_set_unicode_props (c); /* BUFFER: Set general_category and combining_class 
     in var1 */ | 
 |  302  | 
 |  303   hb_ensure_native_direction (c); | 
 |  304  | 
 |  305   hb_form_clusters (c); | 
 |  306  | 
 |  307   hb_ot_shape_setup_masks (c); /* BUFFER: Clobbers var2 */ | 
 |  308  | 
 |  309   /* SUBSTITUTE */ | 
 |  310   { | 
 |  311     /* Mirroring needs to see the original direction */ | 
 |  312     hb_mirror_chars (c); | 
 |  313  | 
 |  314     hb_substitute_default (c); | 
 |  315  | 
 |  316     hb_ot_substitute_complex (c); | 
 |  317  | 
 |  318     if (!c->applied_substitute_complex) | 
 |  319       hb_substitute_complex_fallback (c); | 
 |  320   } | 
 |  321  | 
 |  322   /* POSITION */ | 
 |  323   { | 
 |  324     hb_position_default (c); | 
 |  325  | 
 |  326     hb_ot_position_complex (c); | 
 |  327  | 
 |  328     hb_bool_t position_fallback = !c->applied_position_complex; | 
 |  329     if (position_fallback) | 
 |  330       hb_position_complex_fallback (c); | 
 |  331  | 
 |  332     if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction)) | 
 |  333       hb_buffer_reverse (c->buffer); | 
 |  334  | 
 |  335     if (position_fallback) | 
 |  336       hb_position_complex_fallback_visual (c); | 
 |  337   } | 
 |  338  | 
 |  339   c->buffer->props.direction = c->target_direction; | 
 |  340 } | 
 |  341  | 
 |  342 void | 
 |  343 hb_ot_shape_plan_internal (hb_ot_shape_plan_t       *plan, | 
 |  344                            hb_face_t                *face, | 
 |  345                            const hb_segment_properties_t  *props, | 
 |  346                            const hb_feature_t       *user_features, | 
 |  347                            unsigned int              num_user_features) | 
 |  348 { | 
 |  349   plan->shaper = hb_ot_shape_complex_categorize (props); | 
 |  350  | 
 |  351   hb_ot_shape_collect_features (plan, props, user_features, num_user_features); | 
 |  352  | 
 |  353   plan->map.compile (face, props); | 
 |  354 } | 
 |  355  | 
 |  356 void | 
 |  357 hb_ot_shape_execute (hb_ot_shape_plan_t *plan, | 
 |  358                      hb_font_t          *font, | 
 |  359                      hb_face_t          *face, | 
 |  360                      hb_buffer_t        *buffer, | 
 |  361                      const hb_feature_t *user_features, | 
 |  362                      unsigned int        num_user_features) | 
 |  363 { | 
 |  364   hb_ot_shape_context_t c = {plan, font, face, buffer, user_features, num_user_f
     eatures}; | 
 |  365   hb_ot_shape_execute_internal (&c); | 
 |  366 } | 
 |  367  | 
 |  368 void | 
 |  369 hb_ot_shape (hb_font_t    *font, | 
 |  370              hb_face_t    *face, | 
 |  371              hb_buffer_t  *buffer, | 
 |  372              const hb_feature_t *user_features, | 
 |  373              unsigned int        num_user_features) | 
 |  374 { | 
 |  375   hb_ot_shape_plan_t plan; | 
 |  376  | 
 |  377   hb_ot_shape_plan_internal (&plan, face, &buffer->props, user_features, num_use
     r_features); | 
 |  378   hb_ot_shape_execute (&plan, font, face, buffer, user_features, num_user_featur
     es); | 
 |  379 } | 
 |  380  | 
 |  381  | 
 |  382 HB_END_DECLS | 
| OLD | NEW |