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