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 */
26 #include "../rfxswf.h"
28 static int loadfont_scale = 4;
29 static int skip_unused = 1;
30 static int full_unicode = 0;
32 void swf_SetLoadFontParameters(int _scale, int _skip_unused, int _full_unicode)
34 if(_scale) loadfont_scale = _scale;
35 skip_unused = _skip_unused;
36 full_unicode = _full_unicode;
41 #ifdef HAVE_FT2BUILD_H
43 #include FT_FREETYPE_H
46 #include FT_SFNT_NAMES_H
47 #include FT_TRUETYPE_IDS_H
50 #include <freetype/freetype.h>
51 #include <freetype/ftglyph.h>
52 #include <freetype/ftsizes.h>
53 #include <freetype/ftsnames.h>
54 #include <freetype/ttnameid.h>
55 #include <freetype/ftoutln.h>
58 /* Setting subpixels to 64 also means that the "point size" of the
59 font outlines will be 64. So the font, when rendered at original
60 size (i.e., the swf fontsize is 1024) will have the same size as
61 if it was rendered at 64pt */
64 #define FT_SUBPIXELS 64
66 static int ft_move_to(const 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->moveTo(draw, &to);
75 static int ft_line_to(const 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 draw->lineTo(draw, &to);
84 static int ft_conic_to(const FT_Vector* _c, const FT_Vector* _to, void* user)
86 drawer_t* draw = (drawer_t*)user;
88 to.x = _to->x*FT_SCALE/(float)FT_SUBPIXELS;
89 to.y = -_to->y*FT_SCALE/(float)FT_SUBPIXELS;
90 c.x = _c->x*FT_SCALE/(float)FT_SUBPIXELS;
91 c.y = -_c->y*FT_SCALE/(float)FT_SUBPIXELS;
92 draw_conicTo(draw, &c, &to);
95 static int ft_cubic_to(const FT_Vector* _c1, const FT_Vector* _c2, const FT_Vector* _to, void* user)
97 drawer_t* draw = (drawer_t*)user;
99 to.x = _to->x*FT_SCALE/(float)FT_SUBPIXELS;
100 to.y = -_to->y*FT_SCALE/(float)FT_SUBPIXELS;
101 c1.x = _c1->x*FT_SCALE/(float)FT_SUBPIXELS;
102 c1.y = -_c1->y*FT_SCALE/(float)FT_SUBPIXELS;
103 c2.x = _c2->x*FT_SCALE/(float)FT_SUBPIXELS;
104 c2.y = -_c2->y*FT_SCALE/(float)FT_SUBPIXELS;
105 draw_cubicTo(draw, &c1, &c2, &to);
108 static FT_Outline_Funcs outline_functions =
117 static FT_Library ftlibrary = 0;
119 SWFFONT* swf_LoadTrueTypeFont(const char*filename, char flashtype)
123 const char* name = 0;
133 if(FT_Init_FreeType(&ftlibrary)) {
134 fprintf(stderr, "Couldn't init freetype library!\n");
138 error = FT_New_Face(ftlibrary, filename, 0, &face);
141 fprintf(stderr, "Couldn't load file %s- not a TTF file?\n", filename);
145 int scale = flashtype?20:1;
146 FT_Set_Pixel_Sizes (face, 16*loadfont_scale*scale, 16*loadfont_scale*scale);
148 if(face->num_glyphs <= 0) {
149 fprintf(stderr, "File %s contains %d glyphs\n", filename, (int)face->num_glyphs);
153 font = (SWFFONT*)rfx_calloc(sizeof(SWFFONT));
155 font->version = flashtype?3:2;
157 font->layout = (SWFLAYOUT*)rfx_calloc(sizeof(SWFLAYOUT));
158 font->layout->bounds = (SRECT*)rfx_calloc(face->num_glyphs*sizeof(SRECT));
159 font->style = ((face->style_flags&FT_STYLE_FLAG_ITALIC)?FONT_STYLE_ITALIC:0)
160 |((face->style_flags&FT_STYLE_FLAG_BOLD)?FONT_STYLE_BOLD:0);
161 font->encoding = FONT_ENCODING_UNICODE;
162 font->glyph2ascii = (U16*)rfx_calloc(face->num_glyphs*sizeof(U16));
164 font->glyph = (SWFGLYPH*)rfx_calloc(face->num_glyphs*sizeof(SWFGLYPH));
165 if(FT_HAS_GLYPH_NAMES(face)) {
166 font->glyphnames = (char**)rfx_calloc(face->num_glyphs*sizeof(char*));
169 font->layout->kerningcount = 0;
171 name = face->family_name;
173 name = FT_Get_Postscript_Name(face);
175 font->name = (U8*)strdup(name);
179 /* // Map Glyphs to Unicode, version 1 (quick and dirty):
181 for(t=0;t<65536;t++) {
182 int index = FT_Get_Char_Index(face, t);
183 if(index>=0 && index<face->num_glyphs) {
184 if(font->glyph2ascii[index]<0)
185 font->glyph2ascii[index] = t;
189 // Map Glyphs to Unicode, version 2 (much nicer):
190 // (The third way would be the AGL algorithm, as proposed
191 // by Werner Lemberg on freetype@freetype.org)
193 charcode = FT_Get_First_Char(face, &gindex);
196 if(gindex >= 0 && gindex<face->num_glyphs) {
197 if(!font->glyph2ascii[gindex]) {
198 font->glyph2ascii[gindex] = charcode;
199 if(charcode + 1 > font->maxascii) {
200 font->maxascii = charcode + 1;
204 charcode = FT_Get_Next_Char(face, charcode, &gindex);
207 /* if we didn't find a single encoding character, try
208 the font's charmaps instead. That usually means that
209 the encoding is no longer unicode.
210 TODO: find a way to convert the encoding to unicode
212 if(font->maxascii == 0 && charmap < face->num_charmaps - 1) {
214 FT_Set_Charmap(face, face->charmaps[charmap]);
215 font->encoding = 0;//anything but unicode FIXME
221 font->maxascii = 65535;
223 font->ascii2glyph = (int*)rfx_calloc(font->maxascii*sizeof(int));
225 for(t=0;t<font->maxascii;t++) {
226 int g = FT_Get_Char_Index(face, t);
227 if(!g || g>=face->num_glyphs)
229 font->ascii2glyph[t] = g;
232 if(!font->glyph2ascii[g]) {
233 font->glyph2ascii[g] = t;
237 font->maxascii = max_unicode;
241 glyph2glyph = (int*)rfx_calloc(face->num_glyphs*sizeof(int));
243 SRECT fontbbox = {0,0,0,0};
245 for(t=0; t < face->num_glyphs; t++) {
252 if(FT_HAS_GLYPH_NAMES(face)) {
253 error = FT_Get_Glyph_Name(face, t, name, 127);
254 if(!error && name[0] && !strstr(name, "notdef")) {
255 font->glyphnames[font->numchars] = strdup(name);
259 if(!font->glyph2ascii[t] && !hasname && skip_unused) {
262 error = FT_Load_Glyph(face, t, FT_LOAD_NO_BITMAP);
264 //tends to happen with some pdfs
265 fprintf(stderr, "Warning: Glyph %d has return code %d\n", t, error);
270 error = FT_Get_Glyph(face->glyph, &glyph);
272 fprintf(stderr, "Couldn't get glyph %d, error:%d\n", t, error);
280 FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_unscaled, &bbox);
282 memset(&bbox, 0, sizeof(bbox));
284 bbox.yMin = -bbox.yMin;
285 bbox.yMax = -bbox.yMax;
286 if(bbox.xMax < bbox.xMin) {
288 bbox.xMax ^= bbox.xMin;
289 bbox.xMin ^= bbox.xMax;
290 bbox.xMax ^= bbox.xMin;
292 if(bbox.yMax < bbox.yMin) {
294 bbox.yMax ^= bbox.yMin;
295 bbox.yMin ^= bbox.yMax;
296 bbox.yMax ^= bbox.yMin;
299 swf_Shape01DrawerInit(&draw, 0);
301 //error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &draw);
303 error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &draw);
309 fprintf(stderr, "Couldn't decompose glyph %d\n", t);
316 font->glyph[font->numchars].advance = (bbox.xMax*20*FT_SCALE)/FT_SUBPIXELS;
318 font->glyph[font->numchars].advance = ((bbox.xMax - bbox.xMin)*20*FT_SCALE)/FT_SUBPIXELS;
322 font->glyph[font->numchars].advance = glyph->advance.x*20/65536;
324 font->glyph[font->numchars].advance = 0;
327 SRECT b = swf_ShapeDrawerGetBBox(&draw);
329 //font->layout->bounds[font->numchars].xmin = (bbox.xMin*FT_SCALE*20)/FT_SUBPIXELS;
330 //font->layout->bounds[font->numchars].ymin = (bbox.yMin*FT_SCALE*20)/FT_SUBPIXELS;
331 //font->layout->bounds[font->numchars].xmax = (bbox.xMax*FT_SCALE*20)/FT_SUBPIXELS;
332 //font->layout->bounds[font->numchars].ymax = (bbox.yMax*FT_SCALE*20)/FT_SUBPIXELS;
334 font->layout->bounds[font->numchars] = b;
335 font->glyph[font->numchars].shape = swf_ShapeDrawerToShape(&draw);
337 swf_ExpandRect2(&fontbbox, &font->layout->bounds[font->numchars]);
342 FT_Done_Glyph(glyph);
343 font->glyph2ascii[font->numchars] = font->glyph2ascii[t];
344 glyph2glyph[t] = font->numchars;
348 //font->layout->ascent = abs(face->ascender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMin;
349 //font->layout->descent = abs(face->descender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMax;
350 //font->layout->leading = font->layout->ascent + font->layout->descent;
352 if(-fontbbox.ymin < 0)
353 font->layout->ascent = 0;
355 font->layout->ascent = -fontbbox.ymin;
357 if(fontbbox.ymax < 0)
358 font->layout->descent = 0;
360 font->layout->descent = fontbbox.ymax;
362 int leading = fontbbox.ymax - fontbbox.ymin;
363 font->layout->leading = leading>0x7fff?0x7fff:leading;
365 /* notice: if skip_unused is true, font->glyph2ascii, font->glyphnames and font->layout->bounds will
366 have more memory allocated than just font->numchars, but only the first font->numchars
369 for(t=0;t<font->maxascii;t++) {
370 if(font->ascii2glyph[t]>=0) {
371 font->ascii2glyph[t] = glyph2glyph[font->ascii2glyph[t]];
374 rfx_free(glyph2glyph);
377 FT_Done_FreeType(ftlibrary);ftlibrary=0;
381 #else //HAVE_FREETYPE
383 SWFFONT* swf_LoadTrueTypeFont(const char*filename, char flashtype)
385 fprintf(stderr, "Warning: no freetype library- not able to load %s\n", filename);
395 static int t1lib_initialized = 0;
397 static int counter = 0;
399 SWFFONT* swf_LoadT1Font(const char*filename)
403 float angle,underline;
404 char*fontname,*fullname,*familyname;
413 if(!t1lib_initialized) {
415 if ((T1_InitLib(NO_LOGFILE)==NULL)){
416 fprintf(stderr, "Initialization of t1lib failed\n");
419 t1lib_initialized = 1;
421 nr = T1_AddFont(filename);
424 charnames = T1_GetAllCharNames(nr);
426 fprintf(stderr, "No Charnames record- not a Type1 Font?\n");
430 angle = T1_GetItalicAngle(nr);
431 fontname = T1_GetFontName(nr);
432 fullname = T1_GetFullName(nr);
433 familyname = T1_GetFamilyName(nr);
434 underline = T1_GetUnderlinePosition(nr);
435 bbox = T1_GetFontBBox(nr);
437 font = (SWFFONT*)rfx_calloc(sizeof(SWFFONT));
441 font->name = (U8*)strdup(fontname);
444 font->layout = (SWFLAYOUT*)rfx_calloc(sizeof(SWFLAYOUT));
447 charname = charnames;
451 if(*charname) encoding[num] = strdup(*charname);
452 else encoding[num] = strdup(".notdef");
457 encoding[t] = strdup(".notdef");
459 //T1_ReencodeFont(nr, encoding);
461 font->maxascii = num;
462 font->numchars = num;
464 font->style = (/*bold*/0?FONT_STYLE_BOLD:0) + (angle>0.05?FONT_STYLE_ITALIC:0);
466 font->glyph = (SWFGLYPH*)rfx_calloc(num*sizeof(SWFGLYPH));
467 font->glyph2ascii = (U16*)rfx_calloc(num*sizeof(U16));
468 font->ascii2glyph = (int*)rfx_calloc(font->maxascii*sizeof(int));
469 font->layout->ascent = (U16)(underline - bbox.lly);
470 font->layout->descent = (U16)(bbox.ury - underline);
471 font->layout->leading = (U16)(font->layout->ascent -
472 font->layout->descent -
473 (bbox.lly - bbox.ury));
474 font->layout->bounds = (SRECT*)rfx_calloc(sizeof(SRECT)*num);
475 font->layout->kerningcount = 0;
476 font->layout->kerning = 0;
477 font->glyphnames = rfx_calloc(num*sizeof(char*));
481 charname = charnames;
482 for(c=0;c<font->numchars;c++) {
485 T1_OUTLINE * outline;
489 outline = T1_GetCharOutline(nr, c, 100.0, 0);
490 firstx = outline->dest.x/0xffff;
496 font->glyphnames[c] = strdup(*charname);
499 font->ascii2glyph[c] = c;
500 font->glyph2ascii[c] = c;
502 swf_Shape01DrawerInit(&draw, 0);
505 pos.x += (outline->dest.x/(float)0xffff);
506 pos.y += (outline->dest.y/(float)0xffff);
508 if(outline->type == T1_PATHTYPE_MOVE) {
509 draw.moveTo(&draw,&pos);
510 } else if(outline->type == T1_PATHTYPE_LINE) {
511 draw.lineTo(&draw,&pos);
512 } else if(outline->type == T1_PATHTYPE_BEZIER) {
513 T1_BEZIERSEGMENT*o2 = (T1_BEZIERSEGMENT*)outline;
515 b.x = o2->B.x/(float)0xffff+last.x;
516 b.y = o2->B.y/(float)0xffff+last.y;
517 c.x = o2->C.x/(float)0xffff+last.x;
518 c.y = o2->C.y/(float)0xffff+last.y;
519 draw_cubicTo(&draw,&b,&c,&pos);
521 fprintf(stderr, "loadT1Font: unknown outline type:%d\n", outline->type);
524 outline = outline->link;
529 font->glyph[c].shape = swf_ShapeDrawerToShape(&draw);
530 bbox = swf_ShapeDrawerGetBBox(&draw);
533 font->layout->bounds[c] = bbox;
534 font->glyph[c].advance = bbox.xmax;
535 if(!font->glyph[c].advance) {
536 font->glyph[c].advance = firstx;
543 rfx_free(encoding[t]);
549 SWFFONT* swf_LoadT1Font(const char*filename)
551 fprintf(stderr, "Warning: no t1lib- not able to load %s\n", filename);
557 SWFFONT* swf_DummyFont()
559 SWFFONT*font = (SWFFONT*)rfx_calloc(sizeof(SWFFONT));
563 static int isSWF(const char*filename)
565 FILE*fi = fopen(filename, "rb");
571 memset(a, 0, sizeof(a));
575 if(!strncmp(a, "FWS", 3) || !strncmp(a, "CWS", 3)) {
581 SWFFONT* swf_LoadFont(const char*filename, char flashtype)
585 return swf_DummyFont();
586 is_swf = isSWF(filename);
590 SWFFONT*font = swf_ReadFont(filename);
591 if(flashtype && font->version==2)
592 fprintf(stderr, "Warning: Can't load font v2 file as flashtype (%s)\n", filename);
596 #if defined(HAVE_FREETYPE)
597 return swf_LoadTrueTypeFont(filename, flashtype);
598 #elif defined(HAVE_T1LIB)
599 return swf_LoadT1Font(filename);
601 fprintf(stderr, "Error: Neither T1lib nor FreeType support compiled in. Could not load %s\n", filename);