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 "gfxdevice.h"
27 static int loadfont_scale = 64;
28 static int skip_unused = 0;
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 static int ft_move_to(FT_Vector* _to, void* user)
60 gfxdrawer_t* draw = (gfxdrawer_t*)user;
61 double x = _to->x*FT_SCALE/(float)FT_SUBPIXELS;
62 double y = -_to->y*FT_SCALE/(float)FT_SUBPIXELS;
63 draw->moveTo(draw, x,y);
66 static int ft_line_to(FT_Vector* _to, void* user)
68 gfxdrawer_t* draw = (gfxdrawer_t*)user;
69 double x = _to->x*FT_SCALE/(float)FT_SUBPIXELS;
70 double y = -_to->y*FT_SCALE/(float)FT_SUBPIXELS;
71 draw->lineTo(draw, x,y);
74 static int ft_cubic_to(FT_Vector* _c1, FT_Vector* _c2, FT_Vector* _to, void* user)
76 gfxdrawer_t* draw = (gfxdrawer_t*)user;
77 double tox = _to->x*FT_SCALE/(float)FT_SUBPIXELS;
78 double toy = -_to->y*FT_SCALE/(float)FT_SUBPIXELS;
79 double c1x = _c1->x*FT_SCALE/(float)FT_SUBPIXELS;
80 double c1y = -_c1->y*FT_SCALE/(float)FT_SUBPIXELS;
81 double c2x = _c2->x*FT_SCALE/(float)FT_SUBPIXELS;
82 double c2y = -_c2->y*FT_SCALE/(float)FT_SUBPIXELS;
83 gfxdraw_cubicTo(draw, c1x, c1y, c2x, c2y, tox, toy);
86 static int ft_conic_to(FT_Vector* _c, FT_Vector* _to, void* user)
88 gfxdrawer_t* draw = (gfxdrawer_t*)user;
89 double tox = _to->x*FT_SCALE/(float)FT_SUBPIXELS;
90 double toy = -_to->y*FT_SCALE/(float)FT_SUBPIXELS;
91 double cx = _c->x*FT_SCALE/(float)FT_SUBPIXELS;
92 double cy = -_c->y*FT_SCALE/(float)FT_SUBPIXELS;
93 gfxdraw_conicTo(draw, cx,cy, tox,toy);
96 static FT_Outline_Funcs outline_functions =
105 static FT_Library ftlibrary = 0;
107 static gfxglyph_t cloneGlyph(gfxglyph_t*src)
110 memset(&dest, 0, sizeof(dest));
112 dest.name = strdup(src->name);
113 dest.advance = src->advance;
114 dest.unicode = src->unicode;
115 dest.line = gfxline_clone(src->line);
119 static void glyph_clear(gfxglyph_t*g)
123 free(g->name); g->name = 0;
125 gfxline_free(g->line);g->line = 0;
128 void gfxfont_free(gfxfont_t*font)
131 for(t=0;t<font->num_glyphs;t++) {
132 glyph_clear(&font->glyphs[t]);
135 free(font->glyphs);font->glyphs = 0;
137 font->num_glyphs = 0;
138 if(font->unicode2glyph) {
139 free(font->unicode2glyph);font->unicode2glyph = 0;
144 gfxfont_t* gfxfont_load(char*filename)
148 const char* name = 0;
154 int*glyph2unicode = 0;
161 if(FT_Init_FreeType(&ftlibrary)) {
162 fprintf(stderr, "Couldn't init freetype library!\n");
166 error = FT_New_Face(ftlibrary, filename, 0, &face);
167 FT_Set_Pixel_Sizes (face, 16*loadfont_scale, 16*loadfont_scale);
170 fprintf(stderr, "Couldn't load file %s- not a TTF file?\n", filename);
173 if(face->num_glyphs <= 0) {
174 fprintf(stderr, "File %s contains %d glyphs\n", face->num_glyphs);
178 font = rfx_calloc(sizeof(gfxfont_t));
179 //font->style = ((face->style_flags&FT_STYLE_FLAG_ITALIC)?FONT_STYLE_ITALIC:0) |((face->style_flags&FT_STYLE_FLAG_BOLD)?FONT_STYLE_BOLD:0);
180 //font->ascent = abs(face->ascender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMin;
181 //font->descent = abs(face->descender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMax;
182 //font->leading = font->layout->ascent + font->layout->descent;
183 //font->encoding = FONT_ENCODING_UNICODE;
184 font->max_unicode = 0;
186 font->glyphs = rfx_calloc(face->num_glyphs*sizeof(gfxglyph_t));
187 glyph2unicode = rfx_calloc(face->num_glyphs*sizeof(int));
188 glyph2glyph = rfx_calloc(face->num_glyphs*sizeof(int));
190 if(FT_HAS_GLYPH_NAMES(face)) {
191 //font->glyphnames = rfx_calloc(face->num_glyphs*sizeof(char*));
194 /*name = FT_Get_Postscript_Name(face);
196 font->name = strdup(name);*/
200 charcode = FT_Get_First_Char(face, &gindex);
203 if(gindex >= 0 && gindex<face->num_glyphs) {
204 if(!glyph2unicode[gindex]) {
205 glyph2unicode[gindex] = charcode;
206 if(charcode + 1 > font->max_unicode) {
207 font->max_unicode = charcode + 1;
211 charcode = FT_Get_Next_Char(face, charcode, &gindex);
214 /* if we didn't find a single encoding character, try
215 the font's charmaps instead. That usually means that
216 the encoding is no longer unicode.
217 TODO: find a way to convert the encoding to unicode
219 if(font->max_unicode == 0 && charmap < face->num_charmaps - 1) {
221 FT_Set_Charmap(face, face->charmaps[charmap]);
222 //font->encoding = 0;//anything but unicode FIXME
228 /* TODO: if isunicode is 1, we now need to permutate the character
229 order so that each character is at it's encoding position */
232 font->max_unicode = 65535;
234 font->unicode2glyph = rfx_calloc(font->max_unicode*sizeof(int));
236 for(t=0;t<font->max_unicode;t++) {
237 int g = FT_Get_Char_Index(face, t);
238 if(!g || g>=face->num_glyphs)
240 font->unicode2glyph[t] = g;
243 if(!glyph2unicode[g]) {
244 glyph2unicode[g] = t;
248 font->max_unicode = max_unicode;
250 font->num_glyphs = 0;
252 for(t=0; t < face->num_glyphs; t++) {
261 if(FT_HAS_GLYPH_NAMES(face)) {
262 error = FT_Get_Glyph_Name(face, t, name, 127);
263 if(!error && name[0] && !strstr(name, "notdef")) {
264 font->glyphs[font->num_glyphs].name = strdup(name);
268 if(!glyph2unicode[t] && !hasname && skip_unused) {
271 error = FT_Load_Glyph(face, t, FT_LOAD_NO_BITMAP);
273 fprintf(stderr, "Couldn't load glyph %d, error:%d\n", t, error);
276 error = FT_Get_Glyph(face->glyph, &glyph);
278 fprintf(stderr, "Couldn't get glyph %d, error:%d\n", t, error);
282 FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_unscaled, &bbox);
283 bbox.yMin = -bbox.yMin;
284 bbox.yMax = -bbox.yMax;
285 if(bbox.xMax < bbox.xMin) {
287 bbox.xMax ^= bbox.xMin;
288 bbox.xMin ^= bbox.xMax;
289 bbox.xMax ^= bbox.xMin;
291 if(bbox.yMax < bbox.yMin) {
293 bbox.yMax ^= bbox.yMin;
294 bbox.yMin ^= bbox.yMax;
295 bbox.yMax ^= bbox.yMin;
298 gfxdrawer_target_gfxline(&draw);
300 //error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &draw);
301 error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &draw);
304 fprintf(stderr, "Couldn't decompose glyph %d\n", t);
305 gfxline_free((gfxline_t*)draw.result(&draw));
311 font->glyph[font->num_glyphs].advance = (bbox.xMax*20*FT_SCALE)/FT_SUBPIXELS;
313 font->glyph[font->num_glyphs].advance = ((bbox.xMax - bbox.xMin)*20*FT_SCALE)/FT_SUBPIXELS;
316 font->glyphs[font->num_glyphs].advance = glyph->advance.x*20/65536;
319 font->glyphs[font->num_glyphs].line = (gfxline_t*)draw.result(&draw);
321 /*font->glyphs[font->num_glyphs].bbox.xmin = (bbox.xMin*FT_SCALE*20)/FT_SUBPIXELS;
322 font->glyphs[font->num_glyphs].bbox.ymin = (bbox.yMin*FT_SCALE*20)/FT_SUBPIXELS;
323 font->glyphs[font->num_glyphs].bbox.xmax = (bbox.xMax*FT_SCALE*20)/FT_SUBPIXELS;
324 font->glyphs[font->num_glyphs].bbox.ymax = (bbox.yMax*FT_SCALE*20)/FT_SUBPIXELS;*/
326 FT_Done_Glyph(glyph);
327 font->glyphs[font->num_glyphs].unicode = glyph2unicode[t];
328 glyph2glyph[t] = font->num_glyphs;
331 /* notice: if skip_unused is true, font->glyph2unicode, font->glyphnames and font->layout->bounds will
332 have more memory allocated than just font->num_glyphs, but only the first font->numchars
335 for(t=0;t<font->max_unicode;t++) {
336 if(font->unicode2glyph[t]>=0) {
337 font->unicode2glyph[t] = glyph2glyph[font->unicode2glyph[t]];
340 rfx_free(glyph2glyph);
341 rfx_free(glyph2unicode);
344 FT_Done_FreeType(ftlibrary);ftlibrary=0;
346 if(!isunicode && font->num_glyphs>0) {
347 /* if the encoding isn't unicode, remap the font
348 so that the encoding equals the char position, and
349 remove the unicode table */
351 gfxglyph_t*newglyphs = rfx_calloc(font->max_unicode*sizeof(gfxglyph_t));
353 for(t=0;t<max_unicode;t++) {
354 int c = font->unicode2glyph[t];
355 if(c>=font->num_glyphs || c<0)
357 newglyphs[t] = cloneGlyph(&font->glyphs[c]);
358 newglyphs[t].unicode = -1;
360 for(t=0;t<font->num_glyphs;t++) {
361 glyph_clear(&font->glyphs[t]);
364 font->glyphs = newglyphs;
365 font->num_glyphs = font->max_unicode;
367 free(font->unicode2glyph);font->unicode2glyph = 0;
368 font->max_unicode = 0;
371 if(font->unicode2glyph) {
374 /* check whether the Unicode indices look o.k.
375 If they don't, disable the unicode lookup by setting
376 the unicode map to -1 everywhere */
377 for(t=0;t<font->num_glyphs;t++) {
378 int c = font->glyphs[t].unicode;
379 gfxline_t* line = font->glyphs[t].line;
380 if(c && c < 32 && (line && line->next && line->next->next)) {
381 // the character maps into the unicode control character range
382 // between 0001-001f. Yet it is not empty. Treat the one
383 // mapping as broken, and look how many of those we find.
388 free(font->unicode2glyph);font->unicode2glyph = 0;
389 font->max_unicode = 0;
390 for(t=0;t<font->num_glyphs;t++) {
391 font->glyphs[t].unicode = -1;
400 gfxfont_t* gfxfont_load(char*filename)
402 fprintf(stderr, "No freetype support compiled in! Not able to load %s\n", filename);