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