fontlist structure added
[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*id, 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     int num_names = 0;
156
157     if(ftlibrary == 0) {
158         if(FT_Init_FreeType(&ftlibrary)) {
159             fprintf(stderr, "Couldn't init freetype library!\n");
160             exit(1);
161         }
162     }
163     error = FT_New_Face(ftlibrary, filename, 0, &face);
164     FT_Set_Pixel_Sizes (face, 16*loadfont_scale, 16*loadfont_scale);
165
166     if(error) {
167         fprintf(stderr, "Couldn't load file %s- not a TTF file? (error=%02x)\n", filename, error);
168         return 0;
169     }
170     if(face->num_glyphs <= 0) {
171         fprintf(stderr, "File %s contains %d glyphs\n", face->num_glyphs);
172         return 0;
173     }
174
175     font = rfx_calloc(sizeof(gfxfont_t));
176     //font->style =  ((face->style_flags&FT_STYLE_FLAG_ITALIC)?FONT_STYLE_ITALIC:0) |((face->style_flags&FT_STYLE_FLAG_BOLD)?FONT_STYLE_BOLD:0);
177     //font->ascent = abs(face->ascender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMin;
178     //font->descent = abs(face->descender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMax;
179     //font->leading = font->layout->ascent + font->layout->descent;
180     //font->encoding = FONT_ENCODING_UNICODE;
181     font->max_unicode = 0;
182     font->id = strdup(id);
183     
184     font->glyphs = rfx_calloc(face->num_glyphs*sizeof(gfxglyph_t));
185     glyph2unicode = rfx_calloc(face->num_glyphs*sizeof(int));
186     glyph2glyph = rfx_calloc(face->num_glyphs*sizeof(int));
187
188     if(FT_HAS_GLYPH_NAMES(face)) {
189         //font->glyphnames = rfx_calloc(face->num_glyphs*sizeof(char*));
190     }
191
192     fontname = FT_Get_Postscript_Name(face);
193
194     while(1) 
195     {
196         charcode = FT_Get_First_Char(face, &gindex);
197         while(gindex != 0)
198         {
199             if(gindex >= 0 && gindex<face->num_glyphs) {
200                 if(!glyph2unicode[gindex]) {
201                     glyph2unicode[gindex] = charcode;
202                     if(charcode + 1 > font->max_unicode) {
203                         font->max_unicode = charcode + 1;
204                     }
205                 }
206             }
207             charcode = FT_Get_Next_Char(face, charcode, &gindex);
208         }
209
210         /* if we didn't find a single encoding character, try
211            the font's charmaps instead. That usually means that
212            the encoding is no longer unicode. 
213            TODO: find a way to convert the encoding to unicode
214          */
215         if(font->max_unicode == 0 && charmap < face->num_charmaps-1 && 
216                 face->charmaps[charmap+1]->encoding != 0x41444243 /* custom */)
217                 {
218             charmap++;
219             FT_Set_Charmap(face, face->charmaps[charmap]);
220             isunicode = 0;
221         } else
222             break;
223     }
224
225     /* TODO: if isunicode is 1, we now need to permutate the character
226              order so that each character is at it's encoding position */
227
228     if(full_unicode)
229         font->max_unicode = 65535;
230     
231     font->unicode2glyph = rfx_calloc(font->max_unicode*sizeof(int));
232     
233     for(t=0;t<font->max_unicode;t++) {
234         int g = FT_Get_Char_Index(face, t);
235         if(!g || g>=face->num_glyphs)
236             g = -1;
237         font->unicode2glyph[t] = g;
238         if(g>=0) {
239             max_unicode = t+1;
240             if(!glyph2unicode[g]) {
241                 glyph2unicode[g] = t;
242             }
243         }
244     }
245     font->max_unicode = max_unicode;
246
247     font->num_glyphs = 0;
248
249
250     for(t=0; t < face->num_glyphs; t++) {
251         if(FT_HAS_GLYPH_NAMES(face)) {
252             char name[128];
253             error = FT_Get_Glyph_Name(face, t, name, 127);
254             if(!error && name[0] && !strstr(name, "notdef")) {
255                 num_names++;
256             }
257         }
258     }
259
260
261     for(t=0; t < face->num_glyphs; t++) {
262         FT_Glyph glyph;
263         FT_BBox bbox;
264         FT_Matrix matrix;
265         char name[128];
266         gfxdrawer_t draw;
267         gfxdrawinfo_t info;
268         int ret;
269         char hasname = 0;
270         int omit = 0;
271         name[0]=0;
272         
273         font->glyphs[font->num_glyphs].advance = 0;
274         font->glyphs[font->num_glyphs].line = 0;
275         font->glyphs[font->num_glyphs].unicode = glyph2unicode[t];
276         font->glyphs[font->num_glyphs].name = 0;
277
278         if(FT_HAS_GLYPH_NAMES(face) && (num_names >= face->num_glyphs/10 || num_names > 2)) {
279             name[0] = 0;
280             error = FT_Get_Glyph_Name(face, t, name, 127);
281             if(!error && name[0] && !strstr(name, "notdef")) {
282                 font->glyphs[font->num_glyphs].name = strdup(name);
283                 hasname = 1;
284             }
285         }
286
287 #if 0 // some cantonese pdfs fail to work if this is activated
288
289         if(has_had_errors && (isunicode && !glyph2unicode[t]) && !hasname && t>=256) {
290             /* some freetype versions crash or corrupt memory if we try to load
291                characters (without unicode index or name) above 256 for some fonts.
292                So skip those characters once the first error occured */
293             omit = 1;
294         }
295 #endif
296
297         if(!omit) {
298             error = FT_Load_Glyph(face, t, FT_LOAD_NO_BITMAP);
299             if(error) {
300                 if(hasname)
301                     fprintf(stderr, "Warning: glyph %d/%d (unicode %d, name %s) has return code %d\n", t, face->num_glyphs, glyph2unicode[t], name, error);
302                 else
303                     fprintf(stderr, "Warning: glyph %d/%d (unicode %d) has return code %d\n", t, face->num_glyphs, glyph2unicode[t], error);
304                 omit = 2;
305
306 #if 0
307                 if(!has_had_errors) {
308                     char buf[256];
309                     if(fontname && *fontname) {
310                         fprintf(stderr, "font has been copied to %s.ttf\n", fontname);
311                         sprintf(buf, "cp %s %s.ttf", filename, fontname);
312                     } else {
313                         fprintf(stderr, "font has been copied to badfont%d.ttf\n", errorno);
314                         sprintf(buf, "cp %s badfont%d.ttf", filename, errorno);
315                         errorno++;
316                     }
317                     system(buf);
318                 }
319 #endif
320                 has_had_errors = 1;
321             }
322         }
323         if(!omit) {
324             error = FT_Get_Glyph(face->glyph, &glyph);
325             if(error) {
326                 fprintf(stderr, "Couldn't get glyph %d/%d, error:%d\n", t, face->num_glyphs, error);
327                 omit = 3;
328             }
329         }
330
331         if(!omit) {
332             gfxline_t*l;
333             int ok=0;
334             gfxdrawer_target_gfxline(&draw);
335             info.draw = &draw;
336             info.quality = quality;
337
338             //error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &info);
339             error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &info);
340             
341             if(error) {
342                 fprintf(stderr, "Couldn't decompose glyph %d\n", t);
343                 gfxline_free((gfxline_t*)draw.result(&draw));
344                 FT_Done_Glyph(glyph);
345                 omit = 4;
346             } else {
347                 font->glyphs[font->num_glyphs].advance = (glyph->advance.x*20)/65536;
348                 font->glyphs[font->num_glyphs].line = (gfxline_t*)draw.result(&draw);
349             }
350             l = font->glyphs[font->num_glyphs].line;
351             while(l) {
352                 if(l->type != gfx_moveTo) {
353                     ok = 1;
354                 }
355                 l = l->next;
356             }
357             if(!ok && !name) {
358                 gfxline_free(font->glyphs[font->num_glyphs].line);
359                 font->glyphs[font->num_glyphs].line = 0;
360                 font->glyphs[font->num_glyphs].advance = 0;
361
362                 /* Some PDFs created e.g. by InDesign tend to create
363                    fonts with reduced (empty) characters, which still
364                    have unicode indices attached to them.
365                    Remove that information, in order to not confuse
366                    any converter applications.
367                     */
368                 font->glyphs[font->num_glyphs].unicode = 0;
369                 if(font->glyphs[font->num_glyphs].name) {
370                     free(font->glyphs[font->num_glyphs].name);
371                     font->glyphs[font->num_glyphs].name = 0;
372                 }
373                 FT_Done_Glyph(glyph);
374                 omit = 5;
375             }
376         }
377
378         if(!omit) {
379             FT_Done_Glyph(glyph);
380             font->glyphs[font->num_glyphs].unicode = glyph2unicode[t];
381         }
382
383         glyph2glyph[t] = font->num_glyphs;
384         font->num_glyphs++;
385     }
386
387     /* notice: if skip_unused is true, font->glyph2unicode, font->glyphnames and font->layout->bounds will 
388                have more memory allocated than just font->num_glyphs, but only the first font->numchars 
389                are used/valid */
390
391     for(t=0;t<font->max_unicode;t++) {
392         if(font->unicode2glyph[t]>=0) {
393             font->unicode2glyph[t] = glyph2glyph[font->unicode2glyph[t]];
394         }
395     }
396     rfx_free(glyph2glyph);
397     rfx_free(glyph2unicode);
398
399     FT_Done_Face(face);
400     FT_Done_FreeType(ftlibrary);ftlibrary=0;
401  
402     if(!isunicode && font->num_glyphs>0 && font->max_unicode) {
403         /* if the encoding isn't unicode, remap the font
404            so that the encoding equals the char position, and
405            remove the unicode table */
406         int t;
407         gfxglyph_t*newglyphs = rfx_calloc(font->max_unicode*sizeof(gfxglyph_t));
408
409         for(t=0;t<max_unicode;t++) {
410             int c = font->unicode2glyph[t];
411             if(c>=font->num_glyphs || c<0)
412                 c = 0;
413             newglyphs[t] = cloneGlyph(&font->glyphs[c]);
414             newglyphs[t].unicode = -1;
415         }
416         for(t=0;t<font->num_glyphs;t++) {
417             glyph_clear(&font->glyphs[t]);
418         }
419         free(font->glyphs);
420         font->glyphs = newglyphs;
421         font->num_glyphs = font->max_unicode;
422
423         free(font->unicode2glyph);font->unicode2glyph = 0;
424         font->max_unicode = 0;
425     }
426
427     if(font->unicode2glyph) {
428         int t;
429         int bad = 0;
430         /* check whether the Unicode indices look o.k.
431            If they don't, disable the unicode lookup by setting
432            the unicode map to -1 everywhere */
433         for(t=0;t<font->num_glyphs;t++) {
434             int c = font->glyphs[t].unicode;
435             gfxline_t* line = font->glyphs[t].line;
436             if(c && c < 32 && (line && line->next && line->next->next)) {
437                 // the character maps into the unicode control character range
438                 // between 0001-001f. Yet it is not empty. Treat the one
439                 // mapping as broken, and look how many of those we find.
440                 bad ++;
441             }
442         }
443         if(bad>5) {
444             free(font->unicode2glyph);font->unicode2glyph = 0;
445             font->max_unicode = 0;
446             for(t=0;t<font->num_glyphs;t++) {
447                 font->glyphs[t].unicode = -1;
448             }
449         }
450     }
451
452     return font;
453 }
454 #else
455
456 gfxfont_t* gfxfont_load(char*filename)
457 {
458     fprintf(stderr, "No freetype support compiled in! Not able to load %s\n", filename);
459 }
460
461 #endif
462
463 void gfxfont_free(gfxfont_t*font)
464 {
465     int t;
466     for(t=0;t<font->num_glyphs;t++) {
467         glyph_clear(&font->glyphs[t]);
468     }
469     if(font->glyphs) {
470         free(font->glyphs);font->glyphs = 0;
471     }
472     font->num_glyphs = 0;
473     if(font->unicode2glyph) {
474         free(font->unicode2glyph);font->unicode2glyph = 0;
475     }
476     free(font);
477 }
478