Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright  2009  Red Hat, Inc.
      3  * Copyright  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 #include "hb-private.hh"
     30 
     31 #include "hb-shaper-private.hh"
     32 #include "hb-shape-plan-private.hh"
     33 #include "hb-buffer-private.hh"
     34 #include "hb-font-private.hh"
     35 
     36 
     37 static void
     38 parse_space (const char **pp, const char *end)
     39 {
     40   char c;
     41   while (*pp < end && (c = **pp, ISSPACE (c)))
     42     (*pp)++;
     43 }
     44 
     45 static hb_bool_t
     46 parse_char (const char **pp, const char *end, char c)
     47 {
     48   parse_space (pp, end);
     49 
     50   if (*pp == end || **pp != c)
     51     return false;
     52 
     53   (*pp)++;
     54   return true;
     55 }
     56 
     57 static hb_bool_t
     58 parse_uint (const char **pp, const char *end, unsigned int *pv)
     59 {
     60   char buf[32];
     61   unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
     62   strncpy (buf, *pp, len);
     63   buf[len] = '\0';
     64 
     65   char *p = buf;
     66   char *pend = p;
     67   unsigned int v;
     68 
     69   /* Intentionally use strtol instead of strtoul, such that
     70    * -1 turns into "big number"... */
     71   errno = 0;
     72   v = strtol (p, &pend, 0);
     73   if (errno || p == pend)
     74     return false;
     75 
     76   *pv = v;
     77   *pp += pend - p;
     78   return true;
     79 }
     80 
     81 static hb_bool_t
     82 parse_feature_value_prefix (const char **pp, const char *end, hb_feature_t *feature)
     83 {
     84   if (parse_char (pp, end, '-'))
     85     feature->value = 0;
     86   else {
     87     parse_char (pp, end, '+');
     88     feature->value = 1;
     89   }
     90 
     91   return true;
     92 }
     93 
     94 static hb_bool_t
     95 parse_feature_tag (const char **pp, const char *end, hb_feature_t *feature)
     96 {
     97   const char *p = *pp;
     98   char c;
     99 
    100   parse_space (pp, end);
    101 
    102 #define ISALNUM(c) (('a' <= (c) && (c) <= 'z') || ('A' <= (c) && (c) <= 'Z') || ('0' <= (c) && (c) <= '9'))
    103   while (*pp < end && (c = **pp, ISALNUM(c)))
    104     (*pp)++;
    105 #undef ISALNUM
    106 
    107   if (p == *pp)
    108     return false;
    109 
    110   feature->tag = hb_tag_from_string (p, *pp - p);
    111   return true;
    112 }
    113 
    114 static hb_bool_t
    115 parse_feature_indices (const char **pp, const char *end, hb_feature_t *feature)
    116 {
    117   parse_space (pp, end);
    118 
    119   hb_bool_t has_start;
    120 
    121   feature->start = 0;
    122   feature->end = (unsigned int) -1;
    123 
    124   if (!parse_char (pp, end, '['))
    125     return true;
    126 
    127   has_start = parse_uint (pp, end, &feature->start);
    128 
    129   if (parse_char (pp, end, ':')) {
    130     parse_uint (pp, end, &feature->end);
    131   } else {
    132     if (has_start)
    133       feature->end = feature->start + 1;
    134   }
    135 
    136   return parse_char (pp, end, ']');
    137 }
    138 
    139 static hb_bool_t
    140 parse_feature_value_postfix (const char **pp, const char *end, hb_feature_t *feature)
    141 {
    142   return !parse_char (pp, end, '=') || parse_uint (pp, end, &feature->value);
    143 }
    144 
    145 
    146 static hb_bool_t
    147 parse_one_feature (const char **pp, const char *end, hb_feature_t *feature)
    148 {
    149   return parse_feature_value_prefix (pp, end, feature) &&
    150 	 parse_feature_tag (pp, end, feature) &&
    151 	 parse_feature_indices (pp, end, feature) &&
    152 	 parse_feature_value_postfix (pp, end, feature) &&
    153 	 *pp == end;
    154 }
    155 
    156 hb_bool_t
    157 hb_feature_from_string (const char *str, int len,
    158 			hb_feature_t *feature)
    159 {
    160   if (len < 0)
    161     len = strlen (str);
    162 
    163   return parse_one_feature (&str, str + len, feature);
    164 }
    165 
    166 void
    167 hb_feature_to_string (hb_feature_t *feature,
    168 		      char *buf, unsigned int size)
    169 {
    170   if (unlikely (!size)) return;
    171 
    172   char s[128];
    173   unsigned int len = 0;
    174   if (feature->value == 0)
    175     s[len++] = '-';
    176   hb_tag_to_string (feature->tag, s + len);
    177   len += 4;
    178   while (len && s[len - 1] == ' ')
    179     len--;
    180   if (feature->start != 0 || feature->end != (unsigned int) -1)
    181   {
    182     s[len++] = '[';
    183     if (feature->start)
    184       len += snprintf (s + len, ARRAY_LENGTH (s) - len, "%d", feature->start);
    185     if (feature->end != feature->start + 1) {
    186       s[len++] = ':';
    187       if (feature->end != (unsigned int) -1)
    188 	len += snprintf (s + len, ARRAY_LENGTH (s) - len, "%d", feature->end);
    189     }
    190     s[len++] = ']';
    191   }
    192   if (feature->value > 1)
    193   {
    194     s[len++] = '=';
    195     len += snprintf (s + len, ARRAY_LENGTH (s) - len, "%d", feature->value);
    196   }
    197   assert (len < ARRAY_LENGTH (s));
    198   len = MIN (len, size - 1);
    199   memcpy (buf, s, len);
    200   s[len] = '\0';
    201 }
    202 
    203 
    204 static const char **static_shaper_list;
    205 
    206 static inline
    207 void free_static_shaper_list (void)
    208 {
    209   free (static_shaper_list);
    210 }
    211 
    212 const char **
    213 hb_shape_list_shapers (void)
    214 {
    215 retry:
    216   const char **shaper_list = (const char **) hb_atomic_ptr_get (&static_shaper_list);
    217 
    218   if (unlikely (!shaper_list))
    219   {
    220     /* Not found; allocate one. */
    221     shaper_list = (const char **) calloc (1 + HB_SHAPERS_COUNT, sizeof (const char *));
    222     if (unlikely (!shaper_list)) {
    223       static const char *nil_shaper_list[] = {NULL};
    224       return nil_shaper_list;
    225     }
    226 
    227     const hb_shaper_pair_t *shapers = _hb_shapers_get ();
    228     unsigned int i;
    229     for (i = 0; i < HB_SHAPERS_COUNT; i++)
    230       shaper_list[i] = shapers[i].name;
    231     shaper_list[i] = NULL;
    232 
    233     if (!hb_atomic_ptr_cmpexch (&static_shaper_list, NULL, shaper_list)) {
    234       free (shaper_list);
    235       goto retry;
    236     }
    237 
    238 #ifdef HAVE_ATEXIT
    239     atexit (free_static_shaper_list); /* First person registers atexit() callback. */
    240 #endif
    241   }
    242 
    243   return shaper_list;
    244 }
    245 
    246 
    247 hb_bool_t
    248 hb_shape_full (hb_font_t          *font,
    249 	       hb_buffer_t        *buffer,
    250 	       const hb_feature_t *features,
    251 	       unsigned int        num_features,
    252 	       const char * const *shaper_list)
    253 {
    254   if (unlikely (!buffer->len))
    255     return true;
    256 
    257   assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE);
    258 
    259   hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props, features, num_features, shaper_list);
    260   hb_bool_t res = hb_shape_plan_execute (shape_plan, font, buffer, features, num_features);
    261   hb_shape_plan_destroy (shape_plan);
    262 
    263   if (res)
    264     buffer->content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS;
    265   return res;
    266 }
    267 
    268 void
    269 hb_shape (hb_font_t           *font,
    270 	  hb_buffer_t         *buffer,
    271 	  const hb_feature_t  *features,
    272 	  unsigned int         num_features)
    273 {
    274   hb_shape_full (font, buffer, features, num_features, NULL);
    275 }
    276