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);
138 fprintf(stderr, "Couldn't load file %s- not a TTF file?\n", filename);
142 FT_Set_Pixel_Sizes (face, 16*loadfont_scale, 16*loadfont_scale);
144 if(face->num_glyphs <= 0) {
145 fprintf(stderr, "File %s contains %d glyphs\n", face->num_glyphs);
149 font = rfx_calloc(sizeof(SWFFONT));
152 font->layout = rfx_calloc(sizeof(SWFLAYOUT));
153 font->layout->bounds = rfx_calloc(face->num_glyphs*sizeof(SRECT));
154 font->style = ((face->style_flags&FT_STYLE_FLAG_ITALIC)?FONT_STYLE_ITALIC:0)
155 |((face->style_flags&FT_STYLE_FLAG_BOLD)?FONT_STYLE_BOLD:0);
156 font->encoding = FONT_ENCODING_UNICODE;
157 font->glyph2ascii = rfx_calloc(face->num_glyphs*sizeof(U16));
159 font->glyph = rfx_calloc(face->num_glyphs*sizeof(SWFGLYPH));
160 if(FT_HAS_GLYPH_NAMES(face)) {
161 font->glyphnames = rfx_calloc(face->num_glyphs*sizeof(char*));
164 font->layout->ascent = abs(face->ascender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMin;
165 font->layout->descent = abs(face->descender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMax;
166 font->layout->leading = font->layout->ascent + font->layout->descent;
167 font->layout->kerningcount = 0;
169 name = FT_Get_Postscript_Name(face);
171 font->name = (U8*)strdup(name);
175 /* // Map Glyphs to Unicode, version 1 (quick and dirty):
177 for(t=0;t<65536;t++) {
178 int index = FT_Get_Char_Index(face, t);
179 if(index>=0 && index<face->num_glyphs) {
180 if(font->glyph2ascii[index]<0)
181 font->glyph2ascii[index] = t;
185 // Map Glyphs to Unicode, version 2 (much nicer):
186 // (The third way would be the AGL algorithm, as proposed
187 // by Werner Lemberg on freetype@freetype.org)
189 charcode = FT_Get_First_Char(face, &gindex);
192 if(gindex >= 0 && gindex<face->num_glyphs) {
193 if(!font->glyph2ascii[gindex]) {
194 font->glyph2ascii[gindex] = charcode;
195 if(charcode + 1 > font->maxascii) {
196 font->maxascii = charcode + 1;
200 charcode = FT_Get_Next_Char(face, charcode, &gindex);
203 /* if we didn't find a single encoding character, try
204 the font's charmaps instead. That usually means that
205 the encoding is no longer unicode.
206 TODO: find a way to convert the encoding to unicode
208 if(font->maxascii == 0 && charmap < face->num_charmaps - 1) {
210 FT_Set_Charmap(face, face->charmaps[charmap]);
211 font->encoding = 0;//anything but unicode FIXME
217 font->maxascii = 65535;
219 font->ascii2glyph = rfx_calloc(font->maxascii*sizeof(int));
221 for(t=0;t<font->maxascii;t++) {
222 int g = FT_Get_Char_Index(face, t);
223 if(!g || g>=face->num_glyphs)
225 font->ascii2glyph[t] = g;
228 if(!font->glyph2ascii[g]) {
229 font->glyph2ascii[g] = t;
233 font->maxascii = max_unicode;
237 glyph2glyph = (int*)rfx_calloc(face->num_glyphs*sizeof(int));
239 for(t=0; t < face->num_glyphs; t++) {
248 if(FT_HAS_GLYPH_NAMES(face)) {
249 error = FT_Get_Glyph_Name(face, t, name, 127);
250 if(!error && name[0] && !strstr(name, "notdef")) {
251 font->glyphnames[font->numchars] = strdup(name);
255 if(!font->glyph2ascii[t] && !hasname && skip_unused) {
258 error = FT_Load_Glyph(face, t, FT_LOAD_NO_BITMAP);
260 //tends to happen with some pdfs
261 fprintf(stderr, "Warning: Glyph %d has return code %d\n", t, error);
266 error = FT_Get_Glyph(face->glyph, &glyph);
268 fprintf(stderr, "Couldn't get glyph %d, error:%d\n", t, error);
276 FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_unscaled, &bbox);
278 memset(&bbox, 0, sizeof(bbox));
280 bbox.yMin = -bbox.yMin;
281 bbox.yMax = -bbox.yMax;
282 if(bbox.xMax < bbox.xMin) {
284 bbox.xMax ^= bbox.xMin;
285 bbox.xMin ^= bbox.xMax;
286 bbox.xMax ^= bbox.xMin;
288 if(bbox.yMax < bbox.yMin) {
290 bbox.yMax ^= bbox.yMin;
291 bbox.yMin ^= bbox.yMax;
292 bbox.yMax ^= bbox.yMin;
295 swf_Shape01DrawerInit(&draw, 0);
297 //error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &draw);
299 error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &draw);
305 fprintf(stderr, "Couldn't decompose glyph %d\n", t);
312 font->glyph[font->numchars].advance = (bbox.xMax*20*FT_SCALE)/FT_SUBPIXELS;
314 font->glyph[font->numchars].advance = ((bbox.xMax - bbox.xMin)*20*FT_SCALE)/FT_SUBPIXELS;
318 font->glyph[font->numchars].advance = glyph->advance.x*20/65536;
320 font->glyph[font->numchars].advance = 0;
323 font->glyph[font->numchars].shape = swf_ShapeDrawerToShape(&draw);
325 font->layout->bounds[font->numchars].xmin = (bbox.xMin*FT_SCALE*20)/FT_SUBPIXELS;
326 font->layout->bounds[font->numchars].ymin = (bbox.yMin*FT_SCALE*20)/FT_SUBPIXELS;
327 font->layout->bounds[font->numchars].xmax = (bbox.xMax*FT_SCALE*20)/FT_SUBPIXELS;
328 font->layout->bounds[font->numchars].ymax = (bbox.yMax*FT_SCALE*20)/FT_SUBPIXELS;
333 FT_Done_Glyph(glyph);
334 font->glyph2ascii[font->numchars] = font->glyph2ascii[t];
335 glyph2glyph[t] = font->numchars;
338 /* notice: if skip_unused is true, font->glyph2ascii, font->glyphnames and font->layout->bounds will
339 have more memory allocated than just font->numchars, but only the first font->numchars
342 for(t=0;t<font->maxascii;t++) {
343 if(font->ascii2glyph[t]>=0) {
344 font->ascii2glyph[t] = glyph2glyph[font->ascii2glyph[t]];
347 rfx_free(glyph2glyph);
350 FT_Done_FreeType(ftlibrary);ftlibrary=0;
354 #else //HAVE_FREETYPE
356 SWFFONT* swf_LoadTrueTypeFont(char*filename)
358 fprintf(stderr, "Warning: no freetype library- not able to load %s\n", filename);
368 static int t1lib_initialized = 0;
370 static int counter = 0;
372 SWFFONT* swf_LoadT1Font(char*filename)
376 float angle,underline;
377 char*fontname,*fullname,*familyname;
386 if(!t1lib_initialized) {
388 if ((T1_InitLib(NO_LOGFILE)==NULL)){
389 fprintf(stderr, "Initialization of t1lib failed\n");
392 t1lib_initialized = 1;
394 nr = T1_AddFont(filename);
397 charnames = T1_GetAllCharNames(nr);
399 fprintf(stderr, "No Charnames record- not a Type1 Font?\n");
403 angle = T1_GetItalicAngle(nr);
404 fontname = T1_GetFontName(nr);
405 fullname = T1_GetFullName(nr);
406 familyname = T1_GetFamilyName(nr);
407 underline = T1_GetUnderlinePosition(nr);
408 bbox = T1_GetFontBBox(nr);
410 font = (SWFFONT*)rfx_calloc(sizeof(SWFFONT));
414 font->name = (U8*)strdup(fontname);
417 font->layout = (SWFLAYOUT*)rfx_calloc(sizeof(SWFLAYOUT));
420 charname = charnames;
424 if(*charname) encoding[num] = strdup(*charname);
425 else encoding[num] = strdup(".notdef");
430 encoding[t] = strdup(".notdef");
432 //T1_ReencodeFont(nr, encoding);
434 font->maxascii = num;
435 font->numchars = num;
437 font->style = (/*bold*/0?FONT_STYLE_BOLD:0) + (angle>0.05?FONT_STYLE_ITALIC:0);
439 font->glyph = (SWFGLYPH*)rfx_calloc(num*sizeof(SWFGLYPH));
440 font->glyph2ascii = (U16*)rfx_calloc(num*sizeof(U16));
441 font->ascii2glyph = (int*)rfx_calloc(font->maxascii*sizeof(int));
442 font->layout->ascent = (U16)(underline - bbox.lly);
443 font->layout->descent = (U16)(bbox.ury - underline);
444 font->layout->leading = (U16)(font->layout->ascent -
445 font->layout->descent -
446 (bbox.lly - bbox.ury));
447 font->layout->bounds = (SRECT*)rfx_calloc(sizeof(SRECT)*num);
448 font->layout->kerningcount = 0;
449 font->layout->kerning = 0;
450 font->glyphnames = rfx_calloc(num*sizeof(char*));
454 charname = charnames;
455 for(c=0;c<font->numchars;c++) {
458 T1_OUTLINE * outline;
462 outline = T1_GetCharOutline(nr, c, 100.0, 0);
463 firstx = outline->dest.x/0xffff;
469 font->glyphnames[c] = strdup(*charname);
472 font->ascii2glyph[c] = c;
473 font->glyph2ascii[c] = c;
475 swf_Shape01DrawerInit(&draw, 0);
478 pos.x += (outline->dest.x/(float)0xffff);
479 pos.y += (outline->dest.y/(float)0xffff);
481 if(outline->type == T1_PATHTYPE_MOVE) {
482 draw.moveTo(&draw,&pos);
483 } else if(outline->type == T1_PATHTYPE_LINE) {
484 draw.lineTo(&draw,&pos);
485 } else if(outline->type == T1_PATHTYPE_BEZIER) {
486 T1_BEZIERSEGMENT*o2 = (T1_BEZIERSEGMENT*)outline;
488 b.x = o2->B.x/(float)0xffff+last.x;
489 b.y = o2->B.y/(float)0xffff+last.y;
490 c.x = o2->C.x/(float)0xffff+last.x;
491 c.y = o2->C.y/(float)0xffff+last.y;
492 draw_cubicTo(&draw,&b,&c,&pos);
494 fprintf(stderr, "loadT1Font: unknown outline type:%d\n", outline->type);
497 outline = outline->link;
498 printf("t1lib: (%f,%f) ", pos.x, pos.y);
504 font->glyph[c].shape = swf_ShapeDrawerToShape(&draw);
505 bbox = swf_ShapeDrawerGetBBox(&draw);
508 font->layout->bounds[c] = bbox;
509 font->glyph[c].advance = bbox.xmax;
510 if(!font->glyph[c].advance) {
511 font->glyph[c].advance = firstx;
518 rfx_free(encoding[t]);
524 SWFFONT* swf_LoadT1Font(char*filename)
526 fprintf(stderr, "Warning: no t1lib- not able to load %s\n", filename);
532 SWFFONT* swf_DummyFont()
534 SWFFONT*font = (SWFFONT*)rfx_calloc(sizeof(SWFFONT));
538 static int isSWF(const char*filename)
540 FILE*fi = fopen(filename, "rb");
546 memset(a, 0, sizeof(a));
550 if(!strncmp(a, "FWS", 3) || !strncmp(a, "CWS", 3)) {
556 SWFFONT* swf_LoadFont(char*filename)
560 return swf_DummyFont();
561 is_swf = isSWF(filename);
565 return swf_ReadFont(filename);
568 #if defined(HAVE_FREETYPE)
569 return swf_LoadTrueTypeFont(filename);
570 #elif defined(HAVE_T1LIB)
571 return swf_LoadT1Font(filename);
573 fprintf(stderr, "Error: Neither T1lib nor FreeType support compiled in. Could not load %s\n", filename);