2 * The font parser for the BDF files
4 * Copyright (c) 2001 by the TTF2PT1 project
5 * Copyright (c) 2001 by Sergey Babkin
7 * see COPYRIGHT for the full copyright notice
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);
30 /* front-end descriptor */
31 struct frontsw bdf_sw = {
33 /*descr*/ "BDF bitmapped fonts",
37 /*nglyphs*/ getnglyphs,
39 /*glmetrics*/ readglyphs,
41 /*fnmetrics*/ fnmetrics,
48 #define MAXLINE 10240 /* maximal line length in the input file */
50 static int lineno; /* line number */
52 #define GETLEN(s) s, (sizeof(s)-1)
53 #define LENCMP(str, txt) strncmp(str, txt, sizeof(txt)-1)
55 static FILE *bdf_file;
57 static struct font_metrics fmet;
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
65 static int pixel_size;
67 static int scale_external;
70 static char xlfdname[201];
72 static char *charset_reg;
73 static char *charset_enc;
75 static int is_unicode = 0;
77 /* tempoary storage for returning data to ttf2pt1 later on request */
78 static int maxenc = 0;
80 static GENTRY **glpaths;
82 static int got_glyphs = 0;
86 static int readfile(FILE *f, int (*strfunc)(int len, char *str));
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
97 int (*strfunc)(int len, char *str)
100 static char str[MAXLINE]; /* input line, maybe should be dynamic ? */
105 while(( c=getc(f) )!=EOF) {
109 res = strfunc(len, str);
117 } else if(len<MAXLINE-1) {
121 fprintf(stderr, "**** bdf: line %d is too long (>%d)\n", lineno, MAXLINE-1);
129 * Parse the header of the font file.
130 * Stop after the line CHARS is encountered. Ignore the unknown lines.
134 char *name; /* property name with trailing space */
135 int namelen; /* length of the name string */
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 */
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 */
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} },
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} },
167 { GETLEN("CHARS "), MUST_SEE|IS_LAST, " %d", 1, {&nglyphs} },
168 { NULL, 0, 0 } /* end mark: name==NULL */
182 fprintf(stderr, "line: %s\n", str);
184 for(cl = header; cl->name != 0; cl++) {
185 if(strncmp(str, cl->name, cl->namelen))
188 fprintf(stderr, "match: %s\n", cl->name);
190 if(cl->flags & IS_SEEN) {
191 if(cl->flags & ALLOW_REPEAT)
194 fprintf(stderr, "**** input line %d redefines the property %s\n", lineno, cl->name);
197 cl->flags |= IS_SEEN;
199 s = malloc(len - cl->namelen + 1);
201 fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
204 *((char **)(cl->vp[0])) = s;
206 /* skip until a quote */
207 for(p = str+cl->namelen; (c = *p)!=0; p++) {
213 for(; (c = *p)!=0; p++) {
223 *s = 0; /* end of line */
225 c = sscanf(str+cl->namelen, cl->fmt, cl->vp[0], cl->vp[1], cl->vp[2], cl->vp[3]);
227 fprintf(stderr, "**** property %s at input line %d must have %d arguments\n",
228 cl->name, lineno, cl->nvals);
232 if(cl->flags & IS_LAST)
241 * Parse the description of the glyphs
252 static int xsz, ysz, xoff, yoff;
255 char *p, *plim, *psz;
257 if(!LENCMP(str, "ENDFONT")) {
258 if(curgl < nglyphs) {
259 fprintf(stderr, "**** unexpected end of font file after %d glyphs\n", curgl);
264 if(curgl >= nglyphs) {
265 fprintf(stderr, "**** file contains more glyphs than advertised (%d)\n", nglyphs);
268 if(!LENCMP(str, "STARTCHAR")) {
269 /* sizeof will count \0 instead of ' ' */
270 for(i=sizeof("STARTCHAR"); str[i] == ' '; i++)
273 glyphs[curgl].name = strdup(str + i);
274 if(glyphs[curgl].name == 0) {
275 fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
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);
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);
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);
298 bmap=malloc(xsz*ysz);
300 fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
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")) {
310 curln=ysz-1; /* the lowest line has index 0 */
311 } else if(!LENCMP(str, "ENDCHAR")) {
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);
319 /* remember in a static table or it will be erased */
320 glpaths[curgl] = glyphs[curgl].entries;
321 glyphs[curgl].entries = 0;
324 glyphs[curgl].ttf_pathlen = 1;
326 glyphs[curgl].ttf_pathlen = 0;
331 fprintf(stderr,"**** bitmap is longer than %d lines at line %d\n", ysz, lineno);
336 p=&bmap[curln*xsz]; psz=p+xsz;
340 fprintf(stderr,"**** non-hex digit in bitmap at line %d\n", lineno);
346 c= tolower(c)-'a'+10;
348 for(plim=p+4; p<psz && p<plim; c<<=1)
349 *p++ = (( c & 0x08 )!=0);
352 fprintf(stderr,"**** bitmap line is too short at line %d\n", lineno);
361 * Read all the possible information about the glyphs
375 /* pass them to handle_glyphs() through statics */
377 curgl = 2; /* skip the empty glyph and .notdef */
379 /* initialize the empty glyph and .notdef */
384 g->width = fmet.bbox[2];
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);
400 glpaths[0] = g->entries;
406 g->xMax = g->yMax = 0;
409 if(readfile(bdf_file, handle_glyphs) < 0) {
410 fprintf(stderr, "**** file does not contain the ENDFONT line\n");
417 * Open font and prepare to return information to the main driver.
418 * May print error and warning messages.
425 char *arg /* unused now */
431 if ((bdf_file = fopen(fname, "rb")) == NULL) {
432 fprintf(stderr, "**** Cannot open file '%s'\n", fname);
435 WARNING_2 fprintf(stderr, "Processing file %s\n", fname);
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");
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 */
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];
468 nglyphs += 2; /* add empty glyph and .notdef */
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];
474 scale = 1000/pixel_size; /* XXX ? */
475 if(scale*pixel_size < 950) {
478 fmet.units_per_em = pixel_size;
481 fmet.units_per_em = scale*pixel_size;
483 fmet.underline_position *= scale;
484 fmet.underline_thickness *= scale;
485 fmet.ascender *= scale;
486 fmet.descender *= scale;
488 fmet.bbox[i] *= scale;
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;
496 fmet.is_fixed_pitch = 0;
498 if(fmet.name_copyright==NULL)
499 fmet.name_copyright = "";
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;
507 if(( fmet.name_full = malloc(l) )==NULL) {
508 fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
511 strcpy(fmet.name_full, fmet.name_family);
512 if(fnwidth && strcmp(fnwidth, "Normal")) {
513 strcat(fmet.name_full, fnwidth);
515 if(fmet.name_style && strcmp(fmet.name_style, "Medium")) {
516 strcat(fmet.name_full, fmet.name_style);
518 switch(toupper(slant[0])) {
520 strcat(fmet.name_full, "Oblique");
523 strcat(fmet.name_full, "Italic");
527 fmet.name_ps = fmet.name_full;
528 fmet.name_version = "1.0";
530 if(charset_reg && charset_enc
531 && !strcmp(charset_reg, "iso10646") && !strcmp(charset_enc, "1"))
534 if(( fontenc = calloc(nglyphs, sizeof *fontenc) )==NULL) {
535 fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
538 for(i=0; i<nglyphs; i++)
540 if(( glpaths = calloc(nglyphs, sizeof *glpaths) )==NULL) {
541 fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
556 if(fclose(bdf_file) < 0) {
557 WARNING_1 fprintf(stderr, "Errors when closing the font file, ignored\n");
562 * Get the number of glyphs in font.
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.
584 readglyphs(glyph_list);
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.
603 if(is_unicode || forcemap)
608 for(i=0; i<nglyphs; i++) {
611 e = unicode_rev_lookup(e);
612 if(e>=0 && e<ENCTABSZ && encoding[e] == -1)
618 else if(maxenc > 255)
625 * Get the font metrics
629 struct font_metrics *fm
636 * Get the path of contrours for a glyph.
645 readglyphs(glyf_list);
646 glyf_list[glyphno].entries = glpaths[glyphno];
647 glpaths[glyphno] = 0;
651 * Get the kerning data.
659 return; /* no kerning in BDF */