3 Functions for loading external fonts.
5 Extension module for the rfxswf library.
6 Part of the swftools package.
8 Copyright (c) 2003, 2004 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 static int loadfont_scale = 4;
25 static int skip_unused = 1;
26 static int full_unicode = 0;
28 void swf_SetLoadFontParameters(int _scale, int _skip_unused, int _full_unicode)
30 if(_scale) loadfont_scale = _scale;
31 skip_unused = _skip_unused;
32 full_unicode = _full_unicode;
37 #ifdef HAVE_FT2BUILD_H
39 #include FT_FREETYPE_H
42 #include FT_SFNT_NAMES_H
43 #include FT_TRUETYPE_IDS_H
46 #include <freetype/freetype.h>
47 #include <freetype/ftglyph.h>
48 #include <freetype/ftsizes.h>
49 #include <freetype/ftsnames.h>
50 #include <freetype/ttnameid.h>
51 #include <freetype/ftoutln.h>
54 /* Setting subpixels to 64 also means that the "point size" of the
55 font outlines will be 64. So the font, when rendered at original
56 size (i.e., the swf fontsize is 1024) will have the same size as
57 if it was rendered at 64pt */
60 #define FT_SUBPIXELS 64
62 static int ft_move_to(FT_Vector* _to, void* user)
64 drawer_t* draw = (drawer_t*)user;
66 to.x = _to->x*FT_SCALE/(float)FT_SUBPIXELS;
67 to.y = -_to->y*FT_SCALE/(float)FT_SUBPIXELS;
68 draw->moveTo(draw, &to);
71 static int ft_line_to(FT_Vector* _to, void* user)
73 drawer_t* draw = (drawer_t*)user;
75 to.x = _to->x*FT_SCALE/(float)FT_SUBPIXELS;
76 to.y = -_to->y*FT_SCALE/(float)FT_SUBPIXELS;
77 draw->lineTo(draw, &to);
80 static int ft_cubic_to(FT_Vector* _c1, FT_Vector* _c2, FT_Vector* _to, void* user)
82 drawer_t* draw = (drawer_t*)user;
84 to.x = _to->x*FT_SCALE/(float)FT_SUBPIXELS;
85 to.y = -_to->y*FT_SCALE/(float)FT_SUBPIXELS;
86 c1.x = _c1->x*FT_SCALE/(float)FT_SUBPIXELS;
87 c1.y = -_c1->y*FT_SCALE/(float)FT_SUBPIXELS;
88 c2.x = _c2->x*FT_SCALE/(float)FT_SUBPIXELS;
89 c2.y = -_c2->y*FT_SCALE/(float)FT_SUBPIXELS;
90 draw_cubicTo(draw, &c1, &c2, &to);
93 static int ft_conic_to(FT_Vector* _c, FT_Vector* _to, void* user)
95 drawer_t* draw = (drawer_t*)user;
97 to.x = _to->x*FT_SCALE/(float)FT_SUBPIXELS;
98 to.y = -_to->y*FT_SCALE/(float)FT_SUBPIXELS;
99 c.x = _c->x*FT_SCALE/(float)FT_SUBPIXELS;
100 c.y = -_c->y*FT_SCALE/(float)FT_SUBPIXELS;
101 draw_conicTo(draw, &c, &to);
104 static FT_Outline_Funcs outline_functions =
113 static FT_Library ftlibrary = 0;
115 SWFFONT* swf_LoadTrueTypeFont(char*filename)
119 const char* name = 0;
130 if(FT_Init_FreeType(&ftlibrary)) {
131 fprintf(stderr, "Couldn't init freetype library!\n");
135 error = FT_New_Face(ftlibrary, filename, 0, &face);
136 FT_Set_Pixel_Sizes (face, 16*loadfont_scale, 16*loadfont_scale);
139 fprintf(stderr, "Couldn't load file %s- not a TTF file?\n", filename);
142 if(face->num_glyphs <= 0) {
143 fprintf(stderr, "File %s contains %d glyphs\n", face->num_glyphs);
147 font = rfx_calloc(sizeof(SWFFONT));
150 font->layout = rfx_calloc(sizeof(SWFLAYOUT));
151 font->layout->bounds = rfx_calloc(face->num_glyphs*sizeof(SRECT));
152 font->style = ((face->style_flags&FT_STYLE_FLAG_ITALIC)?FONT_STYLE_ITALIC:0)
153 |((face->style_flags&FT_STYLE_FLAG_BOLD)?FONT_STYLE_BOLD:0);
154 font->encoding = FONT_ENCODING_UNICODE;
155 font->glyph2ascii = rfx_calloc(face->num_glyphs*sizeof(U16));
157 font->glyph = rfx_calloc(face->num_glyphs*sizeof(SWFGLYPH));
158 if(FT_HAS_GLYPH_NAMES(face)) {
159 font->glyphnames = rfx_calloc(face->num_glyphs*sizeof(char*));
162 font->layout->ascent = abs(face->ascender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMin;
163 font->layout->descent = abs(face->descender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMax;
164 font->layout->leading = font->layout->ascent + font->layout->descent;
165 font->layout->kerningcount = 0;
167 name = FT_Get_Postscript_Name(face);
169 font->name = (U8*)strdup(name);
173 /* // Map Glyphs to Unicode, version 1 (quick and dirty):
175 for(t=0;t<65536;t++) {
176 int index = FT_Get_Char_Index(face, t);
177 if(index>=0 && index<face->num_glyphs) {
178 if(font->glyph2ascii[index]<0)
179 font->glyph2ascii[index] = t;
183 // Map Glyphs to Unicode, version 2 (much nicer):
184 // (The third way would be the AGL algorithm, as proposed
185 // by Werner Lemberg on freetype@freetype.org)
187 charcode = FT_Get_First_Char(face, &gindex);
190 if(gindex >= 0 && gindex<face->num_glyphs) {
191 if(!font->glyph2ascii[gindex]) {
192 font->glyph2ascii[gindex] = charcode;
193 if(charcode + 1 > font->maxascii) {
194 font->maxascii = charcode + 1;
198 charcode = FT_Get_Next_Char(face, charcode, &gindex);
201 /* if we didn't find a single encoding character, try
202 the font's charmaps instead. That usually means that
203 the encoding is no longer unicode.
204 TODO: find a way to convert the encoding to unicode
206 if(font->maxascii == 0 && charmap < face->num_charmaps - 1) {
208 FT_Set_Charmap(face, face->charmaps[charmap]);
209 font->encoding = 0;//anything but unicode FIXME
215 font->maxascii = 65535;
217 font->ascii2glyph = rfx_calloc(font->maxascii*sizeof(int));
219 for(t=0;t<font->maxascii;t++) {
220 int g = FT_Get_Char_Index(face, t);
221 if(!g || g>=face->num_glyphs)
223 font->ascii2glyph[t] = g;
226 if(!font->glyph2ascii[g]) {
227 font->glyph2ascii[g] = t;
231 font->maxascii = max_unicode;
235 glyph2glyph = (int*)rfx_calloc(face->num_glyphs*sizeof(int));
237 for(t=0; t < face->num_glyphs; t++) {
246 if(FT_HAS_GLYPH_NAMES(face)) {
247 error = FT_Get_Glyph_Name(face, t, name, 127);
248 if(!error && name[0] && !strstr(name, "notdef")) {
249 font->glyphnames[font->numchars] = strdup(name);
253 if(!font->glyph2ascii[t] && !hasname && skip_unused) {
256 error = FT_Load_Glyph(face, t, FT_LOAD_NO_BITMAP);
258 fprintf(stderr, "Couldn't load glyph %d, error:%d\n", t, error);
261 error = FT_Get_Glyph(face->glyph, &glyph);
263 fprintf(stderr, "Couldn't get glyph %d, error:%d\n", t, error);
267 FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_unscaled, &bbox);
268 bbox.yMin = -bbox.yMin;
269 bbox.yMax = -bbox.yMax;
270 if(bbox.xMax < bbox.xMin) {
272 bbox.xMax ^= bbox.xMin;
273 bbox.xMin ^= bbox.xMax;
274 bbox.xMax ^= bbox.xMin;
276 if(bbox.yMax < bbox.yMin) {
278 bbox.yMax ^= bbox.yMin;
279 bbox.yMin ^= bbox.yMax;
280 bbox.yMax ^= bbox.yMin;
283 swf_Shape01DrawerInit(&draw, 0);
285 //error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &draw);
286 error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &draw);
290 fprintf(stderr, "Couldn't decompose glyph %d\n", t);
297 font->glyph[font->numchars].advance = (bbox.xMax*FT_SCALE)/FT_SUBPIXELS;
299 font->glyph[font->numchars].advance = ((bbox.xMax - bbox.xMin)*FT_SCALE)/FT_SUBPIXELS;
302 font->glyph[font->numchars].advance = glyph->advance.x*20/65536;
305 font->glyph[font->numchars].shape = swf_ShapeDrawerToShape(&draw);
307 font->layout->bounds[font->numchars].xmin = (bbox.xMin*FT_SCALE*20)/FT_SUBPIXELS;
308 font->layout->bounds[font->numchars].ymin = (bbox.yMin*FT_SCALE*20)/FT_SUBPIXELS;
309 font->layout->bounds[font->numchars].xmax = (bbox.xMax*FT_SCALE*20)/FT_SUBPIXELS;
310 font->layout->bounds[font->numchars].ymax = (bbox.yMax*FT_SCALE*20)/FT_SUBPIXELS;
314 FT_Done_Glyph(glyph);
315 font->glyph2ascii[font->numchars] = font->glyph2ascii[t];
316 glyph2glyph[t] = font->numchars;
319 /* notice: if skip_unused is true, font->glyph2ascii, font->glyphnames and font->layout->bounds will
320 have more memory allocated than just font->numchars, but only the first font->numchars
323 for(t=0;t<font->maxascii;t++) {
324 if(font->ascii2glyph[t]>=0) {
325 font->ascii2glyph[t] = glyph2glyph[font->ascii2glyph[t]];
328 rfx_free(glyph2glyph);
331 FT_Done_FreeType(ftlibrary);ftlibrary=0;
335 #else //HAVE_FREETYPE
337 SWFFONT* swf_LoadTrueTypeFont(char*filename)
339 fprintf(stderr, "Warning: no freetype library- not able to load %s\n", filename);
349 static int t1lib_initialized = 0;
351 static int counter = 0;
353 SWFFONT* swf_LoadT1Font(char*filename)
357 float angle,underline;
358 char*fontname,*fullname,*familyname;
367 if(!t1lib_initialized) {
369 if ((T1_InitLib(NO_LOGFILE)==NULL)){
370 fprintf(stderr, "Initialization of t1lib failed\n");
373 t1lib_initialized = 1;
375 nr = T1_AddFont(filename);
378 charnames = T1_GetAllCharNames(nr);
380 fprintf(stderr, "No Charnames record- not a Type1 Font?\n");
384 angle = T1_GetItalicAngle(nr);
385 fontname = T1_GetFontName(nr);
386 fullname = T1_GetFullName(nr);
387 familyname = T1_GetFamilyName(nr);
388 underline = T1_GetUnderlinePosition(nr);
389 bbox = T1_GetFontBBox(nr);
391 font = (SWFFONT*)rfx_calloc(sizeof(SWFFONT));
395 font->name = (U8*)strdup(fontname);
398 font->layout = (SWFLAYOUT*)rfx_calloc(sizeof(SWFLAYOUT));
401 charname = charnames;
405 if(*charname) encoding[num] = strdup(*charname);
406 else encoding[num] = strdup(".notdef");
411 encoding[t] = strdup(".notdef");
413 //T1_ReencodeFont(nr, encoding);
415 font->maxascii = num;
416 font->numchars = num;
418 font->style = (/*bold*/0?FONT_STYLE_BOLD:0) + (angle>0.05?FONT_STYLE_ITALIC:0);
420 font->glyph = (SWFGLYPH*)rfx_calloc(num*sizeof(SWFGLYPH));
421 font->glyph2ascii = (U16*)rfx_calloc(num*sizeof(U16));
422 font->ascii2glyph = (int*)rfx_calloc(font->maxascii*sizeof(int));
423 font->layout->ascent = (U16)(underline - bbox.lly);
424 font->layout->descent = (U16)(bbox.ury - underline);
425 font->layout->leading = (U16)(font->layout->ascent -
426 font->layout->descent -
427 (bbox.lly - bbox.ury));
428 font->layout->bounds = (SRECT*)rfx_calloc(sizeof(SRECT)*num);
429 font->layout->kerningcount = 0;
430 font->layout->kerning = 0;
431 font->glyphnames = rfx_calloc(num*sizeof(char*));
435 charname = charnames;
436 for(c=0;c<font->numchars;c++) {
439 T1_OUTLINE * outline;
443 outline = T1_GetCharOutline(nr, c, 100.0, 0);
444 firstx = outline->dest.x/0xffff;
450 font->glyphnames[c] = strdup(*charname);
453 font->ascii2glyph[c] = c;
454 font->glyph2ascii[c] = c;
456 swf_Shape01DrawerInit(&draw, 0);
459 pos.x += (outline->dest.x/(float)0xffff);
460 pos.y += (outline->dest.y/(float)0xffff);
462 if(outline->type == T1_PATHTYPE_MOVE) {
463 draw.moveTo(&draw,&pos);
464 } else if(outline->type == T1_PATHTYPE_LINE) {
465 draw.lineTo(&draw,&pos);
466 } else if(outline->type == T1_PATHTYPE_BEZIER) {
467 T1_BEZIERSEGMENT*o2 = (T1_BEZIERSEGMENT*)outline;
469 b.x = o2->B.x/(float)0xffff+last.x;
470 b.y = o2->B.y/(float)0xffff+last.y;
471 c.x = o2->C.x/(float)0xffff+last.x;
472 c.y = o2->C.y/(float)0xffff+last.y;
473 draw_cubicTo(&draw,&b,&c,&pos);
475 fprintf(stderr, "loadT1Font: unknown outline type:%d\n", outline->type);
478 outline = outline->link;
479 printf("(%f,%f) ", pos.x, pos.y);
485 font->glyph[c].shape = swf_ShapeDrawerToShape(&draw);
486 bbox = swf_ShapeDrawerGetBBox(&draw);
489 font->layout->bounds[c] = bbox;
490 font->glyph[c].advance = bbox.xmax;
491 if(!font->glyph[c].advance) {
492 font->glyph[c].advance = firstx;
499 rfx_free(encoding[t]);
505 SWFFONT* swf_LoadT1Font(char*filename)
507 fprintf(stderr, "Warning: no t1lib- not able to load %s\n", filename);
513 SWFFONT* swf_DummyFont()
515 SWFFONT*font = (SWFFONT*)rfx_calloc(sizeof(SWFFONT));
519 static int isSWF(const char*filename)
521 FILE*fi = fopen(filename, "rb");
527 memset(a, 0, sizeof(a));
531 if(!strncmp(a, "FWS", 3) || !strncmp(a, "CWS", 3)) {
537 SWFFONT* swf_LoadFont(char*filename)
541 return swf_DummyFont();
542 is_swf = isSWF(filename);
546 return swf_ReadFont(filename);
549 #if defined(HAVE_FREETYPE)
550 return swf_LoadTrueTypeFont(filename);
551 #elif defined(HAVE_T1LIB)
552 return swf_LoadT1Font(filename);
554 fprintf(stderr, "Error: Neither T1lib nor FreeType support compiled in. Could not load %s\n", filename);