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