fixed some mem leaks, added gfxfont_free()
[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 "gfxdevice.h"
25 #include "gfxtools.h"
26
27 static int loadfont_scale = 64;
28 static int skip_unused = 0;
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 static int ft_move_to(FT_Vector* _to, void* user) 
59 {
60     gfxdrawer_t* draw = (gfxdrawer_t*)user;
61     double x = _to->x*FT_SCALE/(float)FT_SUBPIXELS;
62     double y = -_to->y*FT_SCALE/(float)FT_SUBPIXELS;
63     draw->moveTo(draw, x,y);
64     return 0;
65 }
66 static int ft_line_to(FT_Vector* _to, void* user) 
67 {
68     gfxdrawer_t* draw = (gfxdrawer_t*)user;
69     double x = _to->x*FT_SCALE/(float)FT_SUBPIXELS;
70     double y = -_to->y*FT_SCALE/(float)FT_SUBPIXELS;
71     draw->lineTo(draw, x,y);
72     return 0;
73 }
74 static int ft_cubic_to(FT_Vector* _c1, FT_Vector* _c2, FT_Vector* _to, void* user)
75 {
76     gfxdrawer_t* draw = (gfxdrawer_t*)user;
77     double tox = _to->x*FT_SCALE/(float)FT_SUBPIXELS;
78     double toy = -_to->y*FT_SCALE/(float)FT_SUBPIXELS;
79     double c1x = _c1->x*FT_SCALE/(float)FT_SUBPIXELS;
80     double c1y = -_c1->y*FT_SCALE/(float)FT_SUBPIXELS;
81     double c2x = _c2->x*FT_SCALE/(float)FT_SUBPIXELS;
82     double c2y = -_c2->y*FT_SCALE/(float)FT_SUBPIXELS;
83     gfxdraw_cubicTo(draw, c1x, c1y, c2x, c2y, tox, toy);
84     return 0;
85 }
86 static int ft_conic_to(FT_Vector* _c, FT_Vector* _to, void* user) 
87 {
88     gfxdrawer_t* draw = (gfxdrawer_t*)user;
89     double tox = _to->x*FT_SCALE/(float)FT_SUBPIXELS;
90     double toy = -_to->y*FT_SCALE/(float)FT_SUBPIXELS;
91     double cx = _c->x*FT_SCALE/(float)FT_SUBPIXELS;
92     double cy = -_c->y*FT_SCALE/(float)FT_SUBPIXELS;
93     gfxdraw_conicTo(draw, cx,cy, tox,toy);
94     return 0;
95 }
96 static FT_Outline_Funcs outline_functions =
97 {
98   ft_move_to,
99   ft_line_to,
100   ft_conic_to,
101   ft_cubic_to,
102   0,0
103 };
104
105 static FT_Library ftlibrary = 0;
106
107 gfxline_t * clonePath(gfxline_t*line)
108 {
109     gfxline_t*dest = 0;
110     gfxline_t*pos = 0;
111     while(line) {
112         gfxline_t*n = rfx_calloc(sizeof(gfxline_t));
113         *n = *line;
114         n->next = 0;
115         if(!pos) {
116             dest = pos = n;
117         } else {
118             pos->next = n;
119             pos = n;
120         }
121         line = line->next;
122     }
123     return dest;
124 }
125
126 static gfxglyph_t cloneGlyph(gfxglyph_t*src)
127 {
128     gfxglyph_t dest;
129     memset(&dest, 0, sizeof(dest));
130     if(src->name)
131         dest.name = strdup(src->name);
132     dest.advance = src->advance;
133     dest.unicode = src->unicode;
134     dest.line = clonePath(src->line);
135     return dest;
136 }
137
138 static void glyph_clear(gfxglyph_t*g)
139 {
140     gfxline_t*line;
141     if(g->name) {
142         free(g->name); g->name = 0;
143     }
144     gfxline_free(g->line);g->line = 0;
145 }
146
147 void gfxfont_free(gfxfont_t*font)
148 {
149     int t;
150     for(t=0;t<font->num_glyphs;t++) {
151         glyph_clear(&font->glyphs[t]);
152     }
153     if(font->glyphs) {
154         free(font->glyphs);font->glyphs = 0;
155     }
156     font->num_glyphs = 0;
157     if(font->unicode2glyph) {
158         free(font->unicode2glyph);font->unicode2glyph = 0;
159     }
160     if(font->name) {
161         free(font->name);font->name = 0;
162     }
163     free(font);
164 }
165
166 gfxfont_t* gfxfont_load(char*filename)
167 {
168     FT_Face face;
169     FT_Error error;
170     const char* name = 0;
171     FT_ULong charcode;
172     FT_UInt gindex;
173     gfxfont_t* font;
174     int t;
175     int*glyph2glyph = 0;
176     int*glyph2unicode = 0;
177     FT_Size size;
178     int max_unicode = 0;
179     int charmap = -1;
180     int isunicode = 1;
181    
182     if(ftlibrary == 0) {
183         if(FT_Init_FreeType(&ftlibrary)) {
184             fprintf(stderr, "Couldn't init freetype library!\n");
185             exit(1);
186         }
187     }
188     error = FT_New_Face(ftlibrary, filename, 0, &face);
189     FT_Set_Pixel_Sizes (face, 16*loadfont_scale, 16*loadfont_scale);
190
191     if(error) {
192         fprintf(stderr, "Couldn't load file %s- not a TTF file?\n", filename);
193         return 0;
194     }
195     if(face->num_glyphs <= 0) {
196         fprintf(stderr, "File %s contains %d glyphs\n", face->num_glyphs);
197         return 0;
198     }
199
200     font = rfx_calloc(sizeof(gfxfont_t));
201     //font->style =  ((face->style_flags&FT_STYLE_FLAG_ITALIC)?FONT_STYLE_ITALIC:0) |((face->style_flags&FT_STYLE_FLAG_BOLD)?FONT_STYLE_BOLD:0);
202     //font->ascent = abs(face->ascender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMin;
203     //font->descent = abs(face->descender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMax;
204     //font->leading = font->layout->ascent + font->layout->descent;
205     //font->encoding = FONT_ENCODING_UNICODE;
206     font->max_unicode = 0;
207     
208     font->glyphs = rfx_calloc(face->num_glyphs*sizeof(gfxglyph_t));
209     glyph2unicode = rfx_calloc(face->num_glyphs*sizeof(int));
210     glyph2glyph = rfx_calloc(face->num_glyphs*sizeof(int));
211
212     if(FT_HAS_GLYPH_NAMES(face)) {
213         //font->glyphnames = rfx_calloc(face->num_glyphs*sizeof(char*));
214     }
215
216     name = FT_Get_Postscript_Name(face);
217     if(name && *name)
218         font->name = strdup(name);
219
220     while(1) 
221     {
222         charcode = FT_Get_First_Char(face, &gindex);
223         while(gindex != 0)
224         {
225             if(gindex >= 0 && gindex<face->num_glyphs) {
226                 if(!glyph2unicode[gindex]) {
227                     glyph2unicode[gindex] = charcode;
228                     if(charcode + 1 > font->max_unicode) {
229                         font->max_unicode = charcode + 1;
230                     }
231                 }
232             }
233             charcode = FT_Get_Next_Char(face, charcode, &gindex);
234         }
235
236         /* if we didn't find a single encoding character, try
237            the font's charmaps instead. That usually means that
238            the encoding is no longer unicode. 
239            TODO: find a way to convert the encoding to unicode
240          */
241         if(font->max_unicode == 0 && charmap < face->num_charmaps - 1) {
242             charmap++;
243             FT_Set_Charmap(face, face->charmaps[charmap]);
244             //font->encoding = 0;//anything but unicode FIXME
245             isunicode = 0;
246         } else 
247             break;
248     }
249
250     /* TODO: if isunicode is 1, we now need to permutate the character
251              order so that each character is at it's encoding position */
252
253     if(full_unicode)
254         font->max_unicode = 65535;
255     
256     font->unicode2glyph = rfx_calloc(font->max_unicode*sizeof(int));
257     
258     for(t=0;t<font->max_unicode;t++) {
259         int g = FT_Get_Char_Index(face, t);
260         if(!g || g>=face->num_glyphs)
261             g = -1;
262         font->unicode2glyph[t] = g;
263         if(g>=0) {
264             max_unicode = t+1;
265             if(!glyph2unicode[g]) {
266                 glyph2unicode[g] = t;
267             }
268         }
269     }
270     font->max_unicode = max_unicode;
271
272     font->num_glyphs = 0;
273
274     for(t=0; t < face->num_glyphs; t++) {
275         FT_Glyph glyph;
276         FT_BBox bbox;
277         FT_Matrix matrix;
278         char name[128];
279         gfxdrawer_t draw;
280         int ret;
281         char hasname = 0;
282         name[0]=0;
283         if(FT_HAS_GLYPH_NAMES(face)) {
284             error = FT_Get_Glyph_Name(face, t, name, 127);
285             if(!error && name[0] && !strstr(name, "notdef")) {
286                 font->glyphs[font->num_glyphs].name = strdup(name);
287                 hasname = 1;
288             }
289         }
290         if(!glyph2unicode[t] && !hasname && skip_unused) {
291             continue;
292         }
293         error = FT_Load_Glyph(face, t, FT_LOAD_NO_BITMAP);
294         if(error) {
295             fprintf(stderr, "Couldn't load glyph %d, error:%d\n", t, error);
296             continue;
297         }
298         error = FT_Get_Glyph(face->glyph, &glyph);
299         if(error) {
300             fprintf(stderr, "Couldn't get glyph %d, error:%d\n", t, error);
301             continue;
302         }
303
304         FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_unscaled, &bbox);
305         bbox.yMin = -bbox.yMin;
306         bbox.yMax = -bbox.yMax;
307         if(bbox.xMax < bbox.xMin) {
308             // swap
309             bbox.xMax ^= bbox.xMin;
310             bbox.xMin ^= bbox.xMax;
311             bbox.xMax ^= bbox.xMin;
312         }
313         if(bbox.yMax < bbox.yMin) {
314             // swap
315             bbox.yMax ^= bbox.yMin;
316             bbox.yMin ^= bbox.yMax;
317             bbox.yMax ^= bbox.yMin;
318         }
319
320         gfxdrawer_target_gfxline(&draw);
321
322         //error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &draw);
323         error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &draw);
324         
325         if(error) {
326             fprintf(stderr, "Couldn't decompose glyph %d\n", t);
327             gfxline_free((gfxline_t*)draw.result(&draw));
328             continue;
329         }
330
331 #if 0
332         if(bbox.xMin > 0) {
333             font->glyph[font->num_glyphs].advance = (bbox.xMax*20*FT_SCALE)/FT_SUBPIXELS;
334         } else {
335             font->glyph[font->num_glyphs].advance = ((bbox.xMax - bbox.xMin)*20*FT_SCALE)/FT_SUBPIXELS;
336         }
337 #else
338         font->glyphs[font->num_glyphs].advance = glyph->advance.x*20/65536;
339 #endif
340         
341         font->glyphs[font->num_glyphs].line = (gfxline_t*)draw.result(&draw);
342         
343         /*font->glyphs[font->num_glyphs].bbox.xmin = (bbox.xMin*FT_SCALE*20)/FT_SUBPIXELS;
344         font->glyphs[font->num_glyphs].bbox.ymin = (bbox.yMin*FT_SCALE*20)/FT_SUBPIXELS;
345         font->glyphs[font->num_glyphs].bbox.xmax = (bbox.xMax*FT_SCALE*20)/FT_SUBPIXELS;
346         font->glyphs[font->num_glyphs].bbox.ymax = (bbox.yMax*FT_SCALE*20)/FT_SUBPIXELS;*/
347
348         FT_Done_Glyph(glyph);
349         font->glyphs[font->num_glyphs].unicode = glyph2unicode[t];
350         glyph2glyph[t] = font->num_glyphs;
351         font->num_glyphs++;
352     }
353     /* notice: if skip_unused is true, font->glyph2unicode, font->glyphnames and font->layout->bounds will 
354                have more memory allocated than just font->num_glyphs, but only the first font->numchars 
355                are used/valid */
356
357     for(t=0;t<font->max_unicode;t++) {
358         if(font->unicode2glyph[t]>=0) {
359             font->unicode2glyph[t] = glyph2glyph[font->unicode2glyph[t]];
360         }
361     }
362     rfx_free(glyph2glyph);
363     rfx_free(glyph2unicode);
364
365     FT_Done_Face(face);
366     FT_Done_FreeType(ftlibrary);ftlibrary=0;
367    
368     if(!isunicode && font->num_glyphs>0) {
369         /* if the encoding isn't unicode, remap the font
370            so that the encoding equals the char position, and
371            remove the unicode table */
372         int t;
373         gfxglyph_t*newglyphs = rfx_calloc(font->max_unicode*sizeof(gfxglyph_t));
374
375         for(t=0;t<max_unicode;t++) {
376             int c = font->unicode2glyph[t];
377             if(c>=font->num_glyphs || c<0)
378                 c = 0;
379             newglyphs[t] = cloneGlyph(&font->glyphs[c]);
380             newglyphs[t].unicode = -1;
381         }
382         for(t=0;t<font->num_glyphs;t++) {
383             glyph_clear(&font->glyphs[t]);
384         }
385         free(font->glyphs);
386         font->glyphs = newglyphs;
387         font->num_glyphs = font->max_unicode;
388
389         free(font->unicode2glyph);font->unicode2glyph = 0;
390         font->max_unicode = 0;
391     }
392
393     if(font->unicode2glyph) {
394         int t;
395         int bad = 0;
396         /* check whether the Unicode indices look o.k.
397            If they don't, disable the unicode lookup by setting
398            the unicode map to -1 everywhere */
399         for(t=0;t<font->num_glyphs;t++) {
400             int c = font->glyphs[t].unicode;
401             gfxline_t* line = font->glyphs[t].line;
402             if(c && c < 32 && (line && line->next && line->next->next)) {
403                 // the character maps into the unicode control character range
404                 // between 0001-001f. Yet it is not empty. Treat the one
405                 // mapping as broken, and look how many of those we find.
406                 bad ++;
407             }
408         }
409         if(bad>5) {
410             free(font->unicode2glyph);font->unicode2glyph = 0;
411             font->max_unicode = 0;
412             for(t=0;t<font->num_glyphs;t++) {
413                 font->glyphs[t].unicode = -1;
414             }
415         }
416     }
417
418     return font;
419 }
420 #else
421
422 gfxfont_t* gfxfont_load(char*filename)
423 {
424     fprintf(stderr, "No freetype support compiled in! Not able to load %s\n", filename);
425 }
426
427 #endif
428