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);g->line = 0;
147 void gfxfont_free(gfxfont_t*font)
150 for(t=0;t<font->num_glyphs;t++) {
151 glyph_clear(&font->glyphs[t]);
154 free(font->glyphs);font->glyphs = 0;
156 font->num_glyphs = 0;
157 if(font->unicode2glyph) {
158 free(font->unicode2glyph);font->unicode2glyph = 0;
161 free(font->name);font->name = 0;
166 gfxfont_t* gfxfont_load(char*filename)
170 const char* name = 0;
176 int*glyph2unicode = 0;
183 if(FT_Init_FreeType(&ftlibrary)) {
184 fprintf(stderr, "Couldn't init freetype library!\n");
188 error = FT_New_Face(ftlibrary, filename, 0, &face);
189 FT_Set_Pixel_Sizes (face, 16*loadfont_scale, 16*loadfont_scale);
192 fprintf(stderr, "Couldn't load file %s- not a TTF file?\n", filename);
195 if(face->num_glyphs <= 0) {
196 fprintf(stderr, "File %s contains %d glyphs\n", face->num_glyphs);
200 font = rfx_calloc(sizeof(gfxfont_t));
201 //font->style = ((face->style_flags&FT_STYLE_FLAG_ITALIC)?FONT_STYLE_ITALIC:0) |((face->style_flags&FT_STYLE_FLAG_BOLD)?FONT_STYLE_BOLD:0);
202 //font->ascent = abs(face->ascender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMin;
203 //font->descent = abs(face->descender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMax;
204 //font->leading = font->layout->ascent + font->layout->descent;
205 //font->encoding = FONT_ENCODING_UNICODE;
206 font->max_unicode = 0;
208 font->glyphs = rfx_calloc(face->num_glyphs*sizeof(gfxglyph_t));
209 glyph2unicode = rfx_calloc(face->num_glyphs*sizeof(int));
210 glyph2glyph = rfx_calloc(face->num_glyphs*sizeof(int));
212 if(FT_HAS_GLYPH_NAMES(face)) {
213 //font->glyphnames = rfx_calloc(face->num_glyphs*sizeof(char*));
216 name = FT_Get_Postscript_Name(face);
218 font->name = strdup(name);
222 charcode = FT_Get_First_Char(face, &gindex);
225 if(gindex >= 0 && gindex<face->num_glyphs) {
226 if(!glyph2unicode[gindex]) {
227 glyph2unicode[gindex] = charcode;
228 if(charcode + 1 > font->max_unicode) {
229 font->max_unicode = charcode + 1;
233 charcode = FT_Get_Next_Char(face, charcode, &gindex);
236 /* if we didn't find a single encoding character, try
237 the font's charmaps instead. That usually means that
238 the encoding is no longer unicode.
239 TODO: find a way to convert the encoding to unicode
241 if(font->max_unicode == 0 && charmap < face->num_charmaps - 1) {
243 FT_Set_Charmap(face, face->charmaps[charmap]);
244 //font->encoding = 0;//anything but unicode FIXME
250 /* TODO: if isunicode is 1, we now need to permutate the character
251 order so that each character is at it's encoding position */
254 font->max_unicode = 65535;
256 font->unicode2glyph = rfx_calloc(font->max_unicode*sizeof(int));
258 for(t=0;t<font->max_unicode;t++) {
259 int g = FT_Get_Char_Index(face, t);
260 if(!g || g>=face->num_glyphs)
262 font->unicode2glyph[t] = g;
265 if(!glyph2unicode[g]) {
266 glyph2unicode[g] = t;
270 font->max_unicode = max_unicode;
272 font->num_glyphs = 0;
274 for(t=0; t < face->num_glyphs; t++) {
283 if(FT_HAS_GLYPH_NAMES(face)) {
284 error = FT_Get_Glyph_Name(face, t, name, 127);
285 if(!error && name[0] && !strstr(name, "notdef")) {
286 font->glyphs[font->num_glyphs].name = strdup(name);
290 if(!glyph2unicode[t] && !hasname && skip_unused) {
293 error = FT_Load_Glyph(face, t, FT_LOAD_NO_BITMAP);
295 fprintf(stderr, "Couldn't load glyph %d, error:%d\n", t, error);
298 error = FT_Get_Glyph(face->glyph, &glyph);
300 fprintf(stderr, "Couldn't get glyph %d, error:%d\n", t, error);
304 FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_unscaled, &bbox);
305 bbox.yMin = -bbox.yMin;
306 bbox.yMax = -bbox.yMax;
307 if(bbox.xMax < bbox.xMin) {
309 bbox.xMax ^= bbox.xMin;
310 bbox.xMin ^= bbox.xMax;
311 bbox.xMax ^= bbox.xMin;
313 if(bbox.yMax < bbox.yMin) {
315 bbox.yMax ^= bbox.yMin;
316 bbox.yMin ^= bbox.yMax;
317 bbox.yMax ^= bbox.yMin;
320 gfxdrawer_target_gfxline(&draw);
322 //error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &draw);
323 error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &draw);
326 fprintf(stderr, "Couldn't decompose glyph %d\n", t);
327 gfxline_free((gfxline_t*)draw.result(&draw));
333 font->glyph[font->num_glyphs].advance = (bbox.xMax*20*FT_SCALE)/FT_SUBPIXELS;
335 font->glyph[font->num_glyphs].advance = ((bbox.xMax - bbox.xMin)*20*FT_SCALE)/FT_SUBPIXELS;
338 font->glyphs[font->num_glyphs].advance = glyph->advance.x*20/65536;
341 font->glyphs[font->num_glyphs].line = (gfxline_t*)draw.result(&draw);
343 /*font->glyphs[font->num_glyphs].bbox.xmin = (bbox.xMin*FT_SCALE*20)/FT_SUBPIXELS;
344 font->glyphs[font->num_glyphs].bbox.ymin = (bbox.yMin*FT_SCALE*20)/FT_SUBPIXELS;
345 font->glyphs[font->num_glyphs].bbox.xmax = (bbox.xMax*FT_SCALE*20)/FT_SUBPIXELS;
346 font->glyphs[font->num_glyphs].bbox.ymax = (bbox.yMax*FT_SCALE*20)/FT_SUBPIXELS;*/
348 FT_Done_Glyph(glyph);
349 font->glyphs[font->num_glyphs].unicode = glyph2unicode[t];
350 glyph2glyph[t] = font->num_glyphs;
353 /* notice: if skip_unused is true, font->glyph2unicode, font->glyphnames and font->layout->bounds will
354 have more memory allocated than just font->num_glyphs, but only the first font->numchars
357 for(t=0;t<font->max_unicode;t++) {
358 if(font->unicode2glyph[t]>=0) {
359 font->unicode2glyph[t] = glyph2glyph[font->unicode2glyph[t]];
362 rfx_free(glyph2glyph);
363 rfx_free(glyph2unicode);
366 FT_Done_FreeType(ftlibrary);ftlibrary=0;
368 if(!isunicode && font->num_glyphs>0) {
369 /* if the encoding isn't unicode, remap the font
370 so that the encoding equals the char position, and
371 remove the unicode table */
373 gfxglyph_t*newglyphs = rfx_calloc(font->max_unicode*sizeof(gfxglyph_t));
375 for(t=0;t<max_unicode;t++) {
376 int c = font->unicode2glyph[t];
377 if(c>=font->num_glyphs || c<0)
379 newglyphs[t] = cloneGlyph(&font->glyphs[c]);
380 newglyphs[t].unicode = -1;
382 for(t=0;t<font->num_glyphs;t++) {
383 glyph_clear(&font->glyphs[t]);
386 font->glyphs = newglyphs;
387 font->num_glyphs = font->max_unicode;
389 free(font->unicode2glyph);font->unicode2glyph = 0;
390 font->max_unicode = 0;
393 if(font->unicode2glyph) {
396 /* check whether the Unicode indices look o.k.
397 If they don't, disable the unicode lookup by setting
398 the unicode map to -1 everywhere */
399 for(t=0;t<font->num_glyphs;t++) {
400 int c = font->glyphs[t].unicode;
401 gfxline_t* line = font->glyphs[t].line;
402 if(c && c < 32 && (line && line->next && line->next->next)) {
403 // the character maps into the unicode control character range
404 // between 0001-001f. Yet it is not empty. Treat the one
405 // mapping as broken, and look how many of those we find.
410 free(font->unicode2glyph);font->unicode2glyph = 0;
411 font->max_unicode = 0;
412 for(t=0;t<font->num_glyphs;t++) {
413 font->glyphs[t].unicode = -1;
422 gfxfont_t* gfxfont_load(char*filename)
424 fprintf(stderr, "No freetype support compiled in! Not able to load %s\n", filename);