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