< prev index next >

src/java.desktop/share/native/libfontmanager/harfbuzz/hb-shape.cc

Print this page




  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  * SECTION:hb-shape
  38  * @title: Shaping
  39  * @short_description: Conversion of text strings into positioned glyphs
  40  * @include: hb.h
  41  *
  42  * Shaping is the central operation of HarfBuzz. Shaping operates on buffers,
  43  * which are sequences of Unicode characters that use the same font and have
  44  * the same text direction, script and language. After shaping the buffer
  45  * contains the output glyphs and their positions.
  46  **/
  47 
  48 static bool
  49 parse_space (const char **pp, const char *end)
  50 {
  51   while (*pp < end && ISSPACE (**pp))
  52     (*pp)++;
  53   return true;
  54 }
  55 
  56 static bool
  57 parse_char (const char **pp, const char *end, char c)
  58 {
  59   parse_space (pp, end);
  60 
  61   if (*pp == end || **pp != c)
  62     return false;
  63 
  64   (*pp)++;
  65   return true;
  66 }
  67 
  68 static bool
  69 parse_uint (const char **pp, const char *end, unsigned int *pv)
  70 {
  71   char buf[32];
  72   unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
  73   strncpy (buf, *pp, len);
  74   buf[len] = '\0';
  75 
  76   char *p = buf;
  77   char *pend = p;
  78   unsigned int v;
  79 
  80   /* Intentionally use strtol instead of strtoul, such that
  81    * -1 turns into "big number"... */
  82   errno = 0;
  83   v = strtol (p, &pend, 0);
  84   if (errno || p == pend)
  85     return false;
  86 
  87   *pv = v;
  88   *pp += pend - p;
  89   return true;
  90 }
  91 
  92 static bool
  93 parse_bool (const char **pp, const char *end, unsigned int *pv)
  94 {
  95   parse_space (pp, end);
  96 
  97   const char *p = *pp;
  98   while (*pp < end && ISALPHA(**pp))
  99     (*pp)++;
 100 
 101   /* CSS allows on/off as aliases 1/0. */
 102   if (*pp - p == 2 || 0 == strncmp (p, "on", 2))
 103     *pv = 1;
 104   else if (*pp - p == 3 || 0 == strncmp (p, "off", 2))
 105     *pv = 0;
 106   else
 107     return false;
 108 
 109   return true;
 110 }
 111 
 112 static bool
 113 parse_feature_value_prefix (const char **pp, const char *end, hb_feature_t *feature)
 114 {
 115   if (parse_char (pp, end, '-'))
 116     feature->value = 0;
 117   else {
 118     parse_char (pp, end, '+');
 119     feature->value = 1;
 120   }
 121 
 122   return true;
 123 }
 124 
 125 static bool
 126 parse_feature_tag (const char **pp, const char *end, hb_feature_t *feature)
 127 {
 128   parse_space (pp, end);
 129 
 130   char quote = 0;
 131 
 132   if (*pp < end && (**pp == '\'' || **pp == '"'))
 133   {
 134     quote = **pp;
 135     (*pp)++;
 136   }
 137 
 138   const char *p = *pp;
 139   while (*pp < end && ISALNUM(**pp))
 140     (*pp)++;
 141 
 142   if (p == *pp || *pp - p > 4)
 143     return false;
 144 
 145   feature->tag = hb_tag_from_string (p, *pp - p);
 146 
 147   if (quote)
 148   {
 149     /* CSS expects exactly four bytes.  And we only allow quotations for
 150      * CSS compatibility.  So, enforce the length. */
 151      if (*pp - p != 4)
 152        return false;
 153     if (*pp == end || **pp != quote)
 154       return false;
 155     (*pp)++;
 156   }
 157 
 158   return true;
 159 }
 160 
 161 static bool
 162 parse_feature_indices (const char **pp, const char *end, hb_feature_t *feature)
 163 {
 164   parse_space (pp, end);
 165 
 166   bool has_start;
 167 
 168   feature->start = 0;
 169   feature->end = (unsigned int) -1;
 170 
 171   if (!parse_char (pp, end, '['))
 172     return true;
 173 
 174   has_start = parse_uint (pp, end, &feature->start);
 175 
 176   if (parse_char (pp, end, ':')) {
 177     parse_uint (pp, end, &feature->end);
 178   } else {
 179     if (has_start)
 180       feature->end = feature->start + 1;
 181   }
 182 
 183   return parse_char (pp, end, ']');
 184 }
 185 
 186 static bool
 187 parse_feature_value_postfix (const char **pp, const char *end, hb_feature_t *feature)
 188 {
 189   bool had_equal = parse_char (pp, end, '=');
 190   bool had_value = parse_uint (pp, end, &feature->value) ||
 191                    parse_bool (pp, end, &feature->value);
 192   /* CSS doesn't use equal-sign between tag and value.
 193    * If there was an equal-sign, then there *must* be a value.
 194    * A value without an eqaul-sign is ok, but not required. */
 195   return !had_equal || had_value;
 196 }
 197 
 198 
 199 static bool
 200 parse_one_feature (const char **pp, const char *end, hb_feature_t *feature)
 201 {
 202   return parse_feature_value_prefix (pp, end, feature) &&
 203          parse_feature_tag (pp, end, feature) &&
 204          parse_feature_indices (pp, end, feature) &&
 205          parse_feature_value_postfix (pp, end, feature) &&
 206          parse_space (pp, end) &&
 207          *pp == end;
 208 }
 209 
 210 /**
 211  * hb_feature_from_string:
 212  * @str: (array length=len) (element-type uint8_t): a string to parse
 213  * @len: length of @str, or -1 if string is %NULL terminated
 214  * @feature: (out): the #hb_feature_t to initialize with the parsed values
 215  *
 216  * Parses a string into a #hb_feature_t.
 217  *
 218  * TODO: document the syntax here.
 219  *
 220  * Return value:
 221  * %true if @str is successfully parsed, %false otherwise.
 222  *
 223  * Since: 0.9.5
 224  **/
 225 hb_bool_t
 226 hb_feature_from_string (const char *str, int len,
 227                         hb_feature_t *feature)
 228 {
 229   hb_feature_t feat;
 230 
 231   if (len < 0)
 232     len = strlen (str);
 233 
 234   if (likely (parse_one_feature (&str, str + len, &feat)))
 235   {
 236     if (feature)
 237       *feature = feat;
 238     return true;
 239   }
 240 
 241   if (feature)
 242     memset (feature, 0, sizeof (*feature));
 243   return false;
 244 }
 245 
 246 /**
 247  * hb_feature_to_string:
 248  * @feature: an #hb_feature_t to convert
 249  * @buf: (array length=size) (out): output string
 250  * @size: the allocated size of @buf
 251  *
 252  * Converts a #hb_feature_t into a %NULL-terminated string in the format
 253  * understood by hb_feature_from_string(). The client in responsible for
 254  * allocating big enough size for @buf, 128 bytes is more than enough.
 255  *
 256  * Since: 0.9.5
 257  **/
 258 void
 259 hb_feature_to_string (hb_feature_t *feature,
 260                       char *buf, unsigned int size)
 261 {
 262   if (unlikely (!size)) return;
 263 
 264   char s[128];
 265   unsigned int len = 0;
 266   if (feature->value == 0)
 267     s[len++] = '-';
 268   hb_tag_to_string (feature->tag, s + len);
 269   len += 4;
 270   while (len && s[len - 1] == ' ')
 271     len--;
 272   if (feature->start != 0 || feature->end != (unsigned int) -1)
 273   {
 274     s[len++] = '[';
 275     if (feature->start)
 276       len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->start));
 277     if (feature->end != feature->start + 1) {
 278       s[len++] = ':';
 279       if (feature->end != (unsigned int) -1)
 280         len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->end));
 281     }
 282     s[len++] = ']';
 283   }
 284   if (feature->value > 1)
 285   {
 286     s[len++] = '=';
 287     len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->value));
 288   }
 289   assert (len < ARRAY_LENGTH (s));
 290   len = MIN (len, size - 1);
 291   memcpy (buf, s, len);
 292   buf[len] = '\0';
 293 }
 294 
 295 
 296 static const char **static_shaper_list;
 297 
 298 #ifdef HB_USE_ATEXIT
 299 static
 300 void free_static_shaper_list (void)
 301 {
 302   free (static_shaper_list);
 303 }
 304 #endif
 305 
 306 /**
 307  * hb_shape_list_shapers:
 308  *
 309  * Retrieves the list of shapers supported by HarfBuzz.
 310  *
 311  * Return value: (transfer none) (array zero-terminated=1): an array of
 312  *    constant strings
 313  *
 314  * Since: 0.9.2
 315  **/
 316 const char **
 317 hb_shape_list_shapers (void)
 318 {
 319 retry:
 320   const char **shaper_list = (const char **) hb_atomic_ptr_get (&static_shaper_list);
 321 
 322   if (unlikely (!shaper_list))
 323   {
 324     /* Not found; allocate one. */
 325     shaper_list = (const char **) calloc (1 + HB_SHAPERS_COUNT, sizeof (const char *));
 326     if (unlikely (!shaper_list)) {
 327       static const char *nil_shaper_list[] = {NULL};
 328       return nil_shaper_list;
 329     }
 330 
 331     const hb_shaper_pair_t *shapers = _hb_shapers_get ();
 332     unsigned int i;
 333     for (i = 0; i < HB_SHAPERS_COUNT; i++)
 334       shaper_list[i] = shapers[i].name;
 335     shaper_list[i] = NULL;
 336 
 337     if (!hb_atomic_ptr_cmpexch (&static_shaper_list, NULL, shaper_list)) {
 338       free (shaper_list);
 339       goto retry;
 340     }
 341 
 342 #ifdef HB_USE_ATEXIT
 343     atexit (free_static_shaper_list); /* First person registers atexit() callback. */
 344 #endif
 345   }
 346 
 347   return shaper_list;
 348 }
 349 
 350 
 351 /**
 352  * hb_shape_full:
 353  * @font: an #hb_font_t to use for shaping
 354  * @buffer: an #hb_buffer_t to shape
 355  * @features: (array length=num_features) (allow-none): an array of user
 356  *    specified #hb_feature_t or %NULL
 357  * @num_features: the length of @features array
 358  * @shaper_list: (array zero-terminated=1) (allow-none): a %NULL-terminated
 359  *    array of shapers to use or %NULL
 360  *
 361  * See hb_shape() for details. If @shaper_list is not %NULL, the specified
 362  * shapers will be used in the given order, otherwise the default shapers list
 363  * will be used.
 364  *
 365  * Return value: %FALSE if all shapers failed, %TRUE otherwise
 366  *
 367  * Since: 0.9.2
 368  **/
 369 hb_bool_t
 370 hb_shape_full (hb_font_t          *font,
 371                hb_buffer_t        *buffer,
 372                const hb_feature_t *features,
 373                unsigned int        num_features,
 374                const char * const *shaper_list)
 375 {
 376   hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached2 (font->face, &buffer->props,
 377                                                               features, num_features,
 378                                                               font->coords, font->num_coords,
 379                                                               shaper_list);
 380   hb_bool_t res = hb_shape_plan_execute (shape_plan, font, buffer, features, num_features);
 381   hb_shape_plan_destroy (shape_plan);
 382 
 383   if (res)
 384     buffer->content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS;
 385   return res;


 388 /**
 389  * hb_shape:
 390  * @font: an #hb_font_t to use for shaping
 391  * @buffer: an #hb_buffer_t to shape
 392  * @features: (array length=num_features) (allow-none): an array of user
 393  *    specified #hb_feature_t or %NULL
 394  * @num_features: the length of @features array
 395  *
 396  * Shapes @buffer using @font turning its Unicode characters content to
 397  * positioned glyphs. If @features is not %NULL, it will be used to control the
 398  * features applied during shaping.
 399  *
 400  * Since: 0.9.2
 401  **/
 402 void
 403 hb_shape (hb_font_t           *font,
 404           hb_buffer_t         *buffer,
 405           const hb_feature_t  *features,
 406           unsigned int         num_features)
 407 {
 408   hb_shape_full (font, buffer, features, num_features, NULL);
 409 }


  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  * SECTION:hb-shape
  38  * @title: Shaping
  39  * @short_description: Conversion of text strings into positioned glyphs
  40  * @include: hb.h
  41  *
  42  * Shaping is the central operation of HarfBuzz. Shaping operates on buffers,
  43  * which are sequences of Unicode characters that use the same font and have
  44  * the same text direction, script and language. After shaping the buffer
  45  * contains the output glyphs and their positions.
  46  **/
  47 
























































































































































































































































  48 static const char **static_shaper_list;
  49 
  50 #ifdef HB_USE_ATEXIT
  51 static
  52 void free_static_shaper_list (void)
  53 {
  54   free (static_shaper_list);
  55 }
  56 #endif
  57 
  58 /**
  59  * hb_shape_list_shapers:
  60  *
  61  * Retrieves the list of shapers supported by HarfBuzz.
  62  *
  63  * Return value: (transfer none) (array zero-terminated=1): an array of
  64  *    constant strings
  65  *
  66  * Since: 0.9.2
  67  **/
  68 const char **
  69 hb_shape_list_shapers (void)
  70 {
  71 retry:
  72   const char **shaper_list = (const char **) hb_atomic_ptr_get (&static_shaper_list);
  73 
  74   if (unlikely (!shaper_list))
  75   {
  76     /* Not found; allocate one. */
  77     shaper_list = (const char **) calloc (1 + HB_SHAPERS_COUNT, sizeof (const char *));
  78     if (unlikely (!shaper_list)) {
  79       static const char *nil_shaper_list[] = {nullptr};
  80       return nil_shaper_list;
  81     }
  82 
  83     const hb_shaper_pair_t *shapers = _hb_shapers_get ();
  84     unsigned int i;
  85     for (i = 0; i < HB_SHAPERS_COUNT; i++)
  86       shaper_list[i] = shapers[i].name;
  87     shaper_list[i] = nullptr;
  88 
  89     if (!hb_atomic_ptr_cmpexch (&static_shaper_list, nullptr, shaper_list)) {
  90       free (shaper_list);
  91       goto retry;
  92     }
  93 
  94 #ifdef HB_USE_ATEXIT
  95     atexit (free_static_shaper_list); /* First person registers atexit() callback. */
  96 #endif
  97   }
  98 
  99   return shaper_list;
 100 }
 101 
 102 
 103 /**
 104  * hb_shape_full:
 105  * @font: an #hb_font_t to use for shaping
 106  * @buffer: an #hb_buffer_t to shape
 107  * @features: (array length=num_features) (allow-none): an array of user
 108  *    specified #hb_feature_t or %NULL
 109  * @num_features: the length of @features array
 110  * @shaper_list: (array zero-terminated=1) (allow-none): a %NULL-terminated
 111  *    array of shapers to use or %NULL
 112  *
 113  * See hb_shape() for details. If @shaper_list is not %NULL, the specified
 114  * shapers will be used in the given order, otherwise the default shapers list
 115  * will be used.
 116  *
 117  * Return value: false if all shapers failed, true otherwise
 118  *
 119  * Since: 0.9.2
 120  **/
 121 hb_bool_t
 122 hb_shape_full (hb_font_t          *font,
 123                hb_buffer_t        *buffer,
 124                const hb_feature_t *features,
 125                unsigned int        num_features,
 126                const char * const *shaper_list)
 127 {
 128   hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached2 (font->face, &buffer->props,
 129                                                               features, num_features,
 130                                                               font->coords, font->num_coords,
 131                                                               shaper_list);
 132   hb_bool_t res = hb_shape_plan_execute (shape_plan, font, buffer, features, num_features);
 133   hb_shape_plan_destroy (shape_plan);
 134 
 135   if (res)
 136     buffer->content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS;
 137   return res;


 140 /**
 141  * hb_shape:
 142  * @font: an #hb_font_t to use for shaping
 143  * @buffer: an #hb_buffer_t to shape
 144  * @features: (array length=num_features) (allow-none): an array of user
 145  *    specified #hb_feature_t or %NULL
 146  * @num_features: the length of @features array
 147  *
 148  * Shapes @buffer using @font turning its Unicode characters content to
 149  * positioned glyphs. If @features is not %NULL, it will be used to control the
 150  * features applied during shaping.
 151  *
 152  * Since: 0.9.2
 153  **/
 154 void
 155 hb_shape (hb_font_t           *font,
 156           hb_buffer_t         *buffer,
 157           const hb_feature_t  *features,
 158           unsigned int         num_features)
 159 {
 160   hb_shape_full (font, buffer, features, num_features, nullptr);
 161 }
< prev index next >