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