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