1/* 2 * fontconfig/src/fcfreetype.c 3 * 4 * Copyright © 2001 Keith Packard 5 * 6 * Permission to use, copy, modify, distribute, and sell this software and its 7 * documentation for any purpose is hereby granted without fee, provided that 8 * the above copyright notice appear in all copies and that both that 9 * copyright notice and this permission notice appear in supporting 10 * documentation, and that the name of the author(s) not be used in 11 * advertising or publicity pertaining to distribution of the software without 12 * specific, written prior permission. The authors make no 13 * representations about the suitability of this software for any purpose. It 14 * is provided "as is" without express or implied warranty. 15 * 16 * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 18 * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR 19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 22 * PERFORMANCE OF THIS SOFTWARE. 23 */ 24 25#include "fcint.h" 26#include "fcftint.h" 27#include <stdlib.h> 28#include <stdio.h> 29#include <string.h> 30#include <fcntl.h> 31#include <ft2build.h> 32#include FT_FREETYPE_H 33#include FT_ADVANCES_H 34#include FT_TRUETYPE_TABLES_H 35#include FT_SFNT_NAMES_H 36#include FT_TRUETYPE_IDS_H 37#include FT_TYPE1_TABLES_H 38#if HAVE_FT_GET_X11_FONT_FORMAT 39#include FT_XFREE86_H 40#endif 41#if HAVE_FT_GET_BDF_PROPERTY 42#include FT_BDF_H 43#include FT_MODULE_H 44#endif 45#include FT_MULTIPLE_MASTERS_H 46 47#include "fcfoundry.h" 48#include "ftglue.h" 49 50/* 51 * Keep Han languages separated by eliminating languages 52 * that the codePageRange bits says aren't supported 53 */ 54 55static const struct { 56 char bit; 57 const FcChar8 lang[6]; 58} FcCodePageRange[] = { 59 { 17, "ja" }, 60 { 18, "zh-cn" }, 61 { 19, "ko" }, 62 { 20, "zh-tw" }, 63}; 64 65#define NUM_CODE_PAGE_RANGE (int) (sizeof FcCodePageRange / sizeof FcCodePageRange[0]) 66 67FcBool 68FcFreeTypeIsExclusiveLang (const FcChar8 *lang) 69{ 70 int i; 71 72 for (i = 0; i < NUM_CODE_PAGE_RANGE; i++) 73 { 74 if (FcLangCompare (lang, FcCodePageRange[i].lang) == FcLangEqual) 75 return FcTrue; 76 } 77 return FcFalse; 78} 79 80typedef struct { 81 const FT_UShort platform_id; 82 const FT_UShort encoding_id; 83 const char fromcode[12]; 84} FcFtEncoding; 85 86#define TT_ENCODING_DONT_CARE 0xffff 87#define FC_ENCODING_MAC_ROMAN "MACINTOSH" 88 89static const FcFtEncoding fcFtEncoding[] = { 90 { TT_PLATFORM_APPLE_UNICODE, TT_ENCODING_DONT_CARE, "UTF-16BE" }, 91 { TT_PLATFORM_MACINTOSH, TT_MAC_ID_ROMAN, "MACINTOSH" }, 92 { TT_PLATFORM_MACINTOSH, TT_MAC_ID_JAPANESE, "SJIS" }, 93 { TT_PLATFORM_MICROSOFT, TT_MS_ID_SYMBOL_CS, "UTF-16BE" }, 94 { TT_PLATFORM_MICROSOFT, TT_MS_ID_UNICODE_CS, "UTF-16BE" }, 95 { TT_PLATFORM_MICROSOFT, TT_MS_ID_SJIS, "SJIS-WIN" }, 96 { TT_PLATFORM_MICROSOFT, TT_MS_ID_PRC, "GB18030" }, 97 { TT_PLATFORM_MICROSOFT, TT_MS_ID_BIG_5, "BIG-5" }, 98 { TT_PLATFORM_MICROSOFT, TT_MS_ID_WANSUNG, "Wansung" }, 99 { TT_PLATFORM_MICROSOFT, TT_MS_ID_JOHAB, "Johab" }, 100 { TT_PLATFORM_MICROSOFT, TT_MS_ID_UCS_4, "UTF-16BE" }, 101 { TT_PLATFORM_ISO, TT_ISO_ID_7BIT_ASCII, "ASCII" }, 102 { TT_PLATFORM_ISO, TT_ISO_ID_10646, "UTF-16BE" }, 103 { TT_PLATFORM_ISO, TT_ISO_ID_8859_1, "ISO-8859-1" }, 104}; 105 106#define NUM_FC_FT_ENCODING (int) (sizeof (fcFtEncoding) / sizeof (fcFtEncoding[0])) 107 108typedef struct { 109 const FT_UShort platform_id; 110 const FT_UShort language_id; 111 const char lang[8]; 112} FcFtLanguage; 113 114#define TT_LANGUAGE_DONT_CARE 0xffff 115 116static const FcFtLanguage fcFtLanguage[] = { 117 { TT_PLATFORM_APPLE_UNICODE, TT_LANGUAGE_DONT_CARE, "" }, 118 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ENGLISH, "en" }, 119 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_FRENCH, "fr" }, 120 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GERMAN, "de" }, 121 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ITALIAN, "it" }, 122 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_DUTCH, "nl" }, 123 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SWEDISH, "sv" }, 124 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SPANISH, "es" }, 125 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_DANISH, "da" }, 126 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_PORTUGUESE, "pt" }, 127 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_NORWEGIAN, "no" }, 128 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_HEBREW, "he" }, 129 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_JAPANESE, "ja" }, 130 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ARABIC, "ar" }, 131 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_FINNISH, "fi" }, 132 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GREEK, "el" }, 133 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ICELANDIC, "is" }, 134 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MALTESE, "mt" }, 135 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TURKISH, "tr" }, 136 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CROATIAN, "hr" }, 137 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CHINESE_TRADITIONAL, "zh-tw" }, 138 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_URDU, "ur" }, 139 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_HINDI, "hi" }, 140 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_THAI, "th" }, 141 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KOREAN, "ko" }, 142 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_LITHUANIAN, "lt" }, 143 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_POLISH, "pl" }, 144 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_HUNGARIAN, "hu" }, 145 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ESTONIAN, "et" }, 146 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_LETTISH, "lv" }, 147/* { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SAAMISK, ??? */ 148 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_FAEROESE, "fo" }, 149 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_FARSI, "fa" }, 150 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_RUSSIAN, "ru" }, 151 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CHINESE_SIMPLIFIED, "zh-cn" }, 152 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_FLEMISH, "nl" }, 153 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_IRISH, "ga" }, 154 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ALBANIAN, "sq" }, 155 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ROMANIAN, "ro" }, 156 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CZECH, "cs" }, 157 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SLOVAK, "sk" }, 158 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SLOVENIAN, "sl" }, 159 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_YIDDISH, "yi" }, 160 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SERBIAN, "sr" }, 161 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MACEDONIAN, "mk" }, 162 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BULGARIAN, "bg" }, 163 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_UKRAINIAN, "uk" }, 164 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BYELORUSSIAN, "be" }, 165 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_UZBEK, "uz" }, 166 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KAZAKH, "kk" }, 167 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AZERBAIJANI, "az" }, 168 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AZERBAIJANI_CYRILLIC_SCRIPT, "az" }, 169 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT, "ar" }, 170 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ARMENIAN, "hy" }, 171 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GEORGIAN, "ka" }, 172 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MOLDAVIAN, "mo" }, 173 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KIRGHIZ, "ky" }, 174 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TAJIKI, "tg" }, 175 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TURKMEN, "tk" }, 176 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MONGOLIAN, "mn" }, 177 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MONGOLIAN_MONGOLIAN_SCRIPT,"mn" }, 178 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT, "mn" }, 179 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_PASHTO, "ps" }, 180 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KURDISH, "ku" }, 181 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KASHMIRI, "ks" }, 182 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SINDHI, "sd" }, 183 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TIBETAN, "bo" }, 184 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_NEPALI, "ne" }, 185 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SANSKRIT, "sa" }, 186 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MARATHI, "mr" }, 187 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BENGALI, "bn" }, 188 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ASSAMESE, "as" }, 189 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GUJARATI, "gu" }, 190 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_PUNJABI, "pa" }, 191 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ORIYA, "or" }, 192 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MALAYALAM, "ml" }, 193 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KANNADA, "kn" }, 194 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TAMIL, "ta" }, 195 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TELUGU, "te" }, 196 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SINHALESE, "si" }, 197 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BURMESE, "my" }, 198 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KHMER, "km" }, 199 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_LAO, "lo" }, 200 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_VIETNAMESE, "vi" }, 201 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_INDONESIAN, "id" }, 202 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TAGALOG, "tl" }, 203 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MALAY_ROMAN_SCRIPT, "ms" }, 204 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MALAY_ARABIC_SCRIPT, "ms" }, 205 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AMHARIC, "am" }, 206 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TIGRINYA, "ti" }, 207 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GALLA, "om" }, 208 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SOMALI, "so" }, 209 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SWAHILI, "sw" }, 210 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_RUANDA, "rw" }, 211 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_RUNDI, "rn" }, 212 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CHEWA, "ny" }, 213 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MALAGASY, "mg" }, 214 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ESPERANTO, "eo" }, 215 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_WELSH, "cy" }, 216 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BASQUE, "eu" }, 217 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CATALAN, "ca" }, 218 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_LATIN, "la" }, 219 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_QUECHUA, "qu" }, 220 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GUARANI, "gn" }, 221 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AYMARA, "ay" }, 222 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TATAR, "tt" }, 223 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_UIGHUR, "ug" }, 224 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_DZONGKHA, "dz" }, 225 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_JAVANESE, "jw" }, 226 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SUNDANESE, "su" }, 227 228#if 0 /* these seem to be errors that have been dropped */ 229 230 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SCOTTISH_GAELIC }, 231 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_IRISH_GAELIC }, 232 233#endif 234 235 /* The following codes are new as of 2000-03-10 */ 236 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GALICIAN, "gl" }, 237 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AFRIKAANS, "af" }, 238 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BRETON, "br" }, 239 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_INUKTITUT, "iu" }, 240 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SCOTTISH_GAELIC, "gd" }, 241 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MANX_GAELIC, "gv" }, 242 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_IRISH_GAELIC, "ga" }, 243 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TONGAN, "to" }, 244 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GREEK_POLYTONIC, "el" }, 245 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GREELANDIC, "ik" }, 246 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT,"az" }, 247 248 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_SAUDI_ARABIA, "ar" }, 249 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_IRAQ, "ar" }, 250 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_EGYPT, "ar" }, 251 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_LIBYA, "ar" }, 252 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_ALGERIA, "ar" }, 253 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_MOROCCO, "ar" }, 254 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_TUNISIA, "ar" }, 255 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_OMAN, "ar" }, 256 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_YEMEN, "ar" }, 257 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_SYRIA, "ar" }, 258 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_JORDAN, "ar" }, 259 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_LEBANON, "ar" }, 260 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_KUWAIT, "ar" }, 261 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_UAE, "ar" }, 262 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_BAHRAIN, "ar" }, 263 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_QATAR, "ar" }, 264 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BULGARIAN_BULGARIA, "bg" }, 265 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CATALAN_SPAIN, "ca" }, 266 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_TAIWAN, "zh-tw" }, 267 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_PRC, "zh-cn" }, 268 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_HONG_KONG, "zh-hk" }, 269 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_SINGAPORE, "zh-sg" }, 270 271 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_MACAU, "zh-mo" }, 272 273 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CZECH_CZECH_REPUBLIC, "cs" }, 274 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_DANISH_DENMARK, "da" }, 275 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GERMAN_GERMANY, "de" }, 276 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GERMAN_SWITZERLAND, "de" }, 277 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GERMAN_AUSTRIA, "de" }, 278 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GERMAN_LUXEMBOURG, "de" }, 279 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GERMAN_LIECHTENSTEI, "de" }, 280 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GREEK_GREECE, "el" }, 281 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_UNITED_STATES, "en" }, 282 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_UNITED_KINGDOM, "en" }, 283 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_AUSTRALIA, "en" }, 284 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_CANADA, "en" }, 285 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_NEW_ZEALAND, "en" }, 286 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_IRELAND, "en" }, 287 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_SOUTH_AFRICA, "en" }, 288 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_JAMAICA, "en" }, 289 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_CARIBBEAN, "en" }, 290 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_BELIZE, "en" }, 291 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_TRINIDAD, "en" }, 292 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_ZIMBABWE, "en" }, 293 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_PHILIPPINES, "en" }, 294 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_SPAIN_TRADITIONAL_SORT,"es" }, 295 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_MEXICO, "es" }, 296 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_SPAIN_INTERNATIONAL_SORT,"es" }, 297 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_GUATEMALA, "es" }, 298 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_COSTA_RICA, "es" }, 299 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_PANAMA, "es" }, 300 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_DOMINICAN_REPUBLIC,"es" }, 301 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_VENEZUELA, "es" }, 302 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_COLOMBIA, "es" }, 303 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_PERU, "es" }, 304 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_ARGENTINA, "es" }, 305 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_ECUADOR, "es" }, 306 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_CHILE, "es" }, 307 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_URUGUAY, "es" }, 308 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_PARAGUAY, "es" }, 309 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_BOLIVIA, "es" }, 310 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_EL_SALVADOR, "es" }, 311 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_HONDURAS, "es" }, 312 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_NICARAGUA, "es" }, 313 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_PUERTO_RICO, "es" }, 314 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FINNISH_FINLAND, "fi" }, 315 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_FRANCE, "fr" }, 316 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_BELGIUM, "fr" }, 317 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_CANADA, "fr" }, 318 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_SWITZERLAND, "fr" }, 319 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_LUXEMBOURG, "fr" }, 320 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_MONACO, "fr" }, 321 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_HEBREW_ISRAEL, "he" }, 322 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_HUNGARIAN_HUNGARY, "hu" }, 323 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ICELANDIC_ICELAND, "is" }, 324 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ITALIAN_ITALY, "it" }, 325 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ITALIAN_SWITZERLAND, "it" }, 326 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_JAPANESE_JAPAN, "ja" }, 327 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KOREAN_EXTENDED_WANSUNG_KOREA,"ko" }, 328 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KOREAN_JOHAB_KOREA, "ko" }, 329 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_DUTCH_NETHERLANDS, "nl" }, 330 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_DUTCH_BELGIUM, "nl" }, 331 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_NORWEGIAN_NORWAY_BOKMAL, "no" }, 332 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_NORWEGIAN_NORWAY_NYNORSK, "nn" }, 333 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_POLISH_POLAND, "pl" }, 334 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PORTUGUESE_BRAZIL, "pt" }, 335 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PORTUGUESE_PORTUGAL, "pt" }, 336 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_RHAETO_ROMANIC_SWITZERLAND,"rm" }, 337 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ROMANIAN_ROMANIA, "ro" }, 338 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MOLDAVIAN_MOLDAVIA, "mo" }, 339 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_RUSSIAN_RUSSIA, "ru" }, 340 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_RUSSIAN_MOLDAVIA, "ru" }, 341 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CROATIAN_CROATIA, "hr" }, 342 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SERBIAN_SERBIA_LATIN, "sr" }, 343 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SERBIAN_SERBIA_CYRILLIC, "sr" }, 344 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SLOVAK_SLOVAKIA, "sk" }, 345 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ALBANIAN_ALBANIA, "sq" }, 346 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SWEDISH_SWEDEN, "sv" }, 347 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SWEDISH_FINLAND, "sv" }, 348 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_THAI_THAILAND, "th" }, 349 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TURKISH_TURKEY, "tr" }, 350 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_URDU_PAKISTAN, "ur" }, 351 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_INDONESIAN_INDONESIA, "id" }, 352 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_UKRAINIAN_UKRAINE, "uk" }, 353 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BELARUSIAN_BELARUS, "be" }, 354 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SLOVENE_SLOVENIA, "sl" }, 355 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ESTONIAN_ESTONIA, "et" }, 356 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_LATVIAN_LATVIA, "lv" }, 357 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_LITHUANIAN_LITHUANIA, "lt" }, 358 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CLASSIC_LITHUANIAN_LITHUANIA,"lt" }, 359 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MAORI_NEW_ZEALAND, "mi" }, 360 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FARSI_IRAN, "fa" }, 361 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_VIETNAMESE_VIET_NAM, "vi" }, 362 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARMENIAN_ARMENIA, "hy" }, 363 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_AZERI_AZERBAIJAN_LATIN, "az" }, 364 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_AZERI_AZERBAIJAN_CYRILLIC, "az" }, 365 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BASQUE_SPAIN, "eu" }, 366 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SORBIAN_GERMANY, "wen" }, 367 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MACEDONIAN_MACEDONIA, "mk" }, 368 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SUTU_SOUTH_AFRICA, "st" }, 369 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TSONGA_SOUTH_AFRICA, "ts" }, 370 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TSWANA_SOUTH_AFRICA, "tn" }, 371 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_VENDA_SOUTH_AFRICA, "ven" }, 372 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_XHOSA_SOUTH_AFRICA, "xh" }, 373 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ZULU_SOUTH_AFRICA, "zu" }, 374 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_AFRIKAANS_SOUTH_AFRICA, "af" }, 375 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GEORGIAN_GEORGIA, "ka" }, 376 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FAEROESE_FAEROE_ISLANDS, "fo" }, 377 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_HINDI_INDIA, "hi" }, 378 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MALTESE_MALTA, "mt" }, 379 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SAAMI_LAPONIA, "se" }, 380 381 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SCOTTISH_GAELIC_UNITED_KINGDOM,"gd" }, 382 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_IRISH_GAELIC_IRELAND, "ga" }, 383 384 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MALAY_MALAYSIA, "ms" }, 385 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MALAY_BRUNEI_DARUSSALAM, "ms" }, 386 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KAZAK_KAZAKSTAN, "kk" }, 387 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SWAHILI_KENYA, "sw" }, 388 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_UZBEK_UZBEKISTAN_LATIN, "uz" }, 389 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_UZBEK_UZBEKISTAN_CYRILLIC, "uz" }, 390 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TATAR_TATARSTAN, "tt" }, 391 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BENGALI_INDIA, "bn" }, 392 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PUNJABI_INDIA, "pa" }, 393 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GUJARATI_INDIA, "gu" }, 394 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ORIYA_INDIA, "or" }, 395 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TAMIL_INDIA, "ta" }, 396 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TELUGU_INDIA, "te" }, 397 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KANNADA_INDIA, "kn" }, 398 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MALAYALAM_INDIA, "ml" }, 399 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ASSAMESE_INDIA, "as" }, 400 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MARATHI_INDIA, "mr" }, 401 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SANSKRIT_INDIA, "sa" }, 402 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KONKANI_INDIA, "kok" }, 403 404 /* new as of 2001-01-01 */ 405 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_GENERAL, "ar" }, 406 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_GENERAL, "zh" }, 407 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_GENERAL, "en" }, 408 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_WEST_INDIES, "fr" }, 409 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_REUNION, "fr" }, 410 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_CONGO, "fr" }, 411 412 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_SENEGAL, "fr" }, 413 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_CAMEROON, "fr" }, 414 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_COTE_D_IVOIRE, "fr" }, 415 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_MALI, "fr" }, 416 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BOSNIAN_BOSNIA_HERZEGOVINA,"bs" }, 417 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_URDU_INDIA, "ur" }, 418 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TAJIK_TAJIKISTAN, "tg" }, 419 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_YIDDISH_GERMANY, "yi" }, 420 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KIRGHIZ_KIRGHIZSTAN, "ky" }, 421 422 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TURKMEN_TURKMENISTAN, "tk" }, 423 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MONGOLIAN_MONGOLIA, "mn" }, 424 425 /* the following seems to be inconsistent; 426 here is the current "official" way: */ 427 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TIBETAN_BHUTAN, "bo" }, 428 /* and here is what is used by Passport SDK */ 429 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TIBETAN_CHINA, "bo" }, 430 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_DZONGHKA_BHUTAN, "dz" }, 431 /* end of inconsistency */ 432 433 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_WELSH_WALES, "cy" }, 434 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KHMER_CAMBODIA, "km" }, 435 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_LAO_LAOS, "lo" }, 436 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BURMESE_MYANMAR, "my" }, 437 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GALICIAN_SPAIN, "gl" }, 438 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MANIPURI_INDIA, "mni" }, 439 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SINDHI_INDIA, "sd" }, 440 /* the following one is only encountered in Microsoft RTF specification */ 441 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KASHMIRI_PAKISTAN, "ks" }, 442 /* the following one is not in the Passport list, looks like an omission */ 443 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KASHMIRI_INDIA, "ks" }, 444 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_NEPALI_NEPAL, "ne" }, 445 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_NEPALI_INDIA, "ne" }, 446 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRISIAN_NETHERLANDS, "fy" }, 447 448 /* new as of 2001-03-01 (from Office Xp) */ 449 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_HONG_KONG, "en" }, 450 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_INDIA, "en" }, 451 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_MALAYSIA, "en" }, 452 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_SINGAPORE, "en" }, 453 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SYRIAC_SYRIA, "syr" }, 454 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SINHALESE_SRI_LANKA, "si" }, 455 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHEROKEE_UNITED_STATES, "chr" }, 456 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_INUKTITUT_CANADA, "iu" }, 457 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_AMHARIC_ETHIOPIA, "am" }, 458#if 0 459 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TAMAZIGHT_MOROCCO }, 460 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TAMAZIGHT_MOROCCO_LATIN }, 461#endif 462 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PASHTO_AFGHANISTAN, "ps" }, 463 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FILIPINO_PHILIPPINES, "phi" }, 464 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_DHIVEHI_MALDIVES, "div" }, 465 466 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_OROMO_ETHIOPIA, "om" }, 467 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TIGRIGNA_ETHIOPIA, "ti" }, 468 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TIGRIGNA_ERYTHREA, "ti" }, 469 470 /* New additions from Windows Xp/Passport SDK 2001-11-10. */ 471 472 /* don't ask what this one means... It is commented out currently. */ 473#if 0 474 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GREEK_GREECE2 }, 475#endif 476 477 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_UNITED_STATES, "es" }, 478 /* The following two IDs blatantly violate MS specs by using a */ 479 /* sublanguage >,. */ 480 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_LATIN_AMERICA, "es" }, 481 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_NORTH_AFRICA, "fr" }, 482 483 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_MOROCCO, "fr" }, 484 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_HAITI, "fr" }, 485 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BENGALI_BANGLADESH, "bn" }, 486 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PUNJABI_ARABIC_PAKISTAN, "ar" }, 487 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MONGOLIAN_MONGOLIA_MONGOLIAN,"mn" }, 488#if 0 489 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_EDO_NIGERIA }, 490 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FULFULDE_NIGERIA }, 491 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_IBIBIO_NIGERIA }, 492#endif 493 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_HAUSA_NIGERIA, "ha" }, 494 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_YORUBA_NIGERIA, "yo" }, 495 /* language codes from, to, are (still) unknown. */ 496 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_IGBO_NIGERIA, "ibo" }, 497 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KANURI_NIGERIA, "kau" }, 498 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GUARANI_PARAGUAY, "gn" }, 499 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_HAWAIIAN_UNITED_STATES, "haw" }, 500 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_LATIN, "la" }, 501 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SOMALI_SOMALIA, "so" }, 502#if 0 503 /* Note: Yi does not have a (proper) ISO 639-2 code, since it is mostly */ 504 /* not written (but OTOH the peculiar writing system is worth */ 505 /* studying). */ 506 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_YI_CHINA }, 507#endif 508 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PAPIAMENTU_NETHERLANDS_ANTILLES,"pap" }, 509}; 510 511#define NUM_FC_FT_LANGUAGE (int) (sizeof (fcFtLanguage) / sizeof (fcFtLanguage[0])) 512 513typedef struct { 514 FT_UShort language_id; 515 char fromcode[12]; 516} FcMacRomanFake; 517 518static const FcMacRomanFake fcMacRomanFake[] = { 519 { TT_MS_LANGID_JAPANESE_JAPAN, "SJIS-WIN" }, 520 { TT_MS_LANGID_ENGLISH_UNITED_STATES, "ASCII" }, 521}; 522 523static FcChar8 * 524FcFontCapabilities(FT_Face face); 525 526static FcBool 527FcFontHasHint (FT_Face face); 528 529static int 530FcFreeTypeSpacing (FT_Face face); 531 532#define NUM_FC_MAC_ROMAN_FAKE (int) (sizeof (fcMacRomanFake) / sizeof (fcMacRomanFake[0])) 533 534 535/* From http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/ROMAN.TXT */ 536static const FcChar16 fcMacRomanNonASCIIToUnicode[128] = { 537 /*0x80*/ 0x00C4, /* LATIN CAPITAL LETTER A WITH DIAERESIS */ 538 /*0x81*/ 0x00C5, /* LATIN CAPITAL LETTER A WITH RING ABOVE */ 539 /*0x82*/ 0x00C7, /* LATIN CAPITAL LETTER C WITH CEDILLA */ 540 /*0x83*/ 0x00C9, /* LATIN CAPITAL LETTER E WITH ACUTE */ 541 /*0x84*/ 0x00D1, /* LATIN CAPITAL LETTER N WITH TILDE */ 542 /*0x85*/ 0x00D6, /* LATIN CAPITAL LETTER O WITH DIAERESIS */ 543 /*0x86*/ 0x00DC, /* LATIN CAPITAL LETTER U WITH DIAERESIS */ 544 /*0x87*/ 0x00E1, /* LATIN SMALL LETTER A WITH ACUTE */ 545 /*0x88*/ 0x00E0, /* LATIN SMALL LETTER A WITH GRAVE */ 546 /*0x89*/ 0x00E2, /* LATIN SMALL LETTER A WITH CIRCUMFLEX */ 547 /*0x8A*/ 0x00E4, /* LATIN SMALL LETTER A WITH DIAERESIS */ 548 /*0x8B*/ 0x00E3, /* LATIN SMALL LETTER A WITH TILDE */ 549 /*0x8C*/ 0x00E5, /* LATIN SMALL LETTER A WITH RING ABOVE */ 550 /*0x8D*/ 0x00E7, /* LATIN SMALL LETTER C WITH CEDILLA */ 551 /*0x8E*/ 0x00E9, /* LATIN SMALL LETTER E WITH ACUTE */ 552 /*0x8F*/ 0x00E8, /* LATIN SMALL LETTER E WITH GRAVE */ 553 /*0x90*/ 0x00EA, /* LATIN SMALL LETTER E WITH CIRCUMFLEX */ 554 /*0x91*/ 0x00EB, /* LATIN SMALL LETTER E WITH DIAERESIS */ 555 /*0x92*/ 0x00ED, /* LATIN SMALL LETTER I WITH ACUTE */ 556 /*0x93*/ 0x00EC, /* LATIN SMALL LETTER I WITH GRAVE */ 557 /*0x94*/ 0x00EE, /* LATIN SMALL LETTER I WITH CIRCUMFLEX */ 558 /*0x95*/ 0x00EF, /* LATIN SMALL LETTER I WITH DIAERESIS */ 559 /*0x96*/ 0x00F1, /* LATIN SMALL LETTER N WITH TILDE */ 560 /*0x97*/ 0x00F3, /* LATIN SMALL LETTER O WITH ACUTE */ 561 /*0x98*/ 0x00F2, /* LATIN SMALL LETTER O WITH GRAVE */ 562 /*0x99*/ 0x00F4, /* LATIN SMALL LETTER O WITH CIRCUMFLEX */ 563 /*0x9A*/ 0x00F6, /* LATIN SMALL LETTER O WITH DIAERESIS */ 564 /*0x9B*/ 0x00F5, /* LATIN SMALL LETTER O WITH TILDE */ 565 /*0x9C*/ 0x00FA, /* LATIN SMALL LETTER U WITH ACUTE */ 566 /*0x9D*/ 0x00F9, /* LATIN SMALL LETTER U WITH GRAVE */ 567 /*0x9E*/ 0x00FB, /* LATIN SMALL LETTER U WITH CIRCUMFLEX */ 568 /*0x9F*/ 0x00FC, /* LATIN SMALL LETTER U WITH DIAERESIS */ 569 /*0xA0*/ 0x2020, /* DAGGER */ 570 /*0xA1*/ 0x00B0, /* DEGREE SIGN */ 571 /*0xA2*/ 0x00A2, /* CENT SIGN */ 572 /*0xA3*/ 0x00A3, /* POUND SIGN */ 573 /*0xA4*/ 0x00A7, /* SECTION SIGN */ 574 /*0xA5*/ 0x2022, /* BULLET */ 575 /*0xA6*/ 0x00B6, /* PILCROW SIGN */ 576 /*0xA7*/ 0x00DF, /* LATIN SMALL LETTER SHARP S */ 577 /*0xA8*/ 0x00AE, /* REGISTERED SIGN */ 578 /*0xA9*/ 0x00A9, /* COPYRIGHT SIGN */ 579 /*0xAA*/ 0x2122, /* TRADE MARK SIGN */ 580 /*0xAB*/ 0x00B4, /* ACUTE ACCENT */ 581 /*0xAC*/ 0x00A8, /* DIAERESIS */ 582 /*0xAD*/ 0x2260, /* NOT EQUAL TO */ 583 /*0xAE*/ 0x00C6, /* LATIN CAPITAL LETTER AE */ 584 /*0xAF*/ 0x00D8, /* LATIN CAPITAL LETTER O WITH STROKE */ 585 /*0xB0*/ 0x221E, /* INFINITY */ 586 /*0xB1*/ 0x00B1, /* PLUS-MINUS SIGN */ 587 /*0xB2*/ 0x2264, /* LESS-THAN OR EQUAL TO */ 588 /*0xB3*/ 0x2265, /* GREATER-THAN OR EQUAL TO */ 589 /*0xB4*/ 0x00A5, /* YEN SIGN */ 590 /*0xB5*/ 0x00B5, /* MICRO SIGN */ 591 /*0xB6*/ 0x2202, /* PARTIAL DIFFERENTIAL */ 592 /*0xB7*/ 0x2211, /* N-ARY SUMMATION */ 593 /*0xB8*/ 0x220F, /* N-ARY PRODUCT */ 594 /*0xB9*/ 0x03C0, /* GREEK SMALL LETTER PI */ 595 /*0xBA*/ 0x222B, /* INTEGRAL */ 596 /*0xBB*/ 0x00AA, /* FEMININE ORDINAL INDICATOR */ 597 /*0xBC*/ 0x00BA, /* MASCULINE ORDINAL INDICATOR */ 598 /*0xBD*/ 0x03A9, /* GREEK CAPITAL LETTER OMEGA */ 599 /*0xBE*/ 0x00E6, /* LATIN SMALL LETTER AE */ 600 /*0xBF*/ 0x00F8, /* LATIN SMALL LETTER O WITH STROKE */ 601 /*0xC0*/ 0x00BF, /* INVERTED QUESTION MARK */ 602 /*0xC1*/ 0x00A1, /* INVERTED EXCLAMATION MARK */ 603 /*0xC2*/ 0x00AC, /* NOT SIGN */ 604 /*0xC3*/ 0x221A, /* SQUARE ROOT */ 605 /*0xC4*/ 0x0192, /* LATIN SMALL LETTER F WITH HOOK */ 606 /*0xC5*/ 0x2248, /* ALMOST EQUAL TO */ 607 /*0xC6*/ 0x2206, /* INCREMENT */ 608 /*0xC7*/ 0x00AB, /* LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */ 609 /*0xC8*/ 0x00BB, /* RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */ 610 /*0xC9*/ 0x2026, /* HORIZONTAL ELLIPSIS */ 611 /*0xCA*/ 0x00A0, /* NO-BREAK SPACE */ 612 /*0xCB*/ 0x00C0, /* LATIN CAPITAL LETTER A WITH GRAVE */ 613 /*0xCC*/ 0x00C3, /* LATIN CAPITAL LETTER A WITH TILDE */ 614 /*0xCD*/ 0x00D5, /* LATIN CAPITAL LETTER O WITH TILDE */ 615 /*0xCE*/ 0x0152, /* LATIN CAPITAL LIGATURE OE */ 616 /*0xCF*/ 0x0153, /* LATIN SMALL LIGATURE OE */ 617 /*0xD0*/ 0x2013, /* EN DASH */ 618 /*0xD1*/ 0x2014, /* EM DASH */ 619 /*0xD2*/ 0x201C, /* LEFT DOUBLE QUOTATION MARK */ 620 /*0xD3*/ 0x201D, /* RIGHT DOUBLE QUOTATION MARK */ 621 /*0xD4*/ 0x2018, /* LEFT SINGLE QUOTATION MARK */ 622 /*0xD5*/ 0x2019, /* RIGHT SINGLE QUOTATION MARK */ 623 /*0xD6*/ 0x00F7, /* DIVISION SIGN */ 624 /*0xD7*/ 0x25CA, /* LOZENGE */ 625 /*0xD8*/ 0x00FF, /* LATIN SMALL LETTER Y WITH DIAERESIS */ 626 /*0xD9*/ 0x0178, /* LATIN CAPITAL LETTER Y WITH DIAERESIS */ 627 /*0xDA*/ 0x2044, /* FRACTION SLASH */ 628 /*0xDB*/ 0x20AC, /* EURO SIGN */ 629 /*0xDC*/ 0x2039, /* SINGLE LEFT-POINTING ANGLE QUOTATION MARK */ 630 /*0xDD*/ 0x203A, /* SINGLE RIGHT-POINTING ANGLE QUOTATION MARK */ 631 /*0xDE*/ 0xFB01, /* LATIN SMALL LIGATURE FI */ 632 /*0xDF*/ 0xFB02, /* LATIN SMALL LIGATURE FL */ 633 /*0xE0*/ 0x2021, /* DOUBLE DAGGER */ 634 /*0xE1*/ 0x00B7, /* MIDDLE DOT */ 635 /*0xE2*/ 0x201A, /* SINGLE LOW-9 QUOTATION MARK */ 636 /*0xE3*/ 0x201E, /* DOUBLE LOW-9 QUOTATION MARK */ 637 /*0xE4*/ 0x2030, /* PER MILLE SIGN */ 638 /*0xE5*/ 0x00C2, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX */ 639 /*0xE6*/ 0x00CA, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */ 640 /*0xE7*/ 0x00C1, /* LATIN CAPITAL LETTER A WITH ACUTE */ 641 /*0xE8*/ 0x00CB, /* LATIN CAPITAL LETTER E WITH DIAERESIS */ 642 /*0xE9*/ 0x00C8, /* LATIN CAPITAL LETTER E WITH GRAVE */ 643 /*0xEA*/ 0x00CD, /* LATIN CAPITAL LETTER I WITH ACUTE */ 644 /*0xEB*/ 0x00CE, /* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */ 645 /*0xEC*/ 0x00CF, /* LATIN CAPITAL LETTER I WITH DIAERESIS */ 646 /*0xED*/ 0x00CC, /* LATIN CAPITAL LETTER I WITH GRAVE */ 647 /*0xEE*/ 0x00D3, /* LATIN CAPITAL LETTER O WITH ACUTE */ 648 /*0xEF*/ 0x00D4, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX */ 649 /*0xF0*/ 0xF8FF, /* Apple logo */ 650 /*0xF1*/ 0x00D2, /* LATIN CAPITAL LETTER O WITH GRAVE */ 651 /*0xF2*/ 0x00DA, /* LATIN CAPITAL LETTER U WITH ACUTE */ 652 /*0xF3*/ 0x00DB, /* LATIN CAPITAL LETTER U WITH CIRCUMFLEX */ 653 /*0xF4*/ 0x00D9, /* LATIN CAPITAL LETTER U WITH GRAVE */ 654 /*0xF5*/ 0x0131, /* LATIN SMALL LETTER DOTLESS I */ 655 /*0xF6*/ 0x02C6, /* MODIFIER LETTER CIRCUMFLEX ACCENT */ 656 /*0xF7*/ 0x02DC, /* SMALL TILDE */ 657 /*0xF8*/ 0x00AF, /* MACRON */ 658 /*0xF9*/ 0x02D8, /* BREVE */ 659 /*0xFA*/ 0x02D9, /* DOT ABOVE */ 660 /*0xFB*/ 0x02DA, /* RING ABOVE */ 661 /*0xFC*/ 0x00B8, /* CEDILLA */ 662 /*0xFD*/ 0x02DD, /* DOUBLE ACUTE ACCENT */ 663 /*0xFE*/ 0x02DB, /* OGONEK */ 664 /*0xFF*/ 0x02C7, /* CARON */ 665}; 666 667#if USE_ICONV 668#include <iconv.h> 669#endif 670 671/* 672 * A shift-JIS will have many high bits turned on 673 */ 674static FcBool 675FcLooksLikeSJIS (FcChar8 *string, int len) 676{ 677 int nhigh = 0, nlow = 0; 678 679 while (len-- > 0) 680 { 681 if (*string++ & 0x80) nhigh++; 682 else nlow++; 683 } 684 /* 685 * Heuristic -- if more than 1/3 of the bytes have the high-bit set, 686 * this is likely to be SJIS and not ROMAN 687 */ 688 if (nhigh * 2 > nlow) 689 return FcTrue; 690 return FcFalse; 691} 692 693static FcChar8 * 694FcSfntNameTranscode (FT_SfntName *sname) 695{ 696 int i; 697 const char *fromcode; 698#if USE_ICONV 699 iconv_t cd; 700#endif 701 FcChar8 *utf8; 702 FcBool redecoded = FcFalse; 703 704 for (i = 0; i < NUM_FC_FT_ENCODING; i++) 705 if (fcFtEncoding[i].platform_id == sname->platform_id && 706 (fcFtEncoding[i].encoding_id == TT_ENCODING_DONT_CARE || 707 fcFtEncoding[i].encoding_id == sname->encoding_id)) 708 break; 709 if (i == NUM_FC_FT_ENCODING) 710 return 0; 711 fromcode = fcFtEncoding[i].fromcode; 712 713retry: 714 /* 715 * Many names encoded for TT_PLATFORM_MACINTOSH are broken 716 * in various ways. Kludge around them. 717 */ 718 if (!strcmp (fromcode, FC_ENCODING_MAC_ROMAN)) 719 { 720 if (sname->language_id == TT_MAC_LANGID_ENGLISH && 721 FcLooksLikeSJIS (sname->string, sname->string_len)) 722 { 723 fromcode = "SJIS"; 724 } 725 else if (sname->language_id == TT_MAC_LANGID_JAPANESE) 726 { 727 fromcode = "SJIS"; 728 } 729 else if (sname->language_id >= 0x100) 730 { 731 /* 732 * "real" Mac language IDs are all less than 150. 733 * Names using one of the MS language IDs are assumed 734 * to use an associated encoding (Yes, this is a kludge) 735 */ 736 int f; 737 738 fromcode = NULL; 739 for (f = 0; f < NUM_FC_MAC_ROMAN_FAKE; f++) 740 if (fcMacRomanFake[f].language_id == sname->language_id) 741 { 742 fromcode = fcMacRomanFake[f].fromcode; 743 break; 744 } 745 if (!fromcode) 746 return 0; 747 } 748 } 749 if (!strcmp (fromcode, "UCS-2BE") || !strcmp (fromcode, "UTF-16BE")) 750 { 751 FcChar8 *src = sname->string; 752 int src_len = sname->string_len; 753 int len; 754 int wchar; 755 int ilen, olen; 756 FcChar8 *u8; 757 FcChar32 ucs4; 758 759 /* 760 * Convert Utf16 to Utf8 761 */ 762 763 if (!FcUtf16Len (src, FcEndianBig, src_len, &len, &wchar)) 764 return 0; 765 766 /* 767 * Allocate plenty of space. Freed below 768 */ 769 utf8 = malloc (len * FC_UTF8_MAX_LEN + 1); 770 if (!utf8) 771 return 0; 772 773 u8 = utf8; 774 775 while ((ilen = FcUtf16ToUcs4 (src, FcEndianBig, &ucs4, src_len)) > 0) 776 { 777 src_len -= ilen; 778 src += ilen; 779 olen = FcUcs4ToUtf8 (ucs4, u8); 780 u8 += olen; 781 } 782 *u8 = '\0'; 783 goto done; 784 } 785 if (!strcmp (fromcode, "ASCII") || !strcmp (fromcode, "ISO-8859-1")) 786 { 787 FcChar8 *src = sname->string; 788 int src_len = sname->string_len; 789 int olen; 790 FcChar8 *u8; 791 FcChar32 ucs4; 792 793 /* 794 * Convert Latin1 to Utf8. Freed below 795 */ 796 utf8 = malloc (src_len * 2 + 1); 797 if (!utf8) 798 return 0; 799 800 u8 = utf8; 801 while (src_len > 0) 802 { 803 ucs4 = *src++; 804 src_len--; 805 olen = FcUcs4ToUtf8 (ucs4, u8); 806 u8 += olen; 807 } 808 *u8 = '\0'; 809 goto done; 810 } 811 if (!strcmp (fromcode, FC_ENCODING_MAC_ROMAN)) 812 { 813 FcChar8 *src = sname->string; 814 int src_len = sname->string_len; 815 int olen; 816 FcChar8 *u8; 817 FcChar32 ucs4; 818 819 /* 820 * Convert Latin1 to Utf8. Freed below 821 */ 822 utf8 = malloc (src_len * 3 + 1); 823 if (!utf8) 824 return 0; 825 826 u8 = utf8; 827 while (src_len > 0) 828 { 829 ucs4 = *src++; 830 if (ucs4 >= 128) 831 ucs4 = fcMacRomanNonASCIIToUnicode[ucs4 - 128]; 832 src_len--; 833 olen = FcUcs4ToUtf8 (ucs4, u8); 834 u8 += olen; 835 } 836 *u8 = '\0'; 837 goto done; 838 } 839 840#if USE_ICONV 841 cd = iconv_open ("UTF-8", fromcode); 842 if (cd && cd != (iconv_t) (-1)) 843 { 844 size_t in_bytes_left = sname->string_len; 845 size_t out_bytes_left = sname->string_len * FC_UTF8_MAX_LEN; 846 char *inbuf, *outbuf; 847 848 utf8 = malloc (out_bytes_left + 1); 849 if (!utf8) 850 { 851 iconv_close (cd); 852 return 0; 853 } 854 855 outbuf = (char *) utf8; 856 inbuf = (char *) sname->string; 857 858 while (in_bytes_left) 859 { 860 size_t did = iconv (cd, 861 &inbuf, &in_bytes_left, 862 &outbuf, &out_bytes_left); 863 if (did == (size_t) (-1)) 864 { 865 iconv_close (cd); 866 free (utf8); 867 if (!redecoded) 868 { 869 /* Regard the encoding as UTF-16BE and try again. */ 870 redecoded = FcTrue; 871 fromcode = "UTF-16BE"; 872 goto retry; 873 } 874 return 0; 875 } 876 } 877 iconv_close (cd); 878 *outbuf = '\0'; 879 goto done; 880 } 881#else 882 if (!redecoded) 883 { 884 /* Regard the encoding as UTF-16BE and try again. */ 885 redecoded = FcTrue; 886 fromcode = "UTF-16BE"; 887 goto retry; 888 } 889#endif 890 return 0; 891done: 892 if (FcStrCmpIgnoreBlanksAndCase (utf8, (FcChar8 *) "") == 0) 893 { 894 free (utf8); 895 return 0; 896 } 897 return utf8; 898} 899 900static const FcChar8 * 901FcSfntNameLanguage (FT_SfntName *sname) 902{ 903 int i; 904 FT_UShort platform_id = sname->platform_id; 905 FT_UShort language_id = sname->language_id; 906 907 /* 908 * Many names encoded for TT_PLATFORM_MACINTOSH are broken 909 * in various ways. Kludge around them. 910 */ 911 if (platform_id == TT_PLATFORM_MACINTOSH && 912 sname->encoding_id == TT_MAC_ID_ROMAN && 913 FcLooksLikeSJIS (sname->string, sname->string_len)) 914 { 915 language_id = TT_MAC_LANGID_JAPANESE; 916 } 917 918 for (i = 0; i < NUM_FC_FT_LANGUAGE; i++) 919 if (fcFtLanguage[i].platform_id == platform_id && 920 (fcFtLanguage[i].language_id == TT_LANGUAGE_DONT_CARE || 921 fcFtLanguage[i].language_id == language_id)) 922 { 923 if (fcFtLanguage[i].lang[0] == '\0') 924 return NULL; 925 else 926 return (FcChar8 *) fcFtLanguage[i].lang; 927 } 928 return 0; 929} 930 931static const FcChar8 * 932FcNoticeFoundry(const FT_String *notice) 933{ 934 int i; 935 936 if (notice) 937 for(i = 0; i < NUM_NOTICE_FOUNDRIES; i++) 938 { 939 const char *n = FcNoticeFoundries[i][0]; 940 const char *f = FcNoticeFoundries[i][1]; 941 942 if (strstr ((const char *) notice, n)) 943 return (const FcChar8 *) f; 944 } 945 return 0; 946} 947 948typedef struct _FcStringConst { 949 const FcChar8 *name; 950 int value; 951} FcStringConst; 952 953static int 954FcStringIsConst (const FcChar8 *string, 955 const FcStringConst *c, 956 int nc) 957{ 958 int i; 959 960 for (i = 0; i < nc; i++) 961 if (FcStrCmpIgnoreBlanksAndCase (string, c[i].name) == 0) 962 return c[i].value; 963 return -1; 964} 965 966static int 967FcStringContainsConst (const FcChar8 *string, 968 const FcStringConst *c, 969 int nc) 970{ 971 int i; 972 973 for (i = 0; i < nc; i++) 974 { 975 if (c[i].name[0] == '<') 976 { 977 if (FcStrContainsWord (string, c[i].name + 1)) 978 return c[i].value; 979 } 980 else 981 { 982 if (FcStrContainsIgnoreBlanksAndCase (string, c[i].name)) 983 return c[i].value; 984 } 985 } 986 return -1; 987} 988 989typedef FcChar8 *FC8; 990 991static const FcStringConst weightConsts[] = { 992 { (FC8) "thin", FC_WEIGHT_THIN }, 993 { (FC8) "extralight", FC_WEIGHT_EXTRALIGHT }, 994 { (FC8) "ultralight", FC_WEIGHT_ULTRALIGHT }, 995 { (FC8) "demilight", FC_WEIGHT_DEMILIGHT }, 996 { (FC8) "semilight", FC_WEIGHT_SEMILIGHT }, 997 { (FC8) "light", FC_WEIGHT_LIGHT }, 998 { (FC8) "book", FC_WEIGHT_BOOK }, 999 { (FC8) "regular", FC_WEIGHT_REGULAR }, 1000 { (FC8) "normal", FC_WEIGHT_NORMAL }, 1001 { (FC8) "medium", FC_WEIGHT_MEDIUM }, 1002 { (FC8) "demibold", FC_WEIGHT_DEMIBOLD }, 1003 { (FC8) "demi", FC_WEIGHT_DEMIBOLD }, 1004 { (FC8) "semibold", FC_WEIGHT_SEMIBOLD }, 1005 { (FC8) "extrabold", FC_WEIGHT_EXTRABOLD }, 1006 { (FC8) "superbold", FC_WEIGHT_EXTRABOLD }, 1007 { (FC8) "ultrabold", FC_WEIGHT_ULTRABOLD }, 1008 { (FC8) "bold", FC_WEIGHT_BOLD }, 1009 { (FC8) "ultrablack", FC_WEIGHT_ULTRABLACK }, 1010 { (FC8) "superblack", FC_WEIGHT_EXTRABLACK }, 1011 { (FC8) "extrablack", FC_WEIGHT_EXTRABLACK }, 1012 { (FC8) "<ultra", FC_WEIGHT_ULTRABOLD }, /* only if a word */ 1013 { (FC8) "black", FC_WEIGHT_BLACK }, 1014 { (FC8) "heavy", FC_WEIGHT_HEAVY }, 1015}; 1016 1017#define NUM_WEIGHT_CONSTS (int) (sizeof (weightConsts) / sizeof (weightConsts[0])) 1018 1019#define FcIsWeight(s) FcStringIsConst(s,weightConsts,NUM_WEIGHT_CONSTS) 1020#define FcContainsWeight(s) FcStringContainsConst (s,weightConsts,NUM_WEIGHT_CONSTS) 1021 1022static const FcStringConst widthConsts[] = { 1023 { (FC8) "ultracondensed", FC_WIDTH_ULTRACONDENSED }, 1024 { (FC8) "extracondensed", FC_WIDTH_EXTRACONDENSED }, 1025 { (FC8) "semicondensed", FC_WIDTH_SEMICONDENSED }, 1026 { (FC8) "condensed", FC_WIDTH_CONDENSED }, /* must be after *condensed */ 1027 { (FC8) "normal", FC_WIDTH_NORMAL }, 1028 { (FC8) "semiexpanded", FC_WIDTH_SEMIEXPANDED }, 1029 { (FC8) "extraexpanded", FC_WIDTH_EXTRAEXPANDED }, 1030 { (FC8) "ultraexpanded", FC_WIDTH_ULTRAEXPANDED }, 1031 { (FC8) "expanded", FC_WIDTH_EXPANDED }, /* must be after *expanded */ 1032 { (FC8) "extended", FC_WIDTH_EXPANDED }, 1033}; 1034 1035#define NUM_WIDTH_CONSTS (int) (sizeof (widthConsts) / sizeof (widthConsts[0])) 1036 1037#define FcIsWidth(s) FcStringIsConst(s,widthConsts,NUM_WIDTH_CONSTS) 1038#define FcContainsWidth(s) FcStringContainsConst (s,widthConsts,NUM_WIDTH_CONSTS) 1039 1040static const FcStringConst slantConsts[] = { 1041 { (FC8) "italic", FC_SLANT_ITALIC }, 1042 { (FC8) "kursiv", FC_SLANT_ITALIC }, 1043 { (FC8) "oblique", FC_SLANT_OBLIQUE }, 1044}; 1045 1046#define NUM_SLANT_CONSTS (int) (sizeof (slantConsts) / sizeof (slantConsts[0])) 1047 1048#define FcContainsSlant(s) FcStringContainsConst (s,slantConsts,NUM_SLANT_CONSTS) 1049 1050static const FcStringConst decorativeConsts[] = { 1051 { (FC8) "shadow", FcTrue }, 1052 { (FC8) "caps", FcTrue }, 1053 { (FC8) "antiqua", FcTrue }, 1054 { (FC8) "romansc", FcTrue }, 1055 { (FC8) "embosed", FcTrue }, 1056 { (FC8) "dunhill", FcTrue }, 1057}; 1058 1059#define NUM_DECORATIVE_CONSTS (int) (sizeof (decorativeConsts) / sizeof (decorativeConsts[0])) 1060 1061#define FcContainsDecorative(s) FcStringContainsConst (s,decorativeConsts,NUM_DECORATIVE_CONSTS) 1062 1063static double 1064FcGetPixelSize (FT_Face face, int i) 1065{ 1066#if HAVE_FT_GET_BDF_PROPERTY 1067 if (face->num_fixed_sizes == 1) 1068 { 1069 BDF_PropertyRec prop; 1070 int rc; 1071 1072 rc = FT_Get_BDF_Property (face, "PIXEL_SIZE", &prop); 1073 if (rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER) 1074 return (double) prop.u.integer; 1075 } 1076#endif 1077 return (double) face->available_sizes[i].y_ppem / 64.0; 1078} 1079 1080static FcBool 1081FcStringInPatternElement (FcPattern *pat, FcObject obj, const FcChar8 *string) 1082{ 1083 FcPatternIter iter; 1084 FcValueListPtr l; 1085 1086 FcPatternIterStart (pat, &iter); 1087 if (!FcPatternFindObjectIter (pat, &iter, obj)) 1088 return FcFalse; 1089 for (l = FcPatternIterGetValues (pat, &iter); l; l = FcValueListNext (l)) 1090 { 1091 FcValue v = FcValueCanonicalize (&l->value); 1092 if (v.type != FcTypeString) 1093 break; 1094 if (!FcStrCmpIgnoreBlanksAndCase (v.u.s, string)) 1095 return FcTrue; 1096 } 1097 return FcFalse; 1098} 1099 1100static const FT_UShort platform_order[] = { 1101 TT_PLATFORM_MICROSOFT, 1102 TT_PLATFORM_APPLE_UNICODE, 1103 TT_PLATFORM_MACINTOSH, 1104 TT_PLATFORM_ISO, 1105}; 1106#define NUM_PLATFORM_ORDER (sizeof (platform_order) / sizeof (platform_order[0])) 1107 1108static const FT_UShort nameid_order[] = { 1109 TT_NAME_ID_WWS_FAMILY, 1110 TT_NAME_ID_TYPOGRAPHIC_FAMILY, 1111 TT_NAME_ID_FONT_FAMILY, 1112 TT_NAME_ID_MAC_FULL_NAME, 1113 TT_NAME_ID_FULL_NAME, 1114 TT_NAME_ID_WWS_SUBFAMILY, 1115 TT_NAME_ID_TYPOGRAPHIC_SUBFAMILY, 1116 TT_NAME_ID_FONT_SUBFAMILY, 1117 TT_NAME_ID_TRADEMARK, 1118 TT_NAME_ID_MANUFACTURER, 1119}; 1120 1121#define NUM_NAMEID_ORDER (sizeof (nameid_order) / sizeof (nameid_order[0])) 1122 1123typedef struct 1124{ 1125 unsigned int platform_id; 1126 unsigned int name_id; 1127 unsigned int encoding_id; 1128 unsigned int language_id; 1129 unsigned int idx; 1130} FcNameMapping; 1131 1132static FcBool 1133_is_english(int platform, int language) 1134{ 1135 FcBool ret = FcFalse; 1136 1137 switch (platform) 1138 { 1139 case TT_PLATFORM_MACINTOSH: 1140 ret = language == TT_MAC_LANGID_ENGLISH; 1141 break; 1142 case TT_PLATFORM_MICROSOFT: 1143 ret = language == TT_MS_LANGID_ENGLISH_UNITED_STATES; 1144 break; 1145 } 1146 return ret; 1147} 1148 1149static int 1150name_mapping_cmp (const void *pa, const void *pb) 1151{ 1152 const FcNameMapping *a = (const FcNameMapping *) pa; 1153 const FcNameMapping *b = (const FcNameMapping *) pb; 1154 1155 if (a->platform_id != b->platform_id) return (int) a->platform_id - (int) b->platform_id; 1156 if (a->name_id != b->name_id) return (int) a->name_id - (int) b->name_id; 1157 if (a->encoding_id != b->encoding_id) return (int) a->encoding_id - (int) b->encoding_id; 1158 if (a->language_id != b->language_id) return _is_english(a->platform_id, a->language_id) ? -1 : _is_english(b->platform_id, b->language_id) ? 1 : (int) a->language_id - (int) b->language_id; 1159 if (a->idx != b->idx) return (int) a->idx - (int) b->idx; 1160 1161 return 0; 1162} 1163 1164static int 1165FcFreeTypeGetFirstName (const FT_Face face, 1166 unsigned int platform, 1167 unsigned int nameid, 1168 FcNameMapping *mapping, 1169 unsigned int count, 1170 FT_SfntName *sname) 1171{ 1172 int min = 0, max = (int) count - 1; 1173 1174 while (min <= max) 1175 { 1176 int mid = (min + max) / 2; 1177 1178 if (FT_Get_Sfnt_Name (face, mapping[mid].idx, sname) != 0) 1179 return FcFalse; 1180 1181 if (platform < sname->platform_id || 1182 (platform == sname->platform_id && 1183 (nameid < sname->name_id || 1184 (nameid == sname->name_id && 1185 (mid && 1186 platform == mapping[mid - 1].platform_id && 1187 nameid == mapping[mid - 1].name_id 1188 ))))) 1189 max = mid - 1; 1190 else if (platform > sname->platform_id || 1191 (platform == sname->platform_id && 1192 nameid > sname->name_id)) 1193 min = mid + 1; 1194 else 1195 return mid; 1196 } 1197 1198 return -1; 1199} 1200 1201static FcPattern * 1202FcFreeTypeQueryFaceInternal (const FT_Face face, 1203 const FcChar8 *file, 1204 unsigned int id, 1205 FcCharSet **cs_share, 1206 FcLangSet **ls_share, 1207 FcNameMapping **nm_share) 1208{ 1209 FcPattern *pat; 1210 int slant = -1; 1211 double weight = -1; 1212 double width = -1; 1213 FcBool decorative = FcFalse; 1214 FcBool variable = FcFalse; 1215 FcBool variable_weight = FcFalse; 1216 FcBool variable_width = FcFalse; 1217 FcBool variable_size = FcFalse; 1218 FcCharSet *cs; 1219 FcLangSet *ls; 1220 FcNameMapping *name_mapping = NULL; 1221#if 0 1222 FcChar8 *family = 0; 1223#endif 1224 FcChar8 *complex_, *foundry_ = NULL; 1225 const FcChar8 *foundry = 0; 1226 int spacing; 1227 1228 /* Support for glyph-variation named-instances. */ 1229 FT_MM_Var *mmvar = NULL; 1230 FT_Var_Named_Style *instance = NULL; 1231 double weight_mult = 1.0; 1232 double width_mult = 1.0; 1233 1234 TT_OS2 *os2; 1235#if HAVE_FT_GET_PS_FONT_INFO 1236 PS_FontInfoRec psfontinfo; 1237#endif 1238#if HAVE_FT_GET_BDF_PROPERTY 1239 BDF_PropertyRec prop; 1240#endif 1241 TT_Header *head; 1242 const FcChar8 *exclusiveLang = 0; 1243 1244 int name_count = 0; 1245 int nfamily = 0; 1246 int nfamily_lang = 0; 1247 int nstyle = 0; 1248 int nstyle_lang = 0; 1249 int nfullname = 0; 1250 int nfullname_lang = 0; 1251 unsigned int p, n; 1252 1253 FcChar8 *style = 0; 1254 int st; 1255 1256 FcBool symbol = FcFalse; 1257 FT_Error ftresult; 1258 1259 FcInitDebug (); /* We might be called with no initizalization whatsoever. */ 1260 1261 pat = FcPatternCreate (); 1262 if (!pat) 1263 goto bail0; 1264 1265 { 1266 int has_outline = !!(face->face_flags & FT_FACE_FLAG_SCALABLE); 1267 int has_color = 0; 1268 1269 if (!FcPatternObjectAddBool (pat, FC_OUTLINE_OBJECT, has_outline)) 1270 goto bail1; 1271 1272 has_color = !!FT_HAS_COLOR (face); 1273 if (!FcPatternObjectAddBool (pat, FC_COLOR_OBJECT, has_color)) 1274 goto bail1; 1275 1276 /* All color fonts are designed to be scaled, even if they only have 1277 * bitmap strikes. Client is responsible to scale the bitmaps. This 1278 * is in contrast to non-color strikes... */ 1279 if (!FcPatternObjectAddBool (pat, FC_SCALABLE_OBJECT, has_outline || has_color)) 1280 goto bail1; 1281 } 1282 1283 ftresult = FT_Get_MM_Var (face, &mmvar); 1284 1285 if (id >> 16) 1286 { 1287 if (ftresult) 1288 goto bail1; 1289 1290 if (id >> 16 == 0x8000) 1291 { 1292 /* Query variable font itself. */ 1293 unsigned int i; 1294 for (i = 0; i < mmvar->num_axis; i++) 1295 { 1296 double min_value = mmvar->axis[i].minimum / (double) (1U << 16); 1297 double def_value = mmvar->axis[i].def / (double) (1U << 16); 1298 double max_value = mmvar->axis[i].maximum / (double) (1U << 16); 1299 FcObject obj = FC_INVALID_OBJECT; 1300 1301 if (min_value > def_value || def_value > max_value || min_value == max_value) 1302 continue; 1303 1304 switch (mmvar->axis[i].tag) 1305 { 1306 case FT_MAKE_TAG ('w','g','h','t'): 1307 obj = FC_WEIGHT_OBJECT; 1308 min_value = FcWeightFromOpenTypeDouble (min_value); 1309 max_value = FcWeightFromOpenTypeDouble (max_value); 1310 variable_weight = FcTrue; 1311 weight = 0; /* To stop looking for weight. */ 1312 break; 1313 1314 case FT_MAKE_TAG ('w','d','t','h'): 1315 obj = FC_WIDTH_OBJECT; 1316 /* Values in 'wdth' match Fontconfig FC_WIDTH_* scheme directly. */ 1317 variable_width = FcTrue; 1318 width = 0; /* To stop looking for width. */ 1319 break; 1320 1321 case FT_MAKE_TAG ('o','p','s','z'): 1322 obj = FC_SIZE_OBJECT; 1323 /* Values in 'opsz' match Fontconfig FC_SIZE, both are in points. */ 1324 variable_size = FcTrue; 1325 break; 1326 } 1327 1328 if (obj != FC_INVALID_OBJECT) 1329 { 1330 FcRange *r = FcRangeCreateDouble (min_value, max_value); 1331 if (!FcPatternObjectAddRange (pat, obj, r)) 1332 { 1333 FcRangeDestroy (r); 1334 goto bail1; 1335 } 1336 FcRangeDestroy (r); 1337 variable = FcTrue; 1338 } 1339 } 1340 1341 if (!variable) 1342 goto bail1; 1343 1344 id &= 0xFFFF; 1345 } 1346 else if ((id >> 16) - 1 < mmvar->num_namedstyles) 1347 { 1348 /* Pull out weight and width from named-instance. */ 1349 unsigned int i; 1350 1351 instance = &mmvar->namedstyle[(id >> 16) - 1]; 1352 1353 for (i = 0; i < mmvar->num_axis; i++) 1354 { 1355 double value = instance->coords[i] / (double) (1U << 16); 1356 double default_value = mmvar->axis[i].def / (double) (1U << 16); 1357 double mult = default_value ? value / default_value : 1; 1358 //printf ("named-instance, axis %d tag %lx value %g\n", i, mmvar->axis[i].tag, value); 1359 switch (mmvar->axis[i].tag) 1360 { 1361 case FT_MAKE_TAG ('w','g','h','t'): 1362 weight_mult = mult; 1363 break; 1364 1365 case FT_MAKE_TAG ('w','d','t','h'): 1366 width_mult = mult; 1367 break; 1368 1369 case FT_MAKE_TAG ('o','p','s','z'): 1370 if (!FcPatternObjectAddDouble (pat, FC_SIZE_OBJECT, value)) 1371 goto bail1; 1372 break; 1373 } 1374 } 1375 } 1376 else 1377 goto bail1; 1378 } 1379 else 1380 { 1381 if (!ftresult) 1382 { 1383 unsigned int i; 1384 for (i = 0; i < mmvar->num_axis; i++) 1385 { 1386 switch (mmvar->axis[i].tag) 1387 { 1388 case FT_MAKE_TAG ('o','p','s','z'): 1389 if (!FcPatternObjectAddDouble (pat, FC_SIZE_OBJECT, mmvar->axis[i].def / (double) (1U << 16))) 1390 goto bail1; 1391 variable_size = FcTrue; 1392 break; 1393 } 1394 } 1395 } 1396 else 1397 { 1398 /* ignore an error of FT_Get_MM_Var() */ 1399 } 1400 } 1401 if (!FcPatternObjectAddBool (pat, FC_VARIABLE_OBJECT, variable)) 1402 goto bail1; 1403 1404 /* 1405 * Get the OS/2 table 1406 */ 1407 os2 = (TT_OS2 *) FT_Get_Sfnt_Table (face, FT_SFNT_OS2); 1408 1409 /* 1410 * Look first in the OS/2 table for the foundry, if 1411 * not found here, the various notices will be searched for 1412 * that information, either from the sfnt name tables or 1413 * the Postscript FontInfo dictionary. Finally, the 1414 * BDF properties will queried. 1415 */ 1416 1417 if (os2 && os2->version >= 0x0001 && os2->version != 0xffff) 1418 { 1419 if (os2->achVendID[0] != 0) 1420 { 1421 foundry_ = (FcChar8 *) malloc (sizeof (os2->achVendID) + 1); 1422 memcpy ((void *)foundry_, os2->achVendID, sizeof (os2->achVendID)); 1423 foundry_[sizeof (os2->achVendID)] = 0; 1424 foundry = foundry_; 1425 } 1426 } 1427 1428 if (FcDebug () & FC_DBG_SCANV) 1429 printf ("\n"); 1430 /* 1431 * Grub through the name table looking for family 1432 * and style names. FreeType makes quite a hash 1433 * of them 1434 */ 1435 name_count = FT_Get_Sfnt_Name_Count (face); 1436 if (nm_share) 1437 name_mapping = *nm_share; 1438 if (!name_mapping) 1439 { 1440 int i = 0; 1441 name_mapping = malloc (name_count * sizeof (FcNameMapping)); 1442 if (!name_mapping) 1443 name_count = 0; 1444 for (i = 0; i < name_count; i++) 1445 { 1446 FcNameMapping *p = &name_mapping[i]; 1447 FT_SfntName sname; 1448 if (FT_Get_Sfnt_Name (face, i, &sname) == 0) 1449 { 1450 p->platform_id = sname.platform_id; 1451 p->name_id = sname.name_id; 1452 p->encoding_id = sname.encoding_id; 1453 p->language_id = sname.language_id; 1454 p->idx = i; 1455 } 1456 else 1457 { 1458 p->platform_id = 1459 p->name_id = 1460 p->encoding_id = 1461 p->language_id = 1462 p->idx = (unsigned int) -1; 1463 } 1464 } 1465 qsort (name_mapping, name_count, sizeof(FcNameMapping), name_mapping_cmp); 1466 1467 if (nm_share) 1468 *nm_share = name_mapping; 1469 } 1470 for (p = 0; p < NUM_PLATFORM_ORDER; p++) 1471 { 1472 int platform = platform_order[p]; 1473 1474 /* 1475 * Order nameids so preferred names appear first 1476 * in the resulting list 1477 */ 1478 for (n = 0; n < NUM_NAMEID_ORDER; n++) 1479 { 1480 FT_SfntName sname; 1481 int nameidx; 1482 const FcChar8 *lang; 1483 int *np = 0, *nlangp = 0; 1484 size_t len; 1485 int nameid, lookupid; 1486 FcObject obj = FC_INVALID_OBJECT, objlang = FC_INVALID_OBJECT; 1487 1488 nameid = lookupid = nameid_order[n]; 1489 1490 if (instance) 1491 { 1492 /* For named-instances, we skip regular style nameIDs, 1493 * and treat the instance's nameid as FONT_SUBFAMILY. 1494 * Postscript name is automatically handled by FreeType. */ 1495 if (nameid == TT_NAME_ID_WWS_SUBFAMILY || 1496 nameid == TT_NAME_ID_TYPOGRAPHIC_SUBFAMILY || 1497 nameid == TT_NAME_ID_FULL_NAME) 1498 continue; 1499 1500 if (nameid == TT_NAME_ID_FONT_SUBFAMILY) 1501 lookupid = instance->strid; 1502 } 1503 1504 nameidx = FcFreeTypeGetFirstName (face, platform, lookupid, 1505 name_mapping, name_count, 1506 &sname); 1507 if (nameidx == -1) 1508 continue; 1509 do 1510 { 1511 switch (nameid) { 1512 case TT_NAME_ID_WWS_FAMILY: 1513 case TT_NAME_ID_TYPOGRAPHIC_FAMILY: 1514 case TT_NAME_ID_FONT_FAMILY: 1515#if 0 1516 case TT_NAME_ID_UNIQUE_ID: 1517#endif 1518 if (FcDebug () & FC_DBG_SCANV) 1519 printf ("found family (n %2d p %d e %d l 0x%04x)", 1520 sname.name_id, sname.platform_id, 1521 sname.encoding_id, sname.language_id); 1522 1523 obj = FC_FAMILY_OBJECT; 1524 objlang = FC_FAMILYLANG_OBJECT; 1525 np = &nfamily; 1526 nlangp = &nfamily_lang; 1527 break; 1528 case TT_NAME_ID_MAC_FULL_NAME: 1529 case TT_NAME_ID_FULL_NAME: 1530 if (variable) 1531 break; 1532 if (FcDebug () & FC_DBG_SCANV) 1533 printf ("found full (n %2d p %d e %d l 0x%04x)", 1534 sname.name_id, sname.platform_id, 1535 sname.encoding_id, sname.language_id); 1536 1537 obj = FC_FULLNAME_OBJECT; 1538 objlang = FC_FULLNAMELANG_OBJECT; 1539 np = &nfullname; 1540 nlangp = &nfullname_lang; 1541 break; 1542 case TT_NAME_ID_WWS_SUBFAMILY: 1543 case TT_NAME_ID_TYPOGRAPHIC_SUBFAMILY: 1544 case TT_NAME_ID_FONT_SUBFAMILY: 1545 if (variable) 1546 break; 1547 if (FcDebug () & FC_DBG_SCANV) 1548 printf ("found style (n %2d p %d e %d l 0x%04x) ", 1549 sname.name_id, sname.platform_id, 1550 sname.encoding_id, sname.language_id); 1551 1552 obj = FC_STYLE_OBJECT; 1553 objlang = FC_STYLELANG_OBJECT; 1554 np = &nstyle; 1555 nlangp = &nstyle_lang; 1556 break; 1557 case TT_NAME_ID_TRADEMARK: 1558 case TT_NAME_ID_MANUFACTURER: 1559 /* If the foundry wasn't found in the OS/2 table, look here */ 1560 if(!foundry) 1561 { 1562 FcChar8 *utf8; 1563 utf8 = FcSfntNameTranscode (&sname); 1564 foundry = FcNoticeFoundry((FT_String *) utf8); 1565 free (utf8); 1566 } 1567 break; 1568 } 1569 if (obj != FC_INVALID_OBJECT) 1570 { 1571 FcChar8 *utf8, *pp; 1572 1573 utf8 = FcSfntNameTranscode (&sname); 1574 lang = FcSfntNameLanguage (&sname); 1575 1576 if (FcDebug () & FC_DBG_SCANV) 1577 printf ("%s\n", utf8 ? (char *)utf8 : "(null)"); 1578 1579 if (!utf8) 1580 continue; 1581 1582 /* Trim surrounding whitespace. */ 1583 pp = utf8; 1584 while (*pp == ' ') 1585 pp++; 1586 len = strlen ((const char *) pp); 1587 memmove (utf8, pp, len + 1); 1588 pp = utf8 + len; 1589 while (pp > utf8 && *(pp - 1) == ' ') 1590 pp--; 1591 *pp = 0; 1592 1593 if (FcStringInPatternElement (pat, obj, utf8)) 1594 { 1595 free (utf8); 1596 continue; 1597 } 1598 1599 /* add new element */ 1600 if (!FcPatternObjectAddString (pat, obj, utf8)) 1601 { 1602 free (utf8); 1603 goto bail1; 1604 } 1605 free (utf8); 1606 if (lang) 1607 { 1608 /* pad lang list with 'und' to line up with elt */ 1609 while (*nlangp < *np) 1610 { 1611 if (!FcPatternObjectAddString (pat, objlang, (FcChar8 *) "und")) 1612 goto bail1; 1613 ++*nlangp; 1614 } 1615 if (!FcPatternObjectAddString (pat, objlang, lang)) 1616 goto bail1; 1617 ++*nlangp; 1618 } 1619 ++*np; 1620 } 1621 } 1622 while (++nameidx < name_count && 1623 FT_Get_Sfnt_Name (face, name_mapping[nameidx].idx, &sname) == 0 && 1624 platform == sname.platform_id && lookupid == sname.name_id); 1625 } 1626 } 1627 if (!nm_share) 1628 { 1629 free (name_mapping); 1630 name_mapping = NULL; 1631 } 1632 1633 if (!nfamily && face->family_name && 1634 FcStrCmpIgnoreBlanksAndCase ((FcChar8 *) face->family_name, (FcChar8 *) "") != 0) 1635 { 1636 if (FcDebug () & FC_DBG_SCANV) 1637 printf ("using FreeType family \"%s\"\n", face->family_name); 1638 if (!FcPatternObjectAddString (pat, FC_FAMILY_OBJECT, (FcChar8 *) face->family_name)) 1639 goto bail1; 1640 if (!FcPatternObjectAddString (pat, FC_FAMILYLANG_OBJECT, (FcChar8 *) "en")) 1641 goto bail1; 1642 ++nfamily; 1643 } 1644 1645 if (!variable && !nstyle) 1646 { 1647 const FcChar8 *style_regular = (const FcChar8 *) "Regular"; 1648 const FcChar8 *ss; 1649 1650 if (face->style_name && 1651 FcStrCmpIgnoreBlanksAndCase ((FcChar8 *) face->style_name, (FcChar8 *) "") != 0) 1652 { 1653 if (FcDebug () & FC_DBG_SCANV) 1654 printf ("using FreeType style \"%s\"\n", face->style_name); 1655 1656 ss = (const FcChar8 *) face->style_name; 1657 } 1658 else 1659 { 1660 if (FcDebug () & FC_DBG_SCANV) 1661 printf ("applying default style Regular\n"); 1662 ss = style_regular; 1663 } 1664 if (!FcPatternObjectAddString (pat, FC_STYLE_OBJECT, ss)) 1665 goto bail1; 1666 if (!FcPatternObjectAddString (pat, FC_STYLELANG_OBJECT, (FcChar8 *) "en")) 1667 goto bail1; 1668 ++nstyle; 1669 } 1670 1671 if (!nfamily && file && *file) 1672 { 1673 FcChar8 *start, *end; 1674 FcChar8 *family; 1675 1676 start = (FcChar8 *) strrchr ((char *) file, '/'); 1677 if (start) 1678 start++; 1679 else 1680 start = (FcChar8 *) file; 1681 end = (FcChar8 *) strrchr ((char *) start, '.'); 1682 if (!end) 1683 end = start + strlen ((char *) start); 1684 /* freed below */ 1685 family = malloc (end - start + 1); 1686 strncpy ((char *) family, (char *) start, end - start); 1687 family[end - start] = '\0'; 1688 if (FcDebug () & FC_DBG_SCANV) 1689 printf ("using filename for family %s\n", family); 1690 if (!FcPatternObjectAddString (pat, FC_FAMILY_OBJECT, family)) 1691 { 1692 free (family); 1693 goto bail1; 1694 } 1695 if (!FcPatternObjectAddString (pat, FC_FAMILYLANG_OBJECT, (FcChar8 *) "en")) 1696 { 1697 free (family); 1698 goto bail1; 1699 } 1700 free (family); 1701 ++nfamily; 1702 } 1703 1704 /* Add the fullname into the cache */ 1705 if (!variable && !nfullname) 1706 { 1707 FcChar8 *family, *style, *lang = NULL; 1708 int n = 0; 1709 size_t len, i; 1710 FcStrBuf sbuf; 1711 1712 while (FcPatternObjectGetString (pat, FC_FAMILYLANG_OBJECT, n, &lang) == FcResultMatch) 1713 { 1714 if (FcStrCmp (lang, (const FcChar8 *) "en") == 0) 1715 break; 1716 n++; 1717 lang = NULL; 1718 } 1719 if (!lang) 1720 n = 0; 1721 if (FcPatternObjectGetString (pat, FC_FAMILY_OBJECT, n, &family) != FcResultMatch) 1722 goto bail1; 1723 len = strlen ((const char *) family); 1724 for (i = len; i > 0; i--) 1725 { 1726 if (!isspace (family[i-1])) 1727 break; 1728 } 1729 family[i] = 0; 1730 n = 0; 1731 while (FcPatternObjectGetString (pat, FC_STYLELANG_OBJECT, n, &lang) == FcResultMatch) 1732 { 1733 if (FcStrCmp (lang, (const FcChar8 *) "en") == 0) 1734 break; 1735 n++; 1736 lang = NULL; 1737 } 1738 if (!lang) 1739 n = 0; 1740 if (FcPatternObjectGetString (pat, FC_STYLE_OBJECT, n, &style) != FcResultMatch) 1741 goto bail1; 1742 len = strlen ((const char *) style); 1743 for (i = 0; style[i] != 0 && isspace (style[i]); i++); 1744 memmove (style, &style[i], len - i); 1745 FcStrBufInit (&sbuf, NULL, 0); 1746 FcStrBufString (&sbuf, family); 1747 FcStrBufChar (&sbuf, ' '); 1748 FcStrBufString (&sbuf, style); 1749 if (!FcPatternObjectAddString (pat, FC_FULLNAME_OBJECT, FcStrBufDoneStatic (&sbuf))) 1750 { 1751 FcStrBufDestroy (&sbuf); 1752 goto bail1; 1753 } 1754 FcStrBufDestroy (&sbuf); 1755 if (!FcPatternObjectAddString (pat, FC_FULLNAMELANG_OBJECT, (const FcChar8 *) "en")) 1756 goto bail1; 1757 ++nfullname; 1758 } 1759 /* Add the PostScript name into the cache */ 1760 if (!variable) 1761 { 1762 char psname[256]; 1763 const char *tmp; 1764 tmp = FT_Get_Postscript_Name (face); 1765 if (!tmp) 1766 { 1767 unsigned int i; 1768 FcChar8 *family, *familylang = NULL; 1769 size_t len; 1770 int n = 0; 1771 1772 /* Workaround when FT_Get_Postscript_Name didn't give any name. 1773 * try to find out the English family name and convert. 1774 */ 1775 while (FcPatternObjectGetString (pat, FC_FAMILYLANG_OBJECT, n, &familylang) == FcResultMatch) 1776 { 1777 if (FcStrCmp (familylang, (const FcChar8 *)"en") == 0) 1778 break; 1779 n++; 1780 familylang = NULL; 1781 } 1782 if (!familylang) 1783 n = 0; 1784 1785 if (FcPatternObjectGetString (pat, FC_FAMILY_OBJECT, n, &family) != FcResultMatch) 1786 goto bail1; 1787 len = strlen ((const char *)family); 1788 /* the literal name in PostScript Language is limited to 127 characters though, 1789 * It is the architectural limit. so assuming 255 characters may works enough. 1790 */ 1791 for (i = 0; i < len && i < 255; i++) 1792 { 1793 /* those characters are not allowed to be the literal name in PostScript */ 1794 static const char exclusive_chars[] = "\x04()/<>[]{}\t\f\r\n "; 1795 1796 if (strchr(exclusive_chars, family[i]) != NULL) 1797 psname[i] = '-'; 1798 else 1799 psname[i] = family[i]; 1800 } 1801 psname[i] = 0; 1802 } 1803 else 1804 { 1805 strncpy (psname, tmp, 255); 1806 psname[255] = 0; 1807 } 1808 if (!FcPatternObjectAddString (pat, FC_POSTSCRIPT_NAME_OBJECT, (const FcChar8 *)psname)) 1809 goto bail1; 1810 } 1811 1812 if (file && *file && !FcPatternObjectAddString (pat, FC_FILE_OBJECT, file)) 1813 goto bail1; 1814 1815 if (!FcPatternObjectAddInteger (pat, FC_INDEX_OBJECT, id)) 1816 goto bail1; 1817 1818#if 0 1819 /* 1820 * don't even try this -- CJK 'monospace' fonts are really 1821 * dual width, and most other fonts don't bother to set 1822 * the attribute. Sigh. 1823 */ 1824 if ((face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) != 0) 1825 if (!FcPatternObjectAddInteger (pat, FC_SPACING_OBJECT, FC_MONO)) 1826 goto bail1; 1827#endif 1828 1829 /* 1830 * Find the font revision (if available) 1831 */ 1832 head = (TT_Header *) FT_Get_Sfnt_Table (face, ft_sfnt_head); 1833 if (head) 1834 { 1835 if (!FcPatternObjectAddInteger (pat, FC_FONTVERSION_OBJECT, head->Font_Revision)) 1836 goto bail1; 1837 } 1838 else 1839 { 1840 if (!FcPatternObjectAddInteger (pat, FC_FONTVERSION_OBJECT, 0)) 1841 goto bail1; 1842 } 1843 if (!FcPatternObjectAddInteger (pat, FC_ORDER_OBJECT, 0)) 1844 goto bail1; 1845 1846 if (os2 && os2->version >= 0x0001 && os2->version != 0xffff) 1847 { 1848 unsigned int i; 1849 for (i = 0; i < NUM_CODE_PAGE_RANGE; i++) 1850 { 1851 FT_ULong bits; 1852 int bit; 1853 if (FcCodePageRange[i].bit < 32) 1854 { 1855 bits = os2->ulCodePageRange1; 1856 bit = FcCodePageRange[i].bit; 1857 } 1858 else 1859 { 1860 bits = os2->ulCodePageRange2; 1861 bit = FcCodePageRange[i].bit - 32; 1862 } 1863 if (bits & (1U << bit)) 1864 { 1865 /* 1866 * If the font advertises support for multiple 1867 * "exclusive" languages, then include support 1868 * for any language found to have coverage 1869 */ 1870 if (exclusiveLang) 1871 { 1872 exclusiveLang = 0; 1873 break; 1874 } 1875 exclusiveLang = FcCodePageRange[i].lang; 1876 } 1877 } 1878 } 1879 1880 if (os2 && os2->version != 0xffff) 1881 { 1882 weight = os2->usWeightClass; 1883 weight = FcWeightFromOpenTypeDouble (weight * weight_mult); 1884 if ((FcDebug() & FC_DBG_SCANV) && weight != -1) 1885 printf ("\tos2 weight class %d multiplier %g maps to weight %g\n", 1886 os2->usWeightClass, weight_mult, weight); 1887 1888 switch (os2->usWidthClass) { 1889 case 1: width = FC_WIDTH_ULTRACONDENSED; break; 1890 case 2: width = FC_WIDTH_EXTRACONDENSED; break; 1891 case 3: width = FC_WIDTH_CONDENSED; break; 1892 case 4: width = FC_WIDTH_SEMICONDENSED; break; 1893 case 5: width = FC_WIDTH_NORMAL; break; 1894 case 6: width = FC_WIDTH_SEMIEXPANDED; break; 1895 case 7: width = FC_WIDTH_EXPANDED; break; 1896 case 8: width = FC_WIDTH_EXTRAEXPANDED; break; 1897 case 9: width = FC_WIDTH_ULTRAEXPANDED; break; 1898 } 1899 width *= width_mult; 1900 if ((FcDebug() & FC_DBG_SCANV) && width != -1) 1901 printf ("\tos2 width class %d multiplier %g maps to width %g\n", 1902 os2->usWidthClass, width_mult, width); 1903 } 1904 if (os2 && (complex_ = FcFontCapabilities(face))) 1905 { 1906 if (!FcPatternObjectAddString (pat, FC_CAPABILITY_OBJECT, complex_)) 1907 { 1908 free (complex_); 1909 goto bail1; 1910 } 1911 free (complex_); 1912 } 1913 1914 if (!FcPatternObjectAddBool (pat, FC_FONT_HAS_HINT_OBJECT, FcFontHasHint (face))) 1915 goto bail1; 1916 1917 if (!variable_size && os2 && os2->version >= 0x0005 && os2->version != 0xffff) 1918 { 1919 double lower_size, upper_size; 1920 FcRange *r; 1921 1922 /* usLowerPointSize and usUpperPointSize is actually twips */ 1923 lower_size = os2->usLowerOpticalPointSize / 20.0L; 1924 upper_size = os2->usUpperOpticalPointSize / 20.0L; 1925 1926 if (lower_size == upper_size) 1927 { 1928 if (!FcPatternObjectAddDouble (pat, FC_SIZE_OBJECT, lower_size)) 1929 goto bail1; 1930 } 1931 else 1932 { 1933 r = FcRangeCreateDouble (lower_size, upper_size); 1934 if (!FcPatternObjectAddRange (pat, FC_SIZE_OBJECT, r)) 1935 { 1936 FcRangeDestroy (r); 1937 goto bail1; 1938 } 1939 FcRangeDestroy (r); 1940 } 1941 } 1942 1943 /* 1944 * Type 1: Check for FontInfo dictionary information 1945 * Code from g2@magestudios.net (Gerard Escalante) 1946 */ 1947 1948#if HAVE_FT_GET_PS_FONT_INFO 1949 if (FT_Get_PS_Font_Info(face, &psfontinfo) == 0) 1950 { 1951 if (weight == -1 && psfontinfo.weight) 1952 { 1953 weight = FcIsWeight ((FcChar8 *) psfontinfo.weight); 1954 if (FcDebug() & FC_DBG_SCANV) 1955 printf ("\tType1 weight %s maps to %g\n", 1956 psfontinfo.weight, weight); 1957 } 1958 1959#if 0 1960 /* 1961 * Don't bother with italic_angle; FreeType already extracts that 1962 * information for us and sticks it into style_flags 1963 */ 1964 if (psfontinfo.italic_angle) 1965 slant = FC_SLANT_ITALIC; 1966 else 1967 slant = FC_SLANT_ROMAN; 1968#endif 1969 1970 if(!foundry) 1971 foundry = FcNoticeFoundry(psfontinfo.notice); 1972 } 1973#endif /* HAVE_FT_GET_PS_FONT_INFO */ 1974 1975#if HAVE_FT_GET_BDF_PROPERTY 1976 /* 1977 * Finally, look for a FOUNDRY BDF property if no other 1978 * mechanism has managed to locate a foundry 1979 */ 1980 1981 if (!foundry) 1982 { 1983 int rc; 1984 rc = FT_Get_BDF_Property(face, "FOUNDRY", &prop); 1985 if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM) 1986 foundry = (FcChar8 *) prop.u.atom; 1987 } 1988 1989 if (width == -1) 1990 { 1991 if (FT_Get_BDF_Property(face, "RELATIVE_SETWIDTH", &prop) == 0 && 1992 (prop.type == BDF_PROPERTY_TYPE_INTEGER || 1993 prop.type == BDF_PROPERTY_TYPE_CARDINAL)) 1994 { 1995 FT_Int32 value; 1996 1997 if (prop.type == BDF_PROPERTY_TYPE_INTEGER) 1998 value = prop.u.integer; 1999 else 2000 value = (FT_Int32) prop.u.cardinal; 2001 switch ((value + 5) / 10) { 2002 case 1: width = FC_WIDTH_ULTRACONDENSED; break; 2003 case 2: width = FC_WIDTH_EXTRACONDENSED; break; 2004 case 3: width = FC_WIDTH_CONDENSED; break; 2005 case 4: width = FC_WIDTH_SEMICONDENSED; break; 2006 case 5: width = FC_WIDTH_NORMAL; break; 2007 case 6: width = FC_WIDTH_SEMIEXPANDED; break; 2008 case 7: width = FC_WIDTH_EXPANDED; break; 2009 case 8: width = FC_WIDTH_EXTRAEXPANDED; break; 2010 case 9: width = FC_WIDTH_ULTRAEXPANDED; break; 2011 } 2012 } 2013 if (width == -1 && 2014 FT_Get_BDF_Property (face, "SETWIDTH_NAME", &prop) == 0 && 2015 prop.type == BDF_PROPERTY_TYPE_ATOM && prop.u.atom != NULL) 2016 { 2017 width = FcIsWidth ((FcChar8 *) prop.u.atom); 2018 if (FcDebug () & FC_DBG_SCANV) 2019 printf ("\tsetwidth %s maps to %g\n", prop.u.atom, width); 2020 } 2021 } 2022#endif 2023 2024 /* 2025 * Look for weight, width and slant names in the style value 2026 */ 2027 for (st = 0; FcPatternGetString (pat, FC_STYLE, st, &style) == FcResultMatch; st++) 2028 { 2029 if (weight == -1) 2030 { 2031 weight = FcContainsWeight (style); 2032 if (FcDebug() & FC_DBG_SCANV) 2033 printf ("\tStyle %s maps to weight %g\n", style, weight); 2034 } 2035 if (width == -1) 2036 { 2037 width = FcContainsWidth (style); 2038 if (FcDebug() & FC_DBG_SCANV) 2039 printf ("\tStyle %s maps to width %g\n", style, width); 2040 } 2041 if (slant == -1) 2042 { 2043 slant = FcContainsSlant (style); 2044 if (FcDebug() & FC_DBG_SCANV) 2045 printf ("\tStyle %s maps to slant %d\n", style, slant); 2046 } 2047 if (decorative == FcFalse) 2048 { 2049 decorative = FcContainsDecorative (style) > 0; 2050 if (FcDebug() & FC_DBG_SCANV) 2051 printf ("\tStyle %s maps to decorative %d\n", style, decorative); 2052 } 2053 } 2054 /* 2055 * Pull default values from the FreeType flags if more 2056 * specific values not found above 2057 */ 2058 if (slant == -1) 2059 { 2060 slant = FC_SLANT_ROMAN; 2061 if (face->style_flags & FT_STYLE_FLAG_ITALIC) 2062 slant = FC_SLANT_ITALIC; 2063 } 2064 2065 if (weight == -1) 2066 { 2067 weight = FC_WEIGHT_MEDIUM; 2068 if (face->style_flags & FT_STYLE_FLAG_BOLD) 2069 weight = FC_WEIGHT_BOLD; 2070 } 2071 2072 if (width == -1) 2073 width = FC_WIDTH_NORMAL; 2074 2075 if (foundry == 0) 2076 foundry = (FcChar8 *) "unknown"; 2077 2078 if (!FcPatternObjectAddInteger (pat, FC_SLANT_OBJECT, slant)) 2079 goto bail1; 2080 2081 if (!variable_weight && !FcPatternObjectAddDouble (pat, FC_WEIGHT_OBJECT, weight)) 2082 goto bail1; 2083 2084 if (!variable_width && !FcPatternObjectAddDouble (pat, FC_WIDTH_OBJECT, width)) 2085 goto bail1; 2086 2087 if (!FcPatternObjectAddString (pat, FC_FOUNDRY_OBJECT, foundry)) 2088 goto bail1; 2089 2090 if (!FcPatternObjectAddBool (pat, FC_DECORATIVE_OBJECT, decorative)) 2091 goto bail1; 2092 2093 2094 /* 2095 * Compute the unicode coverage for the font 2096 */ 2097 if (cs_share && *cs_share) 2098 cs = FcCharSetCopy (*cs_share); 2099 else 2100 { 2101 cs = FcFreeTypeCharSet (face, NULL); 2102 if (cs_share) 2103 *cs_share = FcCharSetCopy (cs); 2104 } 2105 if (!cs) 2106 goto bail1; 2107 2108 /* The FcFreeTypeCharSet() chose the encoding; test it for symbol. */ 2109 symbol = face->charmap && face->charmap->encoding == FT_ENCODING_MS_SYMBOL; 2110 if (!FcPatternObjectAddBool (pat, FC_SYMBOL_OBJECT, symbol)) 2111 goto bail1; 2112 2113 spacing = FcFreeTypeSpacing (face); 2114#if HAVE_FT_GET_BDF_PROPERTY 2115 /* For PCF fonts, override the computed spacing with the one from 2116 the property */ 2117 if(FT_Get_BDF_Property(face, "SPACING", &prop) == 0 && 2118 prop.type == BDF_PROPERTY_TYPE_ATOM && prop.u.atom != NULL) { 2119 if(!strcmp(prop.u.atom, "c") || !strcmp(prop.u.atom, "C")) 2120 spacing = FC_CHARCELL; 2121 else if(!strcmp(prop.u.atom, "m") || !strcmp(prop.u.atom, "M")) 2122 spacing = FC_MONO; 2123 else if(!strcmp(prop.u.atom, "p") || !strcmp(prop.u.atom, "P")) 2124 spacing = FC_PROPORTIONAL; 2125 } 2126#endif 2127 2128 /* 2129 * Skip over PCF fonts that have no encoded characters; they're 2130 * usually just Unicode fonts transcoded to some legacy encoding 2131 * FT forces us to approximate whether a font is a PCF font 2132 * or not by whether it has any BDF properties. Try PIXEL_SIZE; 2133 * I don't know how to get a list of BDF properties on the font. -PL 2134 */ 2135 if (FcCharSetCount (cs) == 0) 2136 { 2137#if HAVE_FT_GET_BDF_PROPERTY 2138 if(FT_Get_BDF_Property(face, "PIXEL_SIZE", &prop) == 0) 2139 goto bail2; 2140#endif 2141 } 2142 2143 if (!FcPatternObjectAddCharSet (pat, FC_CHARSET_OBJECT, cs)) 2144 goto bail2; 2145 2146 if (!symbol) 2147 { 2148 if (ls_share && *ls_share) 2149 ls = FcLangSetCopy (*ls_share); 2150 else 2151 { 2152 ls = FcFreeTypeLangSet (cs, exclusiveLang); 2153 if (ls_share) 2154 *ls_share = FcLangSetCopy (ls); 2155 } 2156 if (!ls) 2157 goto bail2; 2158 } 2159 else 2160 { 2161 /* Symbol fonts don't cover any language, even though they 2162 * claim to support Latin1 range. */ 2163 ls = FcLangSetCreate (); 2164 } 2165 2166 if (!FcPatternObjectAddLangSet (pat, FC_LANG_OBJECT, ls)) 2167 { 2168 FcLangSetDestroy (ls); 2169 goto bail2; 2170 } 2171 2172 FcLangSetDestroy (ls); 2173 2174 if (spacing != FC_PROPORTIONAL) 2175 if (!FcPatternObjectAddInteger (pat, FC_SPACING_OBJECT, spacing)) 2176 goto bail2; 2177 2178 if (!(face->face_flags & FT_FACE_FLAG_SCALABLE)) 2179 { 2180 int i; 2181 for (i = 0; i < face->num_fixed_sizes; i++) 2182 if (!FcPatternObjectAddDouble (pat, FC_PIXEL_SIZE_OBJECT, 2183 FcGetPixelSize (face, i))) 2184 goto bail2; 2185 if (!FcPatternObjectAddBool (pat, FC_ANTIALIAS_OBJECT, FcFalse)) 2186 goto bail2; 2187 } 2188 2189 FcChar8* wrapper = NULL; 2190 2191#if HAVE_FT_GET_X11_FONT_FORMAT 2192 /* 2193 * Use the (not well documented or supported) X-specific function 2194 * from FreeType to figure out the font format 2195 */ 2196 { 2197 const char *font_format = FT_Get_X11_Font_Format (face); 2198 if (font_format) 2199 { 2200 if (!FcPatternObjectAddString (pat, FC_FONTFORMAT_OBJECT, (FcChar8 *) font_format)) 2201 goto bail2; 2202 2203 /* If this is not a SFNT font and format is CFF, then it is a standlone CFF font */ 2204 if (!FT_IS_SFNT (face) && !strcmp (font_format, "CFF")) 2205 wrapper = (FcChar8*) "CFF"; 2206 } 2207 } 2208#endif 2209 2210 if (!FcPatternObjectAddBool (pat, FC_NAMED_INSTANCE_OBJECT, !!(id > 0xffff))) 2211 goto bail2; 2212 2213 if (FT_IS_SFNT (face)) 2214 { 2215 /* If this is an SFNT wrapper, try to sniff the SFNT tag which is the 2216 * first 4 bytes, to see if it is a WOFF or WOFF2 wrapper. */ 2217 wrapper = (FcChar8*) "SFNT"; 2218 2219 char buf[4]; 2220 int fd = FcOpen ((char *) file, O_RDONLY); 2221 if (fd != -1 && read (fd, buf, 4)) 2222 { 2223 if (buf[0] == 'w' && buf[1] == 'O' && buf[2] == 'F') 2224 { 2225 if (buf[3] == 'F') 2226 wrapper = (FcChar8*) "WOFF"; 2227 else if (buf[3] == '2') 2228 wrapper = (FcChar8*) "WOFF2"; 2229 } 2230 } 2231 close (fd); 2232 } 2233 2234 if (wrapper) 2235 if (!FcPatternObjectAddString (pat, FC_FONT_WRAPPER_OBJECT, wrapper)) 2236 goto bail2; 2237 2238 /* 2239 * Drop our reference to the charset 2240 */ 2241 FcCharSetDestroy (cs); 2242 if (foundry_) 2243 free (foundry_); 2244 2245 if (mmvar) 2246 { 2247#ifdef HAVE_FT_DONE_MM_VAR 2248 if (face->glyph) 2249 FT_Done_MM_Var (face->glyph->library, mmvar); 2250#else 2251 free (mmvar); 2252#endif 2253 } 2254 2255 return pat; 2256 2257bail2: 2258 FcCharSetDestroy (cs); 2259bail1: 2260 FcPatternDestroy (pat); 2261 if (mmvar) 2262 { 2263#ifdef HAVE_FT_DONE_MM_VAR 2264 if (face->glyph) 2265 FT_Done_MM_Var (face->glyph->library, mmvar); 2266#else 2267 free (mmvar); 2268#endif 2269 } 2270 if (!nm_share && name_mapping) 2271 free (name_mapping); 2272 if (foundry_) 2273 free (foundry_); 2274bail0: 2275 return NULL; 2276} 2277 2278FcPattern * 2279FcFreeTypeQueryFace (const FT_Face face, 2280 const FcChar8 *file, 2281 unsigned int id, 2282 FcBlanks *blanks FC_UNUSED) 2283{ 2284 return FcFreeTypeQueryFaceInternal (face, file, id, NULL, NULL, NULL); 2285} 2286 2287FcPattern * 2288FcFreeTypeQuery(const FcChar8 *file, 2289 unsigned int id, 2290 FcBlanks *blanks FC_UNUSED, 2291 int *count) 2292{ 2293 FT_Face face; 2294 FT_Library ftLibrary; 2295 FcPattern *pat = NULL; 2296 2297 if (FT_Init_FreeType (&ftLibrary)) 2298 return NULL; 2299 2300 if (FT_New_Face (ftLibrary, (char *) file, id & 0x7FFFFFFF, &face)) 2301 goto bail; 2302 2303 if (count) 2304 *count = face->num_faces; 2305 2306 pat = FcFreeTypeQueryFaceInternal (face, file, id, NULL, NULL, NULL); 2307 2308 FT_Done_Face (face); 2309bail: 2310 FT_Done_FreeType (ftLibrary); 2311 return pat; 2312} 2313 2314unsigned int 2315FcFreeTypeQueryAll(const FcChar8 *file, 2316 unsigned int id, 2317 FcBlanks *blanks, 2318 int *count, 2319 FcFontSet *set) 2320{ 2321 FT_Face face = NULL; 2322 FT_Library ftLibrary = NULL; 2323 FcCharSet *cs = NULL; 2324 FcLangSet *ls = NULL; 2325 FcNameMapping *nm = NULL; 2326 FT_MM_Var *mm_var = NULL; 2327 FcBool index_set = id != (unsigned int) -1; 2328 unsigned int set_face_num = index_set ? id & 0xFFFF : 0; 2329 unsigned int set_instance_num = index_set ? id >> 16 : 0; 2330 unsigned int face_num = set_face_num; 2331 unsigned int instance_num = set_instance_num; 2332 unsigned int num_faces = 0; 2333 unsigned int num_instances = 0; 2334 unsigned int ret = 0; 2335 int err = 0; 2336 2337 if (count) 2338 *count = 0; 2339 2340 if (FT_Init_FreeType (&ftLibrary)) 2341 return 0; 2342 2343 if (FT_New_Face (ftLibrary, (const char *) file, face_num, &face)) 2344 goto bail; 2345 2346 num_faces = face->num_faces; 2347 num_instances = face->style_flags >> 16; 2348 if (num_instances && (!index_set || instance_num)) 2349 { 2350 FT_Get_MM_Var (face, &mm_var); 2351 if (!mm_var) 2352 num_instances = 0; 2353 } 2354 2355 if (count) 2356 *count = num_faces; 2357 2358 do { 2359 FcPattern *pat = NULL; 2360 2361 if (instance_num == 0x8000 || instance_num > num_instances) 2362 FT_Set_Var_Design_Coordinates (face, 0, NULL); /* Reset variations. */ 2363 else if (instance_num) 2364 { 2365 FT_Var_Named_Style *instance = &mm_var->namedstyle[instance_num - 1]; 2366 FT_Fixed *coords = instance->coords; 2367 FcBool nonzero; 2368 unsigned int i; 2369 2370 /* Skip named-instance that coincides with base instance. */ 2371 nonzero = FcFalse; 2372 for (i = 0; i < mm_var->num_axis; i++) 2373 if (coords[i] != mm_var->axis[i].def) 2374 { 2375 nonzero = FcTrue; 2376 break; 2377 } 2378 if (!nonzero) 2379 goto skip; 2380 2381 FT_Set_Var_Design_Coordinates (face, mm_var->num_axis, coords); 2382 } 2383 2384 id = ((instance_num << 16) + face_num); 2385 pat = FcFreeTypeQueryFaceInternal (face, (const FcChar8 *) file, id, &cs, &ls, &nm); 2386 2387 if (pat) 2388 { 2389 2390 ret++; 2391 if (!set || ! FcFontSetAdd (set, pat)) 2392 FcPatternDestroy (pat); 2393 } 2394 else if (instance_num != 0x8000) 2395 err = 1; 2396 2397skip: 2398 if (!index_set && instance_num < num_instances) 2399 instance_num++; 2400 else if (!index_set && instance_num == num_instances) 2401 instance_num = 0x8000; /* variable font */ 2402 else 2403 { 2404 free (nm); 2405 nm = NULL; 2406 FcLangSetDestroy (ls); 2407 ls = NULL; 2408 FcCharSetDestroy (cs); 2409 cs = NULL; 2410 FT_Done_Face (face); 2411 face = NULL; 2412#ifdef HAVE_FT_DONE_MM_VAR 2413 FT_Done_MM_Var (ftLibrary, mm_var); 2414#else 2415 free (mm_var); 2416#endif 2417 mm_var = NULL; 2418 2419 face_num++; 2420 instance_num = set_instance_num; 2421 2422 if (FT_New_Face (ftLibrary, (const char *) file, face_num, &face)) 2423 break; 2424 2425 num_instances = face->style_flags >> 16; 2426 if (num_instances && (!index_set || instance_num)) 2427 { 2428 FT_Get_MM_Var (face, &mm_var); 2429 if (!mm_var) 2430 num_instances = 0; 2431 } 2432 } 2433 } while (!err && (!index_set || face_num == set_face_num) && face_num < num_faces); 2434 2435bail: 2436#ifdef HAVE_FT_DONE_MM_VAR 2437 FT_Done_MM_Var (ftLibrary, mm_var); 2438#else 2439 free (mm_var); 2440#endif 2441 FcLangSetDestroy (ls); 2442 FcCharSetDestroy (cs); 2443 if (face) 2444 FT_Done_Face (face); 2445 FT_Done_FreeType (ftLibrary); 2446 if (nm) 2447 free (nm); 2448 2449 return ret; 2450} 2451 2452 2453static const FT_Encoding fcFontEncodings[] = { 2454 FT_ENCODING_UNICODE, 2455 FT_ENCODING_MS_SYMBOL 2456}; 2457 2458#define NUM_DECODE (int) (sizeof (fcFontEncodings) / sizeof (fcFontEncodings[0])) 2459 2460/* 2461 * Map a UCS4 glyph to a glyph index. Use all available encoding 2462 * tables to try and find one that works. This information is expected 2463 * to be cached by higher levels, so performance isn't critical 2464 */ 2465 2466FT_UInt 2467FcFreeTypeCharIndex (FT_Face face, FcChar32 ucs4) 2468{ 2469 int initial, offset, decode; 2470 FT_UInt glyphindex; 2471 2472 initial = 0; 2473 2474 if (!face) 2475 return 0; 2476 2477 /* 2478 * Find the current encoding 2479 */ 2480 if (face->charmap) 2481 { 2482 for (; initial < NUM_DECODE; initial++) 2483 if (fcFontEncodings[initial] == face->charmap->encoding) 2484 break; 2485 if (initial == NUM_DECODE) 2486 initial = 0; 2487 } 2488 /* 2489 * Check each encoding for the glyph, starting with the current one 2490 */ 2491 for (offset = 0; offset < NUM_DECODE; offset++) 2492 { 2493 decode = (initial + offset) % NUM_DECODE; 2494 if (!face->charmap || face->charmap->encoding != fcFontEncodings[decode]) 2495 if (FT_Select_Charmap (face, fcFontEncodings[decode]) != 0) 2496 continue; 2497 glyphindex = FT_Get_Char_Index (face, (FT_ULong) ucs4); 2498 if (glyphindex) 2499 return glyphindex; 2500 if (ucs4 < 0x100 && face->charmap && 2501 face->charmap->encoding == FT_ENCODING_MS_SYMBOL) 2502 { 2503 /* For symbol-encoded OpenType fonts, we duplicate the 2504 * U+F000..F0FF range at U+0000..U+00FF. That's what 2505 * Windows seems to do, and that's hinted about at: 2506 * http://www.microsoft.com/typography/otspec/recom.htm 2507 * under "Non-Standard (Symbol) Fonts". 2508 * 2509 * See thread with subject "Webdings and other MS symbol 2510 * fonts don't display" on mailing list from May 2015. 2511 */ 2512 glyphindex = FT_Get_Char_Index (face, (FT_ULong) ucs4 + 0xF000); 2513 if (glyphindex) 2514 return glyphindex; 2515 } 2516 } 2517 return 0; 2518} 2519 2520static inline int fc_min (int a, int b) { return a <= b ? a : b; } 2521static inline int fc_max (int a, int b) { return a >= b ? a : b; } 2522static inline FcBool fc_approximately_equal (int x, int y) 2523{ return abs (x - y) * 33 <= fc_max (abs (x), abs (y)); } 2524 2525static int 2526FcFreeTypeSpacing (FT_Face face) 2527{ 2528 FT_Int load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH | FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; 2529 FT_Pos advances[3] = {0}; 2530 unsigned int num_advances = 0; 2531 int o; 2532 2533 /* When using scalable fonts, only report those glyphs 2534 * which can be scaled; otherwise those fonts will 2535 * only be available at some sizes, and never when 2536 * transformed. Avoid this by simply reporting bitmap-only 2537 * glyphs as missing 2538 */ 2539 if (face->face_flags & FT_FACE_FLAG_SCALABLE) 2540 load_flags |= FT_LOAD_NO_BITMAP; 2541 2542 if (!(face->face_flags & FT_FACE_FLAG_SCALABLE) && 2543 face->num_fixed_sizes > 0 && 2544 FT_Get_Sfnt_Table (face, ft_sfnt_head)) 2545 { 2546 FT_Int strike_index = 0, i; 2547 /* Select the face closest to 16 pixels tall */ 2548 for (i = 1; i < face->num_fixed_sizes; i++) 2549 { 2550 if (abs (face->available_sizes[i].height - 16) < 2551 abs (face->available_sizes[strike_index].height - 16)) 2552 strike_index = i; 2553 } 2554 2555 FT_Select_Size (face, strike_index); 2556 } 2557 2558 for (o = 0; o < NUM_DECODE; o++) 2559 { 2560 FcChar32 ucs4; 2561 FT_UInt glyph; 2562 2563 if (FT_Select_Charmap (face, fcFontEncodings[o]) != 0) 2564 continue; 2565 2566 ucs4 = FT_Get_First_Char (face, &glyph); 2567 while (glyph != 0 && num_advances < 3) 2568 { 2569 FT_Pos advance = 0; 2570 if (!FT_Get_Advance (face, glyph, load_flags, &advance) && advance) 2571 { 2572 unsigned int j; 2573 for (j = 0; j < num_advances; j++) 2574 if (fc_approximately_equal (advance, advances[j])) 2575 break; 2576 if (j == num_advances) 2577 advances[num_advances++] = advance; 2578 } 2579 2580 ucs4 = FT_Get_Next_Char (face, ucs4, &glyph); 2581 } 2582 break; 2583 } 2584 2585 if (num_advances <= 1) 2586 return FC_MONO; 2587 else if (num_advances == 2 && 2588 fc_approximately_equal (fc_min (advances[0], advances[1]) * 2, 2589 fc_max (advances[0], advances[1]))) 2590 return FC_DUAL; 2591 else 2592 return FC_PROPORTIONAL; 2593} 2594 2595FcCharSet * 2596FcFreeTypeCharSet (FT_Face face, FcBlanks *blanks FC_UNUSED) 2597{ 2598 const FT_Int load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH | FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; 2599 FcCharSet *fcs; 2600 int o; 2601 2602 fcs = FcCharSetCreate (); 2603 if (!fcs) 2604 goto bail; 2605 2606#ifdef CHECK 2607 printf ("Family %s style %s\n", face->family_name, face->style_name); 2608#endif 2609 for (o = 0; o < NUM_DECODE; o++) 2610 { 2611 FcChar32 page, off, ucs4; 2612 FcCharLeaf *leaf; 2613 FT_UInt glyph; 2614 2615 if (FT_Select_Charmap (face, fcFontEncodings[o]) != 0) 2616 continue; 2617 2618 page = ~0; 2619 leaf = NULL; 2620 ucs4 = FT_Get_First_Char (face, &glyph); 2621 while (glyph != 0) 2622 { 2623 FcBool good = FcTrue; 2624 2625 /* CID fonts built by Adobe used to make ASCII control chars to cid1 2626 * (space glyph). As such, always check contour for those characters. */ 2627 if (ucs4 <= 0x001F) 2628 { 2629 if (FT_Load_Glyph (face, glyph, load_flags) || 2630 (face->glyph->format == FT_GLYPH_FORMAT_OUTLINE && 2631 face->glyph->outline.n_contours == 0)) 2632 good = FcFalse; 2633 } 2634 2635 if (good) 2636 { 2637 FcCharSetAddChar (fcs, ucs4); 2638 if ((ucs4 >> 8) != page) 2639 { 2640 page = (ucs4 >> 8); 2641 leaf = FcCharSetFindLeafCreate (fcs, ucs4); 2642 if (!leaf) 2643 goto bail; 2644 } 2645 off = ucs4 & 0xff; 2646 leaf->map[off >> 5] |= (1U << (off & 0x1f)); 2647 } 2648 2649 ucs4 = FT_Get_Next_Char (face, ucs4, &glyph); 2650 } 2651 if (fcFontEncodings[o] == FT_ENCODING_MS_SYMBOL) 2652 { 2653 /* For symbol-encoded OpenType fonts, we duplicate the 2654 * U+F000..F0FF range at U+0000..U+00FF. That's what 2655 * Windows seems to do, and that's hinted about at: 2656 * http://www.microsoft.com/typography/otspec/recom.htm 2657 * under "Non-Standard (Symbol) Fonts". 2658 * 2659 * See thread with subject "Webdings and other MS symbol 2660 * fonts don't display" on mailing list from May 2015. 2661 */ 2662 for (ucs4 = 0xF000; ucs4 < 0xF100; ucs4++) 2663 { 2664 if (FcCharSetHasChar (fcs, ucs4)) 2665 FcCharSetAddChar (fcs, ucs4 - 0xF000); 2666 } 2667 } 2668#ifdef CHECK 2669 for (ucs4 = 0x0020; ucs4 < 0x10000; ucs4++) 2670 { 2671 FcBool FT_Has, FC_Has; 2672 2673 FT_Has = FT_Get_Char_Index (face, ucs4) != 0; 2674 FC_Has = FcCharSetHasChar (fcs, ucs4); 2675 if (FT_Has != FC_Has) 2676 { 2677 printf ("0x%08x FT says %d FC says %d\n", ucs4, FT_Has, FC_Has); 2678 } 2679 } 2680#endif 2681 break; 2682 } 2683 2684 return fcs; 2685bail: 2686 FcCharSetDestroy (fcs); 2687 return 0; 2688} 2689 2690FcCharSet * 2691FcFreeTypeCharSetAndSpacing (FT_Face face, FcBlanks *blanks FC_UNUSED, int *spacing) 2692{ 2693 2694 if (spacing) 2695 *spacing = FcFreeTypeSpacing (face); 2696 2697 return FcFreeTypeCharSet (face, blanks); 2698} 2699 2700 2701#define TTAG_GPOS FT_MAKE_TAG( 'G', 'P', 'O', 'S' ) 2702#define TTAG_GSUB FT_MAKE_TAG( 'G', 'S', 'U', 'B' ) 2703#define TTAG_SILF FT_MAKE_TAG( 'S', 'i', 'l', 'f') 2704#define TTAG_prep FT_MAKE_TAG( 'p', 'r', 'e', 'p' ) 2705 2706#define OTLAYOUT_HEAD "otlayout:" 2707#define OTLAYOUT_HEAD_LEN 9 2708#define OTLAYOUT_ID_LEN 4 2709/* space + head + id */ 2710#define OTLAYOUT_LEN (1 + OTLAYOUT_HEAD_LEN + OTLAYOUT_ID_LEN) 2711 2712/* 2713 * This is a bit generous; the registry has only lower case and space 2714 * except for 'DFLT'. 2715 */ 2716#define FcIsSpace(x) (040 == (x)) 2717#define FcIsDigit(c) (('0' <= (c) && (c) <= '9')) 2718#define FcIsValidScript(x) (FcIsLower(x) || FcIsUpper (x) || FcIsDigit(x) || FcIsSpace(x)) 2719 2720static void 2721addtag(FcChar8 *complex_, FT_ULong tag) 2722{ 2723 FcChar8 tagstring[OTLAYOUT_ID_LEN + 1]; 2724 2725 tagstring[0] = (FcChar8)(tag >> 24), 2726 tagstring[1] = (FcChar8)(tag >> 16), 2727 tagstring[2] = (FcChar8)(tag >> 8), 2728 tagstring[3] = (FcChar8)(tag); 2729 tagstring[4] = '\0'; 2730 2731 /* skip tags which aren't alphanumeric, under the assumption that 2732 * they're probably broken 2733 */ 2734 if (!FcIsValidScript(tagstring[0]) || 2735 !FcIsValidScript(tagstring[1]) || 2736 !FcIsValidScript(tagstring[2]) || 2737 !FcIsValidScript(tagstring[3])) 2738 return; 2739 2740 if (*complex_ != '\0') 2741 strcat ((char *) complex_, " "); 2742 strcat ((char *) complex_, OTLAYOUT_HEAD); 2743 strcat ((char *) complex_, (char *) tagstring); 2744} 2745 2746static int 2747compareulong (const void *a, const void *b) 2748{ 2749 const FT_ULong *ua = (const FT_ULong *) a; 2750 const FT_ULong *ub = (const FT_ULong *) b; 2751 return *ua - *ub; 2752} 2753 2754static FcBool 2755FindTable (FT_Face face, FT_ULong tabletag) 2756{ 2757 FT_Stream stream = face->stream; 2758 FT_Error error; 2759 2760 if (!stream) 2761 return FcFalse; 2762 2763 if (( error = ftglue_face_goto_table( face, tabletag, stream ) )) 2764 return FcFalse; 2765 2766 return FcTrue; 2767} 2768 2769static int 2770GetScriptTags(FT_Face face, FT_ULong tabletag, FT_ULong **stags) 2771{ 2772 FT_ULong cur_offset, new_offset, base_offset; 2773 FT_Stream stream = face->stream; 2774 FT_Error error; 2775 FT_UShort n, p; 2776 int script_count; 2777 2778 if (!stream) 2779 return 0; 2780 2781 if (( error = ftglue_face_goto_table( face, tabletag, stream ) )) 2782 return 0; 2783 2784 base_offset = ftglue_stream_pos ( stream ); 2785 2786 /* skip version */ 2787 2788 if ( ftglue_stream_seek ( stream, base_offset + 4L ) || ftglue_stream_frame_enter( stream, 2L ) ) 2789 return 0; 2790 2791 new_offset = GET_UShort() + base_offset; 2792 2793 ftglue_stream_frame_exit( stream ); 2794 2795 cur_offset = ftglue_stream_pos( stream ); 2796 2797 if ( ftglue_stream_seek( stream, new_offset ) != FT_Err_Ok ) 2798 return 0; 2799 2800 base_offset = ftglue_stream_pos( stream ); 2801 2802 if ( ftglue_stream_frame_enter( stream, 2L ) ) 2803 return 0; 2804 2805 script_count = GET_UShort (); 2806 2807 ftglue_stream_frame_exit( stream ); 2808 2809 *stags = malloc(script_count * sizeof (FT_ULong)); 2810 if (!*stags) 2811 return 0; 2812 2813 p = 0; 2814 for ( n = 0; n < script_count; n++ ) 2815 { 2816 if ( ftglue_stream_frame_enter( stream, 6L ) ) 2817 goto Fail; 2818 2819 (*stags)[p] = GET_ULong (); 2820 new_offset = GET_UShort () + base_offset; 2821 2822 ftglue_stream_frame_exit( stream ); 2823 2824 cur_offset = ftglue_stream_pos( stream ); 2825 2826 error = ftglue_stream_seek( stream, new_offset ); 2827 2828 if ( error == FT_Err_Ok ) 2829 p++; 2830 2831 (void)ftglue_stream_seek( stream, cur_offset ); 2832 } 2833 2834 if (!p) 2835 goto Fail; 2836 2837 /* sort the tag list before returning it */ 2838 qsort(*stags, p, sizeof(FT_ULong), compareulong); 2839 2840 return p; 2841 2842Fail: 2843 free(*stags); 2844 *stags = NULL; 2845 return 0; 2846} 2847 2848static FcChar8 * 2849FcFontCapabilities(FT_Face face) 2850{ 2851 FcBool issilgraphitefont = 0; 2852 FT_Error err; 2853 FT_ULong len = 0; 2854 FT_ULong *gsubtags=NULL, *gpostags=NULL; 2855 FT_UShort gsub_count=0, gpos_count=0; 2856 FT_ULong maxsize; 2857 FcChar8 *complex_ = NULL; 2858 int indx1 = 0, indx2 = 0; 2859 2860 err = FT_Load_Sfnt_Table(face, TTAG_SILF, 0, 0, &len); 2861 issilgraphitefont = ( err == FT_Err_Ok); 2862 2863 gpos_count = GetScriptTags(face, TTAG_GPOS, &gpostags); 2864 gsub_count = GetScriptTags(face, TTAG_GSUB, &gsubtags); 2865 2866 if (!issilgraphitefont && !gsub_count && !gpos_count) 2867 goto bail; 2868 2869 maxsize = (((FT_ULong) gpos_count + (FT_ULong) gsub_count) * OTLAYOUT_LEN + 2870 (issilgraphitefont ? 13 : 0)); 2871 complex_ = malloc (sizeof (FcChar8) * maxsize); 2872 if (!complex_) 2873 goto bail; 2874 2875 complex_[0] = '\0'; 2876 if (issilgraphitefont) 2877 strcpy((char *) complex_, "ttable:Silf "); 2878 2879 while ((indx1 < gsub_count) || (indx2 < gpos_count)) { 2880 if (indx1 == gsub_count) { 2881 addtag(complex_, gpostags[indx2]); 2882 indx2++; 2883 } else if ((indx2 == gpos_count) || (gsubtags[indx1] < gpostags[indx2])) { 2884 addtag(complex_, gsubtags[indx1]); 2885 indx1++; 2886 } else if (gsubtags[indx1] == gpostags[indx2]) { 2887 addtag(complex_, gsubtags[indx1]); 2888 indx1++; 2889 indx2++; 2890 } else { 2891 addtag(complex_, gpostags[indx2]); 2892 indx2++; 2893 } 2894 } 2895 if (FcDebug () & FC_DBG_SCANV) 2896 printf("complex_ features in this font: %s\n", complex_); 2897bail: 2898 free(gsubtags); 2899 free(gpostags); 2900 return complex_; 2901} 2902 2903static FcBool 2904FcFontHasHint (FT_Face face) 2905{ 2906 return FindTable (face, TTAG_prep); 2907} 2908 2909 2910#define __fcfreetype__ 2911#include "fcaliastail.h" 2912#include "fcftaliastail.h" 2913#undef __fcfreetype__ 2914