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 font->layout->ascent = -fontbbox.ymin;
351 if(font->layout->ascent < 0)
352 font->layout->ascent = 0;
353 font->layout->descent = fontbbox.ymax;
354 if(font->layout->descent < 0)
355 font->layout->descent = 0;
356 font->layout->leading = fontbbox.ymax - fontbbox.ymin;
358 /* notice: if skip_unused is true, font->glyph2ascii, font->glyphnames and font->layout->bounds will
359 have more memory allocated than just font->numchars, but only the first font->numchars
362 for(t=0;t<font->maxascii;t++) {
363 if(font->ascii2glyph[t]>=0) {
364 font->ascii2glyph[t] = glyph2glyph[font->ascii2glyph[t]];
367 rfx_free(glyph2glyph);
370 FT_Done_FreeType(ftlibrary);ftlibrary=0;
374 #else //HAVE_FREETYPE
376 SWFFONT* swf_LoadTrueTypeFont(const char*filename)
378 fprintf(stderr, "Warning: no freetype library- not able to load %s\n", filename);
388 static int t1lib_initialized = 0;
390 static int counter = 0;
392 SWFFONT* swf_LoadT1Font(const char*filename)
396 float angle,underline;
397 char*fontname,*fullname,*familyname;
406 if(!t1lib_initialized) {
408 if ((T1_InitLib(NO_LOGFILE)==NULL)){
409 fprintf(stderr, "Initialization of t1lib failed\n");
412 t1lib_initialized = 1;
414 nr = T1_AddFont(filename);
417 charnames = T1_GetAllCharNames(nr);
419 fprintf(stderr, "No Charnames record- not a Type1 Font?\n");
423 angle = T1_GetItalicAngle(nr);
424 fontname = T1_GetFontName(nr);
425 fullname = T1_GetFullName(nr);
426 familyname = T1_GetFamilyName(nr);
427 underline = T1_GetUnderlinePosition(nr);
428 bbox = T1_GetFontBBox(nr);
430 font = (SWFFONT*)rfx_calloc(sizeof(SWFFONT));
434 font->name = (U8*)strdup(fontname);
437 font->layout = (SWFLAYOUT*)rfx_calloc(sizeof(SWFLAYOUT));
440 charname = charnames;
444 if(*charname) encoding[num] = strdup(*charname);
445 else encoding[num] = strdup(".notdef");
450 encoding[t] = strdup(".notdef");
452 //T1_ReencodeFont(nr, encoding);
454 font->maxascii = num;
455 font->numchars = num;
457 font->style = (/*bold*/0?FONT_STYLE_BOLD:0) + (angle>0.05?FONT_STYLE_ITALIC:0);
459 font->glyph = (SWFGLYPH*)rfx_calloc(num*sizeof(SWFGLYPH));
460 font->glyph2ascii = (U16*)rfx_calloc(num*sizeof(U16));
461 font->ascii2glyph = (int*)rfx_calloc(font->maxascii*sizeof(int));
462 font->layout->ascent = (U16)(underline - bbox.lly);
463 font->layout->descent = (U16)(bbox.ury - underline);
464 font->layout->leading = (U16)(font->layout->ascent -
465 font->layout->descent -
466 (bbox.lly - bbox.ury));
467 font->layout->bounds = (SRECT*)rfx_calloc(sizeof(SRECT)*num);
468 font->layout->kerningcount = 0;
469 font->layout->kerning = 0;
470 font->glyphnames = rfx_calloc(num*sizeof(char*));
474 charname = charnames;
475 for(c=0;c<font->numchars;c++) {
478 T1_OUTLINE * outline;
482 outline = T1_GetCharOutline(nr, c, 100.0, 0);
483 firstx = outline->dest.x/0xffff;
489 font->glyphnames[c] = strdup(*charname);
492 font->ascii2glyph[c] = c;
493 font->glyph2ascii[c] = c;
495 swf_Shape01DrawerInit(&draw, 0);
498 pos.x += (outline->dest.x/(float)0xffff);
499 pos.y += (outline->dest.y/(float)0xffff);
501 if(outline->type == T1_PATHTYPE_MOVE) {
502 draw.moveTo(&draw,&pos);
503 } else if(outline->type == T1_PATHTYPE_LINE) {
504 draw.lineTo(&draw,&pos);
505 } else if(outline->type == T1_PATHTYPE_BEZIER) {
506 T1_BEZIERSEGMENT*o2 = (T1_BEZIERSEGMENT*)outline;
508 b.x = o2->B.x/(float)0xffff+last.x;
509 b.y = o2->B.y/(float)0xffff+last.y;
510 c.x = o2->C.x/(float)0xffff+last.x;
511 c.y = o2->C.y/(float)0xffff+last.y;
512 draw_cubicTo(&draw,&b,&c,&pos);
514 fprintf(stderr, "loadT1Font: unknown outline type:%d\n", outline->type);
517 outline = outline->link;
522 font->glyph[c].shape = swf_ShapeDrawerToShape(&draw);
523 bbox = swf_ShapeDrawerGetBBox(&draw);
526 font->layout->bounds[c] = bbox;
527 font->glyph[c].advance = bbox.xmax;
528 if(!font->glyph[c].advance) {
529 font->glyph[c].advance = firstx;
536 rfx_free(encoding[t]);
542 SWFFONT* swf_LoadT1Font(const char*filename)
544 fprintf(stderr, "Warning: no t1lib- not able to load %s\n", filename);
550 SWFFONT* swf_DummyFont()
552 SWFFONT*font = (SWFFONT*)rfx_calloc(sizeof(SWFFONT));
556 static int isSWF(const char*filename)
558 FILE*fi = fopen(filename, "rb");
564 memset(a, 0, sizeof(a));
568 if(!strncmp(a, "FWS", 3) || !strncmp(a, "CWS", 3)) {
574 SWFFONT* swf_LoadFont(const char*filename)
578 return swf_DummyFont();
579 is_swf = isSWF(filename);
583 return swf_ReadFont(filename);
586 #if defined(HAVE_FREETYPE)
587 return swf_LoadTrueTypeFont(filename);
588 #elif defined(HAVE_T1LIB)
589 return swf_LoadT1Font(filename);
591 fprintf(stderr, "Error: Neither T1lib nor FreeType support compiled in. Could not load %s\n", filename);