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