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