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