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