/* type1lib.c

    Author - Amish S. Dave

This file contains the entry points of the Amiga shared library
It calls functions in type1interface.c

*/

/**
 * INCLUDES
 **/
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/utility.h>
#include <diskfont/glyph.h>
#include <diskfont/diskfonttag.h>
#include <stdlib.h>
#include <string.h>

#define  OT_Spec2       (OT_Level1 | 0x102)
#define  OT_Spec3       (OT_Level1 | 0x103)

#include "amishfontrequest.h"


void __stdargs _CXFERR(int code)
{
	extern int _FPERR;
	_FPERR = code;
}


/**
 * DEFINES
 **/
#define REG(x) register __## x


/**
 * GLOBAL VARIABLES
 **/
static UBYTE *EngineName = "type1";
static FONTREQUEST fontreq;
static const char *versionstring = "$VER: type1.library.030 1.4 (C) Amish S. Dave";


/**
 * PROTOTYPES
 **/
struct GlyphEngine * __saveds __asm OpenEngine(REG(a6) struct Library *Type1Base);
void __saveds __asm CloseEngine(REG(a0) struct GlyphEngine *engine, REG(a6) struct Library *Type1Base);
ULONG __saveds __asm ObtainInfoA(REG(a0) struct GlyphEngine *engine, REG(a1) struct TagItem *tags, REG(a6) struct Library *Type1Base);
ULONG __saveds __asm SetInfoA(REG(a0) struct GlyphEngine *engine, REG(a1) struct TagItem *tags, REG(a6) struct Library *Type1Base);
ULONG __saveds __asm ReleaseInfoA(REG(a0) struct GlyphEngine *engine, REG(a1) struct TagItem *tags, REG(a6) struct Library *Type1Base);

static void clearfontreq(FONTREQUEST *fontreq_p);
static void scantags(struct TagItem *tags);


/**
 * EXTERNAL PROTOTYPES (from type1interface.c)
 **/
extern void OpenType1Engine(void);
extern void CloseType1Engine(void);
extern unsigned long ReadType1Font(FONTREQUEST *fontreq_p);
extern struct GlyphMap *GetType1GlyphMap(ULONG GlyphCode);
extern void CloseType1Font(void);
extern int MyQueryFontLib(char *filename, char *env, void *dest);
extern unsigned long SetTransformType1Font(FONTREQUEST *fontreq_p);


/**
 * OpenEngine
 **/
struct GlyphEngine * __saveds __asm OpenEngine(REG(a6) struct Library *Type1Base)
{
	struct GlyphEngine *ge;
	extern UBYTE *EngineName;

	ge = AllocVec(sizeof(struct GlyphEngine), 0L);
	ge->gle_Library = Type1Base;
	ge->gle_Name = EngineName;

	clearfontreq(&fontreq);

	OpenType1Engine();
	return ge;
}


/**
 * CloseEngine
 **/
void __saveds __asm CloseEngine(REG(a0) struct GlyphEngine *engine, REG(a6) struct Library *Type1Base)
{
	CloseType1Engine();

	FreeVec(engine);
	return;
}


/**
 * ObtainInfoA
 **/
ULONG __saveds __asm ObtainInfoA(REG(a0) struct GlyphEngine *engine, REG(a1) struct TagItem *tags, REG(a6) struct Library *Type1Base)
{
	struct GlyphMap **gm_p;
	BOOL *IsFixed_p;
	char **familyname, **fontname;

	if (gm_p = (struct GlyphMap **)GetTagData(OT_GlyphMap, NULL, tags))
	{

		if (fontreq.FontDone == 0)
		{
			if (ReadType1Font(&fontreq) != 0)
				return (ULONG)-1;
			fontreq.FontDone = 1;
			fontreq.transformchanged = FALSE;
		}

		if (fontreq.transformchanged == TRUE)
		{
			if (SetTransformType1Font(&fontreq) != 0)	
				return (ULONG)-1;
			fontreq.transformchanged = FALSE;
		}

		if ((*gm_p = GetType1GlyphMap(fontreq.GlyphCode)) == NULL)
			return (ULONG)-1;
	}

	if (IsFixed_p = (BOOL *)GetTagData(OT_IsFixed, NULL, tags))
	{
		if (MyQueryFontLib(fontreq.FontFileName, "isFixedPitch", (void *)IsFixed_p) != 0)
			return (ULONG) -1;
	}

	if (familyname = (char **)GetTagData(OT_Family, NULL, tags))
	{
		if (MyQueryFontLib(fontreq.FontFileName, "FamilyName", (void *)familyname) != 0)
			return (ULONG) -1;
	}

	if (fontname = (char **)GetTagData(OT_Spec3, NULL, tags))
	{
		if (MyQueryFontLib(fontreq.FontFileName, "FontName", (void *)fontname) != 0)
			return (ULONG) -1;
	}

	return 0;
}


/**
 * SetInfoA
 **/
ULONG __saveds __asm SetInfoA(REG(a0) struct GlyphEngine *engine, REG(a1) struct TagItem *tags, REG(a6) struct Library *Type1Base)
{
	struct TagItem *otags;

	scantags(tags);

	if (otags = (struct TagItem *)GetTagData(OT_OTagList, NULL, tags))
		if (GetTagData(OT_OTagList, NULL, otags) == NULL)		/* Just in case... */
			scantags(otags);

	return 0;
}


/**
 * ReleaseInfoA
 **/
ULONG __saveds __asm ReleaseInfoA(REG(a0) struct GlyphEngine *engine, REG(a1) struct TagItem *tags, REG(a6) struct Library *Type1Base)
{
	return 0;
}


static void clearfontreq(FONTREQUEST *fontreq_p)
{
	fontreq_p->FontDone = 0;
	fontreq_p->GlyphCode = 0;
	fontreq_p->DeviceXDPI = 0;
	fontreq_p->DeviceYDPI = 0;
	fontreq_p->PointHeight = 0;
	fontreq_p->SetFactor = 0;
	fontreq_p->PointSet = 0;
	fontreq_p->RotateSin = 0.0;
	fontreq_p->RotateCos = 1.0;
	fontreq_p->ShearSin = 0.0;
	fontreq_p->ShearCos = 1.0;

	fontreq_p->FontFileName[0] = '\0';
	fontreq_p->OTagFileName[0] = '\0';
	fontreq_p->AFMFileName[0] = '\0';
}

#define sgn(a) (a<0?-1:a>0?1:0)
#define FP2DOUBLE(fp) (sgn(fp)*((double)((abs(fp) & 0xffff0000) >> 16) + (((double)(abs(fp) & 0x0000ffff)) / 65536)))

/**
 * scantags
 **/
static void scantags(struct TagItem *tags)
{
	LONG otagdata;
	BOOL transformchanged = FALSE;

	if (otagdata = GetTagData(OT_OTagPath, NULL, tags))
	{
		clearfontreq(&fontreq);
		strcpy(fontreq.OTagFileName, (char *)otagdata);
		CloseType1Font();
	}

	/* OT_Spec1 = the filename string of the pfb file */
	if (otagdata = GetTagData(OT_Spec1 | OT_Indirect, NULL, tags))
		strcpy(fontreq.FontFileName, (char *)otagdata);

	/* OT_Spec2 = the filename of the AFM file */
	if (otagdata = GetTagData(OT_Spec2 | OT_Indirect, NULL, tags))
		strcpy(fontreq.AFMFileName, (char *)otagdata);

    /* OT_Spec3 = the name of the font, from the FontName field of the font itself */
    /* Not to be used in .otags, and not to be set.  Can be queried by an installer. */
	
	/* For now, assume fractional part is zero */
	if (otagdata = GetTagData(OT_PointHeight, 0L, tags))
	{
		fontreq.PointHeight = ((ULONG)otagdata) >> 16;
		transformchanged = TRUE;
	}

	if (otagdata = GetTagData(OT_RotateSin, 0L, tags))
	{
		fontreq.RotateSin = FP2DOUBLE(otagdata);
		transformchanged = TRUE;
	}

	if (otagdata = GetTagData(OT_RotateCos, 0L, tags))
	{
		fontreq.RotateCos = FP2DOUBLE(otagdata);
		transformchanged = TRUE;
	}

	if (otagdata = GetTagData(OT_ShearSin, 0L, tags))
	{
		fontreq.ShearSin = FP2DOUBLE(otagdata);
		transformchanged = TRUE;
	}

	if (otagdata = GetTagData(OT_ShearCos, 0L, tags))
	{
		fontreq.ShearCos = FP2DOUBLE(otagdata);
		transformchanged = TRUE;
	}

	if (otagdata = GetTagData(OT_SetFactor, 0L, tags))
	{
		fontreq.SetFactor = (ULONG)otagdata;
		if (otagdata == 0x00010000)
			fontreq.PointSet = 0;
		else
			fontreq.PointSet = FP2DOUBLE(otagdata) * fontreq.PointHeight;
		transformchanged = TRUE;
	}

	if (otagdata = GetTagData(OT_DeviceDPI, 0L, tags))
	{
		fontreq.DeviceXDPI = ((ULONG)otagdata) >> 16;
		fontreq.DeviceYDPI = ((ULONG)otagdata) & 0xffff;
		transformchanged = TRUE;
	}

	if (otagdata = GetTagData(OT_GlyphCode, 0L, tags))
		fontreq.GlyphCode = (ULONG)otagdata;

	if (transformchanged == TRUE)
		fontreq.transformchanged = TRUE;
}

