aboutsummaryrefslogtreecommitdiff
path: root/nx-X11/extras/ttf2pt1/bdf.c
diff options
context:
space:
mode:
Diffstat (limited to 'nx-X11/extras/ttf2pt1/bdf.c')
-rw-r--r--nx-X11/extras/ttf2pt1/bdf.c660
1 files changed, 660 insertions, 0 deletions
diff --git a/nx-X11/extras/ttf2pt1/bdf.c b/nx-X11/extras/ttf2pt1/bdf.c
new file mode 100644
index 000000000..9f6c72720
--- /dev/null
+++ b/nx-X11/extras/ttf2pt1/bdf.c
@@ -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 */
+}