added quality parameter to gfxdraw_cubicTo()
[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 "gfxdevice.h"
25 #include "gfxtools.h"
26
27 static int loadfont_scale = 64;
28 static int skip_unused = 0;
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 void gfxfont_free(gfxfont_t*font)
138 {
139     int t;
140     for(t=0;t<font->num_glyphs;t++) {
141         glyph_clear(&font->glyphs[t]);
142     }
143     if(font->glyphs) {
144         free(font->glyphs);font->glyphs = 0;
145     }
146     font->num_glyphs = 0;
147     if(font->unicode2glyph) {
148         free(font->unicode2glyph);font->unicode2glyph = 0;
149     }
150     free(font);
151 }
152
153 gfxfont_t* gfxfont_load(char*filename, double quality)
154 {
155     FT_Face face;
156     FT_Error error;
157     const char* name = 0;
158     FT_ULong charcode;
159     FT_UInt gindex;
160     gfxfont_t* font;
161     int t;
162     int*glyph2glyph = 0;
163     int*glyph2unicode = 0;
164     FT_Size size;
165     int max_unicode = 0;
166     int charmap = -1;
167     int isunicode = 1;
168    
169     if(ftlibrary == 0) {
170         if(FT_Init_FreeType(&ftlibrary)) {
171             fprintf(stderr, "Couldn't init freetype library!\n");
172             exit(1);
173         }
174     }
175     error = FT_New_Face(ftlibrary, filename, 0, &face);
176     FT_Set_Pixel_Sizes (face, 16*loadfont_scale, 16*loadfont_scale);
177
178     if(error) {
179         fprintf(stderr, "Couldn't load file %s- not a TTF file?\n", filename);
180         return 0;
181     }
182     if(face->num_glyphs <= 0) {
183         fprintf(stderr, "File %s contains %d glyphs\n", face->num_glyphs);
184         return 0;
185     }
186
187     font = rfx_calloc(sizeof(gfxfont_t));
188     //font->style =  ((face->style_flags&FT_STYLE_FLAG_ITALIC)?FONT_STYLE_ITALIC:0) |((face->style_flags&FT_STYLE_FLAG_BOLD)?FONT_STYLE_BOLD:0);
189     //font->ascent = abs(face->ascender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMin;
190     //font->descent = abs(face->descender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMax;
191     //font->leading = font->layout->ascent + font->layout->descent;
192     //font->encoding = FONT_ENCODING_UNICODE;
193     font->max_unicode = 0;
194     
195     font->glyphs = rfx_calloc(face->num_glyphs*sizeof(gfxglyph_t));
196     glyph2unicode = rfx_calloc(face->num_glyphs*sizeof(int));
197     glyph2glyph = rfx_calloc(face->num_glyphs*sizeof(int));
198
199     if(FT_HAS_GLYPH_NAMES(face)) {
200         //font->glyphnames = rfx_calloc(face->num_glyphs*sizeof(char*));
201     }
202
203     /*name = FT_Get_Postscript_Name(face);
204     if(name && *name)
205         font->name = strdup(name);*/
206
207     while(1) 
208     {
209         charcode = FT_Get_First_Char(face, &gindex);
210         while(gindex != 0)
211         {
212             if(gindex >= 0 && gindex<face->num_glyphs) {
213                 if(!glyph2unicode[gindex]) {
214                     glyph2unicode[gindex] = charcode;
215                     if(charcode + 1 > font->max_unicode) {
216                         font->max_unicode = charcode + 1;
217                     }
218                 }
219             }
220             charcode = FT_Get_Next_Char(face, charcode, &gindex);
221         }
222
223         /* if we didn't find a single encoding character, try
224            the font's charmaps instead. That usually means that
225            the encoding is no longer unicode. 
226            TODO: find a way to convert the encoding to unicode
227          */
228         if(font->max_unicode == 0 && charmap < face->num_charmaps - 1) {
229             charmap++;
230             FT_Set_Charmap(face, face->charmaps[charmap]);
231             //font->encoding = 0;//anything but unicode FIXME
232             isunicode = 0;
233         } else 
234             break;
235     }
236
237     /* TODO: if isunicode is 1, we now need to permutate the character
238              order so that each character is at it's encoding position */
239
240     if(full_unicode)
241         font->max_unicode = 65535;
242     
243     font->unicode2glyph = rfx_calloc(font->max_unicode*sizeof(int));
244     
245     for(t=0;t<font->max_unicode;t++) {
246         int g = FT_Get_Char_Index(face, t);
247         if(!g || g>=face->num_glyphs)
248             g = -1;
249         font->unicode2glyph[t] = g;
250         if(g>=0) {
251             max_unicode = t+1;
252             if(!glyph2unicode[g]) {
253                 glyph2unicode[g] = t;
254             }
255         }
256     }
257     font->max_unicode = max_unicode;
258
259     font->num_glyphs = 0;
260
261     for(t=0; t < face->num_glyphs; t++) {
262         FT_Glyph glyph;
263         FT_BBox bbox;
264         FT_Matrix matrix;
265         char name[128];
266         gfxdrawer_t draw;
267         gfxdrawinfo_t info;
268         int ret;
269         char hasname = 0;
270         name[0]=0;
271         if(FT_HAS_GLYPH_NAMES(face)) {
272             error = FT_Get_Glyph_Name(face, t, name, 127);
273             if(!error && name[0] && !strstr(name, "notdef")) {
274                 font->glyphs[font->num_glyphs].name = strdup(name);
275                 hasname = 1;
276             }
277         }
278         if(!glyph2unicode[t] && !hasname && skip_unused) {
279             continue;
280         }
281         error = FT_Load_Glyph(face, t, FT_LOAD_NO_BITMAP);
282         if(error) {
283             fprintf(stderr, "Couldn't load glyph %d, error:%d\n", t, error);
284             continue;
285         }
286         error = FT_Get_Glyph(face->glyph, &glyph);
287         if(error) {
288             fprintf(stderr, "Couldn't get glyph %d, error:%d\n", t, error);
289             continue;
290         }
291
292         FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_unscaled, &bbox);
293         bbox.yMin = -bbox.yMin;
294         bbox.yMax = -bbox.yMax;
295         if(bbox.xMax < bbox.xMin) {
296             // swap
297             bbox.xMax ^= bbox.xMin;
298             bbox.xMin ^= bbox.xMax;
299             bbox.xMax ^= bbox.xMin;
300         }
301         if(bbox.yMax < bbox.yMin) {
302             // swap
303             bbox.yMax ^= bbox.yMin;
304             bbox.yMin ^= bbox.yMax;
305             bbox.yMax ^= bbox.yMin;
306         }
307
308         gfxdrawer_target_gfxline(&draw);
309         info.draw = &draw;
310         info.quality = quality;
311
312         //error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &info);
313         error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &info);
314         
315         if(error) {
316             fprintf(stderr, "Couldn't decompose glyph %d\n", t);
317             gfxline_free((gfxline_t*)draw.result(&draw));
318             continue;
319         }
320
321 #if 0
322         if(bbox.xMin > 0) {
323             font->glyph[font->num_glyphs].advance = (bbox.xMax*20*FT_SCALE)/FT_SUBPIXELS;
324         } else {
325             font->glyph[font->num_glyphs].advance = ((bbox.xMax - bbox.xMin)*20*FT_SCALE)/FT_SUBPIXELS;
326         }
327 #else
328         font->glyphs[font->num_glyphs].advance = glyph->advance.x*20/65536;
329 #endif
330         
331         font->glyphs[font->num_glyphs].line = (gfxline_t*)draw.result(&draw);
332         
333         /*font->glyphs[font->num_glyphs].bbox.xmin = (bbox.xMin*FT_SCALE*20)/FT_SUBPIXELS;
334         font->glyphs[font->num_glyphs].bbox.ymin = (bbox.yMin*FT_SCALE*20)/FT_SUBPIXELS;
335         font->glyphs[font->num_glyphs].bbox.xmax = (bbox.xMax*FT_SCALE*20)/FT_SUBPIXELS;
336         font->glyphs[font->num_glyphs].bbox.ymax = (bbox.yMax*FT_SCALE*20)/FT_SUBPIXELS;*/
337
338         FT_Done_Glyph(glyph);
339         font->glyphs[font->num_glyphs].unicode = glyph2unicode[t];
340         glyph2glyph[t] = font->num_glyphs;
341         font->num_glyphs++;
342     }
343     /* notice: if skip_unused is true, font->glyph2unicode, font->glyphnames and font->layout->bounds will 
344                have more memory allocated than just font->num_glyphs, but only the first font->numchars 
345                are used/valid */
346
347     for(t=0;t<font->max_unicode;t++) {
348         if(font->unicode2glyph[t]>=0) {
349             font->unicode2glyph[t] = glyph2glyph[font->unicode2glyph[t]];
350         }
351     }
352     rfx_free(glyph2glyph);
353     rfx_free(glyph2unicode);
354
355     FT_Done_Face(face);
356     FT_Done_FreeType(ftlibrary);ftlibrary=0;
357   
358     if(!isunicode && font->num_glyphs>0) {
359         /* if the encoding isn't unicode, remap the font
360            so that the encoding equals the char position, and
361            remove the unicode table */
362         int t;
363         gfxglyph_t*newglyphs = rfx_calloc(font->max_unicode*sizeof(gfxglyph_t));
364
365         for(t=0;t<max_unicode;t++) {
366             int c = font->unicode2glyph[t];
367             if(c>=font->num_glyphs || c<0)
368                 c = 0;
369             newglyphs[t] = cloneGlyph(&font->glyphs[c]);
370             newglyphs[t].unicode = -1;
371         }
372         for(t=0;t<font->num_glyphs;t++) {
373             glyph_clear(&font->glyphs[t]);
374         }
375         free(font->glyphs);
376         font->glyphs = newglyphs;
377         font->num_glyphs = font->max_unicode;
378
379         free(font->unicode2glyph);font->unicode2glyph = 0;
380         font->max_unicode = 0;
381     }
382
383     if(font->unicode2glyph) {
384         int t;
385         int bad = 0;
386         /* check whether the Unicode indices look o.k.
387            If they don't, disable the unicode lookup by setting
388            the unicode map to -1 everywhere */
389         for(t=0;t<font->num_glyphs;t++) {
390             int c = font->glyphs[t].unicode;
391             gfxline_t* line = font->glyphs[t].line;
392             if(c && c < 32 && (line && line->next && line->next->next)) {
393                 // the character maps into the unicode control character range
394                 // between 0001-001f. Yet it is not empty. Treat the one
395                 // mapping as broken, and look how many of those we find.
396                 bad ++;
397             }
398         }
399         if(bad>5) {
400             free(font->unicode2glyph);font->unicode2glyph = 0;
401             font->max_unicode = 0;
402             for(t=0;t<font->num_glyphs;t++) {
403                 font->glyphs[t].unicode = -1;
404             }
405         }
406     }
407
408     return font;
409 }
410 #else
411
412 gfxfont_t* gfxfont_load(char*filename)
413 {
414     fprintf(stderr, "No freetype support compiled in! Not able to load %s\n", filename);
415 }
416
417 #endif
418