92ffeddcbaf589271320dfe28db894953b87403b
[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/ftsnames.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( unsigned 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, "_g_%d", i);
157                         WARNING_2 fprintf(stderr,
158                                 "Glyph No. %d has no postscript name, becomes %s\n", i, bf);
159                 }
160                 glyph_list[i].name = strdup(bf);
161                 if(ISDBG(FT)) fprintf(stderr, "%d has name %s\n", i, bf);
162                 if (glyph_list[i].name == NULL) {
163                         fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
164                         exit(255);
165                 }
166         }
167         return 0;
168 }
169
170 /*
171  * Get the metrics of the glyphs.
172  */
173
174 static void
175 glmetrics(
176         GLYPH *glyph_list
177 )
178 {
179         GLYPH          *g;
180         int i;
181         FT_Glyph_Metrics *met;
182         FT_BBox bbox;
183         FT_Glyph gly;
184
185         for(i=0; i < face->num_glyphs; i++) {
186                 g = &(glyph_list[i]);
187
188                 if( FT_Load_Glyph(face, i, FT_LOAD_NO_BITMAP|FT_LOAD_NO_SCALE) ) {
189                         fprintf(stderr, "Can't load glyph %s, skipped\n", g->name);
190                         continue;
191                 }
192
193                 met = &face->glyph->metrics;
194
195                 if(FT_HAS_HORIZONTAL(face)) {
196                         g->width = met->horiAdvance;
197                         g->lsb = met->horiBearingX;
198                 } else {
199                         WARNING_2 fprintf(stderr, "Glyph %s has no horizontal metrics, guessed them\n", g->name);
200                         g->width = met->width;
201                         g->lsb = 0;
202                 }
203
204                 if( FT_Get_Glyph(face->glyph, &gly) ) {
205                         fprintf(stderr, "Can't access glyph %s bbox, skipped\n", g->name);
206                         continue;
207                 }
208
209                 FT_Glyph_Get_CBox(gly, ft_glyph_bbox_unscaled, &bbox);
210                 g->xMin = bbox.xMin;
211                 g->yMin = bbox.yMin;
212                 g->xMax = bbox.xMax;
213                 g->yMax = bbox.yMax;
214
215                 g->ttf_pathlen = face->glyph->outline.n_points;
216         }
217 }
218
219 /*
220  * Get the original encoding of the font. 
221  * Returns 1 for if the original encoding is Unicode, 2 if the
222  * original encoding is other 16-bit, 0 if 8-bit.
223  */
224
225 static int
226 glenc(
227         GLYPH *glyph_list,
228         int *encoding,
229         int *unimap
230 )
231 {
232         int i, e;
233         unsigned code;
234
235         if(ISDBG(FT)) 
236                 for(e=0; e < face->num_charmaps; e++) {
237                         fprintf(stderr, "found encoding pid=%d eid=%d\n", 
238                                 face->charmaps[e]->platform_id,
239                                 face->charmaps[e]->encoding_id);
240                 }
241
242         if(enc_found)
243                 goto populate_map;
244
245         enc_type = 0;
246
247         /* first check for an explicit PID/EID */
248
249         if(force_pid != -1) {
250                 for(e=0; e < face->num_charmaps; e++) {
251                         if(face->charmaps[e]->platform_id == force_pid
252                         && face->charmaps[e]->encoding_id == force_eid) {
253                                 WARNING_1 fprintf(stderr, "Found Encoding PID=%d/EID=%d\n", 
254                                         force_pid, force_eid);
255                                 if( FT_Set_Charmap(face, face->charmaps[e]) ) {
256                                         fprintf(stderr, "**** Cannot set charmap in FreeType ****\n");
257                                         exit(1);
258                                 }
259                                 enc_type = 1;
260                                 goto populate_map;
261                         }
262                 }
263                 fprintf(stderr, "*** TTF encoding table PID=%d/EID=%d not found\n", 
264                         force_pid, force_eid);
265                 exit(1);
266         }
267
268         /* next check for a direct Adobe mapping */
269
270         if(!forcemap) {
271                 for(e=0; e < face->num_charmaps; e++) {
272                         if(face->charmaps[e]->encoding == ft_encoding_adobe_custom) {
273                                 WARNING_1 fputs("Found Adobe Custom Encoding\n", stderr);
274                                 if( FT_Set_Charmap(face, face->charmaps[e]) ) {
275                                         fprintf(stderr, "**** Cannot set charmap in FreeType ****\n");
276                                         exit(1);
277                                 }
278                                 goto populate_map;
279                         }
280                 }
281         }
282
283         for(e=0; e < face->num_charmaps; e++) {
284                 if(face->charmaps[e]->platform_id == 3) {
285                         switch(face->charmaps[e]->encoding_id) {
286                         case 0:
287                                 WARNING_1 fputs("Found Symbol Encoding\n", stderr);
288                                 break;
289                         case 1:
290                                 WARNING_1 fputs("Found Unicode Encoding\n", stderr);
291                                 enc_type = 1;
292                                 break;
293                         default:
294                                 WARNING_1 {
295                                         fprintf(stderr,
296                                         "****MS Encoding ID %d not supported****\n",
297                                                 face->charmaps[e]->encoding_id);
298                                         fputs("Treating it like Symbol encoding\n", stderr);
299                                 }
300                                 break;
301                         }
302                         break;
303                 }
304         }
305         if(e >= face->num_charmaps) {
306                 WARNING_1 fputs("No Microsoft encoding, using first encoding available\n", stderr);
307                 e = 0;
308         }
309         
310         if( FT_Set_Charmap(face, face->charmaps[e]) ) {
311                 fprintf(stderr, "**** Cannot set charmap in FreeType ****\n");
312                 exit(1);
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                 len = strlen(fm->name_family) + strlen(fm->name_style) + 2;
418                 if(( fm->name_full = malloc(len) )==NULL) {
419                         fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
420                         exit(255);
421                 }
422                 strcpy(fm->name_full, fm->name_family);
423                 if(strlen(fm->name_style) != 0) {
424                         strcat(fm->name_full, " ");
425                         strcat(fm->name_full, fm->name_style);
426                 }
427         } 
428 #ifdef ENABLE_SFNT
429         else
430                 fm->name_full = 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_VERSION_STRING, &sn) )
435 #endif /* ENABLE_SFNT */
436                 fm->name_version = "1.0";
437 #ifdef ENABLE_SFNT
438         else
439                 fm->name_version = dupcnstring(sn.string, sn.string_len);
440 #endif /* ENABLE_SFNT */
441
442 #ifdef ENABLE_SFNT
443         if( FT_Get_Sfnt_Name(face, TT_NAME_ID_PS_NAME , &sn) ) {
444 #endif /* ENABLE_SFNT */
445                 if(( fm->name_ps = strdup(fm->name_full) )==NULL) {
446                         fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
447                         exit(255);
448                 }
449 #ifdef ENABLE_SFNT
450         } else
451                 fm->name_ps = dupcnstring(sn.string, sn.string_len);
452 #endif /* ENABLE_SFNT */
453         for(i=0; fm->name_ps[i]!=0; i++)
454                 if(fm->name_ps[i] == ' ')
455                         fm->name_ps[i] = '_'; /* no spaces in the Postscript name *m
456
457         /* guess the boldness from the font names */
458         fm->force_bold=0;
459
460         fieldstocheck[0] = fm->name_style;
461         fieldstocheck[1] = fm->name_full;
462         fieldstocheck[2] = fm->name_ps;
463
464         for(i=0; !fm->force_bold && i<sizeof fieldstocheck /sizeof(fieldstocheck[0]); i++) {
465                 str=fieldstocheck[i];
466                 for(i=0; str[i]!=0; i++) {
467                         if( (str[i]=='B'
468                                 || str[i]=='b' 
469                                         && ( i==0 || !isalpha(str[i-1]) )
470                                 )
471                         && !strncmp("old",&str[i+1],3)
472                         && !islower(str[i+4])
473                         ) {
474                                 fm->force_bold=1;
475                                 break;
476                         }
477                 }
478         }
479 }
480
481 /*
482  * Functions to decompose the outlines
483  */
484
485 static GLYPH *curg;
486 static double lastx, lasty;
487
488 static int
489 outl_moveto(
490         FT_Vector *to,
491         void *unused
492 )
493 {
494         double tox, toy;
495
496         tox = fscale((double)to->x); toy = fscale((double)to->y);
497
498         /* FreeType does not do explicit closepath() */
499         if(curg->lastentry) {
500                 g_closepath(curg);
501         }
502         fg_rmoveto(curg, tox, toy);
503         lastx = tox; lasty = toy;
504
505         return 0;
506 }
507
508 static int
509 outl_lineto(
510         FT_Vector *to,
511         void *unused
512 )
513 {
514         double tox, toy;
515
516         tox = fscale((double)to->x); toy = fscale((double)to->y);
517
518         fg_rlineto(curg, tox, toy);
519         lastx = tox; lasty = toy;
520
521         return 0;
522 }
523
524 static int
525 outl_conicto(
526         FT_Vector *control1,
527         FT_Vector *to,
528         void *unused
529 )
530 {
531         double c1x, c1y, tox, toy;
532
533         c1x = fscale((double)control1->x); c1y = fscale((double)control1->y);
534         tox = fscale((double)to->x); toy = fscale((double)to->y);
535
536         fg_rrcurveto(curg,
537                 (lastx + 2.0 * c1x) / 3.0, (lasty + 2.0 * c1y) / 3.0,
538                 (2.0 * c1x + tox) / 3.0, (2.0 * c1y + toy) / 3.0,
539                 tox, toy );
540         lastx = tox; lasty = toy;
541
542         return 0;
543 }
544
545 static int
546 outl_cubicto(
547         FT_Vector *control1,
548         FT_Vector *control2,
549         FT_Vector *to,
550         void *unused
551 )
552 {
553         double c1x, c1y, c2x, c2y, tox, toy;
554
555         c1x = fscale((double)control1->x); c1y = fscale((double)control1->y);
556         c2x = fscale((double)control2->x); c2y = fscale((double)control2->y);
557         tox = fscale((double)to->x); toy = fscale((double)to->y);
558
559         fg_rrcurveto(curg, c1x, c1y, c2x, c2y, tox, toy);
560         lastx = tox; lasty = toy;
561
562         return 0;
563 }
564
565 static FT_Outline_Funcs ft_outl_funcs = {
566         outl_moveto,
567         outl_lineto,
568         outl_conicto,
569         outl_cubicto,
570         0,
571         0
572 };
573
574 /*
575  * Get the path of contrours for a glyph.
576  */
577
578 static void
579 glpath(
580         int glyphno,
581         GLYPH *glyf_list
582 )
583 {
584         FT_Outline *ol;
585
586         curg = &glyf_list[glyphno];
587
588         if( FT_Load_Glyph(face, glyphno, FT_LOAD_NO_BITMAP|FT_LOAD_NO_SCALE|FT_LOAD_NO_HINTING) 
589         || face->glyph->format != ft_glyph_format_outline ) {
590                 fprintf(stderr, "Can't load glyph %s, skipped\n", curg->name);
591                 return;
592         }
593
594         ol = &face->glyph->outline;
595         lastx = 0.0; lasty = 0.0;
596
597         if( FT_Outline_Decompose(ol, &ft_outl_funcs, NULL) ) {
598                 fprintf(stderr, "Can't decompose outline of glyph %s, skipped\n", curg->name);
599                 return;
600         }
601
602         /* FreeType does not do explicit closepath() */
603         if(curg->lastentry) {
604                 g_closepath(curg);
605         }
606
607         if(ol->flags & ft_outline_reverse_fill) {
608                 assertpath(curg->entries, __FILE__, __LINE__, curg->name);
609                 reversepaths(curg);
610         }
611 }
612
613 /*
614  * Get the kerning data.
615  */
616
617 static void
618 kerning(
619         GLYPH *glyph_list
620 )
621 {
622         int     i, j, n;
623         int     nglyphs = face->num_glyphs;
624         FT_Vector k;
625         GLYPH *gl;
626
627         if( nglyphs == 0 || !FT_HAS_KERNING(face) ) {
628         WARNING_1 fputs("No Kerning data\n", stderr);
629                 return;
630         }
631
632         for(i=0; i<nglyphs; i++)  {
633                 if( (glyph_list[i].flags & GF_USED) ==0)
634                         continue;
635                 for(j=0; j<nglyphs; j++) {
636                         if( (glyph_list[j].flags & GF_USED) ==0)
637                                 continue;
638                         if( FT_Get_Kerning(face, i, j, ft_kerning_unscaled, &k) )
639                                 continue;
640                         if( k.x == 0 )
641                                 continue;
642
643                         addkernpair(i, j, k.x);
644                 }
645         }
646 }
647
648 #endif