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