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(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->ascent = abs(face->ascender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMin;
168 font->layout->descent = abs(face->descender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMax;
169 font->layout->leading = font->layout->ascent + font->layout->descent;
170 font->layout->kerningcount = 0;
172 name = FT_Get_Postscript_Name(face);
174 font->name = (U8*)strdup(name);
178 /* // Map Glyphs to Unicode, version 1 (quick and dirty):
180 for(t=0;t<65536;t++) {
181 int index = FT_Get_Char_Index(face, t);
182 if(index>=0 && index<face->num_glyphs) {
183 if(font->glyph2ascii[index]<0)
184 font->glyph2ascii[index] = t;
188 // Map Glyphs to Unicode, version 2 (much nicer):
189 // (The third way would be the AGL algorithm, as proposed
190 // by Werner Lemberg on freetype@freetype.org)
192 charcode = FT_Get_First_Char(face, &gindex);
195 if(gindex >= 0 && gindex<face->num_glyphs) {
196 if(!font->glyph2ascii[gindex]) {
197 font->glyph2ascii[gindex] = charcode;
198 if(charcode + 1 > font->maxascii) {
199 font->maxascii = charcode + 1;
203 charcode = FT_Get_Next_Char(face, charcode, &gindex);
206 /* if we didn't find a single encoding character, try
207 the font's charmaps instead. That usually means that
208 the encoding is no longer unicode.
209 TODO: find a way to convert the encoding to unicode
211 if(font->maxascii == 0 && charmap < face->num_charmaps - 1) {
213 FT_Set_Charmap(face, face->charmaps[charmap]);
214 font->encoding = 0;//anything but unicode FIXME
220 font->maxascii = 65535;
222 font->ascii2glyph = (int*)rfx_calloc(font->maxascii*sizeof(int));
224 for(t=0;t<font->maxascii;t++) {
225 int g = FT_Get_Char_Index(face, t);
226 if(!g || g>=face->num_glyphs)
228 font->ascii2glyph[t] = g;
231 if(!font->glyph2ascii[g]) {
232 font->glyph2ascii[g] = t;
236 font->maxascii = max_unicode;
240 glyph2glyph = (int*)rfx_calloc(face->num_glyphs*sizeof(int));
242 for(t=0; t < face->num_glyphs; t++) {
249 if(FT_HAS_GLYPH_NAMES(face)) {
250 error = FT_Get_Glyph_Name(face, t, name, 127);
251 if(!error && name[0] && !strstr(name, "notdef")) {
252 font->glyphnames[font->numchars] = strdup(name);
256 if(!font->glyph2ascii[t] && !hasname && skip_unused) {
259 error = FT_Load_Glyph(face, t, FT_LOAD_NO_BITMAP);
261 //tends to happen with some pdfs
262 fprintf(stderr, "Warning: Glyph %d has return code %d\n", t, error);
267 error = FT_Get_Glyph(face->glyph, &glyph);
269 fprintf(stderr, "Couldn't get glyph %d, error:%d\n", t, error);
277 FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_unscaled, &bbox);
279 memset(&bbox, 0, sizeof(bbox));
281 bbox.yMin = -bbox.yMin;
282 bbox.yMax = -bbox.yMax;
283 if(bbox.xMax < bbox.xMin) {
285 bbox.xMax ^= bbox.xMin;
286 bbox.xMin ^= bbox.xMax;
287 bbox.xMax ^= bbox.xMin;
289 if(bbox.yMax < bbox.yMin) {
291 bbox.yMax ^= bbox.yMin;
292 bbox.yMin ^= bbox.yMax;
293 bbox.yMax ^= bbox.yMin;
296 swf_Shape01DrawerInit(&draw, 0);
298 //error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &draw);
300 error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &draw);
306 fprintf(stderr, "Couldn't decompose glyph %d\n", t);
313 font->glyph[font->numchars].advance = (bbox.xMax*20*FT_SCALE)/FT_SUBPIXELS;
315 font->glyph[font->numchars].advance = ((bbox.xMax - bbox.xMin)*20*FT_SCALE)/FT_SUBPIXELS;
319 font->glyph[font->numchars].advance = glyph->advance.x*20/65536;
321 font->glyph[font->numchars].advance = 0;
324 font->glyph[font->numchars].shape = swf_ShapeDrawerToShape(&draw);
326 font->layout->bounds[font->numchars].xmin = (bbox.xMin*FT_SCALE*20)/FT_SUBPIXELS;
327 font->layout->bounds[font->numchars].ymin = (bbox.yMin*FT_SCALE*20)/FT_SUBPIXELS;
328 font->layout->bounds[font->numchars].xmax = (bbox.xMax*FT_SCALE*20)/FT_SUBPIXELS;
329 font->layout->bounds[font->numchars].ymax = (bbox.yMax*FT_SCALE*20)/FT_SUBPIXELS;
334 FT_Done_Glyph(glyph);
335 font->glyph2ascii[font->numchars] = font->glyph2ascii[t];
336 glyph2glyph[t] = font->numchars;
339 /* notice: if skip_unused is true, font->glyph2ascii, font->glyphnames and font->layout->bounds will
340 have more memory allocated than just font->numchars, but only the first font->numchars
343 for(t=0;t<font->maxascii;t++) {
344 if(font->ascii2glyph[t]>=0) {
345 font->ascii2glyph[t] = glyph2glyph[font->ascii2glyph[t]];
348 rfx_free(glyph2glyph);
351 FT_Done_FreeType(ftlibrary);ftlibrary=0;
355 #else //HAVE_FREETYPE
357 SWFFONT* swf_LoadTrueTypeFont(char*filename)
359 fprintf(stderr, "Warning: no freetype library- not able to load %s\n", filename);
369 static int t1lib_initialized = 0;
371 static int counter = 0;
373 SWFFONT* swf_LoadT1Font(char*filename)
377 float angle,underline;
378 char*fontname,*fullname,*familyname;
387 if(!t1lib_initialized) {
389 if ((T1_InitLib(NO_LOGFILE)==NULL)){
390 fprintf(stderr, "Initialization of t1lib failed\n");
393 t1lib_initialized = 1;
395 nr = T1_AddFont(filename);
398 charnames = T1_GetAllCharNames(nr);
400 fprintf(stderr, "No Charnames record- not a Type1 Font?\n");
404 angle = T1_GetItalicAngle(nr);
405 fontname = T1_GetFontName(nr);
406 fullname = T1_GetFullName(nr);
407 familyname = T1_GetFamilyName(nr);
408 underline = T1_GetUnderlinePosition(nr);
409 bbox = T1_GetFontBBox(nr);
411 font = (SWFFONT*)rfx_calloc(sizeof(SWFFONT));
415 font->name = (U8*)strdup(fontname);
418 font->layout = (SWFLAYOUT*)rfx_calloc(sizeof(SWFLAYOUT));
421 charname = charnames;
425 if(*charname) encoding[num] = strdup(*charname);
426 else encoding[num] = strdup(".notdef");
431 encoding[t] = strdup(".notdef");
433 //T1_ReencodeFont(nr, encoding);
435 font->maxascii = num;
436 font->numchars = num;
438 font->style = (/*bold*/0?FONT_STYLE_BOLD:0) + (angle>0.05?FONT_STYLE_ITALIC:0);
440 font->glyph = (SWFGLYPH*)rfx_calloc(num*sizeof(SWFGLYPH));
441 font->glyph2ascii = (U16*)rfx_calloc(num*sizeof(U16));
442 font->ascii2glyph = (int*)rfx_calloc(font->maxascii*sizeof(int));
443 font->layout->ascent = (U16)(underline - bbox.lly);
444 font->layout->descent = (U16)(bbox.ury - underline);
445 font->layout->leading = (U16)(font->layout->ascent -
446 font->layout->descent -
447 (bbox.lly - bbox.ury));
448 font->layout->bounds = (SRECT*)rfx_calloc(sizeof(SRECT)*num);
449 font->layout->kerningcount = 0;
450 font->layout->kerning = 0;
451 font->glyphnames = rfx_calloc(num*sizeof(char*));
455 charname = charnames;
456 for(c=0;c<font->numchars;c++) {
459 T1_OUTLINE * outline;
463 outline = T1_GetCharOutline(nr, c, 100.0, 0);
464 firstx = outline->dest.x/0xffff;
470 font->glyphnames[c] = strdup(*charname);
473 font->ascii2glyph[c] = c;
474 font->glyph2ascii[c] = c;
476 swf_Shape01DrawerInit(&draw, 0);
479 pos.x += (outline->dest.x/(float)0xffff);
480 pos.y += (outline->dest.y/(float)0xffff);
482 if(outline->type == T1_PATHTYPE_MOVE) {
483 draw.moveTo(&draw,&pos);
484 } else if(outline->type == T1_PATHTYPE_LINE) {
485 draw.lineTo(&draw,&pos);
486 } else if(outline->type == T1_PATHTYPE_BEZIER) {
487 T1_BEZIERSEGMENT*o2 = (T1_BEZIERSEGMENT*)outline;
489 b.x = o2->B.x/(float)0xffff+last.x;
490 b.y = o2->B.y/(float)0xffff+last.y;
491 c.x = o2->C.x/(float)0xffff+last.x;
492 c.y = o2->C.y/(float)0xffff+last.y;
493 draw_cubicTo(&draw,&b,&c,&pos);
495 fprintf(stderr, "loadT1Font: unknown outline type:%d\n", outline->type);
498 outline = outline->link;
503 font->glyph[c].shape = swf_ShapeDrawerToShape(&draw);
504 bbox = swf_ShapeDrawerGetBBox(&draw);
507 font->layout->bounds[c] = bbox;
508 font->glyph[c].advance = bbox.xmax;
509 if(!font->glyph[c].advance) {
510 font->glyph[c].advance = firstx;
517 rfx_free(encoding[t]);
523 SWFFONT* swf_LoadT1Font(char*filename)
525 fprintf(stderr, "Warning: no t1lib- not able to load %s\n", filename);
531 SWFFONT* swf_DummyFont()
533 SWFFONT*font = (SWFFONT*)rfx_calloc(sizeof(SWFFONT));
537 static int isSWF(const char*filename)
539 FILE*fi = fopen(filename, "rb");
545 memset(a, 0, sizeof(a));
549 if(!strncmp(a, "FWS", 3) || !strncmp(a, "CWS", 3)) {
555 SWFFONT* swf_LoadFont(char*filename)
559 return swf_DummyFont();
560 is_swf = isSWF(filename);
564 return swf_ReadFont(filename);
567 #if defined(HAVE_FREETYPE)
568 return swf_LoadTrueTypeFont(filename);
569 #elif defined(HAVE_T1LIB)
570 return swf_LoadT1Font(filename);
572 fprintf(stderr, "Error: Neither T1lib nor FreeType support compiled in. Could not load %s\n", filename);