]> git.wh0rd.org - fontconfig.git/blob - src/fcfreetype.c
Memory leak in XML parsing of matrices (thanks Owen)
[fontconfig.git] / src / fcfreetype.c
1 /*
2 * $XFree86: xc/lib/fontconfig/src/fcfreetype.c,v 1.8 2002/07/09 02:28:29 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 #include <freetype/ftsnames.h>
33 #include <freetype/ttnameid.h>
34
35 /*
36 * Keep Han languages separated by eliminating languages
37 * that the codePageRange bits says aren't supported
38 */
39
40 static const struct {
41 int bit;
42 const FcChar8 *lang;
43 } FcCodePageRange[] = {
44 { 17, (const FcChar8 *) "ja" },
45 { 18, (const FcChar8 *) "zh-cn" },
46 { 19, (const FcChar8 *) "ko" },
47 { 20, (const FcChar8 *) "zh-tw" },
48 };
49
50 #define NUM_CODE_PAGE_RANGE (sizeof FcCodePageRange / sizeof FcCodePageRange[0])
51
52 FcBool
53 FcFreeTypeIsExclusiveLang (const FcChar8 *lang)
54 {
55 int i;
56
57 for (i = 0; i < NUM_CODE_PAGE_RANGE; i++)
58 {
59 if (FcLangCompare (lang, FcCodePageRange[i].lang) != FcLangDifferentLang)
60 return FcTrue;
61 }
62 return FcFalse;
63 }
64
65 #define FC_NAME_PRIO_LANG 0x0f00
66 #define FC_NAME_PRIO_LANG_ENGLISH 0x0200
67 #define FC_NAME_PRIO_LANG_LATIN 0x0100
68 #define FC_NAME_PRIO_LANG_NONE 0x0000
69
70 #define FC_NAME_PRIO_ENC 0x00f0
71 #define FC_NAME_PRIO_ENC_UNICODE 0x0010
72 #define FC_NAME_PRIO_ENC_NONE 0x0000
73
74 #define FC_NAME_PRIO_NAME 0x000f
75 #define FC_NAME_PRIO_NAME_FAMILY 0x0002
76 #define FC_NAME_PRIO_NAME_PS 0x0001
77 #define FC_NAME_PRIO_NAME_NONE 0x0000
78
79 static FcBool
80 FcUcs4IsLatin (FcChar32 ucs4)
81 {
82 FcChar32 page = ucs4 >> 8;
83
84 if (page <= 2)
85 return FcTrue;
86 if (page == 0x1e)
87 return FcTrue;
88 if (0x20 <= page && page <= 0x23)
89 return FcTrue;
90 if (page == 0xfb)
91 return FcTrue;
92 if (page == 0xff)
93 return FcTrue;
94 return FcFalse;
95 }
96
97 static FcBool
98 FcUtf8IsLatin (FcChar8 *str, int len)
99 {
100 while (len)
101 {
102 FcChar32 ucs4;
103 int clen = FcUtf8ToUcs4 (str, &ucs4, len);
104 if (clen <= 0)
105 return FcFalse;
106 if (!FcUcs4IsLatin (ucs4))
107 return FcFalse;
108 len -= clen;
109 str += clen;
110 }
111 return FcTrue;
112 }
113
114 FcPattern *
115 FcFreeTypeQuery (const FcChar8 *file,
116 int id,
117 FcBlanks *blanks,
118 int *count)
119 {
120 FT_Face face;
121 FcPattern *pat;
122 int slant;
123 int weight;
124 int i;
125 FcCharSet *cs;
126 FT_Library ftLibrary;
127 FcChar8 *family;
128 FcChar8 *style;
129 TT_OS2 *os2;
130 const FcChar8 *exclusiveLang = 0;
131 FT_SfntName sname;
132 FT_UInt snamei, snamec;
133 FcBool family_allocated = FcFalse;
134 FcBool style_allocated = FcFalse;
135 int family_prio = 0;
136 int style_prio = 0;
137
138 if (FT_Init_FreeType (&ftLibrary))
139 return 0;
140
141 if (FT_New_Face (ftLibrary, (char *) file, id, &face))
142 goto bail;
143
144 *count = face->num_faces;
145
146 pat = FcPatternCreate ();
147 if (!pat)
148 goto bail0;
149
150 if (!FcPatternAddBool (pat, FC_OUTLINE,
151 (face->face_flags & FT_FACE_FLAG_SCALABLE) != 0))
152 goto bail1;
153
154 if (!FcPatternAddBool (pat, FC_SCALABLE,
155 (face->face_flags & FT_FACE_FLAG_SCALABLE) != 0))
156 goto bail1;
157
158
159 slant = FC_SLANT_ROMAN;
160 if (face->style_flags & FT_STYLE_FLAG_ITALIC)
161 slant = FC_SLANT_ITALIC;
162
163 if (!FcPatternAddInteger (pat, FC_SLANT, slant))
164 goto bail1;
165
166 weight = FC_WEIGHT_MEDIUM;
167 if (face->style_flags & FT_STYLE_FLAG_BOLD)
168 weight = FC_WEIGHT_BOLD;
169
170 if (!FcPatternAddInteger (pat, FC_WEIGHT, weight))
171 goto bail1;
172
173 /*
174 * Grub through the name table looking for family
175 * and style names. FreeType makes quite a hash
176 * of them
177 */
178 family = 0;
179 style = 0;
180 snamec = FT_Get_Sfnt_Name_Count (face);
181 for (snamei = 0; snamei < snamec; snamei++)
182 {
183 FcChar8 *utf8;
184 int len;
185 int wchar;
186 FcChar8 *src;
187 int src_len;
188 FcChar8 *u8;
189 FcChar32 ucs4;
190 int ilen, olen;
191 int prio = 0;
192
193 const FcCharMap *map;
194 enum {
195 FcNameEncodingUtf16,
196 FcNameEncodingAppleRoman,
197 FcNameEncodingLatin1
198 } encoding;
199
200
201 if (FT_Get_Sfnt_Name (face, snamei, &sname) != 0)
202 break;
203
204 /*
205 * Look for Unicode strings
206 */
207 switch (sname.platform_id) {
208 case TT_PLATFORM_APPLE_UNICODE:
209 /*
210 * All APPLE_UNICODE encodings are Utf16 BE
211 *
212 * Because there's no language id for Unicode,
213 * assume it's English
214 */
215 prio |= FC_NAME_PRIO_LANG_ENGLISH;
216 prio |= FC_NAME_PRIO_ENC_UNICODE;
217 encoding = FcNameEncodingUtf16;
218 break;
219 case TT_PLATFORM_MACINTOSH:
220 switch (sname.encoding_id) {
221 case TT_MAC_ID_ROMAN:
222 encoding = FcNameEncodingAppleRoman;
223 break;
224 default:
225 continue;
226 }
227 switch (sname.language_id) {
228 case TT_MAC_LANGID_ENGLISH:
229 prio |= FC_NAME_PRIO_LANG_ENGLISH;
230 break;
231 default:
232 /*
233 * Sometimes Microsoft language ids
234 * end up in the macintosh table. This
235 * is often accompanied by data in
236 * some mystic encoding. Ignore these names
237 */
238 if (sname.language_id >= 0x100)
239 continue;
240 break;
241 }
242 break;
243 case TT_PLATFORM_MICROSOFT:
244 switch (sname.encoding_id) {
245 case TT_MS_ID_UNICODE_CS:
246 encoding = FcNameEncodingUtf16;
247 prio |= FC_NAME_PRIO_ENC_UNICODE;
248 break;
249 default:
250 continue;
251 }
252 switch (sname.language_id & 0xff) {
253 case 0x09:
254 prio |= FC_NAME_PRIO_LANG_ENGLISH;
255 break;
256 default:
257 break;
258 }
259 break;
260 case TT_PLATFORM_ISO:
261 switch (sname.encoding_id) {
262 case TT_ISO_ID_10646:
263 encoding = FcNameEncodingUtf16;
264 prio |= FC_NAME_PRIO_ENC_UNICODE;
265 break;
266 case TT_ISO_ID_7BIT_ASCII:
267 case TT_ISO_ID_8859_1:
268 encoding = FcNameEncodingLatin1;
269 break;
270 default:
271 continue;
272 }
273 break;
274 default:
275 continue;
276 }
277
278 /*
279 * Look for family and style names
280 */
281 switch (sname.name_id) {
282 case TT_NAME_ID_FONT_FAMILY:
283 prio |= FC_NAME_PRIO_NAME_FAMILY;
284 break;
285 case TT_NAME_ID_PS_NAME:
286 prio |= FC_NAME_PRIO_NAME_PS;
287 break;
288 case TT_NAME_ID_FONT_SUBFAMILY:
289 break;
290 default:
291 continue;
292 }
293
294 src = (FcChar8 *) sname.string;
295 src_len = sname.string_len;
296
297 switch (encoding) {
298 case FcNameEncodingUtf16:
299 /*
300 * Convert Utf16 to Utf8
301 */
302
303 if (!FcUtf16Len (src, FcEndianBig, src_len, &len, &wchar))
304 continue;
305
306 /*
307 * Allocate plenty of space
308 */
309 utf8 = malloc (len * FC_UTF8_MAX_LEN + 1);
310 if (!utf8)
311 continue;
312
313 u8 = utf8;
314
315 while ((ilen = FcUtf16ToUcs4 (src, FcEndianBig, &ucs4, src_len)) > 0)
316 {
317 src_len -= ilen;
318 src += ilen;
319 olen = FcUcs4ToUtf8 (ucs4, u8);
320 u8 += olen;
321 }
322 *u8 = '\0';
323 break;
324 case FcNameEncodingLatin1:
325 /*
326 * Convert Latin1 to Utf8
327 */
328 utf8 = malloc (src_len * 2 + 1);
329 if (!utf8)
330 continue;
331
332 u8 = utf8;
333 while (src_len > 0)
334 {
335 ucs4 = *src++;
336 src_len--;
337 olen = FcUcs4ToUtf8 (ucs4, u8);
338 u8 += olen;
339 }
340 *u8 = '\0';
341 break;
342 case FcNameEncodingAppleRoman:
343 /*
344 * Convert AppleRoman to Utf8
345 */
346 map = FcFreeTypeGetPrivateMap (ft_encoding_apple_roman);
347 if (!map)
348 continue;
349
350 utf8 = malloc (src_len * 3 + 1);
351 if (!utf8)
352 continue;
353
354 u8 = utf8;
355 while (src_len > 0)
356 {
357 ucs4 = FcFreeTypePrivateToUcs4 (*src++, map);
358 src_len--;
359 olen = FcUcs4ToUtf8 (ucs4, u8);
360 u8 += olen;
361 }
362 *u8 = '\0';
363 break;
364 default:
365 continue;
366 }
367 if ((prio & FC_NAME_PRIO_LANG) == FC_NAME_PRIO_LANG_NONE)
368 if (FcUtf8IsLatin (utf8, strlen ((char *) utf8)))
369 prio |= FC_NAME_PRIO_LANG_LATIN;
370
371 if (FcDebug () & FC_DBG_SCANV)
372 printf ("\nfound name (name %d platform %d encoding %d language 0x%x prio 0x%x) %s\n",
373 sname.name_id, sname.platform_id,
374 sname.encoding_id, sname.language_id,
375 prio, utf8);
376
377 switch (sname.name_id) {
378 case TT_NAME_ID_FONT_FAMILY:
379 case TT_NAME_ID_PS_NAME:
380 if (!family || prio > family_prio)
381 {
382 if (family)
383 free (family);
384 family = utf8;
385 utf8 = 0;
386 family_allocated = FcTrue;
387 family_prio = prio;
388 }
389 break;
390 case TT_NAME_ID_FONT_SUBFAMILY:
391 if (!style || prio > style_prio)
392 {
393 if (style)
394 free (style);
395 style = utf8;
396 utf8 = 0;
397 style_allocated = FcTrue;
398 style_prio = prio;
399 }
400 break;
401 }
402 if (utf8)
403 free (utf8);
404 }
405
406 if (!family)
407 family = (FcChar8 *) face->family_name;
408
409 if (!style)
410 style = (FcChar8 *) face->style_name;
411
412 if (!family)
413 {
414 FcChar8 *start, *end;
415
416 start = (FcChar8 *) strrchr ((char *) file, '/');
417 if (start)
418 start++;
419 else
420 start = (FcChar8 *) file;
421 end = (FcChar8 *) strrchr ((char *) start, '.');
422 if (!end)
423 end = start + strlen ((char *) start);
424 family = malloc (end - start + 1);
425 strncpy ((char *) family, (char *) start, end - start);
426 family[end - start] = '\0';
427 family_allocated = FcTrue;
428 }
429
430 if (FcDebug() & FC_DBG_SCAN)
431 printf ("\"%s\" \"%s\" ", family, style ? style : (FcChar8 *) "<none>");
432
433 if (!FcPatternAddString (pat, FC_FAMILY, family))
434 {
435 if (family_allocated)
436 free (family);
437 if (style_allocated)
438 free (style);
439 goto bail1;
440 }
441
442 if (family_allocated)
443 free (family);
444
445 if (style)
446 {
447 if (!FcPatternAddString (pat, FC_STYLE, style))
448 {
449 if (style_allocated)
450 free (style);
451 goto bail1;
452 }
453 if (style_allocated)
454 free (style);
455 }
456
457 if (!FcPatternAddString (pat, FC_FILE, file))
458 goto bail1;
459
460 if (!FcPatternAddInteger (pat, FC_INDEX, id))
461 goto bail1;
462
463 if (!FcPatternAddString (pat, FC_SOURCE, (FcChar8 *) "FreeType"))
464 goto bail1;
465
466 #if 1
467 if ((face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) != 0)
468 if (!FcPatternAddInteger (pat, FC_SPACING, FC_MONO))
469 goto bail1;
470 #endif
471
472 /*
473 * Get the OS/2 table and poke about
474 */
475 os2 = (TT_OS2 *) FT_Get_Sfnt_Table (face, ft_sfnt_os2);
476 if (os2 && os2->version >= 0x0001 && os2->version != 0xffff)
477 {
478 for (i = 0; i < NUM_CODE_PAGE_RANGE; i++)
479 {
480 FT_ULong bits;
481 int bit;
482 if (FcCodePageRange[i].bit < 32)
483 {
484 bits = os2->ulCodePageRange1;
485 bit = FcCodePageRange[i].bit;
486 }
487 else
488 {
489 bits = os2->ulCodePageRange2;
490 bit = FcCodePageRange[i].bit - 32;
491 }
492 if (bits & (1 << bit))
493 {
494 /*
495 * If the font advertises support for multiple
496 * "exclusive" languages, then include support
497 * for any language found to have coverage
498 */
499 if (exclusiveLang)
500 {
501 exclusiveLang = 0;
502 break;
503 }
504 exclusiveLang = FcCodePageRange[i].lang;
505 }
506 }
507 }
508
509 /*
510 * Compute the unicode coverage for the font
511 */
512 cs = FcFreeTypeCharSet (face, blanks);
513 if (!cs)
514 goto bail1;
515
516 /*
517 * Skip over PCF fonts that have no encoded characters; they're
518 * usually just Unicode fonts transcoded to some legacy encoding
519 */
520 if (FcCharSetCount (cs) == 0)
521 {
522 if (!strcmp(FT_MODULE_CLASS(&face->driver->root)->module_name, "pcf"))
523 goto bail2;
524 }
525
526 if (!FcPatternAddCharSet (pat, FC_CHARSET, cs))
527 goto bail2;
528
529 if (!FcFreeTypeSetLang (pat, cs, exclusiveLang))
530 goto bail2;
531
532 /*
533 * Drop our reference to the charset
534 */
535 FcCharSetDestroy (cs);
536
537 if (!(face->face_flags & FT_FACE_FLAG_SCALABLE))
538 {
539 for (i = 0; i < face->num_fixed_sizes; i++)
540 if (!FcPatternAddDouble (pat, FC_PIXEL_SIZE,
541 (double) face->available_sizes[i].height))
542 goto bail1;
543 if (!FcPatternAddBool (pat, FC_ANTIALIAS, FcFalse))
544 goto bail1;
545 }
546
547 FT_Done_Face (face);
548 FT_Done_FreeType (ftLibrary);
549 return pat;
550
551 bail2:
552 FcCharSetDestroy (cs);
553 bail1:
554 FcPatternDestroy (pat);
555 bail0:
556 FT_Done_Face (face);
557 bail:
558 FT_Done_FreeType (ftLibrary);
559 return 0;
560 }