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