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(const 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(const 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_conic_to(const FT_Vector* _c, const 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 c.x = _c->x*FT_SCALE/(float)FT_SUBPIXELS;
87 c.y = -_c->y*FT_SCALE/(float)FT_SUBPIXELS;
88 draw_conicTo(draw, &c, &to);
91 static int ft_cubic_to(const FT_Vector* _c1, const FT_Vector* _c2, const FT_Vector* _to, void* user)
93 drawer_t* draw = (drawer_t*)user;
95 to.x = _to->x*FT_SCALE/(float)FT_SUBPIXELS;
96 to.y = -_to->y*FT_SCALE/(float)FT_SUBPIXELS;
97 c1.x = _c1->x*FT_SCALE/(float)FT_SUBPIXELS;
98 c1.y = -_c1->y*FT_SCALE/(float)FT_SUBPIXELS;
99 c2.x = _c2->x*FT_SCALE/(float)FT_SUBPIXELS;
100 c2.y = -_c2->y*FT_SCALE/(float)FT_SUBPIXELS;
101 draw_cubicTo(draw, &c1, &c2, &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;
129 if(FT_Init_FreeType(&ftlibrary)) {
130 fprintf(stderr, "Couldn't init freetype library!\n");
134 error = FT_New_Face(ftlibrary, filename, 0, &face);
137 fprintf(stderr, "Couldn't load file %s- not a TTF file?\n", filename);
141 FT_Set_Pixel_Sizes (face, 16*loadfont_scale, 16*loadfont_scale);
143 if(face->num_glyphs <= 0) {
144 fprintf(stderr, "File %s contains %d glyphs\n", face->num_glyphs);
148 font = (SWFFONT*)rfx_calloc(sizeof(SWFFONT));
151 font->layout = (SWFLAYOUT*)rfx_calloc(sizeof(SWFLAYOUT));
152 font->layout->bounds = (SRECT*)rfx_calloc(face->num_glyphs*sizeof(SRECT));
153 font->style = ((face->style_flags&FT_STYLE_FLAG_ITALIC)?FONT_STYLE_ITALIC:0)
154 |((face->style_flags&FT_STYLE_FLAG_BOLD)?FONT_STYLE_BOLD:0);
155 font->encoding = FONT_ENCODING_UNICODE;
156 font->glyph2ascii = (U16*)rfx_calloc(face->num_glyphs*sizeof(U16));
158 font->glyph = (SWFGLYPH*)rfx_calloc(face->num_glyphs*sizeof(SWFGLYPH));
159 if(FT_HAS_GLYPH_NAMES(face)) {
160 font->glyphnames = (char**)rfx_calloc(face->num_glyphs*sizeof(char*));
163 font->layout->ascent = abs(face->ascender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMin;
164 font->layout->descent = abs(face->descender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMax;
165 font->layout->leading = font->layout->ascent + font->layout->descent;
166 font->layout->kerningcount = 0;
168 name = FT_Get_Postscript_Name(face);
170 font->name = (U8*)strdup(name);
174 /* // Map Glyphs to Unicode, version 1 (quick and dirty):
176 for(t=0;t<65536;t++) {
177 int index = FT_Get_Char_Index(face, t);
178 if(index>=0 && index<face->num_glyphs) {
179 if(font->glyph2ascii[index]<0)
180 font->glyph2ascii[index] = t;
184 // Map Glyphs to Unicode, version 2 (much nicer):
185 // (The third way would be the AGL algorithm, as proposed
186 // by Werner Lemberg on freetype@freetype.org)
188 charcode = FT_Get_First_Char(face, &gindex);
191 if(gindex >= 0 && gindex<face->num_glyphs) {
192 if(!font->glyph2ascii[gindex]) {
193 font->glyph2ascii[gindex] = charcode;
194 if(charcode + 1 > font->maxascii) {
195 font->maxascii = charcode + 1;
199 charcode = FT_Get_Next_Char(face, charcode, &gindex);
202 /* if we didn't find a single encoding character, try
203 the font's charmaps instead. That usually means that
204 the encoding is no longer unicode.
205 TODO: find a way to convert the encoding to unicode
207 if(font->maxascii == 0 && charmap < face->num_charmaps - 1) {
209 FT_Set_Charmap(face, face->charmaps[charmap]);
210 font->encoding = 0;//anything but unicode FIXME
216 font->maxascii = 65535;
218 font->ascii2glyph = (int*)rfx_calloc(font->maxascii*sizeof(int));
220 for(t=0;t<font->maxascii;t++) {
221 int g = FT_Get_Char_Index(face, t);
222 if(!g || g>=face->num_glyphs)
224 font->ascii2glyph[t] = g;
227 if(!font->glyph2ascii[g]) {
228 font->glyph2ascii[g] = t;
232 font->maxascii = max_unicode;
236 glyph2glyph = (int*)rfx_calloc(face->num_glyphs*sizeof(int));
238 for(t=0; t < face->num_glyphs; t++) {
245 if(FT_HAS_GLYPH_NAMES(face)) {
246 error = FT_Get_Glyph_Name(face, t, name, 127);
247 if(!error && name[0] && !strstr(name, "notdef")) {
248 font->glyphnames[font->numchars] = strdup(name);
252 if(!font->glyph2ascii[t] && !hasname && skip_unused) {
255 error = FT_Load_Glyph(face, t, FT_LOAD_NO_BITMAP);
257 //tends to happen with some pdfs
258 fprintf(stderr, "Warning: Glyph %d has return code %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;
499 font->glyph[c].shape = swf_ShapeDrawerToShape(&draw);
500 bbox = swf_ShapeDrawerGetBBox(&draw);
503 font->layout->bounds[c] = bbox;
504 font->glyph[c].advance = bbox.xmax;
505 if(!font->glyph[c].advance) {
506 font->glyph[c].advance = firstx;
513 rfx_free(encoding[t]);
519 SWFFONT* swf_LoadT1Font(char*filename)
521 fprintf(stderr, "Warning: no t1lib- not able to load %s\n", filename);
527 SWFFONT* swf_DummyFont()
529 SWFFONT*font = (SWFFONT*)rfx_calloc(sizeof(SWFFONT));
533 static int isSWF(const char*filename)
535 FILE*fi = fopen(filename, "rb");
541 memset(a, 0, sizeof(a));
545 if(!strncmp(a, "FWS", 3) || !strncmp(a, "CWS", 3)) {
551 SWFFONT* swf_LoadFont(char*filename)
555 return swf_DummyFont();
556 is_swf = isSWF(filename);
560 return swf_ReadFont(filename);
563 #if defined(HAVE_FREETYPE)
564 return swf_LoadTrueTypeFont(filename);
565 #elif defined(HAVE_T1LIB)
566 return swf_LoadT1Font(filename);
568 fprintf(stderr, "Error: Neither T1lib nor FreeType support compiled in. Could not load %s\n", filename);