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