gcc 2.95.4 fixes
[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 #include "../../config.h"
9 #ifdef USE_FREETYPE
10
11 #include <stdio.h>
12 #include <string.h>
13 #include <stdlib.h>
14 #include <ctype.h>
15 #include <sys/types.h>
16 #include <freetype/freetype.h>
17 #include <freetype/ftglyph.h>
18 #include <freetype/ftsnames.h>
19 #include <freetype/ttnameid.h>
20 #include <freetype/ftoutln.h>
21 #include "pt1.h"
22 #include "global.h"
23
24 /* prototypes of call entries */
25 static void openfont(char *fname, char *arg);
26 static void closefont( void);
27 static int getnglyphs ( void);
28 static int glnames( GLYPH *glyph_list);
29 static void glmetrics( GLYPH *glyph_list);
30 static int glenc( GLYPH *glyph_list, int *encoding, int *unimap);
31 static void fnmetrics( struct font_metrics *fm);
32 static void glpath( int glyphno, GLYPH *glyph_list);
33 static void kerning( GLYPH *glyph_list);
34
35 /* globals */
36
37 /* front-end descriptor */
38 struct frontsw freetype_sw = {
39         /*name*/       "ft",
40         /*descr*/      "based on the FreeType library",
41         /*suffix*/     { "ttf", "otf", "pfa", "pfb" },
42         /*open*/       openfont,
43         /*close*/      closefont,
44         /*nglyphs*/    getnglyphs,
45         /*glnames*/    glnames,
46         /*glmetrics*/  glmetrics,
47         /*glenc*/      glenc,
48         /*fnmetrics*/  fnmetrics,
49         /*glpath*/     glpath,
50         /*kerning*/    kerning,
51 };
52
53 /* statics */
54
55 static char * dupcnstring( unsigned char *s, int len);
56
57 static FT_Library library;
58 static FT_Face face;
59
60 static int enc_type, enc_found;
61
62 /* SFNT functions do not seem to be included by default in FT2beta8 */
63 #define ENABLE_SFNT
64
65 /*
66  * Open font and prepare to return information to the main driver.
67  * May print error and warning messages.
68  * Exit on error.
69  */
70
71 static void
72 openfont(
73         char *fname,
74         char *arg /* unused now */
75 )
76 {
77         FT_Error error;
78
79         if( FT_Init_FreeType( &library ) ) {
80                 fprintf(stderr, "** FreeType initialization failed\n");
81                 exit(1);
82         }
83
84         if( error = FT_New_Face( library, fname, 0, &face ) ) {
85                 if ( error == FT_Err_Unknown_File_Format )
86                         fprintf(stderr, "**** %s has format unknown to FreeType\n", fname);
87                 else
88                         fprintf(stderr, "**** Cannot access %s ****\n", fname);
89                 exit(1);
90         }
91
92         if(FT_HAS_FIXED_SIZES(face)) {
93                 WARNING_1 fprintf(stderr, "Font contains bitmaps\n");
94         }
95         if(FT_HAS_MULTIPLE_MASTERS(face)) {
96                 WARNING_1 fprintf(stderr, "Font contains multiple masters, using default\n");
97         }
98
99         if(ISDBG(FT)) fprintf(stderr," %d units per EM\n", face->units_per_EM);
100
101         enc_found = 0;
102 }
103
104 /*
105  * Close font.
106  * Exit on error.
107  */
108
109 static void
110 closefont(
111         void
112 )
113 {
114         if( FT_Done_Face(face) ) {
115                 WARNING_1 fprintf(stderr, "Errors when closing the font file, ignored\n");
116         }
117         if( FT_Done_FreeType(library) ) {
118                 WARNING_1 fprintf(stderr, "Errors when stopping FreeType, ignored\n");
119         }
120 }
121
122 /*
123  * Get the number of glyphs in font.
124  */
125
126 static int
127 getnglyphs (
128         void
129 )
130 {
131         if(ISDBG(FT)) fprintf(stderr, "%d glyphs in font\n", face->num_glyphs);
132         return (int)face->num_glyphs;
133 }
134
135 /*
136  * Get the names of the glyphs.
137  * Returns 0 if the names were assigned, non-zero if the font
138  * provides no glyph names.
139  */
140
141 static int
142 glnames(
143         GLYPH *glyph_list
144 )
145 {
146 #define MAX_NAMELEN     1024
147         unsigned char bf[1024];
148         int i;
149
150         if( ! FT_HAS_GLYPH_NAMES(face) ) {
151                 WARNING_1 fprintf(stderr, "Font has no glyph names\n");
152                 return 1;
153         }
154
155         for(i=0; i < face->num_glyphs; i++) {
156                 if( FT_Get_Glyph_Name(face, i, bf, MAX_NAMELEN) || bf[0]==0 ) {
157                         sprintf(bf, "_g_%d", i);
158                         WARNING_2 fprintf(stderr,
159                                 "Glyph No. %d has no postscript name, becomes %s\n", 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( !face->charmaps || FT_Set_Charmap(face, face->charmaps[e]) ) {
312                 fprintf(stderr, "**** Cannot set charmap in FreeType ****\n");
313         }
314
315 populate_map:
316         enc_found = 1;
317         for(i=0; i<ENCTABSZ; i++) {
318                 if(encoding[i] != -1)
319                         continue;
320                 if(enc_type == 1 || forcemap) {
321                         code = unimap[i];
322                         if(code == (unsigned) -1)
323                                 continue;
324                 } else
325                         code = i;
326
327                 code = FT_Get_Char_Index(face, code);
328                 if(0 && ISDBG(FT)) fprintf(stderr, "code of %3d is %3d\n", i, code);
329                 if(code == 0)
330                         continue; /* .notdef */
331                 encoding[i] = code;
332         }
333
334         return enc_type;
335 }
336
337 /* duplicate a string with counter to a 0-terminated string */
338 static char *
339 dupcnstring(
340         unsigned char *s,
341         int len
342 )
343 {
344         char *res, *out;
345         int i, c;
346         static int warned=0;
347
348         if(( res = malloc(len+1) )==NULL) {
349                 fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
350                 exit(255);
351         }
352
353         out = res;
354         for(i=0; i<len; i++) {
355                 if(( c=s[i] )>=' ' && c!=127)
356                         *out++ = c;
357                 else if(!warned) {
358                         warned=1;
359                         WARNING_1 fprintf(stderr, "Some font name strings are in Unicode, may not show properly\n");
360                 }
361         }
362         *out = 0;
363         return res;
364 }
365
366 /*
367  * Get the font metrics
368  */
369 static void 
370 fnmetrics(
371         struct font_metrics *fm
372 )
373 {
374         char *str;
375         static char *fieldstocheck[3];
376 #ifdef ENABLE_SFNT
377         FT_SfntName sn;
378 #endif /* ENABLE_SFNT */
379         int i;
380
381         fm->italic_angle = 0.0; /* FreeType hides the angle */
382         fm->underline_position = face->underline_position;
383         fm->underline_thickness = face->underline_thickness;
384         fm->is_fixed_pitch = FT_IS_FIXED_WIDTH(face);
385
386         fm->ascender = face->ascender;
387         fm->descender = face->descender;
388
389         fm->units_per_em =  face->units_per_EM;
390
391         fm->bbox[0] = face->bbox.xMin;
392         fm->bbox[1] = face->bbox.yMin;
393         fm->bbox[2] = face->bbox.xMax;
394         fm->bbox[3] = face->bbox.yMax;
395
396 #ifdef ENABLE_SFNT
397         if( FT_Get_Sfnt_Name(face, TT_NAME_ID_COPYRIGHT, &sn) )
398 #endif /* ENABLE_SFNT */
399                 fm->name_copyright = "";
400 #ifdef ENABLE_SFNT
401         else
402                 fm->name_copyright = dupcnstring(sn.string, sn.string_len);
403 #endif /* ENABLE_SFNT */
404
405         fm->name_family = face->family_name;
406
407         fm->name_style = face->style_name;
408         if(fm->name_style == NULL)
409                 fm->name_style = "";
410
411 #ifdef ENABLE_SFNT
412         if( FT_Get_Sfnt_Name(face, TT_NAME_ID_FULL_NAME, &sn) ) 
413 #endif /* ENABLE_SFNT */
414         {
415                 int len;
416
417                 if(!fm->name_family)
418                     fm->name_family = "";
419                 if(!fm->name_style)
420                     fm->name_style= "";
421                 len = strlen(fm->name_family) + strlen(fm->name_style) + 2;
422                 if(( fm->name_full = malloc(len) )==NULL) {
423                         fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
424                         exit(255);
425                 }
426                 strcpy(fm->name_full, fm->name_family);
427                 if(strlen(fm->name_style) != 0) {
428                         strcat(fm->name_full, " ");
429                         strcat(fm->name_full, fm->name_style);
430                 }
431         } 
432 #ifdef ENABLE_SFNT
433         else
434                 fm->name_full = dupcnstring(sn.string, sn.string_len);
435 #endif /* ENABLE_SFNT */
436
437 #ifdef ENABLE_SFNT
438         if( FT_Get_Sfnt_Name(face, TT_NAME_ID_VERSION_STRING, &sn) )
439 #endif /* ENABLE_SFNT */
440                 fm->name_version = "1.0";
441 #ifdef ENABLE_SFNT
442         else
443                 fm->name_version = dupcnstring(sn.string, sn.string_len);
444 #endif /* ENABLE_SFNT */
445
446 #ifdef ENABLE_SFNT
447         if( FT_Get_Sfnt_Name(face, TT_NAME_ID_PS_NAME , &sn) ) {
448 #endif /* ENABLE_SFNT */
449                 if(( fm->name_ps = strdup(fm->name_full) )==NULL) {
450                         fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
451                         exit(255);
452                 }
453 #ifdef ENABLE_SFNT
454         } else
455                 fm->name_ps = dupcnstring(sn.string, sn.string_len);
456 #endif /* ENABLE_SFNT */
457         for(i=0; fm->name_ps[i]!=0; i++)
458                 if(fm->name_ps[i] == ' ')
459                         fm->name_ps[i] = '_'; /* no spaces in the Postscript name */
460
461         /* guess the boldness from the font names */
462         fm->force_bold=0;
463
464         fieldstocheck[0] = fm->name_style;
465         fieldstocheck[1] = fm->name_full;
466         fieldstocheck[2] = fm->name_ps;
467
468         for(i=0; !fm->force_bold && i<sizeof fieldstocheck /sizeof(fieldstocheck[0]); i++) {
469                 int j;
470                 str=fieldstocheck[i];
471                 for(j=0; str[j]!=0; j++) {
472                         if( (str[j]=='B'
473                                 || str[j]=='b' 
474                                         && ( j==0 || !isalpha(str[j-1]) )
475                                 )
476                         && !strncmp("old",&str[j+1],3)
477                         && !islower(str[j+4])
478                         ) {
479                                 fm->force_bold=1;
480                                 break;
481                         }
482                 }
483         }
484 }
485
486 /*
487  * Functions to decompose the outlines
488  */
489
490 static GLYPH *curg;
491 static double lastx, lasty;
492
493 static int
494 outl_moveto(
495         FT_Vector *to,
496         void *unused
497 )
498 {
499         double tox, toy;
500
501         tox = fscale((double)to->x); toy = fscale((double)to->y);
502
503         /* FreeType does not do explicit closepath() */
504         if(curg->lastentry) {
505                 g_closepath(curg);
506         }
507         fg_rmoveto(curg, tox, toy);
508         lastx = tox; lasty = toy;
509
510         return 0;
511 }
512
513 static int
514 outl_lineto(
515         FT_Vector *to,
516         void *unused
517 )
518 {
519         double tox, toy;
520
521         tox = fscale((double)to->x); toy = fscale((double)to->y);
522
523         fg_rlineto(curg, tox, toy);
524         lastx = tox; lasty = toy;
525
526         return 0;
527 }
528
529 static int
530 outl_conicto(
531         FT_Vector *control1,
532         FT_Vector *to,
533         void *unused
534 )
535 {
536         double c1x, c1y, tox, toy;
537
538         c1x = fscale((double)control1->x); c1y = fscale((double)control1->y);
539         tox = fscale((double)to->x); toy = fscale((double)to->y);
540
541         fg_rrcurveto(curg,
542                 (lastx + 2.0 * c1x) / 3.0, (lasty + 2.0 * c1y) / 3.0,
543                 (2.0 * c1x + tox) / 3.0, (2.0 * c1y + toy) / 3.0,
544                 tox, toy );
545         lastx = tox; lasty = toy;
546
547         return 0;
548 }
549
550 static int
551 outl_cubicto(
552         FT_Vector *control1,
553         FT_Vector *control2,
554         FT_Vector *to,
555         void *unused
556 )
557 {
558         double c1x, c1y, c2x, c2y, tox, toy;
559
560         c1x = fscale((double)control1->x); c1y = fscale((double)control1->y);
561         c2x = fscale((double)control2->x); c2y = fscale((double)control2->y);
562         tox = fscale((double)to->x); toy = fscale((double)to->y);
563
564         fg_rrcurveto(curg, c1x, c1y, c2x, c2y, tox, toy);
565         lastx = tox; lasty = toy;
566
567         return 0;
568 }
569
570 static FT_Outline_Funcs ft_outl_funcs = {
571         outl_moveto,
572         outl_lineto,
573         outl_conicto,
574         outl_cubicto,
575         0,
576         0
577 };
578
579 /*
580  * Get the path of contrours for a glyph.
581  */
582
583 static void
584 glpath(
585         int glyphno,
586         GLYPH *glyf_list
587 )
588 {
589         FT_Outline *ol;
590
591         curg = &glyf_list[glyphno];
592
593         if( FT_Load_Glyph(face, glyphno, FT_LOAD_NO_BITMAP|FT_LOAD_NO_SCALE|FT_LOAD_NO_HINTING) 
594         || face->glyph->format != ft_glyph_format_outline ) {
595                 fprintf(stderr, "Can't load glyph %s, skipped\n", curg->name);
596                 return;
597         }
598
599         ol = &face->glyph->outline;
600         lastx = 0.0; lasty = 0.0;
601
602         if( FT_Outline_Decompose(ol, &ft_outl_funcs, NULL) ) {
603                 fprintf(stderr, "Can't decompose outline of glyph %s, skipped\n", curg->name);
604                 return;
605         }
606
607         /* FreeType does not do explicit closepath() */
608         if(curg->lastentry) {
609                 g_closepath(curg);
610         }
611
612         if(ol->flags & ft_outline_reverse_fill) {
613                 assertpath(curg->entries, __FILE__, __LINE__, curg->name);
614                 reversepaths(curg);
615         }
616 }
617
618 /*
619  * Get the kerning data.
620  */
621
622 static void
623 kerning(
624         GLYPH *glyph_list
625 )
626 {
627         int     i, j, n;
628         int     nglyphs = face->num_glyphs;
629         FT_Vector k;
630         GLYPH *gl;
631
632         if( nglyphs == 0 || !FT_HAS_KERNING(face) ) {
633         WARNING_1 fputs("No Kerning data\n", stderr);
634                 return;
635         }
636
637         for(i=0; i<nglyphs; i++)  {
638                 if( (glyph_list[i].flags & GF_USED) ==0)
639                         continue;
640                 for(j=0; j<nglyphs; j++) {
641                         if( (glyph_list[j].flags & GF_USED) ==0)
642                                 continue;
643                         if( FT_Get_Kerning(face, i, j, ft_kerning_unscaled, &k) )
644                                 continue;
645                         if( k.x == 0 )
646                                 continue;
647
648                         addkernpair(i, j, k.x);
649                 }
650         }
651 }
652
653 #endif