header file for artsutils.c
[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 #include "gfxfont.h"
28
29 static int loadfont_scale = 64;
30 static int full_unicode = 1;
31
32 #ifdef HAVE_FREETYPE
33
34 #ifdef HAVE_FT2BUILD_H
35 #include <ft2build.h>
36 #include FT_FREETYPE_H
37 #include FT_GLYPH_H
38 #include FT_SIZES_H
39 #include FT_SFNT_NAMES_H
40 #include FT_TRUETYPE_IDS_H
41 #include FT_OUTLINE_H
42 #else
43 #include <freetype/freetype.h>
44 #include <freetype/ftglyph.h>
45 #include <freetype/ftsizes.h>
46 #include <freetype/ftsnames.h>
47 #include <freetype/ttnameid.h>
48 #include <freetype/ftoutln.h>
49 #endif
50
51 /* Setting subpixels to 64 also means that the "point size" of the
52    font outlines will be 64. So the font, when rendered at original
53    size (i.e., the swf fontsize is 1024) will have the same size as
54    if it was rendered at 64pt */
55
56 #define FT_SCALE 1
57 #define FT_SUBPIXELS 64
58
59 typedef struct _gfxdrawinfo_t {
60     gfxdrawer_t* draw;
61     double quality;
62 } gfxdrawinfo_t;
63
64 static int ft_move_to(const FT_Vector* _to, void* user) 
65 {
66     gfxdrawinfo_t* info = (gfxdrawinfo_t*)user;
67     gfxdrawer_t* draw = info->draw;
68     double x = _to->x*FT_SCALE/(float)FT_SUBPIXELS;
69     double y = -_to->y*FT_SCALE/(float)FT_SUBPIXELS;
70     draw->moveTo(draw, x,y);
71     return 0;
72 }
73 static int ft_line_to(const FT_Vector* _to, void* user) 
74 {
75     gfxdrawinfo_t* info = (gfxdrawinfo_t*)user;
76     gfxdrawer_t* draw = info->draw;
77     double x = _to->x*FT_SCALE/(float)FT_SUBPIXELS;
78     double y = -_to->y*FT_SCALE/(float)FT_SUBPIXELS;
79     draw->lineTo(draw, x,y);
80     return 0;
81 }
82 static int ft_cubic_to(const FT_Vector* _c1, const FT_Vector* _c2, const FT_Vector* _to, void* user)
83 {
84     gfxdrawinfo_t* info = (gfxdrawinfo_t*)user;
85     gfxdrawer_t* draw = info->draw;
86     double tox = _to->x*FT_SCALE/(float)FT_SUBPIXELS;
87     double toy = -_to->y*FT_SCALE/(float)FT_SUBPIXELS;
88     double c1x = _c1->x*FT_SCALE/(float)FT_SUBPIXELS;
89     double c1y = -_c1->y*FT_SCALE/(float)FT_SUBPIXELS;
90     double c2x = _c2->x*FT_SCALE/(float)FT_SUBPIXELS;
91     double c2y = -_c2->y*FT_SCALE/(float)FT_SUBPIXELS;
92     gfxdraw_cubicTo(draw, c1x, c1y, c2x, c2y, tox, toy, info->quality);
93     return 0;
94 }
95 static int ft_conic_to(const FT_Vector* _c, const FT_Vector* _to, void* user) 
96 {
97     gfxdrawinfo_t* info = (gfxdrawinfo_t*)user;
98     gfxdrawer_t* draw = info->draw;
99     double tox = _to->x*FT_SCALE/(float)FT_SUBPIXELS;
100     double toy = -_to->y*FT_SCALE/(float)FT_SUBPIXELS;
101     double cx = _c->x*FT_SCALE/(float)FT_SUBPIXELS;
102     double cy = -_c->y*FT_SCALE/(float)FT_SUBPIXELS;
103     gfxdraw_conicTo(draw, cx,cy, tox,toy, info->quality);
104     return 0;
105 }
106 static FT_Outline_Funcs outline_functions =
107 {
108   ft_move_to,
109   ft_line_to,
110   ft_conic_to,
111   ft_cubic_to,
112   0,0
113 };
114
115 static FT_Library ftlibrary = 0;
116
117 static gfxglyph_t cloneGlyph(gfxglyph_t*src)
118 {
119     gfxglyph_t dest;
120     memset(&dest, 0, sizeof(dest));
121     if(src->name)
122         dest.name = strdup(src->name);
123     dest.advance = src->advance;
124     dest.unicode = src->unicode;
125     dest.line = gfxline_clone(src->line);
126     return dest;
127 }
128
129 static void glyph_clear(gfxglyph_t*g)
130 {
131     gfxline_t*line;
132     if(g->name) {
133         free((void*)g->name); g->name = 0;
134     }
135     gfxline_free(g->line);g->line = 0;
136 }
137
138 static int errorno = 0;
139
140 //#define DEBUG 1
141
142 gfxfont_t* gfxfont_load(char*id, char*filename, unsigned int flags, double quality)
143 {
144     FT_Face face;
145     FT_Error error;
146     const char* fontname = 0;
147     FT_ULong charcode;
148     FT_UInt gindex;
149     gfxfont_t* font;
150     int t;
151     int*glyph2glyph = 0;
152     int*glyph2unicode = 0;
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 = (gfxfont_t*)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 = (gfxglyph_t*)rfx_calloc(face->num_glyphs*sizeof(gfxglyph_t));
190     glyph2unicode = (int*)rfx_calloc(face->num_glyphs*sizeof(int));
191     glyph2glyph = (int*)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 = (int*)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         char name[128];
302         gfxdrawer_t draw;
303         gfxdrawinfo_t info;
304         char hasname = 0;
305         int omit = 0;
306         name[0]=0;
307         
308         font->glyphs[font->num_glyphs].advance = 0;
309         font->glyphs[font->num_glyphs].line = 0;
310         font->glyphs[font->num_glyphs].unicode = glyph2unicode[t];
311         font->glyphs[font->num_glyphs].name = 0;
312
313         if(FT_HAS_GLYPH_NAMES(face) && (num_names >= face->num_glyphs/10 || num_names > 2)) {
314             name[0] = 0;
315             error = FT_Get_Glyph_Name(face, t, name, 127);
316             if(!error && name[0] && !strstr(name, "notdef")) {
317                 font->glyphs[font->num_glyphs].name = strdup(name);
318                 hasname = 1;
319             }
320         }
321
322 #if 0 // some cantonese pdfs fail to work if this is activated
323
324         if(has_had_errors && (isunicode && !glyph2unicode[t]) && !hasname && t>=256) {
325             /* some freetype versions crash or corrupt memory if we try to load
326                characters (without unicode index or name) above 256 for some fonts.
327                So skip those characters once the first error occured */
328             omit = 1;
329         }
330 #endif
331
332         if(!omit) {
333             error = FT_Load_Glyph(face, t, FT_LOAD_NO_BITMAP);
334             if(error) {
335                 if(hasname)
336                     fprintf(stderr, "Warning: glyph %d/%d (unicode %d, name %s) has return code %d\n", t, face->num_glyphs, glyph2unicode[t], name, error);
337                 else
338                     fprintf(stderr, "Warning: glyph %d/%d (unicode %d) has return code %d\n", t, face->num_glyphs, glyph2unicode[t], error);
339                 omit = 2;
340
341 #if 0
342                 if(!has_had_errors) {
343                     char buf[256];
344                     if(fontname && *fontname) {
345                         fprintf(stderr, "font has been copied to %s.ttf\n", fontname);
346                         sprintf(buf, "cp %s %s.ttf", filename, fontname);
347                     } else {
348                         fprintf(stderr, "font has been copied to badfont%d.ttf\n", errorno);
349                         sprintf(buf, "cp %s badfont%d.ttf", filename, errorno);
350                         errorno++;
351                     }
352                     system(buf);
353                 }
354 #endif
355                 has_had_errors = 1;
356             }
357         }
358         if(!omit) {
359             error = FT_Get_Glyph(face->glyph, &glyph);
360             if(error) {
361                 fprintf(stderr, "Couldn't get glyph %d/%d, error:%d\n", t, face->num_glyphs, error);
362                 omit = 3;
363             }
364         }
365
366         if(!omit) {
367             gfxline_t*l;
368             int ok=0;
369             gfxdrawer_target_gfxline(&draw);
370             info.draw = &draw;
371             info.quality = quality;
372
373             //error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &info);
374             error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &info);
375             
376             if(error) {
377                 fprintf(stderr, "Couldn't decompose glyph %d\n", t);
378                 gfxline_free((gfxline_t*)draw.result(&draw));
379                 FT_Done_Glyph(glyph);
380                 omit = 4;
381             } else {
382                 font->glyphs[font->num_glyphs].advance = glyph->advance.x/65536;
383                 font->glyphs[font->num_glyphs].line = (gfxline_t*)draw.result(&draw);
384             }
385             l = font->glyphs[font->num_glyphs].line;
386             while(l) {
387                 if(l->type != gfx_moveTo) {
388                     ok = 1;
389                 }
390                 l = l->next;
391             }
392             if(!ok && !name) {
393                 gfxline_free(font->glyphs[font->num_glyphs].line);
394                 font->glyphs[font->num_glyphs].line = 0;
395                 font->glyphs[font->num_glyphs].advance = 0;
396
397                 /* Some PDFs created e.g. by InDesign tend to create
398                    fonts with reduced (empty) characters, which still
399                    have unicode indices attached to them.
400                    Remove that information, in order to not confuse
401                    any converter applications.
402                     */
403                 font->glyphs[font->num_glyphs].unicode = 0;
404                 if(font->glyphs[font->num_glyphs].name) {
405                     free((void*)font->glyphs[font->num_glyphs].name);
406                     font->glyphs[font->num_glyphs].name = 0;
407                 }
408                 FT_Done_Glyph(glyph);
409                 omit = 5;
410             }
411         }
412
413         if(!omit) {
414             FT_Done_Glyph(glyph);
415             font->glyphs[font->num_glyphs].unicode = glyph2unicode[t];
416         }
417
418         glyph2glyph[t] = font->num_glyphs;
419         font->num_glyphs++;
420     }
421
422     /* notice: if skip_unused is true, font->glyph2unicode, font->glyphnames and font->layout->bounds will 
423                have more memory allocated than just font->num_glyphs, but only the first font->numchars 
424                are used/valid */
425
426     for(t=0;t<font->max_unicode;t++) {
427         if(font->unicode2glyph[t]>=0) {
428             font->unicode2glyph[t] = glyph2glyph[font->unicode2glyph[t]];
429         }
430     }
431     rfx_free(glyph2glyph);
432     rfx_free(glyph2unicode);
433
434     FT_Done_Face(face);
435     FT_Done_FreeType(ftlibrary);ftlibrary=0;
436  
437     if(!isunicode && font->num_glyphs>0 && font->max_unicode) {
438         /* if the encoding isn't unicode, remap the font
439            so that the encoding equals the char position, and
440            remove the unicode table */
441         int t;
442         gfxglyph_t*newglyphs = (gfxglyph_t*)rfx_calloc(font->max_unicode*sizeof(gfxglyph_t));
443
444         for(t=0;t<max_unicode;t++) {
445             int c = font->unicode2glyph[t];
446             if(c>=font->num_glyphs || c<0)
447                 c = 0;
448             newglyphs[t] = cloneGlyph(&font->glyphs[c]);
449             newglyphs[t].unicode = -1;
450         }
451         for(t=0;t<font->num_glyphs;t++) {
452             glyph_clear(&font->glyphs[t]);
453         }
454         free(font->glyphs);
455         font->glyphs = newglyphs;
456         font->num_glyphs = font->max_unicode;
457
458         free(font->unicode2glyph);font->unicode2glyph = 0;
459         font->max_unicode = 0;
460     }
461
462     if(font->unicode2glyph) {
463         int t;
464         int bad = 0;
465         /* check whether the Unicode indices look o.k.
466            If they don't, disable the unicode lookup by setting
467            the unicode map to -1 everywhere */
468         for(t=0;t<font->num_glyphs;t++) {
469             int c = font->glyphs[t].unicode;
470             gfxline_t* line = font->glyphs[t].line;
471             if(c && c < 32 && (line && line->next && line->next->next)) {
472                 // the character maps into the unicode control character range
473                 // between 0001-001f. Yet it is not empty. Treat the one
474                 // mapping as broken, and look how many of those we find.
475                 bad ++;
476             }
477         }
478         if(bad>5) {
479             free(font->unicode2glyph);font->unicode2glyph = 0;
480             font->max_unicode = 0;
481             for(t=0;t<font->num_glyphs;t++) {
482                 font->glyphs[t].unicode = -1;
483             }
484         }
485     }
486
487     return font;
488 }
489 #else
490
491 gfxfont_t* gfxfont_load(char*filename)
492 {
493     fprintf(stderr, "No freetype support compiled in! Not able to load %s\n", filename);
494 }
495
496 #endif
497
498 void gfxfont_free(gfxfont_t*font)
499 {
500     int t;
501     for(t=0;t<font->num_glyphs;t++) {
502         glyph_clear(&font->glyphs[t]);
503     }
504     if(font->glyphs) {
505         free(font->glyphs);font->glyphs = 0;
506     }
507     font->num_glyphs = 0;
508     if(font->unicode2glyph) {
509         free(font->unicode2glyph);font->unicode2glyph = 0;
510     }
511     free(font);
512 }
513