15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Copyright © 2009  Red Hat, Inc.
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Copyright © 2012  Google, Inc.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *  This is part of HarfBuzz, a text shaping library.
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Permission is hereby granted, without written agreement and without
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * license or royalty fees, to use, copy, modify, and distribute this
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * software and its documentation for any purpose, provided that the
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * above copyright notice and the following two paragraphs appear in
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * all copies of this software.
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * DAMAGE.
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Red Hat Author(s): Behdad Esfahbod
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Google Author(s): Behdad Esfahbod
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "hb-private.hh"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "hb-shaper-private.hh"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "hb-shape-plan-private.hh"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "hb-buffer-private.hh"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "hb-font-private.hh"
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)static bool
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)parse_space (const char **pp, const char *end)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
4003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  while (*pp < end && ISSPACE (**pp))
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (*pp)++;
4203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return true;
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)static bool
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)parse_char (const char **pp, const char *end, char c)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parse_space (pp, end);
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (*pp == end || **pp != c)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  (*pp)++;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)static bool
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)parse_uint (const char **pp, const char *end, unsigned int *pv)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char buf[32];
61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  strncpy (buf, *pp, len);
63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  buf[len] = '\0';
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char *p = buf;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char *pend = p;
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int v;
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  /* Intentionally use strtol instead of strtoul, such that
70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)   * -1 turns into "big number"... */
71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  errno = 0;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  v = strtol (p, &pend, 0);
73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (errno || p == pend)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *pv = v;
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *pp += pend - p;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)static bool
8203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)parse_bool (const char **pp, const char *end, unsigned int *pv)
8303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles){
8403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  parse_space (pp, end);
8503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
8603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  const char *p = *pp;
8703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  while (*pp < end && ISALPHA(**pp))
8803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    (*pp)++;
8903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
9003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  /* CSS allows on/off as aliases 1/0. */
9103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (*pp - p == 2 || 0 == strncmp (p, "on", 2))
9203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    *pv = 1;
9303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  else if (*pp - p == 3 || 0 == strncmp (p, "off", 2))
9403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    *pv = 0;
9503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  else
9603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return false;
9703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
9803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return true;
9903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
10003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
10103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)static bool
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)parse_feature_value_prefix (const char **pp, const char *end, hb_feature_t *feature)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (parse_char (pp, end, '-'))
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    feature->value = 0;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else {
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parse_char (pp, end, '+');
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    feature->value = 1;
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)static bool
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)parse_feature_tag (const char **pp, const char *end, hb_feature_t *feature)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parse_space (pp, end);
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  char quote = 0;
12003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
12103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (*pp < end && (**pp == '\'' || **pp == '"'))
12203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  {
12303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    quote = **pp;
12403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    (*pp)++;
12503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
12603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
12703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  const char *p = *pp;
12803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  while (*pp < end && ISALNUM(**pp))
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (*pp)++;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (p == *pp || *pp - p > 4)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  feature->tag = hb_tag_from_string (p, *pp - p);
13503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
13603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (quote)
13703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  {
13803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    /* CSS expects exactly four bytes.  And we only allow quotations for
13903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     * CSS compatibility.  So, enforce the length. */
14003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     if (*pp - p != 4)
14103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)       return false;
14203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (*pp == end || **pp != quote)
14303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      return false;
14403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    (*pp)++;
14503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
14603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)static bool
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)parse_feature_indices (const char **pp, const char *end, hb_feature_t *feature)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parse_space (pp, end);
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  bool has_start;
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  feature->start = 0;
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  feature->end = (unsigned int) -1;
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!parse_char (pp, end, '['))
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  has_start = parse_uint (pp, end, &feature->start);
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (parse_char (pp, end, ':')) {
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parse_uint (pp, end, &feature->end);
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (has_start)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      feature->end = feature->start + 1;
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return parse_char (pp, end, ']');
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)static bool
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)parse_feature_value_postfix (const char **pp, const char *end, hb_feature_t *feature)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
17803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  bool had_equal = parse_char (pp, end, '=');
17903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  bool had_value = parse_uint (pp, end, &feature->value) ||
18003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                   parse_bool (pp, end, &feature->value);
18103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  /* CSS doesn't use equal-sign between tag and value.
18203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   * If there was an equal-sign, then there *must* be a value.
18303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)   * A value without an eqaul-sign is ok, but not required. */
18403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return !had_equal || had_value;
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)static bool
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)parse_one_feature (const char **pp, const char *end, hb_feature_t *feature)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return parse_feature_value_prefix (pp, end, feature) &&
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 parse_feature_tag (pp, end, feature) &&
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 parse_feature_indices (pp, end, feature) &&
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 parse_feature_value_postfix (pp, end, feature) &&
19503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)	 parse_space (pp, end) &&
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 *pp == end;
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
199f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)/**
200f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * hb_feature_from_string:
201f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * @str: (array length=len):
202f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * @len:
20303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * @feature: (out) (allow-none):
204f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *
205f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *
206f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *
207f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * Return value:
208f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *
209f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * Since: 1.0
210f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) **/
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)hb_bool_t
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)hb_feature_from_string (const char *str, int len,
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			hb_feature_t *feature)
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
21503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  hb_feature_t feat;
21603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (len < 0)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    len = strlen (str);
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (likely (parse_one_feature (&str, str + len, &feat)))
22103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  {
22203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (feature)
22303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      *feature = feat;
22403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return true;
22503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
22603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
22703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (feature)
22803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    memset (feature, 0, sizeof (*feature));
22903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return false;
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
232f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)/**
233f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * hb_feature_to_string:
234f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * @feature:
235f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * @buf: (array length=size):
236f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * @size:
237f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *
238f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *
239f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *
240f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * Since: 1.0
241f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) **/
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)hb_feature_to_string (hb_feature_t *feature,
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		      char *buf, unsigned int size)
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (unlikely (!size)) return;
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char s[128];
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int len = 0;
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (feature->value == 0)
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    s[len++] = '-';
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hb_tag_to_string (feature->tag, s + len);
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  len += 4;
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (len && s[len - 1] == ' ')
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    len--;
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (feature->start != 0 || feature->end != (unsigned int) -1)
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    s[len++] = '[';
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (feature->start)
26003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->start));
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (feature->end != feature->start + 1) {
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      s[len++] = ':';
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (feature->end != (unsigned int) -1)
26403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)	len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->end));
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    s[len++] = ']';
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (feature->value > 1)
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    s[len++] = '=';
27103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->value));
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert (len < ARRAY_LENGTH (s));
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  len = MIN (len, size - 1);
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memcpy (buf, s, len);
276f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  buf[len] = '\0';
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char **static_shaper_list;
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
282c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)static inline
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void free_static_shaper_list (void)
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  free (static_shaper_list);
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
288f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)/**
289f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * hb_shape_list_shapers:
290f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *
291f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *
292f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *
293f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * Return value: (transfer none):
294f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *
295f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * Since: 1.0
296f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) **/
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char **
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)hb_shape_list_shapers (void)
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)retry:
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char **shaper_list = (const char **) hb_atomic_ptr_get (&static_shaper_list);
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (unlikely (!shaper_list))
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* Not found; allocate one. */
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    shaper_list = (const char **) calloc (1 + HB_SHAPERS_COUNT, sizeof (const char *));
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (unlikely (!shaper_list)) {
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static const char *nil_shaper_list[] = {NULL};
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return nil_shaper_list;
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const hb_shaper_pair_t *shapers = _hb_shapers_get ();
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned int i;
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (i = 0; i < HB_SHAPERS_COUNT; i++)
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      shaper_list[i] = shapers[i].name;
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    shaper_list[i] = NULL;
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!hb_atomic_ptr_cmpexch (&static_shaper_list, NULL, shaper_list)) {
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      free (shaper_list);
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      goto retry;
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
32303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#ifdef HB_USE_ATEXIT
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    atexit (free_static_shaper_list); /* First person registers atexit() callback. */
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return shaper_list;
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
332f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)/**
333f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * hb_shape_full:
334f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * @font: a font.
335f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * @buffer: a buffer.
336f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * @features: (array length=num_features):
337f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * @num_features:
338f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * @shaper_list: (array zero-terminated=1):
339f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *
340f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *
341f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *
342f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * Return value:
343f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *
344f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * Since: 1.0
345f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) **/
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)hb_bool_t
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)hb_shape_full (hb_font_t          *font,
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	       hb_buffer_t        *buffer,
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	       const hb_feature_t *features,
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	       unsigned int        num_features,
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	       const char * const *shaper_list)
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (unlikely (!buffer->len))
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE);
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props, features, num_features, shaper_list);
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hb_bool_t res = hb_shape_plan_execute (shape_plan, font, buffer, features, num_features);
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hb_shape_plan_destroy (shape_plan);
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (res)
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    buffer->content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS;
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return res;
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
367f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)/**
368f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * hb_shape:
369f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * @font: a font.
370f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * @buffer: a buffer.
371f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * @features: (array length=num_features):
372f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * @num_features:
373f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *
374f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *
375f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *
376f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * Since: 1.0
377f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) **/
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)hb_shape (hb_font_t           *font,
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  hb_buffer_t         *buffer,
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  const hb_feature_t  *features,
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	  unsigned int         num_features)
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hb_shape_full (font, buffer, features, num_features, NULL);
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
386