3 Functions for loading external fonts.
5 Extension module for the rfxswf library.
6 Part of the swftools package.
8 Copyright (c) 2003, 2004, 2005 Matthias Kramm
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.
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.
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 */
24 #include "../config.h"
25 #include "gfxdevice.h"
28 static int loadfont_scale = 64;
29 static int full_unicode = 1;
33 #ifdef HAVE_FT2BUILD_H
35 #include FT_FREETYPE_H
38 #include FT_SFNT_NAMES_H
39 #include FT_TRUETYPE_IDS_H
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>
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 */
56 #define FT_SUBPIXELS 64
58 typedef struct _gfxdrawinfo_t {
63 static int ft_move_to(FT_Vector* _to, void* user)
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);
72 static int ft_line_to(FT_Vector* _to, void* user)
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);
81 static int ft_cubic_to(FT_Vector* _c1, FT_Vector* _c2, FT_Vector* _to, void* user)
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);
94 static int ft_conic_to(FT_Vector* _c, FT_Vector* _to, void* user)
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);
105 static FT_Outline_Funcs outline_functions =
114 static FT_Library ftlibrary = 0;
116 static gfxglyph_t cloneGlyph(gfxglyph_t*src)
119 memset(&dest, 0, sizeof(dest));
121 dest.name = strdup(src->name);
122 dest.advance = src->advance;
123 dest.unicode = src->unicode;
124 dest.line = gfxline_clone(src->line);
128 static void glyph_clear(gfxglyph_t*g)
132 free(g->name); g->name = 0;
134 gfxline_free(g->line);g->line = 0;
137 static int errorno = 0;
139 gfxfont_t* gfxfont_load(char*filename, double quality)
143 const char* fontname = 0;
149 int*glyph2unicode = 0;
154 int has_had_errors = 0;
157 if(FT_Init_FreeType(&ftlibrary)) {
158 fprintf(stderr, "Couldn't init freetype library!\n");
162 error = FT_New_Face(ftlibrary, filename, 0, &face);
163 FT_Set_Pixel_Sizes (face, 16*loadfont_scale, 16*loadfont_scale);
166 fprintf(stderr, "Couldn't load file %s- not a TTF file?\n", filename);
169 if(face->num_glyphs <= 0) {
170 fprintf(stderr, "File %s contains %d glyphs\n", face->num_glyphs);
174 font = rfx_calloc(sizeof(gfxfont_t));
175 //font->style = ((face->style_flags&FT_STYLE_FLAG_ITALIC)?FONT_STYLE_ITALIC:0) |((face->style_flags&FT_STYLE_FLAG_BOLD)?FONT_STYLE_BOLD:0);
176 //font->ascent = abs(face->ascender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMin;
177 //font->descent = abs(face->descender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMax;
178 //font->leading = font->layout->ascent + font->layout->descent;
179 //font->encoding = FONT_ENCODING_UNICODE;
180 font->max_unicode = 0;
182 font->glyphs = rfx_calloc(face->num_glyphs*sizeof(gfxglyph_t));
183 glyph2unicode = rfx_calloc(face->num_glyphs*sizeof(int));
184 glyph2glyph = rfx_calloc(face->num_glyphs*sizeof(int));
186 if(FT_HAS_GLYPH_NAMES(face)) {
187 //font->glyphnames = rfx_calloc(face->num_glyphs*sizeof(char*));
190 fontname = FT_Get_Postscript_Name(face);
194 charcode = FT_Get_First_Char(face, &gindex);
197 if(gindex >= 0 && gindex<face->num_glyphs) {
198 if(!glyph2unicode[gindex]) {
199 glyph2unicode[gindex] = charcode;
200 if(charcode + 1 > font->max_unicode) {
201 font->max_unicode = charcode + 1;
205 charcode = FT_Get_Next_Char(face, charcode, &gindex);
208 /* if we didn't find a single encoding character, try
209 the font's charmaps instead. That usually means that
210 the encoding is no longer unicode.
211 TODO: find a way to convert the encoding to unicode
213 if(font->max_unicode == 0 && charmap < face->num_charmaps - 1) {
215 FT_Set_Charmap(face, face->charmaps[charmap]);
216 //font->encoding = 0;//anything but unicode FIXME
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 */
226 font->max_unicode = 65535;
228 font->unicode2glyph = rfx_calloc(font->max_unicode*sizeof(int));
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)
234 font->unicode2glyph[t] = g;
237 if(!glyph2unicode[g]) {
238 glyph2unicode[g] = t;
242 font->max_unicode = max_unicode;
244 font->num_glyphs = 0;
246 for(t=0; t < face->num_glyphs; t++) {
258 font->glyphs[font->num_glyphs].advance = 0;
259 font->glyphs[font->num_glyphs].line = 0;
260 font->glyphs[font->num_glyphs].unicode = glyph2unicode[t];
261 font->glyphs[font->num_glyphs].name = 0;
263 if(FT_HAS_GLYPH_NAMES(face)) {
264 error = FT_Get_Glyph_Name(face, t, name, 127);
265 if(!error && name[0] && !strstr(name, "notdef")) {
266 font->glyphs[font->num_glyphs].name = strdup(name);
270 if(has_had_errors && (isunicode && !glyph2unicode[t]) && !hasname) {
271 /* some freetype versions crash or corrupt memory if we try to load
272 characters (without unicode index or name) above 256 for some fonts.
273 So skip those characters once the first error occured */
277 error = FT_Load_Glyph(face, t, FT_LOAD_NO_BITMAP);
280 fprintf(stderr, "Warning: glyph %d/%d (unicode %d, name %s) has return code %d\n", t, face->num_glyphs, glyph2unicode[t], name, error);
282 fprintf(stderr, "Warning: glyph %d/%d (unicode %d) has return code %d\n", t, face->num_glyphs, glyph2unicode[t], error);
286 if(!has_had_errors) {
288 if(fontname && *fontname) {
289 fprintf(stderr, "font has been copied to %s.ttf\n", fontname);
290 sprintf(buf, "cp %s %s.ttf", filename, fontname);
292 fprintf(stderr, "font has been copied to badfont%d.ttf\n", errorno);
293 sprintf(buf, "cp %s badfont%d.ttf", filename, errorno);
303 error = FT_Get_Glyph(face->glyph, &glyph);
305 fprintf(stderr, "Couldn't get glyph %d/%d, error:%d\n", t, face->num_glyphs, error);
311 gfxdrawer_target_gfxline(&draw);
313 info.quality = quality;
315 //error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &info);
316 error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &info);
319 fprintf(stderr, "Couldn't decompose glyph %d\n", t);
320 gfxline_free((gfxline_t*)draw.result(&draw));
321 FT_Done_Glyph(glyph);
324 font->glyphs[font->num_glyphs].advance = glyph->advance.x*20/65536;
325 font->glyphs[font->num_glyphs].line = (gfxline_t*)draw.result(&draw);
330 FT_Done_Glyph(glyph);
332 glyph2glyph[t] = font->num_glyphs;
336 /* notice: if skip_unused is true, font->glyph2unicode, font->glyphnames and font->layout->bounds will
337 have more memory allocated than just font->num_glyphs, but only the first font->numchars
340 for(t=0;t<font->max_unicode;t++) {
341 if(font->unicode2glyph[t]>=0) {
342 font->unicode2glyph[t] = glyph2glyph[font->unicode2glyph[t]];
345 rfx_free(glyph2glyph);
346 rfx_free(glyph2unicode);
349 FT_Done_FreeType(ftlibrary);ftlibrary=0;
351 if(!isunicode && font->num_glyphs>0) {
352 /* if the encoding isn't unicode, remap the font
353 so that the encoding equals the char position, and
354 remove the unicode table */
356 gfxglyph_t*newglyphs = rfx_calloc(font->max_unicode*sizeof(gfxglyph_t));
358 for(t=0;t<max_unicode;t++) {
359 int c = font->unicode2glyph[t];
360 if(c>=font->num_glyphs || c<0)
362 newglyphs[t] = cloneGlyph(&font->glyphs[c]);
363 newglyphs[t].unicode = -1;
365 for(t=0;t<font->num_glyphs;t++) {
366 glyph_clear(&font->glyphs[t]);
369 font->glyphs = newglyphs;
370 font->num_glyphs = font->max_unicode;
372 free(font->unicode2glyph);font->unicode2glyph = 0;
373 font->max_unicode = 0;
376 if(font->unicode2glyph) {
379 /* check whether the Unicode indices look o.k.
380 If they don't, disable the unicode lookup by setting
381 the unicode map to -1 everywhere */
382 for(t=0;t<font->num_glyphs;t++) {
383 int c = font->glyphs[t].unicode;
384 gfxline_t* line = font->glyphs[t].line;
385 if(c && c < 32 && (line && line->next && line->next->next)) {
386 // the character maps into the unicode control character range
387 // between 0001-001f. Yet it is not empty. Treat the one
388 // mapping as broken, and look how many of those we find.
393 free(font->unicode2glyph);font->unicode2glyph = 0;
394 font->max_unicode = 0;
395 for(t=0;t<font->num_glyphs;t++) {
396 font->glyphs[t].unicode = -1;
405 gfxfont_t* gfxfont_load(char*filename)
407 fprintf(stderr, "No freetype support compiled in! Not able to load %s\n", filename);
412 void gfxfont_free(gfxfont_t*font)
415 for(t=0;t<font->num_glyphs;t++) {
416 glyph_clear(&font->glyphs[t]);
419 free(font->glyphs);font->glyphs = 0;
421 font->num_glyphs = 0;
422 if(font->unicode2glyph) {
423 free(font->unicode2glyph);font->unicode2glyph = 0;