added workaround for the "couldn't load glyph" freetype memory-corruption
[swftools.git] / lib / gfxfont.c
1 /* swffont.c
2
3    Functions for loading external fonts.
4
5    Extension module for the rfxswf library.
6    Part of the swftools package.
7
8    Copyright (c) 2003, 2004, 2005 Matthias Kramm
9  
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
23
24 #include "../config.h"
25 #include "gfxdevice.h"
26 #include "gfxtools.h"
27
28 static int loadfont_scale = 64;
29 static int full_unicode = 1;
30
31 #ifdef HAVE_FREETYPE
32
33 #ifdef HAVE_FT2BUILD_H
34 #include <ft2build.h>
35 #include FT_FREETYPE_H
36 #include FT_GLYPH_H
37 #include FT_SIZES_H
38 #include FT_SFNT_NAMES_H
39 #include FT_TRUETYPE_IDS_H
40 #include FT_OUTLINE_H
41 #else
42 #include <freetype/freetype.h>
43 #include <freetype/ftglyph.h>
44 #include <freetype/ftsizes.h>
45 #include <freetype/ftsnames.h>
46 #include <freetype/ttnameid.h>
47 #include <freetype/ftoutln.h>
48 #endif
49
50 /* Setting subpixels to 64 also means that the "point size" of the
51    font outlines will be 64. So the font, when rendered at original
52    size (i.e., the swf fontsize is 1024) will have the same size as
53    if it was rendered at 64pt */
54
55 #define FT_SCALE 1
56 #define FT_SUBPIXELS 64
57
58 typedef struct _gfxdrawinfo_t {
59     gfxdrawer_t* draw;
60     double quality;
61 } gfxdrawinfo_t;
62
63 static int ft_move_to(FT_Vector* _to, void* user) 
64 {
65     gfxdrawinfo_t* info = (gfxdrawinfo_t*)user;
66     gfxdrawer_t* draw = info->draw;
67     double x = _to->x*FT_SCALE/(float)FT_SUBPIXELS;
68     double y = -_to->y*FT_SCALE/(float)FT_SUBPIXELS;
69     draw->moveTo(draw, x,y);
70     return 0;
71 }
72 static int ft_line_to(FT_Vector* _to, void* user) 
73 {
74     gfxdrawinfo_t* info = (gfxdrawinfo_t*)user;
75     gfxdrawer_t* draw = info->draw;
76     double x = _to->x*FT_SCALE/(float)FT_SUBPIXELS;
77     double y = -_to->y*FT_SCALE/(float)FT_SUBPIXELS;
78     draw->lineTo(draw, x,y);
79     return 0;
80 }
81 static int ft_cubic_to(FT_Vector* _c1, FT_Vector* _c2, FT_Vector* _to, void* user)
82 {
83     gfxdrawinfo_t* info = (gfxdrawinfo_t*)user;
84     gfxdrawer_t* draw = info->draw;
85     double tox = _to->x*FT_SCALE/(float)FT_SUBPIXELS;
86     double toy = -_to->y*FT_SCALE/(float)FT_SUBPIXELS;
87     double c1x = _c1->x*FT_SCALE/(float)FT_SUBPIXELS;
88     double c1y = -_c1->y*FT_SCALE/(float)FT_SUBPIXELS;
89     double c2x = _c2->x*FT_SCALE/(float)FT_SUBPIXELS;
90     double c2y = -_c2->y*FT_SCALE/(float)FT_SUBPIXELS;
91     gfxdraw_cubicTo(draw, c1x, c1y, c2x, c2y, tox, toy, info->quality);
92     return 0;
93 }
94 static int ft_conic_to(FT_Vector* _c, FT_Vector* _to, void* user) 
95 {
96     gfxdrawinfo_t* info = (gfxdrawinfo_t*)user;
97     gfxdrawer_t* draw = info->draw;
98     double tox = _to->x*FT_SCALE/(float)FT_SUBPIXELS;
99     double toy = -_to->y*FT_SCALE/(float)FT_SUBPIXELS;
100     double cx = _c->x*FT_SCALE/(float)FT_SUBPIXELS;
101     double cy = -_c->y*FT_SCALE/(float)FT_SUBPIXELS;
102     gfxdraw_conicTo(draw, cx,cy, tox,toy, info->quality);
103     return 0;
104 }
105 static FT_Outline_Funcs outline_functions =
106 {
107   ft_move_to,
108   ft_line_to,
109   ft_conic_to,
110   ft_cubic_to,
111   0,0
112 };
113
114 static FT_Library ftlibrary = 0;
115
116 static gfxglyph_t cloneGlyph(gfxglyph_t*src)
117 {
118     gfxglyph_t dest;
119     memset(&dest, 0, sizeof(dest));
120     if(src->name)
121         dest.name = strdup(src->name);
122     dest.advance = src->advance;
123     dest.unicode = src->unicode;
124     dest.line = gfxline_clone(src->line);
125     return dest;
126 }
127
128 static void glyph_clear(gfxglyph_t*g)
129 {
130     gfxline_t*line;
131     if(g->name) {
132         free(g->name); g->name = 0;
133     }
134     gfxline_free(g->line);g->line = 0;
135 }
136
137 static int errorno = 0;
138
139 gfxfont_t* gfxfont_load(char*filename, double quality)
140 {
141     FT_Face face;
142     FT_Error error;
143     const char* fontname = 0;
144     FT_ULong charcode;
145     FT_UInt gindex;
146     gfxfont_t* font;
147     int t;
148     int*glyph2glyph = 0;
149     int*glyph2unicode = 0;
150     FT_Size size;
151     int max_unicode = 0;
152     int charmap = -1;
153     int isunicode = 1;
154     int has_had_errors = 0;
155
156     if(ftlibrary == 0) {
157         if(FT_Init_FreeType(&ftlibrary)) {
158             fprintf(stderr, "Couldn't init freetype library!\n");
159             exit(1);
160         }
161     }
162     error = FT_New_Face(ftlibrary, filename, 0, &face);
163     FT_Set_Pixel_Sizes (face, 16*loadfont_scale, 16*loadfont_scale);
164
165     if(error) {
166         fprintf(stderr, "Couldn't load file %s- not a TTF file?\n", filename);
167         return 0;
168     }
169     if(face->num_glyphs <= 0) {
170         fprintf(stderr, "File %s contains %d glyphs\n", face->num_glyphs);
171         return 0;
172     }
173
174     font = rfx_calloc(sizeof(gfxfont_t));
175     //font->style =  ((face->style_flags&FT_STYLE_FLAG_ITALIC)?FONT_STYLE_ITALIC:0) |((face->style_flags&FT_STYLE_FLAG_BOLD)?FONT_STYLE_BOLD:0);
176     //font->ascent = abs(face->ascender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMin;
177     //font->descent = abs(face->descender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMax;
178     //font->leading = font->layout->ascent + font->layout->descent;
179     //font->encoding = FONT_ENCODING_UNICODE;
180     font->max_unicode = 0;
181     
182     font->glyphs = rfx_calloc(face->num_glyphs*sizeof(gfxglyph_t));
183     glyph2unicode = rfx_calloc(face->num_glyphs*sizeof(int));
184     glyph2glyph = rfx_calloc(face->num_glyphs*sizeof(int));
185
186     if(FT_HAS_GLYPH_NAMES(face)) {
187         //font->glyphnames = rfx_calloc(face->num_glyphs*sizeof(char*));
188     }
189
190     fontname = FT_Get_Postscript_Name(face);
191
192     while(1) 
193     {
194         charcode = FT_Get_First_Char(face, &gindex);
195         while(gindex != 0)
196         {
197             if(gindex >= 0 && gindex<face->num_glyphs) {
198                 if(!glyph2unicode[gindex]) {
199                     glyph2unicode[gindex] = charcode;
200                     if(charcode + 1 > font->max_unicode) {
201                         font->max_unicode = charcode + 1;
202                     }
203                 }
204             }
205             charcode = FT_Get_Next_Char(face, charcode, &gindex);
206         }
207
208         /* if we didn't find a single encoding character, try
209            the font's charmaps instead. That usually means that
210            the encoding is no longer unicode. 
211            TODO: find a way to convert the encoding to unicode
212          */
213         if(font->max_unicode == 0 && charmap < face->num_charmaps - 1) {
214             charmap++;
215             FT_Set_Charmap(face, face->charmaps[charmap]);
216             //font->encoding = 0;//anything but unicode FIXME
217             isunicode = 0;
218         } else 
219             break;
220     }
221
222     /* TODO: if isunicode is 1, we now need to permutate the character
223              order so that each character is at it's encoding position */
224
225     if(full_unicode)
226         font->max_unicode = 65535;
227     
228     font->unicode2glyph = rfx_calloc(font->max_unicode*sizeof(int));
229     
230     for(t=0;t<font->max_unicode;t++) {
231         int g = FT_Get_Char_Index(face, t);
232         if(!g || g>=face->num_glyphs)
233             g = -1;
234         font->unicode2glyph[t] = g;
235         if(g>=0) {
236             max_unicode = t+1;
237             if(!glyph2unicode[g]) {
238                 glyph2unicode[g] = t;
239             }
240         }
241     }
242     font->max_unicode = max_unicode;
243
244     font->num_glyphs = 0;
245
246     for(t=0; t < face->num_glyphs; t++) {
247         FT_Glyph glyph;
248         FT_BBox bbox;
249         FT_Matrix matrix;
250         char name[128];
251         gfxdrawer_t draw;
252         gfxdrawinfo_t info;
253         int ret;
254         char hasname = 0;
255         int omit = 0;
256         name[0]=0;
257         
258         font->glyphs[font->num_glyphs].advance = 0;
259         font->glyphs[font->num_glyphs].line = 0;
260         font->glyphs[font->num_glyphs].unicode = glyph2unicode[t];
261         font->glyphs[font->num_glyphs].name = 0;
262
263         if(FT_HAS_GLYPH_NAMES(face)) {
264             error = FT_Get_Glyph_Name(face, t, name, 127);
265             if(!error && name[0] && !strstr(name, "notdef")) {
266                 font->glyphs[font->num_glyphs].name = strdup(name);
267                 hasname = 1;
268             }
269         }
270         if(has_had_errors && (isunicode && !glyph2unicode[t]) && !hasname) {
271             /* some freetype versions crash or corrupt memory if we try to load
272                characters (without unicode index or name) above 256 for some fonts.
273                So skip those characters once the first error occured */
274             omit = 1;
275         }
276         if(!omit) {
277             error = FT_Load_Glyph(face, t, FT_LOAD_NO_BITMAP);
278             if(error) {
279                 if(hasname)
280                     fprintf(stderr, "Warning: glyph %d/%d (unicode %d, name %s) has return code %d\n", t, face->num_glyphs, glyph2unicode[t], name, error);
281                 else
282                     fprintf(stderr, "Warning: glyph %d/%d (unicode %d) has return code %d\n", t, face->num_glyphs, glyph2unicode[t], error);
283                 omit = 1;
284
285 #if 0
286                 if(!has_had_errors) {
287                     char buf[256];
288                     if(fontname && *fontname) {
289                         fprintf(stderr, "font has been copied to %s.ttf\n", fontname);
290                         sprintf(buf, "cp %s %s.ttf", filename, fontname);
291                     } else {
292                         fprintf(stderr, "font has been copied to badfont%d.ttf\n", errorno);
293                         sprintf(buf, "cp %s badfont%d.ttf", filename, errorno);
294                         errorno++;
295                     }
296                     system(buf);
297                 }
298 #endif
299                 has_had_errors = 1;
300             }
301         }
302         if(!omit) {
303             error = FT_Get_Glyph(face->glyph, &glyph);
304             if(error) {
305                 fprintf(stderr, "Couldn't get glyph %d/%d, error:%d\n", t, face->num_glyphs, error);
306                 omit = 1;
307             }
308         }
309
310         if(!omit) {
311             gfxdrawer_target_gfxline(&draw);
312             info.draw = &draw;
313             info.quality = quality;
314
315             //error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &info);
316             error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &info);
317             
318             if(error) {
319                 fprintf(stderr, "Couldn't decompose glyph %d\n", t);
320                 gfxline_free((gfxline_t*)draw.result(&draw));
321                 FT_Done_Glyph(glyph);
322                 omit = 1;
323             } else {
324                 font->glyphs[font->num_glyphs].advance = glyph->advance.x*20/65536;
325                 font->glyphs[font->num_glyphs].line = (gfxline_t*)draw.result(&draw);
326             }
327         }
328
329         if(!omit) {
330             FT_Done_Glyph(glyph);
331         }
332         glyph2glyph[t] = font->num_glyphs;
333         font->num_glyphs++;
334     }
335
336     /* notice: if skip_unused is true, font->glyph2unicode, font->glyphnames and font->layout->bounds will 
337                have more memory allocated than just font->num_glyphs, but only the first font->numchars 
338                are used/valid */
339
340     for(t=0;t<font->max_unicode;t++) {
341         if(font->unicode2glyph[t]>=0) {
342             font->unicode2glyph[t] = glyph2glyph[font->unicode2glyph[t]];
343         }
344     }
345     rfx_free(glyph2glyph);
346     rfx_free(glyph2unicode);
347
348     FT_Done_Face(face);
349     FT_Done_FreeType(ftlibrary);ftlibrary=0;
350   
351     if(!isunicode && font->num_glyphs>0) {
352         /* if the encoding isn't unicode, remap the font
353            so that the encoding equals the char position, and
354            remove the unicode table */
355         int t;
356         gfxglyph_t*newglyphs = rfx_calloc(font->max_unicode*sizeof(gfxglyph_t));
357
358         for(t=0;t<max_unicode;t++) {
359             int c = font->unicode2glyph[t];
360             if(c>=font->num_glyphs || c<0)
361                 c = 0;
362             newglyphs[t] = cloneGlyph(&font->glyphs[c]);
363             newglyphs[t].unicode = -1;
364         }
365         for(t=0;t<font->num_glyphs;t++) {
366             glyph_clear(&font->glyphs[t]);
367         }
368         free(font->glyphs);
369         font->glyphs = newglyphs;
370         font->num_glyphs = font->max_unicode;
371
372         free(font->unicode2glyph);font->unicode2glyph = 0;
373         font->max_unicode = 0;
374     }
375
376     if(font->unicode2glyph) {
377         int t;
378         int bad = 0;
379         /* check whether the Unicode indices look o.k.
380            If they don't, disable the unicode lookup by setting
381            the unicode map to -1 everywhere */
382         for(t=0;t<font->num_glyphs;t++) {
383             int c = font->glyphs[t].unicode;
384             gfxline_t* line = font->glyphs[t].line;
385             if(c && c < 32 && (line && line->next && line->next->next)) {
386                 // the character maps into the unicode control character range
387                 // between 0001-001f. Yet it is not empty. Treat the one
388                 // mapping as broken, and look how many of those we find.
389                 bad ++;
390             }
391         }
392         if(bad>5) {
393             free(font->unicode2glyph);font->unicode2glyph = 0;
394             font->max_unicode = 0;
395             for(t=0;t<font->num_glyphs;t++) {
396                 font->glyphs[t].unicode = -1;
397             }
398         }
399     }
400
401     return font;
402 }
403 #else
404
405 gfxfont_t* gfxfont_load(char*filename)
406 {
407     fprintf(stderr, "No freetype support compiled in! Not able to load %s\n", filename);
408 }
409
410 #endif
411
412 void gfxfont_free(gfxfont_t*font)
413 {
414     int t;
415     for(t=0;t<font->num_glyphs;t++) {
416         glyph_clear(&font->glyphs[t]);
417     }
418     if(font->glyphs) {
419         free(font->glyphs);font->glyphs = 0;
420     }
421     font->num_glyphs = 0;
422     if(font->unicode2glyph) {
423         free(font->unicode2glyph);font->unicode2glyph = 0;
424     }
425     free(font);
426 }
427