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(const 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(const 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(const FT_Vector* _c1, const FT_Vector* _c2, const 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(const FT_Vector* _c, const 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((void*)g->name); g->name = 0;
134 gfxline_free(g->line);g->line = 0;
137 static int errorno = 0;
139 gfxfont_t* gfxfont_load(char*id, char*filename, double quality)
143 const char* fontname = 0;
149 int*glyph2unicode = 0;
154 int has_had_errors = 0;
158 if(FT_Init_FreeType(&ftlibrary)) {
159 fprintf(stderr, "Couldn't init freetype library!\n");
163 error = FT_New_Face(ftlibrary, filename, 0, &face);
164 FT_Set_Pixel_Sizes (face, 16*loadfont_scale, 16*loadfont_scale);
167 fprintf(stderr, "Couldn't load file %s- not a TTF file? (error=%02x)\n", filename, error);
170 if(face->num_glyphs <= 0) {
171 fprintf(stderr, "File %s contains %d glyphs\n", face->num_glyphs);
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);
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));
188 if(FT_HAS_GLYPH_NAMES(face)) {
189 //font->glyphnames = rfx_calloc(face->num_glyphs*sizeof(char*));
192 fontname = FT_Get_Postscript_Name(face);
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
206 charcode = FT_Get_First_Char(face, &gindex);
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
217 printf("ENCODING: NONE (%d of %d)\n",
218 charmap, face->num_charmaps
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;
232 charcode = FT_Get_Next_Char(face, charcode, &gindex);
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
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 */
246 FT_Set_Charmap(face, face->charmaps[charmap]);
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 */
255 font->max_unicode = 65535;
257 font->unicode2glyph = rfx_calloc(font->max_unicode*sizeof(int));
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)
263 font->unicode2glyph[t] = g;
266 if(!glyph2unicode[g]) {
267 glyph2unicode[g] = t;
271 font->max_unicode = max_unicode;
273 font->num_glyphs = 0;
276 for(t=0; t < face->num_glyphs; t++) {
277 if(FT_HAS_GLYPH_NAMES(face)) {
279 error = FT_Get_Glyph_Name(face, t, name, 127);
280 if(!error && name[0] && !strstr(name, "notdef")) {
287 for(t=0; t < face->num_glyphs; t++) {
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;
304 if(FT_HAS_GLYPH_NAMES(face) && (num_names >= face->num_glyphs/10 || num_names > 2)) {
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);
313 #if 0 // some cantonese pdfs fail to work if this is activated
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 */
324 error = FT_Load_Glyph(face, t, FT_LOAD_NO_BITMAP);
327 fprintf(stderr, "Warning: glyph %d/%d (unicode %d, name %s) has return code %d\n", t, face->num_glyphs, glyph2unicode[t], name, error);
329 fprintf(stderr, "Warning: glyph %d/%d (unicode %d) has return code %d\n", t, face->num_glyphs, glyph2unicode[t], error);
333 if(!has_had_errors) {
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);
339 fprintf(stderr, "font has been copied to badfont%d.ttf\n", errorno);
340 sprintf(buf, "cp %s badfont%d.ttf", filename, errorno);
350 error = FT_Get_Glyph(face->glyph, &glyph);
352 fprintf(stderr, "Couldn't get glyph %d/%d, error:%d\n", t, face->num_glyphs, error);
360 gfxdrawer_target_gfxline(&draw);
362 info.quality = quality;
364 //error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &info);
365 error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &info);
368 fprintf(stderr, "Couldn't decompose glyph %d\n", t);
369 gfxline_free((gfxline_t*)draw.result(&draw));
370 FT_Done_Glyph(glyph);
373 font->glyphs[font->num_glyphs].advance = glyph->advance.x/65536;
374 font->glyphs[font->num_glyphs].line = (gfxline_t*)draw.result(&draw);
376 l = font->glyphs[font->num_glyphs].line;
378 if(l->type != gfx_moveTo) {
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;
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.
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;
399 FT_Done_Glyph(glyph);
405 FT_Done_Glyph(glyph);
406 font->glyphs[font->num_glyphs].unicode = glyph2unicode[t];
409 glyph2glyph[t] = font->num_glyphs;
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
417 for(t=0;t<font->max_unicode;t++) {
418 if(font->unicode2glyph[t]>=0) {
419 font->unicode2glyph[t] = glyph2glyph[font->unicode2glyph[t]];
422 rfx_free(glyph2glyph);
423 rfx_free(glyph2unicode);
426 FT_Done_FreeType(ftlibrary);ftlibrary=0;
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 */
433 gfxglyph_t*newglyphs = rfx_calloc(font->max_unicode*sizeof(gfxglyph_t));
435 for(t=0;t<max_unicode;t++) {
436 int c = font->unicode2glyph[t];
437 if(c>=font->num_glyphs || c<0)
439 newglyphs[t] = cloneGlyph(&font->glyphs[c]);
440 newglyphs[t].unicode = -1;
442 for(t=0;t<font->num_glyphs;t++) {
443 glyph_clear(&font->glyphs[t]);
446 font->glyphs = newglyphs;
447 font->num_glyphs = font->max_unicode;
449 free(font->unicode2glyph);font->unicode2glyph = 0;
450 font->max_unicode = 0;
453 if(font->unicode2glyph) {
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.
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;
482 gfxfont_t* gfxfont_load(char*filename)
484 fprintf(stderr, "No freetype support compiled in! Not able to load %s\n", filename);
489 void gfxfont_free(gfxfont_t*font)
492 for(t=0;t<font->num_glyphs;t++) {
493 glyph_clear(&font->glyphs[t]);
496 free(font->glyphs);font->glyphs = 0;
498 font->num_glyphs = 0;
499 if(font->unicode2glyph) {
500 free(font->unicode2glyph);font->unicode2glyph = 0;