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