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