gfx/harfbuzz/src/hb-ot-tag.cc

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/harfbuzz/src/hb-ot-tag.cc	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,903 @@
     1.4 +/*
     1.5 + * Copyright © 2009  Red Hat, Inc.
     1.6 + * Copyright © 2011  Google, Inc.
     1.7 + *
     1.8 + *  This is part of HarfBuzz, a text shaping library.
     1.9 + *
    1.10 + * Permission is hereby granted, without written agreement and without
    1.11 + * license or royalty fees, to use, copy, modify, and distribute this
    1.12 + * software and its documentation for any purpose, provided that the
    1.13 + * above copyright notice and the following two paragraphs appear in
    1.14 + * all copies of this software.
    1.15 + *
    1.16 + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
    1.17 + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
    1.18 + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
    1.19 + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
    1.20 + * DAMAGE.
    1.21 + *
    1.22 + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
    1.23 + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
    1.24 + * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
    1.25 + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
    1.26 + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
    1.27 + *
    1.28 + * Red Hat Author(s): Behdad Esfahbod
    1.29 + * Google Author(s): Behdad Esfahbod, Roozbeh Pournader
    1.30 + */
    1.31 +
    1.32 +#include "hb-private.hh"
    1.33 +
    1.34 +#include <string.h>
    1.35 +
    1.36 +
    1.37 +
    1.38 +/* hb_script_t */
    1.39 +
    1.40 +static hb_tag_t
    1.41 +hb_ot_old_tag_from_script (hb_script_t script)
    1.42 +{
    1.43 +  /* This seems to be accurate as of end of 2012. */
    1.44 +
    1.45 +  switch ((hb_tag_t) script) {
    1.46 +    case HB_SCRIPT_INVALID:		return HB_OT_TAG_DEFAULT_SCRIPT;
    1.47 +
    1.48 +    /* KATAKANA and HIRAGANA both map to 'kana' */
    1.49 +    case HB_SCRIPT_HIRAGANA:		return HB_TAG('k','a','n','a');
    1.50 +
    1.51 +    /* Spaces at the end are preserved, unlike ISO 15924 */
    1.52 +    case HB_SCRIPT_LAO:			return HB_TAG('l','a','o',' ');
    1.53 +    case HB_SCRIPT_YI:			return HB_TAG('y','i',' ',' ');
    1.54 +    /* Unicode-5.0 additions */
    1.55 +    case HB_SCRIPT_NKO:			return HB_TAG('n','k','o',' ');
    1.56 +    /* Unicode-5.1 additions */
    1.57 +    case HB_SCRIPT_VAI:			return HB_TAG('v','a','i',' ');
    1.58 +    /* Unicode-5.2 additions */
    1.59 +    /* Unicode-6.0 additions */
    1.60 +  }
    1.61 +
    1.62 +  /* Else, just change first char to lowercase and return */
    1.63 +  return ((hb_tag_t) script) | 0x20000000;
    1.64 +}
    1.65 +
    1.66 +static hb_script_t
    1.67 +hb_ot_old_tag_to_script (hb_tag_t tag)
    1.68 +{
    1.69 +  if (unlikely (tag == HB_OT_TAG_DEFAULT_SCRIPT))
    1.70 +    return HB_SCRIPT_INVALID;
    1.71 +
    1.72 +  /* This side of the conversion is fully algorithmic. */
    1.73 +
    1.74 +  /* Any spaces at the end of the tag are replaced by repeating the last
    1.75 +   * letter.  Eg 'nko ' -> 'Nkoo' */
    1.76 +  if (unlikely ((tag & 0x0000FF00) == 0x00002000))
    1.77 +    tag |= (tag >> 8) & 0x0000FF00; /* Copy second letter to third */
    1.78 +  if (unlikely ((tag & 0x000000FF) == 0x00000020))
    1.79 +    tag |= (tag >> 8) & 0x000000FF; /* Copy third letter to fourth */
    1.80 +
    1.81 +  /* Change first char to uppercase and return */
    1.82 +  return (hb_script_t) (tag & ~0x20000000);
    1.83 +}
    1.84 +
    1.85 +static hb_tag_t
    1.86 +hb_ot_new_tag_from_script (hb_script_t script)
    1.87 +{
    1.88 +  switch ((hb_tag_t) script) {
    1.89 +    case HB_SCRIPT_BENGALI:		return HB_TAG('b','n','g','2');
    1.90 +    case HB_SCRIPT_DEVANAGARI:		return HB_TAG('d','e','v','2');
    1.91 +    case HB_SCRIPT_GUJARATI:		return HB_TAG('g','j','r','2');
    1.92 +    case HB_SCRIPT_GURMUKHI:		return HB_TAG('g','u','r','2');
    1.93 +    case HB_SCRIPT_KANNADA:		return HB_TAG('k','n','d','2');
    1.94 +    case HB_SCRIPT_MALAYALAM:		return HB_TAG('m','l','m','2');
    1.95 +    case HB_SCRIPT_ORIYA:		return HB_TAG('o','r','y','2');
    1.96 +    case HB_SCRIPT_TAMIL:		return HB_TAG('t','m','l','2');
    1.97 +    case HB_SCRIPT_TELUGU:		return HB_TAG('t','e','l','2');
    1.98 +    case HB_SCRIPT_MYANMAR:		return HB_TAG('m','y','m','2');
    1.99 +  }
   1.100 +
   1.101 +  return HB_OT_TAG_DEFAULT_SCRIPT;
   1.102 +}
   1.103 +
   1.104 +static hb_script_t
   1.105 +hb_ot_new_tag_to_script (hb_tag_t tag)
   1.106 +{
   1.107 +  switch (tag) {
   1.108 +    case HB_TAG('b','n','g','2'):	return HB_SCRIPT_BENGALI;
   1.109 +    case HB_TAG('d','e','v','2'):	return HB_SCRIPT_DEVANAGARI;
   1.110 +    case HB_TAG('g','j','r','2'):	return HB_SCRIPT_GUJARATI;
   1.111 +    case HB_TAG('g','u','r','2'):	return HB_SCRIPT_GURMUKHI;
   1.112 +    case HB_TAG('k','n','d','2'):	return HB_SCRIPT_KANNADA;
   1.113 +    case HB_TAG('m','l','m','2'):	return HB_SCRIPT_MALAYALAM;
   1.114 +    case HB_TAG('o','r','y','2'):	return HB_SCRIPT_ORIYA;
   1.115 +    case HB_TAG('t','m','l','2'):	return HB_SCRIPT_TAMIL;
   1.116 +    case HB_TAG('t','e','l','2'):	return HB_SCRIPT_TELUGU;
   1.117 +    case HB_TAG('m','y','m','2'):	return HB_SCRIPT_MYANMAR;
   1.118 +  }
   1.119 +
   1.120 +  return HB_SCRIPT_UNKNOWN;
   1.121 +}
   1.122 +
   1.123 +/*
   1.124 + * Complete list at:
   1.125 + * https://www.microsoft.com/typography/otspec/scripttags.htm
   1.126 + * https://www.microsoft.com/typography/otspec160/scripttagsProposed.htm
   1.127 + *
   1.128 + * Most of the script tags are the same as the ISO 15924 tag but lowercased.
   1.129 + * So we just do that, and handle the exceptional cases in a switch.
   1.130 + */
   1.131 +
   1.132 +void
   1.133 +hb_ot_tags_from_script (hb_script_t  script,
   1.134 +			hb_tag_t    *script_tag_1,
   1.135 +			hb_tag_t    *script_tag_2)
   1.136 +{
   1.137 +  hb_tag_t new_tag;
   1.138 +
   1.139 +  *script_tag_2 = HB_OT_TAG_DEFAULT_SCRIPT;
   1.140 +  *script_tag_1 = hb_ot_old_tag_from_script (script);
   1.141 +
   1.142 +  new_tag = hb_ot_new_tag_from_script (script);
   1.143 +  if (unlikely (new_tag != HB_OT_TAG_DEFAULT_SCRIPT)) {
   1.144 +    *script_tag_2 = *script_tag_1;
   1.145 +    *script_tag_1 = new_tag;
   1.146 +  }
   1.147 +}
   1.148 +
   1.149 +hb_script_t
   1.150 +hb_ot_tag_to_script (hb_tag_t tag)
   1.151 +{
   1.152 +  if (unlikely ((tag & 0x000000FF) == '2'))
   1.153 +    return hb_ot_new_tag_to_script (tag);
   1.154 +
   1.155 +  return hb_ot_old_tag_to_script (tag);
   1.156 +}
   1.157 +
   1.158 +
   1.159 +/* hb_language_t */
   1.160 +
   1.161 +typedef struct {
   1.162 +  char language[6];
   1.163 +  hb_tag_t tag;
   1.164 +} LangTag;
   1.165 +
   1.166 +/*
   1.167 + * Complete list at:
   1.168 + * http://www.microsoft.com/typography/otspec/languagetags.htm
   1.169 + *
   1.170 + * Generated by intersecting the OpenType language tag list from
   1.171 + * Draft OpenType 1.5 spec, with with the ISO 639-3 codes from
   1.172 + * 2008-08-04, matching on name, and finally adjusted manually.
   1.173 + *
   1.174 + * Updated on 2012-12-07 with more research into remaining codes.
   1.175 + *
   1.176 + * Updated on 2013-11-23 based on usage in SIL and Microsoft fonts,
   1.177 + * the new proposal from Microsoft, and latest ISO 639-3 names.
   1.178 + *
   1.179 + * Some items still missing.  Those are commented out at the end.
   1.180 + * Keep sorted for bsearch.
   1.181 + */
   1.182 +
   1.183 +static const LangTag ot_languages[] = {
   1.184 +  {"aa",	HB_TAG('A','F','R',' ')},	/* Afar */
   1.185 +  {"ab",	HB_TAG('A','B','K',' ')},	/* Abkhazian */
   1.186 +  {"abq",	HB_TAG('A','B','A',' ')},	/* Abaza */
   1.187 +  {"ach",	HB_TAG('A','C','H',' ')},	/* Acoli */
   1.188 +  {"ada",	HB_TAG('D','N','G',' ')},	/* Dangme */
   1.189 +  {"ady",	HB_TAG('A','D','Y',' ')},	/* Adyghe */
   1.190 +  {"af",	HB_TAG('A','F','K',' ')},	/* Afrikaans */
   1.191 +  {"aii",	HB_TAG('S','W','A',' ')},	/* Swadaya Aramaic */
   1.192 +  {"aio",	HB_TAG('A','I','O',' ')},	/* Aiton */
   1.193 +  {"aiw",	HB_TAG('A','R','I',' ')},	/* Aari */
   1.194 +  {"ak",	HB_TAG('T','W','I',' ')},	/* Akan [macrolanguage] */
   1.195 +  {"alt",	HB_TAG('A','L','T',' ')},	/* [Southern] Altai */
   1.196 +  {"am",	HB_TAG('A','M','H',' ')},	/* Amharic */
   1.197 +  {"amf",	HB_TAG('H','B','N',' ')},	/* Hammer-Banna */
   1.198 +  {"an",	HB_TAG('A','R','G',' ')},	/* Aragonese */
   1.199 +  {"ang",	HB_TAG('A','N','G',' ')},	/* Old English (ca. 450-1100) */
   1.200 +  {"ar",	HB_TAG('A','R','A',' ')},	/* Arabic [macrolanguage] */
   1.201 +  {"arb",	HB_TAG('A','R','A',' ')},	/* Standard Arabic */
   1.202 +  {"arn",	HB_TAG('M','A','P',' ')},	/* Mapudungun */
   1.203 +  {"ary",	HB_TAG('M','O','R',' ')},	/* Moroccan Arabic */
   1.204 +  {"as",	HB_TAG('A','S','M',' ')},	/* Assamese */
   1.205 +  {"ast",	HB_TAG('A','S','T',' ')},	/* Asturian/Asturleonese/Bable/Leonese */
   1.206 +  {"ath",	HB_TAG('A','T','H',' ')},	/* Athapaskan [family] */
   1.207 +  {"atv",	HB_TAG('A','L','T',' ')},	/* [Northern] Altai */
   1.208 +  {"av",	HB_TAG('A','V','R',' ')},	/* Avaric */
   1.209 +  {"awa",	HB_TAG('A','W','A',' ')},	/* Awadhi */
   1.210 +  {"ay",	HB_TAG('A','Y','M',' ')},	/* Aymara [macrolanguage] */
   1.211 +  {"az",	HB_TAG('A','Z','E',' ')},	/* Azerbaijani [macrolanguage] */
   1.212 +  {"azb",	HB_TAG('A','Z','B',' ')},	/* South Azerbaijani */
   1.213 +  {"azj",	HB_TAG('A','Z','E',' ')},	/* North Azerbaijani */
   1.214 +  {"ba",	HB_TAG('B','S','H',' ')},	/* Bashkir */
   1.215 +  {"bai",	HB_TAG('B','M','L',' ')},	/* Bamileke [family] */
   1.216 +  {"bal",	HB_TAG('B','L','I',' ')},	/* Baluchi [macrolangauge] */
   1.217 +  {"ban",	HB_TAG('B','A','N',' ')},	/* Balinese */
   1.218 +  {"bar",	HB_TAG('B','A','R',' ')},	/* Bavarian */
   1.219 +  {"bbc",	HB_TAG('B','B','C',' ')},	/* Batak Toba */
   1.220 +  {"bci",	HB_TAG('B','A','U',' ')},	/* Baoulé */
   1.221 +  {"bcl",	HB_TAG('B','I','K',' ')},	/* Central Bikol */
   1.222 +  {"bcq",	HB_TAG('B','C','H',' ')},	/* Bench */
   1.223 +  {"be",	HB_TAG('B','E','L',' ')},  	/* Belarusian */
   1.224 +  {"bem",	HB_TAG('B','E','M',' ')},	/* Bemba (Zambia) */
   1.225 +  {"ber",	HB_TAG('B','E','R',' ')},  	/* Berber [family] */
   1.226 +  {"bfq",	HB_TAG('B','A','D',' ')},	/* Badaga */
   1.227 +  {"bft",	HB_TAG('B','L','T',' ')},	/* Balti */
   1.228 +  {"bfy",	HB_TAG('B','A','G',' ')},	/* Baghelkhandi */
   1.229 +  {"bg",	HB_TAG('B','G','R',' ')},	/* Bulgarian */
   1.230 +  {"bgc",	HB_TAG('B','G','C',' ')},	/* Haryanvi */
   1.231 +  {"bgq",	HB_TAG('B','G','Q',' ')},	/* Bagri */
   1.232 +  {"bhb",	HB_TAG('B','H','I',' ')},	/* Bhili */
   1.233 +  {"bhk",	HB_TAG('B','I','K',' ')},	/* Albay Bicolano (retired code) */
   1.234 +  {"bho",	HB_TAG('B','H','O',' ')},	/* Bhojpuri */
   1.235 +  {"bi",	HB_TAG('B','I','S',' ')},	/* Bislama */
   1.236 +  {"bik",	HB_TAG('B','I','K',' ')},	/* Bikol [macrolanguage] */
   1.237 +  {"bin",	HB_TAG('E','D','O',' ')},	/* Bini */
   1.238 +  {"bjj",	HB_TAG('B','J','J',' ')},	/* Kanauji */
   1.239 +  {"bjt",	HB_TAG('B','L','N',' ')},	/* Balanta-Ganja */
   1.240 +  {"bla",	HB_TAG('B','K','F',' ')},	/* Blackfoot */
   1.241 +  {"ble",	HB_TAG('B','L','N',' ')},	/* Balanta-Kentohe */
   1.242 +  {"blk",	HB_TAG('B','L','K',' ')},	/* Pa'O/Pa'o Karen */
   1.243 +  {"bln",	HB_TAG('B','I','K',' ')},	/* Southern Catanduanes Bikol */
   1.244 +  {"bm",	HB_TAG('B','M','B',' ')},	/* Bambara */
   1.245 +  {"bn",	HB_TAG('B','E','N',' ')},	/* Bengali */
   1.246 +  {"bo",	HB_TAG('T','I','B',' ')},	/* Tibetan */
   1.247 +  {"bpy",	HB_TAG('B','P','Y',' ')},	/* Bishnupriya */
   1.248 +  {"bqi",	HB_TAG('L','R','C',' ')},	/* Bakhtiari */
   1.249 +  {"br",	HB_TAG('B','R','E',' ')},	/* Breton */
   1.250 +  {"bra",	HB_TAG('B','R','I',' ')},	/* Braj Bhasha */
   1.251 +  {"brh",	HB_TAG('B','R','H',' ')},	/* Brahui */
   1.252 +  {"brx",	HB_TAG('B','R','X',' ')},	/* Bodo (India) */
   1.253 +  {"bs",	HB_TAG('B','O','S',' ')},	/* Bosnian */
   1.254 +  {"btb",	HB_TAG('B','T','I',' ')},	/* Beti (Cameroon) */
   1.255 +  {"bto",	HB_TAG('B','I','K',' ')},	/* Rinconada Bikol */
   1.256 +  {"bts",	HB_TAG('B','T','S',' ')},	/* Batak Simalungun */
   1.257 +  {"bug",	HB_TAG('B','U','G',' ')},	/* Buginese */
   1.258 +  {"bxr",	HB_TAG('R','B','U',' ')},	/* Russian Buriat */
   1.259 +  {"byn",	HB_TAG('B','I','L',' ')},	/* Bilen */
   1.260 +  {"ca",	HB_TAG('C','A','T',' ')},	/* Catalan */
   1.261 +  {"cbk",	HB_TAG('C','B','K',' ')},	/* Chavacano */
   1.262 +  {"ce",	HB_TAG('C','H','E',' ')},	/* Chechen */
   1.263 +  {"ceb",	HB_TAG('C','E','B',' ')},	/* Cebuano */
   1.264 +  {"cgg",	HB_TAG('C','G','G',' ')},	/* Chiga */
   1.265 +  {"ch",	HB_TAG('C','H','A',' ')},	/* Chamorro */
   1.266 +  {"cho",	HB_TAG('C','H','O',' ')},	/* Choctaw */
   1.267 +  {"chp",	HB_TAG('C','H','P',' ')},	/* Chipewyan */
   1.268 +  {"chr",	HB_TAG('C','H','R',' ')},	/* Cherokee */
   1.269 +  {"chy",	HB_TAG('C','H','Y',' ')},	/* Cheyenne */
   1.270 +  {"ckb",	HB_TAG('K','U','R',' ')},	/* Central Kurdish (Sorani) */
   1.271 +  {"ckt",	HB_TAG('C','H','K',' ')},	/* Chukchi */
   1.272 +  {"cop",	HB_TAG('C','O','P',' ')},	/* Coptic */
   1.273 +  {"cr",	HB_TAG('C','R','E',' ')},	/* Cree */
   1.274 +  {"crh",	HB_TAG('C','R','T',' ')},	/* Crimean Tatar */
   1.275 +  {"crj",	HB_TAG('E','C','R',' ')},	/* [Southern] East Cree */
   1.276 +  {"crl",	HB_TAG('E','C','R',' ')},	/* [Northern] East Cree */
   1.277 +  {"crm",	HB_TAG('M','C','R',' ')},	/* Moose Cree */
   1.278 +  {"crx",	HB_TAG('C','R','R',' ')},	/* Carrier */
   1.279 +  {"cs",	HB_TAG('C','S','Y',' ')},	/* Czech */
   1.280 +  {"csb",	HB_TAG('C','S','B',' ')},	/* Kashubian */
   1.281 +  {"ctg",	HB_TAG('C','T','G',' ')},	/* Chittagonian */
   1.282 +  {"cts",	HB_TAG('B','I','K',' ')},	/* Northern Catanduanes Bikol */
   1.283 +  {"cu",	HB_TAG('C','S','L',' ')},	/* Church Slavic */
   1.284 +  {"cv",	HB_TAG('C','H','U',' ')},	/* Chuvash */
   1.285 +  {"cwd",	HB_TAG('D','C','R',' ')},	/* Woods Cree */
   1.286 +  {"cy",	HB_TAG('W','E','L',' ')},	/* Welsh */
   1.287 +  {"da",	HB_TAG('D','A','N',' ')},	/* Danish */
   1.288 +  {"dap",	HB_TAG('N','I','S',' ')},	/* Nisi (India) */
   1.289 +  {"dar",	HB_TAG('D','A','R',' ')},	/* Dargwa */
   1.290 +  {"de",	HB_TAG('D','E','U',' ')},	/* German */
   1.291 +  {"dgo",	HB_TAG('D','G','O',' ')},	/* Dogri */
   1.292 +  {"dhd",	HB_TAG('M','A','W',' ')},	/* Dhundari */
   1.293 +  {"din",	HB_TAG('D','N','K',' ')},	/* Dinka [macrolanguage] */
   1.294 +  {"diq",	HB_TAG('D','I','Q',' ')},	/* Dimli */
   1.295 +  {"dje",	HB_TAG('D','J','R',' ')},	/* Zarma */
   1.296 +  {"dng",	HB_TAG('D','U','N',' ')},	/* Dungan */
   1.297 +  {"doi",	HB_TAG('D','G','R',' ')},	/* Dogri [macrolanguage] */
   1.298 +  {"dsb",	HB_TAG('L','S','B',' ')},	/* Lower Sorbian */
   1.299 +  {"dv",	HB_TAG('D','I','V',' ')},	/* Dhivehi/Divehi/Maldivian */
   1.300 +  {"dyu",	HB_TAG('J','U','L',' ')},	/* Jula */
   1.301 +  {"dz",	HB_TAG('D','Z','N',' ')},	/* Dzongkha */
   1.302 +  {"ee",	HB_TAG('E','W','E',' ')},	/* Ewe */
   1.303 +  {"efi",	HB_TAG('E','F','I',' ')},	/* Efik */
   1.304 +  {"ekk",	HB_TAG('E','T','I',' ')},	/* Standard Estonian */
   1.305 +  {"el",	HB_TAG('E','L','L',' ')},	/* Modern Greek (1453-) */
   1.306 +  {"emk",	HB_TAG('M','N','K',' ')},	/* Eastern Maninkakan */
   1.307 +  {"en",	HB_TAG('E','N','G',' ')},	/* English */
   1.308 +  {"eo",	HB_TAG('N','T','O',' ')},	/* Esperanto */
   1.309 +  {"eot",	HB_TAG('B','T','I',' ')},	/* Beti (Côte d'Ivoire) */
   1.310 +  {"es",	HB_TAG('E','S','P',' ')},	/* Spanish */
   1.311 +  {"et",	HB_TAG('E','T','I',' ')},	/* Estonian [macrolanguage] */
   1.312 +  {"eu",	HB_TAG('E','U','Q',' ')},	/* Basque */
   1.313 +  {"eve",	HB_TAG('E','V','N',' ')},	/* Even */
   1.314 +  {"evn",	HB_TAG('E','V','K',' ')},	/* Evenki */
   1.315 +  {"fa",	HB_TAG('F','A','R',' ')},	/* Persian [macrolanguage] */
   1.316 +  {"ff",	HB_TAG('F','U','L',' ')},	/* Fulah [macrolanguage] */
   1.317 +  {"fi",	HB_TAG('F','I','N',' ')},	/* Finnish */
   1.318 +  {"fil",	HB_TAG('P','I','L',' ')},	/* Filipino */
   1.319 +  {"fj",	HB_TAG('F','J','I',' ')},	/* Fijian */
   1.320 +  {"fo",	HB_TAG('F','O','S',' ')},	/* Faroese */
   1.321 +  {"fon",	HB_TAG('F','O','N',' ')},	/* Fon */
   1.322 +  {"fr",	HB_TAG('F','R','A',' ')},	/* French */
   1.323 +  {"frc",	HB_TAG('F','R','C',' ')},	/* Cajun French */
   1.324 +  {"frp",	HB_TAG('F','R','P',' ')},	/* Arpitan/Francoprovençal */
   1.325 +  {"fur",	HB_TAG('F','R','L',' ')},	/* Friulian */
   1.326 +  {"fuv",	HB_TAG('F','U','V',' ')},	/* Nigerian Fulfulde */
   1.327 +  {"fy",	HB_TAG('F','R','I',' ')},	/* Western Frisian */
   1.328 +  {"ga",	HB_TAG('I','R','I',' ')},	/* Irish */
   1.329 +  {"gaa",	HB_TAG('G','A','D',' ')},	/* Ga */
   1.330 +  {"gag",	HB_TAG('G','A','G',' ')},	/* Gagauz */
   1.331 +  {"gbm",	HB_TAG('G','A','W',' ')},	/* Garhwali */
   1.332 +  {"gd",	HB_TAG('G','A','E',' ')},	/* Scottish Gaelic */
   1.333 +  {"gez",	HB_TAG('G','E','Z',' ')},	/* Ge'ez */
   1.334 +  {"ggo",	HB_TAG('G','O','N',' ')},	/* Southern Gondi */
   1.335 +  {"gl",	HB_TAG('G','A','L',' ')},	/* Galician */
   1.336 +  {"gld",	HB_TAG('N','A','N',' ')},	/* Nanai */
   1.337 +  {"glk",	HB_TAG('G','L','K',' ')},	/* Gilaki */
   1.338 +  {"gn",	HB_TAG('G','U','A',' ')},	/* Guarani [macrolanguage] */
   1.339 +  {"gno",	HB_TAG('G','O','N',' ')},	/* Northern Gondi */
   1.340 +  {"gog",	HB_TAG('G','O','G',' ')},	/* Gogo */
   1.341 +  {"gon",	HB_TAG('G','O','N',' ')},	/* Gondi [macrolanguage] */
   1.342 +  {"grt",	HB_TAG('G','R','O',' ')},	/* Garo */
   1.343 +  {"gru",	HB_TAG('S','O','G',' ')},	/* Sodo Gurage */
   1.344 +  {"gu",	HB_TAG('G','U','J',' ')},	/* Gujarati */
   1.345 +  {"guc",	HB_TAG('G','U','C',' ')},	/* Wayuu */
   1.346 +  {"guk",	HB_TAG('G','M','Z',' ')},	/* Gumuz */
   1.347 +/*{"guk",	HB_TAG('G','U','K',' ')},*/	/* Gumuz (in SIL fonts) */
   1.348 +  {"guz",	HB_TAG('G','U','Z',' ')},	/* Ekegusii/Gusii */
   1.349 +  {"gv",	HB_TAG('M','N','X',' ')},	/* Manx */
   1.350 +  {"ha",	HB_TAG('H','A','U',' ')},	/* Hausa */
   1.351 +  {"har",	HB_TAG('H','R','I',' ')},	/* Harari */
   1.352 +  {"haw",	HB_TAG('H','A','W',' ')},  	/* Hawaiian */
   1.353 +  {"hay",	HB_TAG('H','A','Y',' ')},  	/* Haya */
   1.354 +  {"haz",	HB_TAG('H','A','Z',' ')},  	/* Hazaragi */
   1.355 +  {"he",	HB_TAG('I','W','R',' ')},	/* Hebrew */
   1.356 +  {"hz",	HB_TAG('H','E','R',' ')},	/* Herero */
   1.357 +  {"hi",	HB_TAG('H','I','N',' ')},	/* Hindi */
   1.358 +  {"hil",	HB_TAG('H','I','L',' ')},	/* Hiligaynon */
   1.359 +  {"hnd",	HB_TAG('H','N','D',' ')},	/* [Southern] Hindko */
   1.360 +  {"hne",	HB_TAG('C','H','H',' ')},	/* Chattisgarhi */
   1.361 +  {"hno",	HB_TAG('H','N','D',' ')},	/* [Northern] Hindko */
   1.362 +  {"ho",	HB_TAG('H','M','O',' ')},	/* Hiri Motu */
   1.363 +  {"hoc",	HB_TAG('H','O',' ',' ')},	/* Ho */
   1.364 +  {"hoj",	HB_TAG('H','A','R',' ')},	/* Harauti */
   1.365 +  {"hr",	HB_TAG('H','R','V',' ')},	/* Croatian */
   1.366 +  {"hsb",	HB_TAG('U','S','B',' ')},	/* Upper Sorbian */
   1.367 +  {"ht",	HB_TAG('H','A','I',' ')},	/* Haitian/Haitian Creole */
   1.368 +  {"hu",	HB_TAG('H','U','N',' ')},	/* Hungarian */
   1.369 +  {"hy",	HB_TAG('H','Y','E',' ')},	/* Armenian */
   1.370 +  {"hz",	HB_TAG('H','E','R',' ')},	/* Herero */
   1.371 +  {"ia",	HB_TAG('I','N','A',' ')},	/* Interlingua (International Auxiliary Language Association) */
   1.372 +  {"ibb",	HB_TAG('I','B','B',' ')},	/* Ibibio */
   1.373 +  {"id",	HB_TAG('I','N','D',' ')},	/* Indonesian */
   1.374 +  {"ie",	HB_TAG('I','L','E',' ')},	/* Interlingue/Occidental */
   1.375 +  {"ig",	HB_TAG('I','B','O',' ')},	/* Igbo */
   1.376 +  {"igb",	HB_TAG('E','B','I',' ')},	/* Ebira */
   1.377 +  {"ijc",	HB_TAG('I','J','O',' ')},	/* Izon */
   1.378 +  {"ijo",	HB_TAG('I','J','O',' ')},	/* Ijo [family] */
   1.379 +  {"ik",	HB_TAG('I','P','K',' ')},	/* Inupiaq [macrolanguage] */
   1.380 +  {"ilo",	HB_TAG('I','L','O',' ')},	/* Ilokano */
   1.381 +  {"inh",	HB_TAG('I','N','G',' ')},	/* Ingush */
   1.382 +  {"io",	HB_TAG('I','D','O',' ')},	/* Ido */
   1.383 +  {"is",	HB_TAG('I','S','L',' ')},	/* Icelandic */
   1.384 +  {"it",	HB_TAG('I','T','A',' ')},	/* Italian */
   1.385 +  {"iu",	HB_TAG('I','N','U',' ')},	/* Inuktitut [macrolanguage] */
   1.386 +  {"ja",	HB_TAG('J','A','N',' ')},	/* Japanese */
   1.387 +  {"jam",	HB_TAG('J','A','M',' ')},	/* Jamaican Creole English */
   1.388 +  {"jbo",	HB_TAG('J','B','O',' ')},	/* Lojban */
   1.389 +  {"jv",	HB_TAG('J','A','V',' ')},	/* Javanese */
   1.390 +  {"ka",	HB_TAG('K','A','T',' ')},	/* Georgian */
   1.391 +  {"kaa",	HB_TAG('K','R','K',' ')},	/* Karakalpak */
   1.392 +  {"kab",	HB_TAG('K','A','B',' ')},	/* Kabyle */
   1.393 +  {"kam",	HB_TAG('K','M','B',' ')},	/* Kamba (Kenya) */
   1.394 +  {"kar",	HB_TAG('K','R','N',' ')},	/* Karen [family] */
   1.395 +  {"kbd",	HB_TAG('K','A','B',' ')},	/* Kabardian */
   1.396 +  {"kde",	HB_TAG('K','D','E',' ')},	/* Makonde */
   1.397 +  {"kdr",	HB_TAG('K','R','M',' ')},	/* Karaim */
   1.398 +  {"kdt",	HB_TAG('K','U','Y',' ')},	/* Kuy */
   1.399 +  {"kex",	HB_TAG('K','K','N',' ')},	/* Kokni */
   1.400 +  {"kfr",	HB_TAG('K','A','C',' ')},	/* Kachchi */
   1.401 +  {"kfy",	HB_TAG('K','M','N',' ')},	/* Kumaoni */
   1.402 +  {"kg",	HB_TAG('K','O','N',' ')},	/* Kongo [macrolanguage] */
   1.403 +  {"kha",	HB_TAG('K','S','I',' ')},	/* Khasi */
   1.404 +  {"khb",	HB_TAG('X','B','D',' ')},	/* Lü */
   1.405 +  {"kht",	HB_TAG('K','H','N',' ')},	/* Khamti (Microsoft fonts) */
   1.406 +/*{"kht",	HB_TAG('K','H','T',' ')},*/	/* Khamti (OpenType spec and SIL fonts) */
   1.407 +  {"khw",	HB_TAG('K','H','W',' ')},	/* Khowar */
   1.408 +  {"ki",	HB_TAG('K','I','K',' ')},	/* Gikuyu/Kikuyu */
   1.409 +  {"kj",	HB_TAG('K','U','A',' ')},	/* Kuanyama/Kwanyama */
   1.410 +  {"kjh",	HB_TAG('K','H','A',' ')},	/* Khakass */
   1.411 +  {"kjp",	HB_TAG('K','J','P',' ')},	/* Pwo Eastern Karen */
   1.412 +  {"kk",	HB_TAG('K','A','Z',' ')},	/* Kazakh */
   1.413 +  {"kl",	HB_TAG('G','R','N',' ')},	/* Kalaallisut */
   1.414 +  {"kln",	HB_TAG('K','A','L',' ')},	/* Kalenjin */
   1.415 +  {"km",	HB_TAG('K','H','M',' ')},	/* Central Khmer */
   1.416 +  {"kmb",	HB_TAG('M','B','N',' ')},	/* Kimbundu */
   1.417 +  {"kmw",	HB_TAG('K','M','O',' ')},	/* Komo (Democratic Republic of Congo) */
   1.418 +  {"kn",	HB_TAG('K','A','N',' ')},	/* Kannada */
   1.419 +  {"knn",	HB_TAG('K','O','K',' ')},	/* Konkani */
   1.420 +  {"ko",	HB_TAG('K','O','R',' ')},	/* Korean */
   1.421 +  {"koi",	HB_TAG('K','O','P',' ')},	/* Komi-Permyak */
   1.422 +  {"kok",	HB_TAG('K','O','K',' ')},	/* Konkani [macrolanguage] */
   1.423 +  {"kpe",	HB_TAG('K','P','L',' ')},	/* Kpelle [macrolanguage] */
   1.424 +  {"kpv",	HB_TAG('K','O','Z',' ')},	/* Komi-Zyrian */
   1.425 +  {"kpy",	HB_TAG('K','Y','K',' ')},	/* Koryak */
   1.426 +  {"kqy",	HB_TAG('K','R','T',' ')},	/* Koorete */
   1.427 +  {"kr",	HB_TAG('K','N','R',' ')},	/* Kanuri [macrolanguage] */
   1.428 +  {"kri",	HB_TAG('K','R','I',' ')},	/* Krio */
   1.429 +  {"krl",	HB_TAG('K','R','L',' ')},	/* Karelian */
   1.430 +  {"kru",	HB_TAG('K','U','U',' ')},	/* Kurukh */
   1.431 +  {"ks",	HB_TAG('K','S','H',' ')},	/* Kashmiri */
   1.432 +  {"ksh",	HB_TAG('K','S','H',' ')},	/* Kölsch */
   1.433 +/*{"ksw",	HB_TAG('K','R','N',' ')},*/	/* S'gaw Karen (Microsoft fonts?) */
   1.434 +  {"ksw",	HB_TAG('K','S','W',' ')},	/* S'gaw Karen (OpenType spec and SIL fonts) */
   1.435 +  {"ku",	HB_TAG('K','U','R',' ')},	/* Kurdish [macrolanguage] */
   1.436 +  {"kum",	HB_TAG('K','U','M',' ')},	/* Kumyk */
   1.437 +  {"kv",	HB_TAG('K','O','M',' ')},	/* Komi [macrolanguage] */
   1.438 +  {"kvd",	HB_TAG('K','U','I',' ')},	/* Kui (Indonesia) */
   1.439 +  {"kw",	HB_TAG('C','O','R',' ')},	/* Cornish */
   1.440 +  {"kxc",	HB_TAG('K','M','S',' ')},	/* Komso */
   1.441 +  {"kxu",	HB_TAG('K','U','I',' ')},	/* Kui (India) */
   1.442 +  {"ky",	HB_TAG('K','I','R',' ')},	/* Kirghiz/Kyrgyz */
   1.443 +  {"kyu",	HB_TAG('K','Y','U',' ')},	/* Western Kayah */
   1.444 +  {"la",	HB_TAG('L','A','T',' ')},	/* Latin */
   1.445 +  {"lad",	HB_TAG('J','U','D',' ')},	/* Ladino */
   1.446 +  {"lb",	HB_TAG('L','T','Z',' ')},	/* Luxembourgish */
   1.447 +  {"lbe",	HB_TAG('L','A','K',' ')},	/* Lak */
   1.448 +  {"lbj",	HB_TAG('L','D','K',' ')},	/* Ladakhi */
   1.449 +  {"lez",	HB_TAG('L','E','Z',' ')},	/* Lezgi */
   1.450 +  {"lg",	HB_TAG('L','U','G',' ')},	/* Ganda */
   1.451 +  {"li",	HB_TAG('L','I','M',' ')},	/* Limburgan/Limburger/Limburgish */
   1.452 +  {"lif",	HB_TAG('L','M','B',' ')},	/* Limbu */
   1.453 +  {"lij",	HB_TAG('L','I','J',' ')},	/* Ligurian */
   1.454 +  {"lis",	HB_TAG('L','I','S',' ')},	/* Lisu */
   1.455 +  {"ljp",	HB_TAG('L','J','P',' ')},	/* Lampung Api */
   1.456 +  {"lki",	HB_TAG('L','K','I',' ')},	/* Laki */
   1.457 +  {"lld",	HB_TAG('L','A','D',' ')},	/* Ladin */
   1.458 +  {"lmn",	HB_TAG('L','A','M',' ')},	/* Lambani */
   1.459 +  {"lmo",	HB_TAG('L','M','O',' ')},	/* Lombard */
   1.460 +  {"ln",	HB_TAG('L','I','N',' ')},	/* Lingala */
   1.461 +  {"lo",	HB_TAG('L','A','O',' ')},	/* Lao */
   1.462 +  {"lrc",	HB_TAG('L','R','C',' ')},	/* Northern Luri */
   1.463 +  {"lt",	HB_TAG('L','T','H',' ')},	/* Lithuanian */
   1.464 +  {"lu",	HB_TAG('L','U','B',' ')},	/* Luba-Katanga */
   1.465 +  {"lua",	HB_TAG('L','U','B',' ')},	/* Luba-Kasai */
   1.466 +  {"luo",	HB_TAG('L','U','O',' ')},	/* Luo (Kenya and Tanzania) */
   1.467 +  {"lus",	HB_TAG('M','I','Z',' ')},	/* Mizo */
   1.468 +  {"luy",	HB_TAG('L','U','H',' ')},	/* Luyia/Oluluyia [macrolanguage] */
   1.469 +  {"luz",	HB_TAG('L','R','C',' ')},	/* Southern Luri */
   1.470 +  {"lv",	HB_TAG('L','V','I',' ')},	/* Latvian */
   1.471 +  {"lzz",	HB_TAG('L','A','Z',' ')},	/* Laz */
   1.472 +  {"mad",	HB_TAG('M','A','D',' ')},	/* Madurese */
   1.473 +  {"mag",	HB_TAG('M','A','G',' ')},	/* Magahi */
   1.474 +  {"mai",	HB_TAG('M','T','H',' ')},	/* Maithili */
   1.475 +  {"mak",	HB_TAG('M','K','R',' ')},	/* Makasar */
   1.476 +  {"man",	HB_TAG('M','N','K',' ')},	/* Manding/Mandingo [macrolanguage] */
   1.477 +  {"mdc",	HB_TAG('M','L','E',' ')},	/* Male (Papua New Guinea) */
   1.478 +  {"mdf",	HB_TAG('M','O','K',' ')},	/* Moksha */
   1.479 +  {"mdr",	HB_TAG('M','D','R',' ')},	/* Mandar */
   1.480 +  {"mdy",	HB_TAG('M','L','E',' ')},	/* Male (Ethiopia) */
   1.481 +  {"men",	HB_TAG('M','D','E',' ')},	/* Mende (Sierra Leone) */
   1.482 +  {"mer",	HB_TAG('M','E','R',' ')},	/* Meru */
   1.483 +  {"mfe",	HB_TAG('M','F','E',' ')},	/* Morisyen */
   1.484 +  {"mg",	HB_TAG('M','L','G',' ')},	/* Malagasy [macrolanguage] */
   1.485 +  {"mh",	HB_TAG('M','A','H',' ')},	/* Marshallese */
   1.486 +  {"mhr",	HB_TAG('L','M','A',' ')},	/* Low Mari */
   1.487 +  {"mi",	HB_TAG('M','R','I',' ')},	/* Maori */
   1.488 +  {"min",	HB_TAG('M','I','N',' ')},	/* Minangkabau */
   1.489 +  {"mk",	HB_TAG('M','K','D',' ')},	/* Macedonian */
   1.490 +  {"mku",	HB_TAG('M','N','K',' ')},	/* Konyanka Maninka */
   1.491 +  {"mkw",	HB_TAG('M','K','W',' ')},	/* Kituba (Congo) */
   1.492 +  {"ml",	HB_TAG('M','L','R',' ')},	/* Malayalam */
   1.493 +  {"mlq",	HB_TAG('M','N','K',' ')},	/* Western Maninkakan */
   1.494 +  {"mn",	HB_TAG('M','N','G',' ')},	/* Mongolian [macrolanguage] */
   1.495 +  {"mnc",	HB_TAG('M','C','H',' ')},	/* Manchu */
   1.496 +  {"mni",	HB_TAG('M','N','I',' ')},	/* Manipuri */
   1.497 +  {"mnk",	HB_TAG('M','N','D',' ')},	/* Mandinka */
   1.498 +  {"mns",	HB_TAG('M','A','N',' ')},	/* Mansi */
   1.499 +  {"mnw",	HB_TAG('M','O','N',' ')},	/* Mon */
   1.500 +  {"mo",	HB_TAG('M','O','L',' ')},	/* Moldavian */
   1.501 +  {"moh",	HB_TAG('M','O','H',' ')},	/* Mohawk */
   1.502 +  {"mos",	HB_TAG('M','O','S',' ')},	/* Mossi */
   1.503 +  {"mpe",	HB_TAG('M','A','J',' ')},	/* Majang */
   1.504 +  {"mr",	HB_TAG('M','A','R',' ')},	/* Marathi */
   1.505 +  {"mrj",	HB_TAG('H','M','A',' ')},	/* High Mari */
   1.506 +  {"ms",	HB_TAG('M','L','Y',' ')},	/* Malay [macrolanguage] */
   1.507 +  {"msc",	HB_TAG('M','N','K',' ')},	/* Sankaran Maninka */
   1.508 +  {"mt",	HB_TAG('M','T','S',' ')},	/* Maltese */
   1.509 +  {"mtr",	HB_TAG('M','A','W',' ')},	/* Mewari */
   1.510 +  {"mus",	HB_TAG('M','U','S',' ')},	/* Creek */
   1.511 +  {"mve",	HB_TAG('M','A','W',' ')},	/* Marwari (Pakistan) */
   1.512 +  {"mwk",	HB_TAG('M','N','K',' ')},	/* Kita Maninkakan */
   1.513 +  {"mwl",	HB_TAG('M','W','L',' ')},	/* Mirandese */
   1.514 +  {"mwr",	HB_TAG('M','A','W',' ')},	/* Marwari [macrolanguage] */
   1.515 +  {"mww",	HB_TAG('M','W','W',' ')},	/* Hmong Daw */
   1.516 +  {"my",	HB_TAG('B','R','M',' ')},	/* Burmese */
   1.517 +  {"mym",	HB_TAG('M','E','N',' ')},	/* Me'en */
   1.518 +  {"myq",	HB_TAG('M','N','K',' ')},	/* Forest Maninka (retired code) */
   1.519 +  {"myv",	HB_TAG('E','R','Z',' ')},	/* Erzya */
   1.520 +  {"mzn",	HB_TAG('M','Z','N',' ')},	/* Mazanderani */
   1.521 +  {"na",	HB_TAG('N','A','U',' ')},	/* Nauru */
   1.522 +  {"nag",	HB_TAG('N','A','G',' ')},	/* Naga-Assamese */
   1.523 +  {"nah",	HB_TAG('N','A','H',' ')},	/* Nahuatl [family] */
   1.524 +  {"nap",	HB_TAG('N','A','P',' ')},	/* Neapolitan */
   1.525 +  {"nb",	HB_TAG('N','O','R',' ')},	/* Norwegian Bokmål */
   1.526 +  {"nco",	HB_TAG('S','I','B',' ')},	/* Sibe */
   1.527 +  {"nd",	HB_TAG('N','D','B',' ')},	/* [North] Ndebele */
   1.528 +  {"ndc",	HB_TAG('N','D','C',' ')},	/* Ndau */
   1.529 +  {"nds",	HB_TAG('N','D','S',' ')},	/* Low German/Low Saxon */
   1.530 +  {"ne",	HB_TAG('N','E','P',' ')},	/* Nepali */
   1.531 +  {"new",	HB_TAG('N','E','W',' ')},	/* Newari */
   1.532 +  {"ng",	HB_TAG('N','D','G',' ')},	/* Ndonga */
   1.533 +  {"nga",	HB_TAG('N','G','A',' ')},	/* Ngabaka */
   1.534 +  {"ngl",	HB_TAG('L','M','W',' ')},	/* Lomwe */
   1.535 +  {"niu",	HB_TAG('N','I','U',' ')},	/* Niuean */
   1.536 +  {"niv",	HB_TAG('G','I','L',' ')},	/* Gilyak */
   1.537 +  {"nl",	HB_TAG('N','L','D',' ')},	/* Dutch */
   1.538 +  {"nn",	HB_TAG('N','Y','N',' ')},	/* Norwegian Nynorsk */
   1.539 +  {"no",	HB_TAG('N','O','R',' ')},	/* Norwegian [macrolanguage] */
   1.540 +  {"nod",	HB_TAG('N','T','A',' ')},	/* Northern Thai */
   1.541 +  {"noe",	HB_TAG('N','O','E',' ')},	/* Nimadi */
   1.542 +  {"nog",	HB_TAG('N','O','G',' ')},	/* Nogai */
   1.543 +  {"nov",	HB_TAG('N','O','V',' ')},	/* Novial */
   1.544 +  {"nqo",	HB_TAG('N','K','O',' ')},	/* N'Ko */
   1.545 +  {"nr",	HB_TAG('N','D','B',' ')},	/* [South] Ndebele */
   1.546 +  {"nsk",	HB_TAG('N','A','S',' ')},	/* Naskapi */
   1.547 +  {"nso",	HB_TAG('S','O','T',' ')},	/* [Northern] Sotho */
   1.548 +  {"ny",	HB_TAG('C','H','I',' ')},	/* Chewa/Chichwa/Nyanja */
   1.549 +  {"nym",	HB_TAG('N','Y','M',' ')},	/* Nyamwezi */
   1.550 +  {"nyn",	HB_TAG('N','K','L',' ')},	/* Nyankole */
   1.551 +  {"oc",	HB_TAG('O','C','I',' ')},	/* Occitan (post 1500) */
   1.552 +  {"oj",	HB_TAG('O','J','B',' ')},	/* Ojibwa [macrolanguage] */
   1.553 +  {"ojs",	HB_TAG('O','C','R',' ')},	/* Oji-Cree */
   1.554 +  {"om",	HB_TAG('O','R','O',' ')},	/* Oromo [macrolanguage] */
   1.555 +  {"or",	HB_TAG('O','R','I',' ')},	/* Oriya */
   1.556 +  {"os",	HB_TAG('O','S','S',' ')},	/* Ossetian */
   1.557 +  {"pa",	HB_TAG('P','A','N',' ')},	/* Panjabi */
   1.558 +  {"pag",	HB_TAG('P','A','G',' ')},	/* Pangasinan */
   1.559 +  {"pam",	HB_TAG('P','A','M',' ')},	/* Kapampangan/Pampanga */
   1.560 +  {"pap",	HB_TAG('P','A','P',' ')},	/* Papiamento */
   1.561 +  {"pcc",	HB_TAG('P','C','C',' ')},	/* Bouyei */
   1.562 +  {"pcd",	HB_TAG('P','C','D',' ')},	/* Picard */
   1.563 +  {"pce",	HB_TAG('P','L','G',' ')},	/* [Ruching] Palaung */
   1.564 +  {"pdc",	HB_TAG('P','D','C',' ')},	/* Pennsylvania German */
   1.565 +  {"pes",	HB_TAG('F','A','R',' ')},	/* Iranian Persian */
   1.566 +  {"phk",	HB_TAG('P','H','K',' ')},	/* Phake */
   1.567 +  {"pi",	HB_TAG('P','A','L',' ')},	/* Pali */
   1.568 +  {"pih",	HB_TAG('P','I','H',' ')},	/* Pitcairn-Norfolk */
   1.569 +  {"pl",	HB_TAG('P','L','K',' ')},	/* Polish */
   1.570 +  {"pll",	HB_TAG('P','L','G',' ')},	/* [Shwe] Palaung */
   1.571 +  {"plp",	HB_TAG('P','A','P',' ')},	/* Palpa */
   1.572 +  {"pms",	HB_TAG('P','M','S',' ')},	/* Piemontese */
   1.573 +  {"pnb",	HB_TAG('P','N','B',' ')},	/* Western Panjabi */
   1.574 +  {"prs",	HB_TAG('D','R','I',' ')},	/* Afghan Persian/Dari */
   1.575 +  {"ps",	HB_TAG('P','A','S',' ')},	/* Pashto/Pushto [macrolanguage] */
   1.576 +  {"pt",	HB_TAG('P','T','G',' ')},	/* Portuguese */
   1.577 +  {"pwo",	HB_TAG('P','W','O',' ')},	/* Pwo Western Karen */
   1.578 +  {"qu",	HB_TAG('Q','U','Z',' ')},	/* Quechua [macrolanguage] */
   1.579 +  {"quc",	HB_TAG('Q','U','C',' ')},	/* K'iche'/Quiché */
   1.580 +  {"quz",	HB_TAG('Q','U','Z',' ')},	/* Cusco Quechua */
   1.581 +  {"raj",	HB_TAG('R','A','J',' ')},	/* Rajasthani [macrolanguage] */
   1.582 +  {"rbb",	HB_TAG('P','L','G',' ')},	/* Rumai Palaung */
   1.583 +  {"rej",	HB_TAG('R','E','J',' ')},	/* Rejang */
   1.584 +  {"ria",	HB_TAG('R','I','A',' ')},	/* Riang (India) */
   1.585 +  {"ril",	HB_TAG('R','I','A',' ')},	/* Riang (Myanmar) */
   1.586 +  {"rki",	HB_TAG('A','R','K',' ')},	/* Rakhine */
   1.587 +  {"rm",	HB_TAG('R','M','S',' ')},	/* Romansh */
   1.588 +  {"rmy",	HB_TAG('R','M','Y',' ')},	/* Vlax Romani */
   1.589 +  {"rn",	HB_TAG('R','U','N',' ')},	/* Rundi */
   1.590 +  {"ro",	HB_TAG('R','O','M',' ')},	/* Romanian */
   1.591 +  {"rom",	HB_TAG('R','O','Y',' ')},	/* Romany [macrolanguage] */
   1.592 +  {"ru",	HB_TAG('R','U','S',' ')},	/* Russian */
   1.593 +  {"rue",	HB_TAG('R','S','Y',' ')},	/* Rusyn */
   1.594 +  {"rup",	HB_TAG('R','U','P',' ')},	/* Aromanian/Arumanian/Macedo-Romanian */
   1.595 +  {"rw",	HB_TAG('R','U','A',' ')},	/* Kinyarwanda */
   1.596 +  {"rwr",	HB_TAG('M','A','W',' ')},	/* Marwari (India) */
   1.597 +  {"sa",	HB_TAG('S','A','N',' ')},	/* Sanskrit */
   1.598 +  {"sah",	HB_TAG('Y','A','K',' ')},	/* Yakut */
   1.599 +  {"sas",	HB_TAG('S','A','S',' ')},	/* Sasak */
   1.600 +  {"sat",	HB_TAG('S','A','T',' ')},	/* Santali */
   1.601 +  {"sck",	HB_TAG('S','A','D',' ')},	/* Sadri */
   1.602 +  {"sc",	HB_TAG('S','R','D',' ')},	/* Sardinian [macrolanguage] */
   1.603 +  {"scn",	HB_TAG('S','C','N',' ')},	/* Sicilian */
   1.604 +  {"sco",	HB_TAG('S','C','O',' ')},	/* Scots */
   1.605 +  {"scs",	HB_TAG('S','L','A',' ')},	/* [North] Slavey */
   1.606 +  {"sd",	HB_TAG('S','N','D',' ')},	/* Sindhi */
   1.607 +  {"se",	HB_TAG('N','S','M',' ')},	/* Northern Sami */
   1.608 +  {"seh",	HB_TAG('S','N','A',' ')},	/* Sena */
   1.609 +  {"sel",	HB_TAG('S','E','L',' ')},	/* Selkup */
   1.610 +  {"sg",	HB_TAG('S','G','O',' ')},	/* Sango */
   1.611 +  {"sga",	HB_TAG('S','G','A',' ')},	/* Old Irish (to 900) */
   1.612 +  {"sgs",	HB_TAG('S','G','S',' ')},	/* Samogitian */
   1.613 +  {"sgw",	HB_TAG('C','H','G',' ')},	/* Sebat Bet Gurage */
   1.614 +/*{"sgw",	HB_TAG('S','G','W',' ')},*/	/* Sebat Bet Gurage (in SIL fonts) */
   1.615 +  {"shn",	HB_TAG('S','H','N',' ')},	/* Shan */
   1.616 +  {"si",	HB_TAG('S','N','H',' ')},	/* Sinhala */
   1.617 +  {"sid",	HB_TAG('S','I','D',' ')},	/* Sidamo */
   1.618 +  {"sjd",	HB_TAG('K','S','M',' ')},	/* Kildin Sami */
   1.619 +  {"sk",	HB_TAG('S','K','Y',' ')},	/* Slovak */
   1.620 +  {"skr",	HB_TAG('S','R','K',' ')},	/* Seraiki */
   1.621 +  {"sl",	HB_TAG('S','L','V',' ')},	/* Slovenian */
   1.622 +  {"sm",	HB_TAG('S','M','O',' ')},	/* Samoan */
   1.623 +  {"sma",	HB_TAG('S','S','M',' ')},	/* Southern Sami */
   1.624 +  {"smj",	HB_TAG('L','S','M',' ')},	/* Lule Sami */
   1.625 +  {"smn",	HB_TAG('I','S','M',' ')},	/* Inari Sami */
   1.626 +  {"sms",	HB_TAG('S','K','S',' ')},	/* Skolt Sami */
   1.627 +  {"sn",	HB_TAG('S','N','A',' ')},	/* Shona */
   1.628 +  {"snk",	HB_TAG('S','N','K',' ')},	/* Soninke */
   1.629 +  {"so",	HB_TAG('S','M','L',' ')},	/* Somali */
   1.630 +  {"sop",	HB_TAG('S','O','P',' ')},	/* Songe */
   1.631 +  {"sq",	HB_TAG('S','Q','I',' ')},	/* Albanian [macrolanguage] */
   1.632 +  {"sr",	HB_TAG('S','R','B',' ')},	/* Serbian */
   1.633 +  {"srr",	HB_TAG('S','R','R',' ')},	/* Serer */
   1.634 +  {"ss",	HB_TAG('S','W','Z',' ')},	/* Swati */
   1.635 +  {"st",	HB_TAG('S','O','T',' ')},	/* [Southern] Sotho */
   1.636 +  {"stq",	HB_TAG('S','T','Q',' ')},	/* Saterfriesisch */
   1.637 +  {"stv",	HB_TAG('S','I','G',' ')},	/* Silt'e */
   1.638 +  {"su",	HB_TAG('S','U','N',' ')},	/* Sundanese */
   1.639 +  {"suk",	HB_TAG('S','U','K',' ')},	/* Sukama */
   1.640 +  {"suq",	HB_TAG('S','U','R',' ')},	/* Suri */
   1.641 +  {"sv",	HB_TAG('S','V','E',' ')},	/* Swedish */
   1.642 +  {"sva",	HB_TAG('S','V','A',' ')},	/* Svan */
   1.643 +  {"sw",	HB_TAG('S','W','K',' ')},	/* Swahili [macrolanguage] */
   1.644 +  {"swb",	HB_TAG('C','M','R',' ')},	/* Comorian */
   1.645 +  {"swh",	HB_TAG('S','W','K',' ')},	/* Kiswahili/Swahili */
   1.646 +  {"swv",	HB_TAG('M','A','W',' ')},	/* Shekhawati */
   1.647 +  {"sxu",	HB_TAG('S','X','U',' ')},	/* Upper Saxon */
   1.648 +  {"syl",	HB_TAG('S','Y','L',' ')},	/* Sylheti */
   1.649 +  {"syr",	HB_TAG('S','Y','R',' ')},	/* Syriac [macrolanguage] */
   1.650 +  {"szl",	HB_TAG('S','Z','L',' ')},	/* Silesian */
   1.651 +  {"ta",	HB_TAG('T','A','M',' ')},	/* Tamil */
   1.652 +  {"tab",	HB_TAG('T','A','B',' ')},	/* Tabasaran */
   1.653 +  {"tcy",	HB_TAG('T','U','L',' ')},	/* Tulu */
   1.654 +  {"tdd",	HB_TAG('T','D','D',' ')},	/* Tai Nüa */
   1.655 +  {"te",	HB_TAG('T','E','L',' ')},	/* Telugu */
   1.656 +  {"tem",	HB_TAG('T','M','N',' ')},	/* Temne */
   1.657 +  {"tet",	HB_TAG('T','E','T',' ')},	/* Tetum */
   1.658 +  {"tg",	HB_TAG('T','A','J',' ')},	/* Tajik */
   1.659 +  {"th",	HB_TAG('T','H','A',' ')},	/* Thai */
   1.660 +  {"ti",	HB_TAG('T','G','Y',' ')},	/* Tigrinya */
   1.661 +  {"tig",	HB_TAG('T','G','R',' ')},	/* Tigre */
   1.662 +  {"tiv",	HB_TAG('T','I','V',' ')},	/* Tiv */
   1.663 +  {"tk",	HB_TAG('T','K','M',' ')},	/* Turkmen */
   1.664 +  {"tl",	HB_TAG('T','G','L',' ')},	/* Tagalog */
   1.665 +  {"tmh",	HB_TAG('t','m','h',' ')},	/* Tamashek [macrolanguage] */
   1.666 +  {"tn",	HB_TAG('T','N','A',' ')},	/* Tswana */
   1.667 +  {"to",	HB_TAG('T','G','N',' ')},	/* Tonga (Tonga Islands) */
   1.668 +  {"tpi",	HB_TAG('T','P','I',' ')},	/* Tok Pisin */
   1.669 +  {"tr",	HB_TAG('T','R','K',' ')},	/* Turkish */
   1.670 +  {"tru",	HB_TAG('T','U','A',' ')},	/* Turoyo Aramaic */
   1.671 +  {"ts",	HB_TAG('T','S','G',' ')},	/* Tsonga */
   1.672 +  {"tt",	HB_TAG('T','A','T',' ')},	/* Tatar */
   1.673 +  {"tum",	HB_TAG('T','U','M',' ')},	/* Tumbuka */
   1.674 +  {"tw",	HB_TAG('T','W','I',' ')},	/* Twi */
   1.675 +  {"ty",	HB_TAG('T','H','T',' ')},	/* Tahitian */
   1.676 +  {"tyv",	HB_TAG('T','U','V',' ')},	/* Tuvin */
   1.677 +  {"tyz",	HB_TAG('T','Y','Z',' ')},	/* Tày */
   1.678 +  {"tzm",	HB_TAG('T','Z','M',' ')},	/* Central Atlas Tamazight */
   1.679 +  {"udm",	HB_TAG('U','D','M',' ')},	/* Udmurt */
   1.680 +  {"ug",	HB_TAG('U','Y','G',' ')},	/* Uighur */
   1.681 +  {"uk",	HB_TAG('U','K','R',' ')},	/* Ukrainian */
   1.682 +  {"umb",	HB_TAG('U','M','B',' ')},	/* Umbundu */
   1.683 +  {"unr",	HB_TAG('M','U','N',' ')},	/* Mundari */
   1.684 +  {"ur",	HB_TAG('U','R','D',' ')},	/* Urdu */
   1.685 +  {"uz",	HB_TAG('U','Z','B',' ')},	/* Uzbek [macrolanguage] */
   1.686 +  {"uzn",	HB_TAG('U','Z','B',' ')},	/* Northern Uzbek */
   1.687 +  {"uzs",	HB_TAG('U','Z','B',' ')},	/* Southern Uzbek */
   1.688 +  {"ve",	HB_TAG('V','E','N',' ')},	/* Venda */
   1.689 +  {"vec",	HB_TAG('V','E','C',' ')},	/* Venetian */
   1.690 +  {"vls",	HB_TAG('F','L','E',' ')},	/* Vlaams */
   1.691 +  {"vi",	HB_TAG('V','I','T',' ')},	/* Vietnamese */
   1.692 +  {"vmw",	HB_TAG('M','A','K',' ')},	/* Makhuwa */
   1.693 +  {"vo",	HB_TAG('V','O','L',' ')},	/* Volapük */
   1.694 +  {"vro",	HB_TAG('V','R','O',' ')},	/* Võro */
   1.695 +  {"wa",	HB_TAG('W','L','N',' ')},	/* Walloon */
   1.696 +  {"war",	HB_TAG('W','A','R',' ')},	/* Waray (Philippines) */
   1.697 +  {"wbm",	HB_TAG('W','A',' ',' ')},	/* Wa */
   1.698 +  {"wbr",	HB_TAG('W','A','G',' ')},	/* Wagdi */
   1.699 +  {"wle",	HB_TAG('S','I','G',' ')},	/* Wolane */
   1.700 +  {"wry",	HB_TAG('M','A','W',' ')},	/* Merwari */
   1.701 +  {"wtm",	HB_TAG('W','T','M',' ')},	/* Mewati */
   1.702 +  {"wo",	HB_TAG('W','L','F',' ')},	/* Wolof */
   1.703 +  {"xal",	HB_TAG('K','L','M',' ')},	/* Kalmyk */
   1.704 +  {"xh",	HB_TAG('X','H','S',' ')},	/* Xhosa */
   1.705 +  {"xog",	HB_TAG('X','O','G',' ')},	/* Soga */
   1.706 +  {"xom",	HB_TAG('K','M','O',' ')},	/* Komo (Sudan) */
   1.707 +  {"xsl",	HB_TAG('S','S','L',' ')},	/* South Slavey */
   1.708 +  {"xst",	HB_TAG('S','I','G',' ')},	/* Silt'e (retired code) */
   1.709 +  {"xwo",	HB_TAG('T','O','D',' ')},	/* Written Oirat (Todo) */
   1.710 +  {"yao",	HB_TAG('Y','A','O',' ')},	/* Yao */
   1.711 +  {"yi",	HB_TAG('J','I','I',' ')},	/* Yiddish [macrolanguage] */
   1.712 +  {"yo",	HB_TAG('Y','B','A',' ')},	/* Yoruba */
   1.713 +  {"yso",	HB_TAG('N','I','S',' ')},	/* Nisi (China) */
   1.714 +  {"za",	HB_TAG('Z','H','A',' ')},	/* Chuang/Zhuang [macrolanguage] */
   1.715 +  {"zea",	HB_TAG('Z','E','A',' ')},	/* Zeeuws */
   1.716 +  {"zne",	HB_TAG('Z','N','D',' ')},	/* Zande */
   1.717 +  {"zu",	HB_TAG('Z','U','L',' ')}, 	/* Zulu */
   1.718 +  {"zum",	HB_TAG('L','R','C',' ')}	/* Kumzari */
   1.719 +
   1.720 +  /* The corresponding languages IDs for the following IDs are unclear,
   1.721 +   * overlap, or are architecturally weird. Needs more research. */
   1.722 +
   1.723 +/*{"ahg/awn/xan?",	HB_TAG('A','G','W',' ')},*/	/* Agaw */
   1.724 +/*{"gsw?/gsw-FR?",	HB_TAG('A','L','S',' ')},*/	/* Alsatian */
   1.725 +/*{"krc",	HB_TAG('B','A','L',' ')},*/	/* Balkar */
   1.726 +/*{"??",	HB_TAG('B','C','R',' ')},*/	/* Bible Cree */
   1.727 +/*{"zh?",	HB_TAG('C','H','N',' ')},*/	/* Chinese (seen in Microsoft fonts) */
   1.728 +/*{"acf/gcf?",	HB_TAG('F','A','N',' ')},*/	/* French Antillean */
   1.729 +/*{"enf?/yrk?",	HB_TAG('F','N','E',' ')},*/	/* Forest Nenets */
   1.730 +/*{"fuf?",	HB_TAG('F','T','A',' ')},*/	/* Futa */
   1.731 +/*{"ar-Syrc?",	HB_TAG('G','A','R',' ')},*/	/* Garshuni */
   1.732 +/*{"cfm/rnl?",	HB_TAG('H','A','L',' ')},*/	/* Halam */
   1.733 +/*{"fonipa",	HB_TAG('I','P','P','H')},*/	/* Phonetic transcription—IPA conventions */
   1.734 +/*{"ga-Latg?/Latg?",	HB_TAG('I','R','T',' ')},*/	/* Irish Traditional */
   1.735 +/*{"krc",	HB_TAG('K','A','R',' ')},*/	/* Karachay */
   1.736 +/*{"alw?/ktb?",	HB_TAG('K','E','B',' ')},*/	/* Kebena */
   1.737 +/*{"Geok",	HB_TAG('K','G','E',' ')},*/	/* Khutsuri Georgian */
   1.738 +/*{"kca",	HB_TAG('K','H','K',' ')},*/	/* Khanty-Kazim */
   1.739 +/*{"kca",	HB_TAG('K','H','S',' ')},*/	/* Khanty-Shurishkar */
   1.740 +/*{"kca",	HB_TAG('K','H','V',' ')},*/	/* Khanty-Vakhi */
   1.741 +/*{"guz?/kqs?/kss?",	HB_TAG('K','I','S',' ')},*/	/* Kisii */
   1.742 +/*{"kfa/kfi?/kpb?/xua?/xuj?",	HB_TAG('K','O','D',' ')},*/	/* Kodagu */
   1.743 +/*{"okm?/oko?",	HB_TAG('K','O','H',' ')},*/	/* Korean Old Hangul */
   1.744 +/*{"kon?/ktu?/...",	HB_TAG('K','O','N',' ')},*/	/* Kikongo */
   1.745 +/*{"kfx?",	HB_TAG('K','U','L',' ')},*/	/* Kulvi */
   1.746 +/*{"??",	HB_TAG('L','A','H',' ')},*/	/* Lahuli */
   1.747 +/*{"??",	HB_TAG('L','C','R',' ')},*/	/* L-Cree */
   1.748 +/*{"??",	HB_TAG('M','A','L',' ')},*/	/* Malayalam Traditional */
   1.749 +/*{"mnk?/mlq?/...",	HB_TAG('M','L','N',' ')},*/	/* Malinke */
   1.750 +/*{"??",	HB_TAG('N','C','R',' ')},*/	/* N-Cree */
   1.751 +/*{"??",	HB_TAG('N','H','C',' ')},*/	/* Norway House Cree */
   1.752 +/*{"jpa?/sam?",	HB_TAG('P','A','A',' ')},*/	/* Palestinian Aramaic */
   1.753 +/*{"polyton",	HB_TAG('P','G','R',' ')},*/	/* Polytonic Greek */
   1.754 +/*{"??",	HB_TAG('Q','I','N',' ')},*/	/* Asho Chin */
   1.755 +/*{"??",	HB_TAG('R','C','R',' ')},*/	/* R-Cree */
   1.756 +/*{"chp?",	HB_TAG('S','A','Y',' ')},*/	/* Sayisi */
   1.757 +/*{"xan?",	HB_TAG('S','E','K',' ')},*/	/* Sekota */
   1.758 +/*{"ngo?",	HB_TAG('S','X','T',' ')},*/	/* Sutu */
   1.759 +/*{"??",	HB_TAG('T','C','R',' ')},*/	/* TH-Cree */
   1.760 +/*{"tnz?/tog?/toi?",	HB_TAG('T','N','G',' ')},*/	/* Tonga */
   1.761 +/*{"enh?/yrk?",	HB_TAG('T','N','E',' ')},*/	/* Tundra Nenets */
   1.762 +/*{"??",	HB_TAG('W','C','R',' ')},*/	/* West-Cree */
   1.763 +/*{"cre?",	HB_TAG('Y','C','R',' ')},*/	/* Y-Cree */
   1.764 +/*{"??",	HB_TAG('Y','I','C',' ')},*/	/* Yi Classic */
   1.765 +/*{"ii?/Yiii?",	HB_TAG('Y','I','M',' ')},*/	/* Yi Modern */
   1.766 +/*{"??",	HB_TAG('Z','H','P',' ')},*/	/* Chinese Phonetic */
   1.767 +};
   1.768 +
   1.769 +static const LangTag ot_languages_zh[] = {
   1.770 +  {"zh-cn",	HB_TAG('Z','H','S',' ')},	/* Chinese (China) */
   1.771 +  {"zh-hk",	HB_TAG('Z','H','H',' ')},	/* Chinese (Hong Kong) */
   1.772 +  {"zh-mo",	HB_TAG('Z','H','T',' ')},	/* Chinese (Macao) */
   1.773 +  {"zh-sg",	HB_TAG('Z','H','S',' ')},	/* Chinese (Singapore) */
   1.774 +  {"zh-tw",	HB_TAG('Z','H','T',' ')} 	/* Chinese (Taiwan) */
   1.775 +};
   1.776 +
   1.777 +static int
   1.778 +lang_compare_first_component (const char *a,
   1.779 +			      const char *b)
   1.780 +{
   1.781 +  unsigned int da, db;
   1.782 +  const char *p;
   1.783 +
   1.784 +  p = strchr (a, '-');
   1.785 +  da = p ? (unsigned int) (p - a) : strlen (a);
   1.786 +
   1.787 +  p = strchr (b, '-');
   1.788 +  db = p ? (unsigned int) (p - b) : strlen (b);
   1.789 +
   1.790 +  return strncmp (a, b, MAX (da, db));
   1.791 +}
   1.792 +
   1.793 +static hb_bool_t
   1.794 +lang_matches (const char *lang_str, const char *spec)
   1.795 +{
   1.796 +  unsigned int len = strlen (spec);
   1.797 +
   1.798 +  return strncmp (lang_str, spec, len) == 0 &&
   1.799 +	 (lang_str[len] == '\0' || lang_str[len] == '-');
   1.800 +}
   1.801 +
   1.802 +hb_tag_t
   1.803 +hb_ot_tag_from_language (hb_language_t language)
   1.804 +{
   1.805 +  const char *lang_str, *s;
   1.806 +  const LangTag *lang_tag;
   1.807 +
   1.808 +  if (language == HB_LANGUAGE_INVALID)
   1.809 +    return HB_OT_TAG_DEFAULT_LANGUAGE;
   1.810 +
   1.811 +  lang_str = hb_language_to_string (language);
   1.812 +
   1.813 +  s = strstr (lang_str, "x-hbot");
   1.814 +  if (s) {
   1.815 +    char tag[4];
   1.816 +    int i;
   1.817 +    s += 6;
   1.818 +    for (i = 0; i < 4 && ISALPHA (s[i]); i++)
   1.819 +      tag[i] = TOUPPER (s[i]);
   1.820 +    if (i) {
   1.821 +      for (; i < 4; i++)
   1.822 +	tag[i] = ' ';
   1.823 +      return HB_TAG_CHAR4 (tag);
   1.824 +    }
   1.825 +  }
   1.826 +
   1.827 +  /* Find a language matching in the first component */
   1.828 +  lang_tag = (LangTag *) bsearch (lang_str, ot_languages,
   1.829 +				  ARRAY_LENGTH (ot_languages), sizeof (LangTag),
   1.830 +				  (hb_compare_func_t) lang_compare_first_component);
   1.831 +  if (lang_tag)
   1.832 +    return lang_tag->tag;
   1.833 +
   1.834 +  /* Otherwise, check the Chinese ones */
   1.835 +  if (0 == lang_compare_first_component (lang_str, "zh"))
   1.836 +  {
   1.837 +    unsigned int i;
   1.838 +
   1.839 +    for (i = 0; i < ARRAY_LENGTH (ot_languages_zh); i++)
   1.840 +    {
   1.841 +      lang_tag = &ot_languages_zh[i];
   1.842 +      if (lang_matches (lang_tag->language, lang_str))
   1.843 +	return lang_tag->tag;
   1.844 +    }
   1.845 +
   1.846 +    /* Otherwise just return 'ZHS ' */
   1.847 +    return HB_TAG('Z','H','S',' ');
   1.848 +  }
   1.849 +
   1.850 +  s = strchr (lang_str, '-');
   1.851 +  if (!s)
   1.852 +    s = lang_str + strlen (lang_str);
   1.853 +  if (s - lang_str == 3) {
   1.854 +    /* Assume it's ISO-639-3 and upper-case and use it. */
   1.855 +    return hb_tag_from_string (lang_str, s - lang_str) & ~0x20202000;
   1.856 +  }
   1.857 +
   1.858 +  return HB_OT_TAG_DEFAULT_LANGUAGE;
   1.859 +}
   1.860 +
   1.861 +hb_language_t
   1.862 +hb_ot_tag_to_language (hb_tag_t tag)
   1.863 +{
   1.864 +  unsigned int i;
   1.865 +
   1.866 +  if (tag == HB_OT_TAG_DEFAULT_LANGUAGE)
   1.867 +    return NULL;
   1.868 +
   1.869 +  for (i = 0; i < ARRAY_LENGTH (ot_languages); i++)
   1.870 +    if (ot_languages[i].tag == tag)
   1.871 +      return hb_language_from_string (ot_languages[i].language, -1);
   1.872 +
   1.873 +  /* If tag starts with ZH, it's Chinese */
   1.874 +  if ((tag & 0xFFFF0000)  == 0x5A480000) {
   1.875 +    switch (tag) {
   1.876 +      case HB_TAG('Z','H','H',' '): return hb_language_from_string ("zh-hk", -1); /* Hong Kong */
   1.877 +      default: {
   1.878 +        /* Encode the tag... */
   1.879 +	unsigned char buf[14] = "zh-x-hbot";
   1.880 +	buf[9] = tag >> 24;
   1.881 +	buf[10] = (tag >> 16) & 0xFF;
   1.882 +	buf[11] = (tag >> 8) & 0xFF;
   1.883 +	buf[12] = tag & 0xFF;
   1.884 +	if (buf[12] == 0x20)
   1.885 +	  buf[12] = '\0';
   1.886 +	buf[13] = '\0';
   1.887 +	return hb_language_from_string ((char *) buf, -1);
   1.888 +      }
   1.889 +    }
   1.890 +  }
   1.891 +
   1.892 +  /* Else return a custom language in the form of "x-hbotABCD" */
   1.893 +  {
   1.894 +    unsigned char buf[11] = "x-hbot";
   1.895 +    buf[6] = tag >> 24;
   1.896 +    buf[7] = (tag >> 16) & 0xFF;
   1.897 +    buf[8] = (tag >> 8) & 0xFF;
   1.898 +    buf[9] = tag & 0xFF;
   1.899 +    if (buf[9] == 0x20)
   1.900 +      buf[9] = '\0';
   1.901 +    buf[10] = '\0';
   1.902 +    return hb_language_from_string ((char *) buf, -1);
   1.903 +  }
   1.904 +}
   1.905 +
   1.906 +

mercurial