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