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>
55 #define FT_SUBPIXELS 64
57 static int ft_move_to(FT_Vector* _to, void* user)
59 drawer_t* draw = (drawer_t*)user;
61 to.x = _to->x*FT_SCALE/(float)FT_SUBPIXELS;
62 to.y = -_to->y*FT_SCALE/(float)FT_SUBPIXELS;
63 draw->moveTo(draw, &to);
66 static int ft_line_to(FT_Vector* _to, void* user)
68 drawer_t* draw = (drawer_t*)user;
70 to.x = _to->x*FT_SCALE/(float)FT_SUBPIXELS;
71 to.y = -_to->y*FT_SCALE/(float)FT_SUBPIXELS;
72 draw->lineTo(draw, &to);
75 static int ft_cubic_to(FT_Vector* _c1, FT_Vector* _c2, FT_Vector* _to, void* user)
77 drawer_t* draw = (drawer_t*)user;
79 to.x = _to->x*FT_SCALE/(float)FT_SUBPIXELS;
80 to.y = -_to->y*FT_SCALE/(float)FT_SUBPIXELS;
81 c1.x = _c1->x*FT_SCALE/(float)FT_SUBPIXELS;
82 c1.y = -_c1->y*FT_SCALE/(float)FT_SUBPIXELS;
83 c2.x = _c2->x*FT_SCALE/(float)FT_SUBPIXELS;
84 c2.y = -_c2->y*FT_SCALE/(float)FT_SUBPIXELS;
85 draw_cubicTo(draw, &c1, &c2, &to);
88 static int ft_conic_to(FT_Vector* _c, FT_Vector* _to, void* user)
90 drawer_t* draw = (drawer_t*)user;
92 to.x = _to->x*FT_SCALE/(float)FT_SUBPIXELS;
93 to.y = -_to->y*FT_SCALE/(float)FT_SUBPIXELS;
94 c.x = _c->x*FT_SCALE/(float)FT_SUBPIXELS;
95 c.y = -_c->y*FT_SCALE/(float)FT_SUBPIXELS;
96 draw_conicTo(draw, &c, &to);
99 static FT_Outline_Funcs outline_functions =
108 static FT_Library ftlibrary = 0;
110 SWFFONT* swf_LoadTrueTypeFont(char*filename)
114 const char* name = 0;
125 if(FT_Init_FreeType(&ftlibrary)) {
126 fprintf(stderr, "Couldn't init freetype library!\n");
130 error = FT_New_Face(ftlibrary, filename, 0, &face);
131 FT_Set_Pixel_Sizes (face, 16*loadfont_scale, 16*loadfont_scale);
134 fprintf(stderr, "Couldn't load file %s- not a TTF file?\n", filename);
137 if(face->num_glyphs <= 0) {
138 fprintf(stderr, "File %s contains %d glyphs\n", face->num_glyphs);
142 font = rfx_calloc(sizeof(SWFFONT));
145 font->layout = rfx_calloc(sizeof(SWFLAYOUT));
146 font->layout->bounds = rfx_calloc(face->num_glyphs*sizeof(SRECT));
147 font->style = ((face->style_flags&FT_STYLE_FLAG_ITALIC)?FONT_STYLE_ITALIC:0)
148 |((face->style_flags&FT_STYLE_FLAG_BOLD)?FONT_STYLE_BOLD:0);
149 font->encoding = FONT_ENCODING_UNICODE;
150 font->glyph2ascii = rfx_calloc(face->num_glyphs*sizeof(U16));
152 font->glyph = rfx_calloc(face->num_glyphs*sizeof(SWFGLYPH));
153 if(FT_HAS_GLYPH_NAMES(face)) {
154 font->glyphnames = rfx_calloc(face->num_glyphs*sizeof(char*));
157 font->layout->ascent = abs(face->ascender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMin;
158 font->layout->descent = abs(face->descender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMax;
159 font->layout->leading = font->layout->ascent + font->layout->descent;
160 font->layout->kerningcount = 0;
162 name = FT_Get_Postscript_Name(face);
164 font->name = (U8*)strdup(name);
168 /* // Map Glyphs to Unicode, version 1 (quick and dirty):
170 for(t=0;t<65536;t++) {
171 int index = FT_Get_Char_Index(face, t);
172 if(index>=0 && index<face->num_glyphs) {
173 if(font->glyph2ascii[index]<0)
174 font->glyph2ascii[index] = t;
178 // Map Glyphs to Unicode, version 2 (much nicer):
179 // (The third way would be the AGL algorithm, as proposed
180 // by Werner Lemberg on freetype@freetype.org)
182 charcode = FT_Get_First_Char(face, &gindex);
185 if(gindex >= 0 && gindex<face->num_glyphs) {
186 if(!font->glyph2ascii[gindex]) {
187 font->glyph2ascii[gindex] = charcode;
188 if(charcode + 1 > font->maxascii) {
189 font->maxascii = charcode + 1;
193 charcode = FT_Get_Next_Char(face, charcode, &gindex);
196 /* if we didn't find a single encoding character, try
197 the font's charmaps instead. That usually means that
198 the encoding is no longer unicode.
199 TODO: find a way to convert the encoding to unicode
201 if(font->maxascii == 0 && charmap < face->num_charmaps - 1) {
203 FT_Set_Charmap(face, face->charmaps[charmap]);
204 font->encoding = 0;//anything but unicode FIXME
210 font->maxascii = 65535;
212 font->ascii2glyph = rfx_calloc(font->maxascii*sizeof(int));
214 for(t=0;t<font->maxascii;t++) {
215 int g = FT_Get_Char_Index(face, t);
216 if(!g || g>=face->num_glyphs)
218 font->ascii2glyph[t] = g;
221 if(!font->glyph2ascii[g]) {
222 font->glyph2ascii[g] = t;
226 font->maxascii = max_unicode;
230 glyph2glyph = (int*)rfx_calloc(face->num_glyphs*sizeof(int));
232 for(t=0; t < face->num_glyphs; t++) {
241 if(FT_HAS_GLYPH_NAMES(face)) {
242 error = FT_Get_Glyph_Name(face, t, name, 127);
243 if(!error && name[0] && !strstr(name, "notdef")) {
244 font->glyphnames[font->numchars] = strdup(name);
248 if(!font->glyph2ascii[t] && !hasname && skip_unused) {
251 error = FT_Load_Glyph(face, t, FT_LOAD_NO_BITMAP);
253 fprintf(stderr, "Couldn't load glyph %d, error:%d\n", t, error);
256 error = FT_Get_Glyph(face->glyph, &glyph);
258 fprintf(stderr, "Couldn't get glyph %d, error:%d\n", t, error);
262 FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_unscaled, &bbox);
263 bbox.yMin = -bbox.yMin;
264 bbox.yMax = -bbox.yMax;
265 if(bbox.xMax < bbox.xMin) {
267 bbox.xMax ^= bbox.xMin;
268 bbox.xMin ^= bbox.xMax;
269 bbox.xMax ^= bbox.xMin;
271 if(bbox.yMax < bbox.yMin) {
273 bbox.yMax ^= bbox.yMin;
274 bbox.yMin ^= bbox.yMax;
275 bbox.yMax ^= bbox.yMin;
278 swf_Shape01DrawerInit(&draw, 0);
280 //error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &draw);
281 error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &draw);
285 fprintf(stderr, "Couldn't decompose glyph %d\n", t);
292 font->glyph[font->numchars].advance = (bbox.xMax*FT_SCALE)/FT_SUBPIXELS;
294 font->glyph[font->numchars].advance = ((bbox.xMax - bbox.xMin)*FT_SCALE)/FT_SUBPIXELS;
297 font->glyph[font->numchars].advance = glyph->advance.x*20/65536;
300 font->glyph[font->numchars].shape = swf_ShapeDrawerToShape(&draw);
302 font->layout->bounds[font->numchars].xmin = (bbox.xMin*FT_SCALE*20)/FT_SUBPIXELS;
303 font->layout->bounds[font->numchars].ymin = (bbox.yMin*FT_SCALE*20)/FT_SUBPIXELS;
304 font->layout->bounds[font->numchars].xmax = (bbox.xMax*FT_SCALE*20)/FT_SUBPIXELS;
305 font->layout->bounds[font->numchars].ymax = (bbox.yMax*FT_SCALE*20)/FT_SUBPIXELS;
309 FT_Done_Glyph(glyph);
310 font->glyph2ascii[font->numchars] = font->glyph2ascii[t];
311 glyph2glyph[t] = font->numchars;
314 /* notice: if skip_unused is true, font->glyph2ascii, font->glyphnames and font->layout->bounds will
315 have more memory allocated than just font->numchars, but only the first font->numchars
318 for(t=0;t<font->maxascii;t++) {
319 if(font->ascii2glyph[t]>=0) {
320 font->ascii2glyph[t] = glyph2glyph[font->ascii2glyph[t]];
323 rfx_free(glyph2glyph);
326 FT_Done_FreeType(ftlibrary);ftlibrary=0;
330 #else //HAVE_FREETYPE
332 SWFFONT* swf_LoadTrueTypeFont(char*filename)
334 fprintf(stderr, "Warning: no freetype library- not able to load %s\n", filename);
344 static int t1lib_initialized = 0;
346 static int counter = 0;
348 SWFFONT* swf_LoadT1Font(char*filename)
352 float angle,underline;
353 char*fontname,*fullname,*familyname;
362 if(!t1lib_initialized) {
364 if ((T1_InitLib(NO_LOGFILE)==NULL)){
365 fprintf(stderr, "Initialization of t1lib failed\n");
368 t1lib_initialized = 1;
370 nr = T1_AddFont(filename);
373 charnames = T1_GetAllCharNames(nr);
375 fprintf(stderr, "No Charnames record- not a Type1 Font?\n");
379 angle = T1_GetItalicAngle(nr);
380 fontname = T1_GetFontName(nr);
381 fullname = T1_GetFullName(nr);
382 familyname = T1_GetFamilyName(nr);
383 underline = T1_GetUnderlinePosition(nr);
384 bbox = T1_GetFontBBox(nr);
386 font = (SWFFONT*)rfx_calloc(sizeof(SWFFONT));
390 font->name = (U8*)strdup(fontname);
393 font->layout = (SWFLAYOUT*)rfx_calloc(sizeof(SWFLAYOUT));
396 charname = charnames;
400 if(*charname) encoding[num] = strdup(*charname);
401 else encoding[num] = strdup(".notdef");
406 encoding[t] = strdup(".notdef");
408 //T1_ReencodeFont(nr, encoding);
410 font->maxascii = num;
411 font->numchars = num;
413 font->style = (/*bold*/0?FONT_STYLE_BOLD:0) + (angle>0.05?FONT_STYLE_ITALIC:0);
415 font->glyph = (SWFGLYPH*)rfx_calloc(num*sizeof(SWFGLYPH));
416 font->glyph2ascii = (U16*)rfx_calloc(num*sizeof(U16));
417 font->ascii2glyph = (int*)rfx_calloc(font->maxascii*sizeof(int));
418 font->layout->ascent = (U16)(underline - bbox.lly);
419 font->layout->descent = (U16)(bbox.ury - underline);
420 font->layout->leading = (U16)(font->layout->ascent -
421 font->layout->descent -
422 (bbox.lly - bbox.ury));
423 font->layout->bounds = (SRECT*)rfx_calloc(sizeof(SRECT)*num);
424 font->layout->kerningcount = 0;
425 font->layout->kerning = 0;
426 font->glyphnames = rfx_calloc(num*sizeof(char*));
430 charname = charnames;
431 for(c=0;c<font->numchars;c++) {
434 T1_OUTLINE * outline;
438 outline = T1_GetCharOutline(nr, c, 100.0, 0);
439 firstx = outline->dest.x/0xffff;
445 font->glyphnames[c] = strdup(*charname);
448 font->ascii2glyph[c] = c;
449 font->glyph2ascii[c] = c;
451 swf_Shape01DrawerInit(&draw, 0);
454 pos.x += (outline->dest.x/(float)0xffff);
455 pos.y += (outline->dest.y/(float)0xffff);
457 if(outline->type == T1_PATHTYPE_MOVE) {
458 draw.moveTo(&draw,&pos);
459 } else if(outline->type == T1_PATHTYPE_LINE) {
460 draw.lineTo(&draw,&pos);
461 } else if(outline->type == T1_PATHTYPE_BEZIER) {
462 T1_BEZIERSEGMENT*o2 = (T1_BEZIERSEGMENT*)outline;
464 b.x = o2->B.x/(float)0xffff+last.x;
465 b.y = o2->B.y/(float)0xffff+last.y;
466 c.x = o2->C.x/(float)0xffff+last.x;
467 c.y = o2->C.y/(float)0xffff+last.y;
468 draw_cubicTo(&draw,&b,&c,&pos);
470 fprintf(stderr, "loadT1Font: unknown outline type:%d\n", outline->type);
473 outline = outline->link;
474 printf("(%f,%f) ", pos.x, pos.y);
480 font->glyph[c].shape = swf_ShapeDrawerToShape(&draw);
481 bbox = swf_ShapeDrawerGetBBox(&draw);
484 font->layout->bounds[c] = bbox;
485 font->glyph[c].advance = bbox.xmax;
486 if(!font->glyph[c].advance) {
487 font->glyph[c].advance = firstx;
494 rfx_free(encoding[t]);
500 SWFFONT* swf_LoadT1Font(char*filename)
502 fprintf(stderr, "Warning: no t1lib- not able to load %s\n", filename);
508 SWFFONT* swf_DummyFont()
510 SWFFONT*font = (SWFFONT*)rfx_calloc(sizeof(SWFFONT));
514 static int isSWF(const char*filename)
516 FILE*fi = fopen(filename, "rb");
522 memset(a, 0, sizeof(a));
526 if(!strncmp(a, "FWS", 3) || !strncmp(a, "CWS", 3)) {
532 SWFFONT* swf_LoadFont(char*filename)
536 return swf_DummyFont();
537 is_swf = isSWF(filename);
541 return swf_ReadFont(filename);
544 #if defined(HAVE_FREETYPE)
545 return swf_LoadTrueTypeFont(filename);
546 #elif defined(HAVE_T1LIB)
547 return swf_LoadT1Font(filename);
549 fprintf(stderr, "Error: Neither T1lib nor FreeType support compiled in. Could not load %s\n", filename);