/* Copyright Per Bothner 1987. Read the file Q-INFO */
/* ReadGenericFont(font, filep, options)
 * Read in a font file in GF format into the font buffer 'font'.
 * 'filep' is position at the beginning of the font file.
 * If TFMwidth != NULL, also fills those in.
 */
#include "stdio.h"
#include <Vfont.h>
#include <gfont.h>
#include <bitptr.h>
#define NoKern
#undef NEW_GF
#define NEW_GF 1
extern VRaster *AllocRaster();

SystemCode
ReadGenericFont(font, fp, options)
    register FILE *fp;
    register Vfont *font;
    int options;	/* currently unused; should be zero */
  { register c;
    int i;
    int gBack, minX, maxX, minY, maxY;

    for (c = 0; c <= 255; c++)
      {
	font->c[c] = 0;
	if ((&font->g)[-1].TFMwidth != 0)
	    (&font->g)[-1].TFMwidth[c] = i;
      }
    if (GetUnsigned1(fp) != pre || GetUnsigned1(fp) != gf_magic)
	return BAD_STATE;
#if 0
    c = GetUnsigned1(fp);
    printf("\n[");
    while (--c >= 0) fputc(fgetc(fp), stdout);
    fputc(']', stdout);
    fflush(stdout);
#endif
    fseek(fp, -1, 2);
    while ((c = GetUnsigned1(fp)) == postfill)
      { fseek(fp, -2, 1); }
    if (c != gf_magic) return BAD_STATE;
    fseek(fp, -5, 1);
    i = GetSigned4(fp); /* address of post command */
    fseek(fp, i, 0);
    if (GetUnsigned1(fp) != post) return BAD_STATE;
    gBack = GetSigned4(fp);
    FontPrefixOf(font)->designSize = GetSigned4(fp);
    GetSigned4(fp); /* checksum */
    FontPrefixOf(font)->resolution[X] = GetSigned4(fp);
    FontPrefixOf(font)->resolution[X] = GetSigned4(fp);

 /* font bounding box */
    minX = GetSigned4(fp);
    FontPrefixOf(font)->originAll[X] = -minX;
    FontPrefixOf(font)->bBoxAll[X] = GetSigned4(fp) - minX;
    minY = GetSigned4(fp);
    maxY = GetSigned4(fp) + 1;
    FontPrefixOf(font)->originAll[Y] = maxY;
    FontPrefixOf(font)->bBoxAll[Y] = maxY - minY;

    FontPrefixOf(font)->minChar = 255; FontPrefixOf(font)->maxChar = 0;
    while ((i = GetUnsigned1(fp)) == char_loc || i == char_loc0)
      { long savePos, width[2], bBox[2], byteWidth, start[2];
	register CharPrefix *r;
	c = GetUnsigned1(fp);
	if (NEW_GF && i == char_loc0)
	    width[X] = GetUnsigned1(fp) << 16;
	else
	    width[X] = GetSigned4(fp);
	if (i == char_loc) { width[Y] = GetSigned4(fp); }
	else width[Y] = 0;
	i = GetSigned4(fp);	/* TFMwidth */
	if ((&font->g)[-1].TFMwidth != 0)
	    (&font->g)[-1].TFMwidth[c] = i;
        savePos = ftell(fp);	
	fseek(fp, GetSigned4(fp), 0);
	if ((i = SkipToBoc(fp)) == 0) return BAD_STATE;
	if (i == boc)
	  {
	    if (GetSigned4(fp) != c) return BAD_STATE;
	    if (GetSigned4(fp) != -1) return INTERNAL_ERROR;
	    minX = GetSigned4(fp);
	    maxX = GetSigned4(fp);
	    minY = GetSigned4(fp);
	    maxY = GetSigned4(fp);
	  }
	else /* boc1 */
	  {
	    if (GetUnsigned1(fp) != c) return BAD_STATE;
	    i = GetUnsigned1(fp);
	    maxX = GetUnsigned1(fp);
	    minX = maxX - i;
	    i = GetUnsigned1(fp);
	    maxY = GetUnsigned1(fp);
	    minY = maxY - i;
	  }
	maxY++;
	/* Semi-open interval: min{X,Y} <= {x,y} < max{X,Y} */
	bBox[X] = maxX-minX;
	bBox[Y] = maxY-minY;
#if 0
	if (minX > 0 && ((bBox[X]+15)>>4) == ((maxX + 1)>>4))
	   { bBox[X] += minX; minX = 0; }
	if ((options & NoKern) && width > bBox[X] && () == () )
	  { bBox[X] = width; }
#endif
	start[X] = 0; start[Y] = 0;
	if (options & FontSun100)
	  {
	 /* For the sun100 VGTS, all characters must have same height */
	    i = FontPrefixOf(font)->originAll[Y];
	    start[Y] = i - maxY;
	    if (start[Y] < 0) start[Y] = 0; /* paranoia in case of bad fonts */
	    maxY = i;
	    if (FontPrefixOf(font)->bBoxAll[Y] > bBox[Y]) /* paranoia again */
		bBox[Y] = FontPrefixOf(font)->bBoxAll[Y];
	 /* sun100Vgts text routine only uses bBox[X] as width */
	    if (minX > 0) { bBox[X] += minX; start[X] = minX; minX = 0; }
	    i = width[X] >> 16;
	    if (i > bBox[X]) bBox[X] = i;
	  }
	if (bBox[X] <= 0) { bBox[Y] = 0; maxY = 0; }
	byteWidth = 2 * ((bBox[X] + 15) >> 4);
	r = AllocRaster(bBox[Y] * byteWidth);
	if (r == AllocFailure) return NO_MEMORY;
	r[-1].bBox[X] = bBox[X];
	r[-1].bBox[Y] = bBox[Y];
	r[-1].width[X] = width[X];
	r[-1].width[Y] = width[Y];
	r[-1].origin[X] = -minX;
	r[-1].origin[Y] = maxY;
	if (options & FontSun100)
	    r[-1].stride = bBox[Y];
	else
	    r[-1].stride = byteWidth;
	font->c[c] = r;
	ReadGenericCharacter(fp, r, start, options);
	if (c < FontPrefixOf(font)->minChar) FontPrefixOf(font)->minChar = c;
	if (c > FontPrefixOf(font)->maxChar) FontPrefixOf(font)->maxChar = c;
	fseek(fp, savePos+4, 0);
      }

    return OK;
  }
static SkipToBoc(fp) /* skip to a Beginning of Character command */
    register FILE *fp;
  { int c;
    while (c = GetUnsigned1(fp))
        switch (c)
	  {
	  case xxx1:
	    fseek(fp, GetUnsigned1(fp), 1); continue;
	  case xxx2:
	    fseek(fp, GetUnsigned2(fp), 1); continue;
	  case yyy:
	    GetSigned4(fp); continue;
	  case no_op:
	    continue;
#if NEW_GF
	  case boc1:
	    return boc1;
#endif
	  case boc:
	    return boc;
	  default:
	    return 0;
	  }
  }

static ReadGenericCharacter(fp, r, start, options)
    register FILE *fp;
    register VRaster *r;
    long start[2];
   {
    int i, color = 0, x, y;
    struct BitPtr bPtr;
    x = start[X]; y = start[Y];
    while ((i = GetUnsigned1(fp)) != eoc)
      { register int n; /* parameter for commands */
	if (i >= paint_1 && i <= paint_63)
	  {n = i - (paint_1 - 1); goto paint;}
	if (i >= new_row_0 && i <= new_row_0 + max_new_row)
	  { n = i - new_row_0; goto new_row;}
	switch (i)
	  {
	    case paint_0:  n = 0; goto paint;
	    case paint1: n = GetUnsigned1(fp); goto paint;
	    case paint2: n = GetUnsigned2(fp); goto paint;
	    case skip0: n = 0; goto skip;
	    case skip1: n = GetUnsigned1(fp); goto skip;
	    case skip2: n = GetUnsigned2(fp); goto skip;
/* ??? sign of y? */
/*	    case newrow: n = GetSigned4(fp); goto new_row;*/
	    case no_op: continue;
	    case xxx1: n = GetUnsigned1(fp); goto xxx;
	    case xxx2: n = GetUnsigned2(fp); goto xxx;
	    case yyy: n = GetSigned4(fp); continue;
	    default:
		printf("unknown mf op: %d at %d\n", i, ftell(fp));
		abort(); continue;
    	  }
      xxx: fseek(fp, n, 1); continue;
      new_row:
	y++; x = start[X] + n;
	color = 1; continue;
      skip: n++; y += n; x = start[X]; color = 0;
	continue;
      paint:
	if (color > 0) 
	  {
	    if (options & FontSun100)
	      {
		SetBitPtr_Sun1(&bPtr, r, x, y);
		PaintNBitsSun100(&bPtr, n);
	      }
	    else
	      {
		SetBitPtr(&bPtr, r, x, y);
		PaintNBits(&bPtr, n);
	      }
	  }
	x += n;
	color = 1 - color;
      }
    return;
  }
