added chapter seperation.
[swftools.git] / pdf2swf / ttf2pt1 / bdf.c
1 /*
2  * The font parser for the BDF files
3  *
4  * Copyright (c) 2001 by the TTF2PT1 project
5  * Copyright (c) 2001 by Sergey Babkin
6  *
7  * see COPYRIGHT for the full copyright notice
8  */
9
10 #include <stdio.h>
11 #include <string.h>
12 #include <stdlib.h>
13 #include <ctype.h>
14 #include "pt1.h"
15 #include "global.h"
16
17 /* prototypes of call entries */
18 static void openfont(char *fname, char *arg);
19 static void closefont( void);
20 static int getnglyphs ( void);
21 static int glnames( GLYPH *glyph_list);
22 static void readglyphs( GLYPH *glyph_list);
23 static int glenc( GLYPH *glyph_list, int *encoding, int *unimap);
24 static void fnmetrics( struct font_metrics *fm);
25 static void glpath( int glyphno, GLYPH *glyph_list);
26 static void kerning( GLYPH *glyph_list);
27
28 /* globals */
29
30 /* front-end descriptor */
31 struct frontsw bdf_sw = {
32         /*name*/       "bdf",
33         /*descr*/      "BDF bitmapped fonts",
34         /*suffix*/     { "bdf" },
35         /*open*/       openfont,
36         /*close*/      closefont,
37         /*nglyphs*/    getnglyphs,
38         /*glnames*/    glnames,
39         /*glmetrics*/  readglyphs,
40         /*glenc*/      glenc,
41         /*fnmetrics*/  fnmetrics,
42         /*glpath*/     glpath,
43         /*kerning*/    kerning,
44 };
45
46 /* statics */
47
48 #define MAXLINE 10240 /* maximal line length in the input file */
49
50 static int lineno; /* line number */
51
52 #define GETLEN(s)       s, (sizeof(s)-1)
53 #define LENCMP(str, txt)        strncmp(str, txt, sizeof(txt)-1)
54
55 static FILE *bdf_file;
56 static int nglyphs;
57 static struct font_metrics fmet;
58
59 /* many BDF fonts are of small pixel size, so we better try
60  * to scale them by an integer to keep the dimensions in
61  * whole pixels. However if the size is too big and a non-
62  * integer scaling is needed, we use the standard ttf2pt1's
63  * scaling abilities.
64  */
65 static int pixel_size;
66 static int scale;
67 static int scale_external;
68
69 static char *slant;
70 static char xlfdname[201];
71 static char *spacing;
72 static char *charset_reg;
73 static char *charset_enc;
74 static char *fnwidth;
75 static int is_unicode = 0;
76
77 /* tempoary storage for returning data to ttf2pt1 later on request */
78 static int maxenc = 0;
79 static int *fontenc;
80 static GENTRY **glpaths;
81
82 static int got_glyphs = 0;
83 static GLYPH *glyphs;
84 static int curgl;
85
86 static int readfile(FILE *f, int (*strfunc)(int len, char *str));
87
88 /*
89  * Read the file and parse each string with strfunc(),
90  * until strfunc() returns !=0 or the end of file happens.
91  * Returns -1 on EOF or strfunc() returning <0, else 0
92  */
93
94 static int
95 readfile(
96         FILE *f,
97         int (*strfunc)(int len, char *str)
98 )
99 {
100         static char str[MAXLINE]; /* input line, maybe should be dynamic ? */
101         char *s;
102         int len, c, res;
103
104         len=0;
105         while(( c=getc(f) )!=EOF) {
106                 if(c=='\n') {
107                         str[len]=0;
108
109                         res = strfunc(len, str);
110                         lineno++;
111                         if(res<0)
112                                 return -1;
113                         else if(res!=0)
114                                 return 0;
115
116                         len=0;
117                 } else if(len<MAXLINE-1) {
118                         if(c!='\r')
119                                 str[len++]=c;
120                 } else {
121                         fprintf(stderr, "**** bdf: line %d is too long (>%d)\n", lineno, MAXLINE-1);
122                         exit(1);
123                 }
124         }
125         return -1; /* EOF */
126 }
127
128 /*
129  * Parse the header of the font file. 
130  * Stop after the line CHARS is encountered. Ignore the unknown lines.
131  */
132
133 struct line {
134         char *name; /* property name with trailing space */
135         int namelen; /* length of the name string */
136         enum {
137                 ALLOW_REPEAT = 0x01, /* this property may be repeated in multiple lines */
138                 IS_SEEN = 0x02, /* this property has been seen already */
139                 MUST_SEE = 0x04, /* this property must be seen */
140                 IS_LAST = 0x08 /* this is the last property to be read */
141         } flags;
142         char *fmt; /* format string for the arguments, NULL means a string arg */
143         int nvals; /* number of values to be read by sscanf */
144         void *vp[4]; /* pointers to values to be read */
145 };
146                 
147 static struct line header[] = {
148         { GETLEN("FONT "), 0, " %200s", 1, {&xlfdname} },
149         { GETLEN("SIZE "), MUST_SEE, " %d", 1, {&pixel_size} },
150         { GETLEN("FONTBOUNDINGBOX "), MUST_SEE, " %hd %hd %hd %hd", 4, 
151                 {&fmet.bbox[2], &fmet.bbox[3], &fmet.bbox[0], &fmet.bbox[1]} },
152         { GETLEN("FAMILY_NAME "), MUST_SEE, NULL, 1, {&fmet.name_family} },
153         { GETLEN("WEIGHT_NAME "), MUST_SEE, NULL, 1, {&fmet.name_style} },
154         { GETLEN("COPYRIGHT "), 0, NULL, 1, {&fmet.name_copyright} },
155         { GETLEN("SLANT "), MUST_SEE, NULL, 1, {&slant} },
156         { GETLEN("SPACING "), 0, NULL, 1, {&spacing} },
157         { GETLEN("SETWIDTH_NAME "), 0, NULL, 1, {&fnwidth} },
158         { GETLEN("CHARSET_REGISTRY "), 0, NULL, 1, {&charset_reg} },
159         { GETLEN("CHARSET_ENCODING "), 0, NULL, 1, {&charset_enc} },
160         { GETLEN("FONT_ASCENT "), 0, " %hd", 1, {&fmet.ascender} },
161         { GETLEN("FONT_DESCENT "), 0, " %hd", 1, {&fmet.descender} },
162
163         /* these 2 must go in this order for post-processing */
164         { GETLEN("UNDERLINE_THICKNESS "), 0, " %hd", 1, {&fmet.underline_thickness} },
165         { GETLEN("UNDERLINE_POSITION "), 0, " %hd", 1, {&fmet.underline_position} },
166
167         { GETLEN("CHARS "), MUST_SEE|IS_LAST, " %d", 1, {&nglyphs} },
168         { NULL, 0, 0 } /* end mark: name==NULL */
169 };
170
171 static int
172 handle_header(
173         int len,
174         char *str
175 )
176 {
177         struct line *cl;
178         char *s, *p;
179         int c;
180
181 #if 0
182         fprintf(stderr, "line: %s\n", str);
183 #endif
184         for(cl = header; cl->name != 0; cl++) {
185                 if(strncmp(str, cl->name, cl->namelen))
186                         continue;
187 #if 0
188                 fprintf(stderr, "match: %s\n", cl->name);
189 #endif
190                 if(cl->flags & IS_SEEN) {
191                         if(cl->flags & ALLOW_REPEAT)
192                                 continue;
193                         
194                         fprintf(stderr, "**** input line %d redefines the property %s\n", lineno, cl->name);
195                         exit(1);
196                 }
197                 cl->flags |= IS_SEEN;
198                 if(cl->fmt == 0) {
199                         s = malloc(len - cl->namelen + 1);
200                         if(s == 0) {
201                                 fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
202                                 exit(255);
203                         }
204                         *((char **)(cl->vp[0])) = s;
205
206                         /* skip until a quote */
207                         for(p = str+cl->namelen; (c = *p)!=0; p++) {
208                                 if(c == '"') {
209                                         p++;
210                                         break;
211                                 }
212                         }
213                         for(; (c = *p)!=0; p++) {
214                                 if(c == '"') {
215                                         c = *++p;
216                                         if(c == '"')
217                                                 *s++ = c;
218                                         else
219                                                 break;
220                                 } else
221                                         *s++ = c;
222                         }
223                         *s = 0; /* end of line */
224                 } else {
225                         c = sscanf(str+cl->namelen, cl->fmt, cl->vp[0], cl->vp[1], cl->vp[2], cl->vp[3]);
226                         if(c != cl->nvals) {
227                                 fprintf(stderr, "**** property %s at input line %d must have %d arguments\n", 
228                                         cl->name, lineno, cl->nvals);
229                                 exit(1);
230                         }
231                 }
232                 if(cl->flags & IS_LAST)
233                         return 1;
234                 else
235                         return 0;
236         }
237         return 0;
238 }
239
240 /*
241  * Parse the description of the glyphs
242  */
243
244 static int
245 handle_glyphs(
246         int len,
247         char *str
248 )
249 {
250         static int inbmap=0;
251         static char *bmap;
252         static int xsz, ysz, xoff, yoff;
253         static int curln;
254         int i, c;
255         char *p, *plim, *psz;
256
257         if(!LENCMP(str, "ENDFONT")) {
258                 if(curgl < nglyphs) {
259                         fprintf(stderr, "**** unexpected end of font file after %d glyphs\n", curgl);
260                         exit(1);
261                 } else
262                         return 1;
263         }
264         if(curgl >= nglyphs) {
265                 fprintf(stderr, "**** file contains more glyphs than advertised (%d)\n", nglyphs);
266                 exit(1);
267         }
268         if(!LENCMP(str, "STARTCHAR")) {
269                 /* sizeof will count \0 instead of ' ' */
270                 for(i=sizeof("STARTCHAR"); str[i] == ' '; i++) 
271                         {}
272
273                 glyphs[curgl].name = strdup(str + i);
274                 if(glyphs[curgl].name == 0) {
275                         fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
276                         exit(255);
277                 }
278         } else if(!LENCMP(str, "ENCODING")) {
279                 if(sscanf(str, "ENCODING %d", &fontenc[curgl])!=1) {
280                         fprintf(stderr,"**** weird ENCODING statement at line %d\n", lineno);
281                         exit(1);
282                 }
283                 if(fontenc[curgl] == -1)  /* compatibility format */
284                         sscanf(str, "ENCODING -1 %d", &fontenc[curgl]);
285                 if(fontenc[curgl] > maxenc)
286                         maxenc = fontenc[curgl];
287         } else if(!LENCMP(str, "DWIDTH")) {
288                 if(sscanf(str, "DWIDTH %d %d", &xsz, &ysz)!=2) {
289                         fprintf(stderr,"**** weird DWIDTH statement at line %d\n", lineno);
290                         exit(1);
291                 }
292                 glyphs[curgl].width = xsz*scale;
293         } else if(!LENCMP(str, "BBX")) {
294                 if(sscanf(str, "BBX %d %d %d %d", &xsz, &ysz, &xoff, &yoff)!=4) {
295                         fprintf(stderr,"**** weird BBX statement at line %d\n", lineno);
296                         exit(1);
297                 }
298                 bmap=malloc(xsz*ysz);
299                 if(bmap==0) {
300                         fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
301                         exit(255);
302                 }
303                 glyphs[curgl].lsb = -xoff*scale;
304                 glyphs[curgl].xMin = -xoff*scale;
305                 glyphs[curgl].xMax = (xsz-xoff)*scale;
306                 glyphs[curgl].yMin = -yoff*scale;
307                 glyphs[curgl].yMax = (ysz-xoff)*scale;
308         } else if(!LENCMP(str, "BITMAP")) {
309                 inbmap=1; 
310                 curln=ysz-1; /* the lowest line has index 0 */
311         } else if(!LENCMP(str, "ENDCHAR")) {
312                 inbmap=0;
313                 if(bmap) {
314                         glyphs[curgl].lastentry = 0;
315                         glyphs[curgl].path = 0;
316                         glyphs[curgl].entries = 0;
317                         bmp_outline(&glyphs[curgl], scale, bmap, xsz, ysz, xoff, yoff);
318                         free(bmap);
319                         /* remember in a static table or it will be erased */
320                         glpaths[curgl] = glyphs[curgl].entries;
321                         glyphs[curgl].entries = 0;
322
323                         if(glpaths[curgl])
324                                 glyphs[curgl].ttf_pathlen = 1;
325                         else
326                                 glyphs[curgl].ttf_pathlen = 0;
327                 }
328                 curgl++;
329         } else if(inbmap) {
330                 if(curln<0) {
331                         fprintf(stderr,"**** bitmap is longer than %d lines at line %d\n", ysz, lineno);
332                         exit(1);
333                 }
334
335                 i=0;
336                 p=&bmap[curln*xsz]; psz=p+xsz;
337                 while(i<len) {
338                         c=str[i++];
339                         if(!isxdigit(c)) {
340                                 fprintf(stderr,"**** non-hex digit in bitmap at line %d\n", lineno);
341                                 exit(1);
342                         }
343                         if(c<='9')
344                                 c-='0';
345                         else 
346                                 c= tolower(c)-'a'+10;
347
348                         for(plim=p+4; p<psz && p<plim; c<<=1) 
349                                 *p++ = (( c & 0x08 )!=0);
350                 }
351                 if(p<psz) {
352                         fprintf(stderr,"**** bitmap line is too short at line %d\n", lineno);
353                         exit(1);
354                 }
355                 curln--;
356         }
357         return 0;
358 }
359
360 /*
361  * Read all the possible information about the glyphs
362  */
363
364 static void
365 readglyphs(
366         GLYPH *glyph_list
367 )
368 {
369         int i;
370         GLYPH *g;
371
372         if(got_glyphs)
373                 return;
374
375         /* pass them to handle_glyphs() through statics */
376         glyphs = glyph_list;
377         curgl = 2; /* skip the empty glyph and .notdef */
378
379         /* initialize the empty glyph and .notdef */
380
381         for(i=0; i<2; i++) {
382                 g = &glyphs[i];
383                 g->lsb = 0;
384                 g->width = fmet.bbox[2];
385                 g->xMin = 0;
386                 g->yMin = 0;
387         }
388         g = &glyphs[0];
389         g->name = ".notdef";
390         g->xMax = fmet.bbox[2]*4/5;
391         g->yMax = fmet.bbox[3]*4/5;
392         g->entries = g->path = g->lastentry = 0;
393         /* make it look as a black square */
394         fg_rmoveto(g, 0.0, 0.0);
395         fg_rlineto(g, 0.0, (double)g->yMax);
396         fg_rlineto(g, (double)g->xMax, (double)g->yMax);
397         fg_rlineto(g, (double)g->xMax, 0.0);
398         fg_rlineto(g, 0.0, 0.0);
399         g_closepath(g);
400         glpaths[0] = g->entries;
401         g->entries = 0;
402         g->ttf_pathlen = 4;
403
404         g = &glyphs[1];
405         g->name = ".null";
406         g->xMax = g->yMax = 0;
407         g->ttf_pathlen = 0;
408
409         if(readfile(bdf_file, handle_glyphs) < 0) {
410                 fprintf(stderr, "**** file does not contain the ENDFONT line\n");
411                 exit(1);
412         }
413         got_glyphs = 1;
414 }
415
416 /*
417  * Open font and prepare to return information to the main driver.
418  * May print error and warning messages.
419  * Exit on error.
420  */
421
422 static void
423 openfont(
424         char *fname,
425         char *arg /* unused now */
426 )
427 {
428         struct line *cl;
429         int i, l;
430
431         if ((bdf_file = fopen(fname, "r")) == NULL) {
432                 fprintf(stderr, "**** Cannot open file '%s'\n", fname);
433                 exit(1);
434         } else {
435                 WARNING_2 fprintf(stderr, "Processing file %s\n", fname);
436         }
437
438         lineno = 1;
439
440         for(cl = header; cl->name != 0; cl++)
441                 cl->flags &= ~IS_SEEN;
442         if(readfile(bdf_file, handle_header) < 0) {
443                 fprintf(stderr, "**** file does not contain the CHARS definition\n");
444                 exit(1);
445         }
446         for(cl = header; cl->name != 0; cl++) {
447                 if( (cl->flags & MUST_SEE) && !(cl->flags & IS_SEEN) ) {
448                         fprintf(stderr, "**** mandatory property %sis not found in the input line\n", 
449                                 cl->name); /* cl->name has a space at the end */
450                         exit(1);
451                 }
452
453                 /* set a few defaults */
454                 if( !(cl->flags & IS_SEEN) ) {
455                         if(cl->vp[0] == &fmet.underline_thickness) {
456                                 fmet.underline_thickness = 1;
457                         } else if(cl->vp[0] == &fmet.underline_position) {
458                                 fmet.underline_position = fmet.bbox[1] + fmet.underline_thickness
459                                         - (pixel_size - fmet.bbox[3]);
460                         } else if(cl->vp[0] == &fmet.ascender) {
461                                 fmet.ascender = fmet.bbox[2] + fmet.bbox[0];
462                         } else if(cl->vp[0] == &fmet.descender) {
463                                 fmet.descender = fmet.bbox[0];
464                         }
465                 }
466         }
467
468         nglyphs += 2; /* add empty glyph and .notdef */
469
470         /* postprocessing to compensate for the differences in the metric formats */
471         fmet.bbox[2] += fmet.bbox[0];
472         fmet.bbox[3] += fmet.bbox[1];
473
474         scale = 1000/pixel_size; /* XXX ? */
475         if(scale*pixel_size < 950) {
476                 scale = 1;
477                 scale_external = 1;
478                 fmet.units_per_em = pixel_size;
479         } else {
480                 scale_external = 0;
481                 fmet.units_per_em = scale*pixel_size;
482
483                 fmet.underline_position *= scale;
484                 fmet.underline_thickness *= scale;
485                 fmet.ascender *= scale;
486                 fmet.descender *= scale;
487                 for(i=0; i<4; i++)
488                         fmet.bbox[i] *= scale;
489         }
490
491         fmet.italic_angle = 0.0;
492         if(spacing == 0 /* possibly an old font */ 
493         || toupper(spacing[0]) != 'P') /* or anything non-proportional */
494                 fmet.is_fixed_pitch = 1;
495         else
496                 fmet.is_fixed_pitch = 0;
497
498         if(fmet.name_copyright==NULL)
499                 fmet.name_copyright = "";
500         
501         /* create the full name */
502         l = strlen(fmet.name_family) 
503                 + (fmet.name_style? strlen(fmet.name_style) : 0)
504                 + (fnwidth? strlen(fnwidth) : 0)
505                 + strlen("Oblique") + 1;
506
507         if(( fmet.name_full = malloc(l) )==NULL) {
508                 fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
509                 exit(255);
510         }
511         strcpy(fmet.name_full, fmet.name_family);
512         if(fnwidth && strcmp(fnwidth, "Normal")) {
513                 strcat(fmet.name_full, fnwidth);
514         }
515         if(fmet.name_style && strcmp(fmet.name_style, "Medium")) {
516                 strcat(fmet.name_full, fmet.name_style);
517         }
518         switch(toupper(slant[0])) {
519         case 'O':
520                 strcat(fmet.name_full, "Oblique");
521                 break;
522         case 'I':
523                 strcat(fmet.name_full, "Italic");
524                 break;
525         }
526
527         fmet.name_ps = fmet.name_full;
528         fmet.name_version = "1.0";
529
530         if(charset_reg && charset_enc
531         && !strcmp(charset_reg, "iso10646") && !strcmp(charset_enc, "1"))
532                 is_unicode = 1;
533
534         if(( fontenc = calloc(nglyphs, sizeof *fontenc) )==NULL) {
535                 fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
536                 exit(255);
537         }
538         for(i=0; i<nglyphs; i++)
539                 fontenc[i] = -1;
540         if(( glpaths = calloc(nglyphs, sizeof *glpaths) )==NULL) {
541                 fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
542                 exit(255);
543         }
544 }
545
546 /*
547  * Close font.
548  * Exit on error.
549  */
550
551 static void
552 closefont(
553         void
554 )
555 {
556         if(fclose(bdf_file) < 0) {
557                 WARNING_1 fprintf(stderr, "Errors when closing the font file, ignored\n");
558         }
559 }
560
561 /*
562  * Get the number of glyphs in font.
563  */
564
565 static int
566 getnglyphs (
567         void
568 )
569 {
570         return nglyphs;
571 }
572
573 /*
574  * Get the names of the glyphs.
575  * Returns 0 if the names were assigned, non-zero if the font
576  * provides no glyph names.
577  */
578
579 static int
580 glnames(
581         GLYPH *glyph_list
582 )
583 {
584         readglyphs(glyph_list);
585         return 0;
586 }
587
588 /*
589  * Get the original encoding of the font. 
590  * Returns 1 for if the original encoding is Unicode, 2 if the
591  * original encoding is other 16-bit, 0 if 8-bit.
592  */
593
594 static int
595 glenc(
596         GLYPH *glyph_list,
597         int *encoding,
598         int *unimap
599 )
600 {
601         int i, douni, e;
602
603         if(is_unicode || forcemap)
604                 douni = 1;
605         else
606                 douni = 0;
607
608         for(i=0; i<nglyphs; i++) {
609                 e = fontenc[i];
610                 if(douni)
611                         e = unicode_rev_lookup(e);
612                 if(e>=0 && e<ENCTABSZ && encoding[e] == -1)
613                         encoding[e] = i;
614         }
615
616         if(is_unicode)
617                 return 1;
618         else if(maxenc > 255)
619                 return 2;
620         else
621                 return 0;
622 }
623         
624 /*
625  * Get the font metrics
626  */
627 static void 
628 fnmetrics(
629         struct font_metrics *fm
630 )
631 {
632         *fm = fmet;
633 }
634
635 /*
636  * Get the path of contrours for a glyph.
637  */
638
639 static void
640 glpath(
641         int glyphno,
642         GLYPH *glyf_list
643 )
644 {
645         readglyphs(glyf_list);
646         glyf_list[glyphno].entries = glpaths[glyphno];
647         glpaths[glyphno] = 0;
648 }
649
650 /*
651  * Get the kerning data.
652  */
653
654 static void
655 kerning(
656         GLYPH *glyph_list
657 )
658 {
659         return; /* no kerning in BDF */
660 }