/**
 * INCLUDES
 **/
#ifndef T1GST
#include "global.h"
#endif


/**
 * LOCAL PROTOTYPES
 **/
static void fill(unsigned char *dest, unsigned int h, unsigned int w, struct region *area);
extern void __asm fillrun(register __a0 unsigned char *p, register __d0 x0, register __d1 x1);


/**
 * GLOBAL VARIABLE REFERENCES
 **/
extern psfont *FontP;
extern psobj *ISOLatin1EncArrayP;

static struct XYspace *S;		/* coordinate space for character */
static psobj *fontencoding = NULL;

#ifndef hypot
#define hypot(a,b) (sqrt(((a)*(a))+((b)*(b))))
#endif

int MyType1OpenScalable(
		FontPtr *ppFont,
		char *fileName,
		FontScalablePtr vals)
{
	FontPtr pFont;
	int rc, size;
	struct type1font *type1;

	*ppFont = NULL;

	/* Reject ridiculously small font sizes */
	rc = BadFontName;
	if ((hypot(vals->pixel_matrix[0], vals->pixel_matrix[1]) >= 1.0) &&
	    (hypot(vals->pixel_matrix[2], vals->pixel_matrix[3]) >= 1.0))
	{
		rc = AllocError;
		if ((pFont = (FontPtr) xalloc(sizeof(FontRec))) != NULL)
		{
			if ((type1 = (struct type1font *) xalloc(sizeof(struct type1font))) != NULL)
			{
				bzero(type1, sizeof(struct type1font));
				size = 200000 + 120 * (int)hypot(vals->pixel_matrix[2], vals->pixel_matrix[3]) * sizeof(short);
				if (size > 0)
				{
					addmemory(size);
					if (fontfcnA(fileName, &rc))
					{
						/*
						** To set ISOLatin1 encoding, do:
						** fontencoding = ISOLatin1EncArrayP
						*/
						fontencoding = FontP->fontInfoP[ENCODING].value.data.arrayP;

						type1->pDefault = NULL;
						pFont->fontPrivate = (unsigned char *)type1;

						rc = MyType1SetTransform(pFont, vals);
						if (rc == Successful)
						{
							*ppFont = pFont;
							return Successful;
						}
					}
				}
				xfree(type1);
			}
			xfree(pFont);
		}
	}
	return rc;
}


int MyType1SetTransform(
		FontPtr pFont,
		FontScalablePtr vals)
{
	psobj *fontmatrix;
	double t1 = 0.001, t2 = 0.0, t3 = 0.0, t4 = 0.001;
	extern struct XYspace *IDENTITY;
	struct type1font *type1;
	int i;

	if (pFont == NULL)
		return AllocError;

	if ((type1 = (struct type1font *)pFont->fontPrivate) == NULL)
		return AllocError;

	/*
	** Changing the transform invalidates any glyphs we've already rendered,
	** so free them and mark them NULL, so we'll know to re-render them if
	** asked
	*/
	for (i = 0; i < 256 - FIRSTCOL; i++)
	{
		if (type1->glyphs[i].bits != NULL)
		{
			xfree(type1->glyphs[i].bits);
			type1->glyphs[i].bits = NULL;
		}

		if (type1->glyphs[i].glyphmap != NULL)
		{
			xfree(type1->glyphs[i].glyphmap);
			type1->glyphs[i].glyphmap = NULL;
		}
	}

	/* Reject ridiculously small font sizes */
	if ((hypot(vals->pixel_matrix[0], vals->pixel_matrix[1]) < 1.0) ||
	    (hypot(vals->pixel_matrix[2], vals->pixel_matrix[3]) < 1.0))
		return BadFontName;

	fontmatrix = &FontP->fontInfoP[FONTMATRIX].value;
	if ((objPIsArray(fontmatrix)) && (fontmatrix->len == 6))
	{
#define assign(n,d,f) if (objPIsInteger(fontmatrix->data.arrayP + n)) \
			  d = fontmatrix->data.arrayP[n].data.integer; \
		      else if (objPIsReal(fontmatrix->data.arrayP + n)) \
			  d = fontmatrix->data.arrayP[n].data.real; \
		      else d = f;

		assign (0, t1, .001);
		assign (1, t2, 0.0);
		assign (2, t3, 0.0);
		assign (3, t4, .001);
	}

	S = (struct XYspace *) t1_Transform(IDENTITY, t1, t2, t3, t4);

	/* Oblique */
	if ((vals->ShearSin != 0.0) && (vals->ShearCos != 1.0))
		S = (struct XYspace *) t1_Transform(S, 1.0, 0.0, 
						-1 * vals->ShearSin / vals->ShearCos, 1.0);

	/* Rotate */
	if ((vals->RotateSin != 0.0) && (vals->RotateCos != 1.0))
		S = (struct XYspace *) t1_Transform(S, vals->RotateCos, vals->RotateSin,
						-1.0 * vals->RotateSin, vals->RotateCos);

	S = (struct XYspace *) Permanent(t1_Transform(S, vals->pixel_matrix[0],
						       -(vals->pixel_matrix[1]),
							vals->pixel_matrix[2],
						       -(vals->pixel_matrix[3])));

	return Successful;
}


#define  PAD(bits, pad)  (((bits)+(pad)-1)&-(pad))


int MyType1GetGlyphs(
		FontPtr pFont,
		int i,
		CharInfoPtr *returnglyph)	/* RETURN */
{
	CharInfoPtr pci;
	CharInfoPtr pDefault;
	CharInfoRec *glyphs;
	struct type1font *type1Font;
	int len, rc, size;
	char *codename;
	long paddedW, h, w;
	struct region *area;

	type1Font = (struct type1font *) pFont->fontPrivate;
	pDefault = type1Font->pDefault;
	glyphs = type1Font->glyphs;

	/*
	 * If the requested character is out of bounds,
	 */
	if ((i < FIRSTCOL) || (i > 255))
	{
		*returnglyph = pDefault;
//kprintf("%ld\t%ld\tglyphcode out of bounds\n", __LINE__, i);
		return Successful;
	}

	codename = fontencoding[i].data.valueP;
	len = fontencoding[i].len;

	/*
	 * Or the encoding says the character is '.notdef',
	 * return default glyph
	 */
	if ((len == 7) && (strcmp(codename, ".notdef") == 0))
	{
		*returnglyph = pDefault;
//kprintf("%ld\t%ld\tnotdef glyph requested\n", __LINE__, i);
		return Successful;
	}

	/*
	 * If we have already rendered the character,
	 * return it and go no further
	 */
	if (glyphs[i-FIRSTCOL].glyphmap != NULL)
	{
		if ((pci = &type1Font->glyphs[i-FIRSTCOL])->metrics.characterWidth != 0)
		{
			*returnglyph = pci;
			return Successful;
		}
		else
		{
			*returnglyph = pDefault;
//kprintf("%ld\t%ld\talready rendered, but charwidth == 0\n", __LINE__, i);
			return Successful;
		}
	}

	/** Okay, now we have to render the glyph
	 **/
	rc = 0;
	area = (struct region *) fontfcnB(S, codename, &len, &rc);

	if ((rc != 0) || (area == NULL))
	{
		if (area != NULL)
			Destroy(area);

//kprintf("%ld\t%ld\tfontfcnB failed\n", __LINE__, i);
		return AllocError;
	}

	/** Figure out the size of the bitmap, padded to multiples of 32 bits wide
	 **/
	h = area->ymax - area->ymin;
	w = area->xmax - area->xmin;
	paddedW = PAD(w, 32);			/* paddedW is in bits */
	size = h * (paddedW >> 3);		/* size is in bytes */

	/** If empty/oddball bitmap, return a glyphmap with NULL bitmap, but
	 ** accurate spacing information. (For space characters...)
	 **/
	if ((h <= 0) || (w <= 0))
	{
		if (glyphs[i-FIRSTCOL].glyphmap = (struct GlyphMap *)xalloc(sizeof(struct GlyphMap)))
		{
// This could be a big problem, depending on how the calling programs are written...
			glyphs[i-FIRSTCOL].glyphmap->glm_BitMap = NULL;
			glyphs[i-FIRSTCOL].glyphmap->glm_BMModulo = 0;
			glyphs[i-FIRSTCOL].glyphmap->glm_BMRows = 0;
			glyphs[i-FIRSTCOL].glyphmap->glm_BlackLeft = 0;
			glyphs[i-FIRSTCOL].glyphmap->glm_BlackTop = 0;
			glyphs[i-FIRSTCOL].glyphmap->glm_BlackWidth = 0;
			glyphs[i-FIRSTCOL].glyphmap->glm_BlackHeight = 0;
			glyphs[i-FIRSTCOL].glyphmap->glm_XOrigin = area->origin.x;
			glyphs[i-FIRSTCOL].glyphmap->glm_YOrigin = area->origin.y;
			glyphs[i-FIRSTCOL].glyphmap->glm_X0 = NEARESTPEL(area->origin.x);
			glyphs[i-FIRSTCOL].glyphmap->glm_Y0 = NEARESTPEL(area->origin.y);
			glyphs[i-FIRSTCOL].glyphmap->glm_X1 = NEARESTPEL(area->ending.x);
			glyphs[i-FIRSTCOL].glyphmap->glm_Y1 = NEARESTPEL(area->ending.y);
			glyphs[i-FIRSTCOL].glyphmap->glm_Width = TOFRACTPEL(1);

/* The following line is important because metrics.characterwidth is checked above */
			glyphs[i-FIRSTCOL].metrics.characterWidth = NEARESTPEL(area->ending.x - area->origin.x);

			*returnglyph = &type1Font->glyphs[i-FIRSTCOL];
			Destroy(area);
			return Successful;
		}
		else
		{
			*returnglyph = pDefault;
			Destroy(area);
			return AllocError;
		}
	}

	/** Allocate space for the glyphmap structure and the bitmap
	 **/
	if (glyphs[i-FIRSTCOL].glyphmap = (struct GlyphMap *)xalloc(sizeof(struct GlyphMap)))
	{
		if (glyphs[i-FIRSTCOL].bits = (char *)xalloc(size))
		{
			/** Fill in the glyphmap structure
			 **/
			glyphs[i-FIRSTCOL].glyphmap->glm_BitMap = (unsigned char *)glyphs[i-FIRSTCOL].bits;
			glyphs[i-FIRSTCOL].glyphmap->glm_BMModulo = paddedW >> 3;
			glyphs[i-FIRSTCOL].glyphmap->glm_BMRows = h;
			glyphs[i-FIRSTCOL].glyphmap->glm_BlackLeft = 0;
			glyphs[i-FIRSTCOL].glyphmap->glm_BlackTop = 0;
			glyphs[i-FIRSTCOL].glyphmap->glm_BlackWidth = w;
			glyphs[i-FIRSTCOL].glyphmap->glm_BlackHeight = h;
//			glyphs[i-FIRSTCOL].glyphmap->glm_XOrigin = area->origin.x;
			glyphs[i-FIRSTCOL].glyphmap->glm_XOrigin = area->origin.x + TOFRACTPEL(0-area->xmin);
			glyphs[i-FIRSTCOL].glyphmap->glm_YOrigin = area->origin.y + TOFRACTPEL(0-area->ymin);
//			glyphs[i-FIRSTCOL].glyphmap->glm_X0 = NEARESTPEL(area->origin.x);
			glyphs[i-FIRSTCOL].glyphmap->glm_X0 = NEARESTPEL(area->origin.x) - area->xmin;
			glyphs[i-FIRSTCOL].glyphmap->glm_Y0 = NEARESTPEL(area->origin.y) - area->ymin;
//			glyphs[i-FIRSTCOL].glyphmap->glm_X1 = NEARESTPEL(area->ending.x);
			glyphs[i-FIRSTCOL].glyphmap->glm_X1 = NEARESTPEL(area->ending.x) - area->xmin;
			glyphs[i-FIRSTCOL].glyphmap->glm_Y1 = NEARESTPEL(area->ending.y) - area->ymin;
			glyphs[i-FIRSTCOL].glyphmap->glm_Width = TOFRACTPEL(1);

/* The following line is important because metrics.characterwidth is checked above */
			glyphs[i-FIRSTCOL].metrics.characterWidth = NEARESTPEL(area->ending.x - area->origin.x);

//			glyphs[i-FIRSTCOL].metrics.leftSideBearing = area->xmin;
//			glyphs[i-FIRSTCOL].metrics.rightSideBearing = w + area->xmin;
//			glyphs[i-FIRSTCOL].metrics.descent = area->ymax - NEARESTPEL(area->origin.y);
//			glyphs[i-FIRSTCOL].metrics.ascent = h - glyphs[i-FIRSTCOL].metrics.descent;

//kprintf("Char %ld = %lc\n", i, i);
//kprintf("area->origin.x = %ld\n", NEARESTPEL(area->origin.x));
//kprintf("area->ending.x = %ld\n", NEARESTPEL(area->ending.x));
//kprintf("area->xmin     = %ld\n", area->xmin);
//kprintf("area->xmax     = %ld\n", area->xmax);
//kprintf("w              = %ld\n", w);
//kprintf("leftSideBear   = %ld\n", glyphs[i-FIRSTCOL].metrics.leftSideBearing);
//kprintf("rightSideBear  = %ld\n\n", glyphs[i-FIRSTCOL].metrics.rightSideBearing);

			/** Render the bitmap
			 **/
			bzero(glyphs[i-FIRSTCOL].bits, size);
			fill(glyphs[i-FIRSTCOL].bits, h, paddedW, area);

			/** If the character doesn't have an oddball width, return it
			 **/
			pci = &type1Font->glyphs[i-FIRSTCOL];
			if (NEARESTPEL(area->ending.x - area->origin.x) != 0)
				*returnglyph = pci;
			else
				*returnglyph = pDefault;

			Destroy(area);
			return Successful;
		}

		xfree(glyphs[i-FIRSTCOL].glyphmap);
		glyphs[i-FIRSTCOL].glyphmap = NULL;
	}

	Destroy(area);
	return AllocError;
}


void MyType1CloseFont(FontPtr pFont)
{
	int i;
	struct type1font *type1;

	delmemory();

	if (pFont == NULL)
		return;

	type1 = (struct type1font *)pFont->fontPrivate;
	for (i = 0; i < 256 - FIRSTCOL; i++)
	{
		if (type1->glyphs[i].bits != NULL)
		{
			xfree(type1->glyphs[i].bits);
			type1->glyphs[i].bits = NULL;
		}

		if (type1->glyphs[i].glyphmap != NULL)
		{
			xfree(type1->glyphs[i].glyphmap);
			type1->glyphs[i].glyphmap = NULL;
		}
	}
	xfree(type1);
	xfree(pFont);
}


static void fill(
		unsigned char *dest,	/* destination bitmap */
		unsigned int h,
		unsigned int w,			/* dimensions of 'dest', w padded */
		struct region *area)	/* region to write to 'dest' */
{
	struct edgelist *edge;		/* for looping through edges */
	unsigned char *p;			/* current scan line in 'dest' */
	unsigned int wbytes;		/* number of bytes in width */
	pel *leftP, *rightP;		/* pointers to X values, left and right */
	int xmin = area->xmin;		/* upper left X */
	int ymin = area->ymin;		/* upper left Y */
	int y;

	wbytes = w >> 3;

	for (edge = area->anchor; VALIDEDGE(edge); edge = edge->link->link)
	{
		p = dest + (edge->ymin - ymin) * wbytes;
		leftP = edge->xvalues;
		rightP = edge->link->xvalues;

		for (y = edge->ymin; y < edge->ymax; y++)
		{
			fillrun(p, *leftP++ - xmin, *rightP++ - xmin);
			p += wbytes;
		}
	}
}


//#define  ALLONES  0xFF

//static void __inline fillrun(
//		unsigned char *p,	/* address of this scan line */
//		pel x0, pel x1)		/* left and right X */
//{
//	unsigned char startmask, endmask;	/* bits to set in first and last char*/
//	unsigned int middle;	/* number of chars between start and end + 1    */
//
//	if (x1 <= x0)
//		return;
//	middle = x1 / (unsigned int)8 - x0 / (unsigned int)8;
//	p += x0 / (unsigned int)8;
//	x0 &= 7;
//	x1 &= 7;
//
//	startmask = ALLONES >> x0;
//	endmask = ~(ALLONES >> x1);
//
//	if (middle == 0)
//		*p |= startmask & endmask;
//	else
//	{
//		*p++ |= startmask;
//		while (--middle > 0)
//			*p++ = ALLONES;
//		*p |= endmask;
//	}
//}

