115232e26f4a89dab1b6de35ad9d3d16e75bf93d0Behdad Esfahbod/*
22409d5f8d7dd8b535ce5ea29e933f7db27d33793Behdad Esfahbod * Copyright © 2009  Red Hat, Inc.
3e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod * Copyright © 2012  Google, Inc.
415232e26f4a89dab1b6de35ad9d3d16e75bf93d0Behdad Esfahbod *
5c755cb3e3ac55156d0d2ec05adea7a650b97cc41Behdad Esfahbod *  This is part of HarfBuzz, a text shaping library.
615232e26f4a89dab1b6de35ad9d3d16e75bf93d0Behdad Esfahbod *
715232e26f4a89dab1b6de35ad9d3d16e75bf93d0Behdad Esfahbod * Permission is hereby granted, without written agreement and without
815232e26f4a89dab1b6de35ad9d3d16e75bf93d0Behdad Esfahbod * license or royalty fees, to use, copy, modify, and distribute this
915232e26f4a89dab1b6de35ad9d3d16e75bf93d0Behdad Esfahbod * software and its documentation for any purpose, provided that the
1015232e26f4a89dab1b6de35ad9d3d16e75bf93d0Behdad Esfahbod * above copyright notice and the following two paragraphs appear in
1115232e26f4a89dab1b6de35ad9d3d16e75bf93d0Behdad Esfahbod * all copies of this software.
1215232e26f4a89dab1b6de35ad9d3d16e75bf93d0Behdad Esfahbod *
1315232e26f4a89dab1b6de35ad9d3d16e75bf93d0Behdad Esfahbod * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
1415232e26f4a89dab1b6de35ad9d3d16e75bf93d0Behdad Esfahbod * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
1515232e26f4a89dab1b6de35ad9d3d16e75bf93d0Behdad Esfahbod * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
1615232e26f4a89dab1b6de35ad9d3d16e75bf93d0Behdad Esfahbod * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
1715232e26f4a89dab1b6de35ad9d3d16e75bf93d0Behdad Esfahbod * DAMAGE.
1815232e26f4a89dab1b6de35ad9d3d16e75bf93d0Behdad Esfahbod *
1915232e26f4a89dab1b6de35ad9d3d16e75bf93d0Behdad Esfahbod * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
2015232e26f4a89dab1b6de35ad9d3d16e75bf93d0Behdad Esfahbod * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
2115232e26f4a89dab1b6de35ad9d3d16e75bf93d0Behdad Esfahbod * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
2215232e26f4a89dab1b6de35ad9d3d16e75bf93d0Behdad Esfahbod * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
2315232e26f4a89dab1b6de35ad9d3d16e75bf93d0Behdad Esfahbod * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
2415232e26f4a89dab1b6de35ad9d3d16e75bf93d0Behdad Esfahbod *
2515232e26f4a89dab1b6de35ad9d3d16e75bf93d0Behdad Esfahbod * Red Hat Author(s): Behdad Esfahbod
26e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod * Google Author(s): Behdad Esfahbod
2715232e26f4a89dab1b6de35ad9d3d16e75bf93d0Behdad Esfahbod */
2815232e26f4a89dab1b6de35ad9d3d16e75bf93d0Behdad Esfahbod
29c57d454accff66e5f2c58006e8fb40bc020b6182Behdad Esfahbod#include "hb-private.hh"
3015232e26f4a89dab1b6de35ad9d3d16e75bf93d0Behdad Esfahbod
31027857d0412477fb4427dcb8a8c45287c272e143Behdad Esfahbod#include "hb-shaper-private.hh"
325b95c148cc485f79fd7018bc4520b4cb5f728a18Behdad Esfahbod#include "hb-shape-plan-private.hh"
3322da7fd94d6318c52df69d70470a85464ffc533dBehdad Esfahbod#include "hb-buffer-private.hh"
345b95c148cc485f79fd7018bc4520b4cb5f728a18Behdad Esfahbod#include "hb-font-private.hh"
352f50d873680ce0a43b6ec79df1ac946b91f31e63Behdad Esfahbod
3602aeca985b570763342c35e99af90025bfa088d5Behdad Esfahbod
373f6461847412e78bcddc8eba97200f3afcde869aBehdad Esfahbodstatic bool
38e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbodparse_space (const char **pp, const char *end)
39e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod{
405c5cdbbdf8be231c433e21b050a6c6991d327b61Behdad Esfahbod  while (*pp < end && ISSPACE (**pp))
41e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod    (*pp)++;
423f6461847412e78bcddc8eba97200f3afcde869aBehdad Esfahbod  return true;
43e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod}
44e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod
45f31f7d2259dd8edffc070af55938cb7aa23514c1Behdad Esfahbodstatic bool
46e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbodparse_char (const char **pp, const char *end, char c)
47e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod{
48e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  parse_space (pp, end);
49e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod
50e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  if (*pp == end || **pp != c)
51e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod    return false;
52e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod
53e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  (*pp)++;
54e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  return true;
55e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod}
56e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod
57f31f7d2259dd8edffc070af55938cb7aa23514c1Behdad Esfahbodstatic bool
58e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbodparse_uint (const char **pp, const char *end, unsigned int *pv)
59e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod{
60e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  char buf[32];
61847794e929831750e97525137ab5e285ccd1064eBehdad Esfahbod  unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
62847794e929831750e97525137ab5e285ccd1064eBehdad Esfahbod  strncpy (buf, *pp, len);
63847794e929831750e97525137ab5e285ccd1064eBehdad Esfahbod  buf[len] = '\0';
64e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod
65e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  char *p = buf;
66e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  char *pend = p;
67e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  unsigned int v;
68e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod
698da51112696ec8641d7dd9184b7ab1dd48458813Behdad Esfahbod  /* Intentionally use strtol instead of strtoul, such that
708da51112696ec8641d7dd9184b7ab1dd48458813Behdad Esfahbod   * -1 turns into "big number"... */
71847794e929831750e97525137ab5e285ccd1064eBehdad Esfahbod  errno = 0;
72e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  v = strtol (p, &pend, 0);
73847794e929831750e97525137ab5e285ccd1064eBehdad Esfahbod  if (errno || p == pend)
74e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod    return false;
75e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod
76e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  *pv = v;
77e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  *pp += pend - p;
78e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  return true;
79e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod}
80e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod
81f31f7d2259dd8edffc070af55938cb7aa23514c1Behdad Esfahbodstatic bool
8260cb18a5dea2d30793f89e80995bb729c014864aBehdad Esfahbodparse_bool (const char **pp, const char *end, unsigned int *pv)
8360cb18a5dea2d30793f89e80995bb729c014864aBehdad Esfahbod{
8460cb18a5dea2d30793f89e80995bb729c014864aBehdad Esfahbod  parse_space (pp, end);
8560cb18a5dea2d30793f89e80995bb729c014864aBehdad Esfahbod
8660cb18a5dea2d30793f89e80995bb729c014864aBehdad Esfahbod  const char *p = *pp;
8760cb18a5dea2d30793f89e80995bb729c014864aBehdad Esfahbod  while (*pp < end && ISALPHA(**pp))
8860cb18a5dea2d30793f89e80995bb729c014864aBehdad Esfahbod    (*pp)++;
8960cb18a5dea2d30793f89e80995bb729c014864aBehdad Esfahbod
9060cb18a5dea2d30793f89e80995bb729c014864aBehdad Esfahbod  /* CSS allows on/off as aliases 1/0. */
9160cb18a5dea2d30793f89e80995bb729c014864aBehdad Esfahbod  if (*pp - p == 2 || 0 == strncmp (p, "on", 2))
9260cb18a5dea2d30793f89e80995bb729c014864aBehdad Esfahbod    *pv = 1;
9360cb18a5dea2d30793f89e80995bb729c014864aBehdad Esfahbod  else if (*pp - p == 3 || 0 == strncmp (p, "off", 2))
9460cb18a5dea2d30793f89e80995bb729c014864aBehdad Esfahbod    *pv = 0;
9560cb18a5dea2d30793f89e80995bb729c014864aBehdad Esfahbod  else
9660cb18a5dea2d30793f89e80995bb729c014864aBehdad Esfahbod    return false;
9760cb18a5dea2d30793f89e80995bb729c014864aBehdad Esfahbod
9860cb18a5dea2d30793f89e80995bb729c014864aBehdad Esfahbod  return true;
9960cb18a5dea2d30793f89e80995bb729c014864aBehdad Esfahbod}
10060cb18a5dea2d30793f89e80995bb729c014864aBehdad Esfahbod
101f31f7d2259dd8edffc070af55938cb7aa23514c1Behdad Esfahbodstatic bool
102e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbodparse_feature_value_prefix (const char **pp, const char *end, hb_feature_t *feature)
103e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod{
104e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  if (parse_char (pp, end, '-'))
105e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod    feature->value = 0;
106e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  else {
107e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod    parse_char (pp, end, '+');
108e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod    feature->value = 1;
109e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  }
110e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod
111e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  return true;
112e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod}
113e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod
114f31f7d2259dd8edffc070af55938cb7aa23514c1Behdad Esfahbodstatic bool
115e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbodparse_feature_tag (const char **pp, const char *end, hb_feature_t *feature)
116e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod{
1172ee5f665ded86147acedc400153c0b3a90fe07c6Behdad Esfahbod  parse_space (pp, end);
1182ee5f665ded86147acedc400153c0b3a90fe07c6Behdad Esfahbod
119a795fe637846e0d9561d2f7cdd84cfafd58b23a7Behdad Esfahbod  char quote = 0;
120a795fe637846e0d9561d2f7cdd84cfafd58b23a7Behdad Esfahbod
121a795fe637846e0d9561d2f7cdd84cfafd58b23a7Behdad Esfahbod  if (*pp < end && (**pp == '\'' || **pp == '"'))
122a795fe637846e0d9561d2f7cdd84cfafd58b23a7Behdad Esfahbod  {
123a795fe637846e0d9561d2f7cdd84cfafd58b23a7Behdad Esfahbod    quote = **pp;
124a795fe637846e0d9561d2f7cdd84cfafd58b23a7Behdad Esfahbod    (*pp)++;
125a795fe637846e0d9561d2f7cdd84cfafd58b23a7Behdad Esfahbod  }
126e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod
127a795fe637846e0d9561d2f7cdd84cfafd58b23a7Behdad Esfahbod  const char *p = *pp;
128a795fe637846e0d9561d2f7cdd84cfafd58b23a7Behdad Esfahbod  while (*pp < end && ISALNUM(**pp))
129e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod    (*pp)++;
130e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod
131f4fe9baefdb7e0ff9946f88b6f4b55738fa30cdfBehdad Esfahbod  if (p == *pp || *pp - p > 4)
132e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod    return false;
133e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod
134e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  feature->tag = hb_tag_from_string (p, *pp - p);
135a795fe637846e0d9561d2f7cdd84cfafd58b23a7Behdad Esfahbod
136a795fe637846e0d9561d2f7cdd84cfafd58b23a7Behdad Esfahbod  if (quote)
137a795fe637846e0d9561d2f7cdd84cfafd58b23a7Behdad Esfahbod  {
138a795fe637846e0d9561d2f7cdd84cfafd58b23a7Behdad Esfahbod    /* CSS expects exactly four bytes.  And we only allow quotations for
139a795fe637846e0d9561d2f7cdd84cfafd58b23a7Behdad Esfahbod     * CSS compatibility.  So, enforce the length. */
140a795fe637846e0d9561d2f7cdd84cfafd58b23a7Behdad Esfahbod     if (*pp - p != 4)
141a795fe637846e0d9561d2f7cdd84cfafd58b23a7Behdad Esfahbod       return false;
142a795fe637846e0d9561d2f7cdd84cfafd58b23a7Behdad Esfahbod    if (*pp == end || **pp != quote)
143a795fe637846e0d9561d2f7cdd84cfafd58b23a7Behdad Esfahbod      return false;
144a795fe637846e0d9561d2f7cdd84cfafd58b23a7Behdad Esfahbod    (*pp)++;
145a795fe637846e0d9561d2f7cdd84cfafd58b23a7Behdad Esfahbod  }
146a795fe637846e0d9561d2f7cdd84cfafd58b23a7Behdad Esfahbod
147e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  return true;
148e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod}
149e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod
150f31f7d2259dd8edffc070af55938cb7aa23514c1Behdad Esfahbodstatic bool
151e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbodparse_feature_indices (const char **pp, const char *end, hb_feature_t *feature)
152e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod{
153e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  parse_space (pp, end);
154e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod
155f31f7d2259dd8edffc070af55938cb7aa23514c1Behdad Esfahbod  bool has_start;
156e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod
157e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  feature->start = 0;
158e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  feature->end = (unsigned int) -1;
159e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod
160e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  if (!parse_char (pp, end, '['))
161e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod    return true;
162e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod
163e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  has_start = parse_uint (pp, end, &feature->start);
164e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod
165e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  if (parse_char (pp, end, ':')) {
166e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod    parse_uint (pp, end, &feature->end);
167e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  } else {
168e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod    if (has_start)
169e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod      feature->end = feature->start + 1;
170e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  }
171e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod
172e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  return parse_char (pp, end, ']');
173e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod}
174e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod
175f31f7d2259dd8edffc070af55938cb7aa23514c1Behdad Esfahbodstatic bool
176e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbodparse_feature_value_postfix (const char **pp, const char *end, hb_feature_t *feature)
177e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod{
178e15fa7a8cffbe6a67b1048d7b87b7df77d8b1686Behdad Esfahbod  bool had_equal = parse_char (pp, end, '=');
17960cb18a5dea2d30793f89e80995bb729c014864aBehdad Esfahbod  bool had_value = parse_uint (pp, end, &feature->value) ||
18060cb18a5dea2d30793f89e80995bb729c014864aBehdad Esfahbod                   parse_bool (pp, end, &feature->value);
18160cb18a5dea2d30793f89e80995bb729c014864aBehdad Esfahbod  /* CSS doesn't use equal-sign between tag and value.
18260cb18a5dea2d30793f89e80995bb729c014864aBehdad Esfahbod   * If there was an equal-sign, then there *must* be a value.
183e15fa7a8cffbe6a67b1048d7b87b7df77d8b1686Behdad Esfahbod   * A value without an eqaul-sign is ok, but not required. */
184e15fa7a8cffbe6a67b1048d7b87b7df77d8b1686Behdad Esfahbod  return !had_equal || had_value;
185e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod}
186e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod
187e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod
188f31f7d2259dd8edffc070af55938cb7aa23514c1Behdad Esfahbodstatic bool
189e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbodparse_one_feature (const char **pp, const char *end, hb_feature_t *feature)
190e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod{
191e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  return parse_feature_value_prefix (pp, end, feature) &&
192e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod	 parse_feature_tag (pp, end, feature) &&
193e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod	 parse_feature_indices (pp, end, feature) &&
194e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod	 parse_feature_value_postfix (pp, end, feature) &&
1953f6461847412e78bcddc8eba97200f3afcde869aBehdad Esfahbod	 parse_space (pp, end) &&
196e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod	 *pp == end;
197e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod}
198e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod
199288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod/**
200288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod * hb_feature_from_string:
201288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod * @str: (array length=len):
202288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod * @len:
2035c5cdbbdf8be231c433e21b050a6c6991d327b61Behdad Esfahbod * @feature: (out) (allow-none):
204288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod *
205288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod *
206288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod *
207288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod * Return value:
208288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod *
209288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod * Since: 1.0
210288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod **/
211e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbodhb_bool_t
212e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbodhb_feature_from_string (const char *str, int len,
213e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod			hb_feature_t *feature)
214e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod{
2155c5cdbbdf8be231c433e21b050a6c6991d327b61Behdad Esfahbod  hb_feature_t feat;
2165c5cdbbdf8be231c433e21b050a6c6991d327b61Behdad Esfahbod
217e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  if (len < 0)
218e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod    len = strlen (str);
219e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod
2205c5cdbbdf8be231c433e21b050a6c6991d327b61Behdad Esfahbod  if (likely (parse_one_feature (&str, str + len, &feat)))
2215c5cdbbdf8be231c433e21b050a6c6991d327b61Behdad Esfahbod  {
2225c5cdbbdf8be231c433e21b050a6c6991d327b61Behdad Esfahbod    if (feature)
2235c5cdbbdf8be231c433e21b050a6c6991d327b61Behdad Esfahbod      *feature = feat;
2245c5cdbbdf8be231c433e21b050a6c6991d327b61Behdad Esfahbod    return true;
2255c5cdbbdf8be231c433e21b050a6c6991d327b61Behdad Esfahbod  }
2265c5cdbbdf8be231c433e21b050a6c6991d327b61Behdad Esfahbod
2275c5cdbbdf8be231c433e21b050a6c6991d327b61Behdad Esfahbod  if (feature)
2285c5cdbbdf8be231c433e21b050a6c6991d327b61Behdad Esfahbod    memset (feature, 0, sizeof (*feature));
2295c5cdbbdf8be231c433e21b050a6c6991d327b61Behdad Esfahbod  return false;
230e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod}
231e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod
232288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod/**
233288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod * hb_feature_to_string:
234288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod * @feature:
235288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod * @buf: (array length=size):
236288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod * @size:
237288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod *
238288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod *
239288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod *
240288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod * Since: 1.0
241288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod **/
242e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbodvoid
243e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbodhb_feature_to_string (hb_feature_t *feature,
244e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod		      char *buf, unsigned int size)
245e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod{
246e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  if (unlikely (!size)) return;
247e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod
248e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  char s[128];
249e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  unsigned int len = 0;
250e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  if (feature->value == 0)
251e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod    s[len++] = '-';
252e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  hb_tag_to_string (feature->tag, s + len);
253e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  len += 4;
254e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  while (len && s[len - 1] == ' ')
255e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod    len--;
2561c7e55511a870f2689680ca8f977e00879f3b3e3Behdad Esfahbod  if (feature->start != 0 || feature->end != (unsigned int) -1)
257e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  {
258e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod    s[len++] = '[';
259e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod    if (feature->start)
2606e69200a2aadbc6bba35ffb4a058c14286b84f46Behdad Esfahbod      len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->start));
261e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod    if (feature->end != feature->start + 1) {
262e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod      s[len++] = ':';
263e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod      if (feature->end != (unsigned int) -1)
2646e69200a2aadbc6bba35ffb4a058c14286b84f46Behdad Esfahbod	len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->end));
265e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod    }
266e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod    s[len++] = ']';
267e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  }
268e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  if (feature->value > 1)
269e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  {
270e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod    s[len++] = '=';
2716e69200a2aadbc6bba35ffb4a058c14286b84f46Behdad Esfahbod    len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->value));
272e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  }
273e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  assert (len < ARRAY_LENGTH (s));
274e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  len = MIN (len, size - 1);
275e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  memcpy (buf, s, len);
2767235f33f9e5e031622a00a84f4b2e98f16803579Behdad Esfahbod  buf[len] = '\0';
277e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod}
278e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod
279e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod
280f64b2ebf82c5f355cd95806478cd30c00b1a2731Behdad Esfahbodstatic const char **static_shaper_list;
281f64b2ebf82c5f355cd95806478cd30c00b1a2731Behdad Esfahbod
282e9171af55cc6a402eb20db4ea74c86a0b1e70e85Behdad Esfahbodstatic inline
283f64b2ebf82c5f355cd95806478cd30c00b1a2731Behdad Esfahbodvoid free_static_shaper_list (void)
284f64b2ebf82c5f355cd95806478cd30c00b1a2731Behdad Esfahbod{
285f64b2ebf82c5f355cd95806478cd30c00b1a2731Behdad Esfahbod  free (static_shaper_list);
286f64b2ebf82c5f355cd95806478cd30c00b1a2731Behdad Esfahbod}
2879da554504e30a326fc57b28cdb0e57108bfa9555Behdad Esfahbod
288288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod/**
289288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod * hb_shape_list_shapers:
290288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod *
291288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod *
292288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod *
293288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod * Return value: (transfer none):
294288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod *
295288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod * Since: 1.0
296288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod **/
2979da554504e30a326fc57b28cdb0e57108bfa9555Behdad Esfahbodconst char **
2989da554504e30a326fc57b28cdb0e57108bfa9555Behdad Esfahbodhb_shape_list_shapers (void)
2999da554504e30a326fc57b28cdb0e57108bfa9555Behdad Esfahbod{
300f64b2ebf82c5f355cd95806478cd30c00b1a2731Behdad Esfahbodretry:
301f64b2ebf82c5f355cd95806478cd30c00b1a2731Behdad Esfahbod  const char **shaper_list = (const char **) hb_atomic_ptr_get (&static_shaper_list);
302f64b2ebf82c5f355cd95806478cd30c00b1a2731Behdad Esfahbod
303f64b2ebf82c5f355cd95806478cd30c00b1a2731Behdad Esfahbod  if (unlikely (!shaper_list))
304f64b2ebf82c5f355cd95806478cd30c00b1a2731Behdad Esfahbod  {
305f64b2ebf82c5f355cd95806478cd30c00b1a2731Behdad Esfahbod    /* Not found; allocate one. */
306bd26b4d21f59312805d294f46f15182adbcc47daBehdad Esfahbod    shaper_list = (const char **) calloc (1 + HB_SHAPERS_COUNT, sizeof (const char *));
307f64b2ebf82c5f355cd95806478cd30c00b1a2731Behdad Esfahbod    if (unlikely (!shaper_list)) {
308f64b2ebf82c5f355cd95806478cd30c00b1a2731Behdad Esfahbod      static const char *nil_shaper_list[] = {NULL};
309f64b2ebf82c5f355cd95806478cd30c00b1a2731Behdad Esfahbod      return nil_shaper_list;
310f64b2ebf82c5f355cd95806478cd30c00b1a2731Behdad Esfahbod    }
311f64b2ebf82c5f355cd95806478cd30c00b1a2731Behdad Esfahbod
312bd26b4d21f59312805d294f46f15182adbcc47daBehdad Esfahbod    const hb_shaper_pair_t *shapers = _hb_shapers_get ();
313f64b2ebf82c5f355cd95806478cd30c00b1a2731Behdad Esfahbod    unsigned int i;
314bd26b4d21f59312805d294f46f15182adbcc47daBehdad Esfahbod    for (i = 0; i < HB_SHAPERS_COUNT; i++)
315f64b2ebf82c5f355cd95806478cd30c00b1a2731Behdad Esfahbod      shaper_list[i] = shapers[i].name;
316f64b2ebf82c5f355cd95806478cd30c00b1a2731Behdad Esfahbod    shaper_list[i] = NULL;
317f64b2ebf82c5f355cd95806478cd30c00b1a2731Behdad Esfahbod
318f64b2ebf82c5f355cd95806478cd30c00b1a2731Behdad Esfahbod    if (!hb_atomic_ptr_cmpexch (&static_shaper_list, NULL, shaper_list)) {
319f64b2ebf82c5f355cd95806478cd30c00b1a2731Behdad Esfahbod      free (shaper_list);
320f64b2ebf82c5f355cd95806478cd30c00b1a2731Behdad Esfahbod      goto retry;
321f64b2ebf82c5f355cd95806478cd30c00b1a2731Behdad Esfahbod    }
322f64b2ebf82c5f355cd95806478cd30c00b1a2731Behdad Esfahbod
323f64b2ebf82c5f355cd95806478cd30c00b1a2731Behdad Esfahbod#ifdef HAVE_ATEXIT
324f64b2ebf82c5f355cd95806478cd30c00b1a2731Behdad Esfahbod    atexit (free_static_shaper_list); /* First person registers atexit() callback. */
325f64b2ebf82c5f355cd95806478cd30c00b1a2731Behdad Esfahbod#endif
326f64b2ebf82c5f355cd95806478cd30c00b1a2731Behdad Esfahbod  }
327f64b2ebf82c5f355cd95806478cd30c00b1a2731Behdad Esfahbod
328f64b2ebf82c5f355cd95806478cd30c00b1a2731Behdad Esfahbod  return shaper_list;
3299da554504e30a326fc57b28cdb0e57108bfa9555Behdad Esfahbod}
33002aeca985b570763342c35e99af90025bfa088d5Behdad Esfahbod
331f64b2ebf82c5f355cd95806478cd30c00b1a2731Behdad Esfahbod
332288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod/**
333288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod * hb_shape_full:
334288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod * @font: a font.
335288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod * @buffer: a buffer.
336288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod * @features: (array length=num_features):
337288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod * @num_features:
338288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod * @shaper_list: (array zero-terminated=1):
339288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod *
340288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod *
341288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod *
342288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod * Return value:
343288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod *
344288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod * Since: 1.0
345288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod **/
34602aeca985b570763342c35e99af90025bfa088d5Behdad Esfahbodhb_bool_t
3470501573deda3a8dcdfcea491392f554f21ed0154Behdad Esfahbodhb_shape_full (hb_font_t          *font,
3480501573deda3a8dcdfcea491392f554f21ed0154Behdad Esfahbod	       hb_buffer_t        *buffer,
3490501573deda3a8dcdfcea491392f554f21ed0154Behdad Esfahbod	       const hb_feature_t *features,
3500501573deda3a8dcdfcea491392f554f21ed0154Behdad Esfahbod	       unsigned int        num_features,
3510501573deda3a8dcdfcea491392f554f21ed0154Behdad Esfahbod	       const char * const *shaper_list)
3523286fc0e9adc3f2874c9409e7fdb09e4d2b7dda1Behdad Esfahbod{
353b6b7ba1313bf686e6ed567183466104c90504a67Behdad Esfahbod  if (unlikely (!buffer->len))
354b6b7ba1313bf686e6ed567183466104c90504a67Behdad Esfahbod    return true;
355b6b7ba1313bf686e6ed567183466104c90504a67Behdad Esfahbod
35696fdc04e5c6daafce3d45e7508418e4db94df44cBehdad Esfahbod  assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE);
35796fdc04e5c6daafce3d45e7508418e4db94df44cBehdad Esfahbod
3582f87cebe1062c7007021ebd05c1664e60da80825Behdad Esfahbod  hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props, features, num_features, shaper_list);
359c32c096a429da3e64896cf42ff5ab8c775d3c2ecBehdad Esfahbod  hb_bool_t res = hb_shape_plan_execute (shape_plan, font, buffer, features, num_features);
360c32c096a429da3e64896cf42ff5ab8c775d3c2ecBehdad Esfahbod  hb_shape_plan_destroy (shape_plan);
36196fdc04e5c6daafce3d45e7508418e4db94df44cBehdad Esfahbod
36296fdc04e5c6daafce3d45e7508418e4db94df44cBehdad Esfahbod  if (res)
36396fdc04e5c6daafce3d45e7508418e4db94df44cBehdad Esfahbod    buffer->content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS;
364c32c096a429da3e64896cf42ff5ab8c775d3c2ecBehdad Esfahbod  return res;
3653286fc0e9adc3f2874c9409e7fdb09e4d2b7dda1Behdad Esfahbod}
3663ca6c4ecc299295b6682fa2b6b9f83b213223badBehdad Esfahbod
367288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod/**
368288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod * hb_shape:
369288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod * @font: a font.
370288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod * @buffer: a buffer.
371288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod * @features: (array length=num_features):
372288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod * @num_features:
373288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod *
374288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod *
375288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod *
376288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod * Since: 1.0
377288f2899979bcc9e68f8115cb76e3271ed0e17bcBehdad Esfahbod **/
3783ca6c4ecc299295b6682fa2b6b9f83b213223badBehdad Esfahbodvoid
3793ca6c4ecc299295b6682fa2b6b9f83b213223badBehdad Esfahbodhb_shape (hb_font_t           *font,
3803ca6c4ecc299295b6682fa2b6b9f83b213223badBehdad Esfahbod	  hb_buffer_t         *buffer,
3813ca6c4ecc299295b6682fa2b6b9f83b213223badBehdad Esfahbod	  const hb_feature_t  *features,
3823ca6c4ecc299295b6682fa2b6b9f83b213223badBehdad Esfahbod	  unsigned int         num_features)
3833ca6c4ecc299295b6682fa2b6b9f83b213223badBehdad Esfahbod{
3846bd9b479b8b2befbb0847282e93beade197c8038Behdad Esfahbod  hb_shape_full (font, buffer, features, num_features, NULL);
3853ca6c4ecc299295b6682fa2b6b9f83b213223badBehdad Esfahbod}
386