fixed dates
[swftools.git] / pdf2swf / ttf2pt1 / ft.c
1 /*
2  * The font parser using the FreeType library version 2.
3  *
4  * see COPYRIGHT
5  *
6  */
7
8 #ifdef USE_FREETYPE
9
10 #include <stdio.h>
11 #include <string.h>
12 #include <stdlib.h>
13 #include <ctype.h>
14 #include <sys/types.h>
15 #include <freetype/freetype.h>
16 #include <freetype/ftglyph.h>
17 #include <freetype/ftnames.h>
18 #include <freetype/ttnameid.h>
19 #include <freetype/ftoutln.h>
20 #include "pt1.h"
21 #include "global.h"
22
23 /* prototypes of call entries */
24 static void openfont(char *fname, char *arg);
25 static void closefont( void);
26 static int getnglyphs ( void);
27 static int glnames( GLYPH *glyph_list);
28 static void glmetrics( GLYPH *glyph_list);
29 static int glenc( GLYPH *glyph_list, int *encoding, int *unimap);
30 static void fnmetrics( struct font_metrics *fm);
31 static void glpath( int glyphno, GLYPH *glyph_list);
32 static void kerning( GLYPH *glyph_list);
33
34 /* globals */
35
36 /* front-end descriptor */
37 struct frontsw freetype_sw = {
38         /*name*/       "ft",
39         /*descr*/      "based on the FreeType library",
40         /*suffix*/     { "ttf", "otf", "pfa", "pfb" },
41         /*open*/       openfont,
42         /*close*/      closefont,
43         /*nglyphs*/    getnglyphs,
44         /*glnames*/    glnames,
45         /*glmetrics*/  glmetrics,
46         /*glenc*/      glenc,
47         /*fnmetrics*/  fnmetrics,
48         /*glpath*/     glpath,
49         /*kerning*/    kerning,
50 };
51
52 /* statics */
53
54 static char * dupcnstring( char *s, int len);
55
56 static FT_Library library;
57 static FT_Face face;
58
59 static int enc_type, enc_found;
60
61 /* SFNT functions do not seem to be included by default in FT2beta8 */
62 #define ENABLE_SFNT
63
64 /*
65  * Open font and prepare to return information to the main driver.
66  * May print error and warning messages.
67  * Exit on error.
68  */
69
70 static void
71 openfont(
72         char *fname,
73         char *arg /* unused now */
74 )
75 {
76         FT_Error error;
77
78         if( FT_Init_FreeType( &library ) ) {
79                 fprintf(stderr, "** FreeType initialization failed\n");
80                 exit(1);
81         }
82
83         if( error = FT_New_Face( library, fname, 0, &face ) ) {
84                 if ( error == FT_Err_Unknown_File_Format )
85                         fprintf(stderr, "**** %s has format unknown to FreeType\n", fname);
86                 else
87                         fprintf(stderr, "**** Cannot access %s ****\n", fname);
88                 exit(1);
89         }
90
91         if(FT_HAS_FIXED_SIZES(face)) {
92                 WARNING_1 fprintf(stderr, "Font contains bitmaps\n");
93         }
94         if(FT_HAS_MULTIPLE_MASTERS(face)) {
95                 WARNING_1 fprintf(stderr, "Font contains multiple masters, using default\n");
96         }
97
98         if(ISDBG(FT)) fprintf(stderr," %d units per EM\n", face->units_per_EM);
99
100         enc_found = 0;
101 }
102
103 /*
104  * Close font.
105  * Exit on error.
106  */
107
108 static void
109 closefont(
110         void
111 )
112 {
113         if( FT_Done_Face(face) ) {
114                 WARNING_1 fprintf(stderr, "Errors when closing the font file, ignored\n");
115         }
116         if( FT_Done_FreeType(library) ) {
117                 WARNING_1 fprintf(stderr, "Errors when stopping FreeType, ignored\n");
118         }
119 }
120
121 /*
122  * Get the number of glyphs in font.
123  */
124
125 static int
126 getnglyphs (
127         void
128 )
129 {
130         if(ISDBG(FT)) fprintf(stderr, "%d glyphs in font\n", face->num_glyphs);
131         return (int)face->num_glyphs;
132 }
133
134 /*
135  * Get the names of the glyphs.
136  * Returns 0 if the names were assigned, non-zero if the font
137  * provides no glyph names.
138  */
139
140 static int
141 glnames(
142         GLYPH *glyph_list
143 )
144 {
145 #define MAX_NAMELEN     1024
146         unsigned char bf[1024];
147         int i;
148
149         if( ! FT_HAS_GLYPH_NAMES(face) ) {
150                 WARNING_1 fprintf(stderr, "Font has no glyph names\n");
151                 return 1;
152         }
153
154         for(i=0; i < face->num_glyphs; i++) {
155                 if( FT_Get_Glyph_Name(face, i, bf, MAX_NAMELEN) || bf[0]==0 ) {
156                         sprintf(bf, "_%d", i);
157                         WARNING_2 fprintf(stderr,
158                                 "**** Glyph No. %d has no postscript name, becomes %s ****\n",
159                                 i, bf);
160                 }
161                 glyph_list[i].name = strdup(bf);
162                 if(ISDBG(FT)) fprintf(stderr, "%d has name %s\n", i, bf);
163                 if (glyph_list[i].name == NULL) {
164                         fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
165                         exit(255);
166                 }
167         }
168         return 0;
169 }
170
171 /*
172  * Get the metrics of the glyphs.
173  */
174
175 static void
176 glmetrics(
177         GLYPH *glyph_list
178 )
179 {
180         GLYPH          *g;
181         int i;
182         FT_Glyph_Metrics *met;
183         FT_BBox bbox;
184         FT_Glyph gly;
185
186         for(i=0; i < face->num_glyphs; i++) {
187                 g = &(glyph_list[i]);
188
189                 if( FT_Load_Glyph(face, i, FT_LOAD_NO_BITMAP|FT_LOAD_NO_SCALE) ) {
190                         fprintf(stderr, "Can't load glyph %s, skipped\n", g->name);
191                         continue;
192                 }
193
194                 met = &face->glyph->metrics;
195
196                 if(FT_HAS_HORIZONTAL(face)) {
197                         g->width = met->horiAdvance;
198                         g->lsb = met->horiBearingX;
199                 } else {
200                         WARNING_2 fprintf(stderr, "Glyph %s has no horizontal metrics, guessed them\n", g->name);
201                         g->width = met->width;
202                         g->lsb = 0;
203                 }
204
205                 if( FT_Get_Glyph(face->glyph, &gly) ) {
206                         fprintf(stderr, "Can't access glyph %s bbox, skipped\n", g->name);
207                         continue;
208                 }
209
210                 FT_Glyph_Get_CBox(gly, ft_glyph_bbox_unscaled, &bbox);
211                 g->xMin = bbox.xMin;
212                 g->yMin = bbox.yMin;
213                 g->xMax = bbox.xMax;
214                 g->yMax = bbox.yMax;
215
216                 g->ttf_pathlen = face->glyph->outline.n_points;
217         }
218 }
219
220 /*
221  * Get the original encoding of the font. 
222  * Returns 1 for if the original encoding is Unicode, 2 if the
223  * original encoding is other 16-bit, 0 if 8-bit.
224  */
225
226 static int
227 glenc(
228         GLYPH *glyph_list,
229         int *encoding,
230         int *unimap
231 )
232 {
233         int i, e;
234         unsigned code;
235
236         if(ISDBG(FT)) 
237                 for(e=0; e < face->num_charmaps; e++) {
238                         fprintf(stderr, "found encoding pid=%d eid=%d\n", 
239                                 face->charmaps[e]->platform_id,
240                                 face->charmaps[e]->encoding_id);
241                 }
242
243         if(enc_found)
244                 goto populate_map;
245
246         enc_type = 0;
247
248         /* first check for an explicit PID/EID */
249
250         if(force_pid != -1) {
251                 for(e=0; e < face->num_charmaps; e++) {
252                         if(face->charmaps[e]->platform_id == force_pid
253                         && face->charmaps[e]->encoding_id == force_eid) {
254                                 WARNING_1 fprintf(stderr, "Found Encoding PID=%d/EID=%d\n", 
255                                         force_pid, force_eid);
256                                 if( FT_Set_Charmap(face, face->charmaps[e]) ) {
257                                         fprintf(stderr, "**** Cannot set charmap in FreeType ****\n");
258                                         exit(1);
259                                 }
260                                 enc_type = 1;
261                                 goto populate_map;
262                         }
263                 }
264                 fprintf(stderr, "*** TTF encoding table PID=%d/EID=%d not found\n", 
265                         force_pid, force_eid);
266                 exit(1);
267         }
268
269         /* next check for a direct Adobe mapping */
270
271         if(!forcemap) {
272                 for(e=0; e < face->num_charmaps; e++) {
273                         if(face->charmaps[e]->encoding == ft_encoding_adobe_custom) {
274                                 WARNING_1 fputs("Found Adobe Custom Encoding\n", stderr);
275                                 if( FT_Set_Charmap(face, face->charmaps[e]) ) {
276                                         fprintf(stderr, "**** Cannot set charmap in FreeType ****\n");
277                                         exit(1);
278                                 }
279                                 goto populate_map;
280                         }
281                 }
282         }
283
284         for(e=0; e < face->num_charmaps; e++) {
285                 if(face->charmaps[e]->platform_id == 3) {
286                         switch(face->charmaps[e]->encoding_id) {
287                         case 0:
288                                 WARNING_1 fputs("Found Symbol Encoding\n", stderr);
289                                 break;
290                         case 1:
291                                 WARNING_1 fputs("Found Unicode Encoding\n", stderr);
292                                 enc_type = 1;
293                                 break;
294                         default:
295                                 WARNING_1 {
296                                         fprintf(stderr,
297                                         "****MS Encoding ID %d not supported****\n",
298                                                 face->charmaps[e]->encoding_id);
299                                         fputs("Treating it like Symbol encoding\n", stderr);
300                                 }
301                                 break;
302                         }
303                         break;
304                 }
305         }
306         if(e >= face->num_charmaps) {
307                 WARNING_1 fputs("No Microsoft encoding, using first encoding available\n", stderr);
308                 e = 0;
309         }
310         
311         if( FT_Set_Charmap(face, face->charmaps[e]) ) {
312                 fprintf(stderr, "**** Cannot set charmap in FreeType ****\n");
313                 exit(1);
314         }
315
316 populate_map:
317         enc_found = 1;
318         for(i=0; i<ENCTABSZ; i++) {
319                 if(encoding[i] != -1)
320                         continue;
321                 if(enc_type == 1 || forcemap) {
322                         code = unimap[i];
323                         if(code == (unsigned) -1)
324                                 continue;
325                 } else
326                         code = i;
327
328                 code = FT_Get_Char_Index(face, code);
329                 if(0 && ISDBG(FT)) fprintf(stderr, "code of %3d is %3d\n", i, code);
330                 if(code == 0)
331                         continue; /* .notdef */
332                 encoding[i] = code;
333         }
334
335         return enc_type;
336 }
337
338 /* duplicate a string with counter to a 0-terminated string */
339 static char *
340 dupcnstring(
341         char *s,
342         int len
343 )
344 {
345         char *res;
346
347         if(( res = malloc(len+1) )==NULL) {
348                 fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
349                 exit(255);
350         }
351
352         memcpy(res, s, len);
353         res[len] = 0;
354         return res;
355 }
356
357 /*
358  * Get the font metrics
359  */
360 static void 
361 fnmetrics(
362         struct font_metrics *fm
363 )
364 {
365         char *str;
366         static char *fieldstocheck[3];
367 #ifdef ENABLE_SFNT
368         FT_SfntName sn;
369 #endif /* ENABLE_SFNT */
370         int i;
371
372         fm->italic_angle = 0.0; /* FreeType hides the angle */
373         fm->underline_position = face->underline_position;
374         fm->underline_thickness = face->underline_thickness;
375         fm->is_fixed_pitch = FT_IS_FIXED_WIDTH(face);
376
377         fm->ascender = face->ascender;
378         fm->descender = face->descender;
379
380         fm->units_per_em =  face->units_per_EM;
381
382         fm->bbox[0] = face->bbox.xMin;
383         fm->bbox[1] = face->bbox.yMin;
384         fm->bbox[2] = face->bbox.xMax;
385         fm->bbox[3] = face->bbox.yMax;
386
387 #ifdef ENABLE_SFNT
388         if( FT_Get_Sfnt_Name(face, TT_NAME_ID_COPYRIGHT, &sn) )
389 #endif /* ENABLE_SFNT */
390                 fm->name_copyright = "";
391 #ifdef ENABLE_SFNT
392         else
393                 fm->name_copyright = dupcnstring(sn.string, sn.string_len);
394 #endif /* ENABLE_SFNT */
395
396         fm->name_family = face->family_name;
397
398         fm->name_style = face->style_name;
399         if(fm->name_style == NULL)
400                 fm->name_style = "";
401
402 #ifdef ENABLE_SFNT
403         if( FT_Get_Sfnt_Name(face, TT_NAME_ID_FULL_NAME, &sn) ) 
404 #endif /* ENABLE_SFNT */
405         {
406                 int len;
407
408                 len = strlen(fm->name_family) + strlen(fm->name_style) + 2;
409                 if(( fm->name_full = malloc(len) )==NULL) {
410                         fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
411                         exit(255);
412                 }
413                 strcpy(fm->name_full, fm->name_family);
414                 if(strlen(fm->name_style) != 0) {
415                         strcat(fm->name_full, " ");
416                         strcat(fm->name_full, fm->name_style);
417                 }
418         } 
419 #ifdef ENABLE_SFNT
420         else
421                 fm->name_full = dupcnstring(sn.string, sn.string_len);
422 #endif /* ENABLE_SFNT */
423
424 #ifdef ENABLE_SFNT
425         if( FT_Get_Sfnt_Name(face, TT_NAME_ID_VERSION_STRING, &sn) )
426 #endif /* ENABLE_SFNT */
427                 fm->name_version = "1.0";
428 #ifdef ENABLE_SFNT
429         else
430                 fm->name_version = dupcnstring(sn.string, sn.string_len);
431 #endif /* ENABLE_SFNT */
432
433 #ifdef ENABLE_SFNT
434         if( FT_Get_Sfnt_Name(face, TT_NAME_ID_PS_NAME , &sn) ) {
435 #endif /* ENABLE_SFNT */
436                 if(( fm->name_ps = strdup(fm->name_full) )==NULL) {
437                         fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
438                         exit(255);
439                 }
440 #ifdef ENABLE_SFNT
441         } else
442                 fm->name_ps = dupcnstring(sn.string, sn.string_len);
443 #endif /* ENABLE_SFNT */
444
445         /* guess the boldness from the font names */
446         fm->force_bold=0;
447
448         fieldstocheck[0] = fm->name_style;
449         fieldstocheck[1] = fm->name_full;
450         fieldstocheck[2] = fm->name_ps;
451
452         for(i=0; !fm->force_bold && i<sizeof fieldstocheck /sizeof(fieldstocheck[0]); i++) {
453                 str=fieldstocheck[i];
454                 for(i=0; str[i]!=0; i++) {
455                         if( (str[i]=='B'
456                                 || str[i]=='b' 
457                                         && ( i==0 || !isalpha(str[i-1]) )
458                                 )
459                         && !strncmp("old",&str[i+1],3)
460                         && !islower(str[i+4])
461                         ) {
462                                 fm->force_bold=1;
463                                 break;
464                         }
465                 }
466         }
467 }
468
469 /*
470  * Functions to decompose the outlines
471  */
472
473 static GLYPH *curg;
474 static double lastx, lasty;
475
476 static int
477 outl_moveto(
478         FT_Vector *to,
479         void *unused
480 )
481 {
482         double tox, toy;
483
484         tox = fscale((double)to->x); toy = fscale((double)to->y);
485
486         /* FreeType does not do explicit closepath() */
487         if(curg->lastentry) {
488                 g_closepath(curg);
489         }
490         fg_rmoveto(curg, tox, toy);
491         lastx = tox; lasty = toy;
492
493         return 0;
494 }
495
496 static int
497 outl_lineto(
498         FT_Vector *to,
499         void *unused
500 )
501 {
502         double tox, toy;
503
504         tox = fscale((double)to->x); toy = fscale((double)to->y);
505
506         fg_rlineto(curg, tox, toy);
507         lastx = tox; lasty = toy;
508
509         return 0;
510 }
511
512 static int
513 outl_conicto(
514         FT_Vector *control1,
515         FT_Vector *to,
516         void *unused
517 )
518 {
519         double c1x, c1y, tox, toy;
520
521         c1x = fscale((double)control1->x); c1y = fscale((double)control1->y);
522         tox = fscale((double)to->x); toy = fscale((double)to->y);
523
524         fg_rrcurveto(curg,
525                 (lastx + 2.0 * c1x) / 3.0, (lasty + 2.0 * c1y) / 3.0,
526                 (2.0 * c1x + tox) / 3.0, (2.0 * c1y + toy) / 3.0,
527                 tox, toy );
528         lastx = tox; lasty = toy;
529
530         return 0;
531 }
532
533 static int
534 outl_cubicto(
535         FT_Vector *control1,
536         FT_Vector *control2,
537         FT_Vector *to,
538         void *unused
539 )
540 {
541         double c1x, c1y, c2x, c2y, tox, toy;
542
543         c1x = fscale((double)control1->x); c1y = fscale((double)control1->y);
544         c2x = fscale((double)control2->x); c2y = fscale((double)control2->y);
545         tox = fscale((double)to->x); toy = fscale((double)to->y);
546
547         fg_rrcurveto(curg, c1x, c1y, c2x, c2y, tox, toy);
548         lastx = tox; lasty = toy;
549
550         return 0;
551 }
552
553 static FT_Outline_Funcs ft_outl_funcs = {
554         outl_moveto,
555         outl_lineto,
556         outl_conicto,
557         outl_cubicto,
558         0,
559         0
560 };
561
562 /*
563  * Get the path of contrours for a glyph.
564  */
565
566 static void
567 glpath(
568         int glyphno,
569         GLYPH *glyf_list
570 )
571 {
572         FT_Outline *ol;
573
574         curg = &glyf_list[glyphno];
575
576         if( FT_Load_Glyph(face, glyphno, FT_LOAD_NO_BITMAP|FT_LOAD_NO_SCALE|FT_LOAD_NO_HINTING) 
577         || face->glyph->format != ft_glyph_format_outline ) {
578                 fprintf(stderr, "Can't load glyph %s, skipped\n", curg->name);
579                 return;
580         }
581
582         ol = &face->glyph->outline;
583         lastx = 0.0; lasty = 0.0;
584
585         if( FT_Outline_Decompose(ol, &ft_outl_funcs, NULL) ) {
586                 fprintf(stderr, "Can't decompose outline of glyph %s, skipped\n", curg->name);
587                 return;
588         }
589
590         /* FreeType does not do explicit closepath() */
591         if(curg->lastentry) {
592                 g_closepath(curg);
593         }
594
595         if(ol->flags & ft_outline_reverse_fill) {
596                 assertpath(curg->entries, __FILE__, __LINE__, curg->name);
597                 reversepaths(curg);
598         }
599 }
600
601 /*
602  * Get the kerning data.
603  */
604
605 static void
606 kerning(
607         GLYPH *glyph_list
608 )
609 {
610         int     i, j, n;
611         int     nglyphs = face->num_glyphs;
612         FT_Vector k;
613         GLYPH *gl;
614
615         if( nglyphs == 0 || !FT_HAS_KERNING(face) ) {
616         WARNING_1 fputs("No Kerning data\n", stderr);
617                 return;
618         }
619
620         for(i=0; i<nglyphs; i++)  {
621                 if( (glyph_list[i].flags & GF_USED) ==0)
622                         continue;
623                 for(j=0; j<nglyphs; j++) {
624                         if( (glyph_list[j].flags & GF_USED) ==0)
625                                 continue;
626                         if( FT_Get_Kerning(face, i, j, ft_kerning_unscaled, &k) )
627                                 continue;
628                         if( k.x == 0 )
629                                 continue;
630
631                         addkernpair(i, j, k.x);
632                 }
633         }
634 }
635
636 #endif