/*
 *	This file is based on Beebe's driver program.
 */

#include	"defs.h"
#include	"global.h"
#include	"rastfont.h"
#include	"gffont.h"
#ifdef KPATHSEA
#undef STREQ
#include	<kpathsea/config.h>
#include	<kpathsea/tex-file.h>
#endif

int gftype_access();
void init_gf_fontinfo();
struct fontop gfop = {
    "gf",
    pathtype_init,
    gftype_access,
    init_gf_fontinfo,
};

static FILE *fntfp;
void loadgfchar();

gftype_access(proto, fe, acca)
char *proto;
struct font_entry *fe;
struct accarg *acca;
{
    char *filename;
    BOOLEAN ok;

    rast_mag(fe, acca, 1);
#ifdef KPATHSEA
    if (ok = ((filename = kpsearch_glyph(proto, fe->n, kpse_gf_format,
					 acca, fe->name)) != NULL))
	strcpy(fe->name, filename);
#else
    pave(fe->name, proto, acca);
    ok = access(fe->name, R_OK) == 0;
#endif
#ifdef DEBUG
    rast_debug_report(fe, acca, ok, "gf");
#endif
    return ok;
}

void
init_gf_fontinfo(fe)
struct font_entry *fe;
{
    void read_gf_fontinfo();

    fe->fnt_readfontinfo = read_gf_fontinfo;
    init_rast_fontinfo(fe);
}

void
read_gf_fontinfo(fe)
struct font_entry *fe;
{
    int t, i;
    struct rastchar_entry *ce;
    struct rastinitfontinfo *rii;
    struct rastfntinfo *rfi;
    int ds;
    long possave;

    openfontfile(fe);
    fntfp = fe->openfile;
    (void)fseek(fntfp, -4L, SEEK_END);
    while ((t = getuint(fntfp, 1)) == GF_FILLER)
	(void)fseek(fntfp, -2L, SEEK_CUR);
    if (t != GF_ID)
	Fatal("GF ID = %d, can only process GF ID = %d files",
	      t, GF_ID);
    (void)fseek(fntfp, -6L, SEEK_CUR);
    if ((t = getuint(fntfp, 1)) != GF_POSTPOST)
	Fatal("GF PostPost = %d, can only process GF PostPost = %d files",
	      t, GF_POSTPOST);
    (void)fseek(fntfp, (long)getuint(fntfp, 4), SEEK_SET);
    if ((t = getuint(fntfp, 1)) != GF_POST)
	Fatal("GF Post = %d, can only process GF Post = %d files",
	      t, GF_POST);
    (void)fseek(fntfp, 4L, SEEK_CUR);
    ds = getuint(fntfp, 4);
    t = getuint(fntfp, 4);
    if ((fe->c != 0) && (t != 0) && (fe->c != t))
	Warning("font = \"%s\",\n-->font checksum = %d,\n-->dvi checksum = %d",
		fe->name, fe->c, t);
    t = getuint(fntfp, 4);
    (void)fseek(fntfp, 20L, SEEK_CUR);

    rii = rastinifinfo(fe);
    rastfinfo(fe) = rfi = alloc_rastfinfo(rii->maxc+1, TRUE, rii);
    dev_rast_initfe(fe);
    /* rfi->designsize = ds; */
    /* rfi->magnification = (0.5 + 5.0 * 72.27 * (float)t) / 65536.0; */
    rfi->nfntchars = rii->maxc + 1;
    while (((t = getuint(fntfp, 1)) == GF_CHAR_LOC) || 
	   (t == GF_CHAR_LOC0)) {
	i = getuint(fntfp, 1);
	if (rii->mark[i] == FALSE) {
	    if (t==GF_CHAR_LOC)
		(void)fseek(fntfp, 16L, SEEK_CUR);
	    else
		(void)fseek(fntfp, 9L, SEEK_CUR);
	} else {
	    ce = &(rfi->ch[i]);
	    if (t == GF_CHAR_LOC) 
		(void)fseek(fntfp, 8L, SEEK_CUR);
	    else
		(void)fseek(fntfp, 1L, SEEK_CUR);
	    ce->tfmw = scale(getuint(fntfp, 4), fe->s);
	    ce->where.fileoffset = getuint(fntfp, 4);
	    possave = ftell(fntfp);
	    loadgfchar(fe, i);
	    dev_rast_initfontdict(fe, i);
	    (void)fseek(fntfp, possave, SEEK_SET);
	}
    }
    if (t != GF_POSTPOST)
	Fatal("There is %d between Post Charloc and PostPost", t);

    free((char *)rii);
}

#define		WHITE		0
#define		BLACK		1
#define		SETBIT(x,y)	pixel[y+(x>>3)] |= 0x80>>(x&7)
#define		INVERT(x)	x = 1-x

void
loadgfchar(fe, c)
struct font_entry *fe;
int c;
{
    char *pixel;
    int i, j, k, t;
    int min_m, max_m, del_m, min_n, max_n, del_n;
    int paint, length;
    struct rastchar_entry *ce;

    ce = &(rastfinfo(fe)->ch[c]);
    (void)fseek(fntfp, (long)(ce->where.fileoffset), SEEK_SET);

    for (; t = getuint(fntfp, 1); ) {
	if (GF_XXX1 <= t && t <= GF_XXX4)
	    (void)fseek(fntfp, (long)getint(fntfp, t - GF_XXX1 + 1), SEEK_CUR);
	else if (t == GF_YYY)
	    (void)fseek(fntfp, 4L, SEEK_CUR);
	else if (t == GF_NOP)
	    ;
	else
	    break;
    }
    if (t == GF_BOC) {
	if (getuint(fntfp, 4) != c)
	    Fatal("Postamble %d points glyph %d", c, t);
	(void)fseek(fntfp, 4L, SEEK_CUR);
	min_m = getint(fntfp, 4);
	max_m = getint(fntfp, 4);
	min_n = getint(fntfp, 4);
	max_n = getint(fntfp, 4);
	del_m = max_m - min_m;
	del_n = max_n - min_n;
    } else if (t == GF_BOC1) {
	if (getuint(fntfp, 1) != c)
	    Fatal("Postamble %d points glyph %d", c, t);
	del_m = getuint(fntfp, 1);
	max_m = getuint(fntfp, 1);
	del_n = getuint(fntfp, 1);
	max_n = getuint(fntfp, 1);
	min_m = max_m - del_m;
    } else
	Fatal("%d should be GF BOC or GF BOC1", t);

    ce->width = del_m;
    ce->height = del_n + 1;
    ce->xoffset = -min_m;
    ce->yoffset = max_n;
    ce->nbpl = ((unsigned short)(ce->width + 31) >> 5) * 4;
    if ((pixel = (char *)malloc(ce->nbpl * ce->height)) == NULL)
	Fatal("Unable to allocate memory for char");

    for (i = 0; i < (int)ce->height; i++)
	for (j = 0; j < (int)ce->nbpl; j++)
	    pixel[j+i*ce->nbpl] = 0;

    ce->where.pixptr = pixel;
    i = j = 0;
    paint = WHITE;

    while ((t = getuint(fntfp, 1)) != GF_EOC) {
	switch (t) {
	case GF_PAINT_0 :
	    INVERT(paint);
	    break;
	case GF_PAINT1 : case GF_PAINT2 : case GF_PAINT3 :
	    length = getuint(fntfp, t - GF_PAINT1 + 1);
	    if (paint == BLACK)
		for (k = 0; k < length; i++, k++)
		    SETBIT(i, j);
	    else
		i += length;
	    INVERT(paint);
	    break;
	case GF_SKIP0 :
	    j += ce->nbpl;
	    i = 0;
	    paint = WHITE;
	    break;
	case GF_SKIP1 : case GF_SKIP2 : case GF_SKIP3 :
	    j += ce->nbpl * (getuint(fntfp, t - GF_SKIP0) + 1);
	    i = 0;
	    paint = WHITE;
	    break;
	case GF_XXX1 : case GF_XXX2 : case GF_XXX3 : case GF_XXX4 :
	    (void)fseek(fntfp, (long)getint(fntfp, t - GF_XXX1 + 1), SEEK_CUR);
	    break;
	case GF_YYY :
	    (void)fseek(fntfp, 4L, SEEK_CUR);
	    break;
	case GF_NOP :
	    break;
	default :
	    if ((GF_PAINT_0 < t) && (t < GF_PAINT1)) {
		length = t - GF_PAINT_0;
		if (paint == BLACK)
		    for (k = 0; k < length; i++, k++)
			SETBIT(i,j);
		else
		    i += length;
		INVERT(paint);
	    } else if ((GF_NEW_ROW_0 <= t) && (t <= GF_NEW_ROW_MAX)) {
		j += ce->nbpl;
		paint = BLACK;
		i = t - GF_NEW_ROW_0;
	    } else {
		(void)fprintf(stderr, "GF invalid %d command in %s.\n",
			      t, fe->name);
		(void)fseek(fntfp, -20L, SEEK_CUR);
		for (k = 0; k < 20; k++)
		    (void)fprintf(stderr, "%3d ", getuint(fntfp, 1));
		(void)fprintf(stderr, "\n");
		for (k = 0; k < 20; k++)
		    (void)fprintf(stderr, "%3d ", getuint(fntfp, 1));
		(void)fprintf(stderr, "\n");
	    }
	    break;
	}
    }
}
