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