Imported Upstream version 2.13.0
[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 static FcBool
1140 FcFreeTypeGetName (const FT_Face face,
1141                    unsigned int  platform,
1142                    unsigned int  nameid,
1143                    FT_SfntName   *sname)
1144 {
1145     int min = 0, max = (int) FT_Get_Sfnt_Name_Count (face) - 1;
1146
1147     while (min <= max)
1148     {
1149         int mid = (min + max) / 2;
1150
1151         if (FT_Get_Sfnt_Name (face, mid, sname) != 0)
1152             return FcFalse;
1153
1154         if (platform < sname->platform_id || (platform == sname->platform_id && nameid < sname->name_id))
1155             max = mid - 1;
1156         else if (platform > sname->platform_id || (platform == sname->platform_id && nameid > sname->name_id))
1157             min = mid + 1;
1158         else
1159             return FcTrue;
1160     }
1161
1162     return FcFalse;
1163 }
1164
1165 static FcPattern *
1166 FcFreeTypeQueryFaceInternal (const FT_Face  face,
1167                              const FcChar8  *file,
1168                              unsigned int   id,
1169                              FcCharSet      **cs_share,
1170                              FcLangSet      **ls_share)
1171 {
1172     FcPattern       *pat;
1173     int             slant = -1;
1174     double          weight = -1;
1175     double          width = -1;
1176     FcBool          decorative = FcFalse;
1177     FcBool          variable = FcFalse;
1178     FcBool          variable_weight = FcFalse;
1179     FcBool          variable_width = FcFalse;
1180     FcBool          variable_size = FcFalse;
1181     FcCharSet       *cs;
1182     FcLangSet       *ls;
1183 #if 0
1184     FcChar8         *family = 0;
1185 #endif
1186     FcChar8         *complex_, *foundry_ = NULL;
1187     const FcChar8   *foundry = 0;
1188     int             spacing;
1189
1190     /* Support for glyph-variation named-instances. */
1191     FT_MM_Var       *master = NULL;
1192     FT_Var_Named_Style *instance = NULL;
1193     double          weight_mult = 1.0;
1194     double          width_mult = 1.0;
1195
1196     TT_OS2          *os2;
1197 #if HAVE_FT_GET_PS_FONT_INFO
1198     PS_FontInfoRec  psfontinfo;
1199 #endif
1200 #if HAVE_FT_GET_BDF_PROPERTY
1201     BDF_PropertyRec prop;
1202 #endif
1203     TT_Header       *head;
1204     const FcChar8   *exclusiveLang = 0;
1205
1206     int             nfamily = 0;
1207     int             nfamily_lang = 0;
1208     int             nstyle = 0;
1209     int             nstyle_lang = 0;
1210     int             nfullname = 0;
1211     int             nfullname_lang = 0;
1212     unsigned int    p, n;
1213
1214     FcChar8         *style = 0;
1215     int             st;
1216
1217     FcBool          symbol = FcFalse;
1218
1219     FcInitDebug (); /* We might be called with no initizalization whatsoever. */
1220
1221     pat = FcPatternCreate ();
1222     if (!pat)
1223         goto bail0;
1224
1225     {
1226         int has_outline = !!(face->face_flags & FT_FACE_FLAG_SCALABLE);
1227         int has_color = 0;
1228
1229         if (!FcPatternAddBool (pat, FC_OUTLINE, has_outline))
1230             goto bail1;
1231
1232         has_color = !!(face->face_flags & FT_FACE_FLAG_COLOR);
1233         if (!FcPatternAddBool (pat, FC_COLOR, has_color))
1234             goto bail1;
1235
1236         /* All color fonts are designed to be scaled, even if they only have
1237          * bitmap strikes.  Client is responsible to scale the bitmaps.  This
1238          * is in constrast to non-color strikes... */
1239         if (!FcPatternAddBool (pat, FC_SCALABLE, has_outline || has_color))
1240             goto bail1;
1241     }
1242
1243     if (id >> 16)
1244     {
1245       if (FT_Get_MM_Var (face, &master))
1246           goto bail1;
1247
1248       if (id >> 16 == 0x8000)
1249       {
1250           /* Query variable font itself. */
1251           unsigned int i;
1252
1253           for (i = 0; i < master->num_axis; i++)
1254           {
1255               double min_value = master->axis[i].minimum / (double) (1 << 16);
1256               double def_value = master->axis[i].def / (double) (1 << 16);
1257               double max_value = master->axis[i].maximum / (double) (1 << 16);
1258               const char *elt = NULL;
1259
1260               if (min_value > def_value || def_value > max_value || min_value == max_value)
1261                   continue;
1262
1263               switch (master->axis[i].tag)
1264               {
1265                 case FT_MAKE_TAG ('w','g','h','t'):
1266                   elt = FC_WEIGHT;
1267                   min_value = FcWeightFromOpenTypeDouble (min_value);
1268                   max_value = FcWeightFromOpenTypeDouble (max_value);
1269                   variable_weight = FcTrue;
1270                   weight = 0; /* To stop looking for weight. */
1271                   break;
1272
1273                 case FT_MAKE_TAG ('w','d','t','h'):
1274                   elt = FC_WIDTH;
1275                   /* Values in 'wdth' match Fontconfig FC_WIDTH_* scheme directly. */
1276                   variable_width = FcTrue;
1277                   width = 0; /* To stop looking for width. */
1278                   break;
1279
1280                 case FT_MAKE_TAG ('o','p','s','z'):
1281                   elt = FC_SIZE;
1282                   /* Values in 'opsz' match Fontconfig FC_SIZE, both are in points. */
1283                   variable_size = FcTrue;
1284                   break;
1285               }
1286
1287               if (elt)
1288               {
1289                   FcRange *r = FcRangeCreateDouble (min_value, max_value);
1290                   if (!FcPatternAddRange (pat, elt, r))
1291                   {
1292                       FcRangeDestroy (r);
1293                       goto bail1;
1294                   }
1295                   FcRangeDestroy (r);
1296                   variable = FcTrue;
1297               }
1298           }
1299
1300           if (!variable)
1301               goto bail1;
1302
1303           id &= 0xFFFF;
1304       }
1305       else if ((id >> 16) - 1 < master->num_namedstyles)
1306       {
1307           /* Pull out weight and width from named-instance. */
1308           unsigned int i;
1309
1310           instance = &master->namedstyle[(id >> 16) - 1];
1311
1312           for (i = 0; i < master->num_axis; i++)
1313           {
1314               double value = instance->coords[i] / (double) (1 << 16);
1315               double default_value = master->axis[i].def / (double) (1 << 16);
1316               double mult = default_value ? value / default_value : 1;
1317               //printf ("named-instance, axis %d tag %lx value %g\n", i, master->axis[i].tag, value);
1318               switch (master->axis[i].tag)
1319               {
1320                 case FT_MAKE_TAG ('w','g','h','t'):
1321                   weight_mult = mult;
1322                   break;
1323
1324                 case FT_MAKE_TAG ('w','d','t','h'):
1325                   width_mult = mult;
1326                   break;
1327
1328                 case FT_MAKE_TAG ('o','p','s','z'):
1329                   if (!FcPatternAddDouble (pat, FC_SIZE, value))
1330                       goto bail1;
1331                   break;
1332             }
1333           }
1334         }
1335         else
1336             goto bail1;
1337     }
1338     if (!FcPatternAddBool (pat, FC_VARIABLE, variable))
1339         goto bail1;
1340
1341     /*
1342      * Get the OS/2 table
1343      */
1344     os2 = (TT_OS2 *) FT_Get_Sfnt_Table (face, FT_SFNT_OS2);
1345
1346     /*
1347      * Look first in the OS/2 table for the foundry, if
1348      * not found here, the various notices will be searched for
1349      * that information, either from the sfnt name tables or
1350      * the Postscript FontInfo dictionary.  Finally, the
1351      * BDF properties will queried.
1352      */
1353
1354     if (os2 && os2->version >= 0x0001 && os2->version != 0xffff)
1355     {
1356         if (os2->achVendID && os2->achVendID[0] != 0)
1357         {
1358             foundry_ = (FcChar8 *) malloc (sizeof (os2->achVendID) + 1);
1359             memcpy ((void *)foundry_, os2->achVendID, sizeof (os2->achVendID));
1360             foundry_[sizeof (os2->achVendID)] = 0;
1361             foundry = foundry_;
1362         }
1363     }
1364
1365     if (FcDebug () & FC_DBG_SCANV)
1366         printf ("\n");
1367     /*
1368      * Grub through the name table looking for family
1369      * and style names.  FreeType makes quite a hash
1370      * of them
1371      */
1372     for (p = 0; p < NUM_PLATFORM_ORDER; p++)
1373     {
1374         int platform = platform_order[p];
1375
1376         /*
1377          * Order nameids so preferred names appear first
1378          * in the resulting list
1379          */
1380         for (n = 0; n < NUM_NAMEID_ORDER; n++)
1381         {
1382             FT_SfntName sname;
1383             const FcChar8       *lang;
1384             const char  *elt = 0, *eltlang = 0;
1385             int         *np = 0, *nlangp = 0;
1386             size_t              len;
1387             int nameid, lookupid;
1388
1389             nameid = lookupid = nameid_order[n];
1390
1391             if (instance)
1392             {
1393                 /* For named-instances, we skip regular style nameIDs,
1394                  * and treat the instance's nameid as FONT_SUBFAMILY.
1395                  * Postscript name is automatically handled by FreeType. */
1396                 if (nameid == TT_NAME_ID_WWS_SUBFAMILY ||
1397                     nameid == TT_NAME_ID_PREFERRED_SUBFAMILY)
1398                     continue;
1399
1400                 if (nameid == TT_NAME_ID_FONT_SUBFAMILY)
1401                     lookupid = instance->strid;
1402             }
1403
1404             if (!FcFreeTypeGetName (face, platform, lookupid, &sname))
1405                 continue;
1406
1407             switch (nameid) {
1408             case TT_NAME_ID_WWS_FAMILY:
1409             case TT_NAME_ID_PREFERRED_FAMILY:
1410             case TT_NAME_ID_FONT_FAMILY:
1411 #if 0   
1412             case TT_NAME_ID_UNIQUE_ID:
1413 #endif
1414                 if (FcDebug () & FC_DBG_SCANV)
1415                     printf ("found family (n %2d p %d e %d l 0x%04x)",
1416                             sname.name_id, sname.platform_id,
1417                             sname.encoding_id, sname.language_id);
1418
1419                 elt = FC_FAMILY;
1420                 eltlang = FC_FAMILYLANG;
1421                 np = &nfamily;
1422                 nlangp = &nfamily_lang;
1423                 break;
1424             case TT_NAME_ID_MAC_FULL_NAME:
1425             case TT_NAME_ID_FULL_NAME:
1426                 if (FcDebug () & FC_DBG_SCANV)
1427                     printf ("found full   (n %2d p %d e %d l 0x%04x)",
1428                             sname.name_id, sname.platform_id,
1429                             sname.encoding_id, sname.language_id);
1430
1431                 elt = FC_FULLNAME;
1432                 eltlang = FC_FULLNAMELANG;
1433                 np = &nfullname;
1434                 nlangp = &nfullname_lang;
1435                 break;
1436             case TT_NAME_ID_WWS_SUBFAMILY:
1437             case TT_NAME_ID_PREFERRED_SUBFAMILY:
1438             case TT_NAME_ID_FONT_SUBFAMILY:
1439                 if (variable)
1440                     break;
1441                 if (FcDebug () & FC_DBG_SCANV)
1442                     printf ("found style  (n %2d p %d e %d l 0x%04x) ",
1443                             sname.name_id, sname.platform_id,
1444                             sname.encoding_id, sname.language_id);
1445
1446                 elt = FC_STYLE;
1447                 eltlang = FC_STYLELANG;
1448                 np = &nstyle;
1449                 nlangp = &nstyle_lang;
1450                 break;
1451             case TT_NAME_ID_TRADEMARK:
1452             case TT_NAME_ID_MANUFACTURER:
1453                 /* If the foundry wasn't found in the OS/2 table, look here */
1454                 if(!foundry)
1455                 {
1456                     FcChar8 *utf8;
1457                     utf8 = FcSfntNameTranscode (&sname);
1458                     foundry = FcNoticeFoundry((FT_String *) utf8);
1459                     free (utf8);
1460                 }
1461                 break;
1462             }
1463             if (elt)
1464             {
1465                 FcChar8         *utf8, *pp;
1466
1467                 utf8 = FcSfntNameTranscode (&sname);
1468                 lang = FcSfntNameLanguage (&sname);
1469
1470                 if (FcDebug () & FC_DBG_SCANV)
1471                     printf ("%s\n", utf8);
1472
1473                 if (!utf8)
1474                     continue;
1475
1476                 /* Trim surrounding whitespace. */
1477                 pp = utf8;
1478                 while (*pp == ' ')
1479                     pp++;
1480                 len = strlen ((const char *) pp);
1481                 memmove (utf8, pp, len + 1);
1482                 pp = utf8 + len;
1483                 while (pp > utf8 && *(pp - 1) == ' ')
1484                     pp--;
1485                 *pp = 0;
1486
1487                 if (FcStringInPatternElement (pat, elt, utf8))
1488                 {
1489                     free (utf8);
1490                     continue;
1491                 }
1492
1493                 /* add new element */
1494                 if (!FcPatternAddString (pat, elt, utf8))
1495                 {
1496                     free (utf8);
1497                     goto bail1;
1498                 }
1499                 free (utf8);
1500                 if (lang)
1501                 {
1502                     /* pad lang list with 'und' to line up with elt */
1503                     while (*nlangp < *np)
1504                     {
1505                         if (!FcPatternAddString (pat, eltlang, (FcChar8 *) "und"))
1506                             goto bail1;
1507                         ++*nlangp;
1508                     }
1509                     if (!FcPatternAddString (pat, eltlang, lang))
1510                         goto bail1;
1511                     ++*nlangp;
1512                 }
1513                 ++*np;
1514             }
1515         }
1516     }
1517
1518     if (!nfamily && face->family_name &&
1519         FcStrCmpIgnoreBlanksAndCase ((FcChar8 *) face->family_name, (FcChar8 *) "") != 0)
1520     {
1521         if (FcDebug () & FC_DBG_SCANV)
1522             printf ("using FreeType family \"%s\"\n", face->family_name);
1523         if (!FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) face->family_name))
1524             goto bail1;
1525         if (!FcPatternAddString (pat, FC_STYLELANG, (FcChar8 *) "en"))
1526             goto bail1;
1527         ++nfamily;
1528     }
1529
1530     if (!variable && !nstyle && face->style_name &&
1531         FcStrCmpIgnoreBlanksAndCase ((FcChar8 *) face->style_name, (FcChar8 *) "") != 0)
1532     {
1533         if (FcDebug () & FC_DBG_SCANV)
1534             printf ("using FreeType style \"%s\"\n", face->style_name);
1535
1536         if (!FcPatternAddString (pat, FC_STYLE, (FcChar8 *) face->style_name))
1537             goto bail1;
1538         if (!FcPatternAddString (pat, FC_STYLELANG, (FcChar8 *) "en"))
1539             goto bail1;
1540         ++nstyle;
1541     }
1542
1543     if (!nfamily && file && *file)
1544     {
1545         FcChar8 *start, *end;
1546         FcChar8 *family;
1547         
1548         start = (FcChar8 *) strrchr ((char *) file, '/');
1549         if (start)
1550             start++;
1551         else
1552             start = (FcChar8 *) file;
1553         end = (FcChar8 *) strrchr ((char *) start, '.');
1554         if (!end)
1555             end = start + strlen ((char *) start);
1556         /* freed below */
1557         family = malloc (end - start + 1);
1558         strncpy ((char *) family, (char *) start, end - start);
1559         family[end - start] = '\0';
1560         if (FcDebug () & FC_DBG_SCANV)
1561             printf ("using filename for family %s\n", family);
1562         if (!FcPatternAddString (pat, FC_FAMILY, family))
1563         {
1564             free (family);
1565             goto bail1;
1566         }
1567         free (family);
1568         ++nfamily;
1569     }
1570
1571     /* Add the PostScript name into the cache */
1572     if (!variable)
1573     {
1574         char        psname[256];
1575         const char          *tmp;
1576         tmp = FT_Get_Postscript_Name (face);
1577         if (!tmp)
1578         {
1579             unsigned int i;
1580             FcChar8 *family, *familylang = NULL;
1581             size_t len;
1582             int n = 0;
1583
1584             /* Workaround when FT_Get_Postscript_Name didn't give any name.
1585              * try to find out the English family name and convert.
1586              */
1587             while (FcPatternObjectGetString (pat, FC_FAMILYLANG_OBJECT, n, &familylang) == FcResultMatch)
1588             {
1589                 if (FcStrCmp (familylang, (const FcChar8 *)"en") == 0)
1590                     break;
1591                 n++;
1592                 familylang = NULL;
1593             }
1594             if (!familylang)
1595                 n = 0;
1596
1597             if (FcPatternObjectGetString (pat, FC_FAMILY_OBJECT, n, &family) != FcResultMatch)
1598                 goto bail1;
1599             len = strlen ((const char *)family);
1600             /* the literal name in PostScript Language is limited to 127 characters though,
1601              * It is the architectural limit. so assuming 255 characters may works enough.
1602              */
1603             for (i = 0; i < len && i < 255; i++)
1604             {
1605                 /* those characters are not allowed to be the literal name in PostScript */
1606                 static const char exclusive_chars[] = "\x04()/<>[]{}\t\f\r\n ";
1607
1608                 if (strchr(exclusive_chars, family[i]) != NULL)
1609                     psname[i] = '-';
1610                 else
1611                     psname[i] = family[i];
1612             }
1613             psname[i] = 0;
1614         }
1615         else
1616         {
1617             strncpy (psname, tmp, 255);
1618             psname[255] = 0;
1619         }
1620         if (!FcPatternAddString (pat, FC_POSTSCRIPT_NAME, (const FcChar8 *)psname))
1621             goto bail1;
1622     }
1623
1624     if (file && *file && !FcPatternAddString (pat, FC_FILE, file))
1625         goto bail1;
1626
1627     if (!FcPatternAddInteger (pat, FC_INDEX, id))
1628         goto bail1;
1629
1630 #if 0
1631     /*
1632      * don't even try this -- CJK 'monospace' fonts are really
1633      * dual width, and most other fonts don't bother to set
1634      * the attribute.  Sigh.
1635      */
1636     if ((face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) != 0)
1637         if (!FcPatternAddInteger (pat, FC_SPACING, FC_MONO))
1638             goto bail1;
1639 #endif
1640
1641     /*
1642      * Find the font revision (if available)
1643      */
1644     head = (TT_Header *) FT_Get_Sfnt_Table (face, ft_sfnt_head);
1645     if (head)
1646     {
1647         if (!FcPatternAddInteger (pat, FC_FONTVERSION, head->Font_Revision))
1648             goto bail1;
1649     }
1650     else
1651     {
1652         if (!FcPatternAddInteger (pat, FC_FONTVERSION, 0))
1653             goto bail1;
1654     }
1655
1656     if (os2 && os2->version >= 0x0001 && os2->version != 0xffff)
1657     {
1658         unsigned int i;
1659         for (i = 0; i < NUM_CODE_PAGE_RANGE; i++)
1660         {
1661             FT_ULong    bits;
1662             int         bit;
1663             if (FcCodePageRange[i].bit < 32)
1664             {
1665                 bits = os2->ulCodePageRange1;
1666                 bit = FcCodePageRange[i].bit;
1667             }
1668             else
1669             {
1670                 bits = os2->ulCodePageRange2;
1671                 bit = FcCodePageRange[i].bit - 32;
1672             }
1673             if (bits & (1U << bit))
1674             {
1675                 /*
1676                  * If the font advertises support for multiple
1677                  * "exclusive" languages, then include support
1678                  * for any language found to have coverage
1679                  */
1680                 if (exclusiveLang)
1681                 {
1682                     exclusiveLang = 0;
1683                     break;
1684                 }
1685                 exclusiveLang = FcCodePageRange[i].lang;
1686             }
1687         }
1688     }
1689
1690     if (os2 && os2->version != 0xffff)
1691     {
1692         weight = os2->usWeightClass;
1693         weight = FcWeightFromOpenTypeDouble (weight * weight_mult);
1694         if ((FcDebug() & FC_DBG_SCANV) && weight != -1)
1695             printf ("\tos2 weight class %d multiplier %g maps to weight %g\n",
1696                     os2->usWeightClass, weight_mult, weight);
1697
1698         switch (os2->usWidthClass) {
1699         case 1: width = FC_WIDTH_ULTRACONDENSED; break;
1700         case 2: width = FC_WIDTH_EXTRACONDENSED; break;
1701         case 3: width = FC_WIDTH_CONDENSED; break;
1702         case 4: width = FC_WIDTH_SEMICONDENSED; break;
1703         case 5: width = FC_WIDTH_NORMAL; break;
1704         case 6: width = FC_WIDTH_SEMIEXPANDED; break;
1705         case 7: width = FC_WIDTH_EXPANDED; break;
1706         case 8: width = FC_WIDTH_EXTRAEXPANDED; break;
1707         case 9: width = FC_WIDTH_ULTRAEXPANDED; break;
1708         }
1709         width *= width_mult;
1710         if ((FcDebug() & FC_DBG_SCANV) && width != -1)
1711             printf ("\tos2 width class %d multiplier %g maps to width %g\n",
1712                     os2->usWidthClass, width_mult, width);
1713     }
1714     if (os2 && (complex_ = FcFontCapabilities(face)))
1715     {
1716         if (!FcPatternAddString (pat, FC_CAPABILITY, complex_))
1717         {
1718             free (complex_);
1719             goto bail1;
1720         }
1721         free (complex_);
1722     }
1723
1724     if (!variable_size && os2 && os2->version >= 0x0005 && os2->version != 0xffff)
1725     {
1726         double lower_size, upper_size;
1727         FcRange *r;
1728
1729         /* usLowerPointSize and usUpperPointSize is actually twips */
1730         lower_size = os2->usLowerOpticalPointSize / 20.0L;
1731         upper_size = os2->usUpperOpticalPointSize / 20.0L;
1732
1733         if (lower_size == upper_size)
1734         {
1735             if (!FcPatternAddDouble (pat, FC_SIZE, lower_size))
1736                 goto bail1;
1737         }
1738         else
1739         {
1740             r = FcRangeCreateDouble (lower_size, upper_size);
1741             if (!FcPatternAddRange (pat, FC_SIZE, r))
1742             {
1743                 FcRangeDestroy (r);
1744                 goto bail1;
1745             }
1746             FcRangeDestroy (r);
1747         }
1748     }
1749
1750     /*
1751      * Type 1: Check for FontInfo dictionary information
1752      * Code from g2@magestudios.net (Gerard Escalante)
1753      */
1754
1755 #if HAVE_FT_GET_PS_FONT_INFO
1756     if (FT_Get_PS_Font_Info(face, &psfontinfo) == 0)
1757     {
1758         if (weight == -1 && psfontinfo.weight)
1759         {
1760             weight = FcIsWeight ((FcChar8 *) psfontinfo.weight);
1761             if (FcDebug() & FC_DBG_SCANV)
1762                 printf ("\tType1 weight %s maps to %g\n",
1763                         psfontinfo.weight, weight);
1764         }
1765
1766 #if 0
1767         /*
1768          * Don't bother with italic_angle; FreeType already extracts that
1769          * information for us and sticks it into style_flags
1770          */
1771         if (psfontinfo.italic_angle)
1772             slant = FC_SLANT_ITALIC;
1773         else
1774             slant = FC_SLANT_ROMAN;
1775 #endif
1776
1777         if(!foundry)
1778             foundry = FcNoticeFoundry(psfontinfo.notice);
1779     }
1780 #endif /* HAVE_FT_GET_PS_FONT_INFO */
1781
1782 #if HAVE_FT_GET_BDF_PROPERTY
1783     /*
1784      * Finally, look for a FOUNDRY BDF property if no other
1785      * mechanism has managed to locate a foundry
1786      */
1787
1788     if (!foundry)
1789     {
1790         int             rc;
1791         rc = FT_Get_BDF_Property(face, "FOUNDRY", &prop);
1792         if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM)
1793             foundry = (FcChar8 *) prop.u.atom;
1794     }
1795
1796     if (width == -1)
1797     {
1798         if (FT_Get_BDF_Property(face, "RELATIVE_SETWIDTH", &prop) == 0 &&
1799             (prop.type == BDF_PROPERTY_TYPE_INTEGER ||
1800              prop.type == BDF_PROPERTY_TYPE_CARDINAL))
1801         {
1802             FT_Int32    value;
1803         
1804             if (prop.type == BDF_PROPERTY_TYPE_INTEGER)
1805                 value = prop.u.integer;
1806             else
1807                 value = (FT_Int32) prop.u.cardinal;
1808             switch ((value + 5) / 10) {
1809             case 1: width = FC_WIDTH_ULTRACONDENSED; break;
1810             case 2: width = FC_WIDTH_EXTRACONDENSED; break;
1811             case 3: width = FC_WIDTH_CONDENSED; break;
1812             case 4: width = FC_WIDTH_SEMICONDENSED; break;
1813             case 5: width = FC_WIDTH_NORMAL; break;
1814             case 6: width = FC_WIDTH_SEMIEXPANDED; break;
1815             case 7: width = FC_WIDTH_EXPANDED; break;
1816             case 8: width = FC_WIDTH_EXTRAEXPANDED; break;
1817             case 9: width = FC_WIDTH_ULTRAEXPANDED; break;
1818             }
1819         }
1820         if (width == -1 &&
1821             FT_Get_BDF_Property (face, "SETWIDTH_NAME", &prop) == 0 &&
1822             prop.type == BDF_PROPERTY_TYPE_ATOM && prop.u.atom != NULL)
1823         {
1824             width = FcIsWidth ((FcChar8 *) prop.u.atom);
1825             if (FcDebug () & FC_DBG_SCANV)
1826                 printf ("\tsetwidth %s maps to %g\n", prop.u.atom, width);
1827         }
1828     }
1829 #endif
1830
1831     /*
1832      * Look for weight, width and slant names in the style value
1833      */
1834     for (st = 0; FcPatternGetString (pat, FC_STYLE, st, &style) == FcResultMatch; st++)
1835     {
1836         if (weight == -1)
1837         {
1838             weight = FcContainsWeight (style);
1839             if (FcDebug() & FC_DBG_SCANV)
1840                 printf ("\tStyle %s maps to weight %g\n", style, weight);
1841         }
1842         if (width == -1)
1843         {
1844             width = FcContainsWidth (style);
1845             if (FcDebug() & FC_DBG_SCANV)
1846                 printf ("\tStyle %s maps to width %g\n", style, width);
1847         }
1848         if (slant == -1)
1849         {
1850             slant = FcContainsSlant (style);
1851             if (FcDebug() & FC_DBG_SCANV)
1852                 printf ("\tStyle %s maps to slant %d\n", style, slant);
1853         }
1854         if (decorative == FcFalse)
1855         {
1856             decorative = FcContainsDecorative (style) > 0;
1857             if (FcDebug() & FC_DBG_SCANV)
1858                 printf ("\tStyle %s maps to decorative %d\n", style, decorative);
1859         }
1860     }
1861     /*
1862      * Pull default values from the FreeType flags if more
1863      * specific values not found above
1864      */
1865     if (slant == -1)
1866     {
1867         slant = FC_SLANT_ROMAN;
1868         if (face->style_flags & FT_STYLE_FLAG_ITALIC)
1869             slant = FC_SLANT_ITALIC;
1870     }
1871
1872     if (weight == -1)
1873     {
1874         weight = FC_WEIGHT_MEDIUM;
1875         if (face->style_flags & FT_STYLE_FLAG_BOLD)
1876             weight = FC_WEIGHT_BOLD;
1877     }
1878
1879     if (width == -1)
1880         width = FC_WIDTH_NORMAL;
1881
1882     if (foundry == 0)
1883         foundry = (FcChar8 *) "unknown";
1884
1885     if (!FcPatternAddInteger (pat, FC_SLANT, slant))
1886         goto bail1;
1887
1888     if (!variable_weight && !FcPatternAddDouble (pat, FC_WEIGHT, weight))
1889         goto bail1;
1890
1891     if (!variable_width && !FcPatternAddDouble (pat, FC_WIDTH, width))
1892         goto bail1;
1893
1894     if (!FcPatternAddString (pat, FC_FOUNDRY, foundry))
1895         goto bail1;
1896
1897     if (!FcPatternAddBool (pat, FC_DECORATIVE, decorative))
1898         goto bail1;
1899
1900
1901     /*
1902      * Compute the unicode coverage for the font
1903      */
1904     if (cs_share && *cs_share)
1905         cs = FcCharSetCopy (*cs_share);
1906     else
1907     {
1908         cs = FcFreeTypeCharSet (face, NULL);
1909         if (cs_share)
1910             *cs_share = FcCharSetCopy (cs);
1911     }
1912     if (!cs)
1913         goto bail1;
1914
1915     /* The FcFreeTypeCharSet() chose the encoding; test it for symbol. */
1916     symbol = face->charmap && face->charmap->encoding == FT_ENCODING_MS_SYMBOL;
1917     if (!FcPatternAddBool (pat, FC_SYMBOL, symbol))
1918         goto bail1;
1919
1920     spacing = FcFreeTypeSpacing (face);
1921 #if HAVE_FT_GET_BDF_PROPERTY
1922     /* For PCF fonts, override the computed spacing with the one from
1923        the property */
1924     if(FT_Get_BDF_Property(face, "SPACING", &prop) == 0 &&
1925        prop.type == BDF_PROPERTY_TYPE_ATOM && prop.u.atom != NULL) {
1926         if(!strcmp(prop.u.atom, "c") || !strcmp(prop.u.atom, "C"))
1927             spacing = FC_CHARCELL;
1928         else if(!strcmp(prop.u.atom, "m") || !strcmp(prop.u.atom, "M"))
1929             spacing = FC_MONO;
1930         else if(!strcmp(prop.u.atom, "p") || !strcmp(prop.u.atom, "P"))
1931             spacing = FC_PROPORTIONAL;
1932     }
1933 #endif
1934
1935     /*
1936      * Skip over PCF fonts that have no encoded characters; they're
1937      * usually just Unicode fonts transcoded to some legacy encoding
1938      * FT forces us to approximate whether a font is a PCF font
1939      * or not by whether it has any BDF properties.  Try PIXEL_SIZE;
1940      * I don't know how to get a list of BDF properties on the font. -PL
1941      */
1942     if (FcCharSetCount (cs) == 0)
1943     {
1944 #if HAVE_FT_GET_BDF_PROPERTY
1945         if(FT_Get_BDF_Property(face, "PIXEL_SIZE", &prop) == 0)
1946             goto bail2;
1947 #endif
1948     }
1949
1950     if (!FcPatternAddCharSet (pat, FC_CHARSET, cs))
1951         goto bail2;
1952
1953     if (!symbol)
1954     {
1955         if (ls_share && *ls_share)
1956             ls = FcLangSetCopy (*ls_share);
1957         else
1958         {
1959             ls = FcFreeTypeLangSet (cs, exclusiveLang);
1960             if (ls_share)
1961                 *ls_share = FcLangSetCopy (ls);
1962         }
1963         if (!ls)
1964             goto bail2;
1965     }
1966     else
1967     {
1968         /* Symbol fonts don't cover any language, even though they
1969          * claim to support Latin1 range. */
1970         ls = FcLangSetCreate ();
1971     }
1972
1973     if (!FcPatternAddLangSet (pat, FC_LANG, ls))
1974     {
1975         FcLangSetDestroy (ls);
1976         goto bail2;
1977     }
1978
1979     FcLangSetDestroy (ls);
1980
1981     if (spacing != FC_PROPORTIONAL)
1982         if (!FcPatternAddInteger (pat, FC_SPACING, spacing))
1983             goto bail2;
1984
1985     if (!(face->face_flags & FT_FACE_FLAG_SCALABLE))
1986     {
1987         int i;
1988         for (i = 0; i < face->num_fixed_sizes; i++)
1989             if (!FcPatternAddDouble (pat, FC_PIXEL_SIZE,
1990                                      FcGetPixelSize (face, i)))
1991                 goto bail2;
1992         if (!FcPatternAddBool (pat, FC_ANTIALIAS, FcFalse))
1993             goto bail2;
1994     }
1995 #if HAVE_FT_GET_X11_FONT_FORMAT
1996     /*
1997      * Use the (not well documented or supported) X-specific function
1998      * from FreeType to figure out the font format
1999      */
2000     {
2001         const char *font_format = FT_Get_X11_Font_Format (face);
2002         if (font_format)
2003             if (!FcPatternAddString (pat, FC_FONTFORMAT, (FcChar8 *) font_format))
2004                 goto bail2;
2005     }
2006 #endif
2007
2008     /*
2009      * Drop our reference to the charset
2010      */
2011     FcCharSetDestroy (cs);
2012     if (foundry_)
2013         free (foundry_);
2014
2015     if (master)
2016       {
2017         /* TODO: How to free master?! */
2018       }
2019
2020     return pat;
2021
2022 bail2:
2023     FcCharSetDestroy (cs);
2024 bail1:
2025     FcPatternDestroy (pat);
2026     if (foundry_)
2027         free (foundry_);
2028 bail0:
2029     return NULL;
2030 }
2031
2032 FcPattern *
2033 FcFreeTypeQueryFace (const FT_Face  face,
2034                      const FcChar8  *file,
2035                      unsigned int   id,
2036                      FcBlanks       *blanks FC_UNUSED)
2037 {
2038     return FcFreeTypeQueryFaceInternal (face, file, id, NULL, NULL);
2039 }
2040
2041 FcPattern *
2042 FcFreeTypeQuery(const FcChar8   *file,
2043                 unsigned int    id,
2044                 FcBlanks        *blanks FC_UNUSED,
2045                 int             *count)
2046 {
2047     FT_Face         face;
2048     FT_Library      ftLibrary;
2049     FcPattern       *pat = NULL;
2050
2051     if (FT_Init_FreeType (&ftLibrary))
2052         return NULL;
2053
2054     if (FT_New_Face (ftLibrary, (char *) file, id & 0x7FFFFFFFF, &face))
2055         goto bail;
2056
2057     if (count)
2058       *count = face->num_faces;
2059
2060     pat = FcFreeTypeQueryFaceInternal (face, file, id, NULL, NULL);
2061
2062     FT_Done_Face (face);
2063 bail:
2064     FT_Done_FreeType (ftLibrary);
2065     return pat;
2066 }
2067
2068 unsigned int
2069 FcFreeTypeQueryAll(const FcChar8        *file,
2070                    unsigned int         id,
2071                    FcBlanks             *blanks,
2072                    int                  *count,
2073                    FcFontSet            *set)
2074 {
2075     FT_Face face = NULL;
2076     FT_Library ftLibrary = NULL;
2077     FcCharSet *cs = NULL;
2078     FcLangSet *ls = NULL;
2079     FT_MM_Var *mm_var = NULL;
2080     FcBool index_set = id != (unsigned int) -1;
2081     unsigned int set_face_num = index_set ? id & 0xFFFF : 0;
2082     unsigned int set_instance_num = index_set ? id >> 16 : 0;
2083     unsigned int face_num = set_face_num;
2084     unsigned int instance_num = set_instance_num;
2085     unsigned int num_faces = 0;
2086     unsigned int num_instances = 0;
2087     unsigned int ret = 0;
2088     int err = 0;
2089
2090     if (count)
2091         *count = 0;
2092
2093     if (FT_Init_FreeType (&ftLibrary))
2094         return 0;
2095
2096     if (FT_New_Face (ftLibrary, (const char *) file, face_num, &face))
2097         goto bail;
2098
2099     num_faces = face->num_faces;
2100     num_instances = face->style_flags >> 16;
2101     if (num_instances && (!index_set || instance_num))
2102     {
2103         FT_Get_MM_Var (face, &mm_var);
2104         if (!mm_var)
2105           num_instances = 0;
2106     }
2107
2108     if (count)
2109       *count = num_faces;
2110
2111     do {
2112         FcPattern *pat = NULL;
2113
2114         if (instance_num == 0x8000 || instance_num > num_instances)
2115             FT_Set_Var_Design_Coordinates (face, 0, NULL); /* Reset variations. */
2116         else if (instance_num)
2117         {
2118             FT_Var_Named_Style *instance = &mm_var->namedstyle[instance_num - 1];
2119             FT_Fixed *coords = instance->coords;
2120             FcBool nonzero;
2121             unsigned int i;
2122
2123             /* Skip named-instance that coincides with base instance. */
2124             nonzero = FcFalse;
2125             for (i = 0; i < mm_var->num_axis; i++)
2126                 if (coords[i] != mm_var->axis[i].def)
2127                 {
2128                     nonzero = FcTrue;
2129                     break;
2130                 }
2131             if (!nonzero)
2132                 goto skip;
2133
2134             FT_Set_Var_Design_Coordinates (face, mm_var->num_axis, coords);
2135         }
2136
2137         id = ((instance_num << 16) + face_num);
2138         pat = FcFreeTypeQueryFaceInternal (face, (const FcChar8 *) file, id, &cs, &ls);
2139
2140         if (pat)
2141         {
2142
2143             ret++;
2144             if (!set || ! FcFontSetAdd (set, pat))
2145                 FcPatternDestroy (pat);
2146         }
2147         else if (instance_num != 0x8000)
2148             err = 1;
2149
2150 skip:
2151         if (!index_set && instance_num < num_instances)
2152             instance_num++;
2153         else if (!index_set && instance_num == num_instances)
2154             instance_num = 0x8000; /* variable font */
2155         else
2156         {
2157             FcLangSetDestroy (ls);
2158             ls = NULL;
2159             FcCharSetDestroy (cs);
2160             cs = NULL;
2161             FT_Done_Face (face);
2162             face = NULL;
2163
2164             face_num++;
2165             instance_num = set_instance_num;
2166
2167             if (FT_New_Face (ftLibrary, (const char *) file, face_num, &face))
2168               break;
2169         }
2170     } while (!err && (!index_set || face_num == set_face_num) && face_num < num_faces);
2171
2172 bail:
2173 #ifdef HAVE_FT_DONE_MM_VAR
2174     FT_Done_MM_Var (ftLibrary, mm_var);
2175 #else
2176     free (mm_var);
2177 #endif
2178     FcLangSetDestroy (ls);
2179     FcCharSetDestroy (cs);
2180     if (face)
2181         FT_Done_Face (face);
2182     FT_Done_FreeType (ftLibrary);
2183
2184     return ret;
2185 }
2186
2187
2188 static const FT_Encoding fcFontEncodings[] = {
2189     FT_ENCODING_UNICODE,
2190     FT_ENCODING_MS_SYMBOL
2191 };
2192
2193 #define NUM_DECODE  (int) (sizeof (fcFontEncodings) / sizeof (fcFontEncodings[0]))
2194
2195 /*
2196  * Map a UCS4 glyph to a glyph index.  Use all available encoding
2197  * tables to try and find one that works.  This information is expected
2198  * to be cached by higher levels, so performance isn't critical
2199  */
2200
2201 FT_UInt
2202 FcFreeTypeCharIndex (FT_Face face, FcChar32 ucs4)
2203 {
2204     int             initial, offset, decode;
2205     FT_UInt         glyphindex;
2206
2207     initial = 0;
2208
2209     if (!face)
2210         return 0;
2211
2212     /*
2213      * Find the current encoding
2214      */
2215     if (face->charmap)
2216     {
2217         for (; initial < NUM_DECODE; initial++)
2218             if (fcFontEncodings[initial] == face->charmap->encoding)
2219                 break;
2220         if (initial == NUM_DECODE)
2221             initial = 0;
2222     }
2223     /*
2224      * Check each encoding for the glyph, starting with the current one
2225      */
2226     for (offset = 0; offset < NUM_DECODE; offset++)
2227     {
2228         decode = (initial + offset) % NUM_DECODE;
2229         if (!face->charmap || face->charmap->encoding != fcFontEncodings[decode])
2230             if (FT_Select_Charmap (face, fcFontEncodings[decode]) != 0)
2231                 continue;
2232         glyphindex = FT_Get_Char_Index (face, (FT_ULong) ucs4);
2233         if (glyphindex)
2234             return glyphindex;
2235         if (ucs4 < 0x100 && face->charmap &&
2236             face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
2237         {
2238             /* For symbol-encoded OpenType fonts, we duplicate the
2239              * U+F000..F0FF range at U+0000..U+00FF.  That's what
2240              * Windows seems to do, and that's hinted about at:
2241              * http://www.microsoft.com/typography/otspec/recom.htm
2242              * under "Non-Standard (Symbol) Fonts".
2243              *
2244              * See thread with subject "Webdings and other MS symbol
2245              * fonts don't display" on mailing list from May 2015.
2246              */
2247             glyphindex = FT_Get_Char_Index (face, (FT_ULong) ucs4 + 0xF000);
2248             if (glyphindex)
2249                 return glyphindex;
2250         }
2251     }
2252     return 0;
2253 }
2254
2255 static inline int fc_min (int a, int b) { return a <= b ? a : b; }
2256 static inline int fc_max (int a, int b) { return a >= b ? a : b; }
2257 static inline FcBool fc_approximately_equal (int x, int y)
2258 { return abs (x - y) * 33 <= fc_max (abs (x), abs (y)); }
2259
2260 static int
2261 FcFreeTypeSpacing (FT_Face face)
2262 {
2263     FT_Int          load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH | FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
2264     FT_Pos          advances[3] = {0};
2265     unsigned int    num_advances = 0;
2266     int             o;
2267
2268     /* When using scalable fonts, only report those glyphs
2269      * which can be scaled; otherwise those fonts will
2270      * only be available at some sizes, and never when
2271      * transformed.  Avoid this by simply reporting bitmap-only
2272      * glyphs as missing
2273      */
2274     if (face->face_flags & FT_FACE_FLAG_SCALABLE)
2275         load_flags |= FT_LOAD_NO_BITMAP;
2276
2277     if (!(face->face_flags & FT_FACE_FLAG_SCALABLE) &&
2278         face->num_fixed_sizes > 0 &&
2279         FT_Get_Sfnt_Table (face, ft_sfnt_head))
2280     {
2281         FT_Int strike_index = 0, i;
2282         /* Select the face closest to 16 pixels tall */
2283         for (i = 1; i < face->num_fixed_sizes; i++)
2284         {
2285             if (abs (face->available_sizes[i].height - 16) <
2286                 abs (face->available_sizes[strike_index].height - 16))
2287                 strike_index = i;
2288         }
2289
2290         FT_Select_Size (face, strike_index);
2291     }
2292
2293     for (o = 0; o < NUM_DECODE; o++)
2294     {
2295         FcChar32        ucs4;
2296         FT_UInt         glyph;
2297
2298         if (FT_Select_Charmap (face, fcFontEncodings[o]) != 0)
2299             continue;
2300
2301         ucs4 = FT_Get_First_Char (face, &glyph);
2302         while (glyph != 0 && num_advances < 3)
2303         {
2304             FT_Pos advance = 0;
2305             if (!FT_Get_Advance (face, glyph, load_flags, &advance) && advance)
2306             {
2307                 unsigned int j;
2308                 for (j = 0; j < num_advances; j++)
2309                   if (fc_approximately_equal (advance, advances[j]))
2310                     break;
2311                 if (j == num_advances)
2312                   advances[num_advances++] = advance;
2313             }
2314
2315             ucs4 = FT_Get_Next_Char (face, ucs4, &glyph);
2316         }
2317         break;
2318     }
2319
2320     if (num_advances <= 1)
2321         return FC_MONO;
2322     else if (num_advances == 2 &&
2323              fc_approximately_equal (fc_min (advances[0], advances[1]) * 2,
2324                                      fc_max (advances[0], advances[1])))
2325         return FC_DUAL;
2326     else
2327         return FC_PROPORTIONAL;
2328 }
2329
2330 FcCharSet *
2331 FcFreeTypeCharSet (FT_Face face, FcBlanks *blanks FC_UNUSED)
2332 {
2333     const FT_Int    load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH | FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
2334     FcCharSet       *fcs;
2335     int             o;
2336
2337     fcs = FcCharSetCreate ();
2338     if (!fcs)
2339         goto bail;
2340
2341 #ifdef CHECK
2342     printf ("Family %s style %s\n", face->family_name, face->style_name);
2343 #endif
2344     for (o = 0; o < NUM_DECODE; o++)
2345     {
2346         FcChar32        page, off, ucs4;
2347         FcCharLeaf      *leaf;
2348         FT_UInt         glyph;
2349
2350         if (FT_Select_Charmap (face, fcFontEncodings[o]) != 0)
2351             continue;
2352
2353         page = ~0;
2354         leaf = NULL;
2355         ucs4 = FT_Get_First_Char (face, &glyph);
2356         while (glyph != 0)
2357         {
2358             FcBool good = FcTrue;
2359
2360             /* CID fonts built by Adobe used to make ASCII control chars to cid1
2361              * (space glyph). As such, always check contour for those characters. */
2362             if (ucs4 <= 0x001F)
2363             {
2364                 if (FT_Load_Glyph (face, glyph, load_flags) ||
2365                     (face->glyph->format == FT_GLYPH_FORMAT_OUTLINE &&
2366                      face->glyph->outline.n_contours == 0))
2367                     good = FcFalse;
2368             }
2369
2370             if (good)
2371             {
2372                 FcCharSetAddChar (fcs, ucs4);
2373                 if ((ucs4 >> 8) != page)
2374                 {
2375                     page = (ucs4 >> 8);
2376                     leaf = FcCharSetFindLeafCreate (fcs, ucs4);
2377                     if (!leaf)
2378                         goto bail;
2379                 }
2380                 off = ucs4 & 0xff;
2381                 leaf->map[off >> 5] |= (1U << (off & 0x1f));
2382             }
2383
2384             ucs4 = FT_Get_Next_Char (face, ucs4, &glyph);
2385         }
2386         if (fcFontEncodings[o] == FT_ENCODING_MS_SYMBOL)
2387         {
2388             /* For symbol-encoded OpenType fonts, we duplicate the
2389              * U+F000..F0FF range at U+0000..U+00FF.  That's what
2390              * Windows seems to do, and that's hinted about at:
2391              * http://www.microsoft.com/typography/otspec/recom.htm
2392              * under "Non-Standard (Symbol) Fonts".
2393              *
2394              * See thread with subject "Webdings and other MS symbol
2395              * fonts don't display" on mailing list from May 2015.
2396              */
2397             for (ucs4 = 0xF000; ucs4 < 0xF100; ucs4++)
2398             {
2399                 if (FcCharSetHasChar (fcs, ucs4))
2400                     FcCharSetAddChar (fcs, ucs4 - 0xF000);
2401             }
2402         }
2403 #ifdef CHECK
2404         for (ucs4 = 0x0020; ucs4 < 0x10000; ucs4++)
2405         {
2406             FcBool          FT_Has, FC_Has;
2407
2408             FT_Has = FT_Get_Char_Index (face, ucs4) != 0;
2409             FC_Has = FcCharSetHasChar (fcs, ucs4);
2410             if (FT_Has != FC_Has)
2411             {
2412                 printf ("0x%08x FT says %d FC says %d\n", ucs4, FT_Has, FC_Has);
2413             }
2414         }
2415 #endif
2416         break;
2417     }
2418
2419     return fcs;
2420 bail:
2421     FcCharSetDestroy (fcs);
2422     return 0;
2423 }
2424
2425 FcCharSet *
2426 FcFreeTypeCharSetAndSpacing (FT_Face face, FcBlanks *blanks FC_UNUSED, int *spacing)
2427 {
2428
2429     if (spacing)
2430         *spacing = FcFreeTypeSpacing (face);
2431
2432     return FcFreeTypeCharSet (face, blanks);
2433 }
2434
2435
2436 #define TTAG_GPOS  FT_MAKE_TAG( 'G', 'P', 'O', 'S' )
2437 #define TTAG_GSUB  FT_MAKE_TAG( 'G', 'S', 'U', 'B' )
2438 #define TTAG_SILF  FT_MAKE_TAG( 'S', 'i', 'l', 'f')
2439
2440 #define OTLAYOUT_HEAD       "otlayout:"
2441 #define OTLAYOUT_HEAD_LEN   9
2442 #define OTLAYOUT_ID_LEN     4
2443 /* space + head + id */
2444 #define OTLAYOUT_LEN        (1 + OTLAYOUT_HEAD_LEN + OTLAYOUT_ID_LEN)
2445
2446 /*
2447  * This is a bit generous; the registry has only lower case and space
2448  * except for 'DFLT'.
2449  */
2450 #define FcIsSpace(x)        (040 == (x))
2451 #define FcIsDigit(c)        (('0' <= (c) && (c) <= '9'))
2452 #define FcIsValidScript(x)  (FcIsLower(x) || FcIsUpper (x) || FcIsDigit(x) || FcIsSpace(x))
2453                         
2454 static void
2455 addtag(FcChar8 *complex_, FT_ULong tag)
2456 {
2457     FcChar8 tagstring[OTLAYOUT_ID_LEN + 1];
2458
2459     tagstring[0] = (FcChar8)(tag >> 24),
2460     tagstring[1] = (FcChar8)(tag >> 16),
2461     tagstring[2] = (FcChar8)(tag >> 8),
2462     tagstring[3] = (FcChar8)(tag);
2463     tagstring[4] = '\0';
2464
2465     /* skip tags which aren't alphanumeric, under the assumption that
2466      * they're probably broken
2467      */
2468     if (!FcIsValidScript(tagstring[0]) ||
2469         !FcIsValidScript(tagstring[1]) ||
2470         !FcIsValidScript(tagstring[2]) ||
2471         !FcIsValidScript(tagstring[3]))
2472         return;
2473
2474     if (*complex_ != '\0')
2475         strcat ((char *) complex_, " ");
2476     strcat ((char *) complex_, OTLAYOUT_HEAD);
2477     strcat ((char *) complex_, (char *) tagstring);
2478 }
2479
2480 static int
2481 compareulong (const void *a, const void *b)
2482 {
2483     const FT_ULong *ua = (const FT_ULong *) a;
2484     const FT_ULong *ub = (const FT_ULong *) b;
2485     return *ua - *ub;
2486 }
2487
2488
2489 static int
2490 GetScriptTags(FT_Face face, FT_ULong tabletag, FT_ULong **stags)
2491 {
2492     FT_ULong   cur_offset, new_offset, base_offset;
2493     FT_Stream  stream = face->stream;
2494     FT_Error   error;
2495     FT_UShort  n, p;
2496     int        script_count;
2497
2498     if (!stream)
2499         return 0;
2500
2501     if (( error = ftglue_face_goto_table( face, tabletag, stream ) ))
2502         return 0;
2503
2504     base_offset = ftglue_stream_pos ( stream );
2505
2506     /* skip version */
2507
2508     if ( ftglue_stream_seek ( stream, base_offset + 4L ) || ftglue_stream_frame_enter( stream, 2L ) )
2509         return 0;
2510
2511     new_offset = GET_UShort() + base_offset;
2512
2513     ftglue_stream_frame_exit( stream );
2514
2515     cur_offset = ftglue_stream_pos( stream );
2516
2517     if ( ftglue_stream_seek( stream, new_offset ) != FT_Err_Ok )
2518         return 0;
2519
2520     base_offset = ftglue_stream_pos( stream );
2521
2522     if ( ftglue_stream_frame_enter( stream, 2L ) )
2523         return 0;
2524
2525     script_count = GET_UShort ();
2526
2527     ftglue_stream_frame_exit( stream );
2528
2529     *stags = malloc(script_count * sizeof (FT_ULong));
2530     if (!stags)
2531         return 0;
2532
2533     p = 0;
2534     for ( n = 0; n < script_count; n++ )
2535     {
2536         if ( ftglue_stream_frame_enter( stream, 6L ) )
2537             goto Fail;
2538
2539         (*stags)[p] = GET_ULong ();
2540         new_offset = GET_UShort () + base_offset;
2541
2542         ftglue_stream_frame_exit( stream );
2543
2544         cur_offset = ftglue_stream_pos( stream );
2545
2546         error = ftglue_stream_seek( stream, new_offset );
2547
2548         if ( error == FT_Err_Ok )
2549             p++;
2550
2551         (void)ftglue_stream_seek( stream, cur_offset );
2552     }
2553
2554     if (!p)
2555         goto Fail;
2556
2557     /* sort the tag list before returning it */
2558     qsort(*stags, script_count, sizeof(FT_ULong), compareulong);
2559
2560     return script_count;
2561
2562 Fail:
2563     free(*stags);
2564     *stags = NULL;
2565     return 0;
2566 }
2567
2568 static FcChar8 *
2569 FcFontCapabilities(FT_Face face)
2570 {
2571     FcBool issilgraphitefont = 0;
2572     FT_Error err;
2573     FT_ULong len = 0;
2574     FT_ULong *gsubtags=NULL, *gpostags=NULL;
2575     FT_UShort gsub_count=0, gpos_count=0;
2576     FT_ULong maxsize;
2577     FcChar8 *complex_ = NULL;
2578     int indx1 = 0, indx2 = 0;
2579
2580     err = FT_Load_Sfnt_Table(face, TTAG_SILF, 0, 0, &len);
2581     issilgraphitefont = ( err == FT_Err_Ok);
2582
2583     gpos_count = GetScriptTags(face, TTAG_GPOS, &gpostags);
2584     gsub_count = GetScriptTags(face, TTAG_GSUB, &gsubtags);
2585
2586     if (!issilgraphitefont && !gsub_count && !gpos_count)
2587         goto bail;
2588
2589     maxsize = (((FT_ULong) gpos_count + (FT_ULong) gsub_count) * OTLAYOUT_LEN +
2590                (issilgraphitefont ? 13 : 0));
2591     complex_ = malloc (sizeof (FcChar8) * maxsize);
2592     if (!complex_)
2593         goto bail;
2594
2595     complex_[0] = '\0';
2596     if (issilgraphitefont)
2597         strcpy((char *) complex_, "ttable:Silf ");
2598
2599     while ((indx1 < gsub_count) || (indx2 < gpos_count)) {
2600         if (indx1 == gsub_count) {
2601             addtag(complex_, gpostags[indx2]);
2602             indx2++;
2603         } else if ((indx2 == gpos_count) || (gsubtags[indx1] < gpostags[indx2])) {
2604             addtag(complex_, gsubtags[indx1]);
2605             indx1++;
2606         } else if (gsubtags[indx1] == gpostags[indx2]) {
2607             addtag(complex_, gsubtags[indx1]);
2608             indx1++;
2609             indx2++;
2610         } else {
2611             addtag(complex_, gpostags[indx2]);
2612             indx2++;
2613         }
2614     }
2615     if (FcDebug () & FC_DBG_SCANV)
2616         printf("complex_ features in this font: %s\n", complex_);
2617 bail:
2618     free(gsubtags);
2619     free(gpostags);
2620     return complex_;
2621 }
2622
2623 #define __fcfreetype__
2624 #include "fcaliastail.h"
2625 #include "fcftaliastail.h"
2626 #undef __fcfreetype__