]> git.wh0rd.org - fontconfig.git/blame - src/fcfreetype.c
Guess that mac roman names with lots of high bits are actually SJIS.
[fontconfig.git] / src / fcfreetype.c
CommitLineData
24330d27 1/*
4bd4418a 2 * $RCSId: xc/lib/fontconfig/src/fcfreetype.c,v 1.11 2002/08/31 22:17:32 keithp Exp $
24330d27 3 *
46b51147 4 * Copyright © 2001 Keith Packard
24330d27
KP
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 Keith Packard not be used in
11 * advertising or publicity pertaining to distribution of the software without
12 * specific, written prior permission. Keith Packard makes 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 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 * EVENT SHALL KEITH PACKARD 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
2e2121f9 25/*
46b51147 26 Copyright © 2002-2003 by Juliusz Chroboczek
2e2121f9
KP
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
f045376c 47#include "fcint.h"
24330d27
KP
48#include <stdlib.h>
49#include <stdio.h>
50#include <string.h>
408dd9c0
KP
51#include <ft2build.h>
52#include FT_FREETYPE_H
408dd9c0
KP
53#include FT_TRUETYPE_TABLES_H
54#include FT_SFNT_NAMES_H
55#include FT_TRUETYPE_IDS_H
56#include FT_TYPE1_TABLES_H
537e3d23
KP
57#if HAVE_FT_GET_X11_FONT_FORMAT
58#include FT_XFREE86_H
59#endif
79621aa5 60#if HAVE_FT_GET_BDF_PROPERTY
408dd9c0
KP
61#include FT_BDF_H
62#include FT_MODULE_H
0e7a4347
KP
63#endif
64
8ebf7725
PL
65#include "ftglue.h"
66
5b8e43a4 67#if HAVE_WARNING_CPP_DIRECTIVE
79621aa5 68#if !HAVE_FT_GET_BDF_PROPERTY
ec0c740e 69#warning "No FT_Get_BDF_Property: Please install freetype 2.1.4 or later"
79621aa5
KP
70#endif
71
72#if !HAVE_FT_GET_PS_FONT_INFO
ec0c740e 73#warning "No FT_Get_PS_Font_Info: Please install freetype 2.1.1 or later"
79621aa5 74#endif
5b8e43a4 75#endif
0e7a4347 76
82f4243f 77/*
e50b9ae7
KP
78 * Keep Han languages separated by eliminating languages
79 * that the codePageRange bits says aren't supported
82f4243f 80 */
e50b9ae7 81
24330d27 82static const struct {
82f4243f 83 int bit;
e50b9ae7 84 const FcChar8 *lang;
24330d27 85} FcCodePageRange[] = {
e50b9ae7 86 { 17, (const FcChar8 *) "ja" },
2fcac349 87 { 18, (const FcChar8 *) "zh-cn" },
e50b9ae7 88 { 19, (const FcChar8 *) "ko" },
2fcac349 89 { 20, (const FcChar8 *) "zh-tw" },
24330d27
KP
90};
91
67accef4 92#define NUM_CODE_PAGE_RANGE (int) (sizeof FcCodePageRange / sizeof FcCodePageRange[0])
24330d27 93
82f4243f 94FcBool
e50b9ae7 95FcFreeTypeIsExclusiveLang (const FcChar8 *lang)
82f4243f 96{
e50b9ae7 97 int i;
4c003605 98
e50b9ae7
KP
99 for (i = 0; i < NUM_CODE_PAGE_RANGE; i++)
100 {
16a71eff 101 if (FcLangCompare (lang, FcCodePageRange[i].lang) == FcLangEqual)
82f4243f 102 return FcTrue;
e50b9ae7 103 }
82f4243f
KP
104 return FcFalse;
105}
4c003605 106
4f27c1c0 107typedef struct {
573da729
PL
108 const FT_UShort platform_id;
109 const FT_UShort encoding_id;
bef069e1 110 const char fromcode[12];
4f27c1c0
KP
111} FcFtEncoding;
112
113#define TT_ENCODING_DONT_CARE 0xffff
114#define FC_ENCODING_MAC_ROMAN "MACINTOSH"
115
116static const FcFtEncoding fcFtEncoding[] = {
117 { TT_PLATFORM_APPLE_UNICODE, TT_ENCODING_DONT_CARE, "UCS-2BE" },
118 { TT_PLATFORM_MACINTOSH, TT_MAC_ID_ROMAN, "MACINTOSH" },
119 { TT_PLATFORM_MACINTOSH, TT_MAC_ID_JAPANESE, "SJIS" },
120 { TT_PLATFORM_MICROSOFT, TT_MS_ID_UNICODE_CS, "UTF-16BE" },
121 { TT_PLATFORM_MICROSOFT, TT_MS_ID_SJIS, "SJIS-WIN" },
122 { TT_PLATFORM_MICROSOFT, TT_MS_ID_GB2312, "GB3212" },
123 { TT_PLATFORM_MICROSOFT, TT_MS_ID_BIG_5, "BIG-5" },
124 { TT_PLATFORM_MICROSOFT, TT_MS_ID_WANSUNG, "Wansung" },
97bde49a 125 { TT_PLATFORM_MICROSOFT, TT_MS_ID_JOHAB, "Johab" },
4f27c1c0
KP
126 { TT_PLATFORM_MICROSOFT, TT_MS_ID_UCS_4, "UCS4" },
127 { TT_PLATFORM_ISO, TT_ISO_ID_7BIT_ASCII, "ASCII" },
128 { TT_PLATFORM_ISO, TT_ISO_ID_10646, "UCS-2BE" },
129 { TT_PLATFORM_ISO, TT_ISO_ID_8859_1, "ISO-8859-1" },
130};
69937bd9 131
67accef4 132#define NUM_FC_FT_ENCODING (int) (sizeof (fcFtEncoding) / sizeof (fcFtEncoding[0]))
4f27c1c0
KP
133
134typedef struct {
573da729
PL
135 const FT_UShort platform_id;
136 const FT_UShort language_id;
67accef4 137 const char lang[8];
4f27c1c0
KP
138} FcFtLanguage;
139
140#define TT_LANGUAGE_DONT_CARE 0xffff
141
142static const FcFtLanguage fcFtLanguage[] = {
67accef4 143 { TT_PLATFORM_APPLE_UNICODE, TT_LANGUAGE_DONT_CARE, "" },
4f27c1c0
KP
144 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ENGLISH, "en" },
145 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_FRENCH, "fr" },
146 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GERMAN, "de" },
147 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ITALIAN, "it" },
148 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_DUTCH, "nl" },
149 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SWEDISH, "sv" },
150 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SPANISH, "es" },
151 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_DANISH, "da" },
152 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_PORTUGUESE, "pt" },
153 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_NORWEGIAN, "no" },
154 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_HEBREW, "he" },
155 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_JAPANESE, "ja" },
156 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ARABIC, "ar" },
157 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_FINNISH, "fi" },
158 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GREEK, "el" },
159 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ICELANDIC, "is" },
160 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MALTESE, "mt" },
161 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TURKISH, "tr" },
162 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CROATIAN, "hr" },
163 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CHINESE_TRADITIONAL, "zh-tw" },
164 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_URDU, "ur" },
165 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_HINDI, "hi" },
166 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_THAI, "th" },
167 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KOREAN, "ko" },
168 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_LITHUANIAN, "lt" },
169 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_POLISH, "pl" },
170 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_HUNGARIAN, "hu" },
171 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ESTONIAN, "et" },
172 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_LETTISH, "lv" },
173/* { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SAAMISK, ??? */
174 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_FAEROESE, "fo" },
175 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_FARSI, "fa" },
176 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_RUSSIAN, "ru" },
177 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CHINESE_SIMPLIFIED, "zh-cn" },
178 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_FLEMISH, "nl" },
179 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_IRISH, "ga" },
180 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ALBANIAN, "sq" },
181 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ROMANIAN, "ro" },
182 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CZECH, "cs" },
183 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SLOVAK, "sk" },
184 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SLOVENIAN, "sl" },
185 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_YIDDISH, "yi" },
186 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SERBIAN, "sr" },
187 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MACEDONIAN, "mk" },
188 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BULGARIAN, "bg" },
189 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_UKRAINIAN, "uk" },
190 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BYELORUSSIAN, "be" },
191 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_UZBEK, "uz" },
192 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KAZAKH, "kk" },
193 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AZERBAIJANI, "az" },
194 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AZERBAIJANI_CYRILLIC_SCRIPT, "az" },
195 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT, "ar" },
196 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ARMENIAN, "hy" },
197 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GEORGIAN, "ka" },
198 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MOLDAVIAN, "mo" },
199 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KIRGHIZ, "ky" },
200 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TAJIKI, "tg" },
201 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TURKMEN, "tk" },
202 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MONGOLIAN, "mo" },
203 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MONGOLIAN_MONGOLIAN_SCRIPT,"mo" },
204 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT, "mo" },
205 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_PASHTO, "ps" },
206 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KURDISH, "ku" },
207 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KASHMIRI, "ks" },
208 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SINDHI, "sd" },
209 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TIBETAN, "bo" },
210 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_NEPALI, "ne" },
211 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SANSKRIT, "sa" },
212 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MARATHI, "mr" },
213 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BENGALI, "bn" },
214 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ASSAMESE, "as" },
215 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GUJARATI, "gu" },
216 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_PUNJABI, "pa" },
217 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ORIYA, "or" },
218 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MALAYALAM, "ml" },
219 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KANNADA, "kn" },
220 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TAMIL, "ta" },
221 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TELUGU, "te" },
222 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SINHALESE, "si" },
223 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BURMESE, "my" },
224 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KHMER, "km" },
225 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_LAO, "lo" },
226 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_VIETNAMESE, "vi" },
227 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_INDONESIAN, "id" },
228 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TAGALOG, "tl" },
229 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MALAY_ROMAN_SCRIPT, "ms" },
230 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MALAY_ARABIC_SCRIPT, "ms" },
231 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AMHARIC, "am" },
232 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TIGRINYA, "ti" },
233 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GALLA, "om" },
234 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SOMALI, "so" },
235 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SWAHILI, "sw" },
236 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_RUANDA, "rw" },
237 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_RUNDI, "rn" },
238 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CHEWA, "ny" },
239 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MALAGASY, "mg" },
240 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ESPERANTO, "eo" },
241 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_WELSH, "cy" },
242 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BASQUE, "eu" },
243 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CATALAN, "ca" },
244 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_LATIN, "la" },
245 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_QUECHUA, "qu" },
246 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GUARANI, "gn" },
247 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AYMARA, "ay" },
248 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TATAR, "tt" },
249 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_UIGHUR, "ug" },
250 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_DZONGKHA, "dz" },
251 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_JAVANESE, "jw" },
252 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SUNDANESE, "su" },
253
254#if 0 /* these seem to be errors that have been dropped */
69937bd9 255
4f27c1c0
KP
256 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SCOTTISH_GAELIC },
257 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_IRISH_GAELIC },
69937bd9 258
4f27c1c0 259#endif
69937bd9 260
4f27c1c0
KP
261 /* The following codes are new as of 2000-03-10 */
262 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GALICIAN, "gl" },
263 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AFRIKAANS, "af" },
264 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BRETON, "br" },
265 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_INUKTITUT, "iu" },
266 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SCOTTISH_GAELIC, "gd" },
267 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MANX_GAELIC, "gv" },
268 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_IRISH_GAELIC, "ga" },
269 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TONGAN, "to" },
270 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GREEK_POLYTONIC, "el" },
271 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GREELANDIC, "ik" },
272 { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT,"az" },
273
274 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_SAUDI_ARABIA, "ar" },
275 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_IRAQ, "ar" },
276 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_EGYPT, "ar" },
277 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_LIBYA, "ar" },
278 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_ALGERIA, "ar" },
279 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_MOROCCO, "ar" },
280 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_TUNISIA, "ar" },
281 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_OMAN, "ar" },
282 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_YEMEN, "ar" },
283 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_SYRIA, "ar" },
284 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_JORDAN, "ar" },
285 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_LEBANON, "ar" },
286 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_KUWAIT, "ar" },
287 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_UAE, "ar" },
288 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_BAHRAIN, "ar" },
289 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_QATAR, "ar" },
290 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BULGARIAN_BULGARIA, "bg" },
291 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CATALAN_SPAIN, "ca" },
292 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_TAIWAN, "zh-tw" },
293 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_PRC, "zh-cn" },
294 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_HONG_KONG, "zh-hk" },
295 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_SINGAPORE, "zh-sg" },
296
297 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_MACAU, "zh-mo" },
298
299 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CZECH_CZECH_REPUBLIC, "cs" },
300 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_DANISH_DENMARK, "da" },
301 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GERMAN_GERMANY, "de" },
302 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GERMAN_SWITZERLAND, "de" },
303 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GERMAN_AUSTRIA, "de" },
304 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GERMAN_LUXEMBOURG, "de" },
305 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GERMAN_LIECHTENSTEI, "de" },
306 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GREEK_GREECE, "el" },
307 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_UNITED_STATES, "en" },
308 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_UNITED_KINGDOM, "en" },
309 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_AUSTRALIA, "en" },
310 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_CANADA, "en" },
311 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_NEW_ZEALAND, "en" },
312 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_IRELAND, "en" },
313 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_SOUTH_AFRICA, "en" },
314 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_JAMAICA, "en" },
315 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_CARIBBEAN, "en" },
316 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_BELIZE, "en" },
317 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_TRINIDAD, "en" },
318 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_ZIMBABWE, "en" },
319 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_PHILIPPINES, "en" },
320 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_SPAIN_TRADITIONAL_SORT,"es" },
321 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_MEXICO, "es" },
322 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_SPAIN_INTERNATIONAL_SORT,"es" },
323 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_GUATEMALA, "es" },
324 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_COSTA_RICA, "es" },
325 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_PANAMA, "es" },
326 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_DOMINICAN_REPUBLIC,"es" },
327 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_VENEZUELA, "es" },
328 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_COLOMBIA, "es" },
329 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_PERU, "es" },
330 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_ARGENTINA, "es" },
331 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_ECUADOR, "es" },
332 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_CHILE, "es" },
333 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_URUGUAY, "es" },
334 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_PARAGUAY, "es" },
335 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_BOLIVIA, "es" },
336 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_EL_SALVADOR, "es" },
337 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_HONDURAS, "es" },
338 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_NICARAGUA, "es" },
339 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_PUERTO_RICO, "es" },
340 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FINNISH_FINLAND, "fi" },
341 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_FRANCE, "fr" },
342 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_BELGIUM, "fr" },
343 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_CANADA, "fr" },
344 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_SWITZERLAND, "fr" },
345 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_LUXEMBOURG, "fr" },
346 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_MONACO, "fr" },
347 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_HEBREW_ISRAEL, "he" },
348 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_HUNGARIAN_HUNGARY, "hu" },
349 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ICELANDIC_ICELAND, "is" },
350 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ITALIAN_ITALY, "it" },
351 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ITALIAN_SWITZERLAND, "it" },
352 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_JAPANESE_JAPAN, "ja" },
353 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KOREAN_EXTENDED_WANSUNG_KOREA,"ko" },
354 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KOREAN_JOHAB_KOREA, "ko" },
355 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_DUTCH_NETHERLANDS, "nl" },
356 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_DUTCH_BELGIUM, "nl" },
357 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_NORWEGIAN_NORWAY_BOKMAL, "no" },
358 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_NORWEGIAN_NORWAY_NYNORSK, "nn" },
359 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_POLISH_POLAND, "pl" },
360 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PORTUGUESE_BRAZIL, "pt" },
361 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PORTUGUESE_PORTUGAL, "pt" },
362 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_RHAETO_ROMANIC_SWITZERLAND,"rm" },
363 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ROMANIAN_ROMANIA, "ro" },
364 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MOLDAVIAN_MOLDAVIA, "mo" },
365 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_RUSSIAN_RUSSIA, "ru" },
366 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_RUSSIAN_MOLDAVIA, "ru" },
367 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CROATIAN_CROATIA, "hr" },
368 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SERBIAN_SERBIA_LATIN, "sr" },
369 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SERBIAN_SERBIA_CYRILLIC, "sr" },
370 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SLOVAK_SLOVAKIA, "sk" },
371 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ALBANIAN_ALBANIA, "sq" },
372 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SWEDISH_SWEDEN, "sv" },
373 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SWEDISH_FINLAND, "sv" },
374 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_THAI_THAILAND, "th" },
375 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TURKISH_TURKEY, "tr" },
376 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_URDU_PAKISTAN, "ur" },
377 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_INDONESIAN_INDONESIA, "id" },
378 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_UKRAINIAN_UKRAINE, "uk" },
379 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BELARUSIAN_BELARUS, "be" },
380 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SLOVENE_SLOVENIA, "sl" },
381 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ESTONIAN_ESTONIA, "et" },
382 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_LATVIAN_LATVIA, "lv" },
383 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_LITHUANIAN_LITHUANIA, "lt" },
384 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CLASSIC_LITHUANIAN_LITHUANIA,"lt" },
385
386#ifdef TT_MS_LANGID_MAORI_NEW_ZELAND
387 /* this seems to be an error that have been dropped */
388 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MAORI_NEW_ZEALAND, "mi" },
389#endif
69937bd9 390
4f27c1c0
KP
391 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FARSI_IRAN, "fa" },
392 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_VIETNAMESE_VIET_NAM, "vi" },
393 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARMENIAN_ARMENIA, "hy" },
394 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_AZERI_AZERBAIJAN_LATIN, "az" },
395 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_AZERI_AZERBAIJAN_CYRILLIC, "az" },
396 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BASQUE_SPAIN, "eu" },
397 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SORBIAN_GERMANY, "wen" },
398 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MACEDONIAN_MACEDONIA, "mk" },
399 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SUTU_SOUTH_AFRICA, "st" },
400 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TSONGA_SOUTH_AFRICA, "ts" },
401 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TSWANA_SOUTH_AFRICA, "tn" },
402 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_VENDA_SOUTH_AFRICA, "ven" },
403 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_XHOSA_SOUTH_AFRICA, "xh" },
404 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ZULU_SOUTH_AFRICA, "zu" },
405 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_AFRIKAANS_SOUTH_AFRICA, "af" },
406 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GEORGIAN_GEORGIA, "ka" },
407 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FAEROESE_FAEROE_ISLANDS, "fo" },
408 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_HINDI_INDIA, "hi" },
409 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MALTESE_MALTA, "mt" },
410 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SAAMI_LAPONIA, "se" },
411
412 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SCOTTISH_GAELIC_UNITED_KINGDOM,"gd" },
413 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_IRISH_GAELIC_IRELAND, "ga" },
414
415 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MALAY_MALAYSIA, "ms" },
416 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MALAY_BRUNEI_DARUSSALAM, "ms" },
417 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KAZAK_KAZAKSTAN, "kk" },
418 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SWAHILI_KENYA, "sw" },
419 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_UZBEK_UZBEKISTAN_LATIN, "uz" },
420 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_UZBEK_UZBEKISTAN_CYRILLIC, "uz" },
421 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TATAR_TATARSTAN, "tt" },
422 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BENGALI_INDIA, "bn" },
423 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PUNJABI_INDIA, "pa" },
424 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GUJARATI_INDIA, "gu" },
425 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ORIYA_INDIA, "or" },
426 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TAMIL_INDIA, "ta" },
427 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TELUGU_INDIA, "te" },
428 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KANNADA_INDIA, "kn" },
429 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MALAYALAM_INDIA, "ml" },
430 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ASSAMESE_INDIA, "as" },
431 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MARATHI_INDIA, "mr" },
432 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SANSKRIT_INDIA, "sa" },
433 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KONKANI_INDIA, "kok" },
434
435 /* new as of 2001-01-01 */
436 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_GENERAL, "ar" },
437 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_GENERAL, "zh" },
438 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_GENERAL, "en" },
439 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_WEST_INDIES, "fr" },
440 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_REUNION, "fr" },
441 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_CONGO, "fr" },
442
443 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_SENEGAL, "fr" },
444 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_CAMEROON, "fr" },
445 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_COTE_D_IVOIRE, "fr" },
446 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_MALI, "fr" },
447 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BOSNIAN_BOSNIA_HERZEGOVINA,"bs" },
448 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_URDU_INDIA, "ur" },
449 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TAJIK_TAJIKISTAN, "tg" },
450 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_YIDDISH_GERMANY, "yi" },
451 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KIRGHIZ_KIRGHIZSTAN, "ky" },
452
453 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TURKMEN_TURKMENISTAN, "tk" },
454 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MONGOLIAN_MONGOLIA, "mn" },
455
456 /* the following seems to be inconsistent;
457 here is the current "official" way: */
458 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TIBETAN_BHUTAN, "bo" },
459 /* and here is what is used by Passport SDK */
460 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TIBETAN_CHINA, "bo" },
461 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_DZONGHKA_BHUTAN, "dz" },
462 /* end of inconsistency */
463
464 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_WELSH_WALES, "cy" },
465 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KHMER_CAMBODIA, "km" },
466 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_LAO_LAOS, "lo" },
467 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BURMESE_MYANMAR, "my" },
468 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GALICIAN_SPAIN, "gl" },
469 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MANIPURI_INDIA, "mni" },
470 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SINDHI_INDIA, "sd" },
471 /* the following one is only encountered in Microsoft RTF specification */
472 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KASHMIRI_PAKISTAN, "ks" },
473 /* the following one is not in the Passport list, looks like an omission */
474 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KASHMIRI_INDIA, "ks" },
475 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_NEPALI_NEPAL, "ne" },
476 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_NEPALI_INDIA, "ne" },
477 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRISIAN_NETHERLANDS, "fy" },
478
479 /* new as of 2001-03-01 (from Office Xp) */
480 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_HONG_KONG, "en" },
481 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_INDIA, "en" },
482 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_MALAYSIA, "en" },
483 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_SINGAPORE, "en" },
484 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SYRIAC_SYRIA, "syr" },
485 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SINHALESE_SRI_LANKA, "si" },
486 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHEROKEE_UNITED_STATES, "chr" },
487 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_INUKTITUT_CANADA, "iu" },
488 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_AMHARIC_ETHIOPIA, "am" },
489#if 0
490 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TAMAZIGHT_MOROCCO },
491 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TAMAZIGHT_MOROCCO_LATIN },
492#endif
493 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PASHTO_AFGHANISTAN, "ps" },
494 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FILIPINO_PHILIPPINES, "phi" },
495 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_DHIVEHI_MALDIVES, "div" },
496
497 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_OROMO_ETHIOPIA, "om" },
498 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TIGRIGNA_ETHIOPIA, "ti" },
499 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TIGRIGNA_ERYTHREA, "ti" },
500
501 /* New additions from Windows Xp/Passport SDK 2001-11-10. */
502
503 /* don't ask what this one means... It is commented out currently. */
504#if 0
505 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GREEK_GREECE2 },
506#endif
507
508 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_UNITED_STATES, "es" },
509 /* The following two IDs blatantly violate MS specs by using a */
510 /* sublanguage >,. */
511 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_LATIN_AMERICA, "es" },
512 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_NORTH_AFRICA, "fr" },
513
514 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_MOROCCO, "fr" },
515 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_HAITI, "fr" },
516 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BENGALI_BANGLADESH, "bn" },
517 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PUNJABI_ARABIC_PAKISTAN, "ar" },
518 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MONGOLIAN_MONGOLIA_MONGOLIAN,"mn" },
519#if 0
520 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_EDO_NIGERIA },
521 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FULFULDE_NIGERIA },
522 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_IBIBIO_NIGERIA },
523#endif
524 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_HAUSA_NIGERIA, "ha" },
525 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_YORUBA_NIGERIA, "yo" },
526 /* language codes from, to, are (still) unknown. */
527 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_IGBO_NIGERIA, "ibo" },
528 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KANURI_NIGERIA, "kau" },
529 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GUARANI_PARAGUAY, "gn" },
530 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_HAWAIIAN_UNITED_STATES, "haw" },
531 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_LATIN, "la" },
532 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SOMALI_SOMALIA, "so" },
533#if 0
534 /* Note: Yi does not have a (proper) ISO 639-2 code, since it is mostly */
535 /* not written (but OTOH the peculiar writing system is worth */
536 /* studying). */
537 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_YI_CHINA },
538#endif
539 { TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PAPIAMENTU_NETHERLANDS_ANTILLES,"pap" },
540};
541
67accef4 542#define NUM_FC_FT_LANGUAGE (int) (sizeof (fcFtLanguage) / sizeof (fcFtLanguage[0]))
4f27c1c0
KP
543
544typedef struct {
545 FT_UShort language_id;
bef069e1 546 char fromcode[12];
4f27c1c0
KP
547} FcMacRomanFake;
548
549static const FcMacRomanFake fcMacRomanFake[] = {
550 { TT_MS_LANGID_JAPANESE_JAPAN, "SJIS-WIN" },
551 { TT_MS_LANGID_ENGLISH_UNITED_STATES, "ASCII" },
552};
553
dbf68dd5
KP
554static FcChar8 *
555FcFontCapabilities(FT_Face face);
556
67accef4 557#define NUM_FC_MAC_ROMAN_FAKE (int) (sizeof (fcMacRomanFake) / sizeof (fcMacRomanFake[0]))
4f27c1c0 558
73775d8f 559#if USE_ICONV
4f27c1c0
KP
560#include <iconv.h>
561#endif
562
7295c6f5
KP
563/*
564 * A shift-JIS will have many high bits turned on
565 */
566static FcBool
567FcLooksLikeSJIS (FcChar8 *string, int len)
568{
569 int nhigh = 0, nlow = 0;
570
571 while (len-- > 0)
572 {
573 if (*string++ & 0x80) nhigh++;
574 else nlow++;
575 }
576 /*
577 * Heuristic -- if more than 1/3 of the bytes have the high-bit set,
578 * this is likely to be SJIS and not ROMAN
579 */
580 if (nhigh * 2 > nlow)
581 return FcTrue;
582 return FcFalse;
583}
584
4f27c1c0
KP
585static FcChar8 *
586FcSfntNameTranscode (FT_SfntName *sname)
69937bd9 587{
bef069e1
PL
588 int i;
589 const char *fromcode;
4f27c1c0
KP
590#if USE_ICONV
591 iconv_t cd;
592#endif
593 FcChar8 *utf8;
594
595 for (i = 0; i < NUM_FC_FT_ENCODING; i++)
596 if (fcFtEncoding[i].platform_id == sname->platform_id &&
597 (fcFtEncoding[i].encoding_id == TT_ENCODING_DONT_CARE ||
598 fcFtEncoding[i].encoding_id == sname->encoding_id))
599 break;
600 if (i == NUM_FC_FT_ENCODING)
601 return 0;
602 fromcode = fcFtEncoding[i].fromcode;
603
604 /*
7295c6f5
KP
605 * Many names encoded for TT_PLATFORM_MACINTOSH are broken
606 * in various ways. Kludge around them.
4f27c1c0 607 */
7295c6f5 608 if (!strcmp (fromcode, FC_ENCODING_MAC_ROMAN))
4f27c1c0 609 {
7295c6f5
KP
610 if (sname->language_id == TT_MAC_LANGID_ENGLISH &&
611 FcLooksLikeSJIS (sname->string, sname->string_len))
612 {
613 fromcode = "SJIS";
614 }
615 else if (sname->language_id >= 0x100)
616 {
617 /*
618 * "real" Mac language IDs are all less than 150.
619 * Names using one of the MS language IDs are assumed
620 * to use an associated encoding (Yes, this is a kludge)
621 */
622 int f;
623
624 fromcode = NULL;
625 for (f = 0; f < NUM_FC_MAC_ROMAN_FAKE; f++)
626 if (fcMacRomanFake[f].language_id == sname->language_id)
627 {
628 fromcode = fcMacRomanFake[f].fromcode;
629 break;
630 }
631 if (!fromcode)
632 return 0;
633 }
4f27c1c0 634 }
4f27c1c0
KP
635 if (!strcmp (fromcode, "UCS-2BE") || !strcmp (fromcode, "UTF-16BE"))
636 {
637 FcChar8 *src = sname->string;
638 int src_len = sname->string_len;
639 int len;
640 int wchar;
641 int ilen, olen;
642 FcChar8 *u8;
643 FcChar32 ucs4;
644
645 /*
646 * Convert Utf16 to Utf8
647 */
648
649 if (!FcUtf16Len (src, FcEndianBig, src_len, &len, &wchar))
650 return 0;
651
652 /*
653 * Allocate plenty of space. Freed below
654 */
655 utf8 = malloc (len * FC_UTF8_MAX_LEN + 1);
656 if (!utf8)
657 return 0;
658
659 u8 = utf8;
660
661 while ((ilen = FcUtf16ToUcs4 (src, FcEndianBig, &ucs4, src_len)) > 0)
662 {
663 src_len -= ilen;
664 src += ilen;
665 olen = FcUcs4ToUtf8 (ucs4, u8);
666 u8 += olen;
667 }
668 *u8 = '\0';
669 goto done;
670 }
671 if (!strcmp (fromcode, "ASCII") || !strcmp (fromcode, "ISO-8859-1"))
69937bd9 672 {
4f27c1c0
KP
673 FcChar8 *src = sname->string;
674 int src_len = sname->string_len;
675 int olen;
676 FcChar8 *u8;
69937bd9 677 FcChar32 ucs4;
4f27c1c0
KP
678
679 /*
680 * Convert Latin1 to Utf8. Freed below
681 */
682 utf8 = malloc (src_len * 2 + 1);
683 if (!utf8)
684 return 0;
685
686 u8 = utf8;
687 while (src_len > 0)
688 {
689 ucs4 = *src++;
690 src_len--;
691 olen = FcUcs4ToUtf8 (ucs4, u8);
692 u8 += olen;
693 }
694 *u8 = '\0';
695 goto done;
69937bd9 696 }
4f27c1c0
KP
697 if (!strcmp (fromcode, FC_ENCODING_MAC_ROMAN))
698 {
699 FcChar8 *u8;
700 const FcCharMap *map = FcFreeTypeGetPrivateMap (ft_encoding_apple_roman);
701 FcChar8 *src = (FcChar8 *) sname->string;
702 int src_len = sname->string_len;
703
704 /*
705 * Convert AppleRoman to Utf8
706 */
707 if (!map)
708 return 0;
709
710 utf8 = malloc (sname->string_len * 3 + 1);
711 if (!utf8)
712 return 0;
713
714 u8 = utf8;
715 while (src_len > 0)
716 {
717 FcChar32 ucs4 = FcFreeTypePrivateToUcs4 (*src++, map);
718 int olen = FcUcs4ToUtf8 (ucs4, u8);
719 src_len--;
720 u8 += olen;
721 }
722 *u8 = '\0';
723 goto done;
724 }
716ac8b8
KP
725#if USE_ICONV
726 cd = iconv_open ("UTF-8", fromcode);
727 if (cd && cd != (iconv_t) (-1))
728 {
729 size_t in_bytes_left = sname->string_len;
730 size_t out_bytes_left = sname->string_len * FC_UTF8_MAX_LEN;
731 char *inbuf, *outbuf;
732
733 utf8 = malloc (out_bytes_left + 1);
734 if (!utf8)
735 {
736 iconv_close (cd);
737 return 0;
738 }
739
740 outbuf = (char *) utf8;
741 inbuf = (char *) sname->string;
742
743 while (in_bytes_left)
744 {
745 size_t did = iconv (cd,
746 &inbuf, &in_bytes_left,
747 &outbuf, &out_bytes_left);
748 if (did == (size_t) (-1))
749 {
750 iconv_close (cd);
751 free (utf8);
752 return 0;
753 }
754 }
755 iconv_close (cd);
756 *outbuf = '\0';
757 goto done;
758 }
759#endif
4f27c1c0
KP
760 return 0;
761done:
8245771d 762 if (FcStrCmpIgnoreBlanksAndCase (utf8, (FcChar8 *) "") == 0)
4f27c1c0
KP
763 {
764 free (utf8);
765 return 0;
766 }
767 return utf8;
768}
769
573da729 770static const FcChar8 *
4f27c1c0
KP
771FcSfntNameLanguage (FT_SfntName *sname)
772{
773 int i;
7295c6f5
KP
774 FT_UShort platform_id = sname->platform_id;
775 FT_UShort language_id = sname->language_id;
776
777 /*
778 * Many names encoded for TT_PLATFORM_MACINTOSH are broken
779 * in various ways. Kludge around them.
780 */
781 if (platform_id == TT_PLATFORM_MACINTOSH &&
782 sname->encoding_id == TT_MAC_ID_ROMAN &&
783 FcLooksLikeSJIS (sname->string, sname->string_len))
784 {
785 language_id = TT_MAC_LANGID_JAPANESE;
786 }
787
4f27c1c0 788 for (i = 0; i < NUM_FC_FT_LANGUAGE; i++)
7295c6f5 789 if (fcFtLanguage[i].platform_id == platform_id &&
4f27c1c0 790 (fcFtLanguage[i].language_id == TT_LANGUAGE_DONT_CARE ||
7295c6f5 791 fcFtLanguage[i].language_id == language_id))
67accef4
PL
792 {
793 if (fcFtLanguage[i].lang[0] == '\0')
794 return NULL;
795 else
796 return (FcChar8 *) fcFtLanguage[i].lang;
797 }
4f27c1c0 798 return 0;
69937bd9
KP
799}
800
2e2121f9
KP
801/* Order is significant. For example, some B&H fonts are hinted by
802 URW++, and both strings appear in the notice. */
803
804static const struct {
6ae6acf3 805 const FT_String *notice;
2e2121f9
KP
806 const FcChar8 *foundry;
807} FcNoticeFoundries[] = {
6ae6acf3
KP
808 { (const FT_String *) "Bigelow", (const FcChar8 *) "b&h" },
809 { (const FT_String *) "Adobe", (const FcChar8 *) "adobe" },
810 { (const FT_String *) "Bitstream", (const FcChar8 *) "bitstream" },
811 { (const FT_String *) "Monotype", (const FcChar8 *) "monotype" },
812 { (const FT_String *) "Linotype", (const FcChar8 *) "linotype" },
813 { (const FT_String *) "LINOTYPE-HELL",
814 (const FcChar8 *) "linotype" },
815 { (const FT_String *) "IBM", (const FcChar8 *) "ibm" },
816 { (const FT_String *) "URW", (const FcChar8 *) "urw" },
817 { (const FT_String *) "International Typeface Corporation",
2e2121f9 818 (const FcChar8 *) "itc" },
6ae6acf3
KP
819 { (const FT_String *) "Tiro Typeworks",
820 (const FcChar8 *) "tiro" },
821 { (const FT_String *) "XFree86", (const FcChar8 *) "xfree86" },
822 { (const FT_String *) "Microsoft", (const FcChar8 *) "microsoft" },
823 { (const FT_String *) "Omega", (const FcChar8 *) "omega" },
824 { (const FT_String *) "Font21", (const FcChar8 *) "hwan" },
825 { (const FT_String *) "HanYang System",
826 (const FcChar8 *) "hanyang" }
2e2121f9
KP
827};
828
67accef4 829#define NUM_NOTICE_FOUNDRIES (int) (sizeof (FcNoticeFoundries) / sizeof (FcNoticeFoundries[0]))
2e2121f9
KP
830
831static const FcChar8 *
6ae6acf3 832FcNoticeFoundry(const FT_String *notice)
2ae95e77
JC
833{
834 int i;
2e2121f9
KP
835
836 if (notice)
837 for(i = 0; i < NUM_NOTICE_FOUNDRIES; i++)
838 if (strstr ((const char *) notice, (const char *) FcNoticeFoundries[i].notice))
839 return FcNoticeFoundries[i].foundry;
840 return 0;
2ae95e77
JC
841}
842
2e2121f9 843static FcBool
6ae6acf3 844FcVendorMatch(const FT_Char vendor[4], const FT_Char *vendor_string)
2ae95e77
JC
845{
846 /* vendor is not necessarily NUL-terminated. */
847 int i, len;
2e2121f9 848
8245771d 849 len = strlen((char *) vendor_string);
2e2121f9
KP
850 if (memcmp(vendor, vendor_string, len) != 0)
851 return FcFalse;
852 for (i = len; i < 4; i++)
853 if (vendor[i] != ' ' && vendor[i] != '\0')
854 return FcFalse;
855 return FcTrue;
2ae95e77
JC
856}
857
2e2121f9
KP
858/* This table is partly taken from ttmkfdir by Joerg Pommnitz. */
859
860/* It should not contain useless entries (such as UNKN) nor duplicate
861 entries for padding both with spaces and NULs. */
862
863static const struct {
6ae6acf3 864 const FT_Char *vendor;
2e2121f9
KP
865 const FcChar8 *foundry;
866} FcVendorFoundries[] = {
6ae6acf3
KP
867 { (const FT_Char *) "ADBE", (const FcChar8 *) "adobe"},
868 { (const FT_Char *) "AGFA", (const FcChar8 *) "agfa"},
869 { (const FT_Char *) "ALTS", (const FcChar8 *) "altsys"},
870 { (const FT_Char *) "APPL", (const FcChar8 *) "apple"},
871 { (const FT_Char *) "ARPH", (const FcChar8 *) "arphic"},
872 { (const FT_Char *) "ATEC", (const FcChar8 *) "alltype"},
873 { (const FT_Char *) "B&H", (const FcChar8 *) "b&h"},
874 { (const FT_Char *) "BITS", (const FcChar8 *) "bitstream"},
875 { (const FT_Char *) "CANO", (const FcChar8 *) "cannon"},
876 { (const FT_Char *) "DYNA", (const FcChar8 *) "dynalab"},
877 { (const FT_Char *) "EPSN", (const FcChar8 *) "epson"},
878 { (const FT_Char *) "FJ", (const FcChar8 *) "fujitsu"},
879 { (const FT_Char *) "IBM", (const FcChar8 *) "ibm"},
880 { (const FT_Char *) "ITC", (const FcChar8 *) "itc"},
881 { (const FT_Char *) "IMPR", (const FcChar8 *) "impress"},
882 { (const FT_Char *) "LARA", (const FcChar8 *) "larabiefonts"},
883 { (const FT_Char *) "LEAF", (const FcChar8 *) "interleaf"},
884 { (const FT_Char *) "LETR", (const FcChar8 *) "letraset"},
885 { (const FT_Char *) "LINO", (const FcChar8 *) "linotype"},
886 { (const FT_Char *) "MACR", (const FcChar8 *) "macromedia"},
887 { (const FT_Char *) "MONO", (const FcChar8 *) "monotype"},
888 { (const FT_Char *) "MS", (const FcChar8 *) "microsoft"},
889 { (const FT_Char *) "MT", (const FcChar8 *) "monotype"},
890 { (const FT_Char *) "NEC", (const FcChar8 *) "nec"},
891 { (const FT_Char *) "PARA", (const FcChar8 *) "paratype"},
892 { (const FT_Char *) "QMSI", (const FcChar8 *) "qms"},
893 { (const FT_Char *) "RICO", (const FcChar8 *) "ricoh"},
894 { (const FT_Char *) "URW", (const FcChar8 *) "urw"},
895 { (const FT_Char *) "Y&Y", (const FcChar8 *) "y&y"}
2e2121f9
KP
896};
897
67accef4 898#define NUM_VENDOR_FOUNDRIES (int) (sizeof (FcVendorFoundries) / sizeof (FcVendorFoundries[0]))
2e2121f9
KP
899
900static const FcChar8 *
6ae6acf3 901FcVendorFoundry(const FT_Char vendor[4])
2ae95e77
JC
902{
903 int i;
2e2121f9
KP
904
905 if (vendor)
906 for(i = 0; i < NUM_VENDOR_FOUNDRIES; i++)
907 if (FcVendorMatch (vendor, FcVendorFoundries[i].vendor))
908 return FcVendorFoundries[i].foundry;
909 return 0;
2ae95e77
JC
910}
911
11fec41c 912typedef struct _FcStringConst {
6ae6acf3
KP
913 const FcChar8 *name;
914 int value;
11fec41c
KP
915} FcStringConst;
916
917static int
918FcStringIsConst (const FcChar8 *string,
919 const FcStringConst *c,
920 int nc)
921{
922 int i;
923
924 for (i = 0; i < nc; i++)
925 if (FcStrCmpIgnoreBlanksAndCase (string, c[i].name) == 0)
926 return c[i].value;
927 return -1;
928}
929
930static int
931FcStringContainsConst (const FcChar8 *string,
932 const FcStringConst *c,
933 int nc)
934{
935 int i;
936
937 for (i = 0; i < nc; i++)
938 if (FcStrContainsIgnoreBlanksAndCase (string, c[i].name))
939 return c[i].value;
940 return -1;
941}
942
8245771d
PL
943typedef FcChar8 *FC8;
944
11fec41c 945static const FcStringConst weightConsts[] = {
8245771d
PL
946 { (FC8) "thin", FC_WEIGHT_THIN },
947 { (FC8) "extralight", FC_WEIGHT_EXTRALIGHT },
948 { (FC8) "ultralight", FC_WEIGHT_ULTRALIGHT },
949 { (FC8) "light", FC_WEIGHT_LIGHT },
950 { (FC8) "book", FC_WEIGHT_BOOK },
951 { (FC8) "regular", FC_WEIGHT_REGULAR },
952 { (FC8) "normal", FC_WEIGHT_NORMAL },
953 { (FC8) "medium", FC_WEIGHT_MEDIUM },
954 { (FC8) "demibold", FC_WEIGHT_DEMIBOLD },
955 { (FC8) "demi", FC_WEIGHT_DEMIBOLD },
956 { (FC8) "semibold", FC_WEIGHT_SEMIBOLD },
957 { (FC8) "bold", FC_WEIGHT_BOLD },
958 { (FC8) "extrabold", FC_WEIGHT_EXTRABOLD },
959 { (FC8) "ultrabold", FC_WEIGHT_ULTRABOLD },
960 { (FC8) "black", FC_WEIGHT_BLACK },
961 { (FC8) "heavy", FC_WEIGHT_HEAVY },
11fec41c
KP
962};
963
67accef4 964#define NUM_WEIGHT_CONSTS (int) (sizeof (weightConsts) / sizeof (weightConsts[0]))
11fec41c
KP
965
966#define FcIsWeight(s) FcStringIsConst(s,weightConsts,NUM_WEIGHT_CONSTS)
967#define FcContainsWeight(s) FcStringContainsConst (s,weightConsts,NUM_WEIGHT_CONSTS)
968
969static const FcStringConst widthConsts[] = {
8245771d
PL
970 { (FC8) "ultracondensed", FC_WIDTH_ULTRACONDENSED },
971 { (FC8) "extracondensed", FC_WIDTH_EXTRACONDENSED },
972 { (FC8) "semicondensed", FC_WIDTH_SEMICONDENSED },
973 { (FC8) "condensed", FC_WIDTH_CONDENSED }, /* must be after *condensed */
974 { (FC8) "normal", FC_WIDTH_NORMAL },
975 { (FC8) "semiexpanded", FC_WIDTH_SEMIEXPANDED },
976 { (FC8) "extraexpanded", FC_WIDTH_EXTRAEXPANDED },
977 { (FC8) "ultraexpanded", FC_WIDTH_ULTRAEXPANDED },
978 { (FC8) "expanded", FC_WIDTH_EXPANDED }, /* must be after *expanded */
11fec41c
KP
979};
980
67accef4 981#define NUM_WIDTH_CONSTS (int) (sizeof (widthConsts) / sizeof (widthConsts[0]))
11fec41c
KP
982
983#define FcIsWidth(s) FcStringIsConst(s,widthConsts,NUM_WIDTH_CONSTS)
984#define FcContainsWidth(s) FcStringContainsConst (s,widthConsts,NUM_WIDTH_CONSTS)
985
986static const FcStringConst slantConsts[] = {
8245771d
PL
987 { (FC8) "italic", FC_SLANT_ITALIC },
988 { (FC8) "oblique", FC_SLANT_OBLIQUE },
11fec41c
KP
989};
990
67accef4 991#define NUM_SLANT_CONSTS (int) (sizeof (slantConsts) / sizeof (slantConsts[0]))
11fec41c
KP
992
993#define FcIsSlant(s) FcStringIsConst(s,slantConsts,NUM_SLANT_CONSTS)
994#define FcContainsSlant(s) FcStringContainsConst (s,slantConsts,NUM_SLANT_CONSTS)
2ae95e77 995
b68b9646
KP
996static double
997FcGetPixelSize (FT_Face face, int i)
998{
208a720f 999#if HAVE_FT_GET_BDF_PROPERTY
b68b9646
KP
1000 if (face->num_fixed_sizes == 1)
1001 {
1002 BDF_PropertyRec prop;
1003 int rc;
1004
8ebf7725 1005 rc = FT_Get_BDF_Property (face, "PIXEL_SIZE", &prop);
b68b9646
KP
1006 if (rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER)
1007 return (double) prop.u.integer;
1008 }
1009#endif
208a720f 1010#if HAVE_FT_BITMAP_SIZE_Y_PPEM
b68b9646 1011 return (double) face->available_sizes[i].y_ppem / 64.0;
4f38fa81 1012#else
6ae6acf3 1013 return (double) face->available_sizes[i].height;
4f38fa81 1014#endif
b68b9646
KP
1015}
1016
4f27c1c0 1017static FcBool
67accef4 1018FcStringInPatternElement (FcPattern *pat, const char *elt, FcChar8 *string)
4f27c1c0
KP
1019{
1020 int e;
1021 FcChar8 *old;
1022 for (e = 0; FcPatternGetString (pat, elt, e, &old) == FcResultMatch; e++)
1023 if (!FcStrCmpIgnoreBlanksAndCase (old, string))
1024 {
1025 return FcTrue;
4f27c1c0
KP
1026 }
1027 return FcFalse;
1028}
1029
24330d27 1030FcPattern *
ccb3e93b
KP
1031FcFreeTypeQuery (const FcChar8 *file,
1032 int id,
1033 FcBlanks *blanks,
1034 int *count)
24330d27 1035{
ccb3e93b
KP
1036 FT_Face face;
1037 FcPattern *pat;
11fec41c
KP
1038 int slant = -1;
1039 int weight = -1;
81fa16c3 1040 int width = -1;
ccb3e93b
KP
1041 int i;
1042 FcCharSet *cs;
d8d73958 1043 FcLangSet *ls;
ccb3e93b 1044 FT_Library ftLibrary;
4f27c1c0 1045#if 0
2e2121f9 1046 FcChar8 *family = 0;
4f27c1c0 1047#endif
dbf68dd5 1048 FcChar8 *complex;
2e2121f9 1049 const FcChar8 *foundry = 0;
848d32bd 1050 int spacing;
ccb3e93b 1051 TT_OS2 *os2;
79621aa5 1052#if HAVE_FT_GET_PS_FONT_INFO
d6ea8347 1053 PS_FontInfoRec psfontinfo;
79621aa5
KP
1054#endif
1055#if HAVE_FT_GET_BDF_PROPERTY
53183e66
KP
1056 BDF_PropertyRec prop;
1057#endif
a342e87d 1058 TT_Header *head;
e50b9ae7 1059 const FcChar8 *exclusiveLang = 0;
69937bd9
KP
1060 FT_SfntName sname;
1061 FT_UInt snamei, snamec;
4f27c1c0
KP
1062
1063 int nfamily = 0;
1064 int nfamily_lang = 0;
1065 int nstyle = 0;
1066 int nstyle_lang = 0;
1067 int nfullname = 0;
1068 int nfullname_lang = 0;
24330d27 1069
4f27c1c0
KP
1070 FcChar8 *style = 0;
1071 int st;
1072
24330d27
KP
1073 if (FT_Init_FreeType (&ftLibrary))
1074 return 0;
1075
ccb3e93b 1076 if (FT_New_Face (ftLibrary, (char *) file, id, &face))
24330d27
KP
1077 goto bail;
1078
1079 *count = face->num_faces;
1080
1081 pat = FcPatternCreate ();
1082 if (!pat)
1083 goto bail0;
1084
1085 if (!FcPatternAddBool (pat, FC_OUTLINE,
1086 (face->face_flags & FT_FACE_FLAG_SCALABLE) != 0))
1087 goto bail1;
1088
1089 if (!FcPatternAddBool (pat, FC_SCALABLE,
1090 (face->face_flags & FT_FACE_FLAG_SCALABLE) != 0))
1091 goto bail1;
1092
1093
2ae95e77
JC
1094 /*
1095 * Get the OS/2 table
1096 */
1097 os2 = (TT_OS2 *) FT_Get_Sfnt_Table (face, ft_sfnt_os2);
1098
2e2121f9
KP
1099 /*
1100 * Look first in the OS/2 table for the foundry, if
1101 * not found here, the various notices will be searched for
1102 * that information, either from the sfnt name tables or
0e7a4347
KP
1103 * the Postscript FontInfo dictionary. Finally, the
1104 * BDF properties will queried.
2e2121f9
KP
1105 */
1106
2ae95e77 1107 if (os2 && os2->version >= 0x0001 && os2->version != 0xffff)
2e2121f9 1108 foundry = FcVendorFoundry(os2->achVendID);
2ae95e77 1109
4f27c1c0
KP
1110 if (FcDebug () & FC_DBG_SCANV)
1111 printf ("\n");
69937bd9
KP
1112 /*
1113 * Grub through the name table looking for family
1114 * and style names. FreeType makes quite a hash
1115 * of them
1116 */
69937bd9
KP
1117 snamec = FT_Get_Sfnt_Name_Count (face);
1118 for (snamei = 0; snamei < snamec; snamei++)
1119 {
1120 FcChar8 *utf8;
573da729 1121 const FcChar8 *lang;
67accef4 1122 const char *elt = 0, *eltlang = 0;
4f27c1c0
KP
1123 int *np = 0, *nlangp = 0;
1124
69937bd9 1125 if (FT_Get_Sfnt_Name (face, snamei, &sname) != 0)
4f27c1c0 1126 continue;
69937bd9 1127
4f27c1c0
KP
1128 utf8 = FcSfntNameTranscode (&sname);
1129 lang = FcSfntNameLanguage (&sname);
1130
1131 if (!utf8)
69937bd9 1132 continue;
69937bd9 1133
69937bd9
KP
1134 switch (sname.name_id) {
1135 case TT_NAME_ID_FONT_FAMILY:
4f27c1c0 1136#if 0
69937bd9 1137 case TT_NAME_ID_PS_NAME:
4f27c1c0
KP
1138 case TT_NAME_ID_UNIQUE_ID:
1139#endif
1140 if (FcDebug () & FC_DBG_SCANV)
1141 printf ("found family (n %2d p %d e %d l 0x%04x) %s\n",
1142 sname.name_id, sname.platform_id,
1143 sname.encoding_id, sname.language_id,
1144 utf8);
69937bd9 1145
4f27c1c0
KP
1146 elt = FC_FAMILY;
1147 eltlang = FC_FAMILYLANG;
1148 np = &nfamily;
1149 nlangp = &nfamily_lang;
69937bd9 1150 break;
4f27c1c0
KP
1151 case TT_NAME_ID_FULL_NAME:
1152 case TT_NAME_ID_MAC_FULL_NAME:
1153 if (FcDebug () & FC_DBG_SCANV)
1154 printf ("found full (n %2d p %d e %d l 0x%04x) %s\n",
69937bd9
KP
1155 sname.name_id, sname.platform_id,
1156 sname.encoding_id, sname.language_id,
4f27c1c0 1157 utf8);
69937bd9 1158
4f27c1c0
KP
1159 elt = FC_FULLNAME;
1160 eltlang = FC_FULLNAMELANG;
1161 np = &nfullname;
1162 nlangp = &nfullname_lang;
69937bd9
KP
1163 break;
1164 case TT_NAME_ID_FONT_SUBFAMILY:
4f27c1c0
KP
1165 if (FcDebug () & FC_DBG_SCANV)
1166 printf ("found style (n %2d p %d e %d l 0x%04x) %s\n",
1167 sname.name_id, sname.platform_id,
1168 sname.encoding_id, sname.language_id,
1169 utf8);
1170
1171 elt = FC_STYLE;
1172 eltlang = FC_STYLELANG;
1173 np = &nstyle;
1174 nlangp = &nstyle_lang;
69937bd9 1175 break;
2ae95e77
JC
1176 case TT_NAME_ID_TRADEMARK:
1177 case TT_NAME_ID_MANUFACTURER:
2e2121f9 1178 /* If the foundry wasn't found in the OS/2 table, look here */
2ae95e77 1179 if(!foundry)
6ae6acf3 1180 foundry = FcNoticeFoundry((FT_String *) utf8);
2ae95e77 1181 break;
69937bd9 1182 }
4f27c1c0
KP
1183 if (elt)
1184 {
1185 if (FcStringInPatternElement (pat, elt, utf8))
1186 {
1187 free (utf8);
1188 continue;
1189 }
1190
1191 /* add new element */
1192 if (!FcPatternAddString (pat, elt, utf8))
1193 {
1194 free (utf8);
1195 goto bail1;
1196 }
1197 free (utf8);
1198 if (lang)
1199 {
1200 /* pad lang list with 'xx' to line up with elt */
1201 while (*nlangp < *np)
1202 {
8245771d 1203 if (!FcPatternAddString (pat, eltlang, (FcChar8 *) "xx"))
4f27c1c0
KP
1204 goto bail1;
1205 ++*nlangp;
1206 }
1207 if (!FcPatternAddString (pat, eltlang, lang))
1208 goto bail1;
1209 ++*nlangp;
1210 }
1211 ++*np;
1212 }
1213 else
69937bd9
KP
1214 free (utf8);
1215 }
1216
e4125ef9 1217 if (!nfamily && face->family_name &&
8245771d 1218 FcStrCmpIgnoreBlanksAndCase ((FcChar8 *) face->family_name, (FcChar8 *) "") != 0)
4f27c1c0
KP
1219 {
1220 if (FcDebug () & FC_DBG_SCANV)
e4125ef9 1221 printf ("using FreeType family \"%s\"\n", face->family_name);
8245771d 1222 if (!FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) face->family_name))
4f27c1c0
KP
1223 goto bail1;
1224 ++nfamily;
1225 }
69937bd9 1226
e4125ef9 1227 if (!nstyle && face->style_name &&
8245771d 1228 FcStrCmpIgnoreBlanksAndCase ((FcChar8 *) face->style_name, (FcChar8 *) "") != 0)
4f27c1c0
KP
1229 {
1230 if (FcDebug () & FC_DBG_SCANV)
e4125ef9 1231 printf ("using FreeType style \"%s\"\n", face->style_name);
8245771d 1232 if (!FcPatternAddString (pat, FC_STYLE, (FcChar8 *) face->style_name))
4f27c1c0
KP
1233 goto bail1;
1234 ++nstyle;
1235 }
69937bd9 1236
4f27c1c0 1237 if (!nfamily)
24330d27 1238 {
69937bd9 1239 FcChar8 *start, *end;
4f27c1c0 1240 FcChar8 *family;
69937bd9
KP
1241
1242 start = (FcChar8 *) strrchr ((char *) file, '/');
1243 if (start)
1244 start++;
24330d27 1245 else
69937bd9
KP
1246 start = (FcChar8 *) file;
1247 end = (FcChar8 *) strrchr ((char *) start, '.');
1248 if (!end)
1249 end = start + strlen ((char *) start);
9dac3c59 1250 /* freed below */
69937bd9
KP
1251 family = malloc (end - start + 1);
1252 strncpy ((char *) family, (char *) start, end - start);
1253 family[end - start] = '\0';
4f27c1c0 1254 if (FcDebug () & FC_DBG_SCANV)
e4125ef9 1255 printf ("using filename for family %s\n", family);
4f27c1c0
KP
1256 if (!FcPatternAddString (pat, FC_FAMILY, family))
1257 {
1258 free (family);
1259 goto bail1;
1260 }
1261 free (family);
1262 ++nfamily;
24330d27 1263 }
69937bd9 1264
4f27c1c0
KP
1265 /*
1266 * Walk through FC_FULLNAME entries eliding those in FC_FAMILY
1267 * or which are simply a FC_FAMILY and FC_STYLE glued together
1268 */
24330d27 1269 {
0d745819 1270 int fn, fa;
4f27c1c0
KP
1271 FcChar8 *full;
1272 FcChar8 *fam;
1273 FcChar8 *style;
1274
1275 for (fn = 0; FcPatternGetString (pat, FC_FULLNAME, fn, &full) == FcResultMatch; fn++)
1276 {
1277 FcBool remove = FcFalse;
1278 /*
1279 * Check each family
1280 */
1281 for (fa = 0; !remove &&
1282 FcPatternGetString (pat, FC_FAMILY,
1283 fa, &fam) == FcResultMatch;
1284 fa++)
1285 {
1286 /*
1287 * for exact match
1288 */
1289 if (!FcStrCmpIgnoreBlanksAndCase (full, fam))
1290 {
1291 remove = FcTrue;
1292 break;
1293 }
1294 /*
1295 * If the family is in the full name, check the
1296 * combination of this family with every style
1297 */
1298 if (!FcStrContainsIgnoreBlanksAndCase (full, fam))
1299 continue;
1300 for (st = 0; !remove &&
1301 FcPatternGetString (pat, FC_STYLE,
1302 st, &style) == FcResultMatch;
1303 st++)
1304 {
1305 FcChar8 *both = FcStrPlus (fam, style);
1306
1307 if (both)
1308 {
1309 if (FcStrCmpIgnoreBlanksAndCase (full, both) == 0)
1310 remove = FcTrue;
1311 free (both);
1312 }
1313 }
1314 }
1315 if (remove)
1316 {
1317 FcPatternRemove (pat, FC_FULLNAME, fn);
1318 FcPatternRemove (pat, FC_FULLNAMELANG, fn);
1319 fn--;
1320 nfullname--;
1321 nfullname_lang--;
1322 }
1323 }
1324 if (FcDebug () & FC_DBG_SCANV)
1325 for (fn = 0; FcPatternGetString (pat, FC_FULLNAME, fn, &full) == FcResultMatch; fn++)
1326 printf ("Saving unique fullname %s\n", full);
24330d27
KP
1327 }
1328
c1c3ba06 1329 if (!FcPatternAddString (pat, FC_FILE, file))
24330d27 1330 goto bail1;
e77c1718 1331
24330d27
KP
1332 if (!FcPatternAddInteger (pat, FC_INDEX, id))
1333 goto bail1;
1334
148656ed
KP
1335#if 0
1336 /*
1337 * don't even try this -- CJK 'monospace' fonts are really
1338 * dual width, and most other fonts don't bother to set
1339 * the attribute. Sigh.
1340 */
24330d27
KP
1341 if ((face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) != 0)
1342 if (!FcPatternAddInteger (pat, FC_SPACING, FC_MONO))
1343 goto bail1;
1344#endif
1345
a342e87d
KP
1346 /*
1347 * Find the font revision (if available)
1348 */
1349 head = (TT_Header *) FT_Get_Sfnt_Table (face, ft_sfnt_head);
1350 if (head)
1351 {
1352 if (!FcPatternAddInteger (pat, FC_FONTVERSION, head->Font_Revision))
1353 goto bail1;
1354 }
1355 else
1356 {
1357 if (!FcPatternAddInteger (pat, FC_FONTVERSION, 0))
1358 goto bail1;
1359 }
1360
4c003605
KP
1361 if (os2 && os2->version >= 0x0001 && os2->version != 0xffff)
1362 {
1363 for (i = 0; i < NUM_CODE_PAGE_RANGE; i++)
1364 {
1365 FT_ULong bits;
1366 int bit;
1367 if (FcCodePageRange[i].bit < 32)
1368 {
1369 bits = os2->ulCodePageRange1;
1370 bit = FcCodePageRange[i].bit;
1371 }
1372 else
1373 {
1374 bits = os2->ulCodePageRange2;
1375 bit = FcCodePageRange[i].bit - 32;
1376 }
1377 if (bits & (1 << bit))
1378 {
e50b9ae7
KP
1379 /*
1380 * If the font advertises support for multiple
1381 * "exclusive" languages, then include support
1382 * for any language found to have coverage
1383 */
1384 if (exclusiveLang)
1385 {
1386 exclusiveLang = 0;
1387 break;
1388 }
1389 exclusiveLang = FcCodePageRange[i].lang;
4c003605
KP
1390 }
1391 }
1392 }
1393
81fa16c3
KP
1394 if (os2 && os2->version != 0xffff)
1395 {
1396 if (os2->usWeightClass == 0)
11fec41c 1397 ;
81fa16c3
KP
1398 else if (os2->usWeightClass < 150)
1399 weight = FC_WEIGHT_THIN;
1400 else if (os2->usWeightClass < 250)
1401 weight = FC_WEIGHT_EXTRALIGHT;
1402 else if (os2->usWeightClass < 350)
1403 weight = FC_WEIGHT_LIGHT;
1404 else if (os2->usWeightClass < 450)
1405 weight = FC_WEIGHT_REGULAR;
1406 else if (os2->usWeightClass < 550)
1407 weight = FC_WEIGHT_MEDIUM;
1408 else if (os2->usWeightClass < 650)
1409 weight = FC_WEIGHT_SEMIBOLD;
1410 else if (os2->usWeightClass < 750)
1411 weight = FC_WEIGHT_BOLD;
1412 else if (os2->usWeightClass < 850)
1413 weight = FC_WEIGHT_EXTRABOLD;
1414 else if (os2->usWeightClass < 950)
1415 weight = FC_WEIGHT_BLACK;
81fa16c3
KP
1416
1417 switch (os2->usWidthClass) {
1418 case 1: width = FC_WIDTH_ULTRACONDENSED; break;
1419 case 2: width = FC_WIDTH_EXTRACONDENSED; break;
1420 case 3: width = FC_WIDTH_CONDENSED; break;
1421 case 4: width = FC_WIDTH_SEMICONDENSED; break;
1422 case 5: width = FC_WIDTH_NORMAL; break;
1423 case 6: width = FC_WIDTH_SEMIEXPANDED; break;
1424 case 7: width = FC_WIDTH_EXPANDED; break;
1425 case 8: width = FC_WIDTH_EXTRAEXPANDED; break;
1426 case 9: width = FC_WIDTH_ULTRAEXPANDED; break;
1427 }
1428 }
dbf68dd5
KP
1429 if (os2 && (complex = FcFontCapabilities(face)))
1430 {
1431 if (!FcPatternAddString (pat, FC_CAPABILITY, complex))
1432 {
1433 free (complex);
1434 goto bail1;
1435 }
1436 free (complex);
1437 }
d6ea8347
KP
1438
1439 /*
1440 * Type 1: Check for FontInfo dictionary information
1441 * Code from g2@magestudios.net (Gerard Escalante)
1442 */
1443
79621aa5 1444#if HAVE_FT_GET_PS_FONT_INFO
d6ea8347
KP
1445 if (FT_Get_PS_Font_Info(face, &psfontinfo) == 0)
1446 {
11fec41c 1447 if (weight == -1 && psfontinfo.weight)
52253696 1448 {
8245771d 1449 weight = FcIsWeight ((FcChar8 *) psfontinfo.weight);
11fec41c
KP
1450 if (FcDebug() & FC_DBG_SCANV)
1451 printf ("\tType1 weight %s maps to %d\n",
1452 psfontinfo.weight, weight);
52253696 1453 }
d6ea8347 1454
70ee8809
KP
1455#if 0
1456 /*
1457 * Don't bother with italic_angle; FreeType already extracts that
1458 * information for us and sticks it into style_flags
1459 */
1460 if (psfontinfo.italic_angle)
d6ea8347 1461 slant = FC_SLANT_ITALIC;
70ee8809 1462 else
d6ea8347 1463 slant = FC_SLANT_ROMAN;
70ee8809 1464#endif
2ae95e77
JC
1465
1466 if(!foundry)
2e2121f9 1467 foundry = FcNoticeFoundry(psfontinfo.notice);
d6ea8347 1468 }
79621aa5 1469#endif /* HAVE_FT_GET_PS_FONT_INFO */
81fa16c3 1470
79621aa5 1471#if HAVE_FT_GET_BDF_PROPERTY
0e7a4347
KP
1472 /*
1473 * Finally, look for a FOUNDRY BDF property if no other
1474 * mechanism has managed to locate a foundry
1475 */
1476
1477 if (!foundry)
1478 {
1479 int rc;
8ebf7725 1480 rc = FT_Get_BDF_Property(face, "FOUNDRY", &prop);
0e7a4347 1481 if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM)
8245771d 1482 foundry = (FcChar8 *) prop.u.atom;
0e7a4347
KP
1483 }
1484
1485 if (width == -1)
1486 {
8ebf7725 1487 if (FT_Get_BDF_Property(face, "RELATIVE_SETWIDTH", &prop) == 0 &&
0e7a4347
KP
1488 (prop.type == BDF_PROPERTY_TYPE_INTEGER ||
1489 prop.type == BDF_PROPERTY_TYPE_CARDINAL))
1490 {
1491 FT_Int32 value;
1492
1493 if (prop.type == BDF_PROPERTY_TYPE_INTEGER)
1494 value = prop.u.integer;
1495 else
1496 value = (FT_Int32) prop.u.cardinal;
1497 switch ((value + 5) / 10) {
1498 case 1: width = FC_WIDTH_ULTRACONDENSED; break;
1499 case 2: width = FC_WIDTH_EXTRACONDENSED; break;
1500 case 3: width = FC_WIDTH_CONDENSED; break;
1501 case 4: width = FC_WIDTH_SEMICONDENSED; break;
1502 case 5: width = FC_WIDTH_NORMAL; break;
1503 case 6: width = FC_WIDTH_SEMIEXPANDED; break;
1504 case 7: width = FC_WIDTH_EXPANDED; break;
1505 case 8: width = FC_WIDTH_EXTRAEXPANDED; break;
1506 case 9: width = FC_WIDTH_ULTRAEXPANDED; break;
1507 }
1508 }
0b7a0da2 1509 if (width == -1 &&
8ebf7725 1510 FT_Get_BDF_Property (face, "SETWIDTH_NAME", &prop) == 0 &&
0b7a0da2 1511 prop.type == BDF_PROPERTY_TYPE_ATOM)
0e7a4347 1512 {
8245771d 1513 width = FcIsWidth ((FcChar8 *) prop.u.atom);
0e7a4347 1514 if (FcDebug () & FC_DBG_SCANV)
0b7a0da2 1515 printf ("\tsetwidth %s maps to %d\n", prop.u.atom, width);
0e7a4347
KP
1516 }
1517 }
0e7a4347
KP
1518#endif
1519
11fec41c
KP
1520 /*
1521 * Look for weight, width and slant names in the style value
1522 */
4f27c1c0 1523 for (st = 0; FcPatternGetString (pat, FC_STYLE, st, &style) == FcResultMatch; st++)
11fec41c
KP
1524 {
1525 if (weight == -1)
1526 {
1527 weight = FcContainsWeight (style);
1528 if (FcDebug() & FC_DBG_SCANV)
1529 printf ("\tStyle %s maps to weight %d\n", style, weight);
1530 }
1531 if (width == -1)
1532 {
1533 width = FcContainsWidth (style);
1534 if (FcDebug() & FC_DBG_SCANV)
1535 printf ("\tStyle %s maps to width %d\n", style, width);
1536 }
1537 if (slant == -1)
1538 {
1539 slant = FcContainsSlant (style);
1540 if (FcDebug() & FC_DBG_SCANV)
1541 printf ("\tStyle %s maps to slant %d\n", style, slant);
1542 }
1543 }
1544 /*
1545 * Pull default values from the FreeType flags if more
1546 * specific values not found above
1547 */
1548 if (slant == -1)
1549 {
1550 slant = FC_SLANT_ROMAN;
1551 if (face->style_flags & FT_STYLE_FLAG_ITALIC)
1552 slant = FC_SLANT_ITALIC;
1553 }
1554
1555 if (weight == -1)
1556 {
1557 weight = FC_WEIGHT_MEDIUM;
1558 if (face->style_flags & FT_STYLE_FLAG_BOLD)
1559 weight = FC_WEIGHT_BOLD;
1560 }
1561
89e28590
KP
1562 if (width == -1)
1563 width = FC_WIDTH_NORMAL;
1564
1565 if (foundry == 0)
8245771d 1566 foundry = (FcChar8 *) "unknown";
89e28590 1567
81fa16c3
KP
1568 if (!FcPatternAddInteger (pat, FC_SLANT, slant))
1569 goto bail1;
1570
1571 if (!FcPatternAddInteger (pat, FC_WEIGHT, weight))
1572 goto bail1;
1573
89e28590
KP
1574 if (!FcPatternAddInteger (pat, FC_WIDTH, width))
1575 goto bail1;
81fa16c3 1576
89e28590
KP
1577 if (!FcPatternAddString (pat, FC_FOUNDRY, foundry))
1578 goto bail1;
2e2121f9 1579
4c003605
KP
1580 /*
1581 * Compute the unicode coverage for the font
1582 */
848d32bd 1583 cs = FcFreeTypeCharSetAndSpacing (face, blanks, &spacing);
24330d27
KP
1584 if (!cs)
1585 goto bail1;
1586
79621aa5 1587#if HAVE_FT_GET_BDF_PROPERTY
ecb7c180
JC
1588 /* For PCF fonts, override the computed spacing with the one from
1589 the property */
8ebf7725 1590 if(FT_Get_BDF_Property(face, "SPACING", &prop) == 0 &&
ecb7c180 1591 prop.type == BDF_PROPERTY_TYPE_ATOM) {
02638f1a 1592 if(!strcmp(prop.u.atom, "c") || !strcmp(prop.u.atom, "C"))
ecb7c180 1593 spacing = FC_CHARCELL;
02638f1a 1594 else if(!strcmp(prop.u.atom, "m") || !strcmp(prop.u.atom, "M"))
ecb7c180 1595 spacing = FC_MONO;
02638f1a 1596 else if(!strcmp(prop.u.atom, "p") || !strcmp(prop.u.atom, "P"))
ecb7c180
JC
1597 spacing = FC_PROPORTIONAL;
1598 }
1599#endif
1600
24330d27
KP
1601 /*
1602 * Skip over PCF fonts that have no encoded characters; they're
1603 * usually just Unicode fonts transcoded to some legacy encoding
6f767cec
PL
1604 * ftglue.c forces us to approximate whether a font is a PCF font
1605 * or not by whether it has any BDF properties. Try PIXEL_SIZE;
1606 * I don't know how to get a list of BDF properties on the font. -PL
24330d27 1607 */
e50b9ae7 1608 if (FcCharSetCount (cs) == 0)
24330d27 1609 {
6f767cec
PL
1610#if HAVE_FT_GET_BDF_PROPERTY
1611 if(FT_Get_BDF_Property(face, "PIXEL_SIZE", &prop) == 0)
24330d27 1612 goto bail2;
8ebf7725 1613#endif
6f767cec 1614 }
24330d27
KP
1615
1616 if (!FcPatternAddCharSet (pat, FC_CHARSET, cs))
1617 goto bail2;
4c003605 1618
d8d73958
KP
1619 ls = FcFreeTypeLangSet (cs, exclusiveLang);
1620 if (!ls)
1621 goto bail2;
1622
1623 if (!FcPatternAddLangSet (pat, FC_LANG, ls))
53183e66
KP
1624 {
1625 FcLangSetDestroy (ls);
d8d73958 1626 goto bail2;
53183e66
KP
1627 }
1628
1629 FcLangSetDestroy (ls);
82f4243f 1630
848d32bd
KP
1631 if (spacing != FC_PROPORTIONAL)
1632 if (!FcPatternAddInteger (pat, FC_SPACING, spacing))
1633 goto bail2;
1634
24330d27
KP
1635 if (!(face->face_flags & FT_FACE_FLAG_SCALABLE))
1636 {
1637 for (i = 0; i < face->num_fixed_sizes; i++)
1638 if (!FcPatternAddDouble (pat, FC_PIXEL_SIZE,
b68b9646 1639 FcGetPixelSize (face, i)))
f8a17f32 1640 goto bail2;
24330d27 1641 if (!FcPatternAddBool (pat, FC_ANTIALIAS, FcFalse))
f8a17f32 1642 goto bail2;
79621aa5 1643#if HAVE_FT_GET_BDF_PROPERTY
0f362ad5
JC
1644 if(face->num_fixed_sizes == 1) {
1645 int rc;
1646 int value;
0f362ad5 1647
5657098e
PL
1648 /* skip bitmap fonts which do not even have a family name */
1649 rc = FT_Get_BDF_Property(face, "FAMILY_NAME", &prop);
1650 if (rc != 0 || prop.type != BDF_PROPERTY_TYPE_ATOM)
1651 goto bail2;
1652
8ebf7725 1653 rc = FT_Get_BDF_Property(face, "POINT_SIZE", &prop);
0f362ad5
JC
1654 if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER)
1655 value = prop.u.integer;
1656 else if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_CARDINAL)
1657 value = prop.u.cardinal;
1658 else
1659 goto nevermind;
1660 if(!FcPatternAddDouble(pat, FC_SIZE, value / 10.0))
1661 goto nevermind;
1662
8ebf7725 1663 rc = FT_Get_BDF_Property(face, "RESOLUTION_Y", &prop);
0f362ad5
JC
1664 if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER)
1665 value = prop.u.integer;
1666 else if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_CARDINAL)
1667 value = prop.u.cardinal;
1668 else
1669 goto nevermind;
1670 if(!FcPatternAddDouble(pat, FC_DPI, (double)value))
1671 goto nevermind;
1672
1673 }
1674 nevermind:
1675 ;
1676#endif
24330d27 1677 }
537e3d23
KP
1678#if HAVE_FT_GET_X11_FONT_FORMAT
1679 /*
1680 * Use the (not well documented or supported) X-specific function
1681 * from FreeType to figure out the font format
1682 */
1683 {
1684 const char *font_format = FT_Get_X11_Font_Format (face);
1685 if (font_format)
8245771d 1686 FcPatternAddString (pat, FC_FONTFORMAT, (FcChar8 *) font_format);
537e3d23
KP
1687 }
1688#endif
24330d27 1689
11fec41c
KP
1690 /*
1691 * Drop our reference to the charset
1692 */
1693 FcCharSetDestroy (cs);
1694
1695 /*
1696 * Deallocate family/style values
1697 */
1698
24330d27
KP
1699 FT_Done_Face (face);
1700 FT_Done_FreeType (ftLibrary);
1701 return pat;
1702
1703bail2:
1704 FcCharSetDestroy (cs);
1705bail1:
1706 FcPatternDestroy (pat);
1707bail0:
1708 FT_Done_Face (face);
1709bail:
1710 FT_Done_FreeType (ftLibrary);
1711 return 0;
1712}
c647f6f1
KP
1713
1714
c647f6f1
KP
1715/*
1716 * For our purposes, this approximation is sufficient
1717 */
79621aa5 1718#if !HAVE_FT_GET_NEXT_CHAR
c647f6f1
KP
1719#define FT_Get_Next_Char(face, ucs4, gi) ((ucs4) >= 0xffffff ? \
1720 (*(gi) = 0), 0 : \
1721 (*(gi) = 1), (ucs4) + 1)
ec0c740e 1722#warning "No FT_Get_Next_Char: Please install freetype version 2.1.0 or newer"
c647f6f1
KP
1723#endif
1724
1725typedef struct _FcCharEnt {
1726 FcChar16 bmp;
1727 unsigned char encode;
1728} FcCharEnt;
1729
1730struct _FcCharMap {
1731 const FcCharEnt *ent;
1732 int nent;
1733};
1734
1735typedef struct _FcFontDecode {
1736 FT_Encoding encoding;
1737 const FcCharMap *map;
1738 FcChar32 max;
1739} FcFontDecode;
1740
1741static const FcCharEnt AppleRomanEnt[] = {
1742 { 0x0020, 0x20 }, /* SPACE */
1743 { 0x0021, 0x21 }, /* EXCLAMATION MARK */
1744 { 0x0022, 0x22 }, /* QUOTATION MARK */
1745 { 0x0023, 0x23 }, /* NUMBER SIGN */
1746 { 0x0024, 0x24 }, /* DOLLAR SIGN */
1747 { 0x0025, 0x25 }, /* PERCENT SIGN */
1748 { 0x0026, 0x26 }, /* AMPERSAND */
1749 { 0x0027, 0x27 }, /* APOSTROPHE */
1750 { 0x0028, 0x28 }, /* LEFT PARENTHESIS */
1751 { 0x0029, 0x29 }, /* RIGHT PARENTHESIS */
1752 { 0x002A, 0x2A }, /* ASTERISK */
1753 { 0x002B, 0x2B }, /* PLUS SIGN */
1754 { 0x002C, 0x2C }, /* COMMA */
1755 { 0x002D, 0x2D }, /* HYPHEN-MINUS */
1756 { 0x002E, 0x2E }, /* FULL STOP */
1757 { 0x002F, 0x2F }, /* SOLIDUS */
1758 { 0x0030, 0x30 }, /* DIGIT ZERO */
1759 { 0x0031, 0x31 }, /* DIGIT ONE */
1760 { 0x0032, 0x32 }, /* DIGIT TWO */
1761 { 0x0033, 0x33 }, /* DIGIT THREE */
1762 { 0x0034, 0x34 }, /* DIGIT FOUR */
1763 { 0x0035, 0x35 }, /* DIGIT FIVE */
1764 { 0x0036, 0x36 }, /* DIGIT SIX */
1765 { 0x0037, 0x37 }, /* DIGIT SEVEN */
1766 { 0x0038, 0x38 }, /* DIGIT EIGHT */
1767 { 0x0039, 0x39 }, /* DIGIT NINE */
1768 { 0x003A, 0x3A }, /* COLON */
1769 { 0x003B, 0x3B }, /* SEMICOLON */
1770 { 0x003C, 0x3C }, /* LESS-THAN SIGN */
1771 { 0x003D, 0x3D }, /* EQUALS SIGN */
1772 { 0x003E, 0x3E }, /* GREATER-THAN SIGN */
1773 { 0x003F, 0x3F }, /* QUESTION MARK */
1774 { 0x0040, 0x40 }, /* COMMERCIAL AT */
1775 { 0x0041, 0x41 }, /* LATIN CAPITAL LETTER A */
1776 { 0x0042, 0x42 }, /* LATIN CAPITAL LETTER B */
1777 { 0x0043, 0x43 }, /* LATIN CAPITAL LETTER C */
1778 { 0x0044, 0x44 }, /* LATIN CAPITAL LETTER D */
1779 { 0x0045, 0x45 }, /* LATIN CAPITAL LETTER E */
1780 { 0x0046, 0x46 }, /* LATIN CAPITAL LETTER F */
1781 { 0x0047, 0x47 }, /* LATIN CAPITAL LETTER G */
1782 { 0x0048, 0x48 }, /* LATIN CAPITAL LETTER H */
1783 { 0x0049, 0x49 }, /* LATIN CAPITAL LETTER I */
1784 { 0x004A, 0x4A }, /* LATIN CAPITAL LETTER J */
1785 { 0x004B, 0x4B }, /* LATIN CAPITAL LETTER K */
1786 { 0x004C, 0x4C }, /* LATIN CAPITAL LETTER L */
1787 { 0x004D, 0x4D }, /* LATIN CAPITAL LETTER M */
1788 { 0x004E, 0x4E }, /* LATIN CAPITAL LETTER N */
1789 { 0x004F, 0x4F }, /* LATIN CAPITAL LETTER O */
1790 { 0x0050, 0x50 }, /* LATIN CAPITAL LETTER P */
1791 { 0x0051, 0x51 }, /* LATIN CAPITAL LETTER Q */
1792 { 0x0052, 0x52 }, /* LATIN CAPITAL LETTER R */
1793 { 0x0053, 0x53 }, /* LATIN CAPITAL LETTER S */
1794 { 0x0054, 0x54 }, /* LATIN CAPITAL LETTER T */
1795 { 0x0055, 0x55 }, /* LATIN CAPITAL LETTER U */
1796 { 0x0056, 0x56 }, /* LATIN CAPITAL LETTER V */
1797 { 0x0057, 0x57 }, /* LATIN CAPITAL LETTER W */
1798 { 0x0058, 0x58 }, /* LATIN CAPITAL LETTER X */
1799 { 0x0059, 0x59 }, /* LATIN CAPITAL LETTER Y */
1800 { 0x005A, 0x5A }, /* LATIN CAPITAL LETTER Z */
1801 { 0x005B, 0x5B }, /* LEFT SQUARE BRACKET */
1802 { 0x005C, 0x5C }, /* REVERSE SOLIDUS */
1803 { 0x005D, 0x5D }, /* RIGHT SQUARE BRACKET */
1804 { 0x005E, 0x5E }, /* CIRCUMFLEX ACCENT */
1805 { 0x005F, 0x5F }, /* LOW LINE */
1806 { 0x0060, 0x60 }, /* GRAVE ACCENT */
1807 { 0x0061, 0x61 }, /* LATIN SMALL LETTER A */
1808 { 0x0062, 0x62 }, /* LATIN SMALL LETTER B */
1809 { 0x0063, 0x63 }, /* LATIN SMALL LETTER C */
1810 { 0x0064, 0x64 }, /* LATIN SMALL LETTER D */
1811 { 0x0065, 0x65 }, /* LATIN SMALL LETTER E */
1812 { 0x0066, 0x66 }, /* LATIN SMALL LETTER F */
1813 { 0x0067, 0x67 }, /* LATIN SMALL LETTER G */
1814 { 0x0068, 0x68 }, /* LATIN SMALL LETTER H */
1815 { 0x0069, 0x69 }, /* LATIN SMALL LETTER I */
1816 { 0x006A, 0x6A }, /* LATIN SMALL LETTER J */
1817 { 0x006B, 0x6B }, /* LATIN SMALL LETTER K */
1818 { 0x006C, 0x6C }, /* LATIN SMALL LETTER L */
1819 { 0x006D, 0x6D }, /* LATIN SMALL LETTER M */
1820 { 0x006E, 0x6E }, /* LATIN SMALL LETTER N */
1821 { 0x006F, 0x6F }, /* LATIN SMALL LETTER O */
1822 { 0x0070, 0x70 }, /* LATIN SMALL LETTER P */
1823 { 0x0071, 0x71 }, /* LATIN SMALL LETTER Q */
1824 { 0x0072, 0x72 }, /* LATIN SMALL LETTER R */
1825 { 0x0073, 0x73 }, /* LATIN SMALL LETTER S */
1826 { 0x0074, 0x74 }, /* LATIN SMALL LETTER T */
1827 { 0x0075, 0x75 }, /* LATIN SMALL LETTER U */
1828 { 0x0076, 0x76 }, /* LATIN SMALL LETTER V */
1829 { 0x0077, 0x77 }, /* LATIN SMALL LETTER W */
1830 { 0x0078, 0x78 }, /* LATIN SMALL LETTER X */
1831 { 0x0079, 0x79 }, /* LATIN SMALL LETTER Y */
1832 { 0x007A, 0x7A }, /* LATIN SMALL LETTER Z */
1833 { 0x007B, 0x7B }, /* LEFT CURLY BRACKET */
1834 { 0x007C, 0x7C }, /* VERTICAL LINE */
1835 { 0x007D, 0x7D }, /* RIGHT CURLY BRACKET */
1836 { 0x007E, 0x7E }, /* TILDE */
1837 { 0x00A0, 0xCA }, /* NO-BREAK SPACE */
1838 { 0x00A1, 0xC1 }, /* INVERTED EXCLAMATION MARK */
1839 { 0x00A2, 0xA2 }, /* CENT SIGN */
1840 { 0x00A3, 0xA3 }, /* POUND SIGN */
1841 { 0x00A5, 0xB4 }, /* YEN SIGN */
1842 { 0x00A7, 0xA4 }, /* SECTION SIGN */
1843 { 0x00A8, 0xAC }, /* DIAERESIS */
1844 { 0x00A9, 0xA9 }, /* COPYRIGHT SIGN */
1845 { 0x00AA, 0xBB }, /* FEMININE ORDINAL INDICATOR */
1846 { 0x00AB, 0xC7 }, /* LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */
1847 { 0x00AC, 0xC2 }, /* NOT SIGN */
1848 { 0x00AE, 0xA8 }, /* REGISTERED SIGN */
1849 { 0x00AF, 0xF8 }, /* MACRON */
1850 { 0x00B0, 0xA1 }, /* DEGREE SIGN */
1851 { 0x00B1, 0xB1 }, /* PLUS-MINUS SIGN */
1852 { 0x00B4, 0xAB }, /* ACUTE ACCENT */
1853 { 0x00B5, 0xB5 }, /* MICRO SIGN */
1854 { 0x00B6, 0xA6 }, /* PILCROW SIGN */
1855 { 0x00B7, 0xE1 }, /* MIDDLE DOT */
1856 { 0x00B8, 0xFC }, /* CEDILLA */
1857 { 0x00BA, 0xBC }, /* MASCULINE ORDINAL INDICATOR */
1858 { 0x00BB, 0xC8 }, /* RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */
1859 { 0x00BF, 0xC0 }, /* INVERTED QUESTION MARK */
1860 { 0x00C0, 0xCB }, /* LATIN CAPITAL LETTER A WITH GRAVE */
1861 { 0x00C1, 0xE7 }, /* LATIN CAPITAL LETTER A WITH ACUTE */
1862 { 0x00C2, 0xE5 }, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX */
1863 { 0x00C3, 0xCC }, /* LATIN CAPITAL LETTER A WITH TILDE */
1864 { 0x00C4, 0x80 }, /* LATIN CAPITAL LETTER A WITH DIAERESIS */
1865 { 0x00C5, 0x81 }, /* LATIN CAPITAL LETTER A WITH RING ABOVE */
1866 { 0x00C6, 0xAE }, /* LATIN CAPITAL LETTER AE */
1867 { 0x00C7, 0x82 }, /* LATIN CAPITAL LETTER C WITH CEDILLA */
1868 { 0x00C8, 0xE9 }, /* LATIN CAPITAL LETTER E WITH GRAVE */
1869 { 0x00C9, 0x83 }, /* LATIN CAPITAL LETTER E WITH ACUTE */
1870 { 0x00CA, 0xE6 }, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
1871 { 0x00CB, 0xE8 }, /* LATIN CAPITAL LETTER E WITH DIAERESIS */
1872 { 0x00CC, 0xED }, /* LATIN CAPITAL LETTER I WITH GRAVE */
1873 { 0x00CD, 0xEA }, /* LATIN CAPITAL LETTER I WITH ACUTE */
1874 { 0x00CE, 0xEB }, /* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */
1875 { 0x00CF, 0xEC }, /* LATIN CAPITAL LETTER I WITH DIAERESIS */
1876 { 0x00D1, 0x84 }, /* LATIN CAPITAL LETTER N WITH TILDE */
1877 { 0x00D2, 0xF1 }, /* LATIN CAPITAL LETTER O WITH GRAVE */
1878 { 0x00D3, 0xEE }, /* LATIN CAPITAL LETTER O WITH ACUTE */
1879 { 0x00D4, 0xEF }, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX */
1880 { 0x00D5, 0xCD }, /* LATIN CAPITAL LETTER O WITH TILDE */
1881 { 0x00D6, 0x85 }, /* LATIN CAPITAL LETTER O WITH DIAERESIS */
1882 { 0x00D8, 0xAF }, /* LATIN CAPITAL LETTER O WITH STROKE */
1883 { 0x00D9, 0xF4 }, /* LATIN CAPITAL LETTER U WITH GRAVE */
1884 { 0x00DA, 0xF2 }, /* LATIN CAPITAL LETTER U WITH ACUTE */
1885 { 0x00DB, 0xF3 }, /* LATIN CAPITAL LETTER U WITH CIRCUMFLEX */
1886 { 0x00DC, 0x86 }, /* LATIN CAPITAL LETTER U WITH DIAERESIS */
1887 { 0x00DF, 0xA7 }, /* LATIN SMALL LETTER SHARP S */
1888 { 0x00E0, 0x88 }, /* LATIN SMALL LETTER A WITH GRAVE */
1889 { 0x00E1, 0x87 }, /* LATIN SMALL LETTER A WITH ACUTE */
1890 { 0x00E2, 0x89 }, /* LATIN SMALL LETTER A WITH CIRCUMFLEX */
1891 { 0x00E3, 0x8B }, /* LATIN SMALL LETTER A WITH TILDE */
1892 { 0x00E4, 0x8A }, /* LATIN SMALL LETTER A WITH DIAERESIS */
1893 { 0x00E5, 0x8C }, /* LATIN SMALL LETTER A WITH RING ABOVE */
1894 { 0x00E6, 0xBE }, /* LATIN SMALL LETTER AE */
1895 { 0x00E7, 0x8D }, /* LATIN SMALL LETTER C WITH CEDILLA */
1896 { 0x00E8, 0x8F }, /* LATIN SMALL LETTER E WITH GRAVE */
1897 { 0x00E9, 0x8E }, /* LATIN SMALL LETTER E WITH ACUTE */
1898 { 0x00EA, 0x90 }, /* LATIN SMALL LETTER E WITH CIRCUMFLEX */
1899 { 0x00EB, 0x91 }, /* LATIN SMALL LETTER E WITH DIAERESIS */
1900 { 0x00EC, 0x93 }, /* LATIN SMALL LETTER I WITH GRAVE */
1901 { 0x00ED, 0x92 }, /* LATIN SMALL LETTER I WITH ACUTE */
1902 { 0x00EE, 0x94 }, /* LATIN SMALL LETTER I WITH CIRCUMFLEX */
1903 { 0x00EF, 0x95 }, /* LATIN SMALL LETTER I WITH DIAERESIS */
1904 { 0x00F1, 0x96 }, /* LATIN SMALL LETTER N WITH TILDE */
1905 { 0x00F2, 0x98 }, /* LATIN SMALL LETTER O WITH GRAVE */
1906 { 0x00F3, 0x97 }, /* LATIN SMALL LETTER O WITH ACUTE */
1907 { 0x00F4, 0x99 }, /* LATIN SMALL LETTER O WITH CIRCUMFLEX */
1908 { 0x00F5, 0x9B }, /* LATIN SMALL LETTER O WITH TILDE */
1909 { 0x00F6, 0x9A }, /* LATIN SMALL LETTER O WITH DIAERESIS */
1910 { 0x00F7, 0xD6 }, /* DIVISION SIGN */
1911 { 0x00F8, 0xBF }, /* LATIN SMALL LETTER O WITH STROKE */
1912 { 0x00F9, 0x9D }, /* LATIN SMALL LETTER U WITH GRAVE */
1913 { 0x00FA, 0x9C }, /* LATIN SMALL LETTER U WITH ACUTE */
1914 { 0x00FB, 0x9E }, /* LATIN SMALL LETTER U WITH CIRCUMFLEX */
1915 { 0x00FC, 0x9F }, /* LATIN SMALL LETTER U WITH DIAERESIS */
1916 { 0x00FF, 0xD8 }, /* LATIN SMALL LETTER Y WITH DIAERESIS */
1917 { 0x0131, 0xF5 }, /* LATIN SMALL LETTER DOTLESS I */
1918 { 0x0152, 0xCE }, /* LATIN CAPITAL LIGATURE OE */
1919 { 0x0153, 0xCF }, /* LATIN SMALL LIGATURE OE */
1920 { 0x0178, 0xD9 }, /* LATIN CAPITAL LETTER Y WITH DIAERESIS */
1921 { 0x0192, 0xC4 }, /* LATIN SMALL LETTER F WITH HOOK */
1922 { 0x02C6, 0xF6 }, /* MODIFIER LETTER CIRCUMFLEX ACCENT */
1923 { 0x02C7, 0xFF }, /* CARON */
1924 { 0x02D8, 0xF9 }, /* BREVE */
1925 { 0x02D9, 0xFA }, /* DOT ABOVE */
1926 { 0x02DA, 0xFB }, /* RING ABOVE */
1927 { 0x02DB, 0xFE }, /* OGONEK */
1928 { 0x02DC, 0xF7 }, /* SMALL TILDE */
1929 { 0x02DD, 0xFD }, /* DOUBLE ACUTE ACCENT */
1930 { 0x03A9, 0xBD }, /* GREEK CAPITAL LETTER OMEGA */
1931 { 0x03C0, 0xB9 }, /* GREEK SMALL LETTER PI */
1932 { 0x2013, 0xD0 }, /* EN DASH */
1933 { 0x2014, 0xD1 }, /* EM DASH */
1934 { 0x2018, 0xD4 }, /* LEFT SINGLE QUOTATION MARK */
1935 { 0x2019, 0xD5 }, /* RIGHT SINGLE QUOTATION MARK */
1936 { 0x201A, 0xE2 }, /* SINGLE LOW-9 QUOTATION MARK */
1937 { 0x201C, 0xD2 }, /* LEFT DOUBLE QUOTATION MARK */
1938 { 0x201D, 0xD3 }, /* RIGHT DOUBLE QUOTATION MARK */
1939 { 0x201E, 0xE3 }, /* DOUBLE LOW-9 QUOTATION MARK */
1940 { 0x2020, 0xA0 }, /* DAGGER */
1941 { 0x2021, 0xE0 }, /* DOUBLE DAGGER */
1942 { 0x2022, 0xA5 }, /* BULLET */
1943 { 0x2026, 0xC9 }, /* HORIZONTAL ELLIPSIS */
1944 { 0x2030, 0xE4 }, /* PER MILLE SIGN */
1945 { 0x2039, 0xDC }, /* SINGLE LEFT-POINTING ANGLE QUOTATION MARK */
1946 { 0x203A, 0xDD }, /* SINGLE RIGHT-POINTING ANGLE QUOTATION MARK */
1947 { 0x2044, 0xDA }, /* FRACTION SLASH */
1948 { 0x20AC, 0xDB }, /* EURO SIGN */
1949 { 0x2122, 0xAA }, /* TRADE MARK SIGN */
1950 { 0x2202, 0xB6 }, /* PARTIAL DIFFERENTIAL */
1951 { 0x2206, 0xC6 }, /* INCREMENT */
1952 { 0x220F, 0xB8 }, /* N-ARY PRODUCT */
1953 { 0x2211, 0xB7 }, /* N-ARY SUMMATION */
1954 { 0x221A, 0xC3 }, /* SQUARE ROOT */
1955 { 0x221E, 0xB0 }, /* INFINITY */
1956 { 0x222B, 0xBA }, /* INTEGRAL */
1957 { 0x2248, 0xC5 }, /* ALMOST EQUAL TO */
1958 { 0x2260, 0xAD }, /* NOT EQUAL TO */
1959 { 0x2264, 0xB2 }, /* LESS-THAN OR EQUAL TO */
1960 { 0x2265, 0xB3 }, /* GREATER-THAN OR EQUAL TO */
1961 { 0x25CA, 0xD7 }, /* LOZENGE */
1962 { 0xF8FF, 0xF0 }, /* Apple logo */
1963 { 0xFB01, 0xDE }, /* LATIN SMALL LIGATURE FI */
1964 { 0xFB02, 0xDF }, /* LATIN SMALL LIGATURE FL */
1965};
1966
1967static const FcCharMap AppleRoman = {
1968 AppleRomanEnt,
1969 sizeof (AppleRomanEnt) / sizeof (AppleRomanEnt[0])
1970};
1971
1972static const FcCharEnt AdobeSymbolEnt[] = {
1973 { 0x0020, 0x20 }, /* SPACE # space */
1974 { 0x0021, 0x21 }, /* EXCLAMATION MARK # exclam */
1975 { 0x0023, 0x23 }, /* NUMBER SIGN # numbersign */
1976 { 0x0025, 0x25 }, /* PERCENT SIGN # percent */
1977 { 0x0026, 0x26 }, /* AMPERSAND # ampersand */
1978 { 0x0028, 0x28 }, /* LEFT PARENTHESIS # parenleft */
1979 { 0x0029, 0x29 }, /* RIGHT PARENTHESIS # parenright */
1980 { 0x002B, 0x2B }, /* PLUS SIGN # plus */
1981 { 0x002C, 0x2C }, /* COMMA # comma */
1982 { 0x002E, 0x2E }, /* FULL STOP # period */
1983 { 0x002F, 0x2F }, /* SOLIDUS # slash */
1984 { 0x0030, 0x30 }, /* DIGIT ZERO # zero */
1985 { 0x0031, 0x31 }, /* DIGIT ONE # one */
1986 { 0x0032, 0x32 }, /* DIGIT TWO # two */
1987 { 0x0033, 0x33 }, /* DIGIT THREE # three */
1988 { 0x0034, 0x34 }, /* DIGIT FOUR # four */
1989 { 0x0035, 0x35 }, /* DIGIT FIVE # five */
1990 { 0x0036, 0x36 }, /* DIGIT SIX # six */
1991 { 0x0037, 0x37 }, /* DIGIT SEVEN # seven */
1992 { 0x0038, 0x38 }, /* DIGIT EIGHT # eight */
1993 { 0x0039, 0x39 }, /* DIGIT NINE # nine */
1994 { 0x003A, 0x3A }, /* COLON # colon */
1995 { 0x003B, 0x3B }, /* SEMICOLON # semicolon */
1996 { 0x003C, 0x3C }, /* LESS-THAN SIGN # less */
1997 { 0x003D, 0x3D }, /* EQUALS SIGN # equal */
1998 { 0x003E, 0x3E }, /* GREATER-THAN SIGN # greater */
1999 { 0x003F, 0x3F }, /* QUESTION MARK # question */
2000 { 0x005B, 0x5B }, /* LEFT SQUARE BRACKET # bracketleft */
2001 { 0x005D, 0x5D }, /* RIGHT SQUARE BRACKET # bracketright */
2002 { 0x005F, 0x5F }, /* LOW LINE # underscore */
2003 { 0x007B, 0x7B }, /* LEFT CURLY BRACKET # braceleft */
2004 { 0x007C, 0x7C }, /* VERTICAL LINE # bar */
2005 { 0x007D, 0x7D }, /* RIGHT CURLY BRACKET # braceright */
2006 { 0x00A0, 0x20 }, /* NO-BREAK SPACE # space */
2007 { 0x00AC, 0xD8 }, /* NOT SIGN # logicalnot */
2008 { 0x00B0, 0xB0 }, /* DEGREE SIGN # degree */
2009 { 0x00B1, 0xB1 }, /* PLUS-MINUS SIGN # plusminus */
2010 { 0x00B5, 0x6D }, /* MICRO SIGN # mu */
2011 { 0x00D7, 0xB4 }, /* MULTIPLICATION SIGN # multiply */
2012 { 0x00F7, 0xB8 }, /* DIVISION SIGN # divide */
2013 { 0x0192, 0xA6 }, /* LATIN SMALL LETTER F WITH HOOK # florin */
2014 { 0x0391, 0x41 }, /* GREEK CAPITAL LETTER ALPHA # Alpha */
2015 { 0x0392, 0x42 }, /* GREEK CAPITAL LETTER BETA # Beta */
2016 { 0x0393, 0x47 }, /* GREEK CAPITAL LETTER GAMMA # Gamma */
2017 { 0x0394, 0x44 }, /* GREEK CAPITAL LETTER DELTA # Delta */
2018 { 0x0395, 0x45 }, /* GREEK CAPITAL LETTER EPSILON # Epsilon */
2019 { 0x0396, 0x5A }, /* GREEK CAPITAL LETTER ZETA # Zeta */
2020 { 0x0397, 0x48 }, /* GREEK CAPITAL LETTER ETA # Eta */
2021 { 0x0398, 0x51 }, /* GREEK CAPITAL LETTER THETA # Theta */
2022 { 0x0399, 0x49 }, /* GREEK CAPITAL LETTER IOTA # Iota */
2023 { 0x039A, 0x4B }, /* GREEK CAPITAL LETTER KAPPA # Kappa */
2024 { 0x039B, 0x4C }, /* GREEK CAPITAL LETTER LAMDA # Lambda */
2025 { 0x039C, 0x4D }, /* GREEK CAPITAL LETTER MU # Mu */
2026 { 0x039D, 0x4E }, /* GREEK CAPITAL LETTER NU # Nu */
2027 { 0x039E, 0x58 }, /* GREEK CAPITAL LETTER XI # Xi */
2028 { 0x039F, 0x4F }, /* GREEK CAPITAL LETTER OMICRON # Omicron */
2029 { 0x03A0, 0x50 }, /* GREEK CAPITAL LETTER PI # Pi */
2030 { 0x03A1, 0x52 }, /* GREEK CAPITAL LETTER RHO # Rho */
2031 { 0x03A3, 0x53 }, /* GREEK CAPITAL LETTER SIGMA # Sigma */
2032 { 0x03A4, 0x54 }, /* GREEK CAPITAL LETTER TAU # Tau */
2033 { 0x03A5, 0x55 }, /* GREEK CAPITAL LETTER UPSILON # Upsilon */
2034 { 0x03A6, 0x46 }, /* GREEK CAPITAL LETTER PHI # Phi */
2035 { 0x03A7, 0x43 }, /* GREEK CAPITAL LETTER CHI # Chi */
2036 { 0x03A8, 0x59 }, /* GREEK CAPITAL LETTER PSI # Psi */
2037 { 0x03A9, 0x57 }, /* GREEK CAPITAL LETTER OMEGA # Omega */
2038 { 0x03B1, 0x61 }, /* GREEK SMALL LETTER ALPHA # alpha */
2039 { 0x03B2, 0x62 }, /* GREEK SMALL LETTER BETA # beta */
2040 { 0x03B3, 0x67 }, /* GREEK SMALL LETTER GAMMA # gamma */
2041 { 0x03B4, 0x64 }, /* GREEK SMALL LETTER DELTA # delta */
2042 { 0x03B5, 0x65 }, /* GREEK SMALL LETTER EPSILON # epsilon */
2043 { 0x03B6, 0x7A }, /* GREEK SMALL LETTER ZETA # zeta */
2044 { 0x03B7, 0x68 }, /* GREEK SMALL LETTER ETA # eta */
2045 { 0x03B8, 0x71 }, /* GREEK SMALL LETTER THETA # theta */
2046 { 0x03B9, 0x69 }, /* GREEK SMALL LETTER IOTA # iota */
2047 { 0x03BA, 0x6B }, /* GREEK SMALL LETTER KAPPA # kappa */
2048 { 0x03BB, 0x6C }, /* GREEK SMALL LETTER LAMDA # lambda */
2049 { 0x03BC, 0x6D }, /* GREEK SMALL LETTER MU # mu */
2050 { 0x03BD, 0x6E }, /* GREEK SMALL LETTER NU # nu */
2051 { 0x03BE, 0x78 }, /* GREEK SMALL LETTER XI # xi */
2052 { 0x03BF, 0x6F }, /* GREEK SMALL LETTER OMICRON # omicron */
2053 { 0x03C0, 0x70 }, /* GREEK SMALL LETTER PI # pi */
2054 { 0x03C1, 0x72 }, /* GREEK SMALL LETTER RHO # rho */
2055 { 0x03C2, 0x56 }, /* GREEK SMALL LETTER FINAL SIGMA # sigma1 */
2056 { 0x03C3, 0x73 }, /* GREEK SMALL LETTER SIGMA # sigma */
2057 { 0x03C4, 0x74 }, /* GREEK SMALL LETTER TAU # tau */
2058 { 0x03C5, 0x75 }, /* GREEK SMALL LETTER UPSILON # upsilon */
2059 { 0x03C6, 0x66 }, /* GREEK SMALL LETTER PHI # phi */
2060 { 0x03C7, 0x63 }, /* GREEK SMALL LETTER CHI # chi */
2061 { 0x03C8, 0x79 }, /* GREEK SMALL LETTER PSI # psi */
2062 { 0x03C9, 0x77 }, /* GREEK SMALL LETTER OMEGA # omega */
2063 { 0x03D1, 0x4A }, /* GREEK THETA SYMBOL # theta1 */
2064 { 0x03D2, 0xA1 }, /* GREEK UPSILON WITH HOOK SYMBOL # Upsilon1 */
2065 { 0x03D5, 0x6A }, /* GREEK PHI SYMBOL # phi1 */
2066 { 0x03D6, 0x76 }, /* GREEK PI SYMBOL # omega1 */
2067 { 0x2022, 0xB7 }, /* BULLET # bullet */
2068 { 0x2026, 0xBC }, /* HORIZONTAL ELLIPSIS # ellipsis */
2069 { 0x2032, 0xA2 }, /* PRIME # minute */
2070 { 0x2033, 0xB2 }, /* DOUBLE PRIME # second */
2071 { 0x2044, 0xA4 }, /* FRACTION SLASH # fraction */
2072 { 0x20AC, 0xA0 }, /* EURO SIGN # Euro */
2073 { 0x2111, 0xC1 }, /* BLACK-LETTER CAPITAL I # Ifraktur */
2074 { 0x2118, 0xC3 }, /* SCRIPT CAPITAL P # weierstrass */
2075 { 0x211C, 0xC2 }, /* BLACK-LETTER CAPITAL R # Rfraktur */
2076 { 0x2126, 0x57 }, /* OHM SIGN # Omega */
2077 { 0x2135, 0xC0 }, /* ALEF SYMBOL # aleph */
2078 { 0x2190, 0xAC }, /* LEFTWARDS ARROW # arrowleft */
2079 { 0x2191, 0xAD }, /* UPWARDS ARROW # arrowup */
2080 { 0x2192, 0xAE }, /* RIGHTWARDS ARROW # arrowright */
2081 { 0x2193, 0xAF }, /* DOWNWARDS ARROW # arrowdown */
2082 { 0x2194, 0xAB }, /* LEFT RIGHT ARROW # arrowboth */
2083 { 0x21B5, 0xBF }, /* DOWNWARDS ARROW WITH CORNER LEFTWARDS # carriagereturn */
2084 { 0x21D0, 0xDC }, /* LEFTWARDS DOUBLE ARROW # arrowdblleft */
2085 { 0x21D1, 0xDD }, /* UPWARDS DOUBLE ARROW # arrowdblup */
2086 { 0x21D2, 0xDE }, /* RIGHTWARDS DOUBLE ARROW # arrowdblright */
2087 { 0x21D3, 0xDF }, /* DOWNWARDS DOUBLE ARROW # arrowdbldown */
2088 { 0x21D4, 0xDB }, /* LEFT RIGHT DOUBLE ARROW # arrowdblboth */
2089 { 0x2200, 0x22 }, /* FOR ALL # universal */
2090 { 0x2202, 0xB6 }, /* PARTIAL DIFFERENTIAL # partialdiff */
2091 { 0x2203, 0x24 }, /* THERE EXISTS # existential */
2092 { 0x2205, 0xC6 }, /* EMPTY SET # emptyset */
2093 { 0x2206, 0x44 }, /* INCREMENT # Delta */
2094 { 0x2207, 0xD1 }, /* NABLA # gradient */
2095 { 0x2208, 0xCE }, /* ELEMENT OF # element */
2096 { 0x2209, 0xCF }, /* NOT AN ELEMENT OF # notelement */
2097 { 0x220B, 0x27 }, /* CONTAINS AS MEMBER # suchthat */
2098 { 0x220F, 0xD5 }, /* N-ARY PRODUCT # product */
2099 { 0x2211, 0xE5 }, /* N-ARY SUMMATION # summation */
2100 { 0x2212, 0x2D }, /* MINUS SIGN # minus */
2101 { 0x2215, 0xA4 }, /* DIVISION SLASH # fraction */
2102 { 0x2217, 0x2A }, /* ASTERISK OPERATOR # asteriskmath */
2103 { 0x221A, 0xD6 }, /* SQUARE ROOT # radical */
2104 { 0x221D, 0xB5 }, /* PROPORTIONAL TO # proportional */
2105 { 0x221E, 0xA5 }, /* INFINITY # infinity */
2106 { 0x2220, 0xD0 }, /* ANGLE # angle */
2107 { 0x2227, 0xD9 }, /* LOGICAL AND # logicaland */
2108 { 0x2228, 0xDA }, /* LOGICAL OR # logicalor */
2109 { 0x2229, 0xC7 }, /* INTERSECTION # intersection */
2110 { 0x222A, 0xC8 }, /* UNION # union */
2111 { 0x222B, 0xF2 }, /* INTEGRAL # integral */
2112 { 0x2234, 0x5C }, /* THEREFORE # therefore */
2113 { 0x223C, 0x7E }, /* TILDE OPERATOR # similar */
2114 { 0x2245, 0x40 }, /* APPROXIMATELY EQUAL TO # congruent */
2115 { 0x2248, 0xBB }, /* ALMOST EQUAL TO # approxequal */
2116 { 0x2260, 0xB9 }, /* NOT EQUAL TO # notequal */
2117 { 0x2261, 0xBA }, /* IDENTICAL TO # equivalence */
2118 { 0x2264, 0xA3 }, /* LESS-THAN OR EQUAL TO # lessequal */
2119 { 0x2265, 0xB3 }, /* GREATER-THAN OR EQUAL TO # greaterequal */
2120 { 0x2282, 0xCC }, /* SUBSET OF # propersubset */
2121 { 0x2283, 0xC9 }, /* SUPERSET OF # propersuperset */
2122 { 0x2284, 0xCB }, /* NOT A SUBSET OF # notsubset */
2123 { 0x2286, 0xCD }, /* SUBSET OF OR EQUAL TO # reflexsubset */
2124 { 0x2287, 0xCA }, /* SUPERSET OF OR EQUAL TO # reflexsuperset */
2125 { 0x2295, 0xC5 }, /* CIRCLED PLUS # circleplus */
2126 { 0x2297, 0xC4 }, /* CIRCLED TIMES # circlemultiply */
2127 { 0x22A5, 0x5E }, /* UP TACK # perpendicular */
2128 { 0x22C5, 0xD7 }, /* DOT OPERATOR # dotmath */
2129 { 0x2320, 0xF3 }, /* TOP HALF INTEGRAL # integraltp */
2130 { 0x2321, 0xF5 }, /* BOTTOM HALF INTEGRAL # integralbt */
2131 { 0x2329, 0xE1 }, /* LEFT-POINTING ANGLE BRACKET # angleleft */
2132 { 0x232A, 0xF1 }, /* RIGHT-POINTING ANGLE BRACKET # angleright */
2133 { 0x25CA, 0xE0 }, /* LOZENGE # lozenge */
2134 { 0x2660, 0xAA }, /* BLACK SPADE SUIT # spade */
2135 { 0x2663, 0xA7 }, /* BLACK CLUB SUIT # club */
2136 { 0x2665, 0xA9 }, /* BLACK HEART SUIT # heart */
2137 { 0x2666, 0xA8 }, /* BLACK DIAMOND SUIT # diamond */
2138 { 0xF6D9, 0xD3 }, /* COPYRIGHT SIGN SERIF # copyrightserif (CUS) */
2139 { 0xF6DA, 0xD2 }, /* REGISTERED SIGN SERIF # registerserif (CUS) */
2140 { 0xF6DB, 0xD4 }, /* TRADE MARK SIGN SERIF # trademarkserif (CUS) */
2141 { 0xF8E5, 0x60 }, /* RADICAL EXTENDER # radicalex (CUS) */
2142 { 0xF8E6, 0xBD }, /* VERTICAL ARROW EXTENDER # arrowvertex (CUS) */
2143 { 0xF8E7, 0xBE }, /* HORIZONTAL ARROW EXTENDER # arrowhorizex (CUS) */
2144 { 0xF8E8, 0xE2 }, /* REGISTERED SIGN SANS SERIF # registersans (CUS) */
2145 { 0xF8E9, 0xE3 }, /* COPYRIGHT SIGN SANS SERIF # copyrightsans (CUS) */
2146 { 0xF8EA, 0xE4 }, /* TRADE MARK SIGN SANS SERIF # trademarksans (CUS) */
2147 { 0xF8EB, 0xE6 }, /* LEFT PAREN TOP # parenlefttp (CUS) */
2148 { 0xF8EC, 0xE7 }, /* LEFT PAREN EXTENDER # parenleftex (CUS) */
2149 { 0xF8ED, 0xE8 }, /* LEFT PAREN BOTTOM # parenleftbt (CUS) */
2150 { 0xF8EE, 0xE9 }, /* LEFT SQUARE BRACKET TOP # bracketlefttp (CUS) */
2151 { 0xF8EF, 0xEA }, /* LEFT SQUARE BRACKET EXTENDER # bracketleftex (CUS) */
2152 { 0xF8F0, 0xEB }, /* LEFT SQUARE BRACKET BOTTOM # bracketleftbt (CUS) */
2153 { 0xF8F1, 0xEC }, /* LEFT CURLY BRACKET TOP # bracelefttp (CUS) */
2154 { 0xF8F2, 0xED }, /* LEFT CURLY BRACKET MID # braceleftmid (CUS) */
2155 { 0xF8F3, 0xEE }, /* LEFT CURLY BRACKET BOTTOM # braceleftbt (CUS) */
2156 { 0xF8F4, 0xEF }, /* CURLY BRACKET EXTENDER # braceex (CUS) */
2157 { 0xF8F5, 0xF4 }, /* INTEGRAL EXTENDER # integralex (CUS) */
2158 { 0xF8F6, 0xF6 }, /* RIGHT PAREN TOP # parenrighttp (CUS) */
2159 { 0xF8F7, 0xF7 }, /* RIGHT PAREN EXTENDER # parenrightex (CUS) */
2160 { 0xF8F8, 0xF8 }, /* RIGHT PAREN BOTTOM # parenrightbt (CUS) */
2161 { 0xF8F9, 0xF9 }, /* RIGHT SQUARE BRACKET TOP # bracketrighttp (CUS) */
2162 { 0xF8FA, 0xFA }, /* RIGHT SQUARE BRACKET EXTENDER # bracketrightex (CUS) */
2163 { 0xF8FB, 0xFB }, /* RIGHT SQUARE BRACKET BOTTOM # bracketrightbt (CUS) */
2164 { 0xF8FC, 0xFC }, /* RIGHT CURLY BRACKET TOP # bracerighttp (CUS) */
2165 { 0xF8FD, 0xFD }, /* RIGHT CURLY BRACKET MID # bracerightmid (CUS) */
2166 { 0xF8FE, 0xFE }, /* RIGHT CURLY BRACKET BOTTOM # bracerightbt (CUS) */
2167};
2168
2169static const FcCharMap AdobeSymbol = {
2170 AdobeSymbolEnt,
2171 sizeof (AdobeSymbolEnt) / sizeof (AdobeSymbolEnt[0]),
2172};
2173
2174static const FcFontDecode fcFontDecoders[] = {
2175 { ft_encoding_unicode, 0, (1 << 21) - 1 },
2176 { ft_encoding_symbol, &AdobeSymbol, (1 << 16) - 1 },
2177 { ft_encoding_apple_roman, &AppleRoman, (1 << 16) - 1 },
2178};
2179
67accef4 2180#define NUM_DECODE (int) (sizeof (fcFontDecoders) / sizeof (fcFontDecoders[0]))
c647f6f1 2181
716ac8b8
KP
2182static const FcChar32 prefer_unicode[] = {
2183 0x20ac, /* EURO SIGN */
2184};
2185
67accef4 2186#define NUM_PREFER_UNICODE (int) (sizeof (prefer_unicode) / sizeof (prefer_unicode[0]))
716ac8b8 2187
c647f6f1
KP
2188FcChar32
2189FcFreeTypeUcs4ToPrivate (FcChar32 ucs4, const FcCharMap *map)
2190{
2191 int low, high, mid;
2192 FcChar16 bmp;
2193
2194 low = 0;
2195 high = map->nent - 1;
2196 if (ucs4 < map->ent[low].bmp || map->ent[high].bmp < ucs4)
2197 return ~0;
2198 while (low <= high)
2199 {
2200 mid = (high + low) >> 1;
2201 bmp = map->ent[mid].bmp;
2202 if (ucs4 == bmp)
2203 return (FT_ULong) map->ent[mid].encode;
2204 if (ucs4 < bmp)
2205 high = mid - 1;
2206 else
2207 low = mid + 1;
2208 }
2209 return ~0;
2210}
2211
2212FcChar32
2213FcFreeTypePrivateToUcs4 (FcChar32 private, const FcCharMap *map)
2214{
2215 int i;
2216
2217 for (i = 0; i < map->nent; i++)
2218 if (map->ent[i].encode == private)
2219 return (FcChar32) map->ent[i].bmp;
2220 return ~0;
2221}
2222
2223const FcCharMap *
2224FcFreeTypeGetPrivateMap (FT_Encoding encoding)
2225{
2226 int i;
2227
2228 for (i = 0; i < NUM_DECODE; i++)
2229 if (fcFontDecoders[i].encoding == encoding)
2230 return fcFontDecoders[i].map;
2231 return 0;
2232}
2233
7769c321
KP
2234#include "../fc-glyphname/fcglyphname.h"
2235
2236static FcChar32
2237FcHashGlyphName (const FcChar8 *name)
2238{
2239 FcChar32 h = 0;
2240 FcChar8 c;
2241
2242 while ((c = *name++))
2243 {
2244 h = ((h << 1) | (h >> 31)) ^ c;
2245 }
2246 return h;
2247}
2248
656c69d6 2249#if HAVE_FT_HAS_PS_GLYPH_NAMES
7769c321
KP
2250/*
2251 * Use Type1 glyph names for fonts which have reliable names
2252 * and which export an Adobe Custom mapping
2253 */
2254static FcBool
2255FcFreeTypeUseNames (FT_Face face)
2256{
2257 FT_Int map;
2258
2259 if (!FT_Has_PS_Glyph_Names (face))
2260 return FcFalse;
2261 for (map = 0; map < face->num_charmaps; map++)
d47c9d6e 2262 if (face->charmaps[map]->encoding == ft_encoding_adobe_custom)
7769c321
KP
2263 return FcTrue;
2264 return FcFalse;
2265}
2266
573da729 2267static const FcChar8 *
7769c321
KP
2268FcUcs4ToGlyphName (FcChar32 ucs4)
2269{
2270 int i = (int) (ucs4 % FC_GLYPHNAME_HASH);
2271 int r = 0;
573da729 2272 const FcGlyphName *gn;
7769c321
KP
2273
2274 while ((gn = ucs_to_name[i]))
2275 {
2276 if (gn->ucs == ucs4)
2277 return gn->name;
2278 if (!r)
2279 {
2280 r = (int) (ucs4 % FC_GLYPHNAME_REHASH);
2281 if (!r)
2282 r = 1;
2283 }
2284 i += r;
2285 if (i >= FC_GLYPHNAME_HASH)
2286 i -= FC_GLYPHNAME_HASH;
2287 }
2288 return 0;
2289}
2290
2291static FcChar32
2292FcGlyphNameToUcs4 (FcChar8 *name)
2293{
2294 FcChar32 h = FcHashGlyphName (name);
2295 int i = (int) (h % FC_GLYPHNAME_HASH);
2296 int r = 0;
573da729 2297 const FcGlyphName *gn;
7769c321
KP
2298
2299 while ((gn = name_to_ucs[i]))
2300 {
2301 if (!strcmp ((char *) name, (char *) gn->name))
2302 return gn->ucs;
2303 if (!r)
2304 {
2305 r = (int) (h % FC_GLYPHNAME_REHASH);
2306 if (!r)
2307 r = 1;
2308 }
2309 i += r;
2310 if (i >= FC_GLYPHNAME_HASH)
2311 i -= FC_GLYPHNAME_HASH;
2312 }
2313 return 0xffff;
2314}
2315
2316/*
2317 * Search through a font for a glyph by name. This is
2318 * currently a linear search as there doesn't appear to be
2319 * any defined order within the font
2320 */
2321static FT_UInt
573da729 2322FcFreeTypeGlyphNameIndex (FT_Face face, const FcChar8 *name)
7769c321
KP
2323{
2324 FT_UInt gindex;
2325 FcChar8 name_buf[FC_GLYPHNAME_MAXLEN + 2];
2326
67accef4 2327 for (gindex = 0; gindex < (FT_UInt) face->num_glyphs; gindex++)
7769c321
KP
2328 {
2329 if (FT_Get_Glyph_Name (face, gindex, name_buf, FC_GLYPHNAME_MAXLEN+1) == 0)
2330 if (!strcmp ((char *) name, (char *) name_buf))
2331 return gindex;
2332 }
2333 return 0;
2334}
656c69d6 2335#endif
7769c321 2336
c647f6f1
KP
2337/*
2338 * Map a UCS4 glyph to a glyph index. Use all available encoding
2339 * tables to try and find one that works. This information is expected
2340 * to be cached by higher levels, so performance isn't critical
2341 */
2342
2343FT_UInt
2344FcFreeTypeCharIndex (FT_Face face, FcChar32 ucs4)
2345{
2346 int initial, offset, decode;
2347 FT_UInt glyphindex;
2348 FcChar32 charcode;
716ac8b8 2349 int p;
c647f6f1
KP
2350
2351 initial = 0;
656b47f6
PL
2352
2353 if (!face)
2354 return 0;
2355
c647f6f1
KP
2356 /*
2357 * Find the current encoding
2358 */
2359 if (face->charmap)
2360 {
2361 for (; initial < NUM_DECODE; initial++)
2362 if (fcFontDecoders[initial].encoding == face->charmap->encoding)
2363 break;
2364 if (initial == NUM_DECODE)
2365 initial = 0;
2366 }
716ac8b8
KP
2367 for (p = 0; p < NUM_PREFER_UNICODE; p++)
2368 if (ucs4 == prefer_unicode[p])
2369 {
2370 initial = 0;
2371 break;
2372 }
c647f6f1
KP
2373 /*
2374 * Check each encoding for the glyph, starting with the current one
2375 */
2376 for (offset = 0; offset < NUM_DECODE; offset++)
2377 {
2378 decode = (initial + offset) % NUM_DECODE;
2379 if (!face->charmap || face->charmap->encoding != fcFontDecoders[decode].encoding)
2380 if (FT_Select_Charmap (face, fcFontDecoders[decode].encoding) != 0)
2381 continue;
2382 if (fcFontDecoders[decode].map)
2383 {
2384 charcode = FcFreeTypeUcs4ToPrivate (ucs4, fcFontDecoders[decode].map);
67accef4 2385 if (charcode == ~0U)
c647f6f1
KP
2386 continue;
2387 }
2388 else
2389 charcode = ucs4;
2390 glyphindex = FT_Get_Char_Index (face, (FT_ULong) charcode);
2391 if (glyphindex)
2392 return glyphindex;
2393 }
656c69d6 2394#if HAVE_FT_HAS_PS_GLYPH_NAMES
7769c321
KP
2395 /*
2396 * Check postscript name table if present
2397 */
2398 if (FcFreeTypeUseNames (face))
2399 {
573da729 2400 const FcChar8 *name = FcUcs4ToGlyphName (ucs4);
7769c321
KP
2401 if (name)
2402 {
2403 glyphindex = FcFreeTypeGlyphNameIndex (face, name);
2404 if (glyphindex)
2405 return glyphindex;
2406 }
2407 }
656c69d6 2408#endif
c647f6f1
KP
2409 return 0;
2410}
2411
2412static FcBool
2413FcFreeTypeCheckGlyph (FT_Face face, FcChar32 ucs4,
848d32bd
KP
2414 FT_UInt glyph, FcBlanks *blanks,
2415 FT_Pos *advance)
c647f6f1 2416{
0b7a0da2 2417 FT_Int load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH | FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
c647f6f1
KP
2418 FT_GlyphSlot slot;
2419
2420 /*
2421 * When using scalable fonts, only report those glyphs
2422 * which can be scaled; otherwise those fonts will
2423 * only be available at some sizes, and never when
2424 * transformed. Avoid this by simply reporting bitmap-only
2425 * glyphs as missing
2426 */
2427 if (face->face_flags & FT_FACE_FLAG_SCALABLE)
2428 load_flags |= FT_LOAD_NO_BITMAP;
2429
2430 if (FT_Load_Glyph (face, glyph, load_flags))
2431 return FcFalse;
2432
2433 slot = face->glyph;
2434 if (!glyph)
2435 return FcFalse;
2436
848d32bd
KP
2437 *advance = slot->metrics.horiAdvance;
2438
c647f6f1
KP
2439 switch (slot->format) {
2440 case ft_glyph_format_bitmap:
2441 /*
2442 * Bitmaps are assumed to be reasonable; if
2443 * this proves to be a rash assumption, this
2444 * code can be easily modified
2445 */
2446 return FcTrue;
2447 case ft_glyph_format_outline:
2448 /*
2449 * Glyphs with contours are always OK
2450 */
2451 if (slot->outline.n_contours != 0)
2452 return FcTrue;
2453 /*
2454 * Glyphs with no contours are only OK if
2455 * they're members of the Blanks set specified
2456 * in the configuration. If blanks isn't set,
2457 * then allow any glyph to be blank
2458 */
2459 if (!blanks || FcBlanksIsMember (blanks, ucs4))
2460 return FcTrue;
2461 /* fall through ... */
2462 default:
2463 break;
2464 }
2465 return FcFalse;
2466}
2467
55a69bd0
KP
2468#define FC_MIN(a,b) ((a) < (b) ? (a) : (b))
2469#define FC_MAX(a,b) ((a) > (b) ? (a) : (b))
2470#define FC_ABS(a) ((a) < 0 ? -(a) : (a))
2471#define APPROXIMATELY_EQUAL(x,y) (FC_ABS ((x) - (y)) <= FC_MAX (FC_ABS (x), FC_ABS (y)) / 33)
a05d257f 2472
c647f6f1 2473FcCharSet *
848d32bd 2474FcFreeTypeCharSetAndSpacing (FT_Face face, FcBlanks *blanks, int *spacing)
c647f6f1 2475{
b023dbd3 2476 FcChar32 page, off, ucs4;
c647f6f1
KP
2477#ifdef CHECK
2478 FcChar32 font_max = 0;
2479#endif
2480 FcCharSet *fcs;
2481 FcCharLeaf *leaf;
2482 const FcCharMap *map;
2483 int o;
2484 int i;
2485 FT_UInt glyph;
a05d257f
NL
2486 FT_Pos advance, advance_one = 0, advance_two = 0;
2487 FcBool has_advance = FcFalse, fixed_advance = FcTrue, dual_advance = FcFalse;
c647f6f1
KP
2488
2489 fcs = FcCharSetCreate ();
2490 if (!fcs)
2491 goto bail0;
2492
7769c321
KP
2493#ifdef CHECK
2494 printf ("Family %s style %s\n", face->family_name, face->style_name);
2495#endif
c647f6f1
KP
2496 for (o = 0; o < NUM_DECODE; o++)
2497 {
2498 if (FT_Select_Charmap (face, fcFontDecoders[o].encoding) != 0)
2499 continue;
2500 map = fcFontDecoders[o].map;
2501 if (map)
2502 {
2503 /*
2504 * Non-Unicode tables are easy; there's a list of all possible
2505 * characters
2506 */
2507 for (i = 0; i < map->nent; i++)
2508 {
2509 ucs4 = map->ent[i].bmp;
2510 glyph = FT_Get_Char_Index (face, map->ent[i].encode);
848d32bd
KP
2511 if (glyph &&
2512 FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance))
c647f6f1 2513 {
8245771d
PL
2514 /*
2515 * ignore glyphs with zero advance. They’re
2516 * combining characters, and while their behaviour
2517 * isn’t well defined for monospaced applications in
2518 * Unicode, there are many fonts which include
2519 * zero-width combining characters in otherwise
2520 * monospaced fonts.
2521 */
2522 if (advance)
848d32bd 2523 {
8245771d
PL
2524 if (!has_advance)
2525 {
2526 has_advance = FcTrue;
2527 advance_one = advance;
2528 }
2529 else if (!APPROXIMATELY_EQUAL (advance, advance_one))
2530 {
2531 if (fixed_advance)
2532 {
2533 dual_advance = FcTrue;
2534 fixed_advance = FcFalse;
2535 advance_two = advance;
2536 }
2537 else if (!APPROXIMATELY_EQUAL (advance, advance_two))
2538 dual_advance = FcFalse;
2539 }
848d32bd 2540 }
a05d257f 2541
c647f6f1
KP
2542 leaf = FcCharSetFindLeafCreate (fcs, ucs4);
2543 if (!leaf)
2544 goto bail1;
2545 leaf->map[(ucs4 & 0xff) >> 5] |= (1 << (ucs4 & 0x1f));
2546#ifdef CHECK
2547 if (ucs4 > font_max)
2548 font_max = ucs4;
2549#endif
2550 }
2551 }
2552 }
2553 else
2554 {
2555 FT_UInt gindex;
2556
c647f6f1
KP
2557 /*
2558 * Find the first encoded character in the font
2559 */
2560 if (FT_Get_Char_Index (face, 0))
2561 {
2562 ucs4 = 0;
2563 gindex = 1;
2564 }
2565 else
2566 {
2567 ucs4 = FT_Get_Next_Char (face, 0, &gindex);
2568 if (!ucs4)
2569 gindex = 0;
2570 }
2571
2572 while (gindex)
2573 {
2574 page = ucs4 >> 8;
2575 leaf = 0;
2576 while ((ucs4 >> 8) == page)
2577 {
2578 glyph = FT_Get_Char_Index (face, ucs4);
2579 if (glyph && FcFreeTypeCheckGlyph (face, ucs4,
848d32bd 2580 glyph, blanks, &advance))
c647f6f1 2581 {
8245771d 2582 if (advance)
848d32bd 2583 {
8245771d
PL
2584 if (!has_advance)
2585 {
2586 has_advance = FcTrue;
2587 advance_one = advance;
2588 }
2589 else if (!APPROXIMATELY_EQUAL (advance, advance_one))
2590 {
2591 if (fixed_advance)
2592 {
2593 dual_advance = FcTrue;
2594 fixed_advance = FcFalse;
2595 advance_two = advance;
2596 }
2597 else if (!APPROXIMATELY_EQUAL (advance, advance_two))
2598 dual_advance = FcFalse;
2599 }
848d32bd 2600 }
a05d257f 2601
c647f6f1
KP
2602 if (!leaf)
2603 {
2604 leaf = FcCharSetFindLeafCreate (fcs, ucs4);
2605 if (!leaf)
2606 goto bail1;
2607 }
2608 off = ucs4 & 0xff;
2609 leaf->map[off >> 5] |= (1 << (off & 0x1f));
2610#ifdef CHECK
2611 if (ucs4 > font_max)
2612 font_max = ucs4;
2613#endif
2614 }
2615 ucs4++;
2616 }
2617 ucs4 = FT_Get_Next_Char (face, ucs4 - 1, &gindex);
2618 if (!ucs4)
2619 gindex = 0;
2620 }
2621#ifdef CHECK
2622 for (ucs4 = 0; ucs4 < 0x10000; ucs4++)
2623 {
2624 FcBool FT_Has, FC_Has;
2625
2626 FT_Has = FT_Get_Char_Index (face, ucs4) != 0;
2627 FC_Has = FcCharSetHasChar (fcs, ucs4);
2628 if (FT_Has != FC_Has)
2629 {
2630 printf ("0x%08x FT says %d FC says %d\n", ucs4, FT_Has, FC_Has);
2631 }
2632 }
2633#endif
2634 }
2635 }
656c69d6 2636#if HAVE_FT_HAS_PS_GLYPH_NAMES
7769c321
KP
2637 /*
2638 * Add mapping from PS glyph names if available
2639 */
2640 if (FcFreeTypeUseNames (face))
2641 {
2642 FcChar8 name_buf[FC_GLYPHNAME_MAXLEN + 2];
2643
67accef4 2644 for (glyph = 0; glyph < (FT_UInt) face->num_glyphs; glyph++)
7769c321
KP
2645 {
2646 if (FT_Get_Glyph_Name (face, glyph, name_buf, FC_GLYPHNAME_MAXLEN+1) == 0)
2647 {
2648 ucs4 = FcGlyphNameToUcs4 (name_buf);
2649 if (ucs4 != 0xffff &&
2650 FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance))
2651 {
8245771d 2652 if (advance)
7769c321 2653 {
8245771d
PL
2654 if (!has_advance)
2655 {
2656 has_advance = FcTrue;
2657 advance_one = advance;
2658 }
2659 else if (!APPROXIMATELY_EQUAL (advance, advance_one))
2660 {
2661 if (fixed_advance)
2662 {
2663 dual_advance = FcTrue;
2664 fixed_advance = FcFalse;
2665 advance_two = advance;
2666 }
2667 else if (!APPROXIMATELY_EQUAL (advance, advance_two))
2668 dual_advance = FcFalse;
2669 }
7769c321 2670 }
7769c321
KP
2671 leaf = FcCharSetFindLeafCreate (fcs, ucs4);
2672 if (!leaf)
2673 goto bail1;
2674 leaf->map[(ucs4 & 0xff) >> 5] |= (1 << (ucs4 & 0x1f));
2675#ifdef CHECK
2676 if (ucs4 > font_max)
2677 font_max = ucs4;
2678#endif
2679 }
2680 }
2681 }
2682 }
656c69d6 2683#endif
c647f6f1
KP
2684#ifdef CHECK
2685 printf ("%d glyphs %d encoded\n", (int) face->num_glyphs, FcCharSetCount (fcs));
2686 for (ucs4 = 0; ucs4 <= font_max; ucs4++)
2687 {
7769c321 2688 FcBool has_char = (glyph = FcFreeTypeCharIndex (face, ucs4)) != 0;
c647f6f1
KP
2689 FcBool has_bit = FcCharSetHasChar (fcs, ucs4);
2690
2691 if (has_char && !has_bit)
7769c321
KP
2692 {
2693 if (!FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance))
2694 printf ("Bitmap missing broken char 0x%x\n", ucs4);
2695 else
2696 printf ("Bitmap missing char 0x%x\n", ucs4);
2697 }
c647f6f1
KP
2698 else if (!has_char && has_bit)
2699 printf ("Bitmap extra char 0x%x\n", ucs4);
2700 }
2701#endif
848d32bd
KP
2702 if (fixed_advance)
2703 *spacing = FC_MONO;
55a69bd0 2704 else if (dual_advance && APPROXIMATELY_EQUAL (2 * FC_MIN (advance_one, advance_two), FC_MAX (advance_one, advance_two)))
a05d257f 2705 *spacing = FC_DUAL;
848d32bd
KP
2706 else
2707 *spacing = FC_PROPORTIONAL;
c647f6f1
KP
2708 return fcs;
2709bail1:
2710 FcCharSetDestroy (fcs);
2711bail0:
2712 return 0;
2713}
2714
848d32bd
KP
2715FcCharSet *
2716FcFreeTypeCharSet (FT_Face face, FcBlanks *blanks)
2717{
2718 int spacing;
2719
2720 return FcFreeTypeCharSetAndSpacing (face, blanks, &spacing);
2721}
dbf68dd5
KP
2722
2723
2724#define TTAG_GPOS FT_MAKE_TAG( 'G', 'P', 'O', 'S' )
2725#define TTAG_GSUB FT_MAKE_TAG( 'G', 'S', 'U', 'B' )
2726#define TTAG_SILF FT_MAKE_TAG( 'S', 'i', 'l', 'f')
2727#define TT_Err_Ok FT_Err_Ok
2728#define TT_Err_Invalid_Face_Handle FT_Err_Invalid_Face_Handle
2729#define TTO_Err_Empty_Script 0x1005
2730#define TTO_Err_Invalid_SubTable 0x1001
2731
219f7818
KP
2732#define OTLAYOUT_HEAD "otlayout:"
2733#define OTLAYOUT_HEAD_LEN 9
2734#define OTLAYOUT_ID_LEN 4
2735/* space + head + id */
2736#define OTLAYOUT_LEN (1 + OTLAYOUT_HEAD_LEN + OTLAYOUT_ID_LEN)
2737
76a8dfa3
KP
2738/*
2739 * This is a bit generous; the registry has only lower case and space
2740 * except for 'DFLT'.
2741 */
2742#define FcIsSpace(x) (040 == (x))
2743#define FcIsValidScript(x) (FcIsLower(x) || FcIsUpper (x) || FcIsSpace(x))
2744
dbf68dd5
KP
2745static void
2746addtag(FcChar8 *complex, FT_ULong tag)
2747{
219f7818
KP
2748 FcChar8 tagstring[OTLAYOUT_ID_LEN + 1];
2749
2750 tagstring[0] = (FcChar8)(tag >> 24),
2751 tagstring[1] = (FcChar8)(tag >> 16),
2752 tagstring[2] = (FcChar8)(tag >> 8),
2753 tagstring[3] = (FcChar8)(tag);
2754 tagstring[4] = '\0';
2755
76a8dfa3 2756 /* skip tags which aren't alphabetic, under the assumption that
219f7818
KP
2757 * they're probably broken
2758 */
76a8dfa3
KP
2759 if (!FcIsValidScript(tagstring[0]) ||
2760 !FcIsValidScript(tagstring[1]) ||
2761 !FcIsValidScript(tagstring[2]) ||
2762 !FcIsValidScript(tagstring[3]))
219f7818
KP
2763 return;
2764
2765 if (*complex != '\0')
8245771d
PL
2766 strcat ((char *) complex, " ");
2767 strcat ((char *) complex, "otlayout:");
2768 strcat ((char *) complex, (char *) tagstring);
dbf68dd5
KP
2769}
2770
2771static int
2772compareulong (const void *a, const void *b)
2773{
2774 const FT_ULong *ua = (const FT_ULong *) a;
2775 const FT_ULong *ub = (const FT_ULong *) b;
2776 return *ua - *ub;
2777}
2778
2779
2780static FT_Error
2781GetScriptTags(FT_Face face, FT_ULong tabletag, FT_ULong **stags, FT_UShort *script_count)
2782{
2783 FT_ULong cur_offset, new_offset, base_offset;
dbf68dd5
KP
2784 FT_Stream stream = face->stream;
2785 FT_Error error;
2786 FT_UShort n, p;
04f7d3e7 2787 FT_Memory memory;
dbf68dd5
KP
2788
2789 if ( !stream )
2790 return TT_Err_Invalid_Face_Handle;
2791
04f7d3e7
PL
2792 memory = stream->memory;
2793
8ebf7725 2794 if (( error = ftglue_face_goto_table( face, tabletag, stream ) ))
dbf68dd5
KP
2795 return error;
2796
8ebf7725 2797 base_offset = ftglue_stream_pos ( stream );
dbf68dd5
KP
2798
2799 /* skip version */
2800
8ebf7725 2801 if ( ftglue_stream_seek ( stream, base_offset + 4L ) || ftglue_stream_frame_enter( stream, 2L ) )
dbf68dd5
KP
2802 return error;
2803
d8951c0c 2804 new_offset = GET_UShort() + base_offset;
dbf68dd5 2805
8ebf7725 2806 ftglue_stream_frame_exit( stream );
dbf68dd5 2807
8ebf7725 2808 cur_offset = ftglue_stream_pos( stream );
dbf68dd5 2809
8ebf7725 2810 if ( ftglue_stream_seek( stream, new_offset ) != TT_Err_Ok )
dbf68dd5
KP
2811 return error;
2812
8ebf7725 2813 base_offset = ftglue_stream_pos( stream );
dbf68dd5 2814
8ebf7725 2815 if ( ftglue_stream_frame_enter( stream, 2L ) )
dbf68dd5
KP
2816 return error;
2817
d8951c0c 2818 *script_count = GET_UShort ();
8ebf7725
PL
2819
2820 ftglue_stream_frame_exit( stream );
dbf68dd5 2821
8ebf7725 2822 *stags = ftglue_alloc(memory, *script_count * sizeof( FT_ULong ), &error);
dbf68dd5 2823
8ebf7725 2824 if (error)
dbf68dd5
KP
2825 return error;
2826
2827 p = 0;
2828 for ( n = 0; n < *script_count; n++ )
2829 {
8ebf7725 2830 if ( ftglue_stream_frame_enter( stream, 6L ) )
dbf68dd5
KP
2831 goto Fail;
2832
d8951c0c
PL
2833 (*stags)[p] = GET_ULong ();
2834 new_offset = GET_UShort () + base_offset;
dbf68dd5 2835
8ebf7725 2836 ftglue_stream_frame_exit( stream );
dbf68dd5 2837
8ebf7725 2838 cur_offset = ftglue_stream_pos( stream );
dbf68dd5 2839
2f02e383 2840 error = ftglue_stream_seek( stream, new_offset );
dbf68dd5
KP
2841
2842 if ( error == TT_Err_Ok )
2843 p++;
dbf68dd5 2844
8ebf7725 2845 (void)ftglue_stream_seek( stream, cur_offset );
dbf68dd5
KP
2846 }
2847
2848 if (!p)
2849 {
2850 error = TTO_Err_Invalid_SubTable;
2851 goto Fail;
2852 }
2853
bb6b1993 2854 /* sort the tag list before returning it */
dbf68dd5
KP
2855 qsort(*stags, *script_count, sizeof(FT_ULong), compareulong);
2856
2857 return TT_Err_Ok;
2858
2859Fail:
219f7818 2860 *script_count = 0;
8ebf7725 2861 ftglue_free( memory, *stags );
0cfaf27e 2862 *stags = NULL;
dbf68dd5
KP
2863 return error;
2864}
2865
2866static FcChar8 *
2867FcFontCapabilities(FT_Face face)
2868{
2869 FcBool issilgraphitefont = 0;
2870 FT_Error err;
2871 FT_ULong len = 0;
2872 FT_ULong *gsubtags=NULL, *gpostags=NULL;
219f7818
KP
2873 FT_UShort gsub_count=0, gpos_count=0;
2874 FT_ULong maxsize;
dbf68dd5
KP
2875 FT_Memory memory = face->stream->memory;
2876 FcChar8 *complex = NULL;
2877 int indx1 = 0, indx2 = 0;
2878
2879 err = FT_Load_Sfnt_Table(face, TTAG_SILF, 0, 0, &len);
2880 issilgraphitefont = ( err == FT_Err_Ok);
2881
219f7818
KP
2882 if (GetScriptTags(face, TTAG_GPOS, &gpostags, &gpos_count) != FT_Err_Ok)
2883 gpos_count = 0;
2884 if (GetScriptTags(face, TTAG_GSUB, &gsubtags, &gsub_count) != FT_Err_Ok)
2885 gsub_count = 0;
2886
dbf68dd5 2887 if (!issilgraphitefont && !gsub_count && !gpos_count)
dbf68dd5 2888 goto bail;
dbf68dd5 2889
219f7818
KP
2890 maxsize = (((FT_ULong) gpos_count + (FT_ULong) gsub_count) * OTLAYOUT_LEN +
2891 (issilgraphitefont ? 13 : 0));
dbf68dd5 2892 complex = malloc (sizeof (FcChar8) * maxsize);
219f7818
KP
2893 if (!complex)
2894 goto bail;
2895
2896 complex[0] = '\0';
dbf68dd5 2897 if (issilgraphitefont)
8245771d 2898 strcpy((char *) complex, "ttable:Silf ");
dbf68dd5
KP
2899
2900 while ((indx1 < gsub_count) || (indx2 < gpos_count)) {
2901 if (indx1 == gsub_count) {
2902 addtag(complex, gpostags[indx2]);
2903 indx2++;
2904 } else if ((indx2 == gpos_count) || (gsubtags[indx1] < gpostags[indx2])) {
2905 addtag(complex, gsubtags[indx1]);
2906 indx1++;
2907 } else if (gsubtags[indx1] == gpostags[indx2]) {
2908 addtag(complex, gsubtags[indx1]);
2909 indx1++;
2910 indx2++;
2911 } else {
2912 addtag(complex, gpostags[indx2]);
2913 indx2++;
2914 }
2915 }
2916 if (FcDebug () & FC_DBG_SCANV)
2917 printf("complex features in this font: %s\n", complex);
2918bail:
8ebf7725
PL
2919 ftglue_free(memory, gsubtags);
2920 ftglue_free(memory, gpostags);
dbf68dd5
KP
2921 return complex;
2922}