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