]> git.wh0rd.org - fontconfig.git/blame - src/fcfreetype.c
Store FcNoticeFoundries in read-only memory.
[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 {
1bd0b5ba
KP
83 char bit;
84 const FcChar8 lang[6];
24330d27 85} FcCodePageRange[] = {
1bd0b5ba
KP
86 { 17, "ja" },
87 { 18, "zh-cn" },
88 { 19, "ko" },
89 { 20, "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
481f6c23
TS
804static const char notice_foundry_data[] =
805 "Bigelow\0b&h\0"
806 "Adobe\0adobe\0"
807 "Bitstream\0bitstream\0"
808 "Monotype\0monotype\0"
809 "Linotype\0linotype\0"
810 "LINOTYPE-HELL\0linotype\0"
811 "IBM\0ibm\0"
812 "URW\0urw\0"
813 "International Typeface Corporation\0itc\0"
814 "Tiro Typeworks\0tiro\0"
815 "XFree86\0xfree86\0"
816 "Microsoft\0microsoft\0"
817 "Omega\0omega\0"
818 "Font21\0hwan\0"
819 "HanYang System\0hanyang";
820
821struct _notice_foundry {
822 /* these are the offsets into the
823 * notice_foundry_data array.
824 */
825 unsigned char notice_offset;
826 unsigned char foundry_offset;
827};
828
829static const struct _notice_foundry FcNoticeFoundries[] = {
830 { 0, 8 },
831 { 12, 18 },
832 { 24, 34 },
833 { 44, 53 },
834 { 62, 71 },
835 { 80, 94 },
836 { 103, 107 },
837 { 111, 115 },
838 { 119, 154 },
839 { 158, 173 },
840 { 178, 186 },
841 { 194, 204 },
842 { 214, 220 },
843 { 226, 233 },
844 { 238, 253 }
2e2121f9
KP
845};
846
67accef4 847#define NUM_NOTICE_FOUNDRIES (int) (sizeof (FcNoticeFoundries) / sizeof (FcNoticeFoundries[0]))
2e2121f9
KP
848
849static const FcChar8 *
6ae6acf3 850FcNoticeFoundry(const FT_String *notice)
2ae95e77
JC
851{
852 int i;
2e2121f9
KP
853
854 if (notice)
855 for(i = 0; i < NUM_NOTICE_FOUNDRIES; i++)
481f6c23
TS
856 {
857 const struct _notice_foundry *nf = &FcNoticeFoundries[i];
858 const char *n = notice_foundry_data + nf->notice_offset;
859 const char *f = notice_foundry_data + nf->foundry_offset;
860
861 printf ("foundry \"%s\" -> \"%s\"\n", n, f);
862 if (strstr ((const char *) notice, n))
863 return (const FcChar8 *) f;
864 }
2e2121f9 865 return 0;
2ae95e77
JC
866}
867
2e2121f9 868static FcBool
6ae6acf3 869FcVendorMatch(const FT_Char vendor[4], const FT_Char *vendor_string)
2ae95e77
JC
870{
871 /* vendor is not necessarily NUL-terminated. */
872 int i, len;
2e2121f9 873
8245771d 874 len = strlen((char *) vendor_string);
2e2121f9
KP
875 if (memcmp(vendor, vendor_string, len) != 0)
876 return FcFalse;
877 for (i = len; i < 4; i++)
878 if (vendor[i] != ' ' && vendor[i] != '\0')
879 return FcFalse;
880 return FcTrue;
2ae95e77
JC
881}
882
2e2121f9
KP
883/* This table is partly taken from ttmkfdir by Joerg Pommnitz. */
884
885/* It should not contain useless entries (such as UNKN) nor duplicate
886 entries for padding both with spaces and NULs. */
887
888static const struct {
6ae6acf3 889 const FT_Char *vendor;
2e2121f9
KP
890 const FcChar8 *foundry;
891} FcVendorFoundries[] = {
6ae6acf3
KP
892 { (const FT_Char *) "ADBE", (const FcChar8 *) "adobe"},
893 { (const FT_Char *) "AGFA", (const FcChar8 *) "agfa"},
894 { (const FT_Char *) "ALTS", (const FcChar8 *) "altsys"},
895 { (const FT_Char *) "APPL", (const FcChar8 *) "apple"},
896 { (const FT_Char *) "ARPH", (const FcChar8 *) "arphic"},
897 { (const FT_Char *) "ATEC", (const FcChar8 *) "alltype"},
898 { (const FT_Char *) "B&H", (const FcChar8 *) "b&h"},
899 { (const FT_Char *) "BITS", (const FcChar8 *) "bitstream"},
900 { (const FT_Char *) "CANO", (const FcChar8 *) "cannon"},
901 { (const FT_Char *) "DYNA", (const FcChar8 *) "dynalab"},
902 { (const FT_Char *) "EPSN", (const FcChar8 *) "epson"},
903 { (const FT_Char *) "FJ", (const FcChar8 *) "fujitsu"},
904 { (const FT_Char *) "IBM", (const FcChar8 *) "ibm"},
905 { (const FT_Char *) "ITC", (const FcChar8 *) "itc"},
906 { (const FT_Char *) "IMPR", (const FcChar8 *) "impress"},
907 { (const FT_Char *) "LARA", (const FcChar8 *) "larabiefonts"},
908 { (const FT_Char *) "LEAF", (const FcChar8 *) "interleaf"},
909 { (const FT_Char *) "LETR", (const FcChar8 *) "letraset"},
910 { (const FT_Char *) "LINO", (const FcChar8 *) "linotype"},
911 { (const FT_Char *) "MACR", (const FcChar8 *) "macromedia"},
912 { (const FT_Char *) "MONO", (const FcChar8 *) "monotype"},
913 { (const FT_Char *) "MS", (const FcChar8 *) "microsoft"},
914 { (const FT_Char *) "MT", (const FcChar8 *) "monotype"},
915 { (const FT_Char *) "NEC", (const FcChar8 *) "nec"},
916 { (const FT_Char *) "PARA", (const FcChar8 *) "paratype"},
917 { (const FT_Char *) "QMSI", (const FcChar8 *) "qms"},
918 { (const FT_Char *) "RICO", (const FcChar8 *) "ricoh"},
919 { (const FT_Char *) "URW", (const FcChar8 *) "urw"},
920 { (const FT_Char *) "Y&Y", (const FcChar8 *) "y&y"}
2e2121f9
KP
921};
922
67accef4 923#define NUM_VENDOR_FOUNDRIES (int) (sizeof (FcVendorFoundries) / sizeof (FcVendorFoundries[0]))
2e2121f9
KP
924
925static const FcChar8 *
6ae6acf3 926FcVendorFoundry(const FT_Char vendor[4])
2ae95e77
JC
927{
928 int i;
2e2121f9
KP
929
930 if (vendor)
931 for(i = 0; i < NUM_VENDOR_FOUNDRIES; i++)
932 if (FcVendorMatch (vendor, FcVendorFoundries[i].vendor))
933 return FcVendorFoundries[i].foundry;
934 return 0;
2ae95e77
JC
935}
936
11fec41c 937typedef struct _FcStringConst {
6ae6acf3
KP
938 const FcChar8 *name;
939 int value;
11fec41c
KP
940} FcStringConst;
941
942static int
943FcStringIsConst (const FcChar8 *string,
944 const FcStringConst *c,
945 int nc)
946{
947 int i;
948
949 for (i = 0; i < nc; i++)
950 if (FcStrCmpIgnoreBlanksAndCase (string, c[i].name) == 0)
951 return c[i].value;
952 return -1;
953}
954
955static int
956FcStringContainsConst (const FcChar8 *string,
957 const FcStringConst *c,
958 int nc)
959{
960 int i;
961
962 for (i = 0; i < nc; i++)
963 if (FcStrContainsIgnoreBlanksAndCase (string, c[i].name))
964 return c[i].value;
965 return -1;
966}
967
8245771d
PL
968typedef FcChar8 *FC8;
969
11fec41c 970static const FcStringConst weightConsts[] = {
8245771d
PL
971 { (FC8) "thin", FC_WEIGHT_THIN },
972 { (FC8) "extralight", FC_WEIGHT_EXTRALIGHT },
973 { (FC8) "ultralight", FC_WEIGHT_ULTRALIGHT },
974 { (FC8) "light", FC_WEIGHT_LIGHT },
975 { (FC8) "book", FC_WEIGHT_BOOK },
976 { (FC8) "regular", FC_WEIGHT_REGULAR },
977 { (FC8) "normal", FC_WEIGHT_NORMAL },
978 { (FC8) "medium", FC_WEIGHT_MEDIUM },
979 { (FC8) "demibold", FC_WEIGHT_DEMIBOLD },
980 { (FC8) "demi", FC_WEIGHT_DEMIBOLD },
981 { (FC8) "semibold", FC_WEIGHT_SEMIBOLD },
8245771d 982 { (FC8) "extrabold", FC_WEIGHT_EXTRABOLD },
c2c6976d 983 { (FC8) "superbold", FC_WEIGHT_EXTRABOLD },
8245771d 984 { (FC8) "ultrabold", FC_WEIGHT_ULTRABOLD },
c2c6976d 985 { (FC8) "bold", FC_WEIGHT_BOLD },
8245771d
PL
986 { (FC8) "black", FC_WEIGHT_BLACK },
987 { (FC8) "heavy", FC_WEIGHT_HEAVY },
11fec41c
KP
988};
989
67accef4 990#define NUM_WEIGHT_CONSTS (int) (sizeof (weightConsts) / sizeof (weightConsts[0]))
11fec41c
KP
991
992#define FcIsWeight(s) FcStringIsConst(s,weightConsts,NUM_WEIGHT_CONSTS)
993#define FcContainsWeight(s) FcStringContainsConst (s,weightConsts,NUM_WEIGHT_CONSTS)
994
995static const FcStringConst widthConsts[] = {
8245771d
PL
996 { (FC8) "ultracondensed", FC_WIDTH_ULTRACONDENSED },
997 { (FC8) "extracondensed", FC_WIDTH_EXTRACONDENSED },
998 { (FC8) "semicondensed", FC_WIDTH_SEMICONDENSED },
999 { (FC8) "condensed", FC_WIDTH_CONDENSED }, /* must be after *condensed */
1000 { (FC8) "normal", FC_WIDTH_NORMAL },
1001 { (FC8) "semiexpanded", FC_WIDTH_SEMIEXPANDED },
1002 { (FC8) "extraexpanded", FC_WIDTH_EXTRAEXPANDED },
1003 { (FC8) "ultraexpanded", FC_WIDTH_ULTRAEXPANDED },
1004 { (FC8) "expanded", FC_WIDTH_EXPANDED }, /* must be after *expanded */
11fec41c
KP
1005};
1006
67accef4 1007#define NUM_WIDTH_CONSTS (int) (sizeof (widthConsts) / sizeof (widthConsts[0]))
11fec41c
KP
1008
1009#define FcIsWidth(s) FcStringIsConst(s,widthConsts,NUM_WIDTH_CONSTS)
1010#define FcContainsWidth(s) FcStringContainsConst (s,widthConsts,NUM_WIDTH_CONSTS)
1011
1012static const FcStringConst slantConsts[] = {
8245771d 1013 { (FC8) "italic", FC_SLANT_ITALIC },
c2c6976d 1014 { (FC8) "kursiv", FC_SLANT_ITALIC },
8245771d 1015 { (FC8) "oblique", FC_SLANT_OBLIQUE },
11fec41c
KP
1016};
1017
67accef4 1018#define NUM_SLANT_CONSTS (int) (sizeof (slantConsts) / sizeof (slantConsts[0]))
11fec41c
KP
1019
1020#define FcIsSlant(s) FcStringIsConst(s,slantConsts,NUM_SLANT_CONSTS)
1021#define FcContainsSlant(s) FcStringContainsConst (s,slantConsts,NUM_SLANT_CONSTS)
2ae95e77 1022
c2c6976d
KP
1023static const FcStringConst decorativeConsts[] = {
1024 { (FC8) "shadow", FcTrue },
1025 { (FC8) "smallcaps", FcTrue },
1026 { (FC8) "antiqua", FcTrue },
1027 { (FC8) "romansc", FcTrue },
1028 { (FC8) "embosed", FcTrue },
1029 { (FC8) "romansmallcaps", FcTrue },
1030};
1031
1032#define NUM_DECORATIVE_CONSTS (int) (sizeof (decorativeConsts) / sizeof (decorativeConsts[0]))
1033
1034#define FcIsDecorative(s) FcStringIsConst(s,decorativeConsts,NUM_DECORATIVE_CONSTS)
1035#define FcContainsDecorative(s) FcStringContainsConst (s,decorativeConsts,NUM_DECORATIVE_CONSTS)
1036
b68b9646
KP
1037static double
1038FcGetPixelSize (FT_Face face, int i)
1039{
208a720f 1040#if HAVE_FT_GET_BDF_PROPERTY
b68b9646
KP
1041 if (face->num_fixed_sizes == 1)
1042 {
1043 BDF_PropertyRec prop;
1044 int rc;
1045
8ebf7725 1046 rc = FT_Get_BDF_Property (face, "PIXEL_SIZE", &prop);
b68b9646
KP
1047 if (rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER)
1048 return (double) prop.u.integer;
1049 }
1050#endif
208a720f 1051#if HAVE_FT_BITMAP_SIZE_Y_PPEM
b68b9646 1052 return (double) face->available_sizes[i].y_ppem / 64.0;
4f38fa81 1053#else
6ae6acf3 1054 return (double) face->available_sizes[i].height;
4f38fa81 1055#endif
b68b9646
KP
1056}
1057
4f27c1c0 1058static FcBool
67accef4 1059FcStringInPatternElement (FcPattern *pat, const char *elt, FcChar8 *string)
4f27c1c0
KP
1060{
1061 int e;
1062 FcChar8 *old;
1063 for (e = 0; FcPatternGetString (pat, elt, e, &old) == FcResultMatch; e++)
1064 if (!FcStrCmpIgnoreBlanksAndCase (old, string))
1065 {
1066 return FcTrue;
4f27c1c0
KP
1067 }
1068 return FcFalse;
1069}
1070
253ec760
KP
1071static const FT_UShort platform_order[] = {
1072 TT_PLATFORM_MICROSOFT,
1073 TT_PLATFORM_APPLE_UNICODE,
1074 TT_PLATFORM_MACINTOSH,
1075};
1076#define NUM_PLATFORM_ORDER (sizeof (platform_order) / sizeof (platform_order[0]))
1077
1078static const FT_UShort nameid_order[] = {
1079 TT_NAME_ID_PREFERRED_FAMILY,
1080 TT_NAME_ID_FONT_FAMILY,
1081 TT_NAME_ID_MAC_FULL_NAME,
1082 TT_NAME_ID_FULL_NAME,
1083 TT_NAME_ID_PREFERRED_SUBFAMILY,
1084 TT_NAME_ID_FONT_SUBFAMILY,
1085 TT_NAME_ID_TRADEMARK,
1086 TT_NAME_ID_MANUFACTURER,
1087};
1088
1089#define NUM_NAMEID_ORDER (sizeof (nameid_order) / sizeof (nameid_order[0]))
24330d27 1090FcPattern *
72ffe653
KP
1091FcFreeTypeQueryFace (const FT_Face face,
1092 const FcChar8 *file,
1093 int id,
1094 FcBlanks *blanks)
24330d27 1095{
ccb3e93b 1096 FcPattern *pat;
11fec41c
KP
1097 int slant = -1;
1098 int weight = -1;
81fa16c3 1099 int width = -1;
c2c6976d 1100 FcBool decorative = FcFalse;
ccb3e93b
KP
1101 int i;
1102 FcCharSet *cs;
d8d73958 1103 FcLangSet *ls;
4f27c1c0 1104#if 0
2e2121f9 1105 FcChar8 *family = 0;
4f27c1c0 1106#endif
dbf68dd5 1107 FcChar8 *complex;
2e2121f9 1108 const FcChar8 *foundry = 0;
848d32bd 1109 int spacing;
ccb3e93b 1110 TT_OS2 *os2;
79621aa5 1111#if HAVE_FT_GET_PS_FONT_INFO
d6ea8347 1112 PS_FontInfoRec psfontinfo;
79621aa5
KP
1113#endif
1114#if HAVE_FT_GET_BDF_PROPERTY
53183e66
KP
1115 BDF_PropertyRec prop;
1116#endif
a342e87d 1117 TT_Header *head;
e50b9ae7 1118 const FcChar8 *exclusiveLang = 0;
69937bd9
KP
1119 FT_SfntName sname;
1120 FT_UInt snamei, snamec;
4f27c1c0
KP
1121
1122 int nfamily = 0;
1123 int nfamily_lang = 0;
1124 int nstyle = 0;
1125 int nstyle_lang = 0;
1126 int nfullname = 0;
1127 int nfullname_lang = 0;
253ec760
KP
1128 int p, platform;
1129 int n, nameid;
24330d27 1130
4f27c1c0
KP
1131 FcChar8 *style = 0;
1132 int st;
1133
24330d27
KP
1134 pat = FcPatternCreate ();
1135 if (!pat)
1136 goto bail0;
1137
1138 if (!FcPatternAddBool (pat, FC_OUTLINE,
1139 (face->face_flags & FT_FACE_FLAG_SCALABLE) != 0))
1140 goto bail1;
1141
1142 if (!FcPatternAddBool (pat, FC_SCALABLE,
1143 (face->face_flags & FT_FACE_FLAG_SCALABLE) != 0))
1144 goto bail1;
1145
1146
2ae95e77
JC
1147 /*
1148 * Get the OS/2 table
1149 */
1150 os2 = (TT_OS2 *) FT_Get_Sfnt_Table (face, ft_sfnt_os2);
1151
2e2121f9
KP
1152 /*
1153 * Look first in the OS/2 table for the foundry, if
1154 * not found here, the various notices will be searched for
1155 * that information, either from the sfnt name tables or
0e7a4347
KP
1156 * the Postscript FontInfo dictionary. Finally, the
1157 * BDF properties will queried.
2e2121f9
KP
1158 */
1159
2ae95e77 1160 if (os2 && os2->version >= 0x0001 && os2->version != 0xffff)
2e2121f9 1161 foundry = FcVendorFoundry(os2->achVendID);
2ae95e77 1162
4f27c1c0
KP
1163 if (FcDebug () & FC_DBG_SCANV)
1164 printf ("\n");
69937bd9
KP
1165 /*
1166 * Grub through the name table looking for family
1167 * and style names. FreeType makes quite a hash
1168 * of them
1169 */
69937bd9 1170 snamec = FT_Get_Sfnt_Name_Count (face);
253ec760 1171 for (p = 0; p <= NUM_PLATFORM_ORDER; p++)
69937bd9 1172 {
253ec760
KP
1173 if (p < NUM_PLATFORM_ORDER)
1174 platform = platform_order[p];
1175 else
1176 platform = 0xffff;
4f27c1c0 1177
253ec760
KP
1178 /*
1179 * Order nameids so preferred names appear first
1180 * in the resulting list
1181 */
1182 for (n = 0; n < NUM_NAMEID_ORDER; n++)
4f27c1c0 1183 {
253ec760 1184 nameid = nameid_order[n];
4f27c1c0 1185
253ec760 1186 for (snamei = 0; snamei < snamec; snamei++)
4f27c1c0 1187 {
253ec760
KP
1188 FcChar8 *utf8;
1189 const FcChar8 *lang;
1190 const char *elt = 0, *eltlang = 0;
1191 int *np = 0, *nlangp = 0;
1192
1193 if (FT_Get_Sfnt_Name (face, snamei, &sname) != 0)
1194 continue;
1195 if (sname.name_id != nameid)
1196 continue;
1197
1198 /*
1199 * Sort platforms in preference order, accepting
1200 * all other platforms last
1201 */
1202 if (p < NUM_PLATFORM_ORDER)
1203 {
1204 if (sname.platform_id != platform)
1205 continue;
1206 }
1207 else
1208 {
1209 int sp;
1210
1211 for (sp = 0; sp < NUM_PLATFORM_ORDER; sp++)
1212 if (sname.platform_id == platform_order[sp])
1213 break;
1214 if (sp != NUM_PLATFORM_ORDER)
1215 continue;
1216 }
1217 utf8 = FcSfntNameTranscode (&sname);
1218 lang = FcSfntNameLanguage (&sname);
1219
1220 if (!utf8)
1221 continue;
1222
1223 switch (sname.name_id) {
1224 case TT_NAME_ID_PREFERRED_FAMILY:
1225 case TT_NAME_ID_FONT_FAMILY:
1226#if 0
1227 case TT_NAME_ID_PS_NAME:
1228 case TT_NAME_ID_UNIQUE_ID:
1229#endif
1230 if (FcDebug () & FC_DBG_SCANV)
1231 printf ("found family (n %2d p %d e %d l 0x%04x) %s\n",
1232 sname.name_id, sname.platform_id,
1233 sname.encoding_id, sname.language_id,
1234 utf8);
1235
1236 elt = FC_FAMILY;
1237 eltlang = FC_FAMILYLANG;
1238 np = &nfamily;
1239 nlangp = &nfamily_lang;
1240 break;
1241 case TT_NAME_ID_MAC_FULL_NAME:
1242 case TT_NAME_ID_FULL_NAME:
1243 if (FcDebug () & FC_DBG_SCANV)
1244 printf ("found full (n %2d p %d e %d l 0x%04x) %s\n",
1245 sname.name_id, sname.platform_id,
1246 sname.encoding_id, sname.language_id,
1247 utf8);
1248
1249 elt = FC_FULLNAME;
1250 eltlang = FC_FULLNAMELANG;
1251 np = &nfullname;
1252 nlangp = &nfullname_lang;
1253 break;
1254 case TT_NAME_ID_PREFERRED_SUBFAMILY:
1255 case TT_NAME_ID_FONT_SUBFAMILY:
1256 if (FcDebug () & FC_DBG_SCANV)
1257 printf ("found style (n %2d p %d e %d l 0x%04x) %s\n",
1258 sname.name_id, sname.platform_id,
1259 sname.encoding_id, sname.language_id,
1260 utf8);
1261
1262 elt = FC_STYLE;
1263 eltlang = FC_STYLELANG;
1264 np = &nstyle;
1265 nlangp = &nstyle_lang;
1266 break;
1267 case TT_NAME_ID_TRADEMARK:
1268 case TT_NAME_ID_MANUFACTURER:
1269 /* If the foundry wasn't found in the OS/2 table, look here */
1270 if(!foundry)
1271 foundry = FcNoticeFoundry((FT_String *) utf8);
1272 break;
1273 }
1274 if (elt)
4f27c1c0 1275 {
253ec760
KP
1276 if (FcStringInPatternElement (pat, elt, utf8))
1277 {
1278 free (utf8);
1279 continue;
1280 }
1281
1282 /* add new element */
1283 if (!FcPatternAddString (pat, elt, utf8))
1284 {
1285 free (utf8);
4f27c1c0 1286 goto bail1;
253ec760
KP
1287 }
1288 free (utf8);
1289 if (lang)
1290 {
1291 /* pad lang list with 'xx' to line up with elt */
1292 while (*nlangp < *np)
1293 {
1294 if (!FcPatternAddString (pat, eltlang, (FcChar8 *) "xx"))
1295 goto bail1;
1296 ++*nlangp;
1297 }
1298 if (!FcPatternAddString (pat, eltlang, lang))
1299 goto bail1;
1300 ++*nlangp;
1301 }
1302 ++*np;
4f27c1c0 1303 }
253ec760
KP
1304 else
1305 free (utf8);
4f27c1c0 1306 }
4f27c1c0 1307 }
69937bd9 1308 }
253ec760 1309
e4125ef9 1310 if (!nfamily && face->family_name &&
8245771d 1311 FcStrCmpIgnoreBlanksAndCase ((FcChar8 *) face->family_name, (FcChar8 *) "") != 0)
4f27c1c0
KP
1312 {
1313 if (FcDebug () & FC_DBG_SCANV)
e4125ef9 1314 printf ("using FreeType family \"%s\"\n", face->family_name);
8245771d 1315 if (!FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) face->family_name))
4f27c1c0
KP
1316 goto bail1;
1317 ++nfamily;
1318 }
69937bd9 1319
e4125ef9 1320 if (!nstyle && face->style_name &&
8245771d 1321 FcStrCmpIgnoreBlanksAndCase ((FcChar8 *) face->style_name, (FcChar8 *) "") != 0)
4f27c1c0
KP
1322 {
1323 if (FcDebug () & FC_DBG_SCANV)
e4125ef9 1324 printf ("using FreeType style \"%s\"\n", face->style_name);
8245771d 1325 if (!FcPatternAddString (pat, FC_STYLE, (FcChar8 *) face->style_name))
4f27c1c0
KP
1326 goto bail1;
1327 ++nstyle;
1328 }
69937bd9 1329
4f27c1c0 1330 if (!nfamily)
24330d27 1331 {
69937bd9 1332 FcChar8 *start, *end;
4f27c1c0 1333 FcChar8 *family;
69937bd9
KP
1334
1335 start = (FcChar8 *) strrchr ((char *) file, '/');
1336 if (start)
1337 start++;
24330d27 1338 else
69937bd9
KP
1339 start = (FcChar8 *) file;
1340 end = (FcChar8 *) strrchr ((char *) start, '.');
1341 if (!end)
1342 end = start + strlen ((char *) start);
9dac3c59 1343 /* freed below */
69937bd9
KP
1344 family = malloc (end - start + 1);
1345 strncpy ((char *) family, (char *) start, end - start);
1346 family[end - start] = '\0';
4f27c1c0 1347 if (FcDebug () & FC_DBG_SCANV)
e4125ef9 1348 printf ("using filename for family %s\n", family);
4f27c1c0
KP
1349 if (!FcPatternAddString (pat, FC_FAMILY, family))
1350 {
1351 free (family);
1352 goto bail1;
1353 }
1354 free (family);
1355 ++nfamily;
24330d27 1356 }
69937bd9 1357
c1c3ba06 1358 if (!FcPatternAddString (pat, FC_FILE, file))
24330d27 1359 goto bail1;
e77c1718 1360
24330d27
KP
1361 if (!FcPatternAddInteger (pat, FC_INDEX, id))
1362 goto bail1;
1363
148656ed
KP
1364#if 0
1365 /*
1366 * don't even try this -- CJK 'monospace' fonts are really
1367 * dual width, and most other fonts don't bother to set
1368 * the attribute. Sigh.
1369 */
24330d27
KP
1370 if ((face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) != 0)
1371 if (!FcPatternAddInteger (pat, FC_SPACING, FC_MONO))
1372 goto bail1;
1373#endif
1374
a342e87d
KP
1375 /*
1376 * Find the font revision (if available)
1377 */
1378 head = (TT_Header *) FT_Get_Sfnt_Table (face, ft_sfnt_head);
1379 if (head)
1380 {
1381 if (!FcPatternAddInteger (pat, FC_FONTVERSION, head->Font_Revision))
1382 goto bail1;
1383 }
1384 else
1385 {
1386 if (!FcPatternAddInteger (pat, FC_FONTVERSION, 0))
1387 goto bail1;
1388 }
1389
4c003605
KP
1390 if (os2 && os2->version >= 0x0001 && os2->version != 0xffff)
1391 {
1392 for (i = 0; i < NUM_CODE_PAGE_RANGE; i++)
1393 {
1394 FT_ULong bits;
1395 int bit;
1396 if (FcCodePageRange[i].bit < 32)
1397 {
1398 bits = os2->ulCodePageRange1;
1399 bit = FcCodePageRange[i].bit;
1400 }
1401 else
1402 {
1403 bits = os2->ulCodePageRange2;
1404 bit = FcCodePageRange[i].bit - 32;
1405 }
1406 if (bits & (1 << bit))
1407 {
e50b9ae7
KP
1408 /*
1409 * If the font advertises support for multiple
1410 * "exclusive" languages, then include support
1411 * for any language found to have coverage
1412 */
1413 if (exclusiveLang)
1414 {
1415 exclusiveLang = 0;
1416 break;
1417 }
1418 exclusiveLang = FcCodePageRange[i].lang;
4c003605
KP
1419 }
1420 }
1421 }
1422
81fa16c3
KP
1423 if (os2 && os2->version != 0xffff)
1424 {
1425 if (os2->usWeightClass == 0)
11fec41c 1426 ;
81fa16c3
KP
1427 else if (os2->usWeightClass < 150)
1428 weight = FC_WEIGHT_THIN;
1429 else if (os2->usWeightClass < 250)
1430 weight = FC_WEIGHT_EXTRALIGHT;
1431 else if (os2->usWeightClass < 350)
1432 weight = FC_WEIGHT_LIGHT;
1433 else if (os2->usWeightClass < 450)
1434 weight = FC_WEIGHT_REGULAR;
1435 else if (os2->usWeightClass < 550)
1436 weight = FC_WEIGHT_MEDIUM;
1437 else if (os2->usWeightClass < 650)
1438 weight = FC_WEIGHT_SEMIBOLD;
1439 else if (os2->usWeightClass < 750)
1440 weight = FC_WEIGHT_BOLD;
1441 else if (os2->usWeightClass < 850)
1442 weight = FC_WEIGHT_EXTRABOLD;
1443 else if (os2->usWeightClass < 950)
1444 weight = FC_WEIGHT_BLACK;
c2c6976d
KP
1445 if ((FcDebug() & FC_DBG_SCANV) && weight != -1)
1446 printf ("\tos2 weight class %d maps to weight %d\n",
1447 os2->usWeightClass, weight);
81fa16c3
KP
1448
1449 switch (os2->usWidthClass) {
1450 case 1: width = FC_WIDTH_ULTRACONDENSED; break;
1451 case 2: width = FC_WIDTH_EXTRACONDENSED; break;
1452 case 3: width = FC_WIDTH_CONDENSED; break;
1453 case 4: width = FC_WIDTH_SEMICONDENSED; break;
1454 case 5: width = FC_WIDTH_NORMAL; break;
1455 case 6: width = FC_WIDTH_SEMIEXPANDED; break;
1456 case 7: width = FC_WIDTH_EXPANDED; break;
1457 case 8: width = FC_WIDTH_EXTRAEXPANDED; break;
1458 case 9: width = FC_WIDTH_ULTRAEXPANDED; break;
1459 }
c2c6976d
KP
1460 if ((FcDebug() & FC_DBG_SCANV) && width != -1)
1461 printf ("\tos2 width class %d maps to width %d\n",
1462 os2->usWidthClass, width);
81fa16c3 1463 }
dbf68dd5
KP
1464 if (os2 && (complex = FcFontCapabilities(face)))
1465 {
1466 if (!FcPatternAddString (pat, FC_CAPABILITY, complex))
1467 {
1468 free (complex);
1469 goto bail1;
1470 }
1471 free (complex);
1472 }
d6ea8347
KP
1473
1474 /*
1475 * Type 1: Check for FontInfo dictionary information
1476 * Code from g2@magestudios.net (Gerard Escalante)
1477 */
1478
79621aa5 1479#if HAVE_FT_GET_PS_FONT_INFO
d6ea8347
KP
1480 if (FT_Get_PS_Font_Info(face, &psfontinfo) == 0)
1481 {
11fec41c 1482 if (weight == -1 && psfontinfo.weight)
52253696 1483 {
8245771d 1484 weight = FcIsWeight ((FcChar8 *) psfontinfo.weight);
11fec41c
KP
1485 if (FcDebug() & FC_DBG_SCANV)
1486 printf ("\tType1 weight %s maps to %d\n",
1487 psfontinfo.weight, weight);
52253696 1488 }
d6ea8347 1489
70ee8809
KP
1490#if 0
1491 /*
1492 * Don't bother with italic_angle; FreeType already extracts that
1493 * information for us and sticks it into style_flags
1494 */
1495 if (psfontinfo.italic_angle)
d6ea8347 1496 slant = FC_SLANT_ITALIC;
70ee8809 1497 else
d6ea8347 1498 slant = FC_SLANT_ROMAN;
70ee8809 1499#endif
2ae95e77
JC
1500
1501 if(!foundry)
2e2121f9 1502 foundry = FcNoticeFoundry(psfontinfo.notice);
d6ea8347 1503 }
79621aa5 1504#endif /* HAVE_FT_GET_PS_FONT_INFO */
81fa16c3 1505
79621aa5 1506#if HAVE_FT_GET_BDF_PROPERTY
0e7a4347
KP
1507 /*
1508 * Finally, look for a FOUNDRY BDF property if no other
1509 * mechanism has managed to locate a foundry
1510 */
1511
1512 if (!foundry)
1513 {
1514 int rc;
8ebf7725 1515 rc = FT_Get_BDF_Property(face, "FOUNDRY", &prop);
0e7a4347 1516 if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM)
8245771d 1517 foundry = (FcChar8 *) prop.u.atom;
0e7a4347
KP
1518 }
1519
1520 if (width == -1)
1521 {
8ebf7725 1522 if (FT_Get_BDF_Property(face, "RELATIVE_SETWIDTH", &prop) == 0 &&
0e7a4347
KP
1523 (prop.type == BDF_PROPERTY_TYPE_INTEGER ||
1524 prop.type == BDF_PROPERTY_TYPE_CARDINAL))
1525 {
1526 FT_Int32 value;
1527
1528 if (prop.type == BDF_PROPERTY_TYPE_INTEGER)
1529 value = prop.u.integer;
1530 else
1531 value = (FT_Int32) prop.u.cardinal;
1532 switch ((value + 5) / 10) {
1533 case 1: width = FC_WIDTH_ULTRACONDENSED; break;
1534 case 2: width = FC_WIDTH_EXTRACONDENSED; break;
1535 case 3: width = FC_WIDTH_CONDENSED; break;
1536 case 4: width = FC_WIDTH_SEMICONDENSED; break;
1537 case 5: width = FC_WIDTH_NORMAL; break;
1538 case 6: width = FC_WIDTH_SEMIEXPANDED; break;
1539 case 7: width = FC_WIDTH_EXPANDED; break;
1540 case 8: width = FC_WIDTH_EXTRAEXPANDED; break;
1541 case 9: width = FC_WIDTH_ULTRAEXPANDED; break;
1542 }
1543 }
0b7a0da2 1544 if (width == -1 &&
8ebf7725 1545 FT_Get_BDF_Property (face, "SETWIDTH_NAME", &prop) == 0 &&
0b7a0da2 1546 prop.type == BDF_PROPERTY_TYPE_ATOM)
0e7a4347 1547 {
8245771d 1548 width = FcIsWidth ((FcChar8 *) prop.u.atom);
0e7a4347 1549 if (FcDebug () & FC_DBG_SCANV)
0b7a0da2 1550 printf ("\tsetwidth %s maps to %d\n", prop.u.atom, width);
0e7a4347
KP
1551 }
1552 }
0e7a4347
KP
1553#endif
1554
11fec41c
KP
1555 /*
1556 * Look for weight, width and slant names in the style value
1557 */
4f27c1c0 1558 for (st = 0; FcPatternGetString (pat, FC_STYLE, st, &style) == FcResultMatch; st++)
11fec41c
KP
1559 {
1560 if (weight == -1)
1561 {
1562 weight = FcContainsWeight (style);
1563 if (FcDebug() & FC_DBG_SCANV)
1564 printf ("\tStyle %s maps to weight %d\n", style, weight);
1565 }
1566 if (width == -1)
1567 {
1568 width = FcContainsWidth (style);
1569 if (FcDebug() & FC_DBG_SCANV)
1570 printf ("\tStyle %s maps to width %d\n", style, width);
1571 }
1572 if (slant == -1)
1573 {
1574 slant = FcContainsSlant (style);
1575 if (FcDebug() & FC_DBG_SCANV)
1576 printf ("\tStyle %s maps to slant %d\n", style, slant);
1577 }
c2c6976d
KP
1578 if (decorative == FcFalse)
1579 {
1580 decorative = FcContainsDecorative (style) > 0;
1581 if (FcDebug() & FC_DBG_SCANV)
1582 printf ("\tStyle %s maps to decorative %d\n", style, decorative);
1583 }
11fec41c
KP
1584 }
1585 /*
1586 * Pull default values from the FreeType flags if more
1587 * specific values not found above
1588 */
1589 if (slant == -1)
1590 {
1591 slant = FC_SLANT_ROMAN;
1592 if (face->style_flags & FT_STYLE_FLAG_ITALIC)
1593 slant = FC_SLANT_ITALIC;
1594 }
1595
1596 if (weight == -1)
1597 {
1598 weight = FC_WEIGHT_MEDIUM;
1599 if (face->style_flags & FT_STYLE_FLAG_BOLD)
1600 weight = FC_WEIGHT_BOLD;
1601 }
1602
89e28590
KP
1603 if (width == -1)
1604 width = FC_WIDTH_NORMAL;
1605
1606 if (foundry == 0)
8245771d 1607 foundry = (FcChar8 *) "unknown";
89e28590 1608
81fa16c3
KP
1609 if (!FcPatternAddInteger (pat, FC_SLANT, slant))
1610 goto bail1;
1611
1612 if (!FcPatternAddInteger (pat, FC_WEIGHT, weight))
1613 goto bail1;
1614
89e28590
KP
1615 if (!FcPatternAddInteger (pat, FC_WIDTH, width))
1616 goto bail1;
81fa16c3 1617
89e28590
KP
1618 if (!FcPatternAddString (pat, FC_FOUNDRY, foundry))
1619 goto bail1;
2e2121f9 1620
c2c6976d
KP
1621 if (!FcPatternAddBool (pat, FC_DECORATIVE, decorative))
1622 goto bail1;
1623
4c003605
KP
1624 /*
1625 * Compute the unicode coverage for the font
1626 */
848d32bd 1627 cs = FcFreeTypeCharSetAndSpacing (face, blanks, &spacing);
24330d27
KP
1628 if (!cs)
1629 goto bail1;
1630
79621aa5 1631#if HAVE_FT_GET_BDF_PROPERTY
ecb7c180
JC
1632 /* For PCF fonts, override the computed spacing with the one from
1633 the property */
8ebf7725 1634 if(FT_Get_BDF_Property(face, "SPACING", &prop) == 0 &&
ecb7c180 1635 prop.type == BDF_PROPERTY_TYPE_ATOM) {
02638f1a 1636 if(!strcmp(prop.u.atom, "c") || !strcmp(prop.u.atom, "C"))
ecb7c180 1637 spacing = FC_CHARCELL;
02638f1a 1638 else if(!strcmp(prop.u.atom, "m") || !strcmp(prop.u.atom, "M"))
ecb7c180 1639 spacing = FC_MONO;
02638f1a 1640 else if(!strcmp(prop.u.atom, "p") || !strcmp(prop.u.atom, "P"))
ecb7c180
JC
1641 spacing = FC_PROPORTIONAL;
1642 }
1643#endif
1644
24330d27
KP
1645 /*
1646 * Skip over PCF fonts that have no encoded characters; they're
1647 * usually just Unicode fonts transcoded to some legacy encoding
6f767cec
PL
1648 * ftglue.c forces us to approximate whether a font is a PCF font
1649 * or not by whether it has any BDF properties. Try PIXEL_SIZE;
1650 * I don't know how to get a list of BDF properties on the font. -PL
24330d27 1651 */
e50b9ae7 1652 if (FcCharSetCount (cs) == 0)
24330d27 1653 {
6f767cec
PL
1654#if HAVE_FT_GET_BDF_PROPERTY
1655 if(FT_Get_BDF_Property(face, "PIXEL_SIZE", &prop) == 0)
24330d27 1656 goto bail2;
8ebf7725 1657#endif
6f767cec 1658 }
24330d27
KP
1659
1660 if (!FcPatternAddCharSet (pat, FC_CHARSET, cs))
1661 goto bail2;
4c003605 1662
d8d73958
KP
1663 ls = FcFreeTypeLangSet (cs, exclusiveLang);
1664 if (!ls)
1665 goto bail2;
1666
1667 if (!FcPatternAddLangSet (pat, FC_LANG, ls))
53183e66
KP
1668 {
1669 FcLangSetDestroy (ls);
d8d73958 1670 goto bail2;
53183e66
KP
1671 }
1672
1673 FcLangSetDestroy (ls);
82f4243f 1674
848d32bd
KP
1675 if (spacing != FC_PROPORTIONAL)
1676 if (!FcPatternAddInteger (pat, FC_SPACING, spacing))
1677 goto bail2;
1678
24330d27
KP
1679 if (!(face->face_flags & FT_FACE_FLAG_SCALABLE))
1680 {
1681 for (i = 0; i < face->num_fixed_sizes; i++)
1682 if (!FcPatternAddDouble (pat, FC_PIXEL_SIZE,
b68b9646 1683 FcGetPixelSize (face, i)))
f8a17f32 1684 goto bail2;
24330d27 1685 if (!FcPatternAddBool (pat, FC_ANTIALIAS, FcFalse))
f8a17f32 1686 goto bail2;
79621aa5 1687#if HAVE_FT_GET_BDF_PROPERTY
0f362ad5
JC
1688 if(face->num_fixed_sizes == 1) {
1689 int rc;
1690 int value;
0f362ad5 1691
5657098e
PL
1692 /* skip bitmap fonts which do not even have a family name */
1693 rc = FT_Get_BDF_Property(face, "FAMILY_NAME", &prop);
1694 if (rc != 0 || prop.type != BDF_PROPERTY_TYPE_ATOM)
1695 goto bail2;
1696
8ebf7725 1697 rc = FT_Get_BDF_Property(face, "POINT_SIZE", &prop);
0f362ad5
JC
1698 if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER)
1699 value = prop.u.integer;
1700 else if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_CARDINAL)
1701 value = prop.u.cardinal;
1702 else
1703 goto nevermind;
1704 if(!FcPatternAddDouble(pat, FC_SIZE, value / 10.0))
1705 goto nevermind;
1706
8ebf7725 1707 rc = FT_Get_BDF_Property(face, "RESOLUTION_Y", &prop);
0f362ad5
JC
1708 if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER)
1709 value = prop.u.integer;
1710 else if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_CARDINAL)
1711 value = prop.u.cardinal;
1712 else
1713 goto nevermind;
1714 if(!FcPatternAddDouble(pat, FC_DPI, (double)value))
1715 goto nevermind;
1716
1717 }
1718 nevermind:
1719 ;
1720#endif
24330d27 1721 }
537e3d23
KP
1722#if HAVE_FT_GET_X11_FONT_FORMAT
1723 /*
1724 * Use the (not well documented or supported) X-specific function
1725 * from FreeType to figure out the font format
1726 */
1727 {
1728 const char *font_format = FT_Get_X11_Font_Format (face);
1729 if (font_format)
8245771d 1730 FcPatternAddString (pat, FC_FONTFORMAT, (FcChar8 *) font_format);
537e3d23
KP
1731 }
1732#endif
24330d27 1733
11fec41c
KP
1734 /*
1735 * Drop our reference to the charset
1736 */
1737 FcCharSetDestroy (cs);
1738
24330d27
KP
1739 return pat;
1740
1741bail2:
1742 FcCharSetDestroy (cs);
1743bail1:
1744 FcPatternDestroy (pat);
1745bail0:
72ffe653
KP
1746 return NULL;
1747}
1748
1749FcPattern *
1750FcFreeTypeQuery(const FcChar8 *file,
1751 int id,
1752 FcBlanks *blanks,
1753 int *count)
1754{
1755 FT_Face face;
1756 FT_Library ftLibrary;
1757 FcPattern *pat = NULL;
1758
1759 if (FT_Init_FreeType (&ftLibrary))
1760 return NULL;
1761
1762 if (FT_New_Face (ftLibrary, (char *) file, id, &face))
1763 goto bail;
1764
1765 *count = face->num_faces;
1766
1767 pat = FcFreeTypeQueryFace (face, file, id, blanks);
1768
24330d27
KP
1769 FT_Done_Face (face);
1770bail:
1771 FT_Done_FreeType (ftLibrary);
72ffe653 1772 return pat;
24330d27 1773}
c647f6f1 1774
c647f6f1
KP
1775/*
1776 * For our purposes, this approximation is sufficient
1777 */
79621aa5 1778#if !HAVE_FT_GET_NEXT_CHAR
c647f6f1
KP
1779#define FT_Get_Next_Char(face, ucs4, gi) ((ucs4) >= 0xffffff ? \
1780 (*(gi) = 0), 0 : \
1781 (*(gi) = 1), (ucs4) + 1)
ec0c740e 1782#warning "No FT_Get_Next_Char: Please install freetype version 2.1.0 or newer"
c647f6f1
KP
1783#endif
1784
1785typedef struct _FcCharEnt {
1786 FcChar16 bmp;
1787 unsigned char encode;
1788} FcCharEnt;
1789
1790struct _FcCharMap {
1791 const FcCharEnt *ent;
1792 int nent;
1793};
1794
1795typedef struct _FcFontDecode {
1796 FT_Encoding encoding;
1797 const FcCharMap *map;
1798 FcChar32 max;
1799} FcFontDecode;
1800
1801static const FcCharEnt AppleRomanEnt[] = {
1802 { 0x0020, 0x20 }, /* SPACE */
1803 { 0x0021, 0x21 }, /* EXCLAMATION MARK */
1804 { 0x0022, 0x22 }, /* QUOTATION MARK */
1805 { 0x0023, 0x23 }, /* NUMBER SIGN */
1806 { 0x0024, 0x24 }, /* DOLLAR SIGN */
1807 { 0x0025, 0x25 }, /* PERCENT SIGN */
1808 { 0x0026, 0x26 }, /* AMPERSAND */
1809 { 0x0027, 0x27 }, /* APOSTROPHE */
1810 { 0x0028, 0x28 }, /* LEFT PARENTHESIS */
1811 { 0x0029, 0x29 }, /* RIGHT PARENTHESIS */
1812 { 0x002A, 0x2A }, /* ASTERISK */
1813 { 0x002B, 0x2B }, /* PLUS SIGN */
1814 { 0x002C, 0x2C }, /* COMMA */
1815 { 0x002D, 0x2D }, /* HYPHEN-MINUS */
1816 { 0x002E, 0x2E }, /* FULL STOP */
1817 { 0x002F, 0x2F }, /* SOLIDUS */
1818 { 0x0030, 0x30 }, /* DIGIT ZERO */
1819 { 0x0031, 0x31 }, /* DIGIT ONE */
1820 { 0x0032, 0x32 }, /* DIGIT TWO */
1821 { 0x0033, 0x33 }, /* DIGIT THREE */
1822 { 0x0034, 0x34 }, /* DIGIT FOUR */
1823 { 0x0035, 0x35 }, /* DIGIT FIVE */
1824 { 0x0036, 0x36 }, /* DIGIT SIX */
1825 { 0x0037, 0x37 }, /* DIGIT SEVEN */
1826 { 0x0038, 0x38 }, /* DIGIT EIGHT */
1827 { 0x0039, 0x39 }, /* DIGIT NINE */
1828 { 0x003A, 0x3A }, /* COLON */
1829 { 0x003B, 0x3B }, /* SEMICOLON */
1830 { 0x003C, 0x3C }, /* LESS-THAN SIGN */
1831 { 0x003D, 0x3D }, /* EQUALS SIGN */
1832 { 0x003E, 0x3E }, /* GREATER-THAN SIGN */
1833 { 0x003F, 0x3F }, /* QUESTION MARK */
1834 { 0x0040, 0x40 }, /* COMMERCIAL AT */
1835 { 0x0041, 0x41 }, /* LATIN CAPITAL LETTER A */
1836 { 0x0042, 0x42 }, /* LATIN CAPITAL LETTER B */
1837 { 0x0043, 0x43 }, /* LATIN CAPITAL LETTER C */
1838 { 0x0044, 0x44 }, /* LATIN CAPITAL LETTER D */
1839 { 0x0045, 0x45 }, /* LATIN CAPITAL LETTER E */
1840 { 0x0046, 0x46 }, /* LATIN CAPITAL LETTER F */
1841 { 0x0047, 0x47 }, /* LATIN CAPITAL LETTER G */
1842 { 0x0048, 0x48 }, /* LATIN CAPITAL LETTER H */
1843 { 0x0049, 0x49 }, /* LATIN CAPITAL LETTER I */
1844 { 0x004A, 0x4A }, /* LATIN CAPITAL LETTER J */
1845 { 0x004B, 0x4B }, /* LATIN CAPITAL LETTER K */
1846 { 0x004C, 0x4C }, /* LATIN CAPITAL LETTER L */
1847 { 0x004D, 0x4D }, /* LATIN CAPITAL LETTER M */
1848 { 0x004E, 0x4E }, /* LATIN CAPITAL LETTER N */
1849 { 0x004F, 0x4F }, /* LATIN CAPITAL LETTER O */
1850 { 0x0050, 0x50 }, /* LATIN CAPITAL LETTER P */
1851 { 0x0051, 0x51 }, /* LATIN CAPITAL LETTER Q */
1852 { 0x0052, 0x52 }, /* LATIN CAPITAL LETTER R */
1853 { 0x0053, 0x53 }, /* LATIN CAPITAL LETTER S */
1854 { 0x0054, 0x54 }, /* LATIN CAPITAL LETTER T */
1855 { 0x0055, 0x55 }, /* LATIN CAPITAL LETTER U */
1856 { 0x0056, 0x56 }, /* LATIN CAPITAL LETTER V */
1857 { 0x0057, 0x57 }, /* LATIN CAPITAL LETTER W */
1858 { 0x0058, 0x58 }, /* LATIN CAPITAL LETTER X */
1859 { 0x0059, 0x59 }, /* LATIN CAPITAL LETTER Y */
1860 { 0x005A, 0x5A }, /* LATIN CAPITAL LETTER Z */
1861 { 0x005B, 0x5B }, /* LEFT SQUARE BRACKET */
1862 { 0x005C, 0x5C }, /* REVERSE SOLIDUS */
1863 { 0x005D, 0x5D }, /* RIGHT SQUARE BRACKET */
1864 { 0x005E, 0x5E }, /* CIRCUMFLEX ACCENT */
1865 { 0x005F, 0x5F }, /* LOW LINE */
1866 { 0x0060, 0x60 }, /* GRAVE ACCENT */
1867 { 0x0061, 0x61 }, /* LATIN SMALL LETTER A */
1868 { 0x0062, 0x62 }, /* LATIN SMALL LETTER B */
1869 { 0x0063, 0x63 }, /* LATIN SMALL LETTER C */
1870 { 0x0064, 0x64 }, /* LATIN SMALL LETTER D */
1871 { 0x0065, 0x65 }, /* LATIN SMALL LETTER E */
1872 { 0x0066, 0x66 }, /* LATIN SMALL LETTER F */
1873 { 0x0067, 0x67 }, /* LATIN SMALL LETTER G */
1874 { 0x0068, 0x68 }, /* LATIN SMALL LETTER H */
1875 { 0x0069, 0x69 }, /* LATIN SMALL LETTER I */
1876 { 0x006A, 0x6A }, /* LATIN SMALL LETTER J */
1877 { 0x006B, 0x6B }, /* LATIN SMALL LETTER K */
1878 { 0x006C, 0x6C }, /* LATIN SMALL LETTER L */
1879 { 0x006D, 0x6D }, /* LATIN SMALL LETTER M */
1880 { 0x006E, 0x6E }, /* LATIN SMALL LETTER N */
1881 { 0x006F, 0x6F }, /* LATIN SMALL LETTER O */
1882 { 0x0070, 0x70 }, /* LATIN SMALL LETTER P */
1883 { 0x0071, 0x71 }, /* LATIN SMALL LETTER Q */
1884 { 0x0072, 0x72 }, /* LATIN SMALL LETTER R */
1885 { 0x0073, 0x73 }, /* LATIN SMALL LETTER S */
1886 { 0x0074, 0x74 }, /* LATIN SMALL LETTER T */
1887 { 0x0075, 0x75 }, /* LATIN SMALL LETTER U */
1888 { 0x0076, 0x76 }, /* LATIN SMALL LETTER V */
1889 { 0x0077, 0x77 }, /* LATIN SMALL LETTER W */
1890 { 0x0078, 0x78 }, /* LATIN SMALL LETTER X */
1891 { 0x0079, 0x79 }, /* LATIN SMALL LETTER Y */
1892 { 0x007A, 0x7A }, /* LATIN SMALL LETTER Z */
1893 { 0x007B, 0x7B }, /* LEFT CURLY BRACKET */
1894 { 0x007C, 0x7C }, /* VERTICAL LINE */
1895 { 0x007D, 0x7D }, /* RIGHT CURLY BRACKET */
1896 { 0x007E, 0x7E }, /* TILDE */
1897 { 0x00A0, 0xCA }, /* NO-BREAK SPACE */
1898 { 0x00A1, 0xC1 }, /* INVERTED EXCLAMATION MARK */
1899 { 0x00A2, 0xA2 }, /* CENT SIGN */
1900 { 0x00A3, 0xA3 }, /* POUND SIGN */
1901 { 0x00A5, 0xB4 }, /* YEN SIGN */
1902 { 0x00A7, 0xA4 }, /* SECTION SIGN */
1903 { 0x00A8, 0xAC }, /* DIAERESIS */
1904 { 0x00A9, 0xA9 }, /* COPYRIGHT SIGN */
1905 { 0x00AA, 0xBB }, /* FEMININE ORDINAL INDICATOR */
1906 { 0x00AB, 0xC7 }, /* LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */
1907 { 0x00AC, 0xC2 }, /* NOT SIGN */
1908 { 0x00AE, 0xA8 }, /* REGISTERED SIGN */
1909 { 0x00AF, 0xF8 }, /* MACRON */
1910 { 0x00B0, 0xA1 }, /* DEGREE SIGN */
1911 { 0x00B1, 0xB1 }, /* PLUS-MINUS SIGN */
1912 { 0x00B4, 0xAB }, /* ACUTE ACCENT */
1913 { 0x00B5, 0xB5 }, /* MICRO SIGN */
1914 { 0x00B6, 0xA6 }, /* PILCROW SIGN */
1915 { 0x00B7, 0xE1 }, /* MIDDLE DOT */
1916 { 0x00B8, 0xFC }, /* CEDILLA */
1917 { 0x00BA, 0xBC }, /* MASCULINE ORDINAL INDICATOR */
1918 { 0x00BB, 0xC8 }, /* RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */
1919 { 0x00BF, 0xC0 }, /* INVERTED QUESTION MARK */
1920 { 0x00C0, 0xCB }, /* LATIN CAPITAL LETTER A WITH GRAVE */
1921 { 0x00C1, 0xE7 }, /* LATIN CAPITAL LETTER A WITH ACUTE */
1922 { 0x00C2, 0xE5 }, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX */
1923 { 0x00C3, 0xCC }, /* LATIN CAPITAL LETTER A WITH TILDE */
1924 { 0x00C4, 0x80 }, /* LATIN CAPITAL LETTER A WITH DIAERESIS */
1925 { 0x00C5, 0x81 }, /* LATIN CAPITAL LETTER A WITH RING ABOVE */
1926 { 0x00C6, 0xAE }, /* LATIN CAPITAL LETTER AE */
1927 { 0x00C7, 0x82 }, /* LATIN CAPITAL LETTER C WITH CEDILLA */
1928 { 0x00C8, 0xE9 }, /* LATIN CAPITAL LETTER E WITH GRAVE */
1929 { 0x00C9, 0x83 }, /* LATIN CAPITAL LETTER E WITH ACUTE */
1930 { 0x00CA, 0xE6 }, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
1931 { 0x00CB, 0xE8 }, /* LATIN CAPITAL LETTER E WITH DIAERESIS */
1932 { 0x00CC, 0xED }, /* LATIN CAPITAL LETTER I WITH GRAVE */
1933 { 0x00CD, 0xEA }, /* LATIN CAPITAL LETTER I WITH ACUTE */
1934 { 0x00CE, 0xEB }, /* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */
1935 { 0x00CF, 0xEC }, /* LATIN CAPITAL LETTER I WITH DIAERESIS */
1936 { 0x00D1, 0x84 }, /* LATIN CAPITAL LETTER N WITH TILDE */
1937 { 0x00D2, 0xF1 }, /* LATIN CAPITAL LETTER O WITH GRAVE */
1938 { 0x00D3, 0xEE }, /* LATIN CAPITAL LETTER O WITH ACUTE */
1939 { 0x00D4, 0xEF }, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX */
1940 { 0x00D5, 0xCD }, /* LATIN CAPITAL LETTER O WITH TILDE */
1941 { 0x00D6, 0x85 }, /* LATIN CAPITAL LETTER O WITH DIAERESIS */
1942 { 0x00D8, 0xAF }, /* LATIN CAPITAL LETTER O WITH STROKE */
1943 { 0x00D9, 0xF4 }, /* LATIN CAPITAL LETTER U WITH GRAVE */
1944 { 0x00DA, 0xF2 }, /* LATIN CAPITAL LETTER U WITH ACUTE */
1945 { 0x00DB, 0xF3 }, /* LATIN CAPITAL LETTER U WITH CIRCUMFLEX */
1946 { 0x00DC, 0x86 }, /* LATIN CAPITAL LETTER U WITH DIAERESIS */
1947 { 0x00DF, 0xA7 }, /* LATIN SMALL LETTER SHARP S */
1948 { 0x00E0, 0x88 }, /* LATIN SMALL LETTER A WITH GRAVE */
1949 { 0x00E1, 0x87 }, /* LATIN SMALL LETTER A WITH ACUTE */
1950 { 0x00E2, 0x89 }, /* LATIN SMALL LETTER A WITH CIRCUMFLEX */
1951 { 0x00E3, 0x8B }, /* LATIN SMALL LETTER A WITH TILDE */
1952 { 0x00E4, 0x8A }, /* LATIN SMALL LETTER A WITH DIAERESIS */
1953 { 0x00E5, 0x8C }, /* LATIN SMALL LETTER A WITH RING ABOVE */
1954 { 0x00E6, 0xBE }, /* LATIN SMALL LETTER AE */
1955 { 0x00E7, 0x8D }, /* LATIN SMALL LETTER C WITH CEDILLA */
1956 { 0x00E8, 0x8F }, /* LATIN SMALL LETTER E WITH GRAVE */
1957 { 0x00E9, 0x8E }, /* LATIN SMALL LETTER E WITH ACUTE */
1958 { 0x00EA, 0x90 }, /* LATIN SMALL LETTER E WITH CIRCUMFLEX */
1959 { 0x00EB, 0x91 }, /* LATIN SMALL LETTER E WITH DIAERESIS */
1960 { 0x00EC, 0x93 }, /* LATIN SMALL LETTER I WITH GRAVE */
1961 { 0x00ED, 0x92 }, /* LATIN SMALL LETTER I WITH ACUTE */
1962 { 0x00EE, 0x94 }, /* LATIN SMALL LETTER I WITH CIRCUMFLEX */
1963 { 0x00EF, 0x95 }, /* LATIN SMALL LETTER I WITH DIAERESIS */
1964 { 0x00F1, 0x96 }, /* LATIN SMALL LETTER N WITH TILDE */
1965 { 0x00F2, 0x98 }, /* LATIN SMALL LETTER O WITH GRAVE */
1966 { 0x00F3, 0x97 }, /* LATIN SMALL LETTER O WITH ACUTE */
1967 { 0x00F4, 0x99 }, /* LATIN SMALL LETTER O WITH CIRCUMFLEX */
1968 { 0x00F5, 0x9B }, /* LATIN SMALL LETTER O WITH TILDE */
1969 { 0x00F6, 0x9A }, /* LATIN SMALL LETTER O WITH DIAERESIS */
1970 { 0x00F7, 0xD6 }, /* DIVISION SIGN */
1971 { 0x00F8, 0xBF }, /* LATIN SMALL LETTER O WITH STROKE */
1972 { 0x00F9, 0x9D }, /* LATIN SMALL LETTER U WITH GRAVE */
1973 { 0x00FA, 0x9C }, /* LATIN SMALL LETTER U WITH ACUTE */
1974 { 0x00FB, 0x9E }, /* LATIN SMALL LETTER U WITH CIRCUMFLEX */
1975 { 0x00FC, 0x9F }, /* LATIN SMALL LETTER U WITH DIAERESIS */
1976 { 0x00FF, 0xD8 }, /* LATIN SMALL LETTER Y WITH DIAERESIS */
1977 { 0x0131, 0xF5 }, /* LATIN SMALL LETTER DOTLESS I */
1978 { 0x0152, 0xCE }, /* LATIN CAPITAL LIGATURE OE */
1979 { 0x0153, 0xCF }, /* LATIN SMALL LIGATURE OE */
1980 { 0x0178, 0xD9 }, /* LATIN CAPITAL LETTER Y WITH DIAERESIS */
1981 { 0x0192, 0xC4 }, /* LATIN SMALL LETTER F WITH HOOK */
1982 { 0x02C6, 0xF6 }, /* MODIFIER LETTER CIRCUMFLEX ACCENT */
1983 { 0x02C7, 0xFF }, /* CARON */
1984 { 0x02D8, 0xF9 }, /* BREVE */
1985 { 0x02D9, 0xFA }, /* DOT ABOVE */
1986 { 0x02DA, 0xFB }, /* RING ABOVE */
1987 { 0x02DB, 0xFE }, /* OGONEK */
1988 { 0x02DC, 0xF7 }, /* SMALL TILDE */
1989 { 0x02DD, 0xFD }, /* DOUBLE ACUTE ACCENT */
1990 { 0x03A9, 0xBD }, /* GREEK CAPITAL LETTER OMEGA */
1991 { 0x03C0, 0xB9 }, /* GREEK SMALL LETTER PI */
1992 { 0x2013, 0xD0 }, /* EN DASH */
1993 { 0x2014, 0xD1 }, /* EM DASH */
1994 { 0x2018, 0xD4 }, /* LEFT SINGLE QUOTATION MARK */
1995 { 0x2019, 0xD5 }, /* RIGHT SINGLE QUOTATION MARK */
1996 { 0x201A, 0xE2 }, /* SINGLE LOW-9 QUOTATION MARK */
1997 { 0x201C, 0xD2 }, /* LEFT DOUBLE QUOTATION MARK */
1998 { 0x201D, 0xD3 }, /* RIGHT DOUBLE QUOTATION MARK */
1999 { 0x201E, 0xE3 }, /* DOUBLE LOW-9 QUOTATION MARK */
2000 { 0x2020, 0xA0 }, /* DAGGER */
2001 { 0x2021, 0xE0 }, /* DOUBLE DAGGER */
2002 { 0x2022, 0xA5 }, /* BULLET */
2003 { 0x2026, 0xC9 }, /* HORIZONTAL ELLIPSIS */
2004 { 0x2030, 0xE4 }, /* PER MILLE SIGN */
2005 { 0x2039, 0xDC }, /* SINGLE LEFT-POINTING ANGLE QUOTATION MARK */
2006 { 0x203A, 0xDD }, /* SINGLE RIGHT-POINTING ANGLE QUOTATION MARK */
2007 { 0x2044, 0xDA }, /* FRACTION SLASH */
2008 { 0x20AC, 0xDB }, /* EURO SIGN */
2009 { 0x2122, 0xAA }, /* TRADE MARK SIGN */
2010 { 0x2202, 0xB6 }, /* PARTIAL DIFFERENTIAL */
2011 { 0x2206, 0xC6 }, /* INCREMENT */
2012 { 0x220F, 0xB8 }, /* N-ARY PRODUCT */
2013 { 0x2211, 0xB7 }, /* N-ARY SUMMATION */
2014 { 0x221A, 0xC3 }, /* SQUARE ROOT */
2015 { 0x221E, 0xB0 }, /* INFINITY */
2016 { 0x222B, 0xBA }, /* INTEGRAL */
2017 { 0x2248, 0xC5 }, /* ALMOST EQUAL TO */
2018 { 0x2260, 0xAD }, /* NOT EQUAL TO */
2019 { 0x2264, 0xB2 }, /* LESS-THAN OR EQUAL TO */
2020 { 0x2265, 0xB3 }, /* GREATER-THAN OR EQUAL TO */
2021 { 0x25CA, 0xD7 }, /* LOZENGE */
2022 { 0xF8FF, 0xF0 }, /* Apple logo */
2023 { 0xFB01, 0xDE }, /* LATIN SMALL LIGATURE FI */
2024 { 0xFB02, 0xDF }, /* LATIN SMALL LIGATURE FL */
2025};
2026
2027static const FcCharMap AppleRoman = {
2028 AppleRomanEnt,
2029 sizeof (AppleRomanEnt) / sizeof (AppleRomanEnt[0])
2030};
2031
2032static const FcCharEnt AdobeSymbolEnt[] = {
2033 { 0x0020, 0x20 }, /* SPACE # space */
2034 { 0x0021, 0x21 }, /* EXCLAMATION MARK # exclam */
2035 { 0x0023, 0x23 }, /* NUMBER SIGN # numbersign */
2036 { 0x0025, 0x25 }, /* PERCENT SIGN # percent */
2037 { 0x0026, 0x26 }, /* AMPERSAND # ampersand */
2038 { 0x0028, 0x28 }, /* LEFT PARENTHESIS # parenleft */
2039 { 0x0029, 0x29 }, /* RIGHT PARENTHESIS # parenright */
2040 { 0x002B, 0x2B }, /* PLUS SIGN # plus */
2041 { 0x002C, 0x2C }, /* COMMA # comma */
2042 { 0x002E, 0x2E }, /* FULL STOP # period */
2043 { 0x002F, 0x2F }, /* SOLIDUS # slash */
2044 { 0x0030, 0x30 }, /* DIGIT ZERO # zero */
2045 { 0x0031, 0x31 }, /* DIGIT ONE # one */
2046 { 0x0032, 0x32 }, /* DIGIT TWO # two */
2047 { 0x0033, 0x33 }, /* DIGIT THREE # three */
2048 { 0x0034, 0x34 }, /* DIGIT FOUR # four */
2049 { 0x0035, 0x35 }, /* DIGIT FIVE # five */
2050 { 0x0036, 0x36 }, /* DIGIT SIX # six */
2051 { 0x0037, 0x37 }, /* DIGIT SEVEN # seven */
2052 { 0x0038, 0x38 }, /* DIGIT EIGHT # eight */
2053 { 0x0039, 0x39 }, /* DIGIT NINE # nine */
2054 { 0x003A, 0x3A }, /* COLON # colon */
2055 { 0x003B, 0x3B }, /* SEMICOLON # semicolon */
2056 { 0x003C, 0x3C }, /* LESS-THAN SIGN # less */
2057 { 0x003D, 0x3D }, /* EQUALS SIGN # equal */
2058 { 0x003E, 0x3E }, /* GREATER-THAN SIGN # greater */
2059 { 0x003F, 0x3F }, /* QUESTION MARK # question */
2060 { 0x005B, 0x5B }, /* LEFT SQUARE BRACKET # bracketleft */
2061 { 0x005D, 0x5D }, /* RIGHT SQUARE BRACKET # bracketright */
2062 { 0x005F, 0x5F }, /* LOW LINE # underscore */
2063 { 0x007B, 0x7B }, /* LEFT CURLY BRACKET # braceleft */
2064 { 0x007C, 0x7C }, /* VERTICAL LINE # bar */
2065 { 0x007D, 0x7D }, /* RIGHT CURLY BRACKET # braceright */
2066 { 0x00A0, 0x20 }, /* NO-BREAK SPACE # space */
2067 { 0x00AC, 0xD8 }, /* NOT SIGN # logicalnot */
2068 { 0x00B0, 0xB0 }, /* DEGREE SIGN # degree */
2069 { 0x00B1, 0xB1 }, /* PLUS-MINUS SIGN # plusminus */
2070 { 0x00B5, 0x6D }, /* MICRO SIGN # mu */
2071 { 0x00D7, 0xB4 }, /* MULTIPLICATION SIGN # multiply */
2072 { 0x00F7, 0xB8 }, /* DIVISION SIGN # divide */
2073 { 0x0192, 0xA6 }, /* LATIN SMALL LETTER F WITH HOOK # florin */
2074 { 0x0391, 0x41 }, /* GREEK CAPITAL LETTER ALPHA # Alpha */
2075 { 0x0392, 0x42 }, /* GREEK CAPITAL LETTER BETA # Beta */
2076 { 0x0393, 0x47 }, /* GREEK CAPITAL LETTER GAMMA # Gamma */
2077 { 0x0394, 0x44 }, /* GREEK CAPITAL LETTER DELTA # Delta */
2078 { 0x0395, 0x45 }, /* GREEK CAPITAL LETTER EPSILON # Epsilon */
2079 { 0x0396, 0x5A }, /* GREEK CAPITAL LETTER ZETA # Zeta */
2080 { 0x0397, 0x48 }, /* GREEK CAPITAL LETTER ETA # Eta */
2081 { 0x0398, 0x51 }, /* GREEK CAPITAL LETTER THETA # Theta */
2082 { 0x0399, 0x49 }, /* GREEK CAPITAL LETTER IOTA # Iota */
2083 { 0x039A, 0x4B }, /* GREEK CAPITAL LETTER KAPPA # Kappa */
2084 { 0x039B, 0x4C }, /* GREEK CAPITAL LETTER LAMDA # Lambda */
2085 { 0x039C, 0x4D }, /* GREEK CAPITAL LETTER MU # Mu */
2086 { 0x039D, 0x4E }, /* GREEK CAPITAL LETTER NU # Nu */
2087 { 0x039E, 0x58 }, /* GREEK CAPITAL LETTER XI # Xi */
2088 { 0x039F, 0x4F }, /* GREEK CAPITAL LETTER OMICRON # Omicron */
2089 { 0x03A0, 0x50 }, /* GREEK CAPITAL LETTER PI # Pi */
2090 { 0x03A1, 0x52 }, /* GREEK CAPITAL LETTER RHO # Rho */
2091 { 0x03A3, 0x53 }, /* GREEK CAPITAL LETTER SIGMA # Sigma */
2092 { 0x03A4, 0x54 }, /* GREEK CAPITAL LETTER TAU # Tau */
2093 { 0x03A5, 0x55 }, /* GREEK CAPITAL LETTER UPSILON # Upsilon */
2094 { 0x03A6, 0x46 }, /* GREEK CAPITAL LETTER PHI # Phi */
2095 { 0x03A7, 0x43 }, /* GREEK CAPITAL LETTER CHI # Chi */
2096 { 0x03A8, 0x59 }, /* GREEK CAPITAL LETTER PSI # Psi */
2097 { 0x03A9, 0x57 }, /* GREEK CAPITAL LETTER OMEGA # Omega */
2098 { 0x03B1, 0x61 }, /* GREEK SMALL LETTER ALPHA # alpha */
2099 { 0x03B2, 0x62 }, /* GREEK SMALL LETTER BETA # beta */
2100 { 0x03B3, 0x67 }, /* GREEK SMALL LETTER GAMMA # gamma */
2101 { 0x03B4, 0x64 }, /* GREEK SMALL LETTER DELTA # delta */
2102 { 0x03B5, 0x65 }, /* GREEK SMALL LETTER EPSILON # epsilon */
2103 { 0x03B6, 0x7A }, /* GREEK SMALL LETTER ZETA # zeta */
2104 { 0x03B7, 0x68 }, /* GREEK SMALL LETTER ETA # eta */
2105 { 0x03B8, 0x71 }, /* GREEK SMALL LETTER THETA # theta */
2106 { 0x03B9, 0x69 }, /* GREEK SMALL LETTER IOTA # iota */
2107 { 0x03BA, 0x6B }, /* GREEK SMALL LETTER KAPPA # kappa */
2108 { 0x03BB, 0x6C }, /* GREEK SMALL LETTER LAMDA # lambda */
2109 { 0x03BC, 0x6D }, /* GREEK SMALL LETTER MU # mu */
2110 { 0x03BD, 0x6E }, /* GREEK SMALL LETTER NU # nu */
2111 { 0x03BE, 0x78 }, /* GREEK SMALL LETTER XI # xi */
2112 { 0x03BF, 0x6F }, /* GREEK SMALL LETTER OMICRON # omicron */
2113 { 0x03C0, 0x70 }, /* GREEK SMALL LETTER PI # pi */
2114 { 0x03C1, 0x72 }, /* GREEK SMALL LETTER RHO # rho */
2115 { 0x03C2, 0x56 }, /* GREEK SMALL LETTER FINAL SIGMA # sigma1 */
2116 { 0x03C3, 0x73 }, /* GREEK SMALL LETTER SIGMA # sigma */
2117 { 0x03C4, 0x74 }, /* GREEK SMALL LETTER TAU # tau */
2118 { 0x03C5, 0x75 }, /* GREEK SMALL LETTER UPSILON # upsilon */
2119 { 0x03C6, 0x66 }, /* GREEK SMALL LETTER PHI # phi */
2120 { 0x03C7, 0x63 }, /* GREEK SMALL LETTER CHI # chi */
2121 { 0x03C8, 0x79 }, /* GREEK SMALL LETTER PSI # psi */
2122 { 0x03C9, 0x77 }, /* GREEK SMALL LETTER OMEGA # omega */
2123 { 0x03D1, 0x4A }, /* GREEK THETA SYMBOL # theta1 */
2124 { 0x03D2, 0xA1 }, /* GREEK UPSILON WITH HOOK SYMBOL # Upsilon1 */
2125 { 0x03D5, 0x6A }, /* GREEK PHI SYMBOL # phi1 */
2126 { 0x03D6, 0x76 }, /* GREEK PI SYMBOL # omega1 */
2127 { 0x2022, 0xB7 }, /* BULLET # bullet */
2128 { 0x2026, 0xBC }, /* HORIZONTAL ELLIPSIS # ellipsis */
2129 { 0x2032, 0xA2 }, /* PRIME # minute */
2130 { 0x2033, 0xB2 }, /* DOUBLE PRIME # second */
2131 { 0x2044, 0xA4 }, /* FRACTION SLASH # fraction */
2132 { 0x20AC, 0xA0 }, /* EURO SIGN # Euro */
2133 { 0x2111, 0xC1 }, /* BLACK-LETTER CAPITAL I # Ifraktur */
2134 { 0x2118, 0xC3 }, /* SCRIPT CAPITAL P # weierstrass */
2135 { 0x211C, 0xC2 }, /* BLACK-LETTER CAPITAL R # Rfraktur */
2136 { 0x2126, 0x57 }, /* OHM SIGN # Omega */
2137 { 0x2135, 0xC0 }, /* ALEF SYMBOL # aleph */
2138 { 0x2190, 0xAC }, /* LEFTWARDS ARROW # arrowleft */
2139 { 0x2191, 0xAD }, /* UPWARDS ARROW # arrowup */
2140 { 0x2192, 0xAE }, /* RIGHTWARDS ARROW # arrowright */
2141 { 0x2193, 0xAF }, /* DOWNWARDS ARROW # arrowdown */
2142 { 0x2194, 0xAB }, /* LEFT RIGHT ARROW # arrowboth */
2143 { 0x21B5, 0xBF }, /* DOWNWARDS ARROW WITH CORNER LEFTWARDS # carriagereturn */
2144 { 0x21D0, 0xDC }, /* LEFTWARDS DOUBLE ARROW # arrowdblleft */
2145 { 0x21D1, 0xDD }, /* UPWARDS DOUBLE ARROW # arrowdblup */
2146 { 0x21D2, 0xDE }, /* RIGHTWARDS DOUBLE ARROW # arrowdblright */
2147 { 0x21D3, 0xDF }, /* DOWNWARDS DOUBLE ARROW # arrowdbldown */
2148 { 0x21D4, 0xDB }, /* LEFT RIGHT DOUBLE ARROW # arrowdblboth */
2149 { 0x2200, 0x22 }, /* FOR ALL # universal */
2150 { 0x2202, 0xB6 }, /* PARTIAL DIFFERENTIAL # partialdiff */
2151 { 0x2203, 0x24 }, /* THERE EXISTS # existential */
2152 { 0x2205, 0xC6 }, /* EMPTY SET # emptyset */
2153 { 0x2206, 0x44 }, /* INCREMENT # Delta */
2154 { 0x2207, 0xD1 }, /* NABLA # gradient */
2155 { 0x2208, 0xCE }, /* ELEMENT OF # element */
2156 { 0x2209, 0xCF }, /* NOT AN ELEMENT OF # notelement */
2157 { 0x220B, 0x27 }, /* CONTAINS AS MEMBER # suchthat */
2158 { 0x220F, 0xD5 }, /* N-ARY PRODUCT # product */
2159 { 0x2211, 0xE5 }, /* N-ARY SUMMATION # summation */
2160 { 0x2212, 0x2D }, /* MINUS SIGN # minus */
2161 { 0x2215, 0xA4 }, /* DIVISION SLASH # fraction */
2162 { 0x2217, 0x2A }, /* ASTERISK OPERATOR # asteriskmath */
2163 { 0x221A, 0xD6 }, /* SQUARE ROOT # radical */
2164 { 0x221D, 0xB5 }, /* PROPORTIONAL TO # proportional */
2165 { 0x221E, 0xA5 }, /* INFINITY # infinity */
2166 { 0x2220, 0xD0 }, /* ANGLE # angle */
2167 { 0x2227, 0xD9 }, /* LOGICAL AND # logicaland */
2168 { 0x2228, 0xDA }, /* LOGICAL OR # logicalor */
2169 { 0x2229, 0xC7 }, /* INTERSECTION # intersection */
2170 { 0x222A, 0xC8 }, /* UNION # union */
2171 { 0x222B, 0xF2 }, /* INTEGRAL # integral */
2172 { 0x2234, 0x5C }, /* THEREFORE # therefore */
2173 { 0x223C, 0x7E }, /* TILDE OPERATOR # similar */
2174 { 0x2245, 0x40 }, /* APPROXIMATELY EQUAL TO # congruent */
2175 { 0x2248, 0xBB }, /* ALMOST EQUAL TO # approxequal */
2176 { 0x2260, 0xB9 }, /* NOT EQUAL TO # notequal */
2177 { 0x2261, 0xBA }, /* IDENTICAL TO # equivalence */
2178 { 0x2264, 0xA3 }, /* LESS-THAN OR EQUAL TO # lessequal */
2179 { 0x2265, 0xB3 }, /* GREATER-THAN OR EQUAL TO # greaterequal */
2180 { 0x2282, 0xCC }, /* SUBSET OF # propersubset */
2181 { 0x2283, 0xC9 }, /* SUPERSET OF # propersuperset */
2182 { 0x2284, 0xCB }, /* NOT A SUBSET OF # notsubset */
2183 { 0x2286, 0xCD }, /* SUBSET OF OR EQUAL TO # reflexsubset */
2184 { 0x2287, 0xCA }, /* SUPERSET OF OR EQUAL TO # reflexsuperset */
2185 { 0x2295, 0xC5 }, /* CIRCLED PLUS # circleplus */
2186 { 0x2297, 0xC4 }, /* CIRCLED TIMES # circlemultiply */
2187 { 0x22A5, 0x5E }, /* UP TACK # perpendicular */
2188 { 0x22C5, 0xD7 }, /* DOT OPERATOR # dotmath */
2189 { 0x2320, 0xF3 }, /* TOP HALF INTEGRAL # integraltp */
2190 { 0x2321, 0xF5 }, /* BOTTOM HALF INTEGRAL # integralbt */
2191 { 0x2329, 0xE1 }, /* LEFT-POINTING ANGLE BRACKET # angleleft */
2192 { 0x232A, 0xF1 }, /* RIGHT-POINTING ANGLE BRACKET # angleright */
2193 { 0x25CA, 0xE0 }, /* LOZENGE # lozenge */
2194 { 0x2660, 0xAA }, /* BLACK SPADE SUIT # spade */
2195 { 0x2663, 0xA7 }, /* BLACK CLUB SUIT # club */
2196 { 0x2665, 0xA9 }, /* BLACK HEART SUIT # heart */
2197 { 0x2666, 0xA8 }, /* BLACK DIAMOND SUIT # diamond */
2198 { 0xF6D9, 0xD3 }, /* COPYRIGHT SIGN SERIF # copyrightserif (CUS) */
2199 { 0xF6DA, 0xD2 }, /* REGISTERED SIGN SERIF # registerserif (CUS) */
2200 { 0xF6DB, 0xD4 }, /* TRADE MARK SIGN SERIF # trademarkserif (CUS) */
2201 { 0xF8E5, 0x60 }, /* RADICAL EXTENDER # radicalex (CUS) */
2202 { 0xF8E6, 0xBD }, /* VERTICAL ARROW EXTENDER # arrowvertex (CUS) */
2203 { 0xF8E7, 0xBE }, /* HORIZONTAL ARROW EXTENDER # arrowhorizex (CUS) */
2204 { 0xF8E8, 0xE2 }, /* REGISTERED SIGN SANS SERIF # registersans (CUS) */
2205 { 0xF8E9, 0xE3 }, /* COPYRIGHT SIGN SANS SERIF # copyrightsans (CUS) */
2206 { 0xF8EA, 0xE4 }, /* TRADE MARK SIGN SANS SERIF # trademarksans (CUS) */
2207 { 0xF8EB, 0xE6 }, /* LEFT PAREN TOP # parenlefttp (CUS) */
2208 { 0xF8EC, 0xE7 }, /* LEFT PAREN EXTENDER # parenleftex (CUS) */
2209 { 0xF8ED, 0xE8 }, /* LEFT PAREN BOTTOM # parenleftbt (CUS) */
2210 { 0xF8EE, 0xE9 }, /* LEFT SQUARE BRACKET TOP # bracketlefttp (CUS) */
2211 { 0xF8EF, 0xEA }, /* LEFT SQUARE BRACKET EXTENDER # bracketleftex (CUS) */
2212 { 0xF8F0, 0xEB }, /* LEFT SQUARE BRACKET BOTTOM # bracketleftbt (CUS) */
2213 { 0xF8F1, 0xEC }, /* LEFT CURLY BRACKET TOP # bracelefttp (CUS) */
2214 { 0xF8F2, 0xED }, /* LEFT CURLY BRACKET MID # braceleftmid (CUS) */
2215 { 0xF8F3, 0xEE }, /* LEFT CURLY BRACKET BOTTOM # braceleftbt (CUS) */
2216 { 0xF8F4, 0xEF }, /* CURLY BRACKET EXTENDER # braceex (CUS) */
2217 { 0xF8F5, 0xF4 }, /* INTEGRAL EXTENDER # integralex (CUS) */
2218 { 0xF8F6, 0xF6 }, /* RIGHT PAREN TOP # parenrighttp (CUS) */
2219 { 0xF8F7, 0xF7 }, /* RIGHT PAREN EXTENDER # parenrightex (CUS) */
2220 { 0xF8F8, 0xF8 }, /* RIGHT PAREN BOTTOM # parenrightbt (CUS) */
2221 { 0xF8F9, 0xF9 }, /* RIGHT SQUARE BRACKET TOP # bracketrighttp (CUS) */
2222 { 0xF8FA, 0xFA }, /* RIGHT SQUARE BRACKET EXTENDER # bracketrightex (CUS) */
2223 { 0xF8FB, 0xFB }, /* RIGHT SQUARE BRACKET BOTTOM # bracketrightbt (CUS) */
2224 { 0xF8FC, 0xFC }, /* RIGHT CURLY BRACKET TOP # bracerighttp (CUS) */
2225 { 0xF8FD, 0xFD }, /* RIGHT CURLY BRACKET MID # bracerightmid (CUS) */
2226 { 0xF8FE, 0xFE }, /* RIGHT CURLY BRACKET BOTTOM # bracerightbt (CUS) */
2227};
2228
2229static const FcCharMap AdobeSymbol = {
2230 AdobeSymbolEnt,
2231 sizeof (AdobeSymbolEnt) / sizeof (AdobeSymbolEnt[0]),
2232};
2233
2234static const FcFontDecode fcFontDecoders[] = {
2235 { ft_encoding_unicode, 0, (1 << 21) - 1 },
2236 { ft_encoding_symbol, &AdobeSymbol, (1 << 16) - 1 },
2237 { ft_encoding_apple_roman, &AppleRoman, (1 << 16) - 1 },
2238};
2239
67accef4 2240#define NUM_DECODE (int) (sizeof (fcFontDecoders) / sizeof (fcFontDecoders[0]))
c647f6f1 2241
716ac8b8
KP
2242static const FcChar32 prefer_unicode[] = {
2243 0x20ac, /* EURO SIGN */
2244};
2245
67accef4 2246#define NUM_PREFER_UNICODE (int) (sizeof (prefer_unicode) / sizeof (prefer_unicode[0]))
716ac8b8 2247
c647f6f1
KP
2248FcChar32
2249FcFreeTypeUcs4ToPrivate (FcChar32 ucs4, const FcCharMap *map)
2250{
2251 int low, high, mid;
2252 FcChar16 bmp;
2253
2254 low = 0;
2255 high = map->nent - 1;
2256 if (ucs4 < map->ent[low].bmp || map->ent[high].bmp < ucs4)
2257 return ~0;
2258 while (low <= high)
2259 {
2260 mid = (high + low) >> 1;
2261 bmp = map->ent[mid].bmp;
2262 if (ucs4 == bmp)
2263 return (FT_ULong) map->ent[mid].encode;
2264 if (ucs4 < bmp)
2265 high = mid - 1;
2266 else
2267 low = mid + 1;
2268 }
2269 return ~0;
2270}
2271
2272FcChar32
2273FcFreeTypePrivateToUcs4 (FcChar32 private, const FcCharMap *map)
2274{
2275 int i;
2276
2277 for (i = 0; i < map->nent; i++)
2278 if (map->ent[i].encode == private)
2279 return (FcChar32) map->ent[i].bmp;
2280 return ~0;
2281}
2282
2283const FcCharMap *
2284FcFreeTypeGetPrivateMap (FT_Encoding encoding)
2285{
2286 int i;
2287
2288 for (i = 0; i < NUM_DECODE; i++)
2289 if (fcFontDecoders[i].encoding == encoding)
2290 return fcFontDecoders[i].map;
2291 return 0;
2292}
2293
7769c321
KP
2294#include "../fc-glyphname/fcglyphname.h"
2295
2296static FcChar32
2297FcHashGlyphName (const FcChar8 *name)
2298{
2299 FcChar32 h = 0;
2300 FcChar8 c;
2301
2302 while ((c = *name++))
2303 {
2304 h = ((h << 1) | (h >> 31)) ^ c;
2305 }
2306 return h;
2307}
2308
656c69d6 2309#if HAVE_FT_HAS_PS_GLYPH_NAMES
7769c321
KP
2310/*
2311 * Use Type1 glyph names for fonts which have reliable names
2312 * and which export an Adobe Custom mapping
2313 */
2314static FcBool
2315FcFreeTypeUseNames (FT_Face face)
2316{
2317 FT_Int map;
2318
2319 if (!FT_Has_PS_Glyph_Names (face))
2320 return FcFalse;
2321 for (map = 0; map < face->num_charmaps; map++)
d47c9d6e 2322 if (face->charmaps[map]->encoding == ft_encoding_adobe_custom)
7769c321
KP
2323 return FcTrue;
2324 return FcFalse;
2325}
2326
573da729 2327static const FcChar8 *
7769c321
KP
2328FcUcs4ToGlyphName (FcChar32 ucs4)
2329{
2330 int i = (int) (ucs4 % FC_GLYPHNAME_HASH);
2331 int r = 0;
96925b99 2332 FcGlyphId gn;
7769c321 2333
96925b99 2334 while ((gn = ucs_to_name[i]) != -1)
7769c321 2335 {
96925b99
KP
2336 if (glyphs[gn].ucs == ucs4)
2337 return glyphs[gn].name;
7769c321
KP
2338 if (!r)
2339 {
2340 r = (int) (ucs4 % FC_GLYPHNAME_REHASH);
2341 if (!r)
2342 r = 1;
2343 }
2344 i += r;
2345 if (i >= FC_GLYPHNAME_HASH)
2346 i -= FC_GLYPHNAME_HASH;
2347 }
2348 return 0;
2349}
2350
2351static FcChar32
2352FcGlyphNameToUcs4 (FcChar8 *name)
2353{
2354 FcChar32 h = FcHashGlyphName (name);
2355 int i = (int) (h % FC_GLYPHNAME_HASH);
2356 int r = 0;
96925b99 2357 FcGlyphId gn;
7769c321 2358
96925b99 2359 while ((gn = name_to_ucs[i]) != -1)
7769c321 2360 {
96925b99
KP
2361 if (!strcmp ((char *) name, (char *) glyphs[gn].name))
2362 return glyphs[gn].ucs;
7769c321
KP
2363 if (!r)
2364 {
2365 r = (int) (h % FC_GLYPHNAME_REHASH);
2366 if (!r)
2367 r = 1;
2368 }
2369 i += r;
2370 if (i >= FC_GLYPHNAME_HASH)
2371 i -= FC_GLYPHNAME_HASH;
2372 }
2373 return 0xffff;
2374}
2375
c80a08d6
KP
2376/*
2377 * Work around a bug in some FreeType versions which fail
2378 * to correctly bounds check glyph name buffers and overwrite
2379 * the stack. As Postscript names have a limit of 127 characters,
2380 * this should be sufficient.
2381 */
2382
2383#if FC_GLYPHNAME_MAXLEN < 127
2384# define FC_GLYPHNAME_BUFLEN 127
2385#else
2386# define FC_GLYPHNAME_BUFLEN FC_GLYPHNAME_MAXLEN
2387#endif
2388
7769c321
KP
2389/*
2390 * Search through a font for a glyph by name. This is
2391 * currently a linear search as there doesn't appear to be
2392 * any defined order within the font
2393 */
2394static FT_UInt
573da729 2395FcFreeTypeGlyphNameIndex (FT_Face face, const FcChar8 *name)
7769c321
KP
2396{
2397 FT_UInt gindex;
c80a08d6 2398 FcChar8 name_buf[FC_GLYPHNAME_BUFLEN + 2];
7769c321 2399
67accef4 2400 for (gindex = 0; gindex < (FT_UInt) face->num_glyphs; gindex++)
7769c321 2401 {
c80a08d6 2402 if (FT_Get_Glyph_Name (face, gindex, name_buf, FC_GLYPHNAME_BUFLEN+1) == 0)
7769c321
KP
2403 if (!strcmp ((char *) name, (char *) name_buf))
2404 return gindex;
2405 }
2406 return 0;
2407}
656c69d6 2408#endif
7769c321 2409
c647f6f1
KP
2410/*
2411 * Map a UCS4 glyph to a glyph index. Use all available encoding
2412 * tables to try and find one that works. This information is expected
2413 * to be cached by higher levels, so performance isn't critical
2414 */
2415
2416FT_UInt
2417FcFreeTypeCharIndex (FT_Face face, FcChar32 ucs4)
2418{
2419 int initial, offset, decode;
2420 FT_UInt glyphindex;
2421 FcChar32 charcode;
716ac8b8 2422 int p;
c647f6f1
KP
2423
2424 initial = 0;
656b47f6
PL
2425
2426 if (!face)
2427 return 0;
2428
c647f6f1
KP
2429 /*
2430 * Find the current encoding
2431 */
2432 if (face->charmap)
2433 {
2434 for (; initial < NUM_DECODE; initial++)
2435 if (fcFontDecoders[initial].encoding == face->charmap->encoding)
2436 break;
2437 if (initial == NUM_DECODE)
2438 initial = 0;
2439 }
716ac8b8
KP
2440 for (p = 0; p < NUM_PREFER_UNICODE; p++)
2441 if (ucs4 == prefer_unicode[p])
2442 {
2443 initial = 0;
2444 break;
2445 }
c647f6f1
KP
2446 /*
2447 * Check each encoding for the glyph, starting with the current one
2448 */
2449 for (offset = 0; offset < NUM_DECODE; offset++)
2450 {
2451 decode = (initial + offset) % NUM_DECODE;
2452 if (!face->charmap || face->charmap->encoding != fcFontDecoders[decode].encoding)
2453 if (FT_Select_Charmap (face, fcFontDecoders[decode].encoding) != 0)
2454 continue;
2455 if (fcFontDecoders[decode].map)
2456 {
2457 charcode = FcFreeTypeUcs4ToPrivate (ucs4, fcFontDecoders[decode].map);
67accef4 2458 if (charcode == ~0U)
c647f6f1
KP
2459 continue;
2460 }
2461 else
2462 charcode = ucs4;
2463 glyphindex = FT_Get_Char_Index (face, (FT_ULong) charcode);
2464 if (glyphindex)
2465 return glyphindex;
2466 }
656c69d6 2467#if HAVE_FT_HAS_PS_GLYPH_NAMES
7769c321
KP
2468 /*
2469 * Check postscript name table if present
2470 */
2471 if (FcFreeTypeUseNames (face))
2472 {
573da729 2473 const FcChar8 *name = FcUcs4ToGlyphName (ucs4);
7769c321
KP
2474 if (name)
2475 {
2476 glyphindex = FcFreeTypeGlyphNameIndex (face, name);
2477 if (glyphindex)
2478 return glyphindex;
2479 }
2480 }
656c69d6 2481#endif
c647f6f1
KP
2482 return 0;
2483}
2484
2485static FcBool
2486FcFreeTypeCheckGlyph (FT_Face face, FcChar32 ucs4,
848d32bd
KP
2487 FT_UInt glyph, FcBlanks *blanks,
2488 FT_Pos *advance)
c647f6f1 2489{
0b7a0da2 2490 FT_Int load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH | FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
c647f6f1
KP
2491 FT_GlyphSlot slot;
2492
2493 /*
2494 * When using scalable fonts, only report those glyphs
2495 * which can be scaled; otherwise those fonts will
2496 * only be available at some sizes, and never when
2497 * transformed. Avoid this by simply reporting bitmap-only
2498 * glyphs as missing
2499 */
2500 if (face->face_flags & FT_FACE_FLAG_SCALABLE)
2501 load_flags |= FT_LOAD_NO_BITMAP;
2502
2503 if (FT_Load_Glyph (face, glyph, load_flags))
2504 return FcFalse;
2505
2506 slot = face->glyph;
2507 if (!glyph)
2508 return FcFalse;
2509
848d32bd
KP
2510 *advance = slot->metrics.horiAdvance;
2511
c647f6f1
KP
2512 switch (slot->format) {
2513 case ft_glyph_format_bitmap:
2514 /*
2515 * Bitmaps are assumed to be reasonable; if
2516 * this proves to be a rash assumption, this
2517 * code can be easily modified
2518 */
2519 return FcTrue;
2520 case ft_glyph_format_outline:
2521 /*
2522 * Glyphs with contours are always OK
2523 */
2524 if (slot->outline.n_contours != 0)
2525 return FcTrue;
2526 /*
2527 * Glyphs with no contours are only OK if
2528 * they're members of the Blanks set specified
2529 * in the configuration. If blanks isn't set,
2530 * then allow any glyph to be blank
2531 */
2532 if (!blanks || FcBlanksIsMember (blanks, ucs4))
2533 return FcTrue;
2534 /* fall through ... */
2535 default:
2536 break;
2537 }
2538 return FcFalse;
2539}
2540
55a69bd0
KP
2541#define FC_MIN(a,b) ((a) < (b) ? (a) : (b))
2542#define FC_MAX(a,b) ((a) > (b) ? (a) : (b))
2543#define FC_ABS(a) ((a) < 0 ? -(a) : (a))
2544#define APPROXIMATELY_EQUAL(x,y) (FC_ABS ((x) - (y)) <= FC_MAX (FC_ABS (x), FC_ABS (y)) / 33)
a05d257f 2545
c647f6f1 2546FcCharSet *
848d32bd 2547FcFreeTypeCharSetAndSpacing (FT_Face face, FcBlanks *blanks, int *spacing)
c647f6f1 2548{
b023dbd3 2549 FcChar32 page, off, ucs4;
c647f6f1
KP
2550#ifdef CHECK
2551 FcChar32 font_max = 0;
2552#endif
2553 FcCharSet *fcs;
2554 FcCharLeaf *leaf;
2555 const FcCharMap *map;
2556 int o;
2557 int i;
2558 FT_UInt glyph;
a05d257f
NL
2559 FT_Pos advance, advance_one = 0, advance_two = 0;
2560 FcBool has_advance = FcFalse, fixed_advance = FcTrue, dual_advance = FcFalse;
c647f6f1
KP
2561
2562 fcs = FcCharSetCreate ();
2563 if (!fcs)
2564 goto bail0;
2565
7769c321
KP
2566#ifdef CHECK
2567 printf ("Family %s style %s\n", face->family_name, face->style_name);
2568#endif
c647f6f1
KP
2569 for (o = 0; o < NUM_DECODE; o++)
2570 {
2571 if (FT_Select_Charmap (face, fcFontDecoders[o].encoding) != 0)
2572 continue;
2573 map = fcFontDecoders[o].map;
2574 if (map)
2575 {
2576 /*
2577 * Non-Unicode tables are easy; there's a list of all possible
2578 * characters
2579 */
2580 for (i = 0; i < map->nent; i++)
2581 {
2582 ucs4 = map->ent[i].bmp;
2583 glyph = FT_Get_Char_Index (face, map->ent[i].encode);
848d32bd
KP
2584 if (glyph &&
2585 FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance))
c647f6f1 2586 {
8245771d
PL
2587 /*
2588 * ignore glyphs with zero advance. They’re
2589 * combining characters, and while their behaviour
2590 * isn’t well defined for monospaced applications in
2591 * Unicode, there are many fonts which include
2592 * zero-width combining characters in otherwise
2593 * monospaced fonts.
2594 */
2595 if (advance)
848d32bd 2596 {
8245771d
PL
2597 if (!has_advance)
2598 {
2599 has_advance = FcTrue;
2600 advance_one = advance;
2601 }
2602 else if (!APPROXIMATELY_EQUAL (advance, advance_one))
2603 {
2604 if (fixed_advance)
2605 {
2606 dual_advance = FcTrue;
2607 fixed_advance = FcFalse;
2608 advance_two = advance;
2609 }
2610 else if (!APPROXIMATELY_EQUAL (advance, advance_two))
2611 dual_advance = FcFalse;
2612 }
848d32bd 2613 }
a05d257f 2614
c647f6f1
KP
2615 leaf = FcCharSetFindLeafCreate (fcs, ucs4);
2616 if (!leaf)
2617 goto bail1;
2618 leaf->map[(ucs4 & 0xff) >> 5] |= (1 << (ucs4 & 0x1f));
2619#ifdef CHECK
2620 if (ucs4 > font_max)
2621 font_max = ucs4;
2622#endif
2623 }
2624 }
2625 }
2626 else
2627 {
31e0f032
DT
2628 page = ~0;
2629 leaf = NULL;
2630 ucs4 = FT_Get_First_Char (face, &glyph);
2631 while (glyph != 0)
c647f6f1 2632 {
31e0f032 2633 if (FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance))
c647f6f1 2634 {
31e0f032 2635 if (advance)
c647f6f1 2636 {
31e0f032 2637 if (!has_advance)
848d32bd 2638 {
31e0f032
DT
2639 has_advance = FcTrue;
2640 advance_one = advance;
2641 }
2642 else if (!APPROXIMATELY_EQUAL (advance, advance_one))
2643 {
2644 if (fixed_advance)
8245771d 2645 {
31e0f032
DT
2646 dual_advance = FcTrue;
2647 fixed_advance = FcFalse;
2648 advance_two = advance;
8245771d 2649 }
31e0f032
DT
2650 else if (!APPROXIMATELY_EQUAL (advance, advance_two))
2651 dual_advance = FcFalse;
848d32bd 2652 }
31e0f032 2653 }
a05d257f 2654
31e0f032
DT
2655 if ((ucs4 >> 8) != page)
2656 {
2657 page = (ucs4 >> 8);
2658 leaf = FcCharSetFindLeafCreate (fcs, ucs4);
c647f6f1 2659 if (!leaf)
31e0f032
DT
2660 goto bail1;
2661 }
2662 off = ucs4 & 0xff;
2663 leaf->map[off >> 5] |= (1 << (off & 0x1f));
c647f6f1 2664#ifdef CHECK
31e0f032
DT
2665 if (ucs4 > font_max)
2666 font_max = ucs4;
c647f6f1 2667#endif
c647f6f1 2668 }
31e0f032 2669 ucs4 = FT_Get_Next_Char (face, ucs4, &glyph);
c647f6f1
KP
2670 }
2671#ifdef CHECK
2672 for (ucs4 = 0; ucs4 < 0x10000; ucs4++)
2673 {
2674 FcBool FT_Has, FC_Has;
2675
2676 FT_Has = FT_Get_Char_Index (face, ucs4) != 0;
2677 FC_Has = FcCharSetHasChar (fcs, ucs4);
2678 if (FT_Has != FC_Has)
2679 {
2680 printf ("0x%08x FT says %d FC says %d\n", ucs4, FT_Has, FC_Has);
2681 }
2682 }
2683#endif
2684 }
2685 }
656c69d6 2686#if HAVE_FT_HAS_PS_GLYPH_NAMES
7769c321
KP
2687 /*
2688 * Add mapping from PS glyph names if available
2689 */
2690 if (FcFreeTypeUseNames (face))
2691 {
c80a08d6 2692 FcChar8 name_buf[FC_GLYPHNAME_BUFLEN + 2];
7769c321 2693
67accef4 2694 for (glyph = 0; glyph < (FT_UInt) face->num_glyphs; glyph++)
7769c321 2695 {
c80a08d6 2696 if (FT_Get_Glyph_Name (face, glyph, name_buf, FC_GLYPHNAME_BUFLEN+1) == 0)
7769c321
KP
2697 {
2698 ucs4 = FcGlyphNameToUcs4 (name_buf);
2699 if (ucs4 != 0xffff &&
2700 FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance))
2701 {
8245771d 2702 if (advance)
7769c321 2703 {
8245771d
PL
2704 if (!has_advance)
2705 {
2706 has_advance = FcTrue;
2707 advance_one = advance;
2708 }
2709 else if (!APPROXIMATELY_EQUAL (advance, advance_one))
2710 {
2711 if (fixed_advance)
2712 {
2713 dual_advance = FcTrue;
2714 fixed_advance = FcFalse;
2715 advance_two = advance;
2716 }
2717 else if (!APPROXIMATELY_EQUAL (advance, advance_two))
2718 dual_advance = FcFalse;
2719 }
7769c321 2720 }
7769c321
KP
2721 leaf = FcCharSetFindLeafCreate (fcs, ucs4);
2722 if (!leaf)
2723 goto bail1;
2724 leaf->map[(ucs4 & 0xff) >> 5] |= (1 << (ucs4 & 0x1f));
2725#ifdef CHECK
2726 if (ucs4 > font_max)
2727 font_max = ucs4;
2728#endif
2729 }
2730 }
2731 }
2732 }
656c69d6 2733#endif
c647f6f1
KP
2734#ifdef CHECK
2735 printf ("%d glyphs %d encoded\n", (int) face->num_glyphs, FcCharSetCount (fcs));
2736 for (ucs4 = 0; ucs4 <= font_max; ucs4++)
2737 {
7769c321 2738 FcBool has_char = (glyph = FcFreeTypeCharIndex (face, ucs4)) != 0;
c647f6f1
KP
2739 FcBool has_bit = FcCharSetHasChar (fcs, ucs4);
2740
2741 if (has_char && !has_bit)
7769c321
KP
2742 {
2743 if (!FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance))
2744 printf ("Bitmap missing broken char 0x%x\n", ucs4);
2745 else
2746 printf ("Bitmap missing char 0x%x\n", ucs4);
2747 }
c647f6f1
KP
2748 else if (!has_char && has_bit)
2749 printf ("Bitmap extra char 0x%x\n", ucs4);
2750 }
2751#endif
848d32bd
KP
2752 if (fixed_advance)
2753 *spacing = FC_MONO;
55a69bd0 2754 else if (dual_advance && APPROXIMATELY_EQUAL (2 * FC_MIN (advance_one, advance_two), FC_MAX (advance_one, advance_two)))
a05d257f 2755 *spacing = FC_DUAL;
848d32bd
KP
2756 else
2757 *spacing = FC_PROPORTIONAL;
c647f6f1
KP
2758 return fcs;
2759bail1:
2760 FcCharSetDestroy (fcs);
2761bail0:
2762 return 0;
2763}
2764
848d32bd
KP
2765FcCharSet *
2766FcFreeTypeCharSet (FT_Face face, FcBlanks *blanks)
2767{
2768 int spacing;
2769
2770 return FcFreeTypeCharSetAndSpacing (face, blanks, &spacing);
2771}
dbf68dd5
KP
2772
2773
2774#define TTAG_GPOS FT_MAKE_TAG( 'G', 'P', 'O', 'S' )
2775#define TTAG_GSUB FT_MAKE_TAG( 'G', 'S', 'U', 'B' )
2776#define TTAG_SILF FT_MAKE_TAG( 'S', 'i', 'l', 'f')
2777#define TT_Err_Ok FT_Err_Ok
2778#define TT_Err_Invalid_Face_Handle FT_Err_Invalid_Face_Handle
2779#define TTO_Err_Empty_Script 0x1005
2780#define TTO_Err_Invalid_SubTable 0x1001
2781
219f7818
KP
2782#define OTLAYOUT_HEAD "otlayout:"
2783#define OTLAYOUT_HEAD_LEN 9
2784#define OTLAYOUT_ID_LEN 4
2785/* space + head + id */
2786#define OTLAYOUT_LEN (1 + OTLAYOUT_HEAD_LEN + OTLAYOUT_ID_LEN)
2787
76a8dfa3
KP
2788/*
2789 * This is a bit generous; the registry has only lower case and space
2790 * except for 'DFLT'.
2791 */
2792#define FcIsSpace(x) (040 == (x))
2793#define FcIsValidScript(x) (FcIsLower(x) || FcIsUpper (x) || FcIsSpace(x))
2794
dbf68dd5
KP
2795static void
2796addtag(FcChar8 *complex, FT_ULong tag)
2797{
219f7818
KP
2798 FcChar8 tagstring[OTLAYOUT_ID_LEN + 1];
2799
2800 tagstring[0] = (FcChar8)(tag >> 24),
2801 tagstring[1] = (FcChar8)(tag >> 16),
2802 tagstring[2] = (FcChar8)(tag >> 8),
2803 tagstring[3] = (FcChar8)(tag);
2804 tagstring[4] = '\0';
2805
76a8dfa3 2806 /* skip tags which aren't alphabetic, under the assumption that
219f7818
KP
2807 * they're probably broken
2808 */
76a8dfa3
KP
2809 if (!FcIsValidScript(tagstring[0]) ||
2810 !FcIsValidScript(tagstring[1]) ||
2811 !FcIsValidScript(tagstring[2]) ||
2812 !FcIsValidScript(tagstring[3]))
219f7818
KP
2813 return;
2814
2815 if (*complex != '\0')
8245771d
PL
2816 strcat ((char *) complex, " ");
2817 strcat ((char *) complex, "otlayout:");
2818 strcat ((char *) complex, (char *) tagstring);
dbf68dd5
KP
2819}
2820
2821static int
2822compareulong (const void *a, const void *b)
2823{
2824 const FT_ULong *ua = (const FT_ULong *) a;
2825 const FT_ULong *ub = (const FT_ULong *) b;
2826 return *ua - *ub;
2827}
2828
2829
2830static FT_Error
2831GetScriptTags(FT_Face face, FT_ULong tabletag, FT_ULong **stags, FT_UShort *script_count)
2832{
2833 FT_ULong cur_offset, new_offset, base_offset;
dbf68dd5
KP
2834 FT_Stream stream = face->stream;
2835 FT_Error error;
2836 FT_UShort n, p;
04f7d3e7 2837 FT_Memory memory;
dbf68dd5
KP
2838
2839 if ( !stream )
2840 return TT_Err_Invalid_Face_Handle;
2841
04f7d3e7
PL
2842 memory = stream->memory;
2843
8ebf7725 2844 if (( error = ftglue_face_goto_table( face, tabletag, stream ) ))
dbf68dd5
KP
2845 return error;
2846
8ebf7725 2847 base_offset = ftglue_stream_pos ( stream );
dbf68dd5
KP
2848
2849 /* skip version */
2850
8ebf7725 2851 if ( ftglue_stream_seek ( stream, base_offset + 4L ) || ftglue_stream_frame_enter( stream, 2L ) )
dbf68dd5
KP
2852 return error;
2853
d8951c0c 2854 new_offset = GET_UShort() + base_offset;
dbf68dd5 2855
8ebf7725 2856 ftglue_stream_frame_exit( stream );
dbf68dd5 2857
8ebf7725 2858 cur_offset = ftglue_stream_pos( stream );
dbf68dd5 2859
8ebf7725 2860 if ( ftglue_stream_seek( stream, new_offset ) != TT_Err_Ok )
dbf68dd5
KP
2861 return error;
2862
8ebf7725 2863 base_offset = ftglue_stream_pos( stream );
dbf68dd5 2864
8ebf7725 2865 if ( ftglue_stream_frame_enter( stream, 2L ) )
dbf68dd5
KP
2866 return error;
2867
d8951c0c 2868 *script_count = GET_UShort ();
8ebf7725
PL
2869
2870 ftglue_stream_frame_exit( stream );
dbf68dd5 2871
8ebf7725 2872 *stags = ftglue_alloc(memory, *script_count * sizeof( FT_ULong ), &error);
dbf68dd5 2873
8ebf7725 2874 if (error)
dbf68dd5
KP
2875 return error;
2876
2877 p = 0;
2878 for ( n = 0; n < *script_count; n++ )
2879 {
8ebf7725 2880 if ( ftglue_stream_frame_enter( stream, 6L ) )
dbf68dd5
KP
2881 goto Fail;
2882
d8951c0c
PL
2883 (*stags)[p] = GET_ULong ();
2884 new_offset = GET_UShort () + base_offset;
dbf68dd5 2885
8ebf7725 2886 ftglue_stream_frame_exit( stream );
dbf68dd5 2887
8ebf7725 2888 cur_offset = ftglue_stream_pos( stream );
dbf68dd5 2889
2f02e383 2890 error = ftglue_stream_seek( stream, new_offset );
dbf68dd5
KP
2891
2892 if ( error == TT_Err_Ok )
2893 p++;
dbf68dd5 2894
8ebf7725 2895 (void)ftglue_stream_seek( stream, cur_offset );
dbf68dd5
KP
2896 }
2897
2898 if (!p)
2899 {
2900 error = TTO_Err_Invalid_SubTable;
2901 goto Fail;
2902 }
2903
bb6b1993 2904 /* sort the tag list before returning it */
dbf68dd5
KP
2905 qsort(*stags, *script_count, sizeof(FT_ULong), compareulong);
2906
2907 return TT_Err_Ok;
2908
2909Fail:
219f7818 2910 *script_count = 0;
8ebf7725 2911 ftglue_free( memory, *stags );
0cfaf27e 2912 *stags = NULL;
dbf68dd5
KP
2913 return error;
2914}
2915
2916static FcChar8 *
2917FcFontCapabilities(FT_Face face)
2918{
2919 FcBool issilgraphitefont = 0;
2920 FT_Error err;
2921 FT_ULong len = 0;
2922 FT_ULong *gsubtags=NULL, *gpostags=NULL;
219f7818
KP
2923 FT_UShort gsub_count=0, gpos_count=0;
2924 FT_ULong maxsize;
dbf68dd5
KP
2925 FT_Memory memory = face->stream->memory;
2926 FcChar8 *complex = NULL;
2927 int indx1 = 0, indx2 = 0;
2928
2929 err = FT_Load_Sfnt_Table(face, TTAG_SILF, 0, 0, &len);
2930 issilgraphitefont = ( err == FT_Err_Ok);
2931
219f7818
KP
2932 if (GetScriptTags(face, TTAG_GPOS, &gpostags, &gpos_count) != FT_Err_Ok)
2933 gpos_count = 0;
2934 if (GetScriptTags(face, TTAG_GSUB, &gsubtags, &gsub_count) != FT_Err_Ok)
2935 gsub_count = 0;
2936
dbf68dd5 2937 if (!issilgraphitefont && !gsub_count && !gpos_count)
dbf68dd5 2938 goto bail;
dbf68dd5 2939
219f7818
KP
2940 maxsize = (((FT_ULong) gpos_count + (FT_ULong) gsub_count) * OTLAYOUT_LEN +
2941 (issilgraphitefont ? 13 : 0));
dbf68dd5 2942 complex = malloc (sizeof (FcChar8) * maxsize);
219f7818
KP
2943 if (!complex)
2944 goto bail;
2945
2946 complex[0] = '\0';
dbf68dd5 2947 if (issilgraphitefont)
8245771d 2948 strcpy((char *) complex, "ttable:Silf ");
dbf68dd5
KP
2949
2950 while ((indx1 < gsub_count) || (indx2 < gpos_count)) {
2951 if (indx1 == gsub_count) {
2952 addtag(complex, gpostags[indx2]);
2953 indx2++;
2954 } else if ((indx2 == gpos_count) || (gsubtags[indx1] < gpostags[indx2])) {
2955 addtag(complex, gsubtags[indx1]);
2956 indx1++;
2957 } else if (gsubtags[indx1] == gpostags[indx2]) {
2958 addtag(complex, gsubtags[indx1]);
2959 indx1++;
2960 indx2++;
2961 } else {
2962 addtag(complex, gpostags[indx2]);
2963 indx2++;
2964 }
2965 }
2966 if (FcDebug () & FC_DBG_SCANV)
2967 printf("complex features in this font: %s\n", complex);
2968bail:
8ebf7725
PL
2969 ftglue_free(memory, gsubtags);
2970 ftglue_free(memory, gpostags);
dbf68dd5
KP
2971 return complex;
2972}
23816bf9
KP
2973
2974#define __fcfreetype__
2975#include "fcaliastail.h"
2976#undef __fcfreetype__