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 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 void gfxfont_free(gfxfont_t*font)
140 for(t=0;t<font->num_glyphs;t++) {
141 glyph_clear(&font->glyphs[t]);
144 free(font->glyphs);font->glyphs = 0;
146 font->num_glyphs = 0;
147 if(font->unicode2glyph) {
148 free(font->unicode2glyph);font->unicode2glyph = 0;
153 gfxfont_t* gfxfont_load(char*filename, double quality)
157 const char* name = 0;
163 int*glyph2unicode = 0;
170 if(FT_Init_FreeType(&ftlibrary)) {
171 fprintf(stderr, "Couldn't init freetype library!\n");
175 error = FT_New_Face(ftlibrary, filename, 0, &face);
176 FT_Set_Pixel_Sizes (face, 16*loadfont_scale, 16*loadfont_scale);
179 fprintf(stderr, "Couldn't load file %s- not a TTF file?\n", filename);
182 if(face->num_glyphs <= 0) {
183 fprintf(stderr, "File %s contains %d glyphs\n", face->num_glyphs);
187 font = rfx_calloc(sizeof(gfxfont_t));
188 //font->style = ((face->style_flags&FT_STYLE_FLAG_ITALIC)?FONT_STYLE_ITALIC:0) |((face->style_flags&FT_STYLE_FLAG_BOLD)?FONT_STYLE_BOLD:0);
189 //font->ascent = abs(face->ascender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMin;
190 //font->descent = abs(face->descender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMax;
191 //font->leading = font->layout->ascent + font->layout->descent;
192 //font->encoding = FONT_ENCODING_UNICODE;
193 font->max_unicode = 0;
195 font->glyphs = rfx_calloc(face->num_glyphs*sizeof(gfxglyph_t));
196 glyph2unicode = rfx_calloc(face->num_glyphs*sizeof(int));
197 glyph2glyph = rfx_calloc(face->num_glyphs*sizeof(int));
199 if(FT_HAS_GLYPH_NAMES(face)) {
200 //font->glyphnames = rfx_calloc(face->num_glyphs*sizeof(char*));
203 /*name = FT_Get_Postscript_Name(face);
205 font->name = strdup(name);*/
209 charcode = FT_Get_First_Char(face, &gindex);
212 if(gindex >= 0 && gindex<face->num_glyphs) {
213 if(!glyph2unicode[gindex]) {
214 glyph2unicode[gindex] = charcode;
215 if(charcode + 1 > font->max_unicode) {
216 font->max_unicode = charcode + 1;
220 charcode = FT_Get_Next_Char(face, charcode, &gindex);
223 /* if we didn't find a single encoding character, try
224 the font's charmaps instead. That usually means that
225 the encoding is no longer unicode.
226 TODO: find a way to convert the encoding to unicode
228 if(font->max_unicode == 0 && charmap < face->num_charmaps - 1) {
230 FT_Set_Charmap(face, face->charmaps[charmap]);
231 //font->encoding = 0;//anything but unicode FIXME
237 /* TODO: if isunicode is 1, we now need to permutate the character
238 order so that each character is at it's encoding position */
241 font->max_unicode = 65535;
243 font->unicode2glyph = rfx_calloc(font->max_unicode*sizeof(int));
245 for(t=0;t<font->max_unicode;t++) {
246 int g = FT_Get_Char_Index(face, t);
247 if(!g || g>=face->num_glyphs)
249 font->unicode2glyph[t] = g;
252 if(!glyph2unicode[g]) {
253 glyph2unicode[g] = t;
257 font->max_unicode = max_unicode;
259 font->num_glyphs = 0;
261 for(t=0; t < face->num_glyphs; t++) {
271 if(FT_HAS_GLYPH_NAMES(face)) {
272 error = FT_Get_Glyph_Name(face, t, name, 127);
273 if(!error && name[0] && !strstr(name, "notdef")) {
274 font->glyphs[font->num_glyphs].name = strdup(name);
278 if(!glyph2unicode[t] && !hasname && skip_unused) {
281 error = FT_Load_Glyph(face, t, FT_LOAD_NO_BITMAP);
283 fprintf(stderr, "Couldn't load glyph %d, error:%d\n", t, error);
286 error = FT_Get_Glyph(face->glyph, &glyph);
288 fprintf(stderr, "Couldn't get glyph %d, error:%d\n", t, error);
292 FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_unscaled, &bbox);
293 bbox.yMin = -bbox.yMin;
294 bbox.yMax = -bbox.yMax;
295 if(bbox.xMax < bbox.xMin) {
297 bbox.xMax ^= bbox.xMin;
298 bbox.xMin ^= bbox.xMax;
299 bbox.xMax ^= bbox.xMin;
301 if(bbox.yMax < bbox.yMin) {
303 bbox.yMax ^= bbox.yMin;
304 bbox.yMin ^= bbox.yMax;
305 bbox.yMax ^= bbox.yMin;
308 gfxdrawer_target_gfxline(&draw);
310 info.quality = quality;
312 //error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &info);
313 error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &info);
316 fprintf(stderr, "Couldn't decompose glyph %d\n", t);
317 gfxline_free((gfxline_t*)draw.result(&draw));
323 font->glyph[font->num_glyphs].advance = (bbox.xMax*20*FT_SCALE)/FT_SUBPIXELS;
325 font->glyph[font->num_glyphs].advance = ((bbox.xMax - bbox.xMin)*20*FT_SCALE)/FT_SUBPIXELS;
328 font->glyphs[font->num_glyphs].advance = glyph->advance.x*20/65536;
331 font->glyphs[font->num_glyphs].line = (gfxline_t*)draw.result(&draw);
333 /*font->glyphs[font->num_glyphs].bbox.xmin = (bbox.xMin*FT_SCALE*20)/FT_SUBPIXELS;
334 font->glyphs[font->num_glyphs].bbox.ymin = (bbox.yMin*FT_SCALE*20)/FT_SUBPIXELS;
335 font->glyphs[font->num_glyphs].bbox.xmax = (bbox.xMax*FT_SCALE*20)/FT_SUBPIXELS;
336 font->glyphs[font->num_glyphs].bbox.ymax = (bbox.yMax*FT_SCALE*20)/FT_SUBPIXELS;*/
338 FT_Done_Glyph(glyph);
339 font->glyphs[font->num_glyphs].unicode = glyph2unicode[t];
340 glyph2glyph[t] = font->num_glyphs;
343 /* notice: if skip_unused is true, font->glyph2unicode, font->glyphnames and font->layout->bounds will
344 have more memory allocated than just font->num_glyphs, but only the first font->numchars
347 for(t=0;t<font->max_unicode;t++) {
348 if(font->unicode2glyph[t]>=0) {
349 font->unicode2glyph[t] = glyph2glyph[font->unicode2glyph[t]];
352 rfx_free(glyph2glyph);
353 rfx_free(glyph2unicode);
356 FT_Done_FreeType(ftlibrary);ftlibrary=0;
358 if(!isunicode && font->num_glyphs>0) {
359 /* if the encoding isn't unicode, remap the font
360 so that the encoding equals the char position, and
361 remove the unicode table */
363 gfxglyph_t*newglyphs = rfx_calloc(font->max_unicode*sizeof(gfxglyph_t));
365 for(t=0;t<max_unicode;t++) {
366 int c = font->unicode2glyph[t];
367 if(c>=font->num_glyphs || c<0)
369 newglyphs[t] = cloneGlyph(&font->glyphs[c]);
370 newglyphs[t].unicode = -1;
372 for(t=0;t<font->num_glyphs;t++) {
373 glyph_clear(&font->glyphs[t]);
376 font->glyphs = newglyphs;
377 font->num_glyphs = font->max_unicode;
379 free(font->unicode2glyph);font->unicode2glyph = 0;
380 font->max_unicode = 0;
383 if(font->unicode2glyph) {
386 /* check whether the Unicode indices look o.k.
387 If they don't, disable the unicode lookup by setting
388 the unicode map to -1 everywhere */
389 for(t=0;t<font->num_glyphs;t++) {
390 int c = font->glyphs[t].unicode;
391 gfxline_t* line = font->glyphs[t].line;
392 if(c && c < 32 && (line && line->next && line->next->next)) {
393 // the character maps into the unicode control character range
394 // between 0001-001f. Yet it is not empty. Treat the one
395 // mapping as broken, and look how many of those we find.
400 free(font->unicode2glyph);font->unicode2glyph = 0;
401 font->max_unicode = 0;
402 for(t=0;t<font->num_glyphs;t++) {
403 font->glyphs[t].unicode = -1;
412 gfxfont_t* gfxfont_load(char*filename)
414 fprintf(stderr, "No freetype support compiled in! Not able to load %s\n", filename);