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 = face->family_name;
174 name = FT_Get_Postscript_Name(face);
176 font->name = (U8*)strdup(name);
180 /* // Map Glyphs to Unicode, version 1 (quick and dirty):
182 for(t=0;t<65536;t++) {
183 int index = FT_Get_Char_Index(face, t);
184 if(index>=0 && index<face->num_glyphs) {
185 if(font->glyph2ascii[index]<0)
186 font->glyph2ascii[index] = t;
190 // Map Glyphs to Unicode, version 2 (much nicer):
191 // (The third way would be the AGL algorithm, as proposed
192 // by Werner Lemberg on freetype@freetype.org)
194 charcode = FT_Get_First_Char(face, &gindex);
197 if(gindex >= 0 && gindex<face->num_glyphs) {
198 if(!font->glyph2ascii[gindex]) {
199 font->glyph2ascii[gindex] = charcode;
200 if(charcode + 1 > font->maxascii) {
201 font->maxascii = charcode + 1;
205 charcode = FT_Get_Next_Char(face, charcode, &gindex);
208 /* if we didn't find a single encoding character, try
209 the font's charmaps instead. That usually means that
210 the encoding is no longer unicode.
211 TODO: find a way to convert the encoding to unicode
213 if(font->maxascii == 0 && charmap < face->num_charmaps - 1) {
215 FT_Set_Charmap(face, face->charmaps[charmap]);
216 font->encoding = 0;//anything but unicode FIXME
222 font->maxascii = 65535;
224 font->ascii2glyph = (int*)rfx_calloc(font->maxascii*sizeof(int));
226 for(t=0;t<font->maxascii;t++) {
227 int g = FT_Get_Char_Index(face, t);
228 if(!g || g>=face->num_glyphs)
230 font->ascii2glyph[t] = g;
233 if(!font->glyph2ascii[g]) {
234 font->glyph2ascii[g] = t;
238 font->maxascii = max_unicode;
242 glyph2glyph = (int*)rfx_calloc(face->num_glyphs*sizeof(int));
244 for(t=0; t < face->num_glyphs; t++) {
251 if(FT_HAS_GLYPH_NAMES(face)) {
252 error = FT_Get_Glyph_Name(face, t, name, 127);
253 if(!error && name[0] && !strstr(name, "notdef")) {
254 font->glyphnames[font->numchars] = strdup(name);
258 if(!font->glyph2ascii[t] && !hasname && skip_unused) {
261 error = FT_Load_Glyph(face, t, FT_LOAD_NO_BITMAP);
263 //tends to happen with some pdfs
264 fprintf(stderr, "Warning: Glyph %d has return code %d\n", t, error);
269 error = FT_Get_Glyph(face->glyph, &glyph);
271 fprintf(stderr, "Couldn't get glyph %d, error:%d\n", t, error);
279 FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_unscaled, &bbox);
281 memset(&bbox, 0, sizeof(bbox));
283 bbox.yMin = -bbox.yMin;
284 bbox.yMax = -bbox.yMax;
285 if(bbox.xMax < bbox.xMin) {
287 bbox.xMax ^= bbox.xMin;
288 bbox.xMin ^= bbox.xMax;
289 bbox.xMax ^= bbox.xMin;
291 if(bbox.yMax < bbox.yMin) {
293 bbox.yMax ^= bbox.yMin;
294 bbox.yMin ^= bbox.yMax;
295 bbox.yMax ^= bbox.yMin;
298 swf_Shape01DrawerInit(&draw, 0);
300 //error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &draw);
302 error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &draw);
308 fprintf(stderr, "Couldn't decompose glyph %d\n", t);
315 font->glyph[font->numchars].advance = (bbox.xMax*20*FT_SCALE)/FT_SUBPIXELS;
317 font->glyph[font->numchars].advance = ((bbox.xMax - bbox.xMin)*20*FT_SCALE)/FT_SUBPIXELS;
321 font->glyph[font->numchars].advance = glyph->advance.x*20/65536;
323 font->glyph[font->numchars].advance = 0;
326 font->glyph[font->numchars].shape = swf_ShapeDrawerToShape(&draw);
328 font->layout->bounds[font->numchars].xmin = (bbox.xMin*FT_SCALE*20)/FT_SUBPIXELS;
329 font->layout->bounds[font->numchars].ymin = (bbox.yMin*FT_SCALE*20)/FT_SUBPIXELS;
330 font->layout->bounds[font->numchars].xmax = (bbox.xMax*FT_SCALE*20)/FT_SUBPIXELS;
331 font->layout->bounds[font->numchars].ymax = (bbox.yMax*FT_SCALE*20)/FT_SUBPIXELS;
336 FT_Done_Glyph(glyph);
337 font->glyph2ascii[font->numchars] = font->glyph2ascii[t];
338 glyph2glyph[t] = font->numchars;
341 /* notice: if skip_unused is true, font->glyph2ascii, font->glyphnames and font->layout->bounds will
342 have more memory allocated than just font->numchars, but only the first font->numchars
345 for(t=0;t<font->maxascii;t++) {
346 if(font->ascii2glyph[t]>=0) {
347 font->ascii2glyph[t] = glyph2glyph[font->ascii2glyph[t]];
350 rfx_free(glyph2glyph);
353 FT_Done_FreeType(ftlibrary);ftlibrary=0;
357 #else //HAVE_FREETYPE
359 SWFFONT* swf_LoadTrueTypeFont(char*filename)
361 fprintf(stderr, "Warning: no freetype library- not able to load %s\n", filename);
371 static int t1lib_initialized = 0;
373 static int counter = 0;
375 SWFFONT* swf_LoadT1Font(char*filename)
379 float angle,underline;
380 char*fontname,*fullname,*familyname;
389 if(!t1lib_initialized) {
391 if ((T1_InitLib(NO_LOGFILE)==NULL)){
392 fprintf(stderr, "Initialization of t1lib failed\n");
395 t1lib_initialized = 1;
397 nr = T1_AddFont(filename);
400 charnames = T1_GetAllCharNames(nr);
402 fprintf(stderr, "No Charnames record- not a Type1 Font?\n");
406 angle = T1_GetItalicAngle(nr);
407 fontname = T1_GetFontName(nr);
408 fullname = T1_GetFullName(nr);
409 familyname = T1_GetFamilyName(nr);
410 underline = T1_GetUnderlinePosition(nr);
411 bbox = T1_GetFontBBox(nr);
413 font = (SWFFONT*)rfx_calloc(sizeof(SWFFONT));
417 font->name = (U8*)strdup(fontname);
420 font->layout = (SWFLAYOUT*)rfx_calloc(sizeof(SWFLAYOUT));
423 charname = charnames;
427 if(*charname) encoding[num] = strdup(*charname);
428 else encoding[num] = strdup(".notdef");
433 encoding[t] = strdup(".notdef");
435 //T1_ReencodeFont(nr, encoding);
437 font->maxascii = num;
438 font->numchars = num;
440 font->style = (/*bold*/0?FONT_STYLE_BOLD:0) + (angle>0.05?FONT_STYLE_ITALIC:0);
442 font->glyph = (SWFGLYPH*)rfx_calloc(num*sizeof(SWFGLYPH));
443 font->glyph2ascii = (U16*)rfx_calloc(num*sizeof(U16));
444 font->ascii2glyph = (int*)rfx_calloc(font->maxascii*sizeof(int));
445 font->layout->ascent = (U16)(underline - bbox.lly);
446 font->layout->descent = (U16)(bbox.ury - underline);
447 font->layout->leading = (U16)(font->layout->ascent -
448 font->layout->descent -
449 (bbox.lly - bbox.ury));
450 font->layout->bounds = (SRECT*)rfx_calloc(sizeof(SRECT)*num);
451 font->layout->kerningcount = 0;
452 font->layout->kerning = 0;
453 font->glyphnames = rfx_calloc(num*sizeof(char*));
457 charname = charnames;
458 for(c=0;c<font->numchars;c++) {
461 T1_OUTLINE * outline;
465 outline = T1_GetCharOutline(nr, c, 100.0, 0);
466 firstx = outline->dest.x/0xffff;
472 font->glyphnames[c] = strdup(*charname);
475 font->ascii2glyph[c] = c;
476 font->glyph2ascii[c] = c;
478 swf_Shape01DrawerInit(&draw, 0);
481 pos.x += (outline->dest.x/(float)0xffff);
482 pos.y += (outline->dest.y/(float)0xffff);
484 if(outline->type == T1_PATHTYPE_MOVE) {
485 draw.moveTo(&draw,&pos);
486 } else if(outline->type == T1_PATHTYPE_LINE) {
487 draw.lineTo(&draw,&pos);
488 } else if(outline->type == T1_PATHTYPE_BEZIER) {
489 T1_BEZIERSEGMENT*o2 = (T1_BEZIERSEGMENT*)outline;
491 b.x = o2->B.x/(float)0xffff+last.x;
492 b.y = o2->B.y/(float)0xffff+last.y;
493 c.x = o2->C.x/(float)0xffff+last.x;
494 c.y = o2->C.y/(float)0xffff+last.y;
495 draw_cubicTo(&draw,&b,&c,&pos);
497 fprintf(stderr, "loadT1Font: unknown outline type:%d\n", outline->type);
500 outline = outline->link;
505 font->glyph[c].shape = swf_ShapeDrawerToShape(&draw);
506 bbox = swf_ShapeDrawerGetBBox(&draw);
509 font->layout->bounds[c] = bbox;
510 font->glyph[c].advance = bbox.xmax;
511 if(!font->glyph[c].advance) {
512 font->glyph[c].advance = firstx;
519 rfx_free(encoding[t]);
525 SWFFONT* swf_LoadT1Font(char*filename)
527 fprintf(stderr, "Warning: no t1lib- not able to load %s\n", filename);
533 SWFFONT* swf_DummyFont()
535 SWFFONT*font = (SWFFONT*)rfx_calloc(sizeof(SWFFONT));
539 static int isSWF(const char*filename)
541 FILE*fi = fopen(filename, "rb");
547 memset(a, 0, sizeof(a));
551 if(!strncmp(a, "FWS", 3) || !strncmp(a, "CWS", 3)) {
557 SWFFONT* swf_LoadFont(char*filename)
561 return swf_DummyFont();
562 is_swf = isSWF(filename);
566 return swf_ReadFont(filename);
569 #if defined(HAVE_FREETYPE)
570 return swf_LoadTrueTypeFont(filename);
571 #elif defined(HAVE_T1LIB)
572 return swf_LoadT1Font(filename);
574 fprintf(stderr, "Error: Neither T1lib nor FreeType support compiled in. Could not load %s\n", filename);