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