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