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