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 gfxline_t * clonePath(gfxline_t*line)
112 gfxline_t*n = rfx_calloc(sizeof(gfxline_t));
126 static gfxglyph_t cloneGlyph(gfxglyph_t*src)
129 memset(&dest, 0, sizeof(dest));
131 dest.name = strdup(src->name);
132 dest.advance = src->advance;
133 dest.unicode = src->unicode;
134 dest.line = clonePath(src->line);
138 static void glyph_clear(gfxglyph_t*g)
142 free(g->name); g->name = 0;
144 gfxline_free(g->line);
147 gfxfont_t* gfxfont_load(char*filename)
151 const char* name = 0;
157 int*glyph2unicode = 0;
164 if(FT_Init_FreeType(&ftlibrary)) {
165 fprintf(stderr, "Couldn't init freetype library!\n");
169 error = FT_New_Face(ftlibrary, filename, 0, &face);
170 FT_Set_Pixel_Sizes (face, 16*loadfont_scale, 16*loadfont_scale);
173 fprintf(stderr, "Couldn't load file %s- not a TTF file?\n", filename);
176 if(face->num_glyphs <= 0) {
177 fprintf(stderr, "File %s contains %d glyphs\n", face->num_glyphs);
181 font = rfx_calloc(sizeof(gfxfont_t));
182 //font->style = ((face->style_flags&FT_STYLE_FLAG_ITALIC)?FONT_STYLE_ITALIC:0) |((face->style_flags&FT_STYLE_FLAG_BOLD)?FONT_STYLE_BOLD:0);
183 //font->ascent = abs(face->ascender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMin;
184 //font->descent = abs(face->descender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMax;
185 //font->leading = font->layout->ascent + font->layout->descent;
186 //font->encoding = FONT_ENCODING_UNICODE;
187 font->max_unicode = 0;
189 font->glyphs = rfx_calloc(face->num_glyphs*sizeof(gfxglyph_t));
190 glyph2unicode = rfx_calloc(face->num_glyphs*sizeof(int));
191 glyph2glyph = rfx_calloc(face->num_glyphs*sizeof(int));
193 if(FT_HAS_GLYPH_NAMES(face)) {
194 //font->glyphnames = rfx_calloc(face->num_glyphs*sizeof(char*));
197 name = FT_Get_Postscript_Name(face);
199 font->name = strdup(name);
203 charcode = FT_Get_First_Char(face, &gindex);
206 if(gindex >= 0 && gindex<face->num_glyphs) {
207 if(!glyph2unicode[gindex]) {
208 glyph2unicode[gindex] = charcode;
209 if(charcode + 1 > font->max_unicode) {
210 font->max_unicode = charcode + 1;
214 charcode = FT_Get_Next_Char(face, charcode, &gindex);
217 /* if we didn't find a single encoding character, try
218 the font's charmaps instead. That usually means that
219 the encoding is no longer unicode.
220 TODO: find a way to convert the encoding to unicode
222 if(font->max_unicode == 0 && charmap < face->num_charmaps - 1) {
224 FT_Set_Charmap(face, face->charmaps[charmap]);
225 //font->encoding = 0;//anything but unicode FIXME
231 /* TODO: if isunicode is 1, we now need to permutate the character
232 order so that each character is at it's encoding position */
235 font->max_unicode = 65535;
237 font->unicode2glyph = rfx_calloc(font->max_unicode*sizeof(int));
238 glyph2unicode = (int*)rfx_calloc(face->num_glyphs*sizeof(int));
240 for(t=0;t<font->max_unicode;t++) {
241 int g = FT_Get_Char_Index(face, t);
242 if(!g || g>=face->num_glyphs)
244 font->unicode2glyph[t] = g;
247 if(!glyph2unicode[g]) {
248 glyph2unicode[g] = t;
252 font->max_unicode = max_unicode;
254 font->num_glyphs = 0;
256 glyph2glyph = (int*)rfx_calloc(face->num_glyphs*sizeof(int));
258 for(t=0; t < face->num_glyphs; t++) {
267 if(FT_HAS_GLYPH_NAMES(face)) {
268 error = FT_Get_Glyph_Name(face, t, name, 127);
269 if(!error && name[0] && !strstr(name, "notdef")) {
270 font->glyphs[font->num_glyphs].name = strdup(name);
274 if(!glyph2unicode[t] && !hasname && skip_unused) {
277 error = FT_Load_Glyph(face, t, FT_LOAD_NO_BITMAP);
279 fprintf(stderr, "Couldn't load glyph %d, error:%d\n", t, error);
282 error = FT_Get_Glyph(face->glyph, &glyph);
284 fprintf(stderr, "Couldn't get glyph %d, error:%d\n", t, error);
288 FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_unscaled, &bbox);
289 bbox.yMin = -bbox.yMin;
290 bbox.yMax = -bbox.yMax;
291 if(bbox.xMax < bbox.xMin) {
293 bbox.xMax ^= bbox.xMin;
294 bbox.xMin ^= bbox.xMax;
295 bbox.xMax ^= bbox.xMin;
297 if(bbox.yMax < bbox.yMin) {
299 bbox.yMax ^= bbox.yMin;
300 bbox.yMin ^= bbox.yMax;
301 bbox.yMax ^= bbox.yMin;
304 gfxdrawer_target_gfxline(&draw);
306 //error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &draw);
307 error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &draw);
310 fprintf(stderr, "Couldn't decompose glyph %d\n", t);
311 gfxline_free((gfxline_t*)draw.result(&draw));
317 font->glyph[font->num_glyphs].advance = (bbox.xMax*20*FT_SCALE)/FT_SUBPIXELS;
319 font->glyph[font->num_glyphs].advance = ((bbox.xMax - bbox.xMin)*20*FT_SCALE)/FT_SUBPIXELS;
322 font->glyphs[font->num_glyphs].advance = glyph->advance.x*20/65536;
325 font->glyphs[font->num_glyphs].line = (gfxline_t*)draw.result(&draw);
327 /*font->glyphs[font->num_glyphs].bbox.xmin = (bbox.xMin*FT_SCALE*20)/FT_SUBPIXELS;
328 font->glyphs[font->num_glyphs].bbox.ymin = (bbox.yMin*FT_SCALE*20)/FT_SUBPIXELS;
329 font->glyphs[font->num_glyphs].bbox.xmax = (bbox.xMax*FT_SCALE*20)/FT_SUBPIXELS;
330 font->glyphs[font->num_glyphs].bbox.ymax = (bbox.yMax*FT_SCALE*20)/FT_SUBPIXELS;*/
332 FT_Done_Glyph(glyph);
333 font->glyphs[font->num_glyphs].unicode = glyph2unicode[t];
334 glyph2glyph[t] = font->num_glyphs;
337 /* notice: if skip_unused is true, font->glyph2unicode, font->glyphnames and font->layout->bounds will
338 have more memory allocated than just font->num_glyphs, but only the first font->numchars
341 for(t=0;t<font->max_unicode;t++) {
342 if(font->unicode2glyph[t]>=0) {
343 font->unicode2glyph[t] = glyph2glyph[font->unicode2glyph[t]];
346 rfx_free(glyph2glyph);
347 rfx_free(glyph2unicode);
350 FT_Done_FreeType(ftlibrary);ftlibrary=0;
352 if(!isunicode && font->num_glyphs>0) {
353 /* if the encoding isn't unicode, remap the font
354 so that the encoding equals the char position, and
355 remove the unicode table */
357 gfxglyph_t*newglyphs = rfx_calloc(font->max_unicode*sizeof(gfxglyph_t));
359 for(t=0;t<max_unicode;t++) {
360 int c = font->unicode2glyph[t];
361 if(c>=font->num_glyphs || c<0)
363 newglyphs[t] = cloneGlyph(&font->glyphs[c]);
364 newglyphs[t].unicode = -1;
366 for(t=0;t<font->num_glyphs;t++) {
367 glyph_clear(&font->glyphs[t]);
370 font->glyphs = newglyphs;
371 font->num_glyphs = font->max_unicode;
373 free(font->unicode2glyph);font->unicode2glyph = 0;
374 font->max_unicode = 0;
377 if(font->unicode2glyph) {
380 /* check whether the Unicode indices look o.k.
381 If they don't, disable the unicode lookup by setting
382 the unicode map to -1 everywhere */
383 for(t=0;t<font->num_glyphs;t++) {
384 int c = font->glyphs[t].unicode;
385 gfxline_t* line = font->glyphs[t].line;
386 if(c && c < 32 && (line && line->next && line->next->next)) {
387 // the character maps into the unicode control character range
388 // between 0001-001f. Yet it is not empty. Treat the one
389 // mapping as broken, and look how many of those we find.
394 free(font->unicode2glyph);font->unicode2glyph = 0;
395 font->max_unicode = 0;
396 for(t=0;t<font->num_glyphs;t++) {
397 font->glyphs[t].unicode = -1;
406 gfxfont_t* gfxfont_load(char*filename)
408 fprintf(stderr, "No freetype support compiled in! Not able to load %s\n", filename);