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)
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 FT_Set_Pixel_Sizes (face, 16*loadfont_scale, 16*loadfont_scale);
147 if(face->num_glyphs <= 0) {
148 fprintf(stderr, "File %s contains %d glyphs\n", face->num_glyphs);
152 font = (SWFFONT*)rfx_calloc(sizeof(SWFFONT));
155 font->layout = (SWFLAYOUT*)rfx_calloc(sizeof(SWFLAYOUT));
156 font->layout->bounds = (SRECT*)rfx_calloc(face->num_glyphs*sizeof(SRECT));
157 font->style = ((face->style_flags&FT_STYLE_FLAG_ITALIC)?FONT_STYLE_ITALIC:0)
158 |((face->style_flags&FT_STYLE_FLAG_BOLD)?FONT_STYLE_BOLD:0);
159 font->encoding = FONT_ENCODING_UNICODE;
160 font->glyph2ascii = (U16*)rfx_calloc(face->num_glyphs*sizeof(U16));
162 font->glyph = (SWFGLYPH*)rfx_calloc(face->num_glyphs*sizeof(SWFGLYPH));
163 if(FT_HAS_GLYPH_NAMES(face)) {
164 font->glyphnames = (char**)rfx_calloc(face->num_glyphs*sizeof(char*));
167 font->layout->kerningcount = 0;
169 name = face->family_name;
171 name = FT_Get_Postscript_Name(face);
173 font->name = (U8*)strdup(name);
177 /* // Map Glyphs to Unicode, version 1 (quick and dirty):
179 for(t=0;t<65536;t++) {
180 int index = FT_Get_Char_Index(face, t);
181 if(index>=0 && index<face->num_glyphs) {
182 if(font->glyph2ascii[index]<0)
183 font->glyph2ascii[index] = t;
187 // Map Glyphs to Unicode, version 2 (much nicer):
188 // (The third way would be the AGL algorithm, as proposed
189 // by Werner Lemberg on freetype@freetype.org)
191 charcode = FT_Get_First_Char(face, &gindex);
194 if(gindex >= 0 && gindex<face->num_glyphs) {
195 if(!font->glyph2ascii[gindex]) {
196 font->glyph2ascii[gindex] = charcode;
197 if(charcode + 1 > font->maxascii) {
198 font->maxascii = charcode + 1;
202 charcode = FT_Get_Next_Char(face, charcode, &gindex);
205 /* if we didn't find a single encoding character, try
206 the font's charmaps instead. That usually means that
207 the encoding is no longer unicode.
208 TODO: find a way to convert the encoding to unicode
210 if(font->maxascii == 0 && charmap < face->num_charmaps - 1) {
212 FT_Set_Charmap(face, face->charmaps[charmap]);
213 font->encoding = 0;//anything but unicode FIXME
219 font->maxascii = 65535;
221 font->ascii2glyph = (int*)rfx_calloc(font->maxascii*sizeof(int));
223 for(t=0;t<font->maxascii;t++) {
224 int g = FT_Get_Char_Index(face, t);
225 if(!g || g>=face->num_glyphs)
227 font->ascii2glyph[t] = g;
230 if(!font->glyph2ascii[g]) {
231 font->glyph2ascii[g] = t;
235 font->maxascii = max_unicode;
239 glyph2glyph = (int*)rfx_calloc(face->num_glyphs*sizeof(int));
241 SRECT fontbbox = {0,0,0,0};
243 for(t=0; t < face->num_glyphs; t++) {
250 if(FT_HAS_GLYPH_NAMES(face)) {
251 error = FT_Get_Glyph_Name(face, t, name, 127);
252 if(!error && name[0] && !strstr(name, "notdef")) {
253 font->glyphnames[font->numchars] = strdup(name);
257 if(!font->glyph2ascii[t] && !hasname && skip_unused) {
260 error = FT_Load_Glyph(face, t, FT_LOAD_NO_BITMAP);
262 //tends to happen with some pdfs
263 fprintf(stderr, "Warning: Glyph %d has return code %d\n", t, error);
268 error = FT_Get_Glyph(face->glyph, &glyph);
270 fprintf(stderr, "Couldn't get glyph %d, error:%d\n", t, error);
278 FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_unscaled, &bbox);
280 memset(&bbox, 0, sizeof(bbox));
282 bbox.yMin = -bbox.yMin;
283 bbox.yMax = -bbox.yMax;
284 if(bbox.xMax < bbox.xMin) {
286 bbox.xMax ^= bbox.xMin;
287 bbox.xMin ^= bbox.xMax;
288 bbox.xMax ^= bbox.xMin;
290 if(bbox.yMax < bbox.yMin) {
292 bbox.yMax ^= bbox.yMin;
293 bbox.yMin ^= bbox.yMax;
294 bbox.yMax ^= bbox.yMin;
297 swf_Shape01DrawerInit(&draw, 0);
299 //error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &draw);
301 error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &draw);
307 fprintf(stderr, "Couldn't decompose glyph %d\n", t);
314 font->glyph[font->numchars].advance = (bbox.xMax*20*FT_SCALE)/FT_SUBPIXELS;
316 font->glyph[font->numchars].advance = ((bbox.xMax - bbox.xMin)*20*FT_SCALE)/FT_SUBPIXELS;
320 font->glyph[font->numchars].advance = glyph->advance.x*20/65536;
322 font->glyph[font->numchars].advance = 0;
325 SRECT b = swf_ShapeDrawerGetBBox(&draw);
327 //font->layout->bounds[font->numchars].xmin = (bbox.xMin*FT_SCALE*20)/FT_SUBPIXELS;
328 //font->layout->bounds[font->numchars].ymin = (bbox.yMin*FT_SCALE*20)/FT_SUBPIXELS;
329 //font->layout->bounds[font->numchars].xmax = (bbox.xMax*FT_SCALE*20)/FT_SUBPIXELS;
330 //font->layout->bounds[font->numchars].ymax = (bbox.yMax*FT_SCALE*20)/FT_SUBPIXELS;
332 font->layout->bounds[font->numchars] = b;
333 font->glyph[font->numchars].shape = swf_ShapeDrawerToShape(&draw);
335 swf_ExpandRect2(&fontbbox, &font->layout->bounds[font->numchars]);
340 FT_Done_Glyph(glyph);
341 font->glyph2ascii[font->numchars] = font->glyph2ascii[t];
342 glyph2glyph[t] = font->numchars;
346 //font->layout->ascent = abs(face->ascender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMin;
347 //font->layout->descent = abs(face->descender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMax;
348 //font->layout->leading = font->layout->ascent + font->layout->descent;
350 if(-fontbbox.ymin < 0)
351 font->layout->ascent = 0;
353 font->layout->ascent = -fontbbox.ymin;
355 if(-fontbbox.ymax < 0)
356 font->layout->descent = 0;
358 font->layout->descent = -fontbbox.ymax;
360 font->layout->leading = fontbbox.ymax - fontbbox.ymin;
362 /* notice: if skip_unused is true, font->glyph2ascii, font->glyphnames and font->layout->bounds will
363 have more memory allocated than just font->numchars, but only the first font->numchars
366 for(t=0;t<font->maxascii;t++) {
367 if(font->ascii2glyph[t]>=0) {
368 font->ascii2glyph[t] = glyph2glyph[font->ascii2glyph[t]];
371 rfx_free(glyph2glyph);
374 FT_Done_FreeType(ftlibrary);ftlibrary=0;
378 #else //HAVE_FREETYPE
380 SWFFONT* swf_LoadTrueTypeFont(const char*filename)
382 fprintf(stderr, "Warning: no freetype library- not able to load %s\n", filename);
392 static int t1lib_initialized = 0;
394 static int counter = 0;
396 SWFFONT* swf_LoadT1Font(const char*filename)
400 float angle,underline;
401 char*fontname,*fullname,*familyname;
410 if(!t1lib_initialized) {
412 if ((T1_InitLib(NO_LOGFILE)==NULL)){
413 fprintf(stderr, "Initialization of t1lib failed\n");
416 t1lib_initialized = 1;
418 nr = T1_AddFont(filename);
421 charnames = T1_GetAllCharNames(nr);
423 fprintf(stderr, "No Charnames record- not a Type1 Font?\n");
427 angle = T1_GetItalicAngle(nr);
428 fontname = T1_GetFontName(nr);
429 fullname = T1_GetFullName(nr);
430 familyname = T1_GetFamilyName(nr);
431 underline = T1_GetUnderlinePosition(nr);
432 bbox = T1_GetFontBBox(nr);
434 font = (SWFFONT*)rfx_calloc(sizeof(SWFFONT));
438 font->name = (U8*)strdup(fontname);
441 font->layout = (SWFLAYOUT*)rfx_calloc(sizeof(SWFLAYOUT));
444 charname = charnames;
448 if(*charname) encoding[num] = strdup(*charname);
449 else encoding[num] = strdup(".notdef");
454 encoding[t] = strdup(".notdef");
456 //T1_ReencodeFont(nr, encoding);
458 font->maxascii = num;
459 font->numchars = num;
461 font->style = (/*bold*/0?FONT_STYLE_BOLD:0) + (angle>0.05?FONT_STYLE_ITALIC:0);
463 font->glyph = (SWFGLYPH*)rfx_calloc(num*sizeof(SWFGLYPH));
464 font->glyph2ascii = (U16*)rfx_calloc(num*sizeof(U16));
465 font->ascii2glyph = (int*)rfx_calloc(font->maxascii*sizeof(int));
466 font->layout->ascent = (U16)(underline - bbox.lly);
467 font->layout->descent = (U16)(bbox.ury - underline);
468 font->layout->leading = (U16)(font->layout->ascent -
469 font->layout->descent -
470 (bbox.lly - bbox.ury));
471 font->layout->bounds = (SRECT*)rfx_calloc(sizeof(SRECT)*num);
472 font->layout->kerningcount = 0;
473 font->layout->kerning = 0;
474 font->glyphnames = rfx_calloc(num*sizeof(char*));
478 charname = charnames;
479 for(c=0;c<font->numchars;c++) {
482 T1_OUTLINE * outline;
486 outline = T1_GetCharOutline(nr, c, 100.0, 0);
487 firstx = outline->dest.x/0xffff;
493 font->glyphnames[c] = strdup(*charname);
496 font->ascii2glyph[c] = c;
497 font->glyph2ascii[c] = c;
499 swf_Shape01DrawerInit(&draw, 0);
502 pos.x += (outline->dest.x/(float)0xffff);
503 pos.y += (outline->dest.y/(float)0xffff);
505 if(outline->type == T1_PATHTYPE_MOVE) {
506 draw.moveTo(&draw,&pos);
507 } else if(outline->type == T1_PATHTYPE_LINE) {
508 draw.lineTo(&draw,&pos);
509 } else if(outline->type == T1_PATHTYPE_BEZIER) {
510 T1_BEZIERSEGMENT*o2 = (T1_BEZIERSEGMENT*)outline;
512 b.x = o2->B.x/(float)0xffff+last.x;
513 b.y = o2->B.y/(float)0xffff+last.y;
514 c.x = o2->C.x/(float)0xffff+last.x;
515 c.y = o2->C.y/(float)0xffff+last.y;
516 draw_cubicTo(&draw,&b,&c,&pos);
518 fprintf(stderr, "loadT1Font: unknown outline type:%d\n", outline->type);
521 outline = outline->link;
526 font->glyph[c].shape = swf_ShapeDrawerToShape(&draw);
527 bbox = swf_ShapeDrawerGetBBox(&draw);
530 font->layout->bounds[c] = bbox;
531 font->glyph[c].advance = bbox.xmax;
532 if(!font->glyph[c].advance) {
533 font->glyph[c].advance = firstx;
540 rfx_free(encoding[t]);
546 SWFFONT* swf_LoadT1Font(const char*filename)
548 fprintf(stderr, "Warning: no t1lib- not able to load %s\n", filename);
554 SWFFONT* swf_DummyFont()
556 SWFFONT*font = (SWFFONT*)rfx_calloc(sizeof(SWFFONT));
560 static int isSWF(const char*filename)
562 FILE*fi = fopen(filename, "rb");
568 memset(a, 0, sizeof(a));
572 if(!strncmp(a, "FWS", 3) || !strncmp(a, "CWS", 3)) {
578 SWFFONT* swf_LoadFont(const char*filename)
582 return swf_DummyFont();
583 is_swf = isSWF(filename);
587 return swf_ReadFont(filename);
590 #if defined(HAVE_FREETYPE)
591 return swf_LoadTrueTypeFont(filename);
592 #elif defined(HAVE_T1LIB)
593 return swf_LoadT1Font(filename);
595 fprintf(stderr, "Error: Neither T1lib nor FreeType support compiled in. Could not load %s\n", filename);