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