aee2fae538a05c97d1a86217ee4eb75248314d54
[swftools.git] / lib / modules / swffont.c
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
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
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 }
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 }
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 }
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
119 SWFFONT* swf_LoadTrueTypeFont(const char*filename)
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     FT_Set_Pixel_Sizes (face, 16*loadfont_scale, 16*loadfont_scale);
146
147     if(face->num_glyphs <= 0) {
148         fprintf(stderr, "File %s contains %d glyphs\n", face->num_glyphs);
149         return 0;
150     }
151
152     font = (SWFFONT*)rfx_calloc(sizeof(SWFFONT));
153     font->id = -1;
154     font->version = 2;
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));
161     font->maxascii = 0;
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*));
165     }
166     
167     font->layout->kerningcount = 0;
168     
169     name = face->family_name;
170     if(!(name && *name))
171         name = FT_Get_Postscript_Name(face);
172     if(name && *name)
173         font->name = (U8*)strdup(name);
174
175     while(1) 
176     {
177     /*    // Map Glyphs to Unicode, version 1 (quick and dirty):
178         int t;
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;
184             }
185         }*/
186         
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)
190
191         charcode = FT_Get_First_Char(face, &gindex);
192         while(gindex != 0)
193         {
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;
199                     }
200                 }
201             }
202             charcode = FT_Get_Next_Char(face, charcode, &gindex);
203         }
204
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
209          */
210         if(font->maxascii == 0 && charmap < face->num_charmaps - 1) {
211             charmap++;
212             FT_Set_Charmap(face, face->charmaps[charmap]);
213             font->encoding = 0;//anything but unicode FIXME
214         } else 
215             break;
216     }
217
218     if(full_unicode)
219         font->maxascii = 65535;
220     
221     font->ascii2glyph = (int*)rfx_calloc(font->maxascii*sizeof(int));
222     
223     for(t=0;t<font->maxascii;t++) {
224         int g = FT_Get_Char_Index(face, t);
225         if(!g || g>=face->num_glyphs)
226             g = -1;
227         font->ascii2glyph[t] = g;
228         if(g>=0) {
229             max_unicode = t+1;
230             if(!font->glyph2ascii[g]) {
231                 font->glyph2ascii[g] = t;
232             }
233         }
234     }
235     font->maxascii = max_unicode;
236
237     font->numchars = 0;
238
239     glyph2glyph = (int*)rfx_calloc(face->num_glyphs*sizeof(int));
240
241     SRECT fontbbox = {0,0,0,0};
242
243     for(t=0; t < face->num_glyphs; t++) {
244         FT_Glyph glyph;
245         FT_BBox bbox;
246         char name[128];
247         drawer_t draw;
248         char hasname = 0;
249         name[0]=0;
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);
254                 hasname = 1;
255             }
256         }
257         if(!font->glyph2ascii[t] && !hasname && skip_unused) {
258             continue;
259         }
260         error = FT_Load_Glyph(face, t, FT_LOAD_NO_BITMAP);
261         if(error) {
262             //tends to happen with some pdfs
263             fprintf(stderr, "Warning: Glyph %d has return code %d\n", t, error);
264             glyph=0;
265             if(skip_unused) 
266                 continue;
267         } else {
268             error = FT_Get_Glyph(face->glyph, &glyph);
269             if(error) {
270                 fprintf(stderr, "Couldn't get glyph %d, error:%d\n", t, error);
271                 glyph=0;
272                 if(skip_unused) 
273                     continue;
274             }
275         }
276
277         if(glyph)
278             FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_unscaled, &bbox);
279         else
280             memset(&bbox, 0, sizeof(bbox));
281
282         bbox.yMin = -bbox.yMin;
283         bbox.yMax = -bbox.yMax;
284         if(bbox.xMax < bbox.xMin) {
285             // swap
286             bbox.xMax ^= bbox.xMin;
287             bbox.xMin ^= bbox.xMax;
288             bbox.xMax ^= bbox.xMin;
289         }
290         if(bbox.yMax < bbox.yMin) {
291             // swap
292             bbox.yMax ^= bbox.yMin;
293             bbox.yMin ^= bbox.yMax;
294             bbox.yMax ^= bbox.yMin;
295         }
296
297         swf_Shape01DrawerInit(&draw, 0);
298
299         //error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &draw);
300         if(glyph)
301             error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &draw);
302         else
303             error = 0;
304         draw.finish(&draw);
305         
306         if(error) {
307             fprintf(stderr, "Couldn't decompose glyph %d\n", t);
308             draw.dealloc(&draw);
309             continue;
310         }
311
312 #if 0
313         if(bbox.xMin > 0) {
314             font->glyph[font->numchars].advance = (bbox.xMax*20*FT_SCALE)/FT_SUBPIXELS;
315         } else {
316             font->glyph[font->numchars].advance = ((bbox.xMax - bbox.xMin)*20*FT_SCALE)/FT_SUBPIXELS;
317         }
318 #else
319         if(glyph)
320             font->glyph[font->numchars].advance = glyph->advance.x*20/65536;
321         else
322             font->glyph[font->numchars].advance = 0;
323 #endif
324         
325         SRECT b = swf_ShapeDrawerGetBBox(&draw);
326
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;
331
332         font->layout->bounds[font->numchars] = b;
333         font->glyph[font->numchars].shape = swf_ShapeDrawerToShape(&draw);
334
335         swf_ExpandRect2(&fontbbox, &font->layout->bounds[font->numchars]);
336
337         draw.dealloc(&draw);
338
339         if(glyph)
340             FT_Done_Glyph(glyph);
341         font->glyph2ascii[font->numchars] = font->glyph2ascii[t];
342         glyph2glyph[t] = font->numchars;
343         font->numchars++;
344     }
345     
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;
349
350     if(-fontbbox.ymin < 0)
351         font->layout->ascent = 0;
352     else
353         font->layout->ascent = -fontbbox.ymin;
354
355     if(-fontbbox.ymax < 0)
356         font->layout->descent = 0;
357     else
358         font->layout->descent = -fontbbox.ymax;
359
360     font->layout->leading = fontbbox.ymax - fontbbox.ymin;
361
362     /* notice: if skip_unused is true, font->glyph2ascii, font->glyphnames and font->layout->bounds will 
363                have more memory allocated than just font->numchars, but only the first font->numchars 
364                are used/valid */
365
366     for(t=0;t<font->maxascii;t++) {
367         if(font->ascii2glyph[t]>=0) {
368             font->ascii2glyph[t] = glyph2glyph[font->ascii2glyph[t]];
369         }
370     }
371     rfx_free(glyph2glyph);
372
373     FT_Done_Face(face);
374     FT_Done_FreeType(ftlibrary);ftlibrary=0;
375
376     return font;
377 }
378 #else  //HAVE_FREETYPE
379
380 SWFFONT* swf_LoadTrueTypeFont(const char*filename)
381 {
382     fprintf(stderr, "Warning: no freetype library- not able to load %s\n", filename);
383     return 0;
384 }
385
386 #endif
387
388 #ifdef HAVE_T1LIB
389
390 #include <t1lib.h>
391
392 static int t1lib_initialized = 0;
393
394 static int counter = 0;
395
396 SWFFONT* swf_LoadT1Font(const char*filename)
397 {
398     SWFFONT * font;
399     int nr;
400     float angle,underline;
401     char*fontname,*fullname,*familyname;
402     BBox bbox;
403     int s,num;
404     char**charnames;
405     char**charname;
406     char*encoding[256];
407     int c;
408     int t;
409
410     if(!t1lib_initialized) {
411         T1_SetBitmapPad(16);
412         if ((T1_InitLib(NO_LOGFILE)==NULL)){
413             fprintf(stderr, "Initialization of t1lib failed\n");
414             return 0;
415         }
416         t1lib_initialized = 1;
417     }
418     nr = T1_AddFont(filename);
419     T1_LoadFont(nr);
420
421     charnames = T1_GetAllCharNames(nr);
422     if(!charnames) {
423         fprintf(stderr, "No Charnames record- not a Type1 Font?\n");
424         return 0;
425     }
426
427     angle = T1_GetItalicAngle(nr);
428     fontname = T1_GetFontName(nr);
429     fullname = T1_GetFullName(nr);
430     familyname = T1_GetFamilyName(nr);
431     underline = T1_GetUnderlinePosition(nr);
432     bbox = T1_GetFontBBox(nr);
433
434     font = (SWFFONT*)rfx_calloc(sizeof(SWFFONT));
435
436     font->version = 2;
437     if(fontname) 
438         font->name = (U8*)strdup(fontname);
439     else 
440         font->name = 0;
441     font->layout = (SWFLAYOUT*)rfx_calloc(sizeof(SWFLAYOUT));
442
443     num = 0;
444     charname = charnames;
445     while(*charname) {
446         charname++;
447         if(num<256) {
448             if(*charname) encoding[num] = strdup(*charname);
449             else          encoding[num] = strdup(".notdef");
450         }
451         num++;
452     }
453     for(t=num;t<256;t++)
454         encoding[t] = strdup(".notdef");
455     
456     //T1_ReencodeFont(nr, encoding);
457
458     font->maxascii = num;
459     font->numchars = num;
460     
461     font->style = (/*bold*/0?FONT_STYLE_BOLD:0) + (angle>0.05?FONT_STYLE_ITALIC:0);
462
463     font->glyph = (SWFGLYPH*)rfx_calloc(num*sizeof(SWFGLYPH));
464     font->glyph2ascii = (U16*)rfx_calloc(num*sizeof(U16));
465     font->ascii2glyph = (int*)rfx_calloc(font->maxascii*sizeof(int));
466     font->layout->ascent = (U16)(underline - bbox.lly);
467     font->layout->descent = (U16)(bbox.ury - underline);
468     font->layout->leading = (U16)(font->layout->ascent - 
469                              font->layout->descent -
470                              (bbox.lly - bbox.ury));
471     font->layout->bounds = (SRECT*)rfx_calloc(sizeof(SRECT)*num);
472     font->layout->kerningcount = 0;
473     font->layout->kerning = 0;
474     font->glyphnames = rfx_calloc(num*sizeof(char*));
475   
476     num = 0;
477
478     charname = charnames;
479     for(c=0;c<font->numchars;c++) {
480         drawer_t draw;
481         SRECT bbox;
482         T1_OUTLINE * outline;
483         FPOINT pos,last;
484         int firstx;
485         
486         outline = T1_GetCharOutline(nr, c, 100.0, 0);
487         firstx = outline->dest.x/0xffff;
488
489         pos.x = 0;
490         pos.y = 0;
491         last = pos;
492         
493         font->glyphnames[c] = strdup(*charname);
494
495         if(c<font->maxascii)
496             font->ascii2glyph[c] = c;
497         font->glyph2ascii[c] = c;
498         
499         swf_Shape01DrawerInit(&draw, 0);
500
501         while(outline) {
502             pos.x += (outline->dest.x/(float)0xffff);
503             pos.y += (outline->dest.y/(float)0xffff);
504
505             if(outline->type == T1_PATHTYPE_MOVE) {
506                 draw.moveTo(&draw,&pos);
507             } else if(outline->type == T1_PATHTYPE_LINE) {
508                 draw.lineTo(&draw,&pos);
509             } else if(outline->type == T1_PATHTYPE_BEZIER) {
510                 T1_BEZIERSEGMENT*o2 = (T1_BEZIERSEGMENT*)outline;
511                 FPOINT b,c;
512                 b.x = o2->B.x/(float)0xffff+last.x;
513                 b.y = o2->B.y/(float)0xffff+last.y;
514                 c.x = o2->C.x/(float)0xffff+last.x;
515                 c.y = o2->C.y/(float)0xffff+last.y;
516                 draw_cubicTo(&draw,&b,&c,&pos);
517             } else {
518                 fprintf(stderr, "loadT1Font: unknown outline type:%d\n", outline->type);
519             }
520             last = pos;
521             outline = outline->link;
522         }
523         
524         draw.finish(&draw);
525
526         font->glyph[c].shape = swf_ShapeDrawerToShape(&draw);
527         bbox = swf_ShapeDrawerGetBBox(&draw);
528         draw.dealloc(&draw);
529             
530         font->layout->bounds[c] = bbox;
531         font->glyph[c].advance = bbox.xmax;
532         if(!font->glyph[c].advance) {
533             font->glyph[c].advance = firstx;
534         }
535         charname++;
536     }
537     T1_DeleteFont(nr);
538
539     for(t=0;t<256;t++)
540         rfx_free(encoding[t]);
541     return font;
542 }
543
544 #else
545
546 SWFFONT* swf_LoadT1Font(const char*filename)
547 {
548     fprintf(stderr, "Warning: no t1lib- not able to load %s\n", filename);
549     return 0;
550 }
551
552 #endif
553
554 SWFFONT* swf_DummyFont()
555 {
556     SWFFONT*font = (SWFFONT*)rfx_calloc(sizeof(SWFFONT));
557     return font;
558 }
559
560 static int isSWF(const char*filename)
561 {
562     FILE*fi = fopen(filename, "rb");
563     char a[8];
564     if(!fi) {
565         perror(filename);
566         return -1;
567     }
568     memset(a, 0, sizeof(a));
569     fread(a, 4, 1, fi);
570     fclose(fi);
571
572     if(!strncmp(a, "FWS", 3) || !strncmp(a, "CWS", 3)) {
573         return 1;
574     }
575     return 0;
576 }
577
578 SWFFONT* swf_LoadFont(const char*filename)
579 {
580     int is_swf;
581     if(filename == 0)
582         return swf_DummyFont();
583     is_swf = isSWF(filename);
584     if(is_swf<0)
585         return 0;
586     if(is_swf) {
587         return swf_ReadFont(filename);
588     }
589
590 #if defined(HAVE_FREETYPE)
591     return swf_LoadTrueTypeFont(filename);
592 #elif defined(HAVE_T1LIB)
593     return swf_LoadT1Font(filename);
594 #else
595     fprintf(stderr, "Error: Neither T1lib nor FreeType support compiled in. Could not load %s\n", filename);
596     return 0;
597 #endif
598 }
599