upgraded ttf2pt1 to 3.4.3.
[swftools.git] / pdf2swf / ttf2pt1 / bdf.c
diff --git a/pdf2swf/ttf2pt1/bdf.c b/pdf2swf/ttf2pt1/bdf.c
new file mode 100644 (file)
index 0000000..9f6c727
--- /dev/null
@@ -0,0 +1,660 @@
+/*
+ * The font parser for the BDF files
+ *
+ * Copyright (c) 2001 by the TTF2PT1 project
+ * Copyright (c) 2001 by Sergey Babkin
+ *
+ * see COPYRIGHT for the full copyright notice
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include "pt1.h"
+#include "global.h"
+
+/* prototypes of call entries */
+static void openfont(char *fname, char *arg);
+static void closefont( void);
+static int getnglyphs ( void);
+static int glnames( GLYPH *glyph_list);
+static void readglyphs( GLYPH *glyph_list);
+static int glenc( GLYPH *glyph_list, int *encoding, int *unimap);
+static void fnmetrics( struct font_metrics *fm);
+static void glpath( int glyphno, GLYPH *glyph_list);
+static void kerning( GLYPH *glyph_list);
+
+/* globals */
+
+/* front-end descriptor */
+struct frontsw bdf_sw = {
+       /*name*/       "bdf",
+       /*descr*/      "BDF bitmapped fonts",
+       /*suffix*/     { "bdf" },
+       /*open*/       openfont,
+       /*close*/      closefont,
+       /*nglyphs*/    getnglyphs,
+       /*glnames*/    glnames,
+       /*glmetrics*/  readglyphs,
+       /*glenc*/      glenc,
+       /*fnmetrics*/  fnmetrics,
+       /*glpath*/     glpath,
+       /*kerning*/    kerning,
+};
+
+/* statics */
+
+#define MAXLINE        10240 /* maximal line length in the input file */
+
+static int lineno; /* line number */
+
+#define GETLEN(s)      s, (sizeof(s)-1)
+#define LENCMP(str, txt)       strncmp(str, txt, sizeof(txt)-1)
+
+static FILE *bdf_file;
+static int nglyphs;
+static struct font_metrics fmet;
+
+/* many BDF fonts are of small pixel size, so we better try
+ * to scale them by an integer to keep the dimensions in
+ * whole pixels. However if the size is too big and a non-
+ * integer scaling is needed, we use the standard ttf2pt1's
+ * scaling abilities.
+ */
+static int pixel_size;
+static int scale;
+static int scale_external;
+
+static char *slant;
+static char xlfdname[201];
+static char *spacing;
+static char *charset_reg;
+static char *charset_enc;
+static char *fnwidth;
+static int is_unicode = 0;
+
+/* tempoary storage for returning data to ttf2pt1 later on request */
+static int maxenc = 0;
+static int *fontenc;
+static GENTRY **glpaths;
+
+static int got_glyphs = 0;
+static GLYPH *glyphs;
+static int curgl;
+
+static int readfile(FILE *f, int (*strfunc)(int len, char *str));
+
+/*
+ * Read the file and parse each string with strfunc(),
+ * until strfunc() returns !=0 or the end of file happens.
+ * Returns -1 on EOF or strfunc() returning <0, else 0
+ */
+
+static int
+readfile(
+       FILE *f,
+       int (*strfunc)(int len, char *str)
+)
+{
+       static char str[MAXLINE]; /* input line, maybe should be dynamic ? */
+       char *s;
+       int len, c, res;
+
+       len=0;
+       while(( c=getc(f) )!=EOF) {
+               if(c=='\n') {
+                       str[len]=0;
+
+                       res = strfunc(len, str);
+                       lineno++;
+                       if(res<0)
+                               return -1;
+                       else if(res!=0)
+                               return 0;
+
+                       len=0;
+               } else if(len<MAXLINE-1) {
+                       if(c!='\r')
+                               str[len++]=c;
+               } else {
+                       fprintf(stderr, "**** bdf: line %d is too long (>%d)\n", lineno, MAXLINE-1);
+                       exit(1);
+               }
+       }
+       return -1; /* EOF */
+}
+
+/*
+ * Parse the header of the font file. 
+ * Stop after the line CHARS is encountered. Ignore the unknown lines.
+ */
+
+struct line {
+       char *name; /* property name with trailing space */
+       int namelen; /* length of the name string */
+       enum {
+               ALLOW_REPEAT = 0x01, /* this property may be repeated in multiple lines */
+               IS_SEEN = 0x02, /* this property has been seen already */
+               MUST_SEE = 0x04, /* this property must be seen */
+               IS_LAST = 0x08 /* this is the last property to be read */
+       } flags;
+       char *fmt; /* format string for the arguments, NULL means a string arg */
+       int nvals; /* number of values to be read by sscanf */
+       void *vp[4]; /* pointers to values to be read */
+};
+               
+static struct line header[] = {
+       { GETLEN("FONT "), 0, " %200s", 1, {&xlfdname} },
+       { GETLEN("SIZE "), MUST_SEE, " %d", 1, {&pixel_size} },
+       { GETLEN("FONTBOUNDINGBOX "), MUST_SEE, " %hd %hd %hd %hd", 4, 
+               {&fmet.bbox[2], &fmet.bbox[3], &fmet.bbox[0], &fmet.bbox[1]} },
+       { GETLEN("FAMILY_NAME "), MUST_SEE, NULL, 1, {&fmet.name_family} },
+       { GETLEN("WEIGHT_NAME "), MUST_SEE, NULL, 1, {&fmet.name_style} },
+       { GETLEN("COPYRIGHT "), 0, NULL, 1, {&fmet.name_copyright} },
+       { GETLEN("SLANT "), MUST_SEE, NULL, 1, {&slant} },
+       { GETLEN("SPACING "), 0, NULL, 1, {&spacing} },
+       { GETLEN("SETWIDTH_NAME "), 0, NULL, 1, {&fnwidth} },
+       { GETLEN("CHARSET_REGISTRY "), 0, NULL, 1, {&charset_reg} },
+       { GETLEN("CHARSET_ENCODING "), 0, NULL, 1, {&charset_enc} },
+       { GETLEN("FONT_ASCENT "), 0, " %hd", 1, {&fmet.ascender} },
+       { GETLEN("FONT_DESCENT "), 0, " %hd", 1, {&fmet.descender} },
+
+       /* these 2 must go in this order for post-processing */
+       { GETLEN("UNDERLINE_THICKNESS "), 0, " %hd", 1, {&fmet.underline_thickness} },
+       { GETLEN("UNDERLINE_POSITION "), 0, " %hd", 1, {&fmet.underline_position} },
+
+       { GETLEN("CHARS "), MUST_SEE|IS_LAST, " %d", 1, {&nglyphs} },
+       { NULL, 0, 0 } /* end mark: name==NULL */
+};
+
+static int
+handle_header(
+       int len,
+       char *str
+)
+{
+       struct line *cl;
+       char *s, *p;
+       int c;
+
+#if 0
+       fprintf(stderr, "line: %s\n", str);
+#endif
+       for(cl = header; cl->name != 0; cl++) {
+               if(strncmp(str, cl->name, cl->namelen))
+                       continue;
+#if 0
+               fprintf(stderr, "match: %s\n", cl->name);
+#endif
+               if(cl->flags & IS_SEEN) {
+                       if(cl->flags & ALLOW_REPEAT)
+                               continue;
+                       
+                       fprintf(stderr, "**** input line %d redefines the property %s\n", lineno, cl->name);
+                       exit(1);
+               }
+               cl->flags |= IS_SEEN;
+               if(cl->fmt == 0) {
+                       s = malloc(len - cl->namelen + 1);
+                       if(s == 0) {
+                               fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
+                               exit(255);
+                       }
+                       *((char **)(cl->vp[0])) = s;
+
+                       /* skip until a quote */
+                       for(p = str+cl->namelen; (c = *p)!=0; p++) {
+                               if(c == '"') {
+                                       p++;
+                                       break;
+                               }
+                       }
+                       for(; (c = *p)!=0; p++) {
+                               if(c == '"') {
+                                       c = *++p;
+                                       if(c == '"')
+                                               *s++ = c;
+                                       else
+                                               break;
+                               } else
+                                       *s++ = c;
+                       }
+                       *s = 0; /* end of line */
+               } else {
+                       c = sscanf(str+cl->namelen, cl->fmt, cl->vp[0], cl->vp[1], cl->vp[2], cl->vp[3]);
+                       if(c != cl->nvals) {
+                               fprintf(stderr, "**** property %s at input line %d must have %d arguments\n", 
+                                       cl->name, lineno, cl->nvals);
+                               exit(1);
+                       }
+               }
+               if(cl->flags & IS_LAST)
+                       return 1;
+               else
+                       return 0;
+       }
+       return 0;
+}
+
+/*
+ * Parse the description of the glyphs
+ */
+
+static int
+handle_glyphs(
+       int len,
+       char *str
+)
+{
+       static int inbmap=0;
+       static char *bmap;
+       static int xsz, ysz, xoff, yoff;
+       static int curln;
+       int i, c;
+       char *p, *plim, *psz;
+
+       if(!LENCMP(str, "ENDFONT")) {
+               if(curgl < nglyphs) {
+                       fprintf(stderr, "**** unexpected end of font file after %d glyphs\n", curgl);
+                       exit(1);
+               } else
+                       return 1;
+       }
+       if(curgl >= nglyphs) {
+               fprintf(stderr, "**** file contains more glyphs than advertised (%d)\n", nglyphs);
+               exit(1);
+       }
+       if(!LENCMP(str, "STARTCHAR")) {
+               /* sizeof will count \0 instead of ' ' */
+               for(i=sizeof("STARTCHAR"); str[i] == ' '; i++) 
+                       {}
+
+               glyphs[curgl].name = strdup(str + i);
+               if(glyphs[curgl].name == 0) {
+                       fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
+                       exit(255);
+               }
+       } else if(!LENCMP(str, "ENCODING")) {
+               if(sscanf(str, "ENCODING %d", &fontenc[curgl])!=1) {
+                       fprintf(stderr,"**** weird ENCODING statement at line %d\n", lineno);
+                       exit(1);
+               }
+               if(fontenc[curgl] == -1)  /* compatibility format */
+                       sscanf(str, "ENCODING -1 %d", &fontenc[curgl]);
+               if(fontenc[curgl] > maxenc)
+                       maxenc = fontenc[curgl];
+       } else if(!LENCMP(str, "DWIDTH")) {
+               if(sscanf(str, "DWIDTH %d %d", &xsz, &ysz)!=2) {
+                       fprintf(stderr,"**** weird DWIDTH statement at line %d\n", lineno);
+                       exit(1);
+               }
+               glyphs[curgl].width = xsz*scale;
+       } else if(!LENCMP(str, "BBX")) {
+               if(sscanf(str, "BBX %d %d %d %d", &xsz, &ysz, &xoff, &yoff)!=4) {
+                       fprintf(stderr,"**** weird BBX statement at line %d\n", lineno);
+                       exit(1);
+               }
+               bmap=malloc(xsz*ysz);
+               if(bmap==0) {
+                       fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
+                       exit(255);
+               }
+               glyphs[curgl].lsb = -xoff*scale;
+               glyphs[curgl].xMin = -xoff*scale;
+               glyphs[curgl].xMax = (xsz-xoff)*scale;
+               glyphs[curgl].yMin = -yoff*scale;
+               glyphs[curgl].yMax = (ysz-xoff)*scale;
+       } else if(!LENCMP(str, "BITMAP")) {
+               inbmap=1; 
+               curln=ysz-1; /* the lowest line has index 0 */
+       } else if(!LENCMP(str, "ENDCHAR")) {
+               inbmap=0;
+               if(bmap) {
+                       glyphs[curgl].lastentry = 0;
+                       glyphs[curgl].path = 0;
+                       glyphs[curgl].entries = 0;
+                       bmp_outline(&glyphs[curgl], scale, bmap, xsz, ysz, xoff, yoff);
+                       free(bmap);
+                       /* remember in a static table or it will be erased */
+                       glpaths[curgl] = glyphs[curgl].entries;
+                       glyphs[curgl].entries = 0;
+
+                       if(glpaths[curgl])
+                               glyphs[curgl].ttf_pathlen = 1;
+                       else
+                               glyphs[curgl].ttf_pathlen = 0;
+               }
+               curgl++;
+       } else if(inbmap) {
+               if(curln<0) {
+                       fprintf(stderr,"**** bitmap is longer than %d lines at line %d\n", ysz, lineno);
+                       exit(1);
+               }
+
+               i=0;
+               p=&bmap[curln*xsz]; psz=p+xsz;
+               while(i<len) {
+                       c=str[i++];
+                       if(!isxdigit(c)) {
+                               fprintf(stderr,"**** non-hex digit in bitmap at line %d\n", lineno);
+                               exit(1);
+                       }
+                       if(c<='9')
+                               c-='0';
+                       else 
+                               c= tolower(c)-'a'+10;
+
+                       for(plim=p+4; p<psz && p<plim; c<<=1) 
+                               *p++ = (( c & 0x08 )!=0);
+               }
+               if(p<psz) {
+                       fprintf(stderr,"**** bitmap line is too short at line %d\n", lineno);
+                       exit(1);
+               }
+               curln--;
+       }
+       return 0;
+}
+
+/*
+ * Read all the possible information about the glyphs
+ */
+
+static void
+readglyphs(
+       GLYPH *glyph_list
+)
+{
+       int i;
+       GLYPH *g;
+
+       if(got_glyphs)
+               return;
+
+       /* pass them to handle_glyphs() through statics */
+       glyphs = glyph_list;
+       curgl = 2; /* skip the empty glyph and .notdef */
+
+       /* initialize the empty glyph and .notdef */
+
+       for(i=0; i<2; i++) {
+               g = &glyphs[i];
+               g->lsb = 0;
+               g->width = fmet.bbox[2];
+               g->xMin = 0;
+               g->yMin = 0;
+       }
+       g = &glyphs[0];
+       g->name = ".notdef";
+       g->xMax = fmet.bbox[2]*4/5;
+       g->yMax = fmet.bbox[3]*4/5;
+       g->entries = g->path = g->lastentry = 0;
+       /* make it look as a black square */
+       fg_rmoveto(g, 0.0, 0.0);
+       fg_rlineto(g, 0.0, (double)g->yMax);
+       fg_rlineto(g, (double)g->xMax, (double)g->yMax);
+       fg_rlineto(g, (double)g->xMax, 0.0);
+       fg_rlineto(g, 0.0, 0.0);
+       g_closepath(g);
+       glpaths[0] = g->entries;
+       g->entries = 0;
+       g->ttf_pathlen = 4;
+
+       g = &glyphs[1];
+       g->name = ".null";
+       g->xMax = g->yMax = 0;
+       g->ttf_pathlen = 0;
+
+       if(readfile(bdf_file, handle_glyphs) < 0) {
+               fprintf(stderr, "**** file does not contain the ENDFONT line\n");
+               exit(1);
+       }
+       got_glyphs = 1;
+}
+
+/*
+ * Open font and prepare to return information to the main driver.
+ * May print error and warning messages.
+ * Exit on error.
+ */
+
+static void
+openfont(
+       char *fname,
+       char *arg /* unused now */
+)
+{
+       struct line *cl;
+       int i, l;
+
+       if ((bdf_file = fopen(fname, "r")) == NULL) {
+               fprintf(stderr, "**** Cannot open file '%s'\n", fname);
+               exit(1);
+       } else {
+               WARNING_2 fprintf(stderr, "Processing file %s\n", fname);
+       }
+
+       lineno = 1;
+
+       for(cl = header; cl->name != 0; cl++)
+               cl->flags &= ~IS_SEEN;
+       if(readfile(bdf_file, handle_header) < 0) {
+               fprintf(stderr, "**** file does not contain the CHARS definition\n");
+               exit(1);
+       }
+       for(cl = header; cl->name != 0; cl++) {
+               if( (cl->flags & MUST_SEE) && !(cl->flags & IS_SEEN) ) {
+                       fprintf(stderr, "**** mandatory property %sis not found in the input line\n", 
+                               cl->name); /* cl->name has a space at the end */
+                       exit(1);
+               }
+
+               /* set a few defaults */
+               if( !(cl->flags & IS_SEEN) ) {
+                       if(cl->vp[0] == &fmet.underline_thickness) {
+                               fmet.underline_thickness = 1;
+                       } else if(cl->vp[0] == &fmet.underline_position) {
+                               fmet.underline_position = fmet.bbox[1] + fmet.underline_thickness
+                                       - (pixel_size - fmet.bbox[3]);
+                       } else if(cl->vp[0] == &fmet.ascender) {
+                               fmet.ascender = fmet.bbox[2] + fmet.bbox[0];
+                       } else if(cl->vp[0] == &fmet.descender) {
+                               fmet.descender = fmet.bbox[0];
+                       }
+               }
+       }
+
+       nglyphs += 2; /* add empty glyph and .notdef */
+
+       /* postprocessing to compensate for the differences in the metric formats */
+       fmet.bbox[2] += fmet.bbox[0];
+       fmet.bbox[3] += fmet.bbox[1];
+
+       scale = 1000/pixel_size; /* XXX ? */
+       if(scale*pixel_size < 950) {
+               scale = 1;
+               scale_external = 1;
+               fmet.units_per_em = pixel_size;
+       } else {
+               scale_external = 0;
+               fmet.units_per_em = scale*pixel_size;
+
+               fmet.underline_position *= scale;
+               fmet.underline_thickness *= scale;
+               fmet.ascender *= scale;
+               fmet.descender *= scale;
+               for(i=0; i<4; i++)
+                       fmet.bbox[i] *= scale;
+       }
+
+       fmet.italic_angle = 0.0;
+       if(spacing == 0 /* possibly an old font */ 
+       || toupper(spacing[0]) != 'P') /* or anything non-proportional */
+               fmet.is_fixed_pitch = 1;
+       else
+               fmet.is_fixed_pitch = 0;
+
+       if(fmet.name_copyright==NULL)
+               fmet.name_copyright = "";
+       
+       /* create the full name */
+       l = strlen(fmet.name_family) 
+               + (fmet.name_style? strlen(fmet.name_style) : 0)
+               + (fnwidth? strlen(fnwidth) : 0)
+               + strlen("Oblique") + 1;
+
+       if(( fmet.name_full = malloc(l) )==NULL) {
+               fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
+               exit(255);
+       }
+       strcpy(fmet.name_full, fmet.name_family);
+       if(fnwidth && strcmp(fnwidth, "Normal")) {
+               strcat(fmet.name_full, fnwidth);
+       }
+       if(fmet.name_style && strcmp(fmet.name_style, "Medium")) {
+               strcat(fmet.name_full, fmet.name_style);
+       }
+       switch(toupper(slant[0])) {
+       case 'O':
+               strcat(fmet.name_full, "Oblique");
+               break;
+       case 'I':
+               strcat(fmet.name_full, "Italic");
+               break;
+       }
+
+       fmet.name_ps = fmet.name_full;
+       fmet.name_version = "1.0";
+
+       if(charset_reg && charset_enc
+       && !strcmp(charset_reg, "iso10646") && !strcmp(charset_enc, "1"))
+               is_unicode = 1;
+
+       if(( fontenc = calloc(nglyphs, sizeof *fontenc) )==NULL) {
+               fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
+               exit(255);
+       }
+       for(i=0; i<nglyphs; i++)
+               fontenc[i] = -1;
+       if(( glpaths = calloc(nglyphs, sizeof *glpaths) )==NULL) {
+               fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
+               exit(255);
+       }
+}
+
+/*
+ * Close font.
+ * Exit on error.
+ */
+
+static void
+closefont(
+       void
+)
+{
+       if(fclose(bdf_file) < 0) {
+               WARNING_1 fprintf(stderr, "Errors when closing the font file, ignored\n");
+       }
+}
+
+/*
+ * Get the number of glyphs in font.
+ */
+
+static int
+getnglyphs (
+       void
+)
+{
+       return nglyphs;
+}
+
+/*
+ * Get the names of the glyphs.
+ * Returns 0 if the names were assigned, non-zero if the font
+ * provides no glyph names.
+ */
+
+static int
+glnames(
+       GLYPH *glyph_list
+)
+{
+       readglyphs(glyph_list);
+       return 0;
+}
+
+/*
+ * Get the original encoding of the font. 
+ * Returns 1 for if the original encoding is Unicode, 2 if the
+ * original encoding is other 16-bit, 0 if 8-bit.
+ */
+
+static int
+glenc(
+       GLYPH *glyph_list,
+       int *encoding,
+       int *unimap
+)
+{
+       int i, douni, e;
+
+       if(is_unicode || forcemap)
+               douni = 1;
+       else
+               douni = 0;
+
+       for(i=0; i<nglyphs; i++) {
+               e = fontenc[i];
+               if(douni)
+                       e = unicode_rev_lookup(e);
+               if(e>=0 && e<ENCTABSZ && encoding[e] == -1)
+                       encoding[e] = i;
+       }
+
+       if(is_unicode)
+               return 1;
+       else if(maxenc > 255)
+               return 2;
+       else
+               return 0;
+}
+       
+/*
+ * Get the font metrics
+ */
+static void 
+fnmetrics(
+       struct font_metrics *fm
+)
+{
+       *fm = fmet;
+}
+
+/*
+ * Get the path of contrours for a glyph.
+ */
+
+static void
+glpath(
+       int glyphno,
+       GLYPH *glyf_list
+)
+{
+       readglyphs(glyf_list);
+       glyf_list[glyphno].entries = glpaths[glyphno];
+       glpaths[glyphno] = 0;
+}
+
+/*
+ * Get the kerning data.
+ */
+
+static void
+kerning(
+       GLYPH *glyph_list
+)
+{
+       return; /* no kerning in BDF */
+}