1 /* swffont.c
2 
3    Functions for loading external fonts.
4 
5    Extension module for the rfxswf library.
6    Part of the swftools package.
7 
8    Copyright (c) 2003, 2004 Matthias Kramm
9 
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.
14 
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.
19 
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 */
23 
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include "../rfxswf.h"
27 
28 static int loadfont_scale = 4;
29 static int skip_unused = 1;
30 static int full_unicode = 0;
31 
swf_SetLoadFontParameters(int _scale,int _skip_unused,int _full_unicode)32 void swf_SetLoadFontParameters(int _scale, int _skip_unused, int _full_unicode)
33 {
34     if(_scale) loadfont_scale = _scale;
35     skip_unused = _skip_unused;
36     full_unicode = _full_unicode;
37 }
38 
39 #ifdef HAVE_FREETYPE
40 
41 #ifdef HAVE_FT2BUILD_H
42 #include <ft2build.h>
43 #include FT_FREETYPE_H
44 #include FT_GLYPH_H
45 #include FT_SIZES_H
46 #include FT_SFNT_NAMES_H
47 #include FT_TRUETYPE_IDS_H
48 #include FT_OUTLINE_H
49 #else
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>
56 #endif
57 
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 */
62 
63 #define FT_SCALE 1
64 #define FT_SUBPIXELS 64
65 
ft_move_to(const FT_Vector * _to,void * user)66 static int ft_move_to(const FT_Vector* _to, void* user)
67 {
68     drawer_t* draw = (drawer_t*)user;
69     FPOINT to;
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);
73     return 0;
74 }
ft_line_to(const FT_Vector * _to,void * user)75 static int ft_line_to(const FT_Vector* _to, void* user)
76 {
77     drawer_t* draw = (drawer_t*)user;
78     FPOINT to;
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);
82     return 0;
83 }
ft_conic_to(const FT_Vector * _c,const FT_Vector * _to,void * user)84 static int ft_conic_to(const FT_Vector* _c, const FT_Vector* _to, void* user)
85 {
86     drawer_t* draw = (drawer_t*)user;
87     FPOINT c,to;
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);
93     return 0;
94 }
ft_cubic_to(const FT_Vector * _c1,const FT_Vector * _c2,const FT_Vector * _to,void * user)95 static int ft_cubic_to(const FT_Vector* _c1, const FT_Vector* _c2, const FT_Vector* _to, void* user)
96 {
97     drawer_t* draw = (drawer_t*)user;
98     FPOINT c1,c2,to;
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);
106     return 0;
107 }
108 static FT_Outline_Funcs outline_functions =
109 {
110   ft_move_to,
111   ft_line_to,
112   ft_conic_to,
113   ft_cubic_to,
114   0,0
115 };
116 
117 static FT_Library ftlibrary = 0;
118 
swf_LoadTrueTypeFont(const char * filename,char flashtype)119 SWFFONT* swf_LoadTrueTypeFont(const char*filename, char flashtype)
120 {
121     FT_Face face;
122     FT_Error error;
123     const char* name = 0;
124     FT_ULong charcode;
125     FT_UInt gindex;
126     SWFFONT* font;
127     int t;
128     int*glyph2glyph;
129     int max_unicode = 0;
130     int charmap = -1;
131 
132     if(ftlibrary == 0) {
133 	if(FT_Init_FreeType(&ftlibrary)) {
134 	    fprintf(stderr, "Couldn't init freetype library!\n");
135 	    exit(1);
136 	}
137     }
138     error = FT_New_Face(ftlibrary, filename, 0, &face);
139 
140     if(error || !face) {
141 	fprintf(stderr, "Couldn't load file %s- not a TTF file?\n", filename);
142 	return 0;
143     }
144 
145     int scale = flashtype?20:1;
146     FT_Set_Pixel_Sizes (face, 16*loadfont_scale*scale, 16*loadfont_scale*scale);
147 
148     if(face->num_glyphs <= 0) {
149 	fprintf(stderr, "File %s contains %d glyphs\n", filename, (int)face->num_glyphs);
150 	return 0;
151     }
152 
153     font = (SWFFONT*)rfx_calloc(sizeof(SWFFONT));
154     font->id = -1;
155     font->version = flashtype?3:2;
156 
157     font->layout = (SWFLAYOUT*)rfx_calloc(sizeof(SWFLAYOUT));
158     font->layout->bounds = (SRECT*)rfx_calloc(face->num_glyphs*sizeof(SRECT));
159     font->style =  ((face->style_flags&FT_STYLE_FLAG_ITALIC)?FONT_STYLE_ITALIC:0)
160 	          |((face->style_flags&FT_STYLE_FLAG_BOLD)?FONT_STYLE_BOLD:0);
161     font->encoding = FONT_ENCODING_UNICODE;
162     font->glyph2ascii = (U16*)rfx_calloc(face->num_glyphs*sizeof(U16));
163     font->maxascii = 0;
164     font->glyph = (SWFGLYPH*)rfx_calloc(face->num_glyphs*sizeof(SWFGLYPH));
165     if(FT_HAS_GLYPH_NAMES(face)) {
166 	font->glyphnames = (char**)rfx_calloc(face->num_glyphs*sizeof(char*));
167     }
168 
169     font->layout->kerningcount = 0;
170 
171     name = face->family_name;
172     if(!(name && *name))
173         name = FT_Get_Postscript_Name(face);
174     if(name && *name)
175 	font->name = (U8*)strdup(name);
176 
177     while(1)
178     {
179     /*    // Map Glyphs to Unicode, version 1 (quick and dirty):
180 	int t;
181 	for(t=0;t<65536;t++) {
182 	    int index = FT_Get_Char_Index(face, t);
183 	    if(index>=0 && index<face->num_glyphs) {
184 		if(font->glyph2ascii[index]<0)
185 		    font->glyph2ascii[index] = t;
186 	    }
187 	}*/
188 
189 	// Map Glyphs to Unicode, version 2 (much nicer):
190 	// (The third way would be the AGL algorithm, as proposed
191 	//  by Werner Lemberg on freetype@freetype.org)
192 
193 	charcode = FT_Get_First_Char(face, &gindex);
194 	while(gindex != 0)
195 	{
196 	    if(gindex >= 0 && gindex<face->num_glyphs) {
197 		if(!font->glyph2ascii[gindex]) {
198 		    font->glyph2ascii[gindex] = charcode;
199 		    if(charcode + 1 > font->maxascii) {
200 			font->maxascii = charcode + 1;
201 		    }
202 		}
203 	    }
204 	    charcode = FT_Get_Next_Char(face, charcode, &gindex);
205 	}
206 
207 	/* if we didn't find a single encoding character, try
208 	   the font's charmaps instead. That usually means that
209 	   the encoding is no longer unicode.
210 	   TODO: find a way to convert the encoding to unicode
211 	 */
212 	if(font->maxascii == 0 && charmap < face->num_charmaps - 1) {
213 	    charmap++;
214 	    FT_Set_Charmap(face, face->charmaps[charmap]);
215 	    font->encoding = 0;//anything but unicode FIXME
216 	} else
217 	    break;
218     }
219 
220     if(full_unicode)
221 	font->maxascii = 65535;
222 
223     font->ascii2glyph = (int*)rfx_calloc(font->maxascii*sizeof(int));
224 
225     for(t=0;t<font->maxascii;t++) {
226 	int g = FT_Get_Char_Index(face, t);
227 	if(!g || g>=face->num_glyphs)
228 	    g = -1;
229 	font->ascii2glyph[t] = g;
230 	if(g>=0) {
231 	    max_unicode = t+1;
232 	    if(!font->glyph2ascii[g]) {
233 		font->glyph2ascii[g] = t;
234 	    }
235 	}
236     }
237     font->maxascii = max_unicode;
238 
239     font->numchars = 0;
240 
241     glyph2glyph = (int*)rfx_calloc(face->num_glyphs*sizeof(int));
242 
243     SRECT fontbbox = {0,0,0,0};
244 
245     for(t=0; t < face->num_glyphs; t++) {
246 	FT_Glyph glyph;
247 	FT_BBox bbox;
248 	char name[128];
249 	drawer_t draw;
250 	char hasname = 0;
251 	name[0]=0;
252 	if(FT_HAS_GLYPH_NAMES(face)) {
253 	    error = FT_Get_Glyph_Name(face, t, name, 127);
254 	    if(!error && name[0] && !strstr(name, "notdef")) {
255 		font->glyphnames[font->numchars] = strdup(name);
256 		hasname = 1;
257 	    }
258 	}
259 	if(!font->glyph2ascii[t] && !hasname && skip_unused) {
260 	    continue;
261 	}
262 	error = FT_Load_Glyph(face, t, FT_LOAD_NO_BITMAP);
263 	if(error) {
264 	    //tends to happen with some pdfs
265 	    fprintf(stderr, "Warning: Glyph %d has return code %d\n", t, error);
266 	    glyph=0;
267 	    if(skip_unused)
268 		continue;
269 	} else {
270 	    error = FT_Get_Glyph(face->glyph, &glyph);
271 	    if(error) {
272 		fprintf(stderr, "Couldn't get glyph %d, error:%d\n", t, error);
273 		glyph=0;
274 		if(skip_unused)
275 		    continue;
276 	    }
277 	}
278 
279 	if(glyph)
280 	    FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_unscaled, &bbox);
281 	else
282 	    memset(&bbox, 0, sizeof(bbox));
283 
284 	bbox.yMin = -bbox.yMin;
285 	bbox.yMax = -bbox.yMax;
286 	if(bbox.xMax < bbox.xMin) {
287 	    // swap
288 	    bbox.xMax ^= bbox.xMin;
289 	    bbox.xMin ^= bbox.xMax;
290 	    bbox.xMax ^= bbox.xMin;
291 	}
292 	if(bbox.yMax < bbox.yMin) {
293 	    // swap
294 	    bbox.yMax ^= bbox.yMin;
295 	    bbox.yMin ^= bbox.yMax;
296 	    bbox.yMax ^= bbox.yMin;
297 	}
298 
299 	swf_Shape01DrawerInit(&draw, 0);
300 
301 	//error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &draw);
302 	if(glyph)
303 	    error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &draw);
304 	else
305 	    error = 0;
306 	draw.finish(&draw);
307 
308 	if(error) {
309 	    fprintf(stderr, "Couldn't decompose glyph %d\n", t);
310 	    draw.dealloc(&draw);
311 	    continue;
312 	}
313 
314 #if 0
315 	if(bbox.xMin > 0) {
316 	    font->glyph[font->numchars].advance = (bbox.xMax*20*FT_SCALE)/FT_SUBPIXELS;
317 	} else {
318 	    font->glyph[font->numchars].advance = ((bbox.xMax - bbox.xMin)*20*FT_SCALE)/FT_SUBPIXELS;
319 	}
320 #else
321 	if(glyph)
322 	    font->glyph[font->numchars].advance = glyph->advance.x*20/65536;
323 	else
324 	    font->glyph[font->numchars].advance = 0;
325 #endif
326 
327 	SRECT b = swf_ShapeDrawerGetBBox(&draw);
328 
329 	//font->layout->bounds[font->numchars].xmin = (bbox.xMin*FT_SCALE*20)/FT_SUBPIXELS;
330 	//font->layout->bounds[font->numchars].ymin = (bbox.yMin*FT_SCALE*20)/FT_SUBPIXELS;
331 	//font->layout->bounds[font->numchars].xmax = (bbox.xMax*FT_SCALE*20)/FT_SUBPIXELS;
332 	//font->layout->bounds[font->numchars].ymax = (bbox.yMax*FT_SCALE*20)/FT_SUBPIXELS;
333 
334 	font->layout->bounds[font->numchars] = b;
335 	font->glyph[font->numchars].shape = swf_ShapeDrawerToShape(&draw);
336 
337 	swf_ExpandRect2(&fontbbox, &font->layout->bounds[font->numchars]);
338 
339 	draw.dealloc(&draw);
340 
341 	if(glyph)
342 	    FT_Done_Glyph(glyph);
343 	font->glyph2ascii[font->numchars] = font->glyph2ascii[t];
344 	glyph2glyph[t] = font->numchars;
345 	font->numchars++;
346     }
347 
348     //font->layout->ascent = abs(face->ascender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMin;
349     //font->layout->descent = abs(face->descender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMax;
350     //font->layout->leading = font->layout->ascent + font->layout->descent;
351 
352     if(-fontbbox.ymin < 0)
353         font->layout->ascent = 0;
354     else
355 	font->layout->ascent = -fontbbox.ymin;
356 
357     if(fontbbox.ymax < 0)
358         font->layout->descent = 0;
359     else
360 	font->layout->descent = fontbbox.ymax;
361 
362     int leading = fontbbox.ymax - fontbbox.ymin;
363     font->layout->leading = leading>0x7fff?0x7fff:leading;
364 
365     /* notice: if skip_unused is true, font->glyph2ascii, font->glyphnames and font->layout->bounds will
366 	       have more memory allocated than just font->numchars, but only the first font->numchars
367 	       are used/valid */
368 
369     for(t=0;t<font->maxascii;t++) {
370 	if(font->ascii2glyph[t]>=0) {
371 	    font->ascii2glyph[t] = glyph2glyph[font->ascii2glyph[t]];
372 	}
373     }
374     rfx_free(glyph2glyph);
375 
376     FT_Done_Face(face);
377     FT_Done_FreeType(ftlibrary);ftlibrary=0;
378 
379     return font;
380 }
381 #else  //HAVE_FREETYPE
382 
swf_LoadTrueTypeFont(const char * filename,char flashtype)383 SWFFONT* swf_LoadTrueTypeFont(const char*filename, char flashtype)
384 {
385     fprintf(stderr, "Warning: no freetype library- not able to load %s\n", filename);
386     return 0;
387 }
388 
389 #endif
390 
391 #ifdef HAVE_T1LIB
392 
393 #include <t1lib.h>
394 
395 static int t1lib_initialized = 0;
396 
397 static int counter = 0;
398 
swf_LoadT1Font(const char * filename)399 SWFFONT* swf_LoadT1Font(const char*filename)
400 {
401     SWFFONT * font;
402     int nr;
403     float angle,underline;
404     char*fontname,*fullname,*familyname;
405     BBox bbox;
406     int s,num;
407     char**charnames;
408     char**charname;
409     char*encoding[256];
410     int c;
411     int t;
412 
413     if(!t1lib_initialized) {
414 	T1_SetBitmapPad(16);
415 	if ((T1_InitLib(NO_LOGFILE)==NULL)){
416 	    fprintf(stderr, "Initialization of t1lib failed\n");
417 	    return 0;
418 	}
419 	t1lib_initialized = 1;
420     }
421     nr = T1_AddFont(filename);
422     T1_LoadFont(nr);
423 
424     charnames = T1_GetAllCharNames(nr);
425     if(!charnames) {
426 	fprintf(stderr, "No Charnames record- not a Type1 Font?\n");
427 	return 0;
428     }
429 
430     angle = T1_GetItalicAngle(nr);
431     fontname = T1_GetFontName(nr);
432     fullname = T1_GetFullName(nr);
433     familyname = T1_GetFamilyName(nr);
434     underline = T1_GetUnderlinePosition(nr);
435     bbox = T1_GetFontBBox(nr);
436 
437     font = (SWFFONT*)rfx_calloc(sizeof(SWFFONT));
438 
439     font->version = 2;
440     if(fontname)
441 	font->name = (U8*)strdup(fontname);
442     else
443 	font->name = 0;
444     font->layout = (SWFLAYOUT*)rfx_calloc(sizeof(SWFLAYOUT));
445 
446     num = 0;
447     charname = charnames;
448     while(*charname) {
449 	charname++;
450 	if(num<256) {
451 	    if(*charname) encoding[num] = strdup(*charname);
452 	    else          encoding[num] = strdup(".notdef");
453 	}
454 	num++;
455     }
456     for(t=num;t<256;t++)
457 	encoding[t] = strdup(".notdef");
458 
459     //T1_ReencodeFont(nr, encoding);
460 
461     font->maxascii = num;
462     font->numchars = num;
463 
464     font->style = (/*bold*/0?FONT_STYLE_BOLD:0) + (angle>0.05?FONT_STYLE_ITALIC:0);
465 
466     font->glyph = (SWFGLYPH*)rfx_calloc(num*sizeof(SWFGLYPH));
467     font->glyph2ascii = (U16*)rfx_calloc(num*sizeof(U16));
468     font->ascii2glyph = (int*)rfx_calloc(font->maxascii*sizeof(int));
469     font->layout->ascent = (U16)(underline - bbox.lly);
470     font->layout->descent = (U16)(bbox.ury - underline);
471     font->layout->leading = (U16)(font->layout->ascent -
472 	                     font->layout->descent -
473 			     (bbox.lly - bbox.ury));
474     font->layout->bounds = (SRECT*)rfx_calloc(sizeof(SRECT)*num);
475     font->layout->kerningcount = 0;
476     font->layout->kerning = 0;
477     font->glyphnames = rfx_calloc(num*sizeof(char*));
478 
479     num = 0;
480 
481     charname = charnames;
482     for(c=0;c<font->numchars;c++) {
483 	drawer_t draw;
484 	SRECT bbox;
485 	T1_OUTLINE * outline;
486 	FPOINT pos,last;
487 	int firstx;
488 
489 	outline = T1_GetCharOutline(nr, c, 100.0, 0);
490 	firstx = outline->dest.x/0xffff;
491 
492 	pos.x = 0;
493 	pos.y = 0;
494 	last = pos;
495 
496 	font->glyphnames[c] = strdup(*charname);
497 
498 	if(c<font->maxascii)
499 	    font->ascii2glyph[c] = c;
500 	font->glyph2ascii[c] = c;
501 
502 	swf_Shape01DrawerInit(&draw, 0);
503 
504 	while(outline) {
505 	    pos.x += (outline->dest.x/(float)0xffff);
506 	    pos.y += (outline->dest.y/(float)0xffff);
507 
508 	    if(outline->type == T1_PATHTYPE_MOVE) {
509 		draw.moveTo(&draw,&pos);
510 	    } else if(outline->type == T1_PATHTYPE_LINE) {
511 		draw.lineTo(&draw,&pos);
512 	    } else if(outline->type == T1_PATHTYPE_BEZIER) {
513 		T1_BEZIERSEGMENT*o2 = (T1_BEZIERSEGMENT*)outline;
514 		FPOINT b,c;
515 		b.x = o2->B.x/(float)0xffff+last.x;
516 		b.y = o2->B.y/(float)0xffff+last.y;
517 		c.x = o2->C.x/(float)0xffff+last.x;
518 		c.y = o2->C.y/(float)0xffff+last.y;
519 		draw_cubicTo(&draw,&b,&c,&pos);
520 	    } else {
521 		fprintf(stderr, "loadT1Font: unknown outline type:%d\n", outline->type);
522 	    }
523 	    last = pos;
524 	    outline = outline->link;
525 	}
526 
527 	draw.finish(&draw);
528 
529 	font->glyph[c].shape = swf_ShapeDrawerToShape(&draw);
530 	bbox = swf_ShapeDrawerGetBBox(&draw);
531 	draw.dealloc(&draw);
532 
533 	font->layout->bounds[c] = bbox;
534 	font->glyph[c].advance = bbox.xmax;
535 	if(!font->glyph[c].advance) {
536 	    font->glyph[c].advance = firstx;
537 	}
538 	charname++;
539     }
540     T1_DeleteFont(nr);
541 
542     for(t=0;t<256;t++)
543 	rfx_free(encoding[t]);
544     return font;
545 }
546 
547 #else
548 
swf_LoadT1Font(const char * filename)549 SWFFONT* swf_LoadT1Font(const char*filename)
550 {
551     fprintf(stderr, "Warning: no t1lib- not able to load %s\n", filename);
552     return 0;
553 }
554 
555 #endif
556 
swf_DummyFont()557 SWFFONT* swf_DummyFont()
558 {
559     SWFFONT*font = (SWFFONT*)rfx_calloc(sizeof(SWFFONT));
560     return font;
561 }
562 
isSWF(const char * filename)563 static int isSWF(const char*filename)
564 {
565     FILE*fi = fopen(filename, "rb");
566     char a[8];
567     if(!fi) {
568 	perror(filename);
569 	return -1;
570     }
571     memset(a, 0, sizeof(a));
572     fread(a, 4, 1, fi);
573     fclose(fi);
574 
575     if(!strncmp(a, "FWS", 3) || !strncmp(a, "CWS", 3)) {
576 	return 1;
577     }
578     return 0;
579 }
580 
swf_LoadFont(const char * filename,char flashtype)581 SWFFONT* swf_LoadFont(const char*filename, char flashtype)
582 {
583     int is_swf;
584     if(filename == 0)
585 	return swf_DummyFont();
586     is_swf = isSWF(filename);
587     if(is_swf<0)
588 	return 0;
589     if(is_swf) {
590 	SWFFONT*font = swf_ReadFont(filename);
591 	if(flashtype && font->version==2)
592 	    fprintf(stderr, "Warning: Can't load font v2 file as flashtype (%s)\n", filename);
593 	return font;
594     }
595 
596 #if defined(HAVE_FREETYPE)
597     return swf_LoadTrueTypeFont(filename, flashtype);
598 #elif defined(HAVE_T1LIB)
599     return swf_LoadT1Font(filename);
600 #else
601     fprintf(stderr, "Error: Neither T1lib nor FreeType support compiled in. Could not load %s\n", filename);
602     return 0;
603 #endif
604 }
605 
606