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