Add walloon, update fclang.c to include recent language additions
[platform/upstream/fontconfig.git] / src / fcfreetype.c
1 /*
2  * $XFree86: xc/lib/fontconfig/src/fcfreetype.c,v 1.5 2002/06/29 20:31:02 keithp Exp $
3  *
4  * Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc.
5  *
6  * Permission to use, copy, modify, distribute, and sell this software and its
7  * documentation for any purpose is hereby granted without fee, provided that
8  * the above copyright notice appear in all copies and that both that
9  * copyright notice and this permission notice appear in supporting
10  * documentation, and that the name of Keith Packard not be used in
11  * advertising or publicity pertaining to distribution of the software without
12  * specific, written prior permission.  Keith Packard makes no
13  * representations about the suitability of this software for any purpose.  It
14  * is provided "as is" without express or implied warranty.
15  *
16  * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18  * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22  * PERFORMANCE OF THIS SOFTWARE.
23  */
24
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include "fcint.h"
29 #include <freetype/freetype.h>
30 #include <freetype/internal/ftobjs.h>
31 #include <freetype/tttables.h>
32
33 static const FcChar8    *fcLangLatin1[] = {
34     (FcChar8 *) "br",   /* Breton */
35     (FcChar8 *) "ca",   /* Catalan */
36     (FcChar8 *) "da",   /* Danish */
37     (FcChar8 *) "de",   /* German */
38     (FcChar8 *) "en",   /* English */
39     (FcChar8 *) "es",   /* Spanish */
40     (FcChar8 *) "eu",   /* Basque */
41     (FcChar8 *) "fi",   /* Finnish */
42     (FcChar8 *) "fo",   /* Faroese */
43     (FcChar8 *) "fr",   /* French */
44     (FcChar8 *) "ga",   /* Irish */
45     (FcChar8 *) "gd",   /* Scottish */
46     (FcChar8 *) "gl",   /* Galician */
47     (FcChar8 *) "is",   /* Islandic */
48     (FcChar8 *) "it",   /* Italian */
49     (FcChar8 *) "kl",   /* Greenlandic */
50     (FcChar8 *) "la",   /* Latin */
51     (FcChar8 *) "nl",   /* Dutch */
52     (FcChar8 *) "no",   /* Norwegian */
53     (FcChar8 *) "pt",   /* Portuguese */
54     (FcChar8 *) "rm",   /* Rhaeto-Romanic */
55     (FcChar8 *) "sq",   /* Albanian */
56     (FcChar8 *) "sv",   /* Swedish */
57     0
58 };
59
60 static const FcChar8    *fcLangLatin2[] = {
61     (FcChar8 *) "cs",   /* Czech */
62     (FcChar8 *) "de",   /* German */
63     (FcChar8 *) "en",   /* English */
64     (FcChar8 *) "fi",   /* Finnish */
65     (FcChar8 *) "hr",   /* Croatian */
66     (FcChar8 *) "hu",   /* Hungarian */
67     (FcChar8 *) "la",   /* Latin */
68     (FcChar8 *) "pl",   /* Polish */
69     (FcChar8 *) "ro",   /* Romanian */
70     (FcChar8 *) "sk",   /* Slovak */
71     (FcChar8 *) "sl",   /* Slovenian */
72     (FcChar8 *) "sq",   /* Albanian */
73     0
74 };
75
76 static const FcChar8    *fcLangCyrillic[] = {
77     (FcChar8 *) "az",   /* Azerbaijani */
78     (FcChar8 *) "ba",   /* Bashkir */
79     (FcChar8 *) "bg",   /* Bulgarian */
80     (FcChar8 *) "be",   /* Byelorussian */
81     (FcChar8 *) "kk",   /* Kazakh */
82     (FcChar8 *) "ky",   /* Kirghiz */
83     (FcChar8 *) "mk",   /* Macedonian */
84     (FcChar8 *) "mo",   /* Moldavian */
85     (FcChar8 *) "mn",   /* Mongolian */
86     (FcChar8 *) "ru",   /* Russian */
87     (FcChar8 *) "sr",   /* Serbian */
88     (FcChar8 *) "tg",   /* Tadzhik */
89     (FcChar8 *) "tt",   /* Tatar */
90     (FcChar8 *) "tk",   /* Turkmen */
91     (FcChar8 *) "uz",   /* Uzbek */
92     (FcChar8 *) "uk",   /* Ukrainian */
93     0,
94 };
95
96 static const FcChar8    *fcLangGreek[] = {
97     (FcChar8 *) "el",   /* Greek */
98     0
99 };
100
101 static const FcChar8    *fcLangTurkish[] = {
102     (FcChar8 *) "tr",   /* Turkish */
103     0
104 };
105
106 static const FcChar8    *fcLangHebrew[] = {
107     (FcChar8 *) "he",   /* Hebrew */
108     (FcChar8 *) "yi",   /* Yiddish */
109     0
110 };
111
112 static const FcChar8    *fcLangArabic[] = {
113     (FcChar8 *) "ar",   /* arabic */
114     0
115 };
116
117 static const FcChar8    *fcLangWindowsBaltic[] = {
118     (FcChar8 *) "da",   /* Danish */
119     (FcChar8 *) "de",   /* German */
120     (FcChar8 *) "en",   /* English */
121     (FcChar8 *) "et",   /* Estonian */
122     (FcChar8 *) "fi",   /* Finnish */
123     (FcChar8 *) "la",   /* Latin */
124     (FcChar8 *) "lt",   /* Lithuanian */
125     (FcChar8 *) "lv",   /* Latvian */
126     (FcChar8 *) "no",   /* Norwegian */
127     (FcChar8 *) "pl",   /* Polish */
128     (FcChar8 *) "sl",   /* Slovenian */
129     (FcChar8 *) "sv",   /* Swedish */
130     0
131 };
132
133 static const FcChar8    *fcLangVietnamese[] = {
134     (FcChar8 *) "vi",   /* Vietnamese */
135     0,
136 };
137
138 static const FcChar8    *fcLangThai[] = {
139     (FcChar8 *) "th",   /* Thai */
140     0,
141 };
142
143 static const FcChar8    *fcLangJapanese[] = {
144     (FcChar8 *) "ja",   /* Japanese */
145     0,
146 };
147
148 static const FcChar8    *fcLangSimplifiedChinese[] = {
149     (FcChar8 *) "zh-cn",    /* Chinese-China */
150     0,
151 };
152
153 static const FcChar8    *fcLangKorean[] = {
154     (FcChar8 *) "ko",   /* Korean */
155     0,
156 };
157
158 static const FcChar8    *fcLangTraditionalChinese[] = {
159     (FcChar8 *) "zh-tw",    /* Chinese-Taiwan */
160     0,
161 };
162
163 static const FcChar8    *fcLangEnglish[] = {
164     (FcChar8 *) "en",   /* English */
165     0,
166 };
167
168 /*
169  * Elide some of the less useful bits
170  */
171 static const struct {
172     int             bit;
173     const FcChar8   **lang;
174 } FcCodePageRange[] = {
175     { 0,        fcLangLatin1 },
176     { 1,        fcLangLatin2 },
177     { 2,        fcLangCyrillic },
178     { 3,        fcLangGreek },
179     { 4,        fcLangTurkish },
180     { 5,        fcLangHebrew },
181     { 6,        fcLangArabic },
182     { 7,        fcLangWindowsBaltic },
183     { 8,        fcLangVietnamese },
184 /* 9-15 reserved for Alternate ANSI */
185     { 16,       fcLangThai },
186     { 17,       fcLangJapanese },
187     { 18,       fcLangSimplifiedChinese },
188     { 19,       fcLangKorean },
189     { 20,       fcLangTraditionalChinese },
190     { 21,       fcLangKorean },
191 /* 22-28 reserved for Alternate ANSI & OEM */
192 /*    { 29,     fcLangMacintosh }, */
193 /*    { 30,     fcLangOem }, */
194 /*     { 31,    fcLangSymbol },*/
195 /* 32-47 reserved for OEM */
196     { 48,       fcLangGreek },
197     { 49,       fcLangCyrillic },
198 /*    { 50,     fcLangMsdosNordic }, */
199     { 51,       fcLangArabic },
200 /*    { 52,     fcLangMSDOS_CANADIAN_FRENCH }, */
201     { 53,       fcLangHebrew },
202 /*    { 54,     fcLangMSDOS_ICELANDIC }, */
203 /*    { 55,     fcLangMSDOS_PORTUGUESE }, */
204     { 56,       fcLangTurkish },
205     { 57,       fcLangCyrillic },
206     { 58,       fcLangLatin2 },
207     { 59,       fcLangWindowsBaltic },
208     { 60,       fcLangGreek },
209     { 61,       fcLangArabic },
210     { 62,       fcLangLatin1 },
211     { 63,       fcLangEnglish },
212 };
213
214 #define NUM_CODE_PAGE_RANGE (sizeof FcCodePageRange / sizeof FcCodePageRange[0])
215
216 FcBool
217 FcFreeTypeHasLang (FcPattern *pattern, const FcChar8 *lang)
218 {
219     FcChar8     *old;
220     int         i;
221
222     for (i = 0; FcPatternGetString (pattern, FC_LANG, i, &old) == FcResultMatch; i++)
223         if (!FcStrCmp (lang, old))
224             return FcTrue;
225     return FcFalse;
226 }
227
228 FcPattern *
229 FcFreeTypeQuery (const FcChar8  *file,
230                  int            id,
231                  FcBlanks       *blanks,
232                  int            *count)
233 {
234     FT_Face         face;
235     FcPattern       *pat;
236     int             slant;
237     int             weight;
238     int             i;
239     FcCharSet       *cs;
240     FT_Library      ftLibrary;
241     const FcChar8   *family;
242     TT_OS2          *os2;
243     FcChar32        codepoints;
244     FcChar8         *lang;
245     FcBool          hasLang = FcFalse;
246     
247
248     if (FT_Init_FreeType (&ftLibrary))
249         return 0;
250     
251     if (FT_New_Face (ftLibrary, (char *) file, id, &face))
252         goto bail;
253
254     *count = face->num_faces;
255
256     pat = FcPatternCreate ();
257     if (!pat)
258         goto bail0;
259
260     if (!FcPatternAddBool (pat, FC_OUTLINE,
261                            (face->face_flags & FT_FACE_FLAG_SCALABLE) != 0))
262         goto bail1;
263
264     if (!FcPatternAddBool (pat, FC_SCALABLE,
265                            (face->face_flags & FT_FACE_FLAG_SCALABLE) != 0))
266         goto bail1;
267
268
269     slant = FC_SLANT_ROMAN;
270     if (face->style_flags & FT_STYLE_FLAG_ITALIC)
271         slant = FC_SLANT_ITALIC;
272
273     if (!FcPatternAddInteger (pat, FC_SLANT, slant))
274         goto bail1;
275
276     weight = FC_WEIGHT_MEDIUM;
277     if (face->style_flags & FT_STYLE_FLAG_BOLD)
278         weight = FC_WEIGHT_BOLD;
279
280     if (!FcPatternAddInteger (pat, FC_WEIGHT, weight))
281         goto bail1;
282
283     family = (FcChar8 *) face->family_name;
284     if (!family)
285     {
286         family = (FcChar8 *) strrchr ((char *) file, '/');
287         if (family)
288             family++;
289         else
290             family = file;
291     }
292     if (!FcPatternAddString (pat, FC_FAMILY, family))
293         goto bail1;
294
295     if (face->style_name)
296     {
297         if (!FcPatternAddString (pat, FC_STYLE, (FcChar8 *) face->style_name))
298             goto bail1;
299     }
300
301     if (!FcPatternAddString (pat, FC_FILE, file))
302         goto bail1;
303
304     if (!FcPatternAddInteger (pat, FC_INDEX, id))
305         goto bail1;
306
307     if (!FcPatternAddString (pat, FC_SOURCE, (FcChar8 *) "FreeType"))
308         goto bail1;
309
310 #if 1
311     if ((face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) != 0)
312         if (!FcPatternAddInteger (pat, FC_SPACING, FC_MONO))
313             goto bail1;
314 #endif
315
316     /*
317      * Get the OS/2 table and poke about
318      */
319     os2 = (TT_OS2 *) FT_Get_Sfnt_Table (face, ft_sfnt_os2);
320     if (os2 && os2->version >= 0x0001 && os2->version != 0xffff)
321     {
322         for (i = 0; i < NUM_CODE_PAGE_RANGE; i++)
323         {
324             FT_ULong    bits;
325             int         bit;
326             if (FcCodePageRange[i].bit < 32)
327             {
328                 bits = os2->ulCodePageRange1;
329                 bit = FcCodePageRange[i].bit;
330             }
331             else
332             {
333                 bits = os2->ulCodePageRange2;
334                 bit = FcCodePageRange[i].bit - 32;
335             }
336             if (bits & (1 << bit))
337             {
338                 int             j;
339                 const FcChar8   *lang;
340
341                 for (j = 0; (lang = FcCodePageRange[i].lang[j]); j++)
342                     if (!FcFreeTypeHasLang (pat, lang))
343                     {
344                         if (!FcPatternAddString (pat, FC_LANG, lang))
345                             goto bail1;
346                         hasLang = FcTrue;
347                     }
348             }
349         }
350     }
351
352     /*
353      * Compute the unicode coverage for the font
354      */
355     cs = FcFreeTypeCharSet (face, blanks);
356     if (!cs)
357         goto bail1;
358
359     codepoints = FcCharSetCount (cs);
360     /*
361      * Skip over PCF fonts that have no encoded characters; they're
362      * usually just Unicode fonts transcoded to some legacy encoding
363      */
364     if (codepoints == 0)
365     {
366         if (!strcmp(FT_MODULE_CLASS(&face->driver->root)->module_name, "pcf"))
367             goto bail2;
368     }
369
370     if (!FcPatternAddCharSet (pat, FC_CHARSET, cs))
371         goto bail2;
372
373     if (!hasLang)
374     {
375         if (!FcFreeTypeSetLang (pat, cs))
376             goto bail2;
377
378         /*
379          * Make sure it has a lang entry
380          */
381         if (FcPatternGetString (pat, FC_LANG, 0, &lang) != FcResultMatch)
382             if (!FcPatternAddString (pat, FC_LANG, (FcChar8 *) "x-unknown"))
383                 goto bail2;
384     }
385
386     /*
387      * Drop our reference to the charset
388      */
389     FcCharSetDestroy (cs);
390     
391     if (!(face->face_flags & FT_FACE_FLAG_SCALABLE))
392     {
393         for (i = 0; i < face->num_fixed_sizes; i++)
394             if (!FcPatternAddDouble (pat, FC_PIXEL_SIZE,
395                                      (double) face->available_sizes[i].height))
396                 goto bail1;
397         if (!FcPatternAddBool (pat, FC_ANTIALIAS, FcFalse))
398             goto bail1;
399     }
400
401     FT_Done_Face (face);
402     FT_Done_FreeType (ftLibrary);
403     return pat;
404
405 bail2:
406     FcCharSetDestroy (cs);
407 bail1:
408     FcPatternDestroy (pat);
409 bail0:
410     FT_Done_Face (face);
411 bail:
412     FT_Done_FreeType (ftLibrary);
413     return 0;
414 }