diff packages/services/gfx/mw/current/src/engine/devfont.c @ 208:e0c0827131d1 ecos

Merge from eCos master repository on 2002-05-20-20:11:54-BST
author jlarmour
date Mon, 20 May 2002 22:19:26 +0000
parents
children e1afd37f2f1d
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/packages/services/gfx/mw/current/src/engine/devfont.c
@@ -0,0 +1,2689 @@
+/*
+ * Copyright (c) 2000 Greg Haerr <greg@censoft.com>
+ * T1lib Adobe type1 routines contributed by Vidar Hokstad
+ * Freetype TrueType routines contributed by Martin Jolicoeur
+ * Han Zi Ku routines contributed by Tanghao and Jauming
+ *
+ * Device-independent font and text drawing routines
+ *
+ * These routines do the necessary range checking, clipping, and cursor
+ * overwriting checks, and then call the lower level device dependent
+ * routines to actually do the drawing.  The lower level routines are
+ * only called when it is known that all the pixels to be drawn are
+ * within the device area and are visible.
+ */
+/*#define NDEBUG*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <string.h>
+
+#include "device.h"
+#if (UNIX | DOS_DJGPP)
+#define strcmpi	strcasecmp
+#endif
+
+#if HAVE_T1LIB_SUPPORT
+#include <t1lib.h>
+#define T1LIB_USE_AA_HIGH
+
+typedef struct {
+	PMWFONTPROCS	fontprocs;	/* common hdr*/
+	MWCOORD		fontsize;
+	int		fontrotation;
+	int		fontattr;		
+
+	int		fontid;		/* t1lib stuff*/
+} MWT1LIBFONT, *PMWT1LIBFONT;
+
+static int  t1lib_init(PSD psd);
+static PMWT1LIBFONT t1lib_createfont(const char *name, MWCOORD height,int attr);
+static void t1lib_drawtext(PMWFONT pfont, PSD psd, MWCOORD x, MWCOORD y,
+		const void *text, int cc, int flags);
+static MWBOOL t1lib_getfontinfo(PMWFONT pfont, PMWFONTINFO pfontinfo);
+static void t1lib_gettextsize(PMWFONT pfont, const void *text, int cc,
+		MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase);
+static void t1lib_destroyfont(PMWFONT pfont);
+
+/* handling routines for MWT1LIBFONT*/
+static MWFONTPROCS t1lib_procs = {
+	MWTF_ASCII,			/* routines expect ascii*/
+	t1lib_getfontinfo,
+	t1lib_gettextsize,
+	NULL,				/* gettextbits*/
+	t1lib_destroyfont,
+	t1lib_drawtext,
+	NULL,				/* setfontsize*/
+	NULL,				/* setfontrotation*/
+	NULL,				/* setfontattr*/
+};
+#endif
+
+#ifdef T1LIB_USE_AA_HIGH
+typedef unsigned long OUTPIXELVAL;
+#else
+typedef MWPIXELVAL OUTPIXELVAL;
+#endif
+
+#if HAVE_FREETYPE_SUPPORT
+#include <freetype/freetype.h>
+#include <freetype/ftxkern.h>
+#include <freetype/ftnameid.h>
+#include <freetype/ftxcmap.h>
+#include <freetype/ftxwidth.h>
+#include <math.h>
+
+#ifndef FREETYPE_FONT_DIR
+#define FREETYPE_FONT_DIR "/usr/local/microwin/fonts"
+#endif
+
+#if TT_FREETYPE_MAJOR != 1 | TT_FREETYPE_MINOR < 3
+#error "You must link with freetype lib version 1.3.x +, and not freetype 2. \
+Download it at http://www.freetype.org or http://microwindows.org"
+#endif
+
+typedef struct {
+	PMWFONTPROCS	fontprocs;	/* common hdr*/
+	MWCOORD		fontsize;
+	int		fontrotation;
+	int		fontattr;		
+
+	TT_Face 	face;		/* freetype stuff*/
+	TT_Instance	instance;
+	TT_CharMap 	char_map;
+	TT_Kerning 	directory;
+	TT_Matrix 	matrix;
+	TT_Glyph 	glyph;
+	MWBOOL 		can_kern;
+	short 		last_glyph_code;
+	short 		last_pen_pos;
+} MWFREETYPEFONT, *PMWFREETYPEFONT;
+
+static int  freetype_init(PSD psd);
+static PMWFREETYPEFONT freetype_createfont(const char *name, MWCOORD height,
+		int attr);
+static MWBOOL freetype_getfontinfo(PMWFONT pfont, PMWFONTINFO pfontinfo);
+static void freetype_gettextsize(PMWFONT pfont, const void *text,
+		int cc, MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase);
+static void freetype_destroyfont(PMWFONT pfont);
+static void freetype_drawtext(PMWFONT pfont, PSD psd, MWCOORD x, MWCOORD y,
+		const void *text, int cc, int flags);
+static void freetype_setfontsize(PMWFONT pfont, MWCOORD fontsize);
+static void freetype_setfontrotation(PMWFONT pfont, int tenthdegrees);
+		
+/* handling routines for MWFREETYPEFONT*/
+static MWFONTPROCS freetype_procs = {
+	MWTF_UC16,			/* routines expect unicode 16*/
+	freetype_getfontinfo,
+	freetype_gettextsize,
+	NULL,				/* gettextbits*/
+	freetype_destroyfont,
+	freetype_drawtext,
+	freetype_setfontsize,
+	freetype_setfontrotation,
+	NULL,				/* setfontattr*/
+};
+
+static TT_Engine 	engine;		/* THE ONLY freetype engine */
+#endif /* HAVE_FREETYPE_SUPPORT*/
+
+#if HAVE_HZK_SUPPORT
+/*
+ * 12x12 and 16x16 ascii and chinese fonts
+ * Big5 and GB2312 encodings supported
+ */
+#define MAX_PATH	256
+typedef struct {
+	int	width;
+	int	height;
+	int	size;
+	unsigned long use_count;
+	char *	pFont;
+	char	file[MAX_PATH + 1];
+} HZKFONT;
+
+static int use_big5=1;
+static HZKFONT CFont[2];	/* font cache*/
+static HZKFONT AFont[2];	/* font cache*/
+
+/* jmt: moved inside MWHZKFONT*/
+static int afont_width = 8;
+static int cfont_width = 16;
+static int font_height = 16;
+static char *afont_address;
+static char *cfont_address;
+
+typedef struct {
+	PMWFONTPROCS	fontprocs;	/* common hdr*/
+	MWCOORD		fontsize;
+	int		fontrotation;
+	int		fontattr;		
+
+	HZKFONT 	CFont;		/* hzkfont stuff */
+	HZKFONT 	AFont;
+	int 		afont_width;
+	int 		cfont_width;
+	int 		font_height;
+	char 		*afont_address;
+	char 		*cfont_address;
+} MWHZKFONT, *PMWHZKFONT;
+
+static int  hzk_init(PSD psd);
+static PMWHZKFONT hzk_createfont(const char *name, MWCOORD height,int fontattr);
+static MWBOOL hzk_getfontinfo(PMWFONT pfont, PMWFONTINFO pfontinfo);
+static void hzk_gettextsize(PMWFONT pfont, const void *text,
+		int cc, MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase);
+#if 0
+static void hzk_gettextbits(PMWFONT pfont, int ch, IMAGEBITS *retmap,
+		MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase);
+static void hzk_setfontrotation(PMWFONT pfont, int tenthdegrees);
+#endif
+static void hzk_destroyfont(PMWFONT pfont);
+static void hzk_drawtext(PMWFONT pfont, PSD psd, MWCOORD x, MWCOORD y,
+		const void *text, int cc, int flags);
+static void hzk_setfontsize(PMWFONT pfont, MWCOORD fontsize);
+		
+/* handling routines for MWHZKFONT*/
+static MWFONTPROCS hzk_procs = {
+	MWTF_ASCII,			/* routines expect ASCII*/
+	hzk_getfontinfo,
+	hzk_gettextsize,
+	NULL,				/* hzk_gettextbits*/
+	hzk_destroyfont,
+	hzk_drawtext,
+	hzk_setfontsize,
+	NULL, 				/* setfontrotation*/
+	NULL,				/* setfontattr*/
+};
+
+static int
+UC16_to_GB(const unsigned char *uc16, int cc, unsigned char *ascii);
+#endif /* HAVE_HZK_SUPPORT*/
+
+static PMWFONT	gr_pfont;            	/* current font*/
+
+/* temp extern decls*/
+extern MWPIXELVAL gr_foreground;
+extern MWPIXELVAL gr_background;
+extern MWBOOL gr_usebg;
+
+static int  utf8_to_utf16(const unsigned char *utf8, int cc,
+		unsigned short *unicode16);
+
+#if FONTMAPPER
+/* entry point for font selection*/
+int select_font(const PMWLOGFONT plogfont, char *physname);
+#endif
+
+/*
+ * Set the font for future calls.
+ */
+PMWFONT
+GdSetFont(PMWFONT pfont)
+{
+	PMWFONT	oldfont = gr_pfont;
+
+	gr_pfont = pfont;
+	return oldfont;
+}
+
+/*
+ * Select a font, based on various parameters.
+ * If plogfont is specified, name and height parms are ignored
+ * and instead used from MWLOGFONT.
+ * 
+ * If height is 0, return builtin font from passed name.
+ * Otherwise find builtin font best match based on height.
+ */
+PMWFONT
+GdCreateFont(PSD psd, const char *name, MWCOORD height,
+	const PMWLOGFONT plogfont)
+{
+	int 		i;
+	int		fontht;
+	int		fontno;
+ 	int		fontclass;
+	int		fontattr = 0;
+	PMWFONT		pfont;
+	PMWCOREFONT	pf = psd->builtin_fonts;
+	MWFONTINFO	fontinfo;
+	MWSCREENINFO 	scrinfo;
+ 	char		fontname[128];
+
+	GdGetScreenInfo(psd, &scrinfo);
+
+	/* if plogfont not specified, use name and height*/
+	if (!plogfont) {
+		if (!name)
+			name = MWFONT_SYSTEM_VAR;
+		strcpy(fontname, name);
+		fontclass = MWLF_CLASS_ANY;
+	} else {
+#if FONTMAPPER
+		/* otherwise, use MWLOGFONT name and height*/
+ 		fontclass = select_font(plogfont, fontname);
+#else
+		if (!name)
+			name = MWFONT_SYSTEM_VAR;
+		strcpy(fontname, name);
+		fontclass = MWLF_CLASS_ANY;
+#endif
+		height = plogfont->lfHeight;
+		if (plogfont->lfUnderline)
+			fontattr = MWTF_UNDERLINE;
+	}
+	height = abs(height);
+ 
+ 	if (!fontclass)
+ 		goto first;
+ 
+	/* use builtin screen fonts, FONT_xxx, if height is 0 */
+ 	if (height == 0 || fontclass == MWLF_CLASS_ANY ||
+	    fontclass == MWLF_CLASS_BUILTIN) {
+  		for(i = 0; i < scrinfo.fonts; ++i) {
+ 			if(!strcmpi(pf[i].name, fontname)) {
+  				pf[i].fontsize = pf[i].cfont->height;
+				pf[i].fontattr = fontattr;
+  				return (PMWFONT)&pf[i];
+  			}
+  		}
+ 
+		/* return first builtin font*/
+		if (height == 0 || fontclass == MWLF_CLASS_BUILTIN)
+			goto first;
+  	}
+
+#if HAVE_HZK_SUPPORT
+        /* Make sure the library is initialized */
+	if (hzk_init(psd)) {
+		pfont = (PMWFONT)hzk_createfont(name, height, fontattr);
+		if(pfont)		
+			return pfont;
+		fprintf(stderr, "hzk_createfont: %s not found\n", name);
+	}
+#endif
+
+#if HAVE_FREETYPE_SUPPORT
+ 	if (fontclass == MWLF_CLASS_ANY || fontclass == MWLF_CLASS_FREETYPE) {
+		if (freetype_init(psd)) {
+		/* auto antialias for height > 14 for kaffe*/
+			if (plogfont && plogfont->lfHeight > 14 &&
+				plogfont->lfQuality)
+					fontattr |= MWTF_ANTIALIAS;
+
+			pfont = (PMWFONT)freetype_createfont(fontname, height,
+					fontattr);
+			if(pfont) {
+				/* temp kaffe kluge*/
+				pfont->fontattr |= FS_FREETYPE;
+				return pfont;
+			}
+ 			DPRINTF("freetype_createfont: %s,%d not found\n",
+				fontname, height);
+		}
+  	}
+#endif
+
+#if HAVE_T1LIB_SUPPORT
+	if (fontclass == MWLF_CLASS_ANY || fontclass == MWLF_CLASS_T1LIB) {
+		if (t1lib_init(psd)) {
+			pfont = (PMWFONT)t1lib_createfont(fontname, height,
+					fontattr);
+			if(pfont)
+				return pfont;
+			DPRINTF("t1lib_createfont: %s,%d not found\n",
+				fontname, height);
+		}
+  	}
+#endif
+
+	/* find builtin font closest in height*/
+	if(height != 0) {
+		fontno = 0;
+		height = abs(height);
+		fontht = MAX_MWCOORD;
+		for(i = 0; i < scrinfo.fonts; ++i) {
+			pfont = (PMWFONT)&pf[i];
+			GdGetFontInfo(pfont, &fontinfo);
+			if(fontht > abs(height-fontinfo.height)) { 
+				fontno = i;
+				fontht = abs(height-fontinfo.height);
+			}
+		}
+		pf[fontno].fontsize = pf[fontno].cfont->height;
+		pf[fontno].fontattr = fontattr;
+		return (PMWFONT)&pf[fontno];
+	}
+
+first:
+	/* Return first builtin font*/
+	pf->fontsize = pf->cfont->height;
+	pf->fontattr = fontattr;
+	return (PMWFONT)&pf[0];
+}
+
+/* Set the font size for the passed font*/
+MWCOORD
+GdSetFontSize(PMWFONT pfont, MWCOORD fontsize)
+{
+	MWCOORD	oldfontsize = pfont->fontsize;
+
+	pfont->fontsize = fontsize;
+
+	if (pfont->fontprocs->SetFontSize)
+	    pfont->fontprocs->SetFontSize(pfont, fontsize);
+
+	return oldfontsize;
+}
+
+/* Set the font rotation angle in tenths of degrees for the passed font*/
+int
+GdSetFontRotation(PMWFONT pfont, int tenthdegrees)
+{
+	MWCOORD	oldrotation = pfont->fontrotation;
+
+	pfont->fontrotation = tenthdegrees;
+
+	if (pfont->fontprocs->SetFontRotation)
+	    pfont->fontprocs->SetFontRotation(pfont, tenthdegrees);
+	
+	return oldrotation;
+}
+
+/*
+ * Set/reset font attributes (MWTF_KERNING, MWTF_ANTIALIAS)
+ * for the passed font.
+ */
+int
+GdSetFontAttr(PMWFONT pfont, int setflags, int clrflags)
+{
+	MWCOORD	oldattr = pfont->fontattr;
+
+	pfont->fontattr &= ~clrflags;
+	pfont->fontattr |= setflags;
+
+	if (pfont->fontprocs->SetFontAttr)
+	    pfont->fontprocs->SetFontAttr(pfont, setflags, clrflags);
+	
+	return oldattr;
+}
+
+/* Unload and deallocate font*/
+void
+GdDestroyFont(PMWFONT pfont)
+{
+	if (pfont->fontprocs->DestroyFont)
+		pfont->fontprocs->DestroyFont(pfont);
+}
+
+/* Return information about a specified font*/
+MWBOOL
+GdGetFontInfo(PMWFONT pfont, PMWFONTINFO pfontinfo)
+{
+	if(!pfont || !pfont->fontprocs->GetFontInfo)
+		return FALSE;
+
+	return pfont->fontprocs->GetFontInfo(pfont, pfontinfo);
+}
+
+/*
+ * Convert from one encoding to another
+ * Input cc and returned cc is character count, not bytes
+ * Return < 0 on error or can't translate
+ */
+int
+GdConvertEncoding(const void *istr, int iflags, int cc, void *ostr, int oflags)
+{
+	const unsigned char 	*istr8;
+	const unsigned short 	*istr16;
+	const unsigned long	*istr32;
+	unsigned char 		*ostr8;
+	unsigned short 		*ostr16;
+	unsigned long		*ostr32;
+	unsigned int		ch;
+	int			icc;
+	unsigned short		buf16[512];
+
+	iflags &= MWTF_PACKMASK;
+	oflags &= MWTF_PACKMASK;
+
+	/* allow -1 for len with ascii*/
+	if(cc == -1 && (iflags == MWTF_ASCII))
+		cc = strlen((char *)istr);
+
+	/* first check for utf8 input encoding*/
+	if(iflags == MWTF_UTF8) {
+		/* we've only got uc16 now so convert to uc16...*/
+		cc = utf8_to_utf16((unsigned char *)istr, cc,
+			oflags==MWTF_UC16?(unsigned short*) ostr: buf16);
+
+		if(oflags == MWTF_UC16 || cc < 0)
+			return cc;
+
+		/* will decode again to requested format (probably ascii)*/
+		iflags = MWTF_UC16;
+		istr = buf16;
+	}
+
+#if HAVE_HZK_SUPPORT
+	if(iflags == MWTF_UC16 && oflags == MWTF_ASCII) {
+		/* only support uc16 convert to ascii now...*/
+		cc = UC16_to_GB( istr, cc, ostr);
+		return cc;
+	}
+#endif
+
+	icc = cc;
+	istr8 = istr;
+	istr16 = istr;
+	istr32 = istr;
+	ostr8 = ostr;
+	ostr16 = ostr;
+	ostr32 = ostr;
+
+	/* Convert between formats.  Note that there's no error
+	 * checking here yet.
+	 */
+	while(--icc >= 0) {
+		switch(iflags) {
+		default:
+			ch = *istr8++;
+			break;
+		case MWTF_UC16:
+			ch = *istr16++;
+			break;
+		case MWTF_UC32:
+			ch = *istr32++;
+		}
+		switch(oflags) {
+		default:
+			*ostr8++ = (unsigned char)ch;
+			break;
+		case MWTF_UC16:
+			*ostr16++ = (unsigned short)ch;
+			break;
+		case MWTF_UC32:
+			*ostr32++ = ch;
+		}
+	}
+	return cc;
+}
+
+/* Get the width and height of passed text string in the passed font*/
+void
+GdGetTextSize(PMWFONT pfont, const void *str, int cc, MWCOORD *pwidth,
+	MWCOORD *pheight, MWCOORD *pbase, int flags)
+{
+	const void *	text;
+	unsigned long	buf[256];
+	int		defencoding = pfont->fontprocs->encoding;
+
+	/* convert encoding if required*/
+	if((flags & MWTF_PACKMASK) != defencoding) {
+		cc = GdConvertEncoding(str, flags, cc, buf, defencoding);
+		flags &= ~MWTF_PACKMASK;
+		flags |= defencoding;
+		text = buf;
+	} else text = str;
+
+	if(cc == -1 && (flags & MWTF_PACKMASK) == MWTF_ASCII)
+		cc = strlen((char *)str);
+
+	if(cc <= 0 || !pfont->fontprocs->GetTextSize) {
+		*pwidth = *pheight = *pbase = 0;
+		return;
+	}
+
+	/* calc height and width of string*/
+	pfont->fontprocs->GetTextSize(pfont, text, cc, pwidth, pheight, pbase);
+}
+
+/* Draw a text string at a specifed coordinates in the foreground color
+ * (and possibly the background color), applying clipping if necessary.
+ * The background color is only drawn if the gr_usebg flag is set.
+ * Use the current font.
+ */
+void
+GdText(PSD psd, MWCOORD x, MWCOORD y, const void *str, int cc, int flags)
+{
+	const void *	text;
+	unsigned long	buf[256];
+	int		defencoding = gr_pfont->fontprocs->encoding;
+
+	/* convert encoding if required*/
+	if((flags & MWTF_PACKMASK) != defencoding) {
+		cc = GdConvertEncoding(str, flags, cc, buf, defencoding);
+		flags &= ~MWTF_PACKMASK;
+		flags |= defencoding;
+		text = buf;
+	} else text = str;
+
+	if(cc == -1 && (flags & MWTF_PACKMASK) == MWTF_ASCII)
+		cc = strlen((char *)str);
+
+	if(cc <= 0 || !gr_pfont->fontprocs->DrawText)
+		return;
+
+	/* draw text string*/
+	gr_pfont->fontprocs->DrawText(gr_pfont, psd, x, y, text, cc, flags);
+}
+
+/*
+ * Draw ascii text using COREFONT type font.
+ */
+void
+corefont_drawtext(PMWFONT pfont, PSD psd, MWCOORD x, MWCOORD y,
+	const void *text, int cc, int flags)
+{
+	const unsigned char *str = text;
+	MWCOORD		width;			/* width of text area */
+	MWCOORD 	height;			/* height of text area */
+	MWCOORD		base;			/* baseline of text*/
+	MWCOORD		startx, starty;
+						/* bitmap for characters */
+	MWIMAGEBITS bitmap[MAX_CHAR_HEIGHT*MAX_CHAR_WIDTH/MWIMAGE_BITSPERIMAGE];
+
+	pfont->fontprocs->GetTextSize(pfont, str, cc, &width, &height, &base);
+	
+	if(flags & MWTF_BASELINE)
+		y -= base;
+	else if(flags & MWTF_BOTTOM)
+		y -= (height - 1);
+	startx = x;
+	starty = y + base;
+
+	switch (GdClipArea(psd, x, y, x + width - 1, y + height - 1)) {
+	case CLIP_VISIBLE:
+		/*
+		 * For size considerations, there's no low-level text
+		 * draw, so we've got to draw all text
+		 * with per-point clipping for the time being
+		if (gr_usebg)
+			psd->FillRect(psd, x, y, x + width - 1, y + height - 1,
+				gr_background);
+		psd->DrawText(psd, x, y, str, cc, gr_foreground, pfont);
+		GdFixCursor(psd);
+		return;
+		*/
+		break;
+
+	case CLIP_INVISIBLE:
+		return;
+	}
+
+	/* Get the bitmap for each character individually, and then display
+	 * them using clipping for each one.
+	 */
+	while (--cc >= 0 && x < psd->xvirtres) {
+		unsigned int ch = *str++;
+#if HAVE_BIG5_SUPPORT
+		/* chinese big5 decoding*/
+		if (ch >= 0xA1 && ch <= 0xF9 && cc >= 1 &&
+			((*str >= 0x40 && *str <= 0x7E) ||
+			 (*str >= 0xA1 && *str <= 0xFE)) ) {
+				ch = (ch << 8) | *str++;
+				--cc;
+		}
+#endif
+#if HAVE_GB2312_SUPPORT
+		/* chinese gb2312 decoding*/
+		if (ch >= 0xA1 && ch < 0xF8 && cc >= 1 &&
+			*str >= 0xA1 && *str < 0xFF) {
+				ch = (ch << 8) | *str++;
+				--cc;
+		}
+#endif
+#if HAVE_KSC5601_SUPPORT
+		/* Korean KSC5601 decoding */
+		if (ch >= 0xA1 && ch <= 0xFE && cc >= 1 &&
+			 (*str >= 0xA1 && *str <= 0xFE)) {
+				ch = (ch << 8) | *str++;
+				--cc;
+		}
+#endif
+		pfont->fontprocs->GetTextBits(pfont, ch, bitmap, &width,
+			&height, &base);
+
+		/* note: change to bitmap*/
+		GdBitmap(psd, x, y, width, height, bitmap);
+		x += width;
+	}
+
+	if (pfont->fontattr & MWTF_UNDERLINE)
+		GdLine(psd, startx, starty, x, starty, FALSE);
+
+	GdFixCursor(psd);
+}
+
+#if HAVE_T1LIB_SUPPORT | HAVE_FREETYPE_SUPPORT
+/*
+ * Produce blend table from src and dst based on passed alpha table
+ * Used because we don't quite yet have GdArea with alphablending,
+ * so we pre-blend fg/bg colors for fade effect.
+ */
+static void
+alphablend(PSD psd, OUTPIXELVAL *out, MWPIXELVAL src, MWPIXELVAL dst,
+	unsigned char *alpha, int count)
+{
+	unsigned int	a, d;
+	unsigned char	r, g, b;
+	MWCOLORVAL	palsrc, paldst;
+	extern MWPALENTRY gr_palette[256];
+
+	while (--count >= 0) {
+	    a = *alpha++;
+
+#define BITS(pixel,shift,mask)	(((pixel)>>shift)&(mask))
+	    if(a == 0)
+		*out++ = dst;
+	    else if(a == 255)
+		*out++ = src;
+	    else 
+		switch(psd->pixtype) {
+	        case MWPF_TRUECOLOR0888:
+	        case MWPF_TRUECOLOR888:
+		    d = BITS(dst, 16, 0xff);
+		    r = (unsigned char)(((BITS(src, 16, 0xff) - d)*a)>>8) + d;
+		    d = BITS(dst, 8, 0xff);
+		    g = (unsigned char)(((BITS(src, 8, 0xff) - d)*a)>>8) + d;
+		    d = BITS(dst, 0, 0xff);
+		    b = (unsigned char)(((BITS(src, 0, 0xff) - d)*a)>>8) + d;
+		    *out++ = (r << 16) | (g << 8) | b;
+		    break;
+
+	        case MWPF_TRUECOLOR565:
+		    d = BITS(dst, 11, 0x1f);
+		    r = (unsigned char)(((BITS(src, 11, 0x1f) - d)*a)>>8) + d;
+		    d = BITS(dst, 5, 0x3f);
+		    g = (unsigned char)(((BITS(src, 5, 0x3f) - d)*a)>>8) + d;
+		    d = BITS(dst, 0, 0x1f);
+		    b = (unsigned char)(((BITS(src, 0, 0x1f) - d)*a)>>8) + d;
+		    *out++ = (r << 11) | (g << 5) | b;
+		    break;
+
+	        case MWPF_TRUECOLOR555:
+		    d = BITS(dst, 10, 0x1f);
+		    r = (unsigned char)(((BITS(src, 10, 0x1f) - d)*a)>>8) + d;
+		    d = BITS(dst, 5, 0x1f);
+		    g = (unsigned char)(((BITS(src, 5, 0x1f) - d)*a)>>8) + d;
+		    d = BITS(dst, 0, 0x1f);
+		    b = (unsigned char)(((BITS(src, 0, 0x1f) - d)*a)>>8) + d;
+		    *out++ = (r << 10) | (g << 5) | b;
+		    break;
+
+	        case MWPF_TRUECOLOR332:
+		    d = BITS(dst, 5, 0x07);
+		    r = (unsigned char)(((BITS(src, 5, 0x07) - d)*a)>>8) + d;
+		    d = BITS(dst, 2, 0x07);
+		    g = (unsigned char)(((BITS(src, 2, 0x07) - d)*a)>>8) + d;
+		    d = BITS(dst, 0, 0x03);
+		    b = (unsigned char)(((BITS(src, 0, 0x03) - d)*a)>>8) + d;
+		    *out++ = (r << 5) | (g << 2) | b;
+		    break;
+
+	        case MWPF_PALETTE:
+		    /* reverse lookup palette entry for blend ;-)*/
+		    palsrc = GETPALENTRY(gr_palette, src);
+		    paldst = GETPALENTRY(gr_palette, dst);
+		    d = REDVALUE(paldst);
+		    r = (unsigned char)(((REDVALUE(palsrc) - d)*a)>>8) + d;
+		    d = GREENVALUE(paldst);
+		    g = (unsigned char)(((GREENVALUE(palsrc) - d)*a)>>8) + d;
+		    d = BLUEVALUE(paldst);
+		    b = (unsigned char)(((BLUEVALUE(palsrc) - d)*a)>>8) + d;
+		    *out++ = GdFindNearestColor(gr_palette, (int)psd->ncolors,
+				MWRGB(r, g, b));
+		    break;
+	  	}
+	}
+}
+#endif /*HAVE_T1LIB_SUPPORT | HAVE_FREETYPE_SUPPORT*/
+
+#if HAVE_T1LIB_SUPPORT
+/* contributed by Vidar Hokstad*/
+
+static int
+t1lib_init(PSD psd)
+{
+	char **encoding;
+	static int inited = 0;
+
+	if (inited)
+		return 1;
+
+	T1_SetBitmapPad(8);
+	if (!T1_InitLib(0))
+		return 0;
+
+	/* set default Latin1 encoding*/
+	encoding = T1_LoadEncoding("IsoLatin1.enc");
+	T1_SetDefaultEncoding(encoding);
+
+#ifdef T1LIB_USE_AA_HIGH	 
+	T1_AASetLevel(T1_AA_HIGH);
+#else
+	T1_AASetLevel(T1_AA_LOW);
+#endif	 
+#if 0
+	/* kluge: this is required if 16bpp drawarea driver is used*/
+	if(psd->bpp == 16)
+		T1_AASetBitsPerPixel(16);
+	else
+#endif
+		T1_AASetBitsPerPixel(sizeof(MWPIXELVAL)*8);
+
+	inited = 1;
+	return 1;
+}
+
+static PMWT1LIBFONT
+t1lib_createfont(const char *name, MWCOORD height, int attr)
+{
+	PMWT1LIBFONT	pf;
+	int		id;
+	char *		p;
+	char		buf[256];
+
+	/* match name against t1 font id's from t1 font database*/
+	for(id=0; id<T1_Get_no_fonts(); ++id) {
+		strncpy(buf, T1_GetFontFileName(id), sizeof(buf));
+
+		/* remove extension*/
+		for(p=buf; *p; ++p) {
+			if(*p == '.') {
+				*p = 0;
+				break;
+			}
+		}
+
+		if(!strcmpi(name, buf)) {
+			/* allocate font structure*/
+			pf = (PMWT1LIBFONT)calloc(sizeof(MWT1LIBFONT), 1);
+			if (!pf)
+				return NULL;
+			pf->fontprocs = &t1lib_procs;
+			GdSetFontSize((PMWFONT)pf, height);
+			GdSetFontRotation((PMWFONT)pf, 0);
+			GdSetFontAttr((PMWFONT)pf, attr, 0);
+			pf->fontid = id;
+			return pf;
+		}
+	}
+	return NULL;
+}
+
+/*
+ * Draw ascii text string using T1LIB type font
+ */
+static void
+t1lib_drawtext(PMWFONT pfont, PSD psd, MWCOORD x, MWCOORD y,
+	const void *text, int cc, int flags)
+{
+	PMWT1LIBFONT	pf = (PMWT1LIBFONT)pfont;
+	const unsigned char *str = text;
+   	MWCOORD		width;			/* width of text area */
+	MWCOORD 	height;			/* height of text area */
+	MWCOORD		underliney;
+        GLYPH * g; /* T1lib glyph structure. Memory handling by T1lib */
+#ifdef T1LIB_USE_AA_HIGH   
+        OUTPIXELVAL	gvals[17];
+
+        /* Blending array for antialiasing. The steeper the values increase
+	 * near the end, the sharper the characters look, but also more jagged
+	 */
+        static unsigned char blend[17] = {
+	   0x00, 0x00, 0x04, 0x0c, 0x10, 0x14, 0x18, 0x20,
+	   0x30, 0x38, 0x40, 0x50, 0x70, 0x80, 0xa0, 0xc0, 0xff
+	};
+#else   
+        OUTPIXELVAL	gvals[5];
+        static unsigned char blend[5] = { 0x00, 0x44, 0x88, 0xcc, 0xff };
+#endif   
+
+        /* Check if we should throw out some fonts */
+
+        if (pf->fontattr&MWTF_ANTIALIAS) {
+#ifdef T1LIB_USE_AA_HIGH      
+	   alphablend(psd, gvals, gr_foreground, gr_background, blend, 17);
+           T1_AAHSetGrayValues(gvals);
+#else      
+	   alphablend(psd, gvals, gr_foreground, gr_background, blend, 5);
+           T1_AASetGrayValues(gvals[0],gvals[1],gvals[2],gvals[3],gvals[4]);
+#endif
+	   g = T1_AASetString(pf->fontid,(char *)str,cc,0,
+		(pf->fontattr&MWTF_KERNING)? T1_KERNING: 0,
+		pf->fontsize * 1.0, 0);
+
+	   if (g && g->bits) {
+	      /*MWPIXELVAL save = gr_background;*/
+	      width = g->metrics.rightSideBearing - g->metrics.leftSideBearing;
+	      height = g->metrics.ascent - g->metrics.descent;
+
+	      if(flags & MWTF_BASELINE)
+		y -= g->metrics.ascent;
+	      else if(flags & MWTF_BOTTOM)
+		y -= (height - 1);
+	      underliney = y + g->metrics.ascent;
+
+	      /* FIXME: Looks damn ugly if usebg is false.
+	       * Will be handled when using alphablending in GdArea...
+	       */
+	      /* clipping handled in GdArea*/
+	      /*FIXME kluge for transparency*/
+	      /*gr_background = gr_foreground + 1;*/
+	      /*gr_usebg = 0;*/
+	      GdArea(psd,x,y, width, height, g->bits, MWPF_PIXELVAL);
+	      /*gr_background = save;*/
+
+	      if (pf->fontattr & MWTF_UNDERLINE)
+		   GdLine(psd, x, underliney, x+width, underliney, FALSE);
+
+	   }
+	} else {
+	   /* Do non-aa drawing */
+	   g = T1_SetString(pf->fontid,(char *)str,cc,0,
+			(pf->fontattr&MWTF_KERNING)? T1_KERNING: 0,
+			pf->fontsize * 1.0, 0);
+
+	   if (g && g->bits) {
+	      unsigned char * b;
+	      int xoff;
+	      int maxy;
+	      int xmod;
+	      
+	      /* I'm sure this sorry excuse for a bitmap rendering routine can
+	       * be optimized quite a bit ;)
+	       */
+	      width = g->metrics.rightSideBearing - g->metrics.leftSideBearing;
+	      height = g->metrics.ascent - g->metrics.descent;
+
+	      if(flags & MWTF_BASELINE)
+		y -= g->metrics.ascent;
+	      else if(flags & MWTF_BOTTOM)
+		y -= (height - 1);
+	      underliney = y + g->metrics.ascent;
+	      
+	      b = g->bits;
+	      maxy = y + height;
+	      
+/*	      if ((x + width) > psd->xvirtres) {
+		 xmod = (x + width - psd->xvirtres + 7) >> 3;
+		 width = width + x + width - psd->xvirtres;
+	      } else xmod = 0;
+*/
+	      xmod = 0;
+	      while (y < maxy) {
+		 unsigned char data;
+		 xoff = 0;
+		 while (xoff < width ) {
+		    if (!(xoff % 8)) {
+		       data = *b;
+		       b++;
+		    }
+		    
+		    if (GdClipPoint(psd, x+xoff,y)) {
+		       if (gr_usebg) {
+	 		  psd->DrawPixel(psd,x+xoff,y,
+			      data & (1 << (xoff % 8)) ?
+			            gr_foreground : gr_background);
+		       } else if (data & (1 << (xoff % 8))) {
+			  psd->DrawPixel(psd,x+xoff,y, gr_foreground);
+		       }
+		    }
+		    xoff++;
+		 }
+		 b += xmod;
+		 y++;
+	      }
+	      if (pf->fontattr & MWTF_UNDERLINE)
+		   GdLine(psd, x, underliney, x+xoff, underliney, FALSE);
+	   }
+        }
+
+   if (g && g->bits) {
+	   /* Save some memory */
+	   free(g->bits);
+           g->bits = 0; /* Make sure T1lib doesnt try to free it again */
+   }
+
+   GdFixCursor(psd);
+}
+
+static MWBOOL
+t1lib_getfontinfo(PMWFONT pfont, PMWFONTINFO pfontinfo)
+{
+	int	i;
+	MWCOORD	width, height, baseline;
+
+	/* FIXME, guess all sizes*/
+	GdGetTextSize(pfont, "A", 1, &width, &height, &baseline, MWTF_ASCII);
+	pfontinfo->height = height;
+	pfontinfo->maxwidth = width;
+	pfontinfo->baseline = 0;
+	pfontinfo->firstchar = 32;
+	pfontinfo->lastchar = 255;
+	pfontinfo->fixed = TRUE;
+	for(i=0; i<256; ++i)
+		pfontinfo->widths[i] = width;
+	return TRUE;
+}
+
+/* Get the width and height of passed text string in the current font*/
+static void
+t1lib_gettextsize(PMWFONT pfont, const void *text, int cc,
+	MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase)
+{
+	PMWT1LIBFONT		pf = (PMWT1LIBFONT)pfont;
+	const unsigned char *	str = text;
+	GLYPH *			g;
+
+	g = T1_SetString(pf->fontid, (char *)str, cc, 0,
+			(pf->fontattr&MWTF_KERNING)? T1_KERNING: 0, pf->fontsize * 1.0, 0);
+	*pwidth = g->metrics.rightSideBearing - g->metrics.leftSideBearing;
+	*pheight = g->metrics.ascent - g->metrics.descent;
+	if(g && g->bits) {
+		free(g->bits);
+		g->bits = 0;
+	}
+#if 0
+	BBox 			b;
+
+	/* FIXME. Something is *VERY* wrong here */
+	b = T1_GetStringBBox(pf->fontid, str, cc, 0, (pf->fontattr&MWTF_KERNING)?T1_KERNING:0);
+
+	DPRINTF("b.urx = %d, b.llx = %d\n",b.urx, b.llx);
+	DPRINTF("b.ury = %d, b.lly = %d\n",b.ury, b.lly);
+	*pwidth = (b.urx - b.llx);
+	*pheight = (b.lly - b.ury);
+#endif
+}
+
+static void
+t1lib_destroyfont(PMWFONT pfont)
+{
+	PMWT1LIBFONT	pf = (PMWT1LIBFONT)pfont;
+
+	T1_DeleteAllSizes(pf->fontid);
+	free(pf);
+}
+
+#endif /* HAVE_T1LIB_SUPPORT*/
+
+#if HAVE_FREETYPE_SUPPORT
+static OUTPIXELVAL gray_palette[5];
+
+static int
+freetype_init(PSD psd)
+{
+	static int inited = 0;
+
+	if (inited)
+		return 1;
+	
+	/* Init freetype library */
+	if (TT_Init_FreeType (&engine) != TT_Err_Ok) {
+		return 0;
+	}
+
+	/* Init kerning extension */
+	if (TT_Init_Kerning_Extension (engine) != TT_Err_Ok)
+		return 0;
+
+	inited = 1;
+	return 1;
+}
+
+static PMWFREETYPEFONT
+freetype_createfont(const char *name, MWCOORD height, int attr)
+{
+	PMWFREETYPEFONT 	pf;
+	unsigned short 		i, n;
+	unsigned short 		platform, encoding;
+	TT_Face_Properties 	properties;
+	char *			p;
+	char			fontname[128];
+
+	/* check for pathname prefix*/
+	if (strchr(name, '/') != NULL)
+		strcpy(fontname, name);
+	else {
+		strcpy(fontname, FREETYPE_FONT_DIR);
+		strcat(fontname, "/");
+		strcat(fontname, name);
+	}
+
+	/* check for extension*/
+	if ((p = strrchr(fontname, '.')) == NULL ||
+	    strcmp(p, ".ttf") != 0) {
+		strcat(fontname, ".ttf");
+	}
+
+	/* allocate font structure*/
+	pf = (PMWFREETYPEFONT)calloc(sizeof(MWFREETYPEFONT), 1);
+	if (!pf)
+		return NULL;
+	pf->fontprocs = &freetype_procs;
+
+	/* Load face */
+	if (TT_Open_Face (engine, fontname, &pf->face) != TT_Err_Ok)
+		goto out;
+
+	/* Load first kerning table */
+	pf->can_kern = TRUE;
+	if (TT_Load_Kerning_Table (pf->face, 0) != TT_Err_Ok)
+		pf->can_kern = FALSE;
+	else {
+		if (TT_Get_Kerning_Directory (pf->face, &pf->directory)
+		    != TT_Err_Ok)
+			pf->can_kern = FALSE;
+		else {
+			/* Support only version 0 kerning table ... */
+			if ((pf->directory.version != 0) ||
+				(pf->directory.nTables <= 0) ||
+				(pf->directory.tables->loaded != 1) ||
+				(pf->directory.tables->version != 0) ||
+				(pf->directory.tables->t.kern0.nPairs <= 0))
+					pf->can_kern = FALSE;
+		}
+	}
+
+	/* get face properties and allocate preload arrays */
+	TT_Get_Face_Properties (pf->face, &properties);
+
+#if 0
+	/*
+	 * Use header information for ascent and descent
+	 * to compute scaled ascent/descent for current font height.
+	 */
+	h = properties.os2->sTypoAscender - properties.os2->sTypoDescender
+		+ properties.os2->sTypoLineGap;
+	ascent = properties.os2->sTypoAscender
+		+ properties.os2->sTypoLineGap/2;
+	pf->ascent = (ascent * height + h/2) / h;
+	pf->descent = height - pf->ascent;
+#endif
+	/* Create a glyph container */
+	if (TT_New_Glyph (pf->face, &pf->glyph) != TT_Err_Ok)
+		goto out;
+
+	/* create instance */
+	if (TT_New_Instance (pf->face, &pf->instance) != TT_Err_Ok)
+		goto out;
+
+	/* Set the instance resolution */
+	if (TT_Set_Instance_Resolutions (pf->instance, 96, 96) != TT_Err_Ok)
+		goto out;
+
+	/* Look for a Unicode charmap: Windows flavor of Apple flavor only */
+	n = properties.num_CharMaps;
+
+	for (i = 0; i < n; i++) {
+		TT_Get_CharMap_ID (pf->face, i, &platform, &encoding);
+		if (((platform == TT_PLATFORM_MICROSOFT) &&
+			(encoding == TT_MS_ID_UNICODE_CS)) ||
+				((platform == TT_PLATFORM_APPLE_UNICODE) &&
+			 		(encoding == TT_APPLE_ID_DEFAULT)))
+		{
+			TT_Get_CharMap (pf->face, i, &pf->char_map);
+			i = n + 1;
+		}
+	}
+	if (i == n) {
+		DPRINTF("freetype_createfont: no unicode map table\n");
+		goto out;
+	}
+	
+	GdSetFontSize((PMWFONT)pf, height);
+	GdSetFontRotation((PMWFONT)pf, 0);
+	GdSetFontAttr((PMWFONT)pf, attr, 0);
+
+	return pf;
+
+out:
+	free(pf);
+	return NULL;
+}
+
+static int
+compute_kernval(PMWFREETYPEFONT pf, short current_glyph_code)
+{
+	int 		i = 0;
+	int 		kernval;
+	int 		nPairs = pf->directory.tables->t.kern0.nPairs;
+	TT_Kern_0_Pair *pair = pf->directory.tables->t.kern0.pairs;
+
+	if (pf->last_glyph_code != -1) {
+		while ((pair->left != pf->last_glyph_code)
+			&& (pair->right != current_glyph_code))
+		{
+			pair++;
+			i++;
+			if (i == nPairs)
+			break;
+		}
+
+		if (i == nPairs)
+			kernval = 0;
+		else
+			/* We round the value (hence the +32) */
+			kernval = (pair->value + 32) & -64;
+	} else
+		kernval = 0;
+
+	return kernval;
+}
+
+static TT_UShort
+Get_Glyph_Width(PMWFREETYPEFONT pf, TT_UShort glyph_index)
+{
+	TT_Glyph_Metrics metrics;
+	
+    	if (TT_Load_Glyph ( pf->instance, pf->glyph,
+		TT_Char_Index (pf->char_map,glyph_index),
+		TTLOAD_SCALE_GLYPH|TTLOAD_HINT_GLYPH) != TT_Err_Ok)
+    	{
+		/* Try to load default glyph: index 0 */
+		if (TT_Load_Glyph ( pf->instance, pf->glyph, 0,
+			TTLOAD_SCALE_GLYPH|TTLOAD_HINT_GLYPH) != TT_Err_Ok)
+		    return 0;
+	}
+
+	TT_Get_Glyph_Metrics (pf->glyph, &metrics);
+	return((metrics.advance & 0xFFFFFFC0) >> 6);
+}
+
+/* Render a single glyph*/
+static void
+drawchar(PMWFREETYPEFONT pf, PSD psd, TT_Glyph glyph, int x_offset,
+	int y_offset)
+{
+	TT_F26Dot6 	xmin, ymin, xmax, ymax, x, y, z;
+	unsigned char 	*src, *srcptr;
+	MWPIXELVAL 	*dst, *dstptr;
+	MWPIXELVAL 	*bitmap;
+	int 		size, width, height;
+	TT_Outline 	outline;
+	TT_BBox 	bbox;
+	TT_Raster_Map 	Raster;
+	TT_Error 	error;
+	/*MWPIXELVAL 	save;*/
+
+	/* we begin by grid-fitting the bounding box */
+	TT_Get_Glyph_Outline (pf->glyph, &outline);
+	TT_Get_Outline_BBox (&outline, &bbox);
+
+	xmin = (bbox.xMin & -64) >> 6;
+	ymin = (bbox.yMin & -64) >> 6;
+	xmax = ((bbox.xMax + 63) & -64) >> 6;
+	ymax = ((bbox.yMax + 63) & -64) >> 6;
+	width = xmax - xmin;
+	height = ymax - ymin;
+	size = width * height;
+
+	/* now re-allocate the raster bitmap */
+	Raster.rows = height;
+	Raster.width = width;
+
+	if (pf->fontattr&MWTF_ANTIALIAS)
+		Raster.cols = (Raster.width + 3) & -4;	/* pad to 32-bits */
+	else
+		Raster.cols = (Raster.width + 7) & -8;	/* pad to 64-bits ??? */
+
+	Raster.flow = TT_Flow_Up;
+	Raster.size = Raster.rows * Raster.cols;
+	Raster.bitmap = malloc (Raster.size);
+
+	memset (Raster.bitmap, 0, Raster.size);
+
+	/* now render the glyph in the small pixmap */
+
+	/* IMPORTANT NOTE: the offset parameters passed to the function     */
+	/* TT_Get_Glyph_Bitmap() must be integer pixel values, i.e.,        */
+	/* multiples of 64.  HINTING WILL BE RUINED IF THIS ISN'T THE CASE! */
+	/* This is why we _did_ grid-fit the bounding box, especially xmin  */
+	/* and ymin.                                                        */
+
+	if (!(pf->fontattr&MWTF_ANTIALIAS))
+		error = TT_Get_Glyph_Bitmap (pf->glyph, &Raster,
+				-xmin * 64, -ymin * 64);
+	else
+		error = TT_Get_Glyph_Pixmap (pf->glyph, &Raster,
+				-xmin * 64, -ymin * 64);
+
+	if (error) {
+		free (Raster.bitmap);
+		return;
+	}
+
+	bitmap = malloc (size * sizeof (MWPIXELVAL));
+	memset (bitmap, 0, size * sizeof (MWPIXELVAL));
+
+	src = (char *) Raster.bitmap;
+	dst = bitmap + (size - width);
+
+	for (y = ymin; y < ymax; y++) {
+		srcptr = src;
+		dstptr = dst;
+
+		for (x = xmin; x < xmax; x++) {
+			if (pf->fontattr&MWTF_ANTIALIAS)
+				*dstptr++ = gray_palette[(int) *srcptr];
+			else {
+				for(z=0;
+				    z <= ((xmax-x-1) < 7 ? (xmax-x-1) : 7);
+				    z++) {
+					*dstptr++ = ((*srcptr << z) & 0x80)?
+						gr_foreground: gr_background;
+				}
+				x += 7;
+			}
+
+			srcptr++;
+		}
+
+		src += Raster.cols;
+		dst -= width;
+	}
+
+	/* FIXME - must clear background upstairs if not gr_usebg*/
+	/* FIXME: GdArea problem if fg == bg*/
+	/*save = gr_background;*/
+	/*gr_background = gr_foreground + 1;*/
+
+	/* Now draw the bitmap ... */
+	GdArea(psd, x_offset + xmin, y_offset - (ymin + height), width, height,
+		bitmap, MWPF_PIXELVAL);
+
+	/*gr_background = save;*/
+
+	free (bitmap);
+	free (Raster.bitmap);
+}
+
+/*
+ * Draw unicode 16 text string using FREETYPE type font
+ */
+static void
+freetype_drawtext(PMWFONT pfont, PSD psd, MWCOORD ax, MWCOORD ay,
+	const void *text, int cc, int flags)
+{
+	PMWFREETYPEFONT	pf = (PMWFREETYPEFONT)pfont;
+	const unsigned short *	str = text;
+	TT_F26Dot6 	x = ax, y = ay;
+	TT_Pos 		vec_x, vec_y;
+	int 		i;
+	TT_F26Dot6	startx, starty;
+	TT_Outline 	outline;
+	TT_UShort 	curchar;
+	TT_Glyph_Metrics metrics;
+	TT_Face_Properties properties;
+	TT_Instance_Metrics imetrics;
+	TT_F26Dot6 ascent, descent;
+	static unsigned char blend[5] = { 0x00, 0x44, 0x88, 0xcc, 0xff };
+	static unsigned char virtual_palette[5] = { 0, 1, 2, 3, 4 };
+
+	pf->last_glyph_code = -1;		/* reset kerning*/
+	pf->last_pen_pos = -32767;
+
+	/* 
+	 * Compute instance ascent & descent values
+	 * in fractional units (1/64th pixel)
+	 */
+	TT_Get_Face_Properties (pf->face, &properties);
+	TT_Get_Instance_Metrics(pf->instance, &imetrics);	
+  
+	ascent = ((properties.horizontal->Ascender * imetrics.y_scale)/0x10000);
+	descent = ((properties.horizontal->Descender*imetrics.y_scale)/0x10000);
+
+	/* 
+	 * Offset the starting point if necessary,
+	 * FreeType always aligns at baseline
+	 */
+	if (flags&MWTF_BOTTOM) {
+		vec_x = 0;
+		vec_y = descent;
+		TT_Transform_Vector(&vec_x, &vec_y,&pf->matrix);
+		x -= vec_x / 64;
+		y += vec_y / 64;
+	} else if (flags&MWTF_TOP) {
+		vec_x = 0;
+		vec_y = ascent;
+		TT_Transform_Vector(&vec_x, &vec_y,&pf->matrix);
+		x -= vec_x / 64;
+		y += vec_y / 64;
+	}
+
+	/* Set the "graylevels" */
+	if (pf->fontattr&MWTF_ANTIALIAS) {
+		TT_Set_Raster_Gray_Palette (engine, virtual_palette);
+
+		alphablend(psd, gray_palette, gr_foreground, gr_background,
+			blend, 5);
+	}
+
+	startx = x;
+	starty = y;
+	for (i = 0; i < cc; i++) {
+		curchar = TT_Char_Index (pf->char_map, str[i]);
+
+		if (TT_Load_Glyph (pf->instance, pf->glyph, curchar,
+			TTLOAD_DEFAULT) != TT_Err_Ok)
+				continue;
+
+		if (pf->fontrotation) {
+			TT_Get_Glyph_Outline (pf->glyph, &outline);
+			TT_Transform_Outline (&outline, &pf->matrix);
+		}
+
+		TT_Get_Glyph_Metrics (pf->glyph, &metrics);
+
+		if ((pf->fontattr&MWTF_KERNING) && pf->can_kern) {
+			if (pf->fontrotation) {
+				vec_x = compute_kernval(pf, curchar);
+				vec_y = 0;
+				TT_Transform_Vector(&vec_x, &vec_y,&pf->matrix);
+
+				x += vec_x / 64;
+				y -= vec_y / 64;
+			} else
+				x += compute_kernval(pf, curchar) / 64;
+		}
+			
+		drawchar(pf, psd, pf->glyph, x, y);
+
+		if (pf->fontrotation) {
+			vec_x = metrics.advance;
+			vec_y = 0;
+			TT_Transform_Vector (&vec_x, &vec_y, &pf->matrix);
+
+			x += vec_x / 64;
+			y -= vec_y / 64;
+		} else {
+			x += metrics.advance / 64;
+
+			/* Kerning point syndrome avoidance */
+			if (pf->last_pen_pos > x)
+				x = pf->last_pen_pos;
+			pf->last_pen_pos = x;
+		}
+
+		pf->last_glyph_code = curchar;
+	}
+
+	if (pf->fontattr & MWTF_UNDERLINE)
+		GdLine(psd, startx, starty, x, y, FALSE);
+}
+
+/*
+ * Return information about a specified font.
+ */
+static MWBOOL
+freetype_getfontinfo(PMWFONT pfont, PMWFONTINFO pfontinfo)
+{
+	int	i;
+	PMWFREETYPEFONT	pf = (PMWFREETYPEFONT)pfont;
+	TT_Face_Properties 	properties;
+    TT_Instance_Metrics imetrics;
+    TT_UShort last_glyph_index;
+
+	TT_Get_Face_Properties (pf->face, &properties);
+    TT_Get_Instance_Metrics(pf->instance, &imetrics);
+
+    /* Fill up the fields */
+	pfontinfo->height = (((properties.horizontal->Ascender * \
+	                        imetrics.y_scale)/ 0x10000) >> 6) -
+	                    (((properties.horizontal->Descender * \
+	                        imetrics.y_scale)/ 0x10000) >> 6);
+	pfontinfo->maxwidth = ((properties.horizontal->xMax_Extent * \
+	                        imetrics.x_scale)/ 0x10000) >> 6;
+	pfontinfo->baseline = ((properties.horizontal->Ascender * \
+	                        imetrics.y_scale)/ 0x10000) >> 6;
+	pfontinfo->firstchar = TT_CharMap_First(pf->char_map, NULL);
+	pfontinfo->lastchar = TT_CharMap_Last(pf->char_map, NULL);
+	pfontinfo->fixed = properties.postscript->isFixedPitch;
+		
+    last_glyph_index = properties.num_Glyphs > 255 ? 255: properties.num_Glyphs-1;
+
+    /* Doesn't work ... don't know why ....*/
+#if 0
+    if (TT_Get_Face_Widths( pf->face, 0,
+                            last_glyph_index, widths, NULL ) != TT_Err_Ok) {
+        return TRUE;
+    }
+
+    for(i=0; i<=last_glyph_index; i++)
+		DPRINTF("widths[%d]: %d\n", i, widths[i]);
+#endif
+
+    /* Get glyphs widths */
+	for(i=0; i<=last_glyph_index; i++)
+		pfontinfo->widths[i] = Get_Glyph_Width(pf, i);
+
+#if 0
+    DPRINTF("x_ppem: %d\ny_ppem: %d\nx_scale: %d\ny_scale: %d\n\
+    x_resolution: %d\ny_resolution: %d\n",
+    imetrics.x_ppem, imetrics.y_ppem, imetrics.x_scale, \
+    imetrics.y_scale, imetrics.x_resolution, imetrics.y_resolution);
+
+    DPRINTF("Ascender: %d\nDescender: %d\nxMax_Extent: %d\n\
+    Mac Style Say Italic?: %d\nMac Style Say Bold?: %d\n\
+    sTypoAscender: %d\nsTypoDescender: %d\nusWinAscent: %d\n\
+    usWinDescent: %d\nusFirstCharIndex: %d\nusLastCharIndex: %d\n\
+    OS2 Say Italic?: %d\nOS2 Say Bold?: %d\nOS2 Say monospaced?: %d\n\
+    Postscript Say monospaced?: %d\n",\
+    properties.horizontal->Ascender,
+    properties.horizontal->Descender,
+    properties.horizontal->xMax_Extent,
+    (properties.header->Mac_Style & 0x2)?1:0,
+    (properties.header->Mac_Style & 0x1)?1:0,
+    properties.os2->sTypoAscender,
+    properties.os2->sTypoDescender,
+    properties.os2->usWinAscent,
+    properties.os2->usWinDescent,
+    properties.os2->usFirstCharIndex,
+    properties.os2->usLastCharIndex,
+    (properties.os2->fsSelection & 0x1)?1:0,
+    (properties.os2->fsSelection & 0x20)?1:0,
+    properties.postscript->isFixedPitch,
+    (properties.os2->panose[3] == 9)?1:0);
+#endif	
+			
+	return TRUE;
+}
+
+static void
+freetype_gettextsize(PMWFONT pfont, const void *text, int cc,
+	MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase)
+{
+	PMWFREETYPEFONT	pf = (PMWFREETYPEFONT)pfont;
+	const unsigned short *	str = text;
+	TT_F26Dot6 	x = 0;
+	int 		i;
+	TT_UShort 	curchar;
+	TT_Glyph_Metrics metrics;
+	TT_Face_Properties 	properties;
+	TT_Instance_Metrics imetrics;
+
+	TT_Get_Face_Properties (pf->face, &properties);
+	TT_Get_Instance_Metrics(pf->instance, &imetrics);
+	
+	pf->last_glyph_code = -1;		/* reset kerning*/
+	pf->last_pen_pos = -32767;
+	
+	for (i = 0; i < cc; i++) {
+		curchar = TT_Char_Index (pf->char_map, str[i]);
+
+		if (TT_Load_Glyph (pf->instance, pf->glyph, curchar,
+			TTLOAD_SCALE_GLYPH|TTLOAD_HINT_GLYPH) != TT_Err_Ok)
+				continue;
+
+		TT_Get_Glyph_Metrics (pf->glyph, &metrics);
+
+		if ((pf->fontattr&MWTF_KERNING) && pf->can_kern) {
+				x += compute_kernval(pf, curchar) / 64;
+		}
+		
+		x += metrics.advance / 64;
+
+		/* Kerning point syndrome avoidance */
+		if (pf->last_pen_pos > x)
+			x = pf->last_pen_pos;
+		pf->last_pen_pos = x;
+
+		pf->last_glyph_code = curchar;
+	}
+
+	*pwidth = x;
+	*pheight =  (((properties.horizontal->Ascender * 
+	                imetrics.y_scale)/ 0x10000) >> 6) -
+	            (((properties.horizontal->Descender * 
+	            imetrics.y_scale)/ 0x10000) >> 6);
+    	/* FIXME: is it what's required ?? */
+	*pbase = (((-properties.horizontal->Descender) * 
+	            imetrics.y_scale)/ 0x10000) >> 6;
+}
+
+static void
+freetype_destroyfont(PMWFONT pfont)
+{
+	PMWFREETYPEFONT	pf = (PMWFREETYPEFONT)pfont;
+
+	TT_Close_Face(pf->face);
+	free(pf);
+}
+
+static void
+freetype_setfontsize(PMWFONT pfont, MWCOORD fontsize)
+{
+	PMWFREETYPEFONT	pf = (PMWFREETYPEFONT)pfont;
+	
+	pf->fontsize = fontsize;
+	
+	/* We want real pixel sizes ... not points ...*/
+	TT_Set_Instance_PixelSizes( pf->instance, pf->fontsize,
+                                pf->fontsize, pf->fontsize * 64 );
+#if 0
+	/* set charsize (convert to points for freetype)*/
+	TT_Set_Instance_CharSize (pf->instance,
+		((pf->fontsize * 72 + 96/2) / 96) * 64);
+#endif
+}
+
+static void
+freetype_setfontrotation(PMWFONT pfont, int tenthdegrees)
+{
+	PMWFREETYPEFONT	pf = (PMWFREETYPEFONT)pfont;
+	float 		angle;
+	
+	pf->fontrotation = tenthdegrees;
+
+	/* Build the rotation matrix with the given angle */
+	TT_Set_Instance_Transform_Flags (pf->instance, TRUE, FALSE);
+
+	angle = pf->fontrotation * M_PI / 1800;
+	pf->matrix.yy = (TT_Fixed) (cos (angle) * (1 << 16));
+	pf->matrix.yx = (TT_Fixed) (sin (angle) * (1 << 16));
+	pf->matrix.xx = pf->matrix.yy;
+	pf->matrix.xy = -pf->matrix.yx;
+}
+
+#endif /* HAVE_FREETYPE_SUPPORT*/
+
+/* UTF-8 to UTF-16 conversion.  Surrogates are handeled properly, e.g.
+ * a single 4-byte UTF-8 character is encoded into a surrogate pair.
+ * On the other hand, if the UTF-8 string contains surrogate values, this
+ * is considered an error and returned as such.
+ *
+ * The destination array must be able to hold as many Unicode-16 characters
+ * as there are ASCII characters in the UTF-8 string.  This in case all UTF-8
+ * characters are ASCII characters.  No more will be needed.
+ *
+ * Copyright (c) 2000 Morten Rolland, Screen Media
+ */
+static int
+utf8_to_utf16(const unsigned char *utf8, int cc, unsigned short *unicode16)
+{
+	int count = 0;
+	unsigned char c0, c1;
+	unsigned long scalar;
+
+	while(--cc >= 0) {
+		c0 = *utf8++;
+		/*DPRINTF("Trying: %02x\n",c0);*/
+
+		if ( c0 < 0x80 ) {
+			/* Plain ASCII character, simple translation :-) */
+			*unicode16++ = c0;
+			count++;
+			continue;
+		}
+
+		if ( (c0 & 0xc0) == 0x80 )
+			/* Illegal; starts with 10xxxxxx */
+			return -1;
+
+		/* c0 must be 11xxxxxx if we get here => at least 2 bytes */
+		scalar = c0;
+		if(--cc < 0)
+			return -1;
+		c1 = *utf8++;
+		/*DPRINTF("c1=%02x\n",c1);*/
+		if ( (c1 & 0xc0) != 0x80 )
+			/* Bad byte */
+			return -1;
+		scalar <<= 6;
+		scalar |= (c1 & 0x3f);
+
+		if ( !(c0 & 0x20) ) {
+			/* Two bytes UTF-8 */
+			if ( scalar < 0x80 )
+				return -1;	/* Overlong encoding */
+			*unicode16++ = scalar & 0x7ff;
+			count++;
+			continue;
+		}
+
+		/* c0 must be 111xxxxx if we get here => at least 3 bytes */
+		if(--cc < 0)
+			return -1;
+		c1 = *utf8++;
+		/*DPRINTF("c1=%02x\n",c1);*/
+		if ( (c1 & 0xc0) != 0x80 )
+			/* Bad byte */
+			return -1;
+		scalar <<= 6;
+		scalar |= (c1 & 0x3f);
+
+		if ( !(c0 & 0x10) ) {
+			/*DPRINTF("####\n");*/
+			/* Three bytes UTF-8 */
+			if ( scalar < 0x800 )
+				return -1;	/* Overlong encoding */
+			if ( scalar >= 0xd800 && scalar < 0xe000 )
+				return -1;	/* UTF-16 high/low halfs */
+			*unicode16++ = scalar & 0xffff;
+			count++;
+			continue;
+		}
+
+		/* c0 must be 1111xxxx if we get here => at least 4 bytes */
+		c1 = *utf8++;
+		if(--cc < 0)
+			return -1;
+		/*DPRINTF("c1=%02x\n",c1);*/
+		if ( (c1 & 0xc0) != 0x80 )
+			/* Bad byte */
+			return -1;
+		scalar <<= 6;
+		scalar |= (c1 & 0x3f);
+
+		if ( !(c0 & 0x08) ) {
+			/* Four bytes UTF-8, needs encoding as surrogates */
+			if ( scalar < 0x10000 )
+				return -1;	/* Overlong encoding */
+			scalar -= 0x10000;
+			*unicode16++ = ((scalar >> 10) & 0x3ff) + 0xd800;
+			*unicode16++ = (scalar & 0x3ff) + 0xdc00;
+			count += 2;
+			continue;
+		}
+
+		return -1;	/* No support for more than four byte UTF-8 */
+	}
+	return count;
+}
+
+#if HAVE_HZK_SUPPORT
+
+/* UniCode-16 (MWTF_UC16) to GB(MWTF_ASCII) Chinese Characters conversion.
+ * a single 2-byte UC16 character is encoded into a surrogate pair.
+ * return -1 ,if error;
+ * The destination array must be able to hold as many
+ * as there are Unicode-16 characters.
+ *
+ * Copyright (c) 2000 Tang Hao (TownHall)(tang_hao@263.net).
+ */
+static int
+UC16_to_GB(const unsigned char *uc16, int cc, unsigned char *ascii)
+{
+	FILE* fp;
+	char buffer[256];
+	unsigned char *uc16p;
+	int i=0,j=0, k;
+	unsigned char *filebuffer;
+	unsigned short *uc16pp,*table;
+	unsigned short uc16px;
+	int length=31504;
+
+	if (use_big5)
+		length=54840;
+
+    	uc16p=(unsigned char *) uc16;
+	uc16pp=(unsigned short *) uc16;
+
+	strcpy(buffer,HZK_FONT_DIR);
+	if (use_big5)
+    		strcat(buffer,"/BG2UBG.KU");
+	else
+    		strcat(buffer,"/UGB2GB.KU");
+	if(!(fp = fopen(buffer, "rb"))) 
+	{
+   	  	 fprintf (stderr, "Error.\nThe %s file can not be found!\n",buffer);
+   		 return -1;
+    	}
+
+	filebuffer= (unsigned char *)malloc ( length);
+
+	if(fread(filebuffer, sizeof(char),length, fp) < length) {
+	   	  fprintf (stderr, "Error in reading ugb2gb.ku file!\n");
+	   	  fclose(fp);
+ 	     	  return -1;
+	}
+    	fclose(fp);
+
+	if (use_big5)
+	{
+		table=(unsigned short *)filebuffer;
+		while(1)
+		{
+			if(j>=cc)
+			{
+				ascii[i]=0;
+				break;
+			}
+			uc16px=*uc16pp;
+			if((uc16px)<=0x00ff)
+			{
+				ascii[i]=(char)(*uc16pp);
+				i++;
+			}
+			else
+			{
+				ascii[i]=0xa1; ascii[i+1]=0x40;
+				for (k=0; k<13710; k++)
+				{
+					if (*(table+(k*2+1))==(uc16px))
+					{
+						ascii[i]=(char)((*(table+(k*2)) & 0xff00) >> 8);
+						ascii[i+1]=(char)(*(table+(k*2)) & 0x00ff);
+						break;
+					}
+				}
+				i+=2;
+			}
+			uc16pp++; j++;
+		}
+	}
+	else
+	{
+	while(1)
+	{
+		if(j>=cc)
+		{
+			ascii[i]=0;
+			break;
+		}
+		if((*((uc16p)+j)==0)&&(*((uc16p)+j+1)==0))
+		{
+			ascii[i]=0;
+			break;
+		}
+		else
+		{
+			if(*((uc16p)+j+1)==0)
+			{
+				ascii[i]=*((uc16p)+j);
+				i++;
+				j+=2;
+			}
+			else
+			{
+			/* to find the place of unicode charater .¶þ·Ö·¨Æ¥Åä*/
+            		{
+				int p1=0,p2=length-4,p;
+				unsigned int c1,c2,c,d;
+				c1=((unsigned int )filebuffer[p1])*0x100+(filebuffer[p1+1]);
+                		c2=((unsigned int )filebuffer[p2])*0x100+(filebuffer[p2+1]);
+				d=((unsigned int )*((uc16p)+j))*0x100+*((uc16p)+j+1);
+                		if(c1==d)
+				{
+					ascii[i]=filebuffer[p1+2];
+					ascii[i+1]=filebuffer[p1+3];
+					goto findit;
+ 	            		}
+                		if(c2==d)
+				{
+					ascii[i]=filebuffer[p2+2];
+					ascii[i+1]=filebuffer[p2+3];
+					goto findit;
+                		}
+				while(1)
+				{
+					p=(((p2-p1)/2+p1)>>2)<<2;
+					c=((unsigned int )filebuffer[p])*0x100+(filebuffer[p+1]);
+					if(d==c)	/* find it*/
+					{
+						ascii[i]=filebuffer[p+2];
+						ascii[i+1]=filebuffer[p+3];
+						break;
+          	   	   		}
+					else if(p2<=p1+4)	/* can't find.*/
+					{
+						ascii[i]='.';	/* ((uc16p)+j);*/
+						ascii[i+1]='.';	/* ((uc16p)+j+1);*/
+						break;
+					}
+					else if(d<c)
+					{
+						p2=p;
+						c2=c;										
+                  			}
+					else
+					{
+						p1=p;
+						c1=c;														
+					}
+				}
+	            	}
+			findit:
+  			i+=2;
+			j+=2;
+			}
+		}
+	}
+	}
+	free(filebuffer);
+
+	return i;
+}
+
+/************************** functions definition ******************************/
+
+static int hzk_id( PMWHZKFONT pf )
+{
+	switch(pf->font_height)
+	{
+	case 12:
+		return 0;
+	case 16: default:
+		return 1;
+	}
+}
+
+/* This function get Chinese font info from etc file.*/
+static MWBOOL GetCFontInfo( PMWHZKFONT pf )
+{
+	int charset;
+
+	if (use_big5)
+		charset=(13094+408);
+	else
+		charset=8178;
+
+    	CFont[hzk_id(pf)].width = pf->cfont_width;
+    	pf->CFont.width = pf->cfont_width;
+
+    	CFont[hzk_id(pf)].height = pf->font_height;
+    	pf->CFont.height = pf->font_height;
+
+    	CFont[hzk_id(pf)].size = ((pf->CFont.width + 7) / 8) *
+		pf->CFont.height * charset;
+    	pf->CFont.size = ((pf->CFont.width + 7) / 8) * pf->CFont.height * charset;
+
+    	if(pf->CFont.size < charset * 8)
+        	return FALSE;
+
+	strcpy(CFont[hzk_id(pf)].file,HZK_FONT_DIR);
+	strcpy(pf->CFont.file,HZK_FONT_DIR);
+
+	if(pf->font_height==16)
+	{
+		strcat(CFont[hzk_id(pf)].file,"/hzk16");
+		strcat(pf->CFont.file,"/hzk16");
+	}
+	else
+	{
+		strcat(CFont[hzk_id(pf)].file,"/hzk12");
+		strcat(pf->CFont.file,"/hzk12");
+	}
+
+    	if (use_big5)
+    	{
+		CFont[hzk_id(pf)].file[strlen(pf->CFont.file)-3]+=use_big5;
+		pf->CFont.file[strlen(pf->CFont.file)-3]+=use_big5;
+    	}
+
+    	return TRUE;
+}
+
+/* This function get ASCII font info from etc file.*/
+static MWBOOL GetAFontInfo( PMWHZKFONT pf )
+{
+    	AFont[hzk_id(pf)].width = pf->afont_width;
+    	pf->AFont.width = pf->afont_width;
+
+    	AFont[hzk_id(pf)].height = pf->font_height;
+    	pf->AFont.height = pf->font_height;
+
+    	AFont[hzk_id(pf)].size = ((pf->AFont.width + 7) / 8) *
+		pf->AFont.height * 255;
+    	pf->AFont.size = ((pf->AFont.width + 7) / 8) * pf->AFont.height * 255;
+    
+	if(pf->AFont.size < 255 * 8)
+        	return FALSE;
+
+	strcpy(AFont[hzk_id(pf)].file,HZK_FONT_DIR);
+	strcpy(pf->AFont.file,HZK_FONT_DIR);
+	
+	if(pf->font_height==16)
+	{
+	    	strcat(AFont[hzk_id(pf)].file,"/asc16");
+	    	strcat(pf->AFont.file,"/asc16");
+	}
+  	else
+	{
+	    	strcat(AFont[hzk_id(pf)].file,"/asc12");
+	    	strcat(pf->AFont.file,"/asc12");
+	}
+    	return TRUE;
+}
+
+/* This function load system font into memory.*/
+static MWBOOL LoadFont( PMWHZKFONT pf )
+{
+    	FILE* fp;
+
+	if(!GetCFontInfo(pf))
+	{
+		fprintf (stderr, "Get Chinese HZK font info failure!\n");
+		return FALSE;
+	}
+    	if(CFont[hzk_id(pf)].pFont == NULL)	/* check font cache*/
+	{
+		
+
+ 	   	/* Allocate system memory for Chinese font.*/
+ 		if( !(CFont[hzk_id(pf)].pFont = (char *)malloc(pf->CFont.size)) )
+ 		{
+	 	       	fprintf (stderr, "Allocate memory for Chinese HZK font failure.\n");
+		        return FALSE;
+	 	}
+ 	
+		/* Open font file and read information to the system memory.*/
+ 		fprintf (stderr, "Loading Chinese HZK font from file(%s)..." ,pf->CFont.file);
+		if(!(fp = fopen(CFont[hzk_id(pf)].file, "rb"))) 
+		{
+   		  	fprintf (stderr, "Error.\nThe Chinese HZK font file can not be found!\n");
+   	    	 	return FALSE;
+    		}
+	    	if(fread(CFont[hzk_id(pf)].pFont, sizeof(char), pf->CFont.size, fp) < pf->CFont.size) 
+		{
+	      	  	fprintf (stderr, "Error in reading Chinese HZK font file!\n");
+	 	     	fclose(fp);
+ 	       		return FALSE;
+		}
+
+		fclose(fp);
+
+		CFont[hzk_id(pf)].use_count=0;
+
+		fprintf (stderr, "done.\n" );
+
+	}
+	cfont_address = CFont[hzk_id(pf)].pFont;
+	pf->cfont_address = CFont[hzk_id(pf)].pFont;
+	pf->CFont.pFont = CFont[hzk_id(pf)].pFont;
+
+	CFont[hzk_id(pf)].use_count++;
+
+	if(!GetAFontInfo(pf))
+	{
+	       fprintf (stderr, "Get ASCII HZK font info failure!\n");
+	       return FALSE;
+	}
+    	if(AFont[hzk_id(pf)].pFont == NULL)	/* check font cache*/
+	{
+		
+ 		
+ 		/* Allocate system memory for ASCII font.*/
+ 		if( !(AFont[hzk_id(pf)].pFont = (char *)malloc(pf->AFont.size)) )
+ 		{
+ 		       	fprintf (stderr, "Allocate memory for ASCII HZK font failure.\n");
+ 		       	free(CFont[hzk_id(pf)].pFont);
+ 		       	CFont[hzk_id(pf)].pFont = NULL;
+			return FALSE;
+ 		}
+ 	
+	 	/* Load ASCII font information to the near memory.*/
+ 		fprintf (stderr, "Loading ASCII HZK font..." );
+ 		if(!(fp = fopen(AFont[hzk_id(pf)].file, "rb"))) 
+		{
+ 		       	fprintf (stderr, "Error.\nThe ASCII HZK font file can not be found!\n");
+ 		       	return FALSE;
+ 		}
+	 	if(fread(AFont[hzk_id(pf)].pFont, sizeof(char), pf->AFont.size, fp) < pf->AFont.size) 
+		{
+ 		       	fprintf (stderr, "Error in reading ASCII HZK font file!\n");
+ 		       	fclose(fp);
+ 		       	return FALSE;
+	 	}
+ 	
+ 		fclose(fp);
+ 	
+		AFont[hzk_id(pf)].use_count=0;
+
+		fprintf (stderr, "done.\n" );
+
+  	}
+	afont_address = AFont[hzk_id(pf)].pFont;
+	pf->afont_address = AFont[hzk_id(pf)].pFont;
+	pf->AFont.pFont = AFont[hzk_id(pf)].pFont;
+
+	AFont[hzk_id(pf)].use_count++;
+
+  	return TRUE;
+}
+
+/* This function unload system font from memory.*/
+static void UnloadFont( PMWHZKFONT pf )
+{
+	CFont[hzk_id(pf)].use_count--;
+	AFont[hzk_id(pf)].use_count--;
+
+	if (!CFont[hzk_id(pf)].use_count)
+	{	
+	    	free(pf->CFont.pFont);
+	    	free(pf->AFont.pFont);
+
+	    	CFont[hzk_id(pf)].pFont = NULL;
+	    	AFont[hzk_id(pf)].pFont = NULL;
+	}
+}
+
+static int
+hzk_init(PSD psd)
+{
+	/* FIXME: *.KU file should be opened and
+	 * read in here...*/
+	return 1;
+}
+
+static PMWHZKFONT
+hzk_createfont(const char *name, MWCOORD height, int attr)
+{
+	PMWHZKFONT	pf;
+
+	if(strcmp(name,"HZKFONT")!=0 && strcmp(name,"HZXFONT")!=0)
+		return FALSE;
+
+	/*printf("hzk_createfont(%s,%d)\n",name,height);*/
+
+	use_big5=name[2]-'K';
+
+	/* allocate font structure*/
+	pf = (PMWHZKFONT)calloc(sizeof(MWHZKFONT), 1);
+	if (!pf)
+		return NULL;
+	pf->fontprocs = &hzk_procs;
+
+	pf->fontsize=height;
+#if 0
+	GdSetFontSize((PMWFONT)pf, height);
+#endif
+	GdSetFontRotation((PMWFONT)pf, 0);
+	GdSetFontAttr((PMWFONT)pf, attr, 0);
+
+	if(height==12)
+	{		
+		afont_width = 6;
+		cfont_width = 12;
+		font_height = 12;
+
+		pf->afont_width = 6;
+		pf->cfont_width = 12;
+		pf->font_height = 12;
+	}
+	else 	
+	{		
+		afont_width = 8;
+		cfont_width = 16;
+		font_height = 16;
+
+		pf->afont_width = 8;
+		pf->cfont_width = 16;
+		pf->font_height = 16;
+	}
+
+    	/* Load the font library to the system memory.*/
+	if(!LoadFont(pf))
+  	      	return FALSE;
+
+	return pf;
+}
+
+int IsBig5(int i)
+{
+	if ((i>=0xa140 && i<=0xa3bf) || /* a140-a3bf(!a3e0) */
+	    (i>=0xa440 && i<=0xc67e) || /* a440-c67e        */
+	    (i>=0xc6a1 && i<=0xc8d3) || /* c6a1-c8d3(!c8fe) */
+	    (i>=0xc940 && i<=0xf9fe))   /* c940-f9fe        */
+		return 1;
+	else
+		return 0;
+}
+
+/*
+ * following several function is used in hzk_drawtext
+ */
+
+static int getnextchar(char* s, unsigned char* cc)
+{
+    	if( s[0] == '\0') return 0;
+
+    	cc[0] = (unsigned char)(*s);
+    	cc[1] = (unsigned char)(*(s + 1));
+
+    	if (use_big5)
+    	{
+		if( IsBig5( (int) ( (cc[0] << 8) + cc[1]) ) )
+			return 1;
+    	}
+    	else
+	{
+    		if( ((unsigned char)cc[0] > 0xa0) &&
+		    ((unsigned char)cc[1] > 0xa0) )
+        		return 1;
+	}
+
+    	cc[1] = '\0';
+
+    	return 1;
+}
+
+static void
+expandcchar(PMWHZKFONT pf, int bg, int fg, unsigned char* c, MWPIXELVAL* bitmap)
+{
+	int i=0;
+    	int c1, c2, seq;
+	int x,y;
+    	unsigned char *font;
+    	int b = 0;		/* keep gcc happy with b = 0 - MW */
+
+	int pixelsize;
+	pixelsize=sizeof(MWPIXELVAL);
+
+   	c1 = c[0];
+    	c2 = c[1];
+	if (use_big5)
+	{
+		seq=0;
+		/* ladd=loby-(if(loby<127)?64:98)*/
+		c2-=(c2<127?64:98);   
+
+		/* hadd=(hiby-164)*157*/
+		if (c1>=0xa4)	/* standard font*/
+		{
+			seq=(((c1-164)*157)+c2);
+			if (seq>=5809) seq-=408;
+		}
+
+		/* hadd=(hiby-161)*157*/
+		if (c1<=0xa3)	/* special font*/
+			seq=(((c1-161)*157)+c2)+13094;
+	}
+	else
+    		seq=((c1 - 161)*94 + c2 - 161); 
+
+	font = pf->cfont_address + ((seq) *
+		  (pf->font_height * ((pf->cfont_width + 7) / 8)));
+
+     	for (y = 0; y < pf->font_height; y++)
+        	for (x = 0; x < pf->cfont_width; x++) 
+		{
+            		if (x % 8 == 0)
+                		b = *font++;
+
+            		if (b & (128 >> (x % 8)))   /* pixel */
+			  	bitmap[i++]=fg;
+			else
+				bitmap[i++]=bg;
+		}		
+}
+
+static void expandchar(PMWHZKFONT pf, int bg, int fg, int c, MWPIXELVAL* bitmap)
+{
+	int i=0;
+	int x,y;
+    	unsigned char *font;
+	int pixelsize;
+    	int b = 0;		/* keep gcc happy with b = 0 - MW */
+
+	pixelsize=sizeof(MWPIXELVAL);
+
+    	font = pf->afont_address + c * (pf->font_height *
+		((pf->afont_width + 7) / 8));
+
+  	for (y = 0; y < pf->font_height; y++)
+		for (x = 0; x < pf->afont_width; x++) 
+		{
+	    		if (x % 8 == 0)
+				b = *font++;
+	    		if (b & (128 >> (x % 8)))	/* pixel */
+				bitmap[i++]=fg;
+			else
+				bitmap[i++]=bg;
+  		}
+}
+
+/*
+ * Draw ASCII text string using HZK type font
+ */
+static void
+hzk_drawtext(PMWFONT pfont, PSD psd, MWCOORD ax, MWCOORD ay,
+	const void *text, int cc, int flags)
+{
+	PMWHZKFONT pf=(PMWHZKFONT)pfont;
+
+    	unsigned char c[2];
+	MWPIXELVAL *bitmap;
+    	unsigned char s1[3];
+ 	char *s,*sbegin;
+
+	s=(char *)text;
+
+	if(cc==1)
+	{
+		s1[0]=*((unsigned char*)text);
+		s1[1]=0x0;
+		s1[2]=0x0;
+		s=s1;
+    	}
+
+	sbegin=s;
+    	bitmap = (MWPIXELVAL *)ALLOCA(pf->cfont_width * pf->font_height *
+			sizeof(MWPIXELVAL));
+
+    	while( getnextchar(s, c) )
+	{
+              	if( c[1] != '\0') 
+		{
+                	expandcchar(pf, gr_background,gr_foreground,
+                            c, bitmap);
+			/* Now draw the bitmap ... */
+			
+			if (flags&MWTF_TOP)
+				GdArea(psd,ax, ay, pf->cfont_width,
+					pf->font_height, bitmap, MWPF_PIXELVAL);
+			else
+				GdArea(psd,ax, ay-pf->font_height+2,
+					pf->cfont_width, pf->font_height,
+					bitmap, MWPF_PIXELVAL);
+
+                	s += 2;
+                	ax += pf->cfont_width;
+            	}
+            	else 
+		{
+                	expandchar(pf, gr_background,gr_foreground,
+                           c[0], bitmap);
+			/* Now draw the bitmap ... */
+
+			if (flags&MWTF_TOP) 
+				GdArea(psd,ax, ay, pf->afont_width,
+					pf->font_height, bitmap, MWPF_PIXELVAL);
+			else
+				GdArea(psd,ax, ay-pf->font_height+2,
+					pf->afont_width, pf->font_height,
+					bitmap, MWPF_PIXELVAL);
+
+                	s += 1;
+                	ax += pf->afont_width;
+            	}
+						
+		if(s>=sbegin+cc)break;
+    	}
+
+	FREEA(bitmap);
+}
+
+/*
+ * Return information about a specified font.
+ */
+static MWBOOL
+hzk_getfontinfo(PMWFONT pfont, PMWFONTINFO pfontinfo)
+{
+	PMWHZKFONT pf=(PMWHZKFONT)pfont;
+
+	int i;
+
+	pfontinfo->height = pf->font_height;
+	pfontinfo->maxwidth = pf->cfont_width;
+	pfontinfo->baseline = pf->font_height-2;
+	pfontinfo->firstchar = 0;
+	pfontinfo->lastchar = 0;
+	pfontinfo->fixed = TRUE;
+		
+	for(i=0; i<=256; i++)
+		pfontinfo->widths[i] = pf->afont_width;
+
+	return TRUE;
+}
+
+static void
+hzk_gettextsize(PMWFONT pfont, const void *text, int cc,
+	MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase)
+{
+	PMWHZKFONT pf=(PMWHZKFONT)pfont;
+
+   	unsigned char c[2];
+ 	char *s,*sbegin;
+    	unsigned char s1[3];
+
+	int ax=0;
+	s=(char *)text;
+	if(cc==0)
+	{
+		*pwidth = 0;
+		*pheight = pf->font_height;
+		*pbase = pf->font_height-2;
+
+	}
+	if(cc==1)
+	{
+		s1[0]=*((unsigned char*)text);
+		s1[1]=0x0;
+		s1[2]=0x0;
+		s=s1;
+    	}
+	sbegin=s;
+    	while( getnextchar(s, c) )
+	{
+		if( c[1] != '\0') 
+		{
+           		s += 2;
+           		ax += pf->cfont_width;
+        	}
+        	else 
+		{
+           		s += 1;
+           		ax += pf->afont_width;
+        	}
+		if(s>=sbegin+cc) {
+			/*fprintf(stderr,"s=%x,sbegin=%x,cc=%x\n",s,sbegin,cc);*/
+			break;
+		}
+
+    	}
+	/*fprintf(stderr,"ax=%d,\n",ax);*/
+
+	*pwidth = ax;
+	*pheight = pf->font_height;
+	*pbase = pf->font_height-2;
+}
+
+static void
+hzk_destroyfont(PMWFONT pfont)
+{
+	PMWHZKFONT pf=(PMWHZKFONT)pfont;
+	UnloadFont(pf);
+	free(pf);
+}
+
+static void
+hzk_setfontsize(PMWFONT pfont, MWCOORD fontsize)
+{
+	PMWHZKFONT pf=(PMWHZKFONT)pfont;
+	/* jmt: hzk_setfontsize not supported*/
+	/* & pf->fontsize can't be changed*/
+	/* because of hzk_id() :p*/
+	pf->fontsize=pf->font_height;
+}
+#endif /* HAVE_HZK_SUPPORT*/
+
+/* FIXME: this routine should work for all font renderers...*/
+int
+GdGetTextSizeEx(PMWFONT pfont, const void *str, int cc,int nMaxExtent,
+	int* lpnFit, int* alpDx,MWCOORD *pwidth,MWCOORD *pheight,
+	MWCOORD *pbase, int flags)
+{
+#ifdef HAVE_FREETYPE_SUPPORT
+	unsigned short	buf[256];
+	unsigned short* text;
+	PMWFREETYPEFONT	pf = (PMWFREETYPEFONT)pfont;
+	int		defencoding = pf->fontprocs->encoding;
+	int 		x = 0;
+	int 		i;
+	TT_UShort 	curchar;
+	TT_Glyph_Metrics metrics;
+	TT_Face_Properties 	properties;
+	TT_Instance_Metrics imetrics;
+
+	if ((cc<0)||(!str))
+	{
+		*pwidth = *pheight = *pbase = 0;
+		return 0;
+	}
+	/* convert encoding if required*/
+	if((flags & MWTF_PACKMASK) != defencoding) 
+	{
+		cc = GdConvertEncoding(str, flags, cc, buf, defencoding);
+		flags &= ~MWTF_PACKMASK;
+		flags |= defencoding;
+		text=buf;
+	} else text =(unsigned short*)str;
+	if(cc <= 0)
+	{
+		*pwidth = *pheight = *pbase = 0;
+		return 0;
+	}
+
+	TT_Get_Face_Properties (pf->face, &properties);
+	TT_Get_Instance_Metrics(pf->instance, &imetrics);
+	
+	pf->last_glyph_code = -1;		/* reset kerning*/
+	pf->last_pen_pos = -32767;
+	if (lpnFit)
+	     *lpnFit=-1;
+	for (i = 0; i < cc; i++) 
+	{
+		curchar = TT_Char_Index (pf->char_map,text[i]);
+		
+		if (TT_Load_Glyph (pf->instance, pf->glyph, curchar,
+			TTLOAD_SCALE_GLYPH|TTLOAD_HINT_GLYPH) != TT_Err_Ok)			
+		{		
+		     fprintf(stderr, "Unable to load glyph with index=%d\n",curchar);    
+			return 0;
+		}
+		TT_Get_Glyph_Metrics (pf->glyph, &metrics);
+		if ((pf->fontattr&MWTF_KERNING) && pf->can_kern)
+		{
+			x += compute_kernval(pf, curchar) / 64;
+		}
+		x += metrics.advance / 64;
+     		if((lpnFit)&&(alpDx))
+		{
+			if (x<=nMaxExtent)
+			     alpDx[i]=x;
+			else
+			     if (*lpnFit==-1)
+					(*lpnFit)=i;               		     
+		}
+		/* Kerning point syndrome avoidance */
+		if (pf->last_pen_pos > x)
+			x = pf->last_pen_pos;
+		pf->last_pen_pos = x;
+		pf->last_glyph_code = curchar;
+	}
+     	if ((lpnFit)&&(*lpnFit==-1))
+    		*lpnFit=cc;
+	*pwidth = x;
+	*pheight = (((properties.horizontal->Ascender * 
+	                imetrics.y_scale)/ 0x10000) >> 6) -
+			    (((properties.horizontal->Descender * 
+			    imetrics.y_scale)/ 0x10000) >> 6);
+	/* FIXME: is it what's required ??*/
+	if (pbase)
+		*pbase = (((-properties.horizontal->Descender) * 
+			    imetrics.y_scale)/ 0x10000) >> 6;
+	return 1;
+#else /* HAVE_FREETYPE_SUPPORT*/
+	*pwidth = *pheight = *pbase = 0;
+	return 0;
+#endif
+}
+
+#ifdef HAVE_FREETYPE_SUPPORT
+#include <dirent.h>
+/* 
+ * This function is taken almost verbatim from ftdump.c from 
+ * the freetype library (version 1.3.1)
+ */
+static char *
+tt_lookup_name(TT_Face face)
+{
+	TT_Face_Properties prop;
+	unsigned short i, n;
+	unsigned short platform, encoding, language, id;
+	char *string;
+	char *name_buffer;
+	unsigned short string_len;
+	int j, found;
+	int index = 4; /* I dont know why as yet.. */
+	int name_len;
+
+
+	TT_Get_Face_Properties(face, &prop);
+	n = prop.num_Names;
+
+	for ( i = 0; i < n; i++ ) {
+		TT_Get_Name_ID( face, i, &platform, &encoding, &language, &id );
+		TT_Get_Name_String( face, i, &string, &string_len );
+
+		if (id == index ) {
+			/* The following code was inspired from Mark Leisher's */
+			/* ttf2bdf package                                     */
+			found = 0;
+
+			/* Try to find a Microsoft English name */
+			if ( platform == 3 )
+				for ( j = 1; j >= 0; j-- )
+					if ( encoding == j )  /* Microsoft ? */
+						if ( (language & 0x3FF) == 0x009 ) {
+							/* English language */
+							found = 1;
+							break;
+						}
+
+			if ( !found && platform == 0 && language == 0 )
+				found = 1;
+
+			/* Found a Unicode Name. */
+			if ( found ) {
+				if ( string_len > 512 )
+					string_len = 512;
+
+				name_len = 0;
+				name_buffer = (char*)malloc((string_len / 2) + 1);
+
+				for ( i = 1; i < string_len; i += 2 )
+					name_buffer[name_len++] = string[i];
+
+				name_buffer[name_len] = '\0';
+
+				return name_buffer;
+			}
+		}
+	}
+
+	/* Not found */
+	return NULL;
+}
+
+static char *
+get_tt_name(char *p)
+{
+	TT_Face face;
+	char *ret;
+
+	/*printf("Trying to open: %s!\n",p);*/
+
+	if (TT_Open_Face(engine, p, &face) != TT_Err_Ok) {
+		fprintf(stderr, "Error opening font: %s\n", p);
+		return NULL;
+	}
+
+	ret = tt_lookup_name(face);
+
+	TT_Close_Face(face);
+
+	return ret;
+}
+
+void
+GdFreeFontList(MWFONTLIST ***fonts, int n)
+{
+	int i;
+	MWFONTLIST *g, **list = *fonts;
+
+	for (i = 0; i < n; i++) {
+		g = list[i];
+		if(g) {
+			if(g->mwname) 
+				free(g->mwname);
+			if(g->ttname) 
+				free(g->ttname);
+			free(g);
+		}
+	}
+	free(list);
+	*fonts = 0;
+}
+
+void
+GdGetFontList(MWFONTLIST ***fonts, int *numfonts)
+{
+	DIR *dir;
+	struct dirent *dent;
+	char *p, *ftmp;
+	int pl, idx = 0;
+	MWFONTLIST **list;
+	
+
+	if (TT_Err_Ok != TT_Init_FreeType(&engine)) {
+		fprintf(stderr, "Unable to initialize freetype\n");
+		*numfonts = -1;
+		return ;
+	}
+
+	dir = opendir(FREETYPE_FONT_DIR);
+
+	if (dir <= 0) {
+		fprintf(stderr, "Error opening font directory\n");
+		*numfonts = -1;
+		return ;
+	}
+
+	/* get the number of strings we need to allocate */
+	while ((dent = readdir(dir)) != NULL) {
+		p = strrchr(dent->d_name, '.');
+		if (strcasecmp(p, ".ttf") == 0)
+			idx++;
+	}
+
+	*numfonts = idx;
+	rewinddir(dir);
+
+	/* allocate strings */
+	list = (MWFONTLIST**)malloc(idx * sizeof(MWFONTLIST*));
+	for (pl = 0; pl < idx; pl++)
+		list[pl] = (MWFONTLIST*)malloc(sizeof(MWFONTLIST));
+
+	*fonts = list;
+
+	idx = 0;
+
+	while ((dent = readdir(dir)) != NULL) {
+		/* check extension */
+		p = strrchr(dent->d_name, '.');
+
+		if (strcasecmp(p, ".ttf") == 0) {
+			
+			/* get full path */
+			p = 0;
+			pl = strlen(FREETYPE_FONT_DIR) + strlen(dent->d_name) *	
+						sizeof(char) + 2;
+			p = (char*)malloc(pl);
+			p = (char*)memset(p, '\0', pl);
+			p = (char*)strcat(p, FREETYPE_FONT_DIR);
+			p = (char*)strcat(p, "/");
+			p = (char*)strcat(p, dent->d_name);
+
+
+			if((ftmp = get_tt_name(p)) != NULL) {
+				list[idx]->ttname = ftmp;
+				list[idx]->mwname = malloc(strlen(dent->d_name) + 1);
+				list[idx]->mwname = strcpy(list[idx]->mwname, dent->d_name);
+
+				idx++;
+			}
+
+			free(p);
+		}
+	}
+	
+	closedir(dir);
+}
+#else /* !HAVE_FREETYPE_SUPPORT*/
+
+void
+GdFreeFontList(MWFONTLIST ***fonts, int n)
+{
+}
+
+void
+GdGetFontList(MWFONTLIST ***fonts, int *numfonts)
+{
+	*numfonts = -1;
+}
+#endif /* !HAVE_FREETYPE_SUPPORT*/