fixed "bad code offset" bug.
[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 #if 0
270         if(bbox.xMin > 0) {
271             font->glyph[font->numchars].advance = (bbox.xMax*FT_SCALE)/FT_SUBPIXELS;
272         } else {
273             font->glyph[font->numchars].advance = ((bbox.xMax - bbox.xMin)*FT_SCALE)/FT_SUBPIXELS;
274         }
275 #else
276         font->glyph[font->numchars].advance = glyph->advance.x*20/65536;
277 #endif
278         
279         font->glyph[font->numchars].shape = swf_ShapeDrawerToShape(&draw);
280         
281         font->layout->bounds[font->numchars].xmin = (bbox.xMin*FT_SCALE*20)/FT_SUBPIXELS;
282         font->layout->bounds[font->numchars].ymin = (bbox.yMin*FT_SCALE*20)/FT_SUBPIXELS;
283         font->layout->bounds[font->numchars].xmax = (bbox.xMax*FT_SCALE*20)/FT_SUBPIXELS;
284         font->layout->bounds[font->numchars].ymax = (bbox.yMax*FT_SCALE*20)/FT_SUBPIXELS;
285
286         draw.dealloc(&draw);
287
288         FT_Done_Glyph(glyph);
289         font->glyph2ascii[font->numchars] = font->glyph2ascii[t];
290         glyph2glyph[t] = font->numchars;
291         font->numchars++;
292     }
293     /* notice: if skip_unused is true, font->glyph2ascii, font->glyphnames and font->layout->bounds will 
294                have more memory allocated than just font->numchars, but only the first font->numchars 
295                are used/valid */
296
297     for(t=0;t<font->maxascii;t++) {
298         if(font->ascii2glyph[t]>=0) {
299             font->ascii2glyph[t] = glyph2glyph[font->ascii2glyph[t]];
300         }
301     }
302     free(glyph2glyph);
303
304     FT_Done_Face(face);
305     FT_Done_FreeType(ftlibrary);ftlibrary=0;
306
307     return font;
308 }
309 #else  //HAVE_FREETYPE
310
311 SWFFONT* swf_LoadTrueTypeFont(char*filename)
312 {
313     fprintf(stderr, "Warning: no freetype library- not able to load %s\n", filename);
314     return 0;
315 }
316
317 #endif
318
319 #ifdef HAVE_T1LIB
320
321 #include <t1lib.h>
322
323 static int t1lib_initialized = 0;
324
325 static int counter = 0;
326
327 SWFFONT* swf_LoadT1Font(char*filename)
328 {
329     SWFFONT * font;
330     int nr;
331     float angle,underline;
332     char*fontname,*fullname,*familyname;
333     BBox bbox;
334     int s,num;
335     char**charnames;
336     char**charname;
337     char*encoding[256];
338     int c;
339     int t;
340
341     if(!t1lib_initialized) {
342         T1_SetBitmapPad(16);
343         if ((T1_InitLib(NO_LOGFILE)==NULL)){
344             fprintf(stderr, "Initialization of t1lib failed\n");
345             return 0;
346         }
347         t1lib_initialized = 1;
348     }
349     nr = T1_AddFont(filename);
350     T1_LoadFont(nr);
351
352     charnames = T1_GetAllCharNames(nr);
353     if(!charnames) {
354         fprintf(stderr, "No Charnames record- not a Type1 Font?\n");
355         return 0;
356     }
357
358     angle = T1_GetItalicAngle(nr);
359     fontname = T1_GetFontName(nr);
360     fullname = T1_GetFullName(nr);
361     familyname = T1_GetFamilyName(nr);
362     underline = T1_GetUnderlinePosition(nr);
363     bbox = T1_GetFontBBox(nr);
364
365     font = (SWFFONT*)malloc(sizeof(SWFFONT));
366     memset(font, 0, sizeof(SWFFONT));
367
368     font->version = 2;
369     if(fontname) 
370         font->name = (U8*)strdup(fontname);
371     else 
372         font->name = 0;
373     font->layout = (SWFLAYOUT*)malloc(sizeof(SWFLAYOUT));
374     memset(font->layout, 0, sizeof(SWFLAYOUT));
375
376     num = 0;
377     charname = charnames;
378     while(*charname) {
379         charname++;
380         if(num<256) {
381             if(*charname) encoding[num] = strdup(*charname);
382             else          encoding[num] = strdup(".notdef");
383         }
384         num++;
385     }
386     for(t=num;t<256;t++)
387         encoding[t] = strdup(".notdef");
388     
389     //T1_ReencodeFont(nr, encoding);
390
391     font->maxascii = num;
392     font->numchars = num;
393     
394     font->style = (/*bold*/0?FONT_STYLE_BOLD:0) + (angle>0.05?FONT_STYLE_ITALIC:0);
395
396     font->glyph = (SWFGLYPH*)malloc(num*sizeof(SWFGLYPH));
397     memset(font->glyph, 0, num*sizeof(SWFGLYPH));
398     font->glyph2ascii = (U16*)malloc(num*sizeof(U16));
399     memset(font->glyph2ascii, 0, num*sizeof(U16));
400     font->ascii2glyph = (int*)malloc(font->maxascii*sizeof(int));
401     memset(font->ascii2glyph, -1, font->maxascii*sizeof(int));
402     font->layout->ascent = (U16)(underline - bbox.lly);
403     font->layout->descent = (U16)(bbox.ury - underline);
404     font->layout->leading = (U16)(font->layout->ascent - 
405                              font->layout->descent -
406                              (bbox.lly - bbox.ury));
407     font->layout->bounds = (SRECT*)malloc(sizeof(SRECT)*num);
408     memset(font->layout->bounds, 0, sizeof(SRECT)*num);
409     font->layout->kerningcount = 0;
410     font->layout->kerning = 0;
411     font->glyphnames = malloc(num*sizeof(char*));
412     memset(font->glyphnames, 0, num*sizeof(char*));
413   
414     num = 0;
415
416     charname = charnames;
417     for(c=0;c<font->numchars;c++) {
418         drawer_t draw;
419         SRECT bbox;
420         T1_OUTLINE * outline;
421         FPOINT pos,last;
422         int firstx;
423         
424         outline = T1_GetCharOutline(nr, c, 100.0, 0);
425         firstx = outline->dest.x/0xffff;
426
427         pos.x = 0;
428         pos.y = 0;
429         last = pos;
430         
431         font->glyphnames[c] = strdup(*charname);
432
433         if(c<font->maxascii)
434             font->ascii2glyph[c] = c;
435         font->glyph2ascii[c] = c;
436         
437         swf_Shape01DrawerInit(&draw, 0);
438
439         while(outline) {
440             pos.x += (outline->dest.x/(float)0xffff);
441             pos.y += (outline->dest.y/(float)0xffff);
442
443             if(outline->type == T1_PATHTYPE_MOVE) {
444                 draw.moveTo(&draw,&pos);
445             } else if(outline->type == T1_PATHTYPE_LINE) {
446                 draw.lineTo(&draw,&pos);
447             } else if(outline->type == T1_PATHTYPE_BEZIER) {
448                 T1_BEZIERSEGMENT*o2 = (T1_BEZIERSEGMENT*)outline;
449                 FPOINT b,c;
450                 b.x = o2->B.x/(float)0xffff+last.x;
451                 b.y = o2->B.y/(float)0xffff+last.y;
452                 c.x = o2->C.x/(float)0xffff+last.x;
453                 c.y = o2->C.y/(float)0xffff+last.y;
454                 draw_cubicTo(&draw,&b,&c,&pos);
455             } else {
456                 fprintf(stderr, "loadT1Font: unknown outline type:%d\n", outline->type);
457             }
458             last = pos;
459             outline = outline->link;
460             printf("(%f,%f) ", pos.x, pos.y);
461         }
462         printf("\n");
463         
464         draw.finish(&draw);
465
466         font->glyph[c].shape = swf_ShapeDrawerToShape(&draw);
467         bbox = swf_ShapeDrawerGetBBox(&draw);
468         draw.dealloc(&draw);
469             
470         font->layout->bounds[c] = bbox;
471         font->glyph[c].advance = bbox.xmax;
472         if(!font->glyph[c].advance) {
473             font->glyph[c].advance = firstx;
474         }
475         charname++;
476     }
477     T1_DeleteFont(nr);
478
479     for(t=0;t<256;t++)
480         free(encoding[t]);
481     return font;
482 }
483
484 #else
485
486 SWFFONT* swf_LoadT1Font(char*filename)
487 {
488     fprintf(stderr, "Warning: no t1lib- not able to load %s\n", filename);
489     return 0;
490 }
491
492 #endif
493
494 SWFFONT* swf_DummyFont()
495 {
496     SWFFONT*font = (SWFFONT*)malloc(sizeof(SWFFONT));
497     memset(font, 0, sizeof(SWFFONT));
498     return font;
499 }
500
501 static int isSWF(const char*filename)
502 {
503     FILE*fi = fopen(filename, "rb");
504     char a[8];
505     if(!fi) {
506         perror(filename);
507         return -1;
508     }
509     memset(a, 0, sizeof(a));
510     fread(a, 4, 1, fi);
511     fclose(fi);
512
513     if(!strncmp(a, "FWS", 3) || !strncmp(a, "CWS", 3)) {
514         return 1;
515     }
516     return 0;
517 }
518
519 SWFFONT* swf_LoadFont(char*filename)
520 {
521     int is_swf;
522     if(filename == 0)
523         return swf_DummyFont();
524     is_swf = isSWF(filename);
525     if(is_swf<0)
526         return 0;
527     if(is_swf) {
528         return swf_ReadFont(filename);
529     }
530
531 #if defined(HAVE_FREETYPE)
532     return swf_LoadTrueTypeFont(filename);
533 #elif defined(HAVE_T1LIB)
534     return swf_LoadT1Font(filename);
535 #else
536     fprintf(stderr, "Error: Neither T1lib nor FreeType support compiled in. Could not load %s\n", filename);
537     return 0;
538 #endif
539 }
540