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
readfile(FILE * f,int (* strfunc)(int len,char * str))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
handle_header(int len,char * str)172 handle_header(
173 int len,
174 char *str
175 )
176 {
177 struct line *cl;
178 char *s, *p;
179 char bf[2000];
180 int c;
181
182 #if 0
183 fprintf(stderr, "line: %s\n", str);
184 #endif
185 for(cl = header; cl->name != 0; cl++) {
186 if(strncmp(str, cl->name, cl->namelen))
187 continue;
188 #if 0
189 fprintf(stderr, "match: %s\n", cl->name);
190 #endif
191 if(cl->flags & IS_SEEN) {
192 if(cl->flags & ALLOW_REPEAT)
193 continue;
194
195 fprintf(stderr, "**** input line %d redefines the property %s\n", lineno, cl->name);
196 exit(1);
197 }
198 cl->flags |= IS_SEEN;
199 if(cl->fmt == 0) {
200 if(len - cl->namelen + 1 > sizeof bf)
201 len = sizeof bf; /* cut it down */
202
203 s = bf; /* a temporary buffer to extract the value */
204
205 /* skip until a quote */
206 for(p = str+cl->namelen; len!=0 && (c = *p)!=0; p++, len--) {
207 if(c == '"') {
208 p++;
209 break;
210 }
211 }
212 for(; len!=0 && (c = *p)!=0; p++, len--) {
213 if(c == '"') {
214 c = *++p;
215 if(c == '"')
216 *s++ = c;
217 else
218 break;
219 } else
220 *s++ = c;
221 }
222 *s = 0; /* end of line */
223
224 *((char **)(cl->vp[0])) = dupcnstring(bf, s-bf);
225 } else {
226 c = sscanf(str+cl->namelen, cl->fmt, cl->vp[0], cl->vp[1], cl->vp[2], cl->vp[3]);
227 if(c != cl->nvals) {
228 fprintf(stderr, "**** property %s at input line %d must have %d arguments\n",
229 cl->name, lineno, cl->nvals);
230 exit(1);
231 }
232 }
233 if(cl->flags & IS_LAST)
234 return 1;
235 else
236 return 0;
237 }
238 return 0;
239 }
240
241 /*
242 * Parse the description of the glyphs
243 */
244
245 static int
handle_glyphs(int len,char * str)246 handle_glyphs(
247 int len,
248 char *str
249 )
250 {
251 static int inbmap=0;
252 static char *bmap;
253 static int xsz, ysz, xoff, yoff;
254 static int curln;
255 int i, c;
256 char *p, *plim, *psz;
257
258 if(!LENCMP(str, "ENDFONT")) {
259 if(curgl < nglyphs) {
260 fprintf(stderr, "**** unexpected end of font file after %d glyphs\n", curgl);
261 exit(1);
262 } else
263 return 1;
264 }
265 if(curgl >= nglyphs) {
266 fprintf(stderr, "**** file contains more glyphs than advertised (%d)\n", nglyphs);
267 exit(1);
268 }
269 if(!LENCMP(str, "STARTCHAR")) {
270 /* sizeof will count \0 instead of ' ' */
271 for(i=sizeof("STARTCHAR"); str[i] == ' '; i++)
272 {}
273
274 glyphs[curgl].name = strdup(str + i);
275 if(glyphs[curgl].name == 0) {
276 fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
277 exit(255);
278 }
279 } else if(!LENCMP(str, "ENCODING")) {
280 if(sscanf(str, "ENCODING %d", &fontenc[curgl])!=1) {
281 fprintf(stderr,"**** weird ENCODING statement at line %d\n", lineno);
282 exit(1);
283 }
284 if(fontenc[curgl] == -1) /* compatibility format */
285 sscanf(str, "ENCODING -1 %d", &fontenc[curgl]);
286 if(fontenc[curgl] > maxenc)
287 maxenc = fontenc[curgl];
288 } else if(!LENCMP(str, "DWIDTH")) {
289 if(sscanf(str, "DWIDTH %d %d", &xsz, &ysz)!=2) {
290 fprintf(stderr,"**** weird DWIDTH statement at line %d\n", lineno);
291 exit(1);
292 }
293 glyphs[curgl].width = xsz*scale;
294 } else if(!LENCMP(str, "BBX")) {
295 if(sscanf(str, "BBX %d %d %d %d", &xsz, &ysz, &xoff, &yoff)!=4) {
296 fprintf(stderr,"**** weird BBX statement at line %d\n", lineno);
297 exit(1);
298 }
299 bmap=malloc(xsz*ysz);
300 if(bmap==0) {
301 fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
302 exit(255);
303 }
304 glyphs[curgl].lsb = -xoff*scale;
305 glyphs[curgl].xMin = -xoff*scale;
306 glyphs[curgl].xMax = (xsz-xoff)*scale;
307 glyphs[curgl].yMin = -yoff*scale;
308 glyphs[curgl].yMax = (ysz-xoff)*scale;
309 } else if(!LENCMP(str, "BITMAP")) {
310 inbmap=1;
311 curln=ysz-1; /* the lowest line has index 0 */
312 } else if(!LENCMP(str, "ENDCHAR")) {
313 inbmap=0;
314 if(bmap) {
315 glyphs[curgl].lastentry = 0;
316 glyphs[curgl].path = 0;
317 glyphs[curgl].entries = 0;
318 bmp_outline(&glyphs[curgl], scale, bmap, xsz, ysz, xoff, yoff);
319 free(bmap);
320 /* remember in a static table or it will be erased */
321 glpaths[curgl] = glyphs[curgl].entries;
322 glyphs[curgl].entries = 0;
323
324 if(glpaths[curgl])
325 glyphs[curgl].ttf_pathlen = 1;
326 else
327 glyphs[curgl].ttf_pathlen = 0;
328 }
329 curgl++;
330 } else if(inbmap) {
331 if(curln<0) {
332 fprintf(stderr,"**** bitmap is longer than %d lines at line %d\n", ysz, lineno);
333 exit(1);
334 }
335
336 i=0;
337 p=&bmap[curln*xsz]; psz=p+xsz;
338 while(i<len) {
339 c=str[i++];
340 if(!isxdigit(c)) {
341 fprintf(stderr,"**** non-hex digit in bitmap at line %d\n", lineno);
342 exit(1);
343 }
344 if(c<='9')
345 c-='0';
346 else
347 c= tolower(c)-'a'+10;
348
349 for(plim=p+4; p<psz && p<plim; c<<=1)
350 *p++ = (( c & 0x08 )!=0);
351 }
352 if(p<psz) {
353 fprintf(stderr,"**** bitmap line is too short at line %d\n", lineno);
354 exit(1);
355 }
356 curln--;
357 }
358 return 0;
359 }
360
361 /*
362 * Read all the possible information about the glyphs
363 */
364
365 static void
readglyphs(GLYPH * glyph_list)366 readglyphs(
367 GLYPH *glyph_list
368 )
369 {
370 int i;
371 GLYPH *g;
372
373 if(got_glyphs)
374 return;
375
376 /* pass them to handle_glyphs() through statics */
377 glyphs = glyph_list;
378 curgl = 2; /* skip the empty glyph and .notdef */
379
380 /* initialize the empty glyph and .notdef */
381
382 for(i=0; i<2; i++) {
383 g = &glyphs[i];
384 g->lsb = 0;
385 g->width = fmet.bbox[2];
386 g->xMin = 0;
387 g->yMin = 0;
388 }
389 g = &glyphs[0];
390 g->name = ".notdef";
391 g->xMax = fmet.bbox[2]*4/5;
392 g->yMax = fmet.bbox[3]*4/5;
393 g->entries = g->path = g->lastentry = 0;
394 /* make it look as a black square */
395 fg_rmoveto(g, 0.0, 0.0);
396 fg_rlineto(g, 0.0, (double)g->yMax);
397 fg_rlineto(g, (double)g->xMax, (double)g->yMax);
398 fg_rlineto(g, (double)g->xMax, 0.0);
399 fg_rlineto(g, 0.0, 0.0);
400 g_closepath(g);
401 glpaths[0] = g->entries;
402 g->entries = 0;
403 g->ttf_pathlen = 4;
404
405 g = &glyphs[1];
406 g->name = ".null";
407 g->xMax = g->yMax = 0;
408 g->ttf_pathlen = 0;
409
410 if(readfile(bdf_file, handle_glyphs) < 0) {
411 fprintf(stderr, "**** file does not contain the ENDFONT line\n");
412 exit(1);
413 }
414 got_glyphs = 1;
415 }
416
417 /*
418 * Open font and prepare to return information to the main driver.
419 * May print error and warning messages.
420 * Exit on error.
421 */
422
423 static void
openfont(char * fname,char * arg)424 openfont(
425 char *fname,
426 char *arg /* unused now */
427 )
428 {
429 struct line *cl;
430 int i, l;
431
432 if ((bdf_file = fopen(fname, "r")) == NULL) {
433 fprintf(stderr, "**** Cannot open file '%s'\n", fname);
434 exit(1);
435 } else {
436 WARNING_2 fprintf(stderr, "Processing file %s\n", fname);
437 }
438
439 lineno = 1;
440
441 for(cl = header; cl->name != 0; cl++)
442 cl->flags &= ~IS_SEEN;
443 if(readfile(bdf_file, handle_header) < 0) {
444 fprintf(stderr, "**** file does not contain the CHARS definition\n");
445 exit(1);
446 }
447 for(cl = header; cl->name != 0; cl++) {
448 if( (cl->flags & MUST_SEE) && !(cl->flags & IS_SEEN) ) {
449 fprintf(stderr, "**** mandatory property %sis not found in the input line\n",
450 cl->name); /* cl->name has a space at the end */
451 exit(1);
452 }
453
454 /* set a few defaults */
455 if( !(cl->flags & IS_SEEN) ) {
456 if(cl->vp[0] == &fmet.underline_thickness) {
457 fmet.underline_thickness = 1;
458 } else if(cl->vp[0] == &fmet.underline_position) {
459 fmet.underline_position = fmet.bbox[1] + fmet.underline_thickness
460 - (pixel_size - fmet.bbox[3]);
461 } else if(cl->vp[0] == &fmet.ascender) {
462 fmet.ascender = fmet.bbox[2] + fmet.bbox[0];
463 } else if(cl->vp[0] == &fmet.descender) {
464 fmet.descender = fmet.bbox[0];
465 }
466 }
467 }
468
469 nglyphs += 2; /* add empty glyph and .notdef */
470
471 /* postprocessing to compensate for the differences in the metric formats */
472 fmet.bbox[2] += fmet.bbox[0];
473 fmet.bbox[3] += fmet.bbox[1];
474
475 scale = 1000/pixel_size; /* XXX ? */
476 if(scale*pixel_size < 950) {
477 scale = 1;
478 scale_external = 1;
479 fmet.units_per_em = pixel_size;
480 } else {
481 scale_external = 0;
482 fmet.units_per_em = scale*pixel_size;
483
484 fmet.underline_position *= scale;
485 fmet.underline_thickness *= scale;
486 fmet.ascender *= scale;
487 fmet.descender *= scale;
488 for(i=0; i<4; i++)
489 fmet.bbox[i] *= scale;
490 }
491
492 fmet.italic_angle = 0.0;
493 if(spacing == 0 /* possibly an old font */
494 || toupper(spacing[0]) != 'P') /* or anything non-proportional */
495 fmet.is_fixed_pitch = 1;
496 else
497 fmet.is_fixed_pitch = 0;
498
499 if(fmet.name_copyright==NULL)
500 fmet.name_copyright = "";
501
502 /* create the full name */
503 l = strlen(fmet.name_family)
504 + (fmet.name_style? strlen(fmet.name_style) : 0)
505 + (fnwidth? strlen(fnwidth) : 0)
506 + strlen("Oblique") + 1;
507
508 if(( fmet.name_full = malloc(l) )==NULL) {
509 fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
510 exit(255);
511 }
512 strcpy(fmet.name_full, fmet.name_family);
513 if(fnwidth && strcmp(fnwidth, "Normal")) {
514 strcat(fmet.name_full, fnwidth);
515 }
516 if(fmet.name_style && strcmp(fmet.name_style, "Medium")) {
517 strcat(fmet.name_full, fmet.name_style);
518 }
519 switch(toupper(slant[0])) {
520 case 'O':
521 strcat(fmet.name_full, "Oblique");
522 break;
523 case 'I':
524 strcat(fmet.name_full, "Italic");
525 break;
526 }
527
528 fmet.name_ps = fmet.name_full;
529 fmet.name_version = "1.0";
530
531 if(charset_reg && charset_enc
532 && !strcmp(charset_reg, "iso10646") && !strcmp(charset_enc, "1"))
533 is_unicode = 1;
534
535 if(( fontenc = calloc(nglyphs, sizeof *fontenc) )==NULL) {
536 fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
537 exit(255);
538 }
539 for(i=0; i<nglyphs; i++)
540 fontenc[i] = -1;
541 if(( glpaths = calloc(nglyphs, sizeof *glpaths) )==NULL) {
542 fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
543 exit(255);
544 }
545 }
546
547 /*
548 * Close font.
549 * Exit on error.
550 */
551
552 static void
closefont(void)553 closefont(
554 void
555 )
556 {
557 if(fclose(bdf_file) < 0) {
558 WARNING_1 fprintf(stderr, "Errors when closing the font file, ignored\n");
559 }
560 }
561
562 /*
563 * Get the number of glyphs in font.
564 */
565
566 static int
getnglyphs(void)567 getnglyphs (
568 void
569 )
570 {
571 return nglyphs;
572 }
573
574 /*
575 * Get the names of the glyphs.
576 * Returns 0 if the names were assigned, non-zero if the font
577 * provides no glyph names.
578 */
579
580 static int
glnames(GLYPH * glyph_list)581 glnames(
582 GLYPH *glyph_list
583 )
584 {
585 readglyphs(glyph_list);
586 return 0;
587 }
588
589 /*
590 * Get the original encoding of the font.
591 * Returns 1 for if the original encoding is Unicode, 2 if the
592 * original encoding is other 16-bit, 0 if 8-bit.
593 */
594
595 static int
glenc(GLYPH * glyph_list,int * encoding,int * unimap)596 glenc(
597 GLYPH *glyph_list,
598 int *encoding,
599 int *unimap
600 )
601 {
602 int i, douni, e;
603
604 if(is_unicode || forcemap)
605 douni = 1;
606 else
607 douni = 0;
608
609 for(i=0; i<nglyphs; i++) {
610 e = fontenc[i];
611 if(douni)
612 e = unicode_rev_lookup(e);
613 if(e>=0 && e<ENCTABSZ && encoding[e] == -1)
614 encoding[e] = i;
615 }
616
617 if(is_unicode)
618 return 1;
619 else if(maxenc > 255)
620 return 2;
621 else
622 return 0;
623 }
624
625 /*
626 * Get the font metrics
627 */
628 static void
fnmetrics(struct font_metrics * fm)629 fnmetrics(
630 struct font_metrics *fm
631 )
632 {
633 *fm = fmet;
634 }
635
636 /*
637 * Get the path of contrours for a glyph.
638 */
639
640 static void
glpath(int glyphno,GLYPH * glyf_list)641 glpath(
642 int glyphno,
643 GLYPH *glyf_list
644 )
645 {
646 readglyphs(glyf_list);
647 glyf_list[glyphno].entries = glpaths[glyphno];
648 glpaths[glyphno] = 0;
649 }
650
651 /*
652 * Get the kerning data.
653 */
654
655 static void
kerning(GLYPH * glyph_list)656 kerning(
657 GLYPH *glyph_list
658 )
659 {
660 return; /* no kerning in BDF */
661 }
662