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);
263 error = FT_Get_Glyph(face->glyph, &glyph);
265 fprintf(stderr, "Couldn't get glyph %d, error:%d\n", t, error);
273 FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_unscaled, &bbox);
275 memset(&bbox, 0, sizeof(bbox));
277 bbox.yMin = -bbox.yMin;
278 bbox.yMax = -bbox.yMax;
279 if(bbox.xMax < bbox.xMin) {
281 bbox.xMax ^= bbox.xMin;
282 bbox.xMin ^= bbox.xMax;
283 bbox.xMax ^= bbox.xMin;
285 if(bbox.yMax < bbox.yMin) {
287 bbox.yMax ^= bbox.yMin;
288 bbox.yMin ^= bbox.yMax;
289 bbox.yMax ^= bbox.yMin;
292 swf_Shape01DrawerInit(&draw, 0);
294 //error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &draw);
296 error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &draw);
302 fprintf(stderr, "Couldn't decompose glyph %d\n", t);
309 font->glyph[font->numchars].advance = (bbox.xMax*20*FT_SCALE)/FT_SUBPIXELS;
311 font->glyph[font->numchars].advance = ((bbox.xMax - bbox.xMin)*20*FT_SCALE)/FT_SUBPIXELS;
315 font->glyph[font->numchars].advance = glyph->advance.x*20/65536;
317 font->glyph[font->numchars].advance = 0;
320 font->glyph[font->numchars].shape = swf_ShapeDrawerToShape(&draw);
322 font->layout->bounds[font->numchars].xmin = (bbox.xMin*FT_SCALE*20)/FT_SUBPIXELS;
323 font->layout->bounds[font->numchars].ymin = (bbox.yMin*FT_SCALE*20)/FT_SUBPIXELS;
324 font->layout->bounds[font->numchars].xmax = (bbox.xMax*FT_SCALE*20)/FT_SUBPIXELS;
325 font->layout->bounds[font->numchars].ymax = (bbox.yMax*FT_SCALE*20)/FT_SUBPIXELS;
330 FT_Done_Glyph(glyph);
331 font->glyph2ascii[font->numchars] = font->glyph2ascii[t];
332 glyph2glyph[t] = font->numchars;
335 /* notice: if skip_unused is true, font->glyph2ascii, font->glyphnames and font->layout->bounds will
336 have more memory allocated than just font->numchars, but only the first font->numchars
339 for(t=0;t<font->maxascii;t++) {
340 if(font->ascii2glyph[t]>=0) {
341 font->ascii2glyph[t] = glyph2glyph[font->ascii2glyph[t]];
344 rfx_free(glyph2glyph);
347 FT_Done_FreeType(ftlibrary);ftlibrary=0;
351 #else //HAVE_FREETYPE
353 SWFFONT* swf_LoadTrueTypeFont(char*filename)
355 fprintf(stderr, "Warning: no freetype library- not able to load %s\n", filename);
365 static int t1lib_initialized = 0;
367 static int counter = 0;
369 SWFFONT* swf_LoadT1Font(char*filename)
373 float angle,underline;
374 char*fontname,*fullname,*familyname;
383 if(!t1lib_initialized) {
385 if ((T1_InitLib(NO_LOGFILE)==NULL)){
386 fprintf(stderr, "Initialization of t1lib failed\n");
389 t1lib_initialized = 1;
391 nr = T1_AddFont(filename);
394 charnames = T1_GetAllCharNames(nr);
396 fprintf(stderr, "No Charnames record- not a Type1 Font?\n");
400 angle = T1_GetItalicAngle(nr);
401 fontname = T1_GetFontName(nr);
402 fullname = T1_GetFullName(nr);
403 familyname = T1_GetFamilyName(nr);
404 underline = T1_GetUnderlinePosition(nr);
405 bbox = T1_GetFontBBox(nr);
407 font = (SWFFONT*)rfx_calloc(sizeof(SWFFONT));
411 font->name = (U8*)strdup(fontname);
414 font->layout = (SWFLAYOUT*)rfx_calloc(sizeof(SWFLAYOUT));
417 charname = charnames;
421 if(*charname) encoding[num] = strdup(*charname);
422 else encoding[num] = strdup(".notdef");
427 encoding[t] = strdup(".notdef");
429 //T1_ReencodeFont(nr, encoding);
431 font->maxascii = num;
432 font->numchars = num;
434 font->style = (/*bold*/0?FONT_STYLE_BOLD:0) + (angle>0.05?FONT_STYLE_ITALIC:0);
436 font->glyph = (SWFGLYPH*)rfx_calloc(num*sizeof(SWFGLYPH));
437 font->glyph2ascii = (U16*)rfx_calloc(num*sizeof(U16));
438 font->ascii2glyph = (int*)rfx_calloc(font->maxascii*sizeof(int));
439 font->layout->ascent = (U16)(underline - bbox.lly);
440 font->layout->descent = (U16)(bbox.ury - underline);
441 font->layout->leading = (U16)(font->layout->ascent -
442 font->layout->descent -
443 (bbox.lly - bbox.ury));
444 font->layout->bounds = (SRECT*)rfx_calloc(sizeof(SRECT)*num);
445 font->layout->kerningcount = 0;
446 font->layout->kerning = 0;
447 font->glyphnames = rfx_calloc(num*sizeof(char*));
451 charname = charnames;
452 for(c=0;c<font->numchars;c++) {
455 T1_OUTLINE * outline;
459 outline = T1_GetCharOutline(nr, c, 100.0, 0);
460 firstx = outline->dest.x/0xffff;
466 font->glyphnames[c] = strdup(*charname);
469 font->ascii2glyph[c] = c;
470 font->glyph2ascii[c] = c;
472 swf_Shape01DrawerInit(&draw, 0);
475 pos.x += (outline->dest.x/(float)0xffff);
476 pos.y += (outline->dest.y/(float)0xffff);
478 if(outline->type == T1_PATHTYPE_MOVE) {
479 draw.moveTo(&draw,&pos);
480 } else if(outline->type == T1_PATHTYPE_LINE) {
481 draw.lineTo(&draw,&pos);
482 } else if(outline->type == T1_PATHTYPE_BEZIER) {
483 T1_BEZIERSEGMENT*o2 = (T1_BEZIERSEGMENT*)outline;
485 b.x = o2->B.x/(float)0xffff+last.x;
486 b.y = o2->B.y/(float)0xffff+last.y;
487 c.x = o2->C.x/(float)0xffff+last.x;
488 c.y = o2->C.y/(float)0xffff+last.y;
489 draw_cubicTo(&draw,&b,&c,&pos);
491 fprintf(stderr, "loadT1Font: unknown outline type:%d\n", outline->type);
494 outline = outline->link;
495 printf("t1lib: (%f,%f) ", pos.x, pos.y);
501 font->glyph[c].shape = swf_ShapeDrawerToShape(&draw);
502 bbox = swf_ShapeDrawerGetBBox(&draw);
505 font->layout->bounds[c] = bbox;
506 font->glyph[c].advance = bbox.xmax;
507 if(!font->glyph[c].advance) {
508 font->glyph[c].advance = firstx;
515 rfx_free(encoding[t]);
521 SWFFONT* swf_LoadT1Font(char*filename)
523 fprintf(stderr, "Warning: no t1lib- not able to load %s\n", filename);
529 SWFFONT* swf_DummyFont()
531 SWFFONT*font = (SWFFONT*)rfx_calloc(sizeof(SWFFONT));
535 static int isSWF(const char*filename)
537 FILE*fi = fopen(filename, "rb");
543 memset(a, 0, sizeof(a));
547 if(!strncmp(a, "FWS", 3) || !strncmp(a, "CWS", 3)) {
553 SWFFONT* swf_LoadFont(char*filename)
557 return swf_DummyFont();
558 is_swf = isSWF(filename);
562 return swf_ReadFont(filename);
565 #if defined(HAVE_FREETYPE)
566 return swf_LoadTrueTypeFont(filename);
567 #elif defined(HAVE_T1LIB)
568 return swf_LoadT1Font(filename);
570 fprintf(stderr, "Error: Neither T1lib nor FreeType support compiled in. Could not load %s\n", filename);