/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 *
 * The contents of this file are subject to the Netscape Public License
 * Version 1.0 (the "NPL"); you may not use this file except in
 * compliance with the NPL.  You may obtain a copy of the NPL at
 * http://www.mozilla.org/NPL/
 *
 * Software distributed under the NPL is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
 * for the specific language governing rights and limitations under the
 * NPL.
 *
 * The Initial Developer of this code under the NPL is Netscape
 * Communications Corporation.  Portions created by Netscape are
 * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
 * Reserved.
 */
/* 
   fonts.c --- managing fonts for layout.
   Created:    Jamie Zawinski     <jwz@netscape.com>, 23-Jun-94.
   Re-written: Erik van der Poel <erik@netscape.com>, 15-Oct-95.
 */


/* Currently, we allow the user to select the size of the font used, and
   the family/foundry.  Within that, the document author specifies
   a size from 1-7, a face (normal, bold, italic, bold-italic) and whether
   the font is fixed or variable width.  Meaning 7*4*2 = 56 possible
   fonts (but we load lazily).
 */


#include "mozilla.h"
#include "xfe.h"
#include "fonts.h"
#include "libi18n.h"
#include "prprf.h"
#include "prmem.h"
#include <xpgetstr.h>
#include "xupfonts.h"
#ifndef NO_WEB_FONTS
#include "nf.h"
#include "Mnfrc.h"     /* before Mnffbc to stop warnings about nfrc */
#include "Mnffmi.h"    /* before Mnffbc to stop warnings about nffmi */
#include "Mnff.h"      /* before Mnfdoer to stop warnings about nff */
#include "Mnfdoer.h"   /* before Mnffbc to stop warnings about nfdoer */
#include "Mnfrf.h"     /* before Mnffbc to stop warnings about nfrf */
#include "Mnffp.h"
#include "Mnffbc.h"    /* font consumer interface definitions */
#include "Mnffbu.h"    /* font utility interface definitions */
#include "Mnffbp.h"    /* font producer interface definitions */
#endif

#include "xp_qsort.h"

/* for XP_GetString() */
extern int XFE_OTHER_LANGUAGE;
extern int XFE_USER_DEFINED;


/* for debugging */
/* #define FE_PRINT_FONTS 1 */

#ifndef NO_WEB_FONTS
/* This is defined in mozilla.c */
extern void fe_GetProgramDirectory(char *path, int len);
#endif /* NO_WEB_FONTS */

#define fe_FONT_PITCH_MONO		0x1
#define fe_FONT_PITCH_PROPORTIONAL	0x2
#define fe_FONT_PITCH_BOTH		0x3


#define fe_TryFont(context, familyName, points, sizeNum, fontmask, charset, pitch, faceNum, dpy) \
	(*fe_CharSetFuncsArray[fe_CharSetInfoArray[charset].info].loadFont) \
(context, familyName, points, sizeNum, fontmask, charset, pitch, faceNum, dpy)


#define FE_MAYBE_FREE(p) do { if (p) { free(p); (p) = NULL; } } while (0)


#define FE_MALLOC_ZAP(type) ((type *) calloc(1, sizeof(type)))


#define FE_FONT_MASK_TO_PITCH(fontmask) (((fontmask) & LO_FONT_FIXED) ? 1 : 0)

#define FE_FONT_MASK_TOGGLE_PITCH(fontmask) ((fontmask) ^ LO_FONT_FIXED)

#define FE_NORMALIZE_SIZE(sizeNum) \
    do { (sizeNum) &= 0x7; if ((sizeNum) < 1) { (sizeNum) = 1; } } while (0)

#define FE_OPPOSITE_PITCH(p) ((p)==0 ? 1 : 0)
#define FE_OPPOSITE_WEIGHT_FACE(f) ((f)^1)
#define FE_OPPOSITE_SLANT_FACE(f) ((f)^2)

#define FE_FONT_MASK_TO_FACE(fontmask) \
	((((fontmask) & LO_FONT_BOLD) && \
	  ((fontmask) & LO_FONT_ITALIC)) ? 3 : \
	  ((fontmask) & LO_FONT_ITALIC) ? 2 : \
	  ((fontmask) & LO_FONT_BOLD) ? 1 : 0);

#define FE_FONT_SELECTED_FAMILY(charset, pitch) \
	fe_FontFindSelectedFamily(&fe_FontCharSets[charset].pitches[pitch])

typedef struct fe_StringProcessTable
{
	unsigned char	fontIndex;
	unsigned char	skip;
	unsigned char	len;
} fe_StringProcessTable;


typedef struct fe_FontGroupFont
{
	unsigned char	mask1;

	unsigned char	mask2;

	XFontStruct	*xFont;

} fe_FontGroupFont;


typedef struct fe_FontSetListEntry fe_FontSetListEntry;

struct fe_FontSetListEntry
{
	fe_FontSetListEntry	*next;
	char			*list;
	XFontSet		fontSet;
};


typedef int (*fe_XDrawStringFunc)(Display *dpy, Drawable d, GC gc,
	int x, int y, char *string, int len);


static fe_Font fe_FixedFont = NULL;

#define FE_DEFAULT_FONT_SIZE_INCREMENT	0.2
static double fe_FontSizeIncrement = FE_DEFAULT_FONT_SIZE_INCREMENT;

/* Allowing an arbitrarily large point sizes enables a condition
 * where viewing a web page which requests fonts in large point sizes
 * could cause the X server to run out of memory and crash.
 * Choose a reasonable maximum point size and normalize requests.
 */
#define FE_DEFAULT_FONT_MAXIMUM_POINTS 200
static int fe_FontMaximumPoints = FE_DEFAULT_FONT_MAXIMUM_POINTS;

static fe_FontFace *fe_FontFaceList = NULL;
static fe_FontSize *fe_FontSizeList = NULL;

static fe_FontSetListEntry *fe_FontSetList = NULL;

#ifndef NO_WEB_FONTS
static struct nffbc * fe_FontBroker  = NULL;
       struct nffbu * fe_FontUtility = NULL;
#endif

fe_FontCharSet fe_FontCharSets[INTL_CHAR_SET_MAX];

unsigned char fe_SortedFontCharSets[INTL_CHAR_SET_MAX];

typedef struct GenericFontFamily {
    char * class_name;
    char * generic_name;
    char * family_name;
} GenericFontFamily;

static GenericFontFamily fe_generics[] = {
    {"Serif",		"serif",      "times"},
    {"Sans-Serif",	"sans-serif", "helvetica"},
    {"Cursive",		"cursive",    "itc zapf chancery"},
    {"Fantasy",		"fantasy",    "new century schoolbook"},
    {"Monospace",	"monospace",  "courier"}
};

#define fe_GenericFamilyCount (sizeof(fe_generics) / sizeof(GenericFontFamily))

static XP_Bool fe_AreNormalFontsAvail(int16 win_csid);

static XmFontList fe_GetFontListNormal(int16 charset, fe_Font font, int numOfFont);
static XmString fe_ToXmStringNormal(int16 charset, fe_Font font, char * string, int len);

static fe_Font
fe_LoadNormalFont(MWContext *context, char *familyName, 
                  int points, int sizeNum,
		  int fontmask, int charset, int pitch, int faceNum,
		  Display *dpy);

static fe_Font
fe_LoadFont(MWContext *context, int16 *charset, char *familyName,
            int points, int size, int fontmask);

static fe_Font
fe_LoadFontWithoutSubstitution(MWContext *context, int16 *charset, char *familyName,
                               int points, int sizeNum, int fontmask);

static fe_Font WrapPlatformFont(fe_Font platform_font,
                                unsigned char font_type);
#ifndef NO_WEB_FONTS
static fe_Font fe_LoadRenderableFont(MWContext *context, LO_TextAttr *attr,
                                     int16 *charset, char *family);

static double fe_ConvertHTMLSizeToPointSize(LO_TextAttr *attr, int16 charset);
#endif

static fe_FontSize *
fe_FindFontPointSize(fe_FontFamily *family, double decipoints,
                     XP_Bool search_for_fit, XP_Bool scale_to_fit);

static char * fe_FindGenericFamily(int charsetID, char *familyName);

static XP_Bool fe_AreEUCCNFontsAvail(int16 /* win_csid */);

static XmFontList fe_FontGroupGetFontList(int16 charset, fe_Font font, int numOfFonts);
static XmString fe_EUCToXmString(int16 charset, fe_Font fontGroup, char * string, int len,
                                 fe_StringProcessTable *table);

static fe_Font
fe_LoadEUCCNFont(MWContext *context, char *familyName, int points,
                 int sizeNum, int fontmask, int charset, int pitch,
                 int faceNum, Display *dpy);
static void
fe_EUCCNTextExtents(fe_Font font, char *string, int len, int *direction,
	int *fontAscent, int *fontDescent, XCharStruct *overall);
static void
fe_DrawEUCCNString(Display *dpy, Drawable d, fe_Font font, GC gc, int x,
	int y, char *string, int len);
static void
fe_DrawEUCCNImageString(Display *dpy, Drawable d, fe_Font font, GC gc, GC gc2,
	int x, int y, char *string, int len);

static XmString fe_EUCCNToXmString(int16 charset, fe_Font fontGroup, char * string, int len);
static XP_Bool fe_AreEUCJPFontsAvail(int16 /* win_csid */);

static fe_Font
fe_LoadEUCJPFont(MWContext *context, char *familyName, int points,
                 int sizeNum, int fontmask, int charset, int pitch,
                 int faceNum, Display *dpy);
static void
fe_EUCJPTextExtents(fe_Font font, char *string, int len, int *direction,
	int *fontAscent, int *fontDescent, XCharStruct *overall);
static void
fe_DrawEUCJPString(Display *dpy, Drawable d, fe_Font font, GC gc, int x,
	int y, char *string, int len);
static void
fe_DrawEUCJPImageString(Display *dpy, Drawable d, fe_Font font, GC gc, GC gc2,
	int x, int y, char *string, int len);
static XmString fe_EUCJPToXmString(int16 charset, fe_Font fontGroup, char * string, int len);

static XP_Bool fe_AreEUCKRFontsAvail(int16 /* win_csid */);

static fe_Font
fe_LoadEUCKRFont(MWContext *context, char *familyName, int points,
                 int sizeNum, int fontmask, int charset, int pitch,
                 int faceNum, Display *dpy);
static void
fe_EUCKRTextExtents(fe_Font font, char *string, int len, int *direction,
	int *fontAscent, int *fontDescent, XCharStruct *overall);
static void
fe_DrawEUCKRString(Display *dpy, Drawable d, fe_Font font, GC gc, int x,
	int y, char *string, int len);
static void
fe_DrawEUCKRImageString(Display *dpy, Drawable d, fe_Font font, GC gc, GC gc2,
	int x, int y, char *string, int len);
static XmString fe_EUCKRToXmString(int16 charset, fe_Font fontGroup, char * string, int len);

static XP_Bool fe_AreEUCTWFontsAvail(int16 /* win_csid */);

static fe_Font
fe_LoadEUCTWFont(MWContext *context, char *familyName, int points,
                 int sizeNum, int fontmask, int charset, int pitch,
                 int faceNum, Display *dpy);
static void
fe_EUCTWTextExtents(fe_Font font, char *string, int len, int *direction,
	int *fontAscent, int *fontDescent, XCharStruct *overall);
static void
fe_DrawEUCTWString(Display *dpy, Drawable d, fe_Font font, GC gc, int x,
	int y, char *string, int len);
static void
fe_DrawEUCTWImageString(Display *dpy, Drawable d, fe_Font font, GC gc, GC gc2,
	int x, int y, char *string, int len);
static XmString fe_EUCTWToXmString(int16 charset, fe_Font fontGroup, char * string, int len);

static XP_Bool fe_AreBIG5FontsAvail(int16 /* win_csid */);

static fe_Font
fe_LoadBIG5Font(MWContext *context, char *familyName, int points,
                int sizeNum, int fontmask, int charset, int pitch,
                int faceNum, Display *dpy);
static void
fe_BIG5TextExtents(fe_Font font, char *string, int len, int *direction,
	int *fontAscent, int *fontDescent, XCharStruct *overall);
static void
fe_DrawBIG5String(Display *dpy, Drawable d, fe_Font font, GC gc, int x,
	int y, char *string, int len);
static void
fe_DrawBIG5ImageString(Display *dpy, Drawable d, fe_Font font, GC gc, GC gc2,
	int x, int y, char *string, int len);
static XmString fe_BIG5ToXmString(int16 charset, fe_Font fontGroup, char * string, int len);

/* Unicode support */
static XP_Bool fe_AreUnicodeFontsAvail(int16 /* win_csid */);
static void
fe_DrawUTF8StringImage(Display *dpy, Drawable d, fe_Font font, GC gc, GC gc2,
	int x, int y, char *string, int len);
static XFontStruct *
fe_UnicodeInitXfont(fe_UnicodePseudoFont *ufont, uint16 encoding);
static int16 *INTL_GetXCharSetIDs(Display *dpy);


static XmFontList fe_UTF8GetFontList(int16 charset, fe_Font font, int numOfFont);
static XmString fe_UTF8ToXmString(int16 charset, fe_Font fontGroup, char * string, int len);

enum
{
	FE_FONT_INFO_X8 = 0,
	FE_FONT_INFO_X16,
	FE_FONT_INFO_EUCCN,
	FE_FONT_INFO_EUCJP,
	FE_FONT_INFO_EUCKR,
	FE_FONT_INFO_EUCTW,
	FE_FONT_INFO_BIG5,
    FE_FONT_INFO_UNICODE
};


fe_CharSetFuncs fe_CharSetFuncsArray[] =
{
	{
						1,
		(fe_AreFontsAvailFunc)	fe_AreNormalFontsAvail,
		(fe_LoadFontFunc)		fe_LoadNormalFont,
		(fe_TextExtentsFunc)		XTextExtents,
		(fe_DrawStringFunc)		XDrawString,
		(fe_DrawImageStringFunc)	XDrawImageString,
		(fe_GetFontList)	        fe_GetFontListNormal,
		(fe_ToXmString)	                fe_ToXmStringNormal
	},
	{
						1,
		(fe_AreFontsAvailFunc)	fe_AreNormalFontsAvail,
		(fe_LoadFontFunc)		fe_LoadNormalFont,
		(fe_TextExtentsFunc)		XTextExtents16,
		(fe_DrawStringFunc)		XDrawString16,
		(fe_DrawImageStringFunc)	XDrawImageString16,
		(fe_GetFontList)	        fe_GetFontListNormal,
		(fe_ToXmString)	                fe_ToXmStringNormal
	},
	{
						2,
		(fe_AreFontsAvailFunc)		fe_AreEUCCNFontsAvail,
		(fe_LoadFontFunc)		fe_LoadEUCCNFont,
		(fe_TextExtentsFunc)		fe_EUCCNTextExtents,
		(fe_DrawStringFunc)		fe_DrawEUCCNString,
		(fe_DrawImageStringFunc)	fe_DrawEUCCNImageString,
		(fe_GetFontList)	        fe_FontGroupGetFontList,
		(fe_ToXmString)	                fe_EUCCNToXmString
	},
	{
						4,
		(fe_AreFontsAvailFunc)		fe_AreEUCJPFontsAvail,
		(fe_LoadFontFunc)		fe_LoadEUCJPFont,
		(fe_TextExtentsFunc)		fe_EUCJPTextExtents,
		(fe_DrawStringFunc)		fe_DrawEUCJPString,
		(fe_DrawImageStringFunc)	fe_DrawEUCJPImageString,
		(fe_GetFontList)	        fe_FontGroupGetFontList,
		(fe_ToXmString)	                fe_EUCJPToXmString
	},
	{
						2,
		(fe_AreFontsAvailFunc)		fe_AreEUCKRFontsAvail,
		(fe_LoadFontFunc)		fe_LoadEUCKRFont,
		(fe_TextExtentsFunc)		fe_EUCKRTextExtents,
		(fe_DrawStringFunc)		fe_DrawEUCKRString,
		(fe_DrawImageStringFunc)	fe_DrawEUCKRImageString,
		(fe_GetFontList)	        fe_FontGroupGetFontList,
		(fe_ToXmString)	                fe_EUCKRToXmString
	},
	{
						3,
		(fe_AreFontsAvailFunc)		fe_AreEUCTWFontsAvail,
		(fe_LoadFontFunc)		fe_LoadEUCTWFont,
		(fe_TextExtentsFunc)		fe_EUCTWTextExtents,
		(fe_DrawStringFunc)		fe_DrawEUCTWString,
		(fe_DrawImageStringFunc)	fe_DrawEUCTWImageString,
		(fe_GetFontList)	        fe_FontGroupGetFontList,
		(fe_ToXmString)	                fe_EUCTWToXmString
	},
	{
						2,
		(fe_AreFontsAvailFunc)		fe_AreBIG5FontsAvail,
		(fe_LoadFontFunc)		fe_LoadBIG5Font,
		(fe_TextExtentsFunc)		fe_BIG5TextExtents,
		(fe_DrawStringFunc)		fe_DrawBIG5String,
		(fe_DrawImageStringFunc)	fe_DrawBIG5ImageString,
		(fe_GetFontList)	        fe_FontGroupGetFontList,
		(fe_ToXmString)	                fe_BIG5ToXmString
	},
	{
						4,
		(fe_AreFontsAvailFunc)		fe_AreUnicodeFontsAvail,
		(fe_LoadFontFunc)		fe_LoadUnicodeFont,
		(fe_TextExtentsFunc)		fe_UTF8TextExtents,
		(fe_DrawStringFunc)		fe_DrawUTF8String,
		(fe_DrawImageStringFunc)	fe_DrawUTF8StringImage,
		(fe_GetFontList)	        fe_UTF8GetFontList,
		(fe_ToXmString)	                fe_UTF8ToXmString
	},
};


fe_CharSetInfo fe_CharSetInfoArray[] =
{
    { CS_DEFAULT      , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_ASCII        , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_LATIN1       , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_JIS          , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_SJIS         , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_EUCJP        , FE_FONT_TYPE_GROUP , FE_FONT_INFO_EUCJP    },
    { CS_MAC_ROMAN    , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_BIG5         , FE_FONT_TYPE_GROUP , FE_FONT_INFO_BIG5     },
    { CS_GB_8BIT      , FE_FONT_TYPE_GROUP , FE_FONT_INFO_EUCCN    },
    { CS_CNS_8BIT     , FE_FONT_TYPE_GROUP , FE_FONT_INFO_EUCTW    },
    { CS_LATIN2       , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_MAC_CE       , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_KSC_8BIT     , FE_FONT_TYPE_GROUP , FE_FONT_INFO_EUCKR    },
    { CS_2022_KR      , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_8859_3       , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_8859_4       , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_8859_5       , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_8859_6       , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_8859_7       , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_8859_8       , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_8859_9       , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_SYMBOL       , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_DINGBATS     , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_DECTECH      , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_CNS11643_1   , FE_FONT_TYPE_X16   , FE_FONT_INFO_X16      },
    { CS_CNS11643_2   , FE_FONT_TYPE_X16   , FE_FONT_INFO_X16      },
    { CS_JISX0208     , FE_FONT_TYPE_X16   , FE_FONT_INFO_X16      },
    { CS_JISX0201     , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_KSC5601      , FE_FONT_TYPE_X16   , FE_FONT_INFO_X16      },
    { CS_TIS620       , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_JISX0212     , FE_FONT_TYPE_X16   , FE_FONT_INFO_X16      },
    { CS_GB2312       , FE_FONT_TYPE_X16   , FE_FONT_INFO_X16      },
    { CS_UCS2         , FE_FONT_TYPE_X16   , FE_FONT_INFO_X16      },
    { CS_UCS4         , FE_FONT_TYPE_X16   , FE_FONT_INFO_X16      },
    { CS_UTF8         , FE_FONT_TYPE_GROUP , FE_FONT_INFO_UNICODE  },
    { CS_UTF7         , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_NPC          , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_X_BIG5       , FE_FONT_TYPE_X16   , FE_FONT_INFO_X16      },
    { CS_USRDEF2      , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_KOI8_R       , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_MAC_CYRILLIC , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_CP_1251      , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_MAC_GREEK    , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_CP_1253      , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_CP_1250      , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_CP_1254      , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_MAC_TURKISH  , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_GB2312_11    , FE_FONT_TYPE_X16   , FE_FONT_INFO_X16      },
    { CS_JISX0208_11  , FE_FONT_TYPE_X16   , FE_FONT_INFO_X16      },
    { CS_KSC5601_11   , FE_FONT_TYPE_X16   , FE_FONT_INFO_X16      },
    { CS_CNS11643_1110, FE_FONT_TYPE_X16   , FE_FONT_INFO_X16      },
    { CS_UCS2_SWAP    , FE_FONT_TYPE_X16   , FE_FONT_INFO_X16      },
    { CS_IMAP4_UTF7   , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_CP_850       , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_CP_852       , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_CP_855       , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_CP_857       , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_CP_862       , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_CP_864       , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_CP_866       , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_CP_874       , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_CP_1257      , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_CP_1258      , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       },
    { CS_ARMSCII8     , FE_FONT_TYPE_X8    , FE_FONT_INFO_X8       }
};

static unsigned char *fe_LocaleCharSets = NULL;
static int32 smallestFontFoundSize = 12;

XP_Bool
fe_IsCharSetSupported(int16 doc_csid)
{
/* need to deal with webfonts */
#if 1
	return TRUE;
#else
	int16 win_csid;

	win_csid = INTL_DocToWinCharSetID(doc_csid);
	return(fe_AreFontsAvail(win_csid));
#endif
}

XP_Bool
fe_AreFontsAvail(int16 win_csid)
{
	int result;

	result = (*fe_CharSetFuncsArray[fe_CharSetInfoArray[(win_csid) & 0xff].info
										].areFontsAvail)(win_csid);
	return result;
}

static void
fe_GetLocaleCharSets(Display *dpy)
{
	char		*charset;
	int16		charsetID;
	char		clas[512];
	XrmDatabase	db;
	char		*def;
	XFontSet	fontSet;
	int		i;
	int		j;
	char		*mimeCharSet;
	int		missCount;
	char		**missing;
	char		name[512];
	char		*p;
	char		*type;
	XrmValue	value;

	if (fe_LocaleCharSets)
	{
		return;
	}

#if defined(SCO) || defined(UNIXWARE) && (XlibSpecificationRelease == 5)
	/*
	** XCreateFontSet is very slow in old Xlibs, fixed in X11R6
	** If locale == C, just punt
	*/
	{
		char *locale;
		locale = setlocale(LC_CTYPE, NULL);
		if (*locale == 'C') /* SCO is C_C.C */
		{
			return;
		}
	}
#endif

	missing = NULL;
	missCount = 0;
	def = NULL;
	fontSet = XCreateFontSet(dpy, "*-iso8859-1", &missing, &missCount,
		&def);
	if ((!fontSet) || (missCount < 1) || (!missing))
	{
		goto get_locale_char_sets_fail;
	}

	fe_LocaleCharSets = malloc(missCount + 2);
	if (!fe_LocaleCharSets)
	{
		goto get_locale_char_sets_fail;
	}
	j = 0;
	fe_LocaleCharSets[j++] = ((unsigned char) (CS_LATIN1 & 0xff));

	charset = NULL;

	db = XtDatabase(dpy);

	for (i = 0; i < missCount; i++)
	{
		FE_MAYBE_FREE(charset);
		if (!missing[i])
		{
			continue;
		}
		/*
		(void) fprintf(real_stderr, "locale font %d: \"%s\"\n", i + 1,
			missing[i]);
		*/
		charset = strdup(missing[i]);
		if (!charset)
		{
			goto get_locale_char_sets_fail;
		}
		p = charset;
		while (*p)
		{
			(*p) = XP_TO_LOWER(*p);
			p++;
		}
		(void) PR_snprintf(clas, sizeof(clas),
			"%s.DocumentFonts.CharSet.Name", fe_progclass);
		(void) PR_snprintf(name, sizeof(name),
			"%s.documentFonts.charset.%s", fe_progclass, charset);
		if (XrmGetResource(db, name, clas, &type, &value))
		{
			mimeCharSet = (char *) value.addr;
		}
		else
		{
#ifdef DEBUG
			(void) fprintf(real_stderr, "fontset charset %s\n",
				charset);
#endif /* DEBUG */
			continue;
		}
		charsetID = INTL_CharSetNameToID(mimeCharSet);
		if ((charsetID == CS_UNKNOWN) && strcmp(charset, "x-ignore"))
		{
#ifdef DEBUG
			(void) fprintf(real_stderr, "fontset internal %s %s\n",
				charset, mimeCharSet);
#endif /* DEBUG */
			continue;
		}
		if (!strcmp(charset, "x-ignore"))
		{
			continue;
		}
		charsetID &= 0xff;
		if (charsetID >= INTL_CHAR_SET_MAX)
		{
			continue;
		}
		fe_LocaleCharSets[j++] = (unsigned char) charsetID;
	}

	FE_MAYBE_FREE(charset);

	fe_LocaleCharSets[j] = 0;

	XFreeStringList(missing);
	XFreeFontSet(dpy, fontSet);

	return;

get_locale_char_sets_fail:

	if (fontSet)
	{
		XFreeFontSet(dpy, fontSet);
	}
	if (missing)
	{
		XFreeStringList(missing);
	}
	if (fe_LocaleCharSets)
	{
		free(fe_LocaleCharSets);
		fe_LocaleCharSets = NULL;
	}
}

fe_FontFamily *
fe_FontFindSelectedFamily(fe_FontPitch *pitch)
{
	fe_FontFamily		*family;
	int			i;

	if (!pitch) return(NULL);

	if (pitch->selectedFamily) return(pitch->selectedFamily);

	family = NULL;
	for (i = 0; i < pitch->numberOfFamilies; i++)
	{
		if (pitch->families[i].selected)
		{
			family = &pitch->families[i];
			break;
		}
	}
	if (!family)
	{
		family = FE_MALLOC_ZAP(fe_FontFamily);
	}
	
	pitch->selectedFamily = family;
	return (family);
}

static fe_FontFamily *
fe_GetFontFamily(uint16 charset, int pitch)
{
	fe_FontFamily *family;
	family = FE_FONT_SELECTED_FAMILY((charset&0xFF), pitch);
	if (family == NULL) {
		return NULL;
	}
	if (!family->htmlSizesComputed) {
		fe_ComputeFontSizeTable(family);
	}
	return family;
}

fe_FontFamily *
fe_FontFindFamily(int charsetID, int pitchID, char *familyName)
{
	fe_FontFamily		*family;
	fe_FontPitch		*pitch;
	int			i;
        char *                  genericFamily;

	if (!familyName || !*familyName) return(NULL);

	family = NULL;
	pitch = &fe_FontCharSets[charsetID&0xFF].pitches[pitchID];
	for (i = 0; i < pitch->numberOfFamilies; i++)
	{
		if (!XP_STRCASECMP(pitch->families[i].family, familyName))
		{
			family = &pitch->families[i];
			if (!family->htmlSizesComputed) {
				fe_ComputeFontSizeTable(family);
			}
			break;
		}
	}

        if (family)
            return family;

        genericFamily = fe_FindGenericFamily(charsetID, familyName);
        if (!genericFamily)
            return family;

	for (i = 0; i < pitch->numberOfFamilies; i++) {
            if (!XP_STRCASECMP(pitch->families[i].family, genericFamily)) {
                family = &pitch->families[i];
                if (!family->htmlSizesComputed) {
                    fe_ComputeFontSizeTable(family);
                }
                break;
            }
	}
	return (family);
}

static char * fe_FindGenericFamily(int charsetID, char *familyName)
{
    char * genericFamily;
    int i;

    /* This is the "default font displayer's" mapping of the
     * generic font names, as described by CSS1, into common X fonts.
     */

    if (!familyName || !*familyName) return(NULL);

    /* Generic font names are mapped only for the Latin-1 charset */
    if (CS_LATIN1 != charsetID) return NULL;

    genericFamily = NULL;
    for (i = 0; i < fe_GenericFamilyCount; i++) {
        if (!XP_STRCASECMP(fe_generics[i].generic_name, familyName)) {
            genericFamily = fe_generics[i].family_name;
            break;
        }
    }
    return genericFamily;
}


XtPointer
fe_GetFont(MWContext *context, int sizeNum, int fontmask)
{
        XmFontListEntry flentry;
        XtPointer       fontOrFontSet;
        XmFontType      type;
	XmFontList      fontList;

        fontOrFontSet = fe_GetFontOrFontSet(context, NULL, sizeNum, fontmask,
                &type);
        if (!fontOrFontSet)
        {
                return NULL;
        }
        flentry = XmFontListEntryCreate(XmFONTLIST_DEFAULT_TAG, type,
                fontOrFontSet);
        if (!flentry)
        {
                return NULL;
        }
        fontList = XmFontListAppendEntry(NULL, flentry);
        if (!fontList)
        {
                return NULL;
        }
        XmFontListEntryFree(&flentry);
	return fontList;
}


XtPointer
fe_GetFontOrFontSet(MWContext *context, char *familyName, int sizeNum,
	int fontmask, XmFontType *type)
{
	unsigned char		charset;
	int16			cs;
	char			*def;
	Display			*dpy;
	fe_FontSetListEntry	*f;
	fe_FontFace		*face;
	int			faceNum;
	XtPointer		fontOrFontSet;
	char			*list;
	int			missCount;
	char			**missing;
	char			*newList;
	unsigned char		*p;
	int			pitch;
	fe_FontSize		*size;
	fe_FontFamily		*family;

	def = NULL;
	dpy = XtDisplay(CONTEXT_WIDGET(context));
	faceNum = FE_FONT_MASK_TO_FACE(fontmask);
	list = NULL;
	missCount = 0;
	missing = NULL;
	pitch = FE_FONT_MASK_TO_PITCH(fontmask);
	FE_NORMALIZE_SIZE(sizeNum);

	if (fe_LocaleCharSets)
	{
		p = fe_LocaleCharSets;
		while (*p)
		{
			charset = *p++;
			family = NULL;
			if (familyName && *familyName)
			{
				family = fe_FontFindFamily(charset, pitch, familyName);
				if (!family) return NULL;
			}
			if (!family)
			{
				family = fe_GetFontFamily(charset, pitch);
				if (!family)
				{
					return NULL;
				}
			}
			size = family->htmlSizes[sizeNum-1];
			if (!size)
			{
				continue;
			}
			face = size->faces[faceNum];
			if (!face)
			{
				continue;
			}
			if (!face->longXLFDFontName)
			{
				continue;
			}
			if (list)
			{
				newList = PR_smprintf("%s,%s", list,
					face->longXLFDFontName);
				free(list);
				list = newList;
			}
			else
			{
				list = strdup(face->longXLFDFontName);
			}
			if (!list)
			{
				return NULL;
			}
		}
		f = fe_FontSetList;
		while (f)
		{
			if (!strcmp(f->list, list))
			{
				break;
			}
			f = f->next;
		}
		if (f)
		{
			free(list);
			fontOrFontSet = f->fontSet;
			*type = XmFONT_IS_FONTSET;
		}
		else
		{
			fontOrFontSet = XCreateFontSet(dpy, list, &missing,
				&missCount, &def);
			if (fontOrFontSet)
			{
				/*
				(void) fprintf(real_stderr,
					"font set \"%s\" succeeded\n", list);
				*/
				f = XP_NEW_ZAP(fe_FontSetListEntry);
				if (!f)
				{
					return NULL;
				}
				f->next = fe_FontSetList;
				fe_FontSetList = f;
				f->list = list;
				f->fontSet = fontOrFontSet;
				*type = XmFONT_IS_FONTSET;
			}
			else
			{
				/*
				(void) fprintf(real_stderr,
					"font set \"%s\" failed\n", list);
				*/
				return NULL;
			}
		}
	}
	else
	{
		cs = CS_LATIN1;
		fontOrFontSet = fe_LoadFont(context, &cs, familyName,
					    0 /* no pointsize */,
                                            sizeNum, fontmask);
		*type = XmFONT_IS_FONT;
	}

	return fontOrFontSet;
}


static int
fe_PitchAndFaceToFontMask(int pitch, int face)
{
	int	fontmask;

	if (pitch)
	{
		fontmask = LO_FONT_FIXED;
	}
	else
	{
		fontmask = 0;
	}

	switch (face)
	{
	case 1:
		fontmask |= LO_FONT_BOLD;
		break;
	case 2:
		fontmask |= LO_FONT_ITALIC;
		break;
	case 3:
		fontmask |= (LO_FONT_BOLD | LO_FONT_ITALIC);
		break;
	default:
		break;
	}

	return fontmask;
}


static fe_Font
fe_LoadFontGroup(MWContext *context, char *familyName,
                 int points, int sizeNum,
	int fontmask, int16 charsetID, int pitch, int faceNum, Display *dpy)
{
	fe_FontFace	*face;
	fe_Font		font;
	int		i;
	fe_FontSize	*size;
	fe_FontFamily	*family;

	size = FE_MALLOC_ZAP(fe_FontSize);
	if (!size)
	{
		return NULL;
	}

	for (i = 0; i < 4; i++)
	{
		face = FE_MALLOC_ZAP(fe_FontFace);
		if (!face)
		{
			return NULL;
		}
		size->faces[i] = face;

		/*
		 * @@@ ignore familyName for now
		 * need to modify all the loadFont funcs too
		 */
		font = (*fe_CharSetFuncsArray[fe_CharSetInfoArray[charsetID].
			info].loadFont)(context, NULL, points, sizeNum,
			fe_PitchAndFaceToFontMask(pitch, i), charsetID,
			pitch, i, dpy);

		if (!font)
		{
			return NULL;
		}
		face->font = font;
	}

	family = FE_FONT_SELECTED_FAMILY(charsetID, pitch);
	if (!family)
	{
		XP_FREE(size);
		return NULL;
	}

        /* XXX what is going on here for pointsizes?  -converse */

        if (!points) {
            family->htmlSizes[sizeNum-1] = size;
        }
        return size->faces[faceNum]->font;
}


static fe_Font
fe_LoadFont(MWContext *context, int16 *charset, char *familyName,
	    int points, int sizeNum, int fontmask)
{
	int16		charsetID;
	Display		*dpy;
	fe_FontFace	*face;
	int		faceNum;
	fe_Font		font;
	int		pitch;
	fe_FontSize	*size;
	int		trySize;
	fe_FontFamily	*family;
        double          decipoints;

	/*
	 * paranoia, robustness
	 */

	charsetID = 0;
	if (charset)
	{
		charsetID = *charset;
	}
	else
	{
		charset = &charsetID;
	}

	if (!charsetID)
	{
		charsetID = INTL_DefaultTextAttributeCharSetID(context);
		if (!charsetID)
		{
			charsetID = CS_LATIN1;
		}
		*charset = charsetID;
	}
	charsetID &= 0xff;
	if (charsetID >= INTL_CHAR_SET_MAX)
	{
		charsetID = (CS_LATIN1 & 0xff);
		*charset = CS_LATIN1;
	}

	pitch = FE_FONT_MASK_TO_PITCH(fontmask);

	faceNum = FE_FONT_MASK_TO_FACE(fontmask);

	dpy = XtDisplay(CONTEXT_WIDGET(context));

	family = NULL;
	if (familyName && *familyName)
	{
		family = fe_FontFindFamily(charsetID, pitch, familyName);
		if ((!family) && (fe_CharSetInfoArray[charsetID].type !=
			FE_FONT_TYPE_GROUP))
		{
			return NULL;
		}
	}
	if (!family)
	{
		/* We blew the font lookup, falling back to default. */
		family = fe_GetFontFamily(*charset, pitch);

        /* Invalidate the point size, I can't read it. */
		points = 0;

		if (!family)
		{
			if (*charset == CS_LATIN1)
			{
				return fe_FixedFont;
			}
			else
			{
				*charset = CS_LATIN1;
				return fe_LoadFont(context, charset,
                                                   familyName, points,
                                                   sizeNum, fontmask);
			}
		}
	}
        if (! points)
            size = family->htmlSizes[sizeNum-1];
        else {
            decipoints = (double) (points * 10);
            size = fe_FindFontPointSize(family, decipoints, False, True);
        }
	if (!size)
	{
		if (fe_CharSetInfoArray[charsetID].type == FE_FONT_TYPE_GROUP)
		{
			font = fe_LoadFontGroup(context, familyName, points,
                                                sizeNum, fontmask, charsetID,
                                                pitch, faceNum, dpy);
			if (font)
			{
				return font;
			}
		}

		/*
		 * this charset is not available
		 * use Latin-1 font to display the bytes
		 */
		if (*charset == CS_LATIN1)
		{
			return fe_FixedFont;
		}
		else
		{
			*charset = CS_LATIN1;
			return fe_LoadFont(context, charset, familyName,
					   points, sizeNum, fontmask);
		}
	}

	face = size->faces[faceNum];
	if (!face)
	{
		/*
		 * this shouldn't happen
		 * if it does, we will display these bytes in a Latin-1 font
		 */
		if (*charset == CS_LATIN1)
		{
			return fe_FixedFont;
		}
		else
		{
			*charset = CS_LATIN1;
			return fe_LoadFont(context, charset, familyName,
					   points, sizeNum, fontmask);
		}
	}

	font = face->font;
	if (!font)
	{
		font = fe_TryFont(context, familyName, points, sizeNum,
                                  fontmask, charsetID, pitch, faceNum, dpy);
		if (font)
		{
                    face->font = font;
		}
		else
		{
			for (trySize = sizeNum - 1; trySize > 0; trySize--)
			{
				font = fe_TryFont(context, familyName,
						  points, trySize, fontmask,
						  charsetID, pitch,
						  faceNum, dpy);
				if (font)
				{
					return font;
				}
			}

			for (trySize = sizeNum + 1; trySize < 8; trySize++)
			{
				font = fe_TryFont(context, familyName,
						  points, trySize, fontmask,
						  charsetID, pitch,
						  faceNum, dpy);
				if (font)
				{
					return font;
				}
			}

			*charset = CS_LATIN1;
			font = fe_FixedFont;
			face->font = font;
			return font;

			/* @@@ need to change this */
			/*
			(void) fprintf(real_stderr, "could not load\n%s\n",
				face->longXLFDFontName);
			*/
			/* XP_GetString(XFE_COULD_NOT_LOAD_FONT) */
			/* XP_GetString(XFE_USING_FALLBACK_FONT) */
			/* XP_GetString(XFE_NO_FALLBACK_FONT) */
			/* FE_Alert(context, msg); */
		}
	}

	return font;
}

static fe_Font
fe_LoadFontWithoutSubstitution(MWContext *context, int16 *charset, char *familyName,
                               int points, int sizeNum, int fontmask)
{
	int16		charsetID;
	Display		*dpy;
	fe_FontFace	*face;
	int		faceNum;
	fe_Font		font;
	int		pitch;
	fe_FontSize	*size;
	int		trySize;
	fe_FontFamily	*family;
        double          decipoints;

	/*
	 * paranoia, robustness
	 */

	charsetID = 0;
	if (charset)
	{
		charsetID = *charset;
	}
	else
	{
		charset = &charsetID;
	}

	if (!charsetID)
	{
		charsetID = INTL_DefaultTextAttributeCharSetID(context);
		if (!charsetID)
		{
			charsetID = CS_LATIN1;
		}
		*charset = charsetID;
	}
	charsetID &= 0xff;
	if (charsetID >= INTL_CHAR_SET_MAX)
	{
		charsetID = (CS_LATIN1 & 0xff);
		*charset = CS_LATIN1;
	}

	pitch = FE_FONT_MASK_TO_PITCH(fontmask);

	faceNum = FE_FONT_MASK_TO_FACE(fontmask);

	dpy = XtDisplay(CONTEXT_WIDGET(context));

	family = NULL;
	if (familyName && *familyName)
	{
		family = fe_FontFindFamily(charsetID, pitch, familyName);
		if (!family)
		{
			return NULL;
		}
	}
        else
        {
            return NULL;
        }
        if (! points)
            size = family->htmlSizes[sizeNum-1];
        else {
            decipoints = (double) (points * 10);
            size = fe_FindFontPointSize(family, decipoints, False, True);
        }
	if (!size)
	{
            return NULL;
        }
	face = size->faces[faceNum];
	if (!face)
	{
            return NULL;
	}
	font = face->font;
	if (!font)
	{
		font = fe_TryFont(context, familyName, points, sizeNum,
                                  fontmask, charsetID, pitch, faceNum, dpy);
		if (font)
		{
                    face->font = font;
		}
		else if (points == 0)
		{
			for (trySize = sizeNum - 1; trySize > 0; trySize--)
			{
				font = fe_TryFont(context, familyName,
						  points, trySize, fontmask,
						  charsetID, pitch,
						  faceNum, dpy);
				if (font)
				{
					return font;
				}
			}

			for (trySize = sizeNum + 1; trySize < 8; trySize++)
			{
				font = fe_TryFont(context, familyName,
						  points, trySize, fontmask,
						  charsetID, pitch,
						  faceNum, dpy);
				if (font)
				{
					return font;
				}
			}
		}
	}
	return font;
}


static char * NameFromList(char * namelist)
{
    static char * list;
    static int next;
    static int len;

    int start;
    int end;
    char final = '\0';

    if (namelist) {
        list = namelist;
        len = strlen(namelist);
        next = 0;
    }
    
    start = next;
        
    if (! list || list[start] == '\0')
        return (char *) NULL;
        
    /* skip over leading whitespace and commas to find the start of the name */
    while (list[start] != '\0' && (list[start] == ',' || isspace(list[start])))
        start++;
        
    /* find the end of the name */
    next = start;
    while(list[next] != '\0' && list[next] != ',') {
        if (list[next] == '"' || list[next] == '\'') {
            final = list[next];
                        
            /* find the matching quote */
            next++;
            while (list[next] != '\0' && list[next] != final)
                next++;

            /* if list[next] is null, there was no matching quote, so bail */
            if (list[next] == '\0')
                break;
        }
        next++;
    }
    end = next - 1;

    if (list[next] != '\0' && next < len)
        next++;

    /* strip off trailing whitespace */        
    while (end >= start && isspace(list[end]))
        end--;
        
    /* if it's quoted, strip off the quotes */
    if ((list[start] == '"' || list[start] == '\'') && list[end] == list[start]) {
        start++;
        end--;
    }

    end++;
    list[end] = '\0';
    return &(list[start]);
}

fe_Font
fe_LoadFontFromFace(MWContext *context, LO_TextAttr *attr, int16 *charset, char *net_font_face,
		   int size, int fontmask)
{
	fe_Font font = 0;
	char *local_net_font_face = NULL;
	char *familyname = NULL;
        char *last_familyname = NULL;
        unsigned char font_type = 0;
        int16 charsetID;
        int16 saved_charset;
        int points = 0;

	if (attr)
	{
		font = (fe_Font) attr->FE_Data;
		if (font) return(font);

                points = (int) attr->point_size;
                if (points < 1)
                    points = 0;
                if (points > fe_FontMaximumPoints)
                    points = fe_FontMaximumPoints;

                if (attr->font_weight > 0) {
                    if (attr->font_weight <= 500)
                        fontmask &= ~LO_FONT_BOLD;
                    else 
                        fontmask |= LO_FONT_BOLD;
                }
	}

        charsetID = 0;
	if (charset)
	{
		charsetID = *charset;
	}
	else
	{
		charset = &charsetID;
	}

	if (!charsetID)
	{
		charsetID = INTL_DefaultTextAttributeCharSetID(context);
		if (!charsetID)
		{
			charsetID = CS_LATIN1;
		}
		*charset = charsetID;
	}
	charsetID &= 0xff;
	if (charsetID >= INTL_CHAR_SET_MAX)
	{
		charsetID = (CS_LATIN1 & 0xff);
		*charset = CS_LATIN1;
	}
        saved_charset = *charset;

	FE_NORMALIZE_SIZE(size);

	if (net_font_face && *net_font_face)
	{
		local_net_font_face = strdup(net_font_face);
		if (!local_net_font_face) return (0);
		familyname = NameFromList(local_net_font_face);
		while (familyname)
		{
#if !defined(NO_WEB_FONTS) && !defined(NO_BROKERED_WEB_FONTS)

                    /* Prefer fonts from the broker. */
                    font = fe_LoadRenderableFont(context, attr, charset,
                                                 familyname);
                    if (font)
                        font_type = FE_FONT_TYPE_RENDERABLE;
#endif
                    if (! font) {

                        /* First, determine whether any font is available
                         * in this charset; if not, the charset will be 
                         * reassigned to CS_LATIN1.
                         */
                        (void) fe_LoadFont(context, charset, NULL, 0, 3, 0);

                        font = fe_LoadFontWithoutSubstitution(context, charset,
                                    familyname, points, size, fontmask);
                        if (!font)
                            /* Try the other pitch */
                            font = fe_LoadFontWithoutSubstitution(context,
                                        charset, familyname, points, size,
                                        FE_FONT_MASK_TOGGLE_PITCH(fontmask));
                    }

                    if (font) break;
                    last_familyname = familyname;
                    familyname = NameFromList((char *) NULL);
		}
                if (!font && last_familyname) {
                    font = fe_LoadFont(context, charset, last_familyname,
                                       points, size, fontmask);
                    if (!font)
			{
                            /* Try the other pitch */
                            font = fe_LoadFont(context, charset,
                                               familyname, points, size,
                                               FE_FONT_MASK_TOGGLE_PITCH(fontmask));
			}
                }
                XP_FREE(local_net_font_face);
	}

	/* If we didn't get a font from the face, default to no font_face */
	if (!font)
	{
            font =  fe_LoadFont(context, charset, NULL, points, size,
                                fontmask);
	}
	if (font)
	{
                fe_Font platform_font = font;
                if (FE_FONT_TYPE_RENDERABLE != font_type)
                    font_type = fe_CharSetInfoArray[(*charset) & 0xff].type;
                font = WrapPlatformFont(platform_font, font_type);
		if (attr)
		{
			attr->FE_Data = (void *) font;
		}
	}
        /* Preserve the document charset.  Web fonts may be used to
         * render glyphs in character sets which are not represented
         * in the platform-specific font catalog.  
         */
        *charset = saved_charset;
	return(font);
}


static fe_Font WrapPlatformFont(fe_Font platform_font, unsigned char font_type)
{
    fe_FontWrap *fw;

    fw = XP_NEW(fe_FontWrap);
    if (!fw) return NULL;

    fw->platform_font = platform_font;
    fw->distinguisher = font_type;

    return (fe_Font) fw;
}

/* Delete the wrapper but do not free the font. */
void fe_DoneWithFont(fe_Font font)
{
    XP_DELETE(font);
}

static void FreePlatformFont(Display *dpy, XFontStruct *xfs, LO_TextAttr *attr)
{
    XFontProp *prop;
    int n;
    fe_FontSize *size = 0;
    fe_FontSize **prev = 0;
    fe_FontFace *face = 0;
    fe_FontFamily *family;
    XP_Bool in_use;
    XP_Bool found;
    char * familyName;
    int pitch;
    Atom atom;

    /* Do not free fonts which fulfill requests for HTML sizes */
    if (attr->point_size < 1)
        return;

    /* Take the family name from the FAMILY_NAME property of the font */
    familyName = NULL;
    for (n = xfs->n_properties, prop=xfs->properties; --n >= 0; prop++) {
        if (XA_FAMILY_NAME == prop->name) {
            atom = prop->card32;
            familyName = XGetAtomName(dpy, atom);
            break;
        }
    }
    if (! familyName)
        return;

    /* Use the font family name, the requested charset and the 
     * requested pitch to find the family record.
     */
    pitch = FE_FONT_MASK_TO_PITCH(attr->fontmask);
    family = fe_FontFindFamily(attr->charset, pitch, familyName);
    if (! family) {
        pitch = FE_OPPOSITE_PITCH(pitch);
        family = fe_FontFindFamily(attr->charset, pitch, familyName);
    }
    if (! family && CS_LATIN1 != attr->charset) {
        pitch = FE_FONT_MASK_TO_PITCH(attr->fontmask);
        family = fe_FontFindFamily(CS_LATIN1, pitch, familyName);
        if (! family) {
            pitch = FE_OPPOSITE_PITCH(pitch);
            family = fe_FontFindFamily(CS_LATIN1, pitch, familyName);
        }
    }        
    XFree(familyName);

    /* Search through the family pool for a match on this xfs */
    found = False;
    if (family) {
        prev = &(family->pool);
        for (size = family->pool; size; prev = &(size->next), 
                 size = size->next) {
            for (n=0; n <= 3; n++) {
                face = size->faces[n];
                if (face && face->font == xfs) {
                    found = True;
                    break;
                }
            }
            if (found)
                break;
        }
    }

    /* Free the font and set the font field to NULL */
    if (found && size) {
        XFreeFont(dpy, xfs);
        face->font = NULL;

        /* If all the faces are not loaded, free the faces
         * and free the size record which points to them.
         */
        in_use = False;
        for (n=0; n < 4; n++) {
            if (size->faces[n]->font != NULL)
                in_use = True;
        }
        if ((! in_use) && prev) {
            *prev = size->next;
            for (n=0; n < 4; n++) {
                face = size->faces[n];
                if (face->longXLFDFontName)
                    free(face->longXLFDFontName);
                free(face);
            }
            free(size);
        }
    }
}

void FE_ReleaseTextAttrFeData(MWContext *context, LO_TextAttr *attr)
{
    fe_FontWrap *fw;
    struct nfrf *rf;
    XFontStruct *xfs;
    Display *dpy;

    if (!context || !attr)
        return;

    fw = (fe_FontWrap *) attr->FE_Data;
    if (! fw) return;

    switch (fw->distinguisher) {
    case FE_FONT_TYPE_X8:
    case FE_FONT_TYPE_X16:
        dpy = XtDisplay(CONTEXT_WIDGET(context));
        xfs = (XFontStruct *) fw->platform_font;
        FreePlatformFont(dpy, xfs, attr);
        break;

    case FE_FONT_TYPE_GROUP:
    default:
        break;

    case FE_FONT_TYPE_RENDERABLE:
        rf = (struct nfrf *) fw->platform_font;
        nfrf_release(rf, NULL);
        break;
    }

    XP_DELETE(fw);
    attr->FE_Data = NULL;
}

#ifndef NO_WEB_FONTS
static fe_Font fe_LoadRenderableFont(MWContext *context, LO_TextAttr *attr,
                                     int16 *charset, char *family)

{
    int weight;
    int escapement;
    int style;
    int underline;
    int strikeout;
    int charsetID;
    struct nfrc *  rc;
    struct nffmi * fmi;
    struct nff *   unsized_font = NULL;
    struct nfrf *  renderable_font = NULL;
    void *         rcbuf[4];
    double pointsize;
    char mime_name[128];

    if (!context || !attr || !charset)
        return (fe_Font) NULL;
    
    /* Create a rendering context */

    rcbuf[0] = XtDisplay(CONTEXT_WIDGET(context));
    rcbuf[1] = rcbuf[2] = NULL;
    rc = nffbu_CreateRenderingContext(fe_FontUtility, NF_RC_DIRECT, 0,
                                      rcbuf, 3, NULL);
    if (!rc)
        return (fe_Font) NULL;

    /* Create a font match information object */

    charsetID = *charset;
    if (charsetID < 0 || (charsetID & 0xff) >= INTL_CHAR_SET_MAX)
        return (fe_Font) NULL;
    INTL_CharSetIDToName(charsetID, mime_name);
    weight = attr->font_weight;
    if (0 == weight)
        weight = (LO_FONT_BOLD & attr->attrmask) ? 700 : 400;
    style = (LO_FONT_ITALIC & attr->attrmask)
        ? nfStyleItalic : nfStyleNormal;
    underline = (LO_ATTR_UNDERLINE & attr->attrmask) 
        ? nfUnderlineYes : nfUnderlineNo;
    strikeout = (LO_ATTR_STRIKEOUT & attr->attrmask)
        ? nfStrikeOutYes : nfStrikeOutNo;
    escapement = (LO_FONT_FIXED & attr->attrmask)
        ? nfSpacingMonospaced : nfSpacingProportional;
    fmi = nffbu_CreateFontMatchInfo(fe_FontUtility,
                                    family, NULL, mime_name, weight,
                                    escapement, style, underline, strikeout,
                                    nfResolutionDontCare,
                                    nfResolutionDontCare,
                                    NULL /* exception */);

    /* Create the font, cleanup, and return the font */

    if (fmi) {
		/* Find the url that is loading this font */
		History_entry *he = SHIST_GetCurrent(&context->hist);
		const char *accessing_url_str = NULL;
		if (he)
		{
	 		accessing_url_str = he->address;
		}

        unsized_font = nffbc_LookupFont(fe_FontBroker, rc, fmi,
					accessing_url_str, NULL);
        if (!unsized_font) {
            nffbu_LookupFailed(fe_FontUtility, context, rc, fmi, NULL);
        }
        nffmi_release(fmi, NULL);

        if (unsized_font) {

            pointsize = attr->point_size;
            if (pointsize <= 0)
                pointsize = fe_ConvertHTMLSizeToPointSize(attr, charsetID);

            renderable_font = nff_GetRenderableFont(unsized_font, rc,
                                                    pointsize, NULL);
            nff_release(unsized_font, NULL);
        }
    }
    nfrc_release(rc, NULL);
    return ((fe_Font) renderable_font);
}


int fe_WebfontsNeedReload(MWContext *context)
{
	int ret = 0;
	if (fe_FontUtility)
	{
    	ret = nffbu_WebfontsNeedReload(fe_FontUtility, context, NULL);
	}
	return (ret);
}

void fe_ShutdownWebfonts(void)
{
	char buf[MAXPATHLEN];
	char *home = NULL;

	/* Load Catalog */
	if (home = getenv("HOME"))
	{
		/* Form "$HOME/.netscape/dynfonts/fonts.cat" into buf */
		strncpy(buf, home, sizeof(buf)-1);
		strncat(buf, "/.netscape/dynfonts/fonts.cat",
				sizeof(buf)-1 - strlen(buf));
		buf[sizeof(buf)-1] = '\0';
		nffbu_SaveCatalog(fe_FontUtility, buf, NULL);
	}
}


static double fe_ConvertHTMLSizeToPointSize(LO_TextAttr *attr, int16 charset)
{
    int j;
    int size3;
    double decipoints = 0.0;
    fe_FontFamily *family;
    fe_FontSize *size;
    int pitch;
    double pointsize;

    /* Translate HTML sizes 1-7 to pointsize */

    /* Take the default size of the default family for
     * this charset to be the pointsize of HTML size 3,
     * if it is given; otherwise, use 12 points.
     */
    size3 = 0;
    size = NULL;
    pitch = FE_FONT_MASK_TO_PITCH(attr->attrmask);
    family = FE_FONT_SELECTED_FAMILY(charset, pitch);
    if (family && family->name) {
        for (j = 0; j < family->numberOfPointSizes; j++) {
            size = &family->pointSizes[j];
            if (size->selected) {
                break;
            } else {
                size = NULL;
            }
        }
        if (size)
            size3 = size->size;
        if (!size3)
            size3 = family->scaledSize;
    }
    if (!size3)
        size3 = 120;

    /* Sizing logic from fe_ComputeFontSizeTable */
    if (attr->size < 3) {
        decipoints = ((1 - ((3 - attr->size)
                            * fe_FontSizeIncrement)) * size3);
        if (decipoints < 10)
            decipoints = 10;
    } else if (attr->size == 3) {
        decipoints = size3;
    } else if (attr->size > 3) {
        decipoints = ((1 + ((attr->size - 3)
                            * fe_FontSizeIncrement)) * size3);
    }

    pointsize = decipoints / 10;
    return pointsize;
}

#endif /* ifndef NO_WEB_FONTS */


XtPointer
fe_GetFontOrFontSetFromFace(MWContext *context, LO_TextAttr *attr, char *net_font_face,
			    int size, int fontmask, XmFontType *type)
{
	XtPointer fontOrFontset = 0;
	char *local_net_font_face = NULL;
	char *familyname = NULL;

	if (attr)
	{
		fontOrFontset = (fe_Font) attr->FE_Data;
		if (fontOrFontset) return(fontOrFontset);
	}
	
	if (net_font_face && *net_font_face)
	{
		local_net_font_face = strdup(net_font_face);
		if (!local_net_font_face) return (0);
		familyname = NameFromList(local_net_font_face);
		while (familyname)
		{
			fontOrFontset = fe_GetFontOrFontSet(context, familyname, size,
							    fontmask, type);
			if (!fontOrFontset)
			{
				/* Try the other pitch */
				fontOrFontset = fe_GetFontOrFontSet(context, familyname, size,
								    FE_FONT_MASK_TOGGLE_PITCH(fontmask),
								    type);
			}
			if (fontOrFontset) break;
			familyname = NameFromList((char *) NULL);
		}
		XP_FREE(local_net_font_face);
	}
	
	if (!fontOrFontset)
	{
		fontOrFontset = fe_GetFontOrFontSet(context, NULL, size,
						    fontmask, type);
	}
	if (fontOrFontset)
	{
		if (attr)
		{
			attr->FE_Data = (void *) fontOrFontset;
		}
	}
	return(fontOrFontset);
}


static void *
fe_ReallocZap(void *p, int oldSize, int newSize)
{
	char	*end;
	char	*q;

	p = realloc(p, newSize);
	if (p)
	{
		if (newSize > oldSize)
		{
			end = ((char *) p) + newSize;
			for (q = ((char *) p) + oldSize; q < end; q++)
			{
				*q = 0;
			}
		}
	}

	return p;
}


#define FE_REALLOC_ZAP(p, oldSize, newSize, type) \
  ((type *) fe_ReallocZap((p), (oldSize) * sizeof(type), \
    (newSize) * sizeof(type)))


static char *
fe_CapitalizeFontName(char *name)
{
	char	*p;
	char	*ret;

	ret = strdup(name);
	if (!ret)
	{
		return NULL;
	}

	p = ret;
	while (1)
	{
		while ((*p) && XP_IS_SPACE(*p))
		{
			p++;
		}
		if (!*p)
		{
			break;
		}
		*p = XP_TO_UPPER(*p);
		while ((*p) && (!XP_IS_SPACE(*p)))
		{
			p++;
		}
		if (!*p)
		{
			break;
		}
	}

	return ret;
}


static void
fe_AddFontSize(fe_FontFamily *family, int faceNum, int pixelSizeNum,
	int pointSizeNum, char *pixelSizeFontSpec, char *pointSizeFontSpec)
{
	int		alloc;
	fe_FontFace	*face;
	int		i;
	fe_FontSize	*newSizes;
	fe_FontSize	*size;

	/*
	 * first we do the pixel size
	 */

	size = NULL;

	if (family->pixelSizes)
	{
		for (i = 0; i < family->numberOfPixelSizes; i++)
		{
			size = &family->pixelSizes[i];
			if (size->size == pixelSizeNum)
			{
				break;
			}
			else
			{
				size = NULL;
			}
		}
	}

	if (!size)
	{
		if (family->numberOfPixelSizes >= family->pixelAlloc)
		{
			alloc = (2 * (family->pixelAlloc + 1));
			newSizes = FE_REALLOC_ZAP(family->pixelSizes,
				family->pixelAlloc, alloc, fe_FontSize);
			if (!newSizes)
			{
				return;
			}
			family->pixelSizes = newSizes;
			family->pixelAlloc = alloc;
		}
		size = &family->pixelSizes[family->numberOfPixelSizes++];
		size->size = pixelSizeNum;
	}

	if (!size->faces[faceNum])
	{
		face = FE_MALLOC_ZAP(fe_FontFace);
		if (!face)
		{
			return;
		}
		face->longXLFDFontName = strdup(pixelSizeFontSpec);
		if (!face->longXLFDFontName)
		{
			free(face);
			return;
		}
		face->next = fe_FontFaceList;
		fe_FontFaceList = face;
		size->faces[faceNum] = face;
	}
	else
	{
		/* @@@ fix this -- erik */
		/*
		(void) fprintf(real_stderr, "dup %s\n", pixelSizeFontSpec);
		*/
	}

	/*
	 * now we do the same for the point size
	 */

	size = NULL;

	if (family->pointSizes)
	{
		for (i = 0; i < family->numberOfPointSizes; i++)
		{
			size = &family->pointSizes[i];
			if (size->size == pointSizeNum)
			{
				break;
			}
			else
			{
				size = NULL;
			}
		}
	}

	if (!size)
	{
		if (family->numberOfPointSizes >= family->pointAlloc)
		{
			alloc = (2 * (family->pointAlloc + 1));
			newSizes = FE_REALLOC_ZAP(family->pointSizes,
				family->pointAlloc, alloc, fe_FontSize);
			if (!newSizes)
			{
				return;
			}
			family->pointSizes = newSizes;
			family->pointAlloc = alloc;
		}
		size = &family->pointSizes[family->numberOfPointSizes++];
		size->size = pointSizeNum;
	}

	if (!size->faces[faceNum])
	{
		face = FE_MALLOC_ZAP(fe_FontFace);
		if (!face)
		{
			return;
		}
		face->longXLFDFontName = strdup(pointSizeFontSpec);
		if (!face->longXLFDFontName)
		{
			free(face);
			return;
		}
		face->next = fe_FontFaceList;
		fe_FontFaceList = face;
		size->faces[faceNum] = face;
	}
	else
	{
		/* @@@ fix this -- erik */
		/*
		(void) fprintf(real_stderr, "dup %s\n", pointSizeFontSpec);
		*/
	}
}


static void
fe_AddFontFamily(fe_FontPitch *pitch, char *origFoundry, char *foundry,
	char *origFamily, char *familyName, int face, int pixelSize,
	int pointSize, char *pixelSizeFontSpec, char *pointSizeFontSpec,
	int charsetID, char *origCharset)
{
	int		alloc;
	fe_FontFamily	*family;
	int		i;
	char		*name;
	fe_FontFamily	*newFamilies;

	if (charsetID == CS_USRDEF2)
	{
		if (*foundry)
		{
			name = PR_smprintf("%s (%s, %s)", familyName, foundry,
				origCharset);
		}
		else
		{
			name = PR_smprintf("%s (%s)", familyName, origCharset);
		}
	}
	else
	{
		if (*foundry)
		{
			name = PR_smprintf("%s (%s)", familyName, foundry);
		}
		else
		{
			name = strdup(familyName);
		}
	}
	if (!name)
	{
		return;
	}

	family = NULL;

	if (pitch->families)
	{
		for (i = 0; i < pitch->numberOfFamilies; i++)
		{
			family = &pitch->families[i];
			if (!strcmp(family->name, name))
			{
				break;
			}
			else
			{
				family = NULL;
			}
		}
	}

	if (family)
	{
		free(name);
	}
	else
	{
		if (pitch->numberOfFamilies >= pitch->alloc)
		{
			alloc = (2 * (pitch->alloc + 1));
			newFamilies = FE_REALLOC_ZAP(pitch->families,
				pitch->alloc, alloc, fe_FontFamily);
			if (!newFamilies)
			{
				free(name);
				return;
			}
			pitch->families = newFamilies;
			pitch->alloc = alloc;
		}
		family = &pitch->families[pitch->numberOfFamilies++];
		family->name = name;
		family->family = strdup(origFamily);
		family->foundry = strdup(origFoundry);
	}

	fe_AddFontSize(family, face, pixelSize, pointSize, pixelSizeFontSpec,
		pointSizeFontSpec);
}


static void
fe_AddFontCharSet(char *origFoundry, char *foundry, char *origFamily,
	char *family, int face, int pixelSize, int pointSize, int pitch,
	int charsetID, char *charset, char *charsetlang,
	char *pixelSizeFontSpec, char *pointSizeFontSpec, char *origCharset)
{
	char	mimeName[128];
	char	*name;

	if ((charsetID < 0) || (charsetID >= INTL_CHAR_SET_MAX))
	{
		return;
	}

	if (!fe_FontCharSets[charsetID].name)
	{
		if (charsetID == CS_USRDEF2)
		{
			name = strdup(XP_GetString(XFE_USER_DEFINED));
		}
		else
		{
			name = PR_smprintf("%s (%s)", charsetlang, charset);
		}
		if (!name)
		{
			return;
		}
		fe_FontCharSets[charsetID].name = name;

		INTL_CharSetIDToName(charsetID, mimeName);
		fe_FontCharSets[charsetID].mimeName = strdup(mimeName);
		if (!fe_FontCharSets[charsetID].mimeName)
		{
			return;
		}
	}

	if (pitch & fe_FONT_PITCH_PROPORTIONAL)
	{
		fe_AddFontFamily(&fe_FontCharSets[charsetID].pitches[0],
			origFoundry, foundry, origFamily, family, face,
			pixelSize, pointSize, pixelSizeFontSpec,
			pointSizeFontSpec, charsetID, origCharset);
	}

	if (pitch & fe_FONT_PITCH_MONO)
	{
		fe_AddFontFamily(&fe_FontCharSets[charsetID].pitches[1],
			origFoundry, foundry, origFamily, family, face,
			pixelSize, pointSize, pixelSizeFontSpec,
			pointSizeFontSpec, charsetID, origCharset);
	}
}


static char *
fe_PropOrFixedFont(int i)
{
	return i == 0 ? "prop" : "fixed";
}


#define FE_INDEX_TO_FACE(face) (face == 0 ? "normal" : face == 1 ? "bold" : \
	face == 2 ? "italic" : "boldItalic")


#ifdef FE_PRINT_FONTS
static void
fe_PrintFamily(fe_FontFamily *family)
{
	fe_FontFace	*face;
	int		i;
	int		j;
	fe_FontSize	*size;

        (void) fprintf(real_stderr, "    %s\n", family->name);
	for (i = 0; i < family->numberOfPointSizes; i++)
	{
		size = &family->pointSizes[i];
		(void) fprintf(real_stderr, "      %d\n", size->size / 10);
		for (j = 0; j < 4; j++)
		{
			(void) fprintf(real_stderr, "        %s\n",
				FE_INDEX_TO_FACE(j));
			face = size->faces[j];
			(void) fprintf(real_stderr, "          %s\n",
					face->longXLFDFontName);
		}
	}
}


static void
fe_PrintFonts(void)
{
	fe_FontCharSet	*charset;
	int		i;
	int		j;
	int		k;
	fe_FontPitch	*pitch;

	for (i = 0; i < INTL_CHAR_SET_MAX; i++)
	{
		charset = &fe_FontCharSets[i];
		if (!charset->name)
		{
			continue;
		}
		(void) fprintf(real_stderr, "%s\n", charset->name);
		for (j = 0; j < 2; j++)
		{
			(void) fprintf(real_stderr, "  %s\n",
				fe_PropOrFixedFont(j));
			pitch = &charset->pitches[j];
			for (k = 0; k < pitch->numberOfFamilies; k++)
			{
				fe_PrintFamily(&pitch->families[k]);
			}
		}
	}
}
#endif /* FE_PRINT_FONTS */


static int
fe_CompareFontCharSets(unsigned char *charset1, unsigned char *charset2)
{
	char	*name1;
	char	*name2;

	name1 = fe_FontCharSets[*charset1].name;
	name2 = fe_FontCharSets[*charset2].name;

	if (!name1)
	{
		if (!name2)
		{
			return 0;
		}

		return 1;
	}

	if (!name2)
	{
		return -1;
	}

	return strcmp(name1, name2);
}


static int
fe_CompareFontFamilies(fe_FontFamily *family1, fe_FontFamily *family2)
{
	return strcmp(family1->name, family2->name);
}


static int
fe_CompareFontSizes(fe_FontSize *size1, fe_FontSize *size2)
{
	return size1->size - size2->size;
}


typedef int (*fe_CompFunc)(const void *, const void *);


static void
fe_SortFonts(void)
{
	fe_FontCharSet	*charset;
	fe_FontFamily	*family;
	int		i;
	int		j;
	int		k;
	fe_FontPitch	*pitch;


	for (i = 0; i < INTL_CHAR_SET_MAX; i++)
	{
		fe_SortedFontCharSets[i] = i;
	}
	XP_QSORT(fe_SortedFontCharSets, INTL_CHAR_SET_MAX,
			 sizeof(*fe_SortedFontCharSets),
			 (fe_CompFunc) fe_CompareFontCharSets);


	for (i = 0; i < INTL_CHAR_SET_MAX; i++)
	{
		charset = &fe_FontCharSets[i];
		if (!charset->name)
		{
			continue;
		}
		for (j = 0; j < 2; j++)
		{
			pitch = &charset->pitches[j];
			if (pitch->families)
			{
				XP_QSORT(pitch->families, pitch->numberOfFamilies,
						 sizeof(fe_FontFamily),
						 (fe_CompFunc) fe_CompareFontFamilies);
			}
			for (k = 0; k < pitch->numberOfFamilies; k++)
			{
				family = &pitch->families[k];
				XP_QSORT(family->pixelSizes,
						 family->numberOfPixelSizes,
						 sizeof(fe_FontSize),
						 (fe_CompFunc) fe_CompareFontSizes);
				XP_QSORT(family->pointSizes,
						 family->numberOfPointSizes,
						 sizeof(fe_FontSize),
						 (fe_CompFunc) fe_CompareFontSizes);
			}
		}
	}
}


void
fe_ReadFontCharSet(char *charsetname)
{
	fe_FontCharSet	*charset;
	int16		charsetID;
	int		i;

	charsetID = (INTL_CharSetNameToID(charsetname) & 0xff);
	if ((charsetID < 0) || (charsetID >= INTL_CHAR_SET_MAX))
	{
		charsetID = CS_LATIN1;
	}
	charsetID &= 0xff;

	for (i = 0; i < INTL_CHAR_SET_MAX; i++)
	{
		fe_FontCharSets[i].selected = 0;
	}

	charset = &fe_FontCharSets[charsetID];
	if (charset->name)
	{
		charset->selected = 1;
	}
	else
	{
		charset = NULL;
		for (i = 0; i < INTL_CHAR_SET_MAX; i++)
		{
			charset = &fe_FontCharSets[i];
			if (!charset->name)
			{
				charset = NULL;
				continue;
			}
			charset->selected = 1;
			break;
		}
	}
	if (!charset)
	{
		/* this should never happen */
		(void) fprintf(real_stderr, "no recognized font charsets!\n");
		exit(1);
	}
}


void
fe_ReadFontSpec(char *spec)
{
	fe_FontCharSet	*charset;
	char		*charSetName;
	fe_FontFamily	*family;
	char		*familyName;
	char		*foundry;
	int		i;
	int		j;
	int		k;
	int		m;
	char		*p;
	fe_FontPitch	*pitch;
	char		*pitchName;
	char		*s;
	char		*scaling;
	fe_FontSize	*size;
	char		*sizeName;
	int		sizeNum;

	s = strdup(spec);
	if (!s)
	{
		return;
	}

	p = s;

	foundry = p;
	p = strchr(p, '-');
	if (!p)
	{
		return;
	}
	*p++ = 0;

	familyName = p;
	p = strchr(p, '-');
	if (!p)
	{
		return;
	}
	*p++ = 0;

	sizeName = p;
	p = strchr(p, '-');
	if (!p)
	{
		return;
	}
	*p++ = 0;
	(void) sscanf(sizeName, "%d", &sizeNum);

	scaling = p;
	p = strchr(p, '-');
	if (!p)
	{
		return;
	}
	*p++ = 0;

	pitchName = p;
	p = strchr(p, '-');
	if (!p)
	{
		return;
	}
	*p++ = 0;

	charSetName = p;


	for (i = 0; i < INTL_CHAR_SET_MAX; i++)
	{
		charset = &fe_FontCharSets[i];
		if ((!charset->name) || strcmp(charset->mimeName, charSetName))
		{
			continue;
		}

		j = (*pitchName == 'p' ? 0 : 1);
		pitch = &charset->pitches[j];

		family = NULL;
		for (k = 0; k < pitch->numberOfFamilies; k++)
		{
			family = &pitch->families[k];

			if ((!strcmp(family->foundry, foundry)) &&
				(!strcmp(family->family, familyName)))
			{
				break;
			}
			else
			{
				family = NULL;
			}
		}
		if (family)
		{
			for (k = 0; k < pitch->numberOfFamilies; k++)
			{
				pitch->families[k].selected = 0;
			}
			family->selected = 1;
			pitch->selectedFamily = family;

			family->allowScaling = (((*scaling) == 's') ? 1 : 0);

			/*
			 * sanity check
			 */
			if (family->pointSizes->size)
			{
				family->allowScaling = 0;
			}
			else if (family->numberOfPointSizes == 1)
			{
				family->allowScaling = 1;
			}

			size = NULL;
			for (m = 0; m < family->numberOfPointSizes; m++)
			{
				size = &family->pointSizes[m];
				if (size->size == sizeNum)
				{
					break;
				}
				else
				{
					size = NULL;
				}
			}
			if (size)
			{
				for (m = 0; m < family->numberOfPointSizes; m++)
				{
					family->pointSizes[m].selected = 0;
				}
				size->selected = 1;
			}
			else if (family->allowScaling)
			{
				for (m = 0; m < family->numberOfPointSizes; m++)
				{
					family->pointSizes[m].selected = 0;
				}
				family->pointSizes[0].selected = 1;
				family->scaledSize = sizeNum;
			}
		}

		break;
	}

	free(s);
}


static fe_FontSize *
fe_GetScaledFontSize(fe_FontFamily *family, double idealSize, XP_Bool make_global)
{
	fe_FontFace	*face;
	int		i;
	fe_FontSize	*ret;

	ret = FE_MALLOC_ZAP(fe_FontSize);
	if (!ret)
	{
		return NULL;
	}
        if (make_global) {
            ret->next = fe_FontSizeList;
            fe_FontSizeList = ret;
        }

	ret->size = idealSize;

	for (i = 0; i < 4; i++)
	{
		ret->faces[i] = FE_MALLOC_ZAP(fe_FontFace);
		face = ret->faces[i];
		if (!face)
		{
			return NULL;
		}
                if (make_global) {
                    face->next = fe_FontFaceList;
                    fe_FontFaceList = face;
                }
		face->longXLFDFontName = PR_smprintf(
			family->pointSizes->faces[i]->longXLFDFontName,
			ret->size);
		if (!face->longXLFDFontName)
		{
			return NULL;
		}
	}

	return ret;
}


static fe_FontSize *
fe_FindFontPointSize(fe_FontFamily *family, double idealSize,
                     XP_Bool search_for_fit, XP_Bool scale_to_fit)
{
	int		i;
	double		minDist;
	fe_FontSize	*minSize;
	fe_FontSize	*maxSize;
	double		newDist;
	fe_FontSize	*ret;
	fe_FontSize	*size;

	ret = NULL;

        if (! family->pointSizes)
            return NULL;

	if (family->pointSizes->size == 0)
	{
		minSize = &family->pointSizes[1];
	}
	else
	{
		minSize = family->pointSizes;
	}
	maxSize = &family->pointSizes[family->numberOfPointSizes - 1];

	if ((idealSize < minSize->size) || (idealSize > maxSize->size))
	{
		if (idealSize > maxSize->size)
		{
			ret = maxSize;
		}
		if (idealSize < minSize->size)
		{
			ret = minSize;
		}
	}
	else
	{
                minDist = (1E+36);
		ret = family->pointSizes;
		for (i = 0; i < family->numberOfPointSizes; i++)
		{
			size = &family->pointSizes[i];
			newDist = ((idealSize - size->size) *
				   (idealSize - size->size));
			if (newDist < minDist)
			{
				minDist = newDist;
				ret = size;
			}
			else
			{
				break;
			}
		}
	}

        if (search_for_fit) {

            minDist =  (ret)
                ? ((idealSize - ret->size) * (idealSize - ret->size))
                : (1E+36);

            for (size = family->pool; size; size = size->next) {
                newDist = ((idealSize - size->size) *
                           (idealSize - size->size));
                if (newDist < minDist) {
                    minDist = newDist;
                    ret = size;
                }
            }
        }

        if (scale_to_fit) {

            /* We have deliberately first searched through the array
             * of HTML point sizes for a match within 1/2 point of the
             * requested point size because we prefer hand-tuned bitmaps
             * to scaled outlines, all other things being equal.
             */

            minDist =  (ret)
                ? ((idealSize - ret->size) * (idealSize - ret->size))
                : (1E+36);

            if (0 == family->pointSizes->size && minDist > 0.25) {

                size = fe_GetScaledFontSize(family, idealSize, False);
                if (size) {

                    /* mark to be freed when the context expires */
                    size->in_pool = 1;

                    /* hang off of the family */
                    size->next = family->pool;
                    family->pool = size;

                    ret = size;
                }
            }
        }

	return ret;
}


static fe_FontSize *
fe_ComputeFontSize(fe_FontFamily *family, double idealSize)
{
    if (family->allowScaling)
        return fe_GetScaledFontSize(family, idealSize, True);

    /* Pass False for scale_to_fit: fe_ComputeFontSize
     * is used only to compute the table of HTML sizes.  
     * In integrating the range of sizes allowed by CSS-1, we want
     * no perturbation of font sizes as they are instantiated through
     * HTML size requests.  Therefore, offer to scale outline fonts
     * in the construction of the HTML size table only when the
     * allowScaling flag is set for that particular family, as was
     * the case prior to CSS-1.
     */

    return fe_FindFontPointSize(family, idealSize, False, False);
}


void
fe_FreeFontGroups(void)
{
#if 0
	fe_FontCharSet	*charset;
	fe_FontFace	*face;
	int		i;
	int		j;
	int		k;
	int		m;
	fe_FontPitch	*pitch;
	fe_FontSize	*size;

	for (i = 0; i < INTL_CHAR_SET_MAX; i++)
	{
		charset = &fe_FontCharSets[i];
		if (fe_CharSetInfoArray[i].type == FE_FONT_TYPE_GROUP)
		{
			for (j = 0; j < 2; j++)
			{
				pitch = &charset->pitches[j];
				if (!pitch->selectedFamily)
				{
					continue;
				}
				for (k = 0; k < 7; k++)
				{
					size = pitch->selectedFamily->htmlSizes[k];
					if (size)
					{
						for (m = 0; m < 4; m++)
						{
							face = size->faces[m];
							if (face)
							{
								free(face);
							}
						}
						free(size);
					}
				}
				free(pitch->selectedFamily);
				pitch->selectedFamily = NULL;
			}
		}
	}
#endif
}

void
fe_FreeUnicodeFonts(void)
{
    fe_FontCharSet *charset;
    fe_FontFace *face;
    int i_pitch, i_htmlsize, i_face, i_encodings;
    fe_FontPitch *pitch;
    fe_FontSize *size;
    fe_UnicodePseudoFont *ufont;

    charset = &fe_FontCharSets[CS_UTF8&0xFF];
    for (i_pitch = 0; i_pitch < 2; i_pitch++) {
        pitch = &charset->pitches[i_pitch];
        if (!pitch->selectedFamily)
           continue;
        for (i_htmlsize = 0; i_htmlsize < 7; i_htmlsize++) {
            size = pitch->selectedFamily->htmlSizes[i_htmlsize];
            if (!size)
                continue;
            for (i_face = 0; i_face < 4; i_face++) {
                face = size->faces[i_face];
                if (!face)
                    continue;
                if (!face->font)
                    continue;
                ufont = (fe_UnicodePseudoFont *)face->font;
                if (ufont->tag != UNICODE_PSEUDO_FONT_TAG) {
                    continue;
                }
                for (i_encodings=0; i_encodings<INTL_CHAR_SET_MAX; 
                                                        i_encodings++) {
                    if (ufont->xfont_scaled[i_encodings]) {
                        XFreeFont(ufont->dpy, ufont->xFonts[i_encodings]);
						XP_FREE(ufont->xfont_name[i_encodings]);
                    }
                    ufont->xfont_inited[i_encodings] = FALSE;
                    ufont->xfont_scaled[i_encodings] = FALSE;
                    ufont->xfont_name[i_encodings] = NULL;
                    ufont->larger_fonts_avail[i_encodings] = FALSE;
					if (ufont->xmfontlist) 
						XmFontListFree(ufont->xmfontlist);
					ufont->xmfontlist = NULL;
					if (ufont->xm_fontset) 
						XmFontListFree(ufont->xm_fontset);
					ufont->xm_fontset = NULL;
					if (ufont->xfontset) 
						XFreeFontSet(ufont->dpy, ufont->xfontset);
					ufont->xfontset = NULL;
                }
            }
        }
    }
}

void
fe_FreeFontSizeTable(fe_FontFamily *family)
{
	int		k,m;
	fe_FontSize	*size;
	fe_FontFace	*face;

	if (!family->htmlSizesComputed) return;

	family->htmlSizesComputed = 0;

	/*
	 * Only the scaled fonts were allocated new sizes. Hence we free
	 * only them.
	 */
	if (!family->allowScaling) return;

	for (k = 0; k < 7; k++)
	{
		size = family->htmlSizes[k];
		if (size)
		{
			for (m = 0; m < 4; m++)
			{
				face = size->faces[m];
				if (face)
				{
					free(face);
				}
			}
			free(size);
			family->htmlSizes[k] = NULL;
		}
	}
}

void
fe_ComputeFontSizeTable(fe_FontFamily *family)
{
	int		i;
	double		idealSize;
	int		j;
	fe_FontSize	*size;
	int		size3;

	size = NULL;

	/*
	 * first, find the size selected within the family
	 */
	for (j = 0; j < family->numberOfPointSizes; j++)
	{
		size = &family->pointSizes[j];
		if (size->selected)
		{
			break;
		}
		else
		{
			size = NULL;
		}
	}

	if ((!family) || (!size))
	{
		/* this should not happen */
		return;
	}

	fe_FreeFontGroups();
	fe_FreeFontSizeTable(family);

	/*
	 * set the default size (3)
	 */
	size3 = size->size;
	if (!size3)
	{
		size3 = family->scaledSize;
	}
	if (!size3)
	{
		size3 = 120;
	}

	i = 3;
	idealSize = size3;
	family->htmlSizes[i - 1] = fe_ComputeFontSize(family, idealSize);

	/*
	 * set the higher sizes (4-7)
	 */
	for (i = 4; i <= 7; i++)
	{
		idealSize = ((1 + ((i - 3) * fe_FontSizeIncrement)) * size3);
		family->htmlSizes[i - 1] = fe_ComputeFontSize(family, idealSize);
	}

	/*
	 * set the lower sizes (1-2)
	 */
	for (i = 1; i <= 2; i++)
	{
		idealSize = ((1 - ((3 - i) * fe_FontSizeIncrement)) * size3);
		if (idealSize < 10)
		{
			idealSize = 10;
		}
		family->htmlSizes[i - 1] = fe_ComputeFontSize(family, idealSize);
	}

	/*
	 * mark family that htmlSizes has been computed.
	 */
	family->htmlSizesComputed = 1;

	/* @@@ need to implement this in case any of the scaled
	 * sizes couldn't be malloc'ed -- erik
	 * fe_CheckFonts();
	 */
}


static int
fe_CloneFamily(fe_FontFamily *cloneFamily, fe_FontFamily *origFamily)
{
	int	i;

	cloneFamily->name = strdup(origFamily->name);
	cloneFamily->foundry = strdup(origFamily->foundry);
	cloneFamily->family = strdup(origFamily->family);
	if ((!cloneFamily->name) || (!cloneFamily->foundry) ||
		(!cloneFamily->family))
	{
		return 0;
	}

	cloneFamily->selected = origFamily->selected;
	cloneFamily->allowScaling = origFamily->allowScaling;

	cloneFamily->pointAlloc = origFamily->pointAlloc;
	cloneFamily->numberOfPointSizes = origFamily->numberOfPointSizes;

	cloneFamily->pointSizes = XP_CALLOC(cloneFamily->pointAlloc,
		sizeof(fe_FontSize));
	if (!cloneFamily->pointSizes)
	{
		return 0;
	}

	for (i = 0; i < cloneFamily->numberOfPointSizes; i++)
	{
		cloneFamily->pointSizes[i] = origFamily->pointSizes[i];
	}

	if (origFamily->allowScaling)
	{
		/*
		 * For scaled families, take care to copy the sizes and faces.
		 * Setting this will make the sizes get recomputed.
		 */
		cloneFamily->htmlSizesComputed = 0;
	}
	else 
	{
		cloneFamily->htmlSizesComputed = origFamily->htmlSizesComputed;
		for (i = 0; i < 7; i++)
		{
			cloneFamily->htmlSizes[i] = origFamily->htmlSizes[i];
		}
	}
	return 1;
}


static int
fe_ClonePitch(fe_FontPitch *clonePitch, fe_FontPitch *origPitch)
{
	int	i;

	clonePitch->alloc = origPitch->alloc;
	clonePitch->numberOfFamilies = origPitch->numberOfFamilies;

	clonePitch->families = XP_CALLOC(clonePitch->alloc,
		sizeof(fe_FontFamily));
	if (!clonePitch->families)
	{
		return 0;
	}

	for (i = 0; i < clonePitch->numberOfFamilies; i++)
	{
		if (!fe_CloneFamily(&clonePitch->families[i],
			&origPitch->families[i]))
		{
			return 0;
		}
	}

	clonePitch->selectedFamily = NULL;

	return 1;
}


static void
fe_SetDefaultFontSettings(Display *dpy)
{
	fe_FontCharSet	*charset;
	char		*charsetname;
	char		clas[512];
	XrmDatabase	db;
	fe_FontFace	**faces;
	fe_FontFamily	*family;
	int		i;
	int		j;
	int		k;
	int		m;
	char		name[512];
	fe_FontPitch	*pitch;
	fe_FontSize	*size;
	char		*spec;
	char		*type;
	XrmValue	value;


	db = XtDatabase(dpy);


	/*
	 * try to get the default charset from the resources
	 */
	(void) PR_snprintf(clas, sizeof(clas),
		"%s.DocumentFonts.DefaultCharSet", fe_progclass);
	(void) PR_snprintf(name, sizeof(name),
		"%s.documentFonts.defaultCharSet", fe_progclass);
	if (XrmGetResource(db, name, clas, &type, &value))
	{
		charsetname = (char *) value.addr;
	}
	else
	{
		charsetname = "iso-8859-1";
	}
	fe_ReadFontCharSet(charsetname);


	/*
	 * try to get the default fonts from the resources
	 */
	for (i = 0; i < INTL_CHAR_SET_MAX; i++)
	{
		charset = &fe_FontCharSets[i];
		if (!charset->name)
		{
			continue;
		}
		for (j = 0; j < 2; j++)
		{
			(void) PR_snprintf(clas, sizeof(clas),
				"%s.DocumentFonts.DefaultFont.CharSet.Pitch",
				fe_progclass);
			(void) PR_snprintf(name, sizeof(name),
				"%s.documentFonts.defaultFont.%s.%s",
				fe_progclass, charset->mimeName,
				fe_PropOrFixedFont(j));
			if (XrmGetResource(db, name, clas, &type, &value))
			{
				spec = PR_smprintf("%s-%s-%s",
					(char *) value.addr,
					fe_PropOrFixedFont(j),
					charset->mimeName);
				if (!spec)
				{
					continue;
				}
				fe_ReadFontSpec(spec);
				free(spec);
			}
		}
	}


	/*
	 * make sure we have families set for each charset/pitch,
	 * and sizes set for each family
	 */
	for (i = 0; i < INTL_CHAR_SET_MAX; i++)
	{
		charset = &fe_FontCharSets[i];
		if (!charset->name)
		{
			continue;
		}
		for (j = 0; j < 2; j++)
		{
			pitch = &charset->pitches[j];
			for (k = 0; k < pitch->numberOfFamilies; k++)
			{
				family = &pitch->families[k];
				for (m = 0; m < family->numberOfPointSizes; m++)
				{
					faces = family->pointSizes[m].faces;
					if (!faces[0])
					{
						if (faces[1])
						{
							faces[0] = faces[1];
						}
						else if (faces[2])
						{
							faces[0] = faces[2];
						}
						else
						{
							faces[0] = faces[3];
						}
					}
					if (!faces[1])
					{
						if (faces[3])
						{
							faces[1] = faces[3];
						}
						else if (faces[2])
						{
							faces[1] = faces[2];
						}
						else
						{
							faces[1] = faces[0];
						}
					}
					if (!faces[2])
					{
						if (faces[3])
						{
							faces[2] = faces[3];
						}
						else if (faces[1])
						{
							faces[2] = faces[1];
						}
						else
						{
							faces[2] = faces[0];
						}
					}
					if (!faces[3])
					{
						if (faces[1])
						{
							faces[3] = faces[1];
						}
						else if (faces[2])
						{
							faces[3] = faces[2];
						}
						else
						{
							faces[3] = faces[0];
						}
					}
				}

				/*
				 * make sure a size is selected for each family
				 */
				size = NULL;
				for (m = 0; m < family->numberOfPointSizes; m++)
				{
					size = &family->pointSizes[m];
					if (size->selected)
					{
						break;
					}
					else
					{
						size = NULL;
					}
				}
				if ((!size) && family->numberOfPointSizes)
				{
					size = &family->pointSizes
						[(family->numberOfPointSizes+1)/2-1];
					size->selected = 1;
				}

				/*
				 * determine whether or not we allow scaling
				 * from the available sizes
				 */
				if ((family->numberOfPointSizes == 1) &&
					(family->pointSizes->size == 0))
				{
					family->allowScaling = 1;
				}
			}

			/*
			 * make sure a family is selected for each pitch
			 */
			family = NULL;
			for (k = 0; k < pitch->numberOfFamilies; k++)
			{
				family = &pitch->families[k];
				if (family->selected)
				{
					break;
				}
				else
				{
					family = NULL;
				}
			}
			if ((!family) && pitch->numberOfFamilies)
			{
				family = &pitch->families[0];
				family->selected = 1;
			}
			/* Force recomputation */
			if (family) fe_FreeFontSizeTable(family);
		}

		/*
		 * if some charset has fonts in one pitch, but not the
		 * other, we clone the one that is available, so that
		 * we always have a pitch available
		 */
		if (!charset->pitches[0].families)
		{
			if (!fe_ClonePitch(&charset->pitches[0],
				&charset->pitches[1]))
			{
				/*
				 * if we can't clone the pitch, we
				 * disable the whole charset
				 */
				free(charset->name);
				charset->name = NULL;
			}
		}
		else if (!charset->pitches[1].families)
		{
			if (!fe_ClonePitch(&charset->pitches[1],
				&charset->pitches[0]))
			{
				/*
				 * if we can't clone the pitch, we
				 * disable the whole charset
				 */
				free(charset->name);
				charset->name = NULL;
			}
		}
	}
}


static void
fe_ReportFontCharSets(void)
{
	fe_FontCharSet	*charset;
	int16		*charsets;
	int		i;
	int		j;

	charsets = calloc(INTL_CHAR_SET_MAX, sizeof(*charsets));
	if (!charsets)
	{
		return;
	}

	j = 0;
	for (i = 1; i < INTL_CHAR_SET_MAX; i++)
	{
		charset = &fe_FontCharSets[i];
		if (!charset->name)
		{
			continue;
		}
		charsets[j++] = fe_CharSetInfoArray[i].charsetID;
	}

	INTL_ReportFontCharSets(charsets);
}


static fe_Font
fe_LoadXFont(Display *dpy, char *name)
{
	XFontStruct	*f;

	f = XLoadQueryFont(dpy, name);

	if (f)
	{
		/*
		 * The width check is from xemacs.
		 * The ascent check is from Sun's AWT.
		 */
		if ((!f->max_bounds.width) || (f->ascent < 0))
		{
			XFreeFont(dpy, f);
			f = NULL;
		}
	}

	return (fe_Font) f;
}

static float default_UnicodePseudoFontSizes[] = {
    0.0, 
    8.0,   9.0, 10.0, 11.0, 12.0, 14.0, 
    16.0, 18.0, 20.0, 22.0, 24.0, 28.0, 
    32.0, 36.0,
    48.0, 60.0, 72.0,
};

static float* UnicodePseudoFontSizes = default_UnicodePseudoFontSizes;
static int num_UnicodePseudoFontSizes = 
			sizeof(default_UnicodePseudoFontSizes)/sizeof(float*);

static char *
fe_generatePixelSizeFontSpec(
		int  pixelSizeNum,
		char *origFoundry,
		char *origFamily,
		char *origWeight,
		char *avgwidth,
		char *origCharset)
{
	char *pixelSizeFontSpec;

	/*
	 * Note:
	 * origWeight has 2 values
	 * origCharset has 2 values
	 */
#ifdef SOLARIS
		if (pixelSizeNum)
		{
			pixelSizeFontSpec = PR_smprintf(
				"-%s-%s-%s-*-*-%d-*-*-*-*-%s-%s", origFoundry,
				origFamily, origWeight, pixelSizeNum, avgwidth,
				origCharset);
		}
		else
		{
			pixelSizeFontSpec = PR_smprintf(
				"-%s-%s-%s-*-*-%%d-*-*-*-*-%s-%s", origFoundry,
				origFamily, origWeight, avgwidth, origCharset);
		}
#else /* SOLARIS */
		if (pixelSizeNum)
		{
			pixelSizeFontSpec = PR_smprintf(
				"-%s-%s-%s-*-*-%d-*-*-*-*-*-%s", origFoundry,
				origFamily, origWeight, pixelSizeNum,
				origCharset);
		}
		else
		{
			pixelSizeFontSpec = PR_smprintf(
				"-%s-%s-%s-*-*-%%d-*-*-*-*-*-%s", origFoundry,
				origFamily, origWeight, origCharset);
		}
#endif /* SOLARIS */
	return pixelSizeFontSpec;

}

static char *
fe_generatePointSizeFontSpec(
		int  pointSizeNum,
		char *origFoundry,
		char *origFamily,
		char *origWeight,
		char *xResolution,
		char *yResolution,
		char *avgwidth,
		char *origCharset)
{
	char *pointSizeFontSpec;

	/*
	 * Note:
	 * origWeight has 2 values
	 * origCharset has 2 values
	 */
#ifdef SOLARIS
		if (pointSizeNum)
		{
			pointSizeFontSpec = PR_smprintf(
				"-%s-%s-%s-*-*-*-%d-%s-%s-*-%s-%s",
				origFoundry, origFamily, origWeight,
				pointSizeNum, xResolution, yResolution,
				avgwidth, origCharset);
		}
		else
		{
			pointSizeFontSpec = PR_smprintf(
				"-%s-%s-%s-*-*-*-%%d-%s-%s-*-%s-%s",
				origFoundry, origFamily, origWeight,
				xResolution, yResolution, avgwidth,
				origCharset);
		}
#else /* SOLARIS */
		if (pointSizeNum)
		{
			pointSizeFontSpec = PR_smprintf(
				"-%s-%s-%s-*-*-*-%d-%s-%s-*-*-%s", origFoundry,
				origFamily, origWeight, pointSizeNum,
				xResolution, yResolution, origCharset);
		}
		else
		{
			pointSizeFontSpec = PR_smprintf(
				"-%s-%s-%s-*-*-*-%%d-%s-%s-*-*-%s",
				origFoundry, origFamily, origWeight,
				xResolution, yResolution, origCharset);
		}
#endif /* SOLARIS */
	return pointSizeFontSpec;

}

/*
 * fe_loadUnicodePseudoFonts
 *
 * At this time, Sept. 1996, Unicode fonts are not
 * available for Unix. To display (size) a Unicode string
 * we convert the Unicode string to a series substrings each
 * of which is converted in a locally displayable encoding.
 * We then display (size) each substring using a standard
 * X font from a this Unicode Pseudo font.
 *
 * A Unicode Pseudo font is therefore an array of X fonts
 * each of the given size/pitch/weight for this font with one
 * one X font per encoding.
 *
 * In loading these Unicode Pseudo fonts we pretend to
 * to have these Unicode fonts available and fill in the master 
 * font table. Actually checking for a X font for each
 * for each size/pitch/weight/encoding would require loading 
 * a huge number of fonts.
 *
 *    11 sizes * 2 pitches * 2 weights * 35 encodings = 1540 fonts
 *
 * Because of the large number of fonts and the fact that asian 
 * fonts are large (1M per font) and the fact we might ask for 
 * scaling this loading time could be in the order of 
 * several minutes.  During this font loading time the X server 
 * appears to freeze and this is quite distressing to the user.
 *
 * HENCE BECAUSE OF THE UNACCEPTABLE LOADING DELAYS 
 * WE JUST ASSUME THE UNICODE FONTS ARE AVAILABLE.
 *
 * Even when we begin using a Unicode Pseudo font we only
 * load the X fonts for the encodings that have actually been 
 * seen.  Just loading X fonts for all the encodings for a given
 * size/pitch/weight requires a large number of X fonts.
 * 
 *    11 sizes * 2 pitches * 2 weights = 44 X fonts
 *
 */
static void
fe_loadUnicodePseudoFonts(Display *dpy, char *my_origFamily, int my_pitch)
{
    int i, j;
    char *my_origFoundry = "nsPseudoFont";
    char *my_foundry = my_origFoundry;
    char *my_family = my_origFamily;
    int   my_face;
    int   my_pointSizeNum;
    int   my_pixelSizeNum;
    int16 my_charsetID = CS_UTF8 & 0xFF;
    char *my_origCharset = "unicode-2-0";
    char *my_charset = my_origCharset;
    char *my_charsetlang = "unicode-2-0";
    char *my_pixelSizeFontSpec = NULL; 
    char *my_pointSizeFontSpec = NULL;
    char *my_origWeight;
    char *my_avgwidth = "*";
    char *my_xResolution = "*";
    char *my_yResolution = "*";
    char name[512], clas[512];
    char *type;
    XrmValue value;
    XrmDatabase	db = XtDatabase(dpy);

    /* Family name */
    (void) PR_snprintf(name, sizeof(name),
             "%s.documentFonts.family.%s", fe_progclass, my_origFamily);
    (void) PR_snprintf(clas, sizeof(clas),
                "%s.DocumentFonts.Family.Name", fe_progclass);
    if (XrmGetResource(db, name, clas, &type, &value))
        my_family = (char *) value.addr;

    /* Foundry name */
    (void) PR_snprintf(name, sizeof(name),
             "%s.documentFonts.foundry.%s", fe_progclass, my_origFoundry);
    (void) PR_snprintf(clas, sizeof(clas),
                "%s.DocumentFonts.Foundry.Name", fe_progclass);
    if (XrmGetResource(db, name, clas, &type, &value))
        my_foundry = (char *) value.addr;

    /* CharsetLang name */
    (void) PR_snprintf(name, sizeof(name),
             "%s.documentFonts.charsetlang.%s", fe_progclass, my_charsetlang);
    (void) PR_snprintf(clas, sizeof(clas),
                "%s.DocumentFonts.CharSetLang.Name", fe_progclass);
    if (XrmGetResource(db, name, clas, &type, &value))
        my_charsetlang = (char *) value.addr;

    /*
     * Create the Pseudo font sizes
     */

    for (i=0; i<num_UnicodePseudoFontSizes; i++) {
        /* one of these is not quite right */
        my_pixelSizeNum = (int)(UnicodePseudoFontSizes[i] * 10);
        my_pointSizeNum = (int)(UnicodePseudoFontSizes[i] * 10);
        /*
         * for each size create a plain/bold/italic/boldItalic version
         * (0=plain, 1=bold, 2=italic, 3=boldItalic)
         */
        for (j=0; j<4; j++) {
            my_face = j;
            switch(j) {
                default:
                case 0:
                    my_origWeight = "medium-r";
                    break;
                case 1:
                    my_origWeight = "bold-r";
                    break;
                case 2:
                    my_origWeight = "medium-i";
                    break;
                case 3:
                    my_origWeight = "bold-i";
                    break;
            };

            /*
             * Proportional/Monospaced
             */
            my_pixelSizeFontSpec = fe_generatePixelSizeFontSpec(
                                            my_pixelSizeNum,
                                            my_origFoundry,
                                            my_origFamily,
                                            my_origWeight,
                                            my_avgwidth,
                                            my_origCharset);
            if (!my_pixelSizeFontSpec)
                continue;
            my_pointSizeFontSpec = fe_generatePointSizeFontSpec(
                                        my_pointSizeNum,
                                        my_origFoundry,
                                        my_origFamily,
                                        my_origWeight,
                                        my_xResolution,
                                        my_yResolution,
                                        my_avgwidth,
                                        my_origCharset);
            if (!my_pointSizeFontSpec)
                continue;

            fe_AddFontCharSet(
                    my_origFoundry, 
                    my_foundry,
                    my_origFamily,
                    my_family,
                    my_face,
                    my_pixelSizeNum,
                    my_pointSizeNum,
                    my_pitch,
                    my_charsetID,
                    my_charset,
                    my_charsetlang,
                    my_pixelSizeFontSpec,
                    my_pointSizeFontSpec,
                    my_origCharset);
            FE_MAYBE_FREE(my_pixelSizeFontSpec);
            FE_MAYBE_FREE(my_pointSizeFontSpec);
        }
    }
}

#ifndef NO_WEB_FONTS

#define WF_FONT_DISPLAYER_PATH_1 "~/.netscape/dynfonts"
#define WF_FONT_DISPLAYER_PATH_4 "/usr/local/lib/netscape/dynfonts"

/* This static is outside of fe_InitializeWebfonts() 'cause HPUX has a
 * bug that causes it to become a loaded error with
 *	ld: Invalid loader fixup for symbol
 */
static char *dynfonts_str = "/dynfonts";
static char *dynfonts_str_no_slash = "dynfonts";

static void
fe_InitializeWebfonts(void)
{
	struct nffbp *fbp;
	char buf[MAXPATHLEN];
	char *mozilla_home = NULL;
	char *home = NULL;

	/* Initialize and obtain the font broker and font utility provider. */
	fe_FontBroker = NF_FontBrokerInitialize();
	fe_FontUtility = (struct nffbu *)
		nffbc_getInterface(fe_FontBroker, &nffbu_ID, NULL);

	/* Load Catalog */
	if (home = getenv("HOME"))
	{
		/* Form "$HOME/.netscape/dynfonts/fonts.cat" into buf */
		strncpy(buf, home, sizeof(buf)-1);
		strncat(buf, "/.netscape/dynfonts/fonts.cat",
				sizeof(buf)-1 - strlen(buf));
		buf[sizeof(buf)-1] = '\0';
		nffbu_LoadCatalog(fe_FontUtility, buf, NULL);
	}

	/* Load all font displayers */
	fbp = (struct nffbp *)
		nffbc_getInterface(fe_FontBroker, &nffbp_ID, NULL);

	/* Scan for font displayers. Here is the order and list of places
	 * where we look for font displayers.
	 *	~/.netscape/dynfonts
	 *	$MOZILLA_HOME/dynfonts
	 *	<program directory>/dynfonts
	 *	/usr/local/lib/netscape/dynfonts
	 *
	 * According to our webfont implementation, if a font displayer with
	 * the same name exists in more than one directory, then the
	 * first one takes priority.
	 */
	nffbp_ScanForFontDisplayers(fbp, WF_FONT_DISPLAYER_PATH_1, NULL);

	/* WF_FONT_DISPLAYER_PATH_2 */
	if (mozilla_home = getenv("MOZILLA_HOME"))
	{
		/* Form "$MOZILLA_HOME/dynfonts" into buf */
		strncpy(buf, mozilla_home, sizeof(buf)-1);
		strncat(buf, dynfonts_str, sizeof(buf)-1 - strlen(buf));
		buf[sizeof(buf)-1] = '\0';
		nffbp_ScanForFontDisplayers(fbp, buf, NULL);
	}

	/* WF_FONT_DISPLAYER_PATH_3 */
	/* Form "<program-dir>/dynfonts" into buf */
	buf[0] = '\0';
	fe_GetProgramDirectory(buf, sizeof(buf)-1);
	if (buf[0])
	{
		strncat(buf, dynfonts_str_no_slash, sizeof(buf)-1 - strlen(buf));
		buf[sizeof(buf)-1] = '\0';
		nffbp_ScanForFontDisplayers(fbp, buf, NULL);
	}

	/* WF_FONT_DISPLAYER_PATH_4 */
	nffbp_ScanForFontDisplayers(fbp, WF_FONT_DISPLAYER_PATH_4, NULL);
}
#endif

void
fe_InitFonts(Display *dpy)
{
	char		*avgwidth = NULL;
#ifdef SOLARIS
	int		avgWidthNum;
#endif
	char		*charset;
	int16		charsetID;
	char		*charsetlang;
	char		clas[512];
	int		count;
	XrmDatabase	db;
	int		face;
	char		*family;
	char		*font;
	char		**fonts;
	char		*foundry;
	int		i;
	int		j;
	char		name[512];
	char		*origCharset;
	char		*origFamily;
	char		*origFoundry;
	char		*origWeight; /* note: has weight and slant */
	char		*p;
	int		pitch;
	char		*pixelSize;
	char		*pixelSizeFontSpec;
	int		pixelSizeNum;
	char		*pointSize;
	char		*pointSizeFontSpec;
	int		pointSizeNum;
	char		*resx;
	char		*setwidth;
	char		*spacing;
	char		*type;
	XrmValue	value;
	char		*weight;
	char		*xResolution;
	char		*yResolution;

#ifdef SOLARIS
	avgwidth = NULL;
#endif
	charset = NULL;
	charsetlang = NULL;
	family = NULL;
	font = NULL;
	fonts = NULL;
	foundry = NULL;
	origCharset = NULL;
	origFamily = NULL;
	origFoundry = NULL;
	origWeight = NULL;
	p = NULL;
	pixelSize = NULL;
	pixelSizeFontSpec = NULL;
	pointSize = NULL;
	pointSizeFontSpec = NULL;
	resx = NULL;
	setwidth = NULL;
	spacing = NULL;
	type = NULL;
	weight = NULL;
	xResolution = NULL;
	yResolution = NULL;

#ifndef NO_WEB_FONTS
	/* Initialize font library */
	fe_InitializeWebfonts();
#endif
	/*
	 * do this first so that we are very likely to have this
	 * font available if/when we fail to load any other font
	 */
	fe_FixedFont = fe_LoadXFont(dpy, "fixed");

	fe_GetLocaleCharSets(dpy);

#ifdef DEBUG
	if (sizeof(fe_CharSetInfoArray) / sizeof(*fe_CharSetInfoArray) !=
		INTL_CHAR_SET_MAX)
	{
		(void) fprintf(real_stderr,
			"fe_CharSetInfoArray broken (size)\n");
#if 0 
		/* to fix 93446
		 */
		fe_Exit(1);
#endif
	}
	for (i = 0; i < INTL_CHAR_SET_MAX; i++)
	{
		if ((fe_CharSetInfoArray[i].charsetID & 0xff) != i)
		{
			(void) fprintf(real_stderr,
				"fe_CharSetInfoArray broken (%d)\n", i);
#if 0 
			/* to fix 93446
			 */
			fe_Exit(1);
#endif
		}
	}
#endif /* DEBUG */

	fonts = XListFonts(dpy, "-*-*-*-*-*-*-*-*-*-*-*-*-*-*", INT_MAX,
                           &count);
	if (!fonts)
	{
		return;
	}

	(void) memset(fe_FontCharSets, 0, sizeof(fe_FontCharSets));

        db = XtDatabase(dpy);

	for (i = 0; i < count; i++)
	{
		FE_MAYBE_FREE(font);
		FE_MAYBE_FREE(origCharset);
		FE_MAYBE_FREE(origFamily);
		FE_MAYBE_FREE(origWeight);
		FE_MAYBE_FREE(pixelSizeFontSpec);
		FE_MAYBE_FREE(pointSizeFontSpec);

		/* ignore the non-XLFD short names */
		if ((!fonts[i]) || (fonts[i][0] != '-'))
		{
			continue;
		}

		font = strdup(fonts[i]);
		if (!font)
		{
			continue;
		}

		p = font;
		j = 0;
		while (1)
		{
			p = strchr(p, '-');
			if (!p)
			{
				break;
			}
			p++;
			switch (j)
			{
			case 0:
				foundry = p;
				break;
			case 1:
				family = p;
				break;
			case 2:
				weight = p;
				break;
			case 4:
				setwidth = p;
				break;
			case 6:
				pixelSize = p;
				break;
			case 7:
				pointSize = p;
				break;
			case 8:
				resx = p;
				break;
			case 10:
				spacing = p;
				break;
#ifdef SOLARIS
			case 11:
				avgwidth = p;
				break;
#endif
			case 12:
				charset = p;
				break;
			default:
				break;
			}
			j++;
		}

		if (j < 14)
		{
			/* skip non-XLFD names */
			continue;
		}

                /* Skip Applix fonts -- if these are installed, there are
                   hundreds of them, and they do not have proper XLFD names:
                   the bold/italic/etc versions of the fonts have different
                   *families* as well ("axhvr" for Helvetica-normal,
                   "axhvb" for Helvetica-bold, etc) so all they do is bloat
                   the menus and make the UI unusable.
                 */
                if (family &&
                    strncasecomp(family, "ax", 2) &&
                    XP_STRLEN(family) == 5)
                    continue;

		(void) PR_snprintf(clas, sizeof(clas),
			"%s.DocumentFonts.Foundry.Name", fe_progclass);
		family[-1] = 0;
		(void) PR_snprintf(name, sizeof(name),
			"%s.documentFonts.foundry.%s", fe_progclass, foundry);
		origFoundry = strdup(foundry);
		if (!origFoundry)
		{
			continue;
		}
		if (XrmGetResource(db, name, clas, &type, &value))
		{
			foundry = strdup((char *) value.addr);
		}
		else
		{
			foundry = fe_CapitalizeFontName(foundry);
		}
		if (!foundry)
		{
			continue;
		}

		(void) PR_snprintf(clas, sizeof(clas),
			"%s.DocumentFonts.Family.Name", fe_progclass);
		weight[-1] = 0;
		(void) PR_snprintf(name, sizeof(name),
			"%s.documentFonts.family.%s", fe_progclass, family);
		origFamily = strdup(family);
		if (!origFamily)
		{
			continue;
		}
		if (XrmGetResource(db, name, clas, &type, &value))
		{
			family = strdup((char *) value.addr);
		}
		else
		{
			family = fe_CapitalizeFontName(family);
		}
		if (!family)
		{
			continue;
		}

		(void) PR_snprintf(clas, sizeof(clas),
			"%s.DocumentFonts.Face.Name", fe_progclass);
		setwidth[-1] = 0;
		(void) PR_snprintf(name, sizeof(name),
			"%s.documentFonts.face.%s", fe_progclass, weight);
		origWeight = strdup(weight);
		if (!origWeight)
		{
			continue;
		}
		if (XrmGetResource(db, name, clas, &type, &value))
		{
			weight = (char *) value.addr;
		}
		else
		{
#ifdef DEBUG_xxx
			(void) fprintf(real_stderr, "face %s\n", weight);
#endif /* DEBUG_xxx */
			weight = "";
		}
		if (!strcmp(weight, "bold"))
		{
			face = 1;
		}
		else if (!strcmp(weight, "boldItalic"))
		{
			face = 3;
		}
		else if (!strcmp(weight, "italic"))
		{
			face = 2;
		}
		else
		{
			face = 0;
		}

		pointSize[-1] = 0;
		sscanf(pixelSize, "%d", &pixelSizeNum);
		if (pixelSizeNum < 0)
		{
			continue;
		}

		resx[-1] = 0;
		sscanf(pointSize, "%d", &pointSizeNum);
		if (pointSizeNum < 0)
		{
			continue;
		}

		switch (spacing[0])
		{
		case 'm':
			pitch = fe_FONT_PITCH_MONO;
			break;
		case 'p':
			pitch = fe_FONT_PITCH_PROPORTIONAL;
			break;
		case 'c':
			/* fall through */
		default:
			pitch = fe_FONT_PITCH_BOTH;
			break;
		}

#ifdef SOLARIS
		charset[-1] = 0;
		sscanf(avgwidth, "%d", &avgWidthNum);
		if (avgWidthNum < 0)
		{
			continue;
		}
#endif

		(void) PR_snprintf(clas, sizeof(clas),
			"%s.DocumentFonts.CharSet.Family.Name", fe_progclass);
		(void) PR_snprintf(name, sizeof(name),
			"%s.documentFonts.charset.%s.%s", fe_progclass,
			origFamily, charset);
		origCharset = strdup(charset);
		if (!origCharset)
		{
			continue;
		}
		charsetlang = charset;
		if (XrmGetResource(db, name, clas, &type, &value))
		{
			charset = (char *) value.addr;
		}
		else
		{
			/*
			 * if the user has messed with the app-defaults, we
			 * might not be able to find our mapping, so check for
			 * the following at least
			 */
			if (!strcmp(charset, "iso8859-1"))
			{
				charset = "iso-8859-1";
			}
#ifdef DEBUG
			else
			{
				(void) fprintf(real_stderr, "charset %s %s\n",
					origFamily, charsetlang);
			}
#endif /* DEBUG */
		}
		charsetID = (INTL_CharSetNameToID(charset) & 0xff);

#ifdef SOLARIS
		if (charsetID == (CS_GB2312 & 0xff))
		{
			/*
			 * Simplified Chinese Solaris has broken fonts that
			 * say GB2312 but are actually ASCII fonts. Skip 'em.
			 */
			if (avgWidthNum && (avgWidthNum == (pointSizeNum / 2)))
			{
				continue;
			}
		}
		else
		{
			avgwidth = "*";
		}
#endif /* SOLARIS */

#ifdef DEBUG
		if ((charsetID == CS_UNKNOWN) && strcmp(charset, "x-ignore"))
		{
			(void) fprintf(real_stderr, "internal %s %s %s\n",
				origFamily, charsetlang, charset);
		}
#endif /* DEBUG */
		if (!strcmp(charset, "x-ignore"))
		{
			charsetID = CS_USRDEF2;
		}
		if (charsetID >= INTL_CHAR_SET_MAX)
		{
			charsetID = CS_USRDEF2;
		}
		if (fe_CharSetInfoArray[charsetID].type == FE_FONT_TYPE_GROUP)
		{
			continue;
		}
		(void) PR_snprintf(clas, sizeof(clas),
			"%s.DocumentFonts.CharSetLang.Name", fe_progclass);
		(void) PR_snprintf(name, sizeof(name),
			"%s.documentFonts.charsetlang.%s", fe_progclass,
			charset);
		if (XrmGetResource(db, name, clas, &type, &value))
		{
			charsetlang = (char *) value.addr;
		}
		else
		{
#if 0
			(void) fprintf(real_stderr, "charsetlang %s\n",
				charsetlang);
#endif /* 0 */
			charsetlang = XP_GetString(XFE_OTHER_LANGUAGE);
		}

		(void) PR_snprintf(clas, sizeof(clas),
			"%s.DocumentFonts.XResolution.CharSet", fe_progclass);
		(void) PR_snprintf(name, sizeof(name),
			"%s.documentFonts.xResolution.%s", fe_progclass,
			charset);
		if (XrmGetResource(db, name, clas, &type, &value))
		{
			xResolution = (char *) value.addr;
		}
		else
		{
			xResolution = "*";
		}

		(void) PR_snprintf(clas, sizeof(clas),
			"%s.DocumentFonts.YResolution.CharSet", fe_progclass);
		(void) PR_snprintf(name, sizeof(name),
			"%s.documentFonts.yResolution.%s", fe_progclass,
			charset);
		if (XrmGetResource(db, name, clas, &type, &value))
		{
			yResolution = (char *) value.addr;
		}
		else
		{
			yResolution = "*";
		}

		pixelSizeFontSpec = fe_generatePixelSizeFontSpec(
								pixelSizeNum,
								origFoundry,
								origFamily,
								origWeight,
								avgwidth,
								origCharset);
		if (!pixelSizeFontSpec)
		{
			continue;
		}

		pointSizeFontSpec = fe_generatePointSizeFontSpec(
								pointSizeNum,
								origFoundry,
								origFamily,
								origWeight,
								xResolution,
								yResolution,
								avgwidth,
								origCharset);
		if (!pointSizeFontSpec)
		{
			continue;
		}

		fe_AddFontCharSet(origFoundry, foundry, origFamily, family,
			face, pixelSizeNum, pointSizeNum, pitch, charsetID,
			charset, charsetlang, pixelSizeFontSpec,
			pointSizeFontSpec, origCharset);

#if 0
(void) fprintf
(
	real_stderr,
	"\"%s\" \"%s\" \"%s\" %d \"%s%s\" %d \"%s\" \"%s\"\n\"%s\"\n",
	foundry,
	family,
	FE_INDEX_TO_FACE(face),
	pointSizeNum,
	((pitch & fe_FONT_PITCH_MONO) ? "m" : ""),
	((pitch & fe_FONT_PITCH_PROPORTIONAL) ? "p" : ""),
	charsetID,
	charset,
	charsetlang,
	pointSizeFontSpec
);
#endif /* 0 */

		free(origFoundry);
		free(foundry);
		free(family);
	}

	FE_MAYBE_FREE(font);
	FE_MAYBE_FREE(origCharset);
	FE_MAYBE_FREE(origFamily);
	FE_MAYBE_FREE(origWeight);
	FE_MAYBE_FREE(pixelSizeFontSpec);
	FE_MAYBE_FREE(pointSizeFontSpec);

	XFreeFontNames(fonts);

	(void) PR_snprintf(clas, sizeof(clas),
		"%s.DocumentFonts.SizeIncrement", fe_progclass);
	(void) PR_snprintf(name, sizeof(name),
		"%s.documentFonts.sizeIncrement", fe_progclass);
	if (XrmGetResource(db, name, clas, &type, &value))
	{
		fe_FontSizeIncrement = (((double) atoi(value.addr)) / 100.0);
		if (fe_FontSizeIncrement <= 0)
		{
			fe_FontSizeIncrement = FE_DEFAULT_FONT_SIZE_INCREMENT;
		}
	}

	(void) PR_snprintf(clas, sizeof(clas),
                           "%s.DocumentFonts.MaximumPoints", fe_progclass);
	(void) PR_snprintf(name, sizeof(name),
                           "%s.documentFonts.maximumPoints", fe_progclass);
	if (XrmGetResource(db, name, clas, &type, &value))
	{
            fe_FontMaximumPoints = atoi(value.addr);
            if (fe_FontMaximumPoints <= 0)
                fe_FontMaximumPoints = FE_DEFAULT_FONT_MAXIMUM_POINTS;
	}

        for (i=0; i < fe_GenericFamilyCount; i++) {
            (void) PR_snprintf(clas, sizeof(clas),
                               "%s.DocumentFonts.Generic.%s",
                               fe_progclass, fe_generics[i].class_name);
            (void) PR_snprintf(name, sizeof(name),
                               "%s.documentFonts.generic.%s",
                               fe_progclass, fe_generics[i].generic_name);
            if (XrmGetResource(db, name, clas, &type, &value))
                fe_generics[i].family_name = strdup(value.addr);
        }

	fe_loadUnicodePseudoFonts(dpy, "helvetica", fe_FONT_PITCH_PROPORTIONAL);
	fe_loadUnicodePseudoFonts(dpy, "times",     fe_FONT_PITCH_PROPORTIONAL);
	fe_loadUnicodePseudoFonts(dpy, "courier",   fe_FONT_PITCH_MONO);
	fe_loadUnicodePseudoFonts(dpy, "fixed",     fe_FONT_PITCH_MONO);

	fe_SortFonts();

	fe_SetDefaultFontSettings(dpy);

	fe_ReportFontCharSets();

#ifdef FE_PRINT_FONTS
	fe_PrintFonts();
#endif
}


#ifdef DEBUG
void
fe_FreeFonts(void)
{
	fe_FontCharSet	*charset;
	fe_FontFace	*face;
	fe_FontFamily	*family;
	int		i;
	int		j;
	int		k;
	fe_FontFace	*nextFace;
	fe_FontPitch	*pitch;

	for (i = 0; i < INTL_CHAR_SET_MAX; i++)
	{
		charset = &fe_FontCharSets[i];
		if (!charset->name)
		{
			continue;
		}
		for (j = 0; j < 2; j++)
		{
			pitch = &charset->pitches[j];
			for (k = 0; k < pitch->numberOfFamilies; k++)
			{
				family = &pitch->families[k];
				free(family->name);
				free(family->foundry);
				free(family->family);
				free(family->pixelSizes);
				free(family->pointSizes);
			}
			free(pitch->families);
		}
		free(charset->name);
		free(charset->mimeName);
	}

	(void) memset(fe_FontCharSets, 0, sizeof(fe_FontCharSets));

	face = fe_FontFaceList;
	while (face)
	{
		nextFace = face->next;
		if (face->longXLFDFontName)
		{
			free(face->longXLFDFontName);
		}
		if (face->font)
		{
			XFreeFont(fe_display, face->font);
		}
		face->loaded = FALSE;
		free(face);
		face = nextFace;
	}
	fe_FontFaceList = NULL;

	if (fe_FixedFont)
	{
		XFreeFont(fe_display, fe_FixedFont);
		fe_FixedFont = NULL;
	}
}
#endif /* DEBUG */


static void
fe_AddFontSetting(fe_FontSettings **ret, fe_FontCharSet *charset, int i,
	fe_FontFamily *family, fe_FontSize *size)
{
	fe_FontSettings	*set;
	char		*spec;

	spec = PR_smprintf
	(
		"%s-%s-%d-%s-%s-%s\n",
		family->foundry,
		family->family,
		size->size,
		family->allowScaling ? "scale" : "noscale",
		fe_PropOrFixedFont(i),
		charset->mimeName
	);

	set = FE_MALLOC_ZAP(fe_FontSettings);

	if ((!spec) || (!set))
	{
		return;
	}

	set->spec = spec;
	set->next = *ret;
	*ret = set;
}


fe_FontSettings *
fe_GetFontSettings(void)
{
	fe_FontCharSet	*charset;
	fe_FontFamily	*family;
	int		i;
	int		j;
	int		k;
	int		m;
	fe_FontPitch	*pitch;
	fe_FontSettings	*ret;
	fe_FontSize	*size;

	ret = NULL;

	for (i = 0; i < INTL_CHAR_SET_MAX; i++)
	{
		charset = &fe_FontCharSets[i];
		if (!charset->name)
		{
			continue;
		}
		for (j = 0; j < 2; j++)
		{
			pitch = &charset->pitches[j];
			for (k = 0; k < pitch->numberOfFamilies; k++)
			{
				family = &pitch->families[k];
				if (family->selected)
				{
					for (m = 0; m < family->numberOfPointSizes;
						m++)
					{
						size = &family->pointSizes[m];
						if (size->selected)
						{
							fe_AddFontSetting
							(
								&ret,
								charset,
								j,
								family,
								size
							);
						}
					}
				}
			}
		}
	}

	return ret;
}


void
fe_SetFontSettings(fe_FontSettings *set)
{
}


char *
fe_GetFontCharSetSetting(void)
{
	fe_FontCharSet	*charset;
	int		i;

	for (i = 0; i < INTL_CHAR_SET_MAX; i++)
	{
		charset = &fe_FontCharSets[i];
		if (!charset->name)
		{
			continue;
		}
		if (charset->selected)
		{
			return charset->mimeName;
		}
	}

	return "";
}


void
fe_FreeFontSettings(fe_FontSettings *set)
{
	fe_FontSettings	*next;

	while (set)
	{
		next = set->next;
		free(set->spec);
		free(set);
		set = next;
	}
}


int
fe_GetStrikePosition(int charset, fe_Font font)
{
	int		ascent;
	int		descent;
	XCharStruct	overall;

	/*
	 * strike through the middle of lower case letters
	 */
	FE_TEXT_EXTENTS(charset, font, "a", 1, &ascent, &descent, &overall);

	return -((overall.ascent + 1) / 2);
}


int
fe_GetUnderlinePosition(int charset)
{
	/*
	 * Underline position does not depend on font, otherwise you get
	 * varying positions within a single line, and this looks bad.
	 */

	if ((fe_CharSetInfoArray[charset & 0xff].type == FE_FONT_TYPE_GROUP)
		|| ((charset&0xFF) == (CS_UTF8&0xFF)))
	{
		/*
		 * East Asian fonts have a lower baseline.
		 * Underline looks better like this.
		 */
		return 3;
	}

	return 1;
}


static XP_Bool
fe_AreNormalFontsAvail(int16 win_csid)
{
	if (fe_FontCharSets[win_csid & 0xff].name != NULL)
		return TRUE;
	else
		return FALSE;
}

static fe_Font
fe_LoadNormalFont(MWContext *context, char *familyName, 
                  int points, int sizeNum,
		  int fontmask, int charset,
		  int pitch, int faceNum, Display *dpy)
{
	fe_FontFace	*face;
	fe_Font		font;
	fe_FontFamily	*family = NULL;
        fe_FontSize     *size;
        double          decipoints;

	if (familyName && *familyName)
	{
		family = fe_FontFindFamily(charset, pitch, familyName);
	}
	if (!family)
	{
		family = fe_GetFontFamily(charset, pitch);
		if (!family)
		{
			return NULL;
		}
	}
        if (! points)
            size = family->htmlSizes[sizeNum-1];
        else {
            decipoints = (double) (points * 10);
            size = fe_FindFontPointSize(family, decipoints, True, False);
        }
        if (!size)
            return NULL;
        face = size->faces[faceNum];
        if (!face)
            return NULL;

	font = face->font;
	if (font)
	{
		return font;
	}

	else {
		font = fe_LoadXFont(dpy, face->longXLFDFontName);
	}
	if (font)
	{
		face->font = font;
		return font;
	}

	return NULL;
}

static XmFontList
fe_GetFontListNormal(int16 charset, fe_Font font, int numOfFonts)
{
        XmFontList fl;
        XmFontListEntry e;
        e = XmFontListEntryCreate("f0", XmFONT_IS_FONT, (XFontStruct*) font);
        XP_ASSERT(NULL != e);

        fl = XmFontListAppendEntry(NULL, e);
        XP_ASSERT(NULL != fl);

        XmFontListEntryFree(&e);
        return fl;
}
static XmString fe_ToXmStringNormal(int16 charset, fe_Font font, char * string, int len)
{
        return XmStringCreate(string, "f0");
}

void
fe_GenericFontExtents(int charset, fe_Font font, 
						int *fontAscent, int *fontDescent)
{
	int			ascent;
	int			ascentExtra;
	int			descent;
	int			descentExtra;
	XFontStruct		*f;
	fe_FontGroupFont	*fonts;
	int			i;
	int			num;
    fe_CharSetInfo  *info = &fe_CharSetInfoArray[(charset) & 0xff];

	/*
	 * Handle Unicode Pseudo Fonts
	 */
    if (info->info == FE_FONT_INFO_UNICODE) {
        fe_UnicodePseudoFont *ufont = (fe_UnicodePseudoFont *)font;
        if (ufont->tag != UNICODE_PSEUDO_FONT_TAG) {
#ifdef DEBUG_bstell
            printf("bad ufont %s %d\n", __FILE__, __LINE__);
#endif
            *(fontAscent) = 12;
            *(fontDescent) = 3;
	    }
					
        (void)fe_UnicodeInitXfont(font, CS_LATIN1);
        *(fontAscent) = ufont->ascent;
        *(fontDescent) = ufont->descent;
        return;
    }

	/*
	 * Handle EUC Fonts
	 */
	fonts = (fe_FontGroupFont *) font;

	ascent = 0;
	descent = 0;

	num = fe_CharSetFuncsArray[info->info].numberOfFonts;
	for (i = 0; i < num; i++)
	{
		if (i)
		{
			/*
			 * East Asian text looks better with extra space for
			 * underline.
			 */
			ascentExtra = 1;
			descentExtra = 2;
		}
		else
		{
			ascentExtra = 0;
			descentExtra = 0;
		}
		f = fonts[i].xFont;
		if (f)
		{
			if (f->ascent + ascentExtra > ascent)
			{
				ascent = f->ascent + ascentExtra;
			}
			if (f->descent + descentExtra > descent)
			{
				descent = f->descent + descentExtra;
			}
		}
	}

	*fontAscent = ascent;
	*fontDescent = descent;
}


#define FE_PROCESS_STRING_BUFFER_SIZE	1024

static void
fe_ProcessEUCString(int charset, fe_StringProcessTable *table, 
	fe_XDrawStringFunc draw1, 
	fe_XDrawStringFunc draw2, 
	Display *dpy, Drawable d, fe_Font fontGroup,
	GC gc, int x, int y, unsigned char *in, unsigned int inEnd,
	int *fontAscent, int *fontDescent, XCharStruct *overall,
	unsigned char numberOfFonts)
{
	int			ascent;
	int			descent;
	int			direction;
	fe_StringProcessTable	*entry;
	fe_FontGroupFont	*font;
	unsigned char		fontIndex;
	fe_FontGroupFont	*fonts;
	unsigned int		inIndex;
	unsigned char		len;
	unsigned char		mask1;
	unsigned char		mask2;
	XCharStruct		metrics;
	unsigned char		nextFontIndex;
	unsigned char		out1[FE_PROCESS_STRING_BUFFER_SIZE];
	XChar2b			out2[FE_PROCESS_STRING_BUFFER_SIZE/2];
	unsigned int		out1Index;
	unsigned int		out2Index;
	XChar2b			*p;
	unsigned char		skip;
	XFontStruct		*xFont;

	if (inEnd > FE_PROCESS_STRING_BUFFER_SIZE)
	{
		inEnd = FE_PROCESS_STRING_BUFFER_SIZE;
	}

	fonts = (fe_FontGroupFont *) fontGroup;

	inIndex = 0;

	out1Index = 0;

	out2Index = 0;

	if (overall)
	{
		overall->lbearing = 0;
		overall->rbearing = 0;
		overall->width = 0;
		overall->ascent = 0;
		overall->descent = 0;
	}

	while (inIndex < inEnd)
	{
		entry = &table[in[inIndex]];
		skip = entry->skip;
		len = entry->len;
		fontIndex = entry->fontIndex;
		font = &fonts[fontIndex];
		xFont = font->xFont;
		if (gc && xFont)
		{
			XSetFont(dpy, gc, xFont->fid);
		}
		if (len == 1)
		{
			while (inIndex < inEnd)
			{
				inIndex += skip;
				if (inIndex >= inEnd)
				{
					break;
				}
				out1[out1Index++] = in[inIndex++];
				if (inIndex >= inEnd)
				{
					break;
				}
				nextFontIndex = table[in[inIndex]].fontIndex;
				if (nextFontIndex != fontIndex)
				{
					break;
				}
			}
			if (out1Index && xFont)
			{
				XTextExtents(xFont, out1, out1Index,
					&direction, &ascent, &descent,
					&metrics);
				if (draw1)
				{
					(*draw1)(dpy, d, gc, x, y,
						out1, out1Index);
				}
				x += metrics.width;
				if (overall)
				{
					overall->width += metrics.width;
					if (metrics.ascent > overall->ascent)
					{
						overall->ascent =
							metrics.ascent;
					}
					if (metrics.descent > overall->descent)
					{
						overall->descent =
							metrics.descent;
					}
				}
			}
			out1Index = 0;
		}
		else
		{
			mask1 = font->mask1;
			mask2 = font->mask2;
			while (inIndex < inEnd)
			{
				inIndex += skip;
				if ((inIndex + 1) >= inEnd)
				{
					inIndex++;
					break;
				}
				p = &out2[out2Index++];
				p->byte1 = (in[inIndex++] & mask1);
				p->byte2 = (in[inIndex++] & mask2);
				if (inIndex >= inEnd)
				{
					break;
				}
				nextFontIndex = table[in[inIndex]].fontIndex;
				if (nextFontIndex != fontIndex)
				{
					break;
				}
			}
			if (out2Index && xFont)
			{
				XTextExtents16(xFont, out2, out2Index,
					&direction, &ascent, &descent,
					&metrics);
				if (draw2)
				{
					(*draw2)(dpy, d, gc, x, y,
						(char *) out2, out2Index);
				}
				x += metrics.width;
				if (overall)
				{
					overall->width += metrics.width;
					if (metrics.ascent > overall->ascent)
					{
						overall->ascent =
							metrics.ascent;
					}
					if (metrics.descent > overall->descent)
					{
						overall->descent =
							metrics.descent;
					}
				}
			}
			out2Index = 0;
		}
	}

	if (overall)
	{
		/* @@@ fix */
		overall->rbearing = overall->width;

		fe_GenericFontExtents(charset, fontGroup, fontAscent,
			fontDescent);
	}
}

static XmString fe_create_and_concatnate_XmString(
       XmString list, char* str, int len, char* flabel)
{
    XmString ret;
    XmString seg = NULL;

    str[len++] = '\0';

    if(NULL == list)
       return XmStringCreate(str, flabel);

    seg = XmStringCreate(str, flabel);
    XP_ASSERT(NULL != seg);

    ret = XmStringConcat(list, seg);
    XP_ASSERT(NULL != list);

    XmStringFree(list);
    XmStringFree(seg);

    return ret;
}

static XmString fe_EUCToXmString(int16 charset, fe_Font fontGroup, char * string, int len,
                                 fe_StringProcessTable *table)
{
    int begin, cur, out;
    unsigned char curFI;
    char flabel[4]; 
    XmString xms = NULL;
    unsigned char		buf[FE_PROCESS_STRING_BUFFER_SIZE];
    fe_StringProcessTable *entry = &table[(unsigned char)string[0]];
    unsigned char lastFI = entry->fontIndex;
    unsigned char mask1 = 0xff;
    unsigned char mask2 = 0xff;
    fe_FontGroupFont	*fonts;
    fonts = (fe_FontGroupFont *) fontGroup;

    if(FALSE == fe_AreFontsAvail(charset)) 
    {  /* The font is not available, it does not matter what we do, fall back to a simple string */
           return XmStringCreateLocalized(string);
    }

    XP_STRCPY(flabel, "f0");

    if(entry->len > 1)
    {
        mask1 = fonts[lastFI].mask1;
        mask2 = fonts[lastFI].mask2;
    }

    for(out=cur=begin=0; cur < len; )
    {
       entry = &table[(unsigned char)string[cur]];
       curFI = entry->fontIndex;
      
       /* Need to switch font, generate a new segment */
       if((lastFI != curFI) || (out >= (FE_PROCESS_STRING_BUFFER_SIZE - 4)))
       {
         (void)PR_snprintf(flabel, sizeof(flabel), "f%d", lastFI);

         xms = fe_create_and_concatnate_XmString( xms, buf, out, flabel);

         /* Now we should save the state somewhere */
         out = 0;
         begin = cur;
         lastFI = curFI;
         if(entry->len > 1)
         {
              mask1 = fonts[lastFI].mask1;
              mask2 = fonts[lastFI].mask2;
         }
       }

       cur += entry->skip;
       if(1 == entry->len)
       {
         if(cur < len) buf[out++] = string[cur++];
       }
       else
       {
         if(cur < len) buf[out++] = (string[cur++] & mask1);
         if(cur < len) buf[out++] = (string[cur++] & mask2);
       }

    }
    if(begin != len)
    {
         (void)PR_snprintf(flabel, sizeof(flabel), "f%d", lastFI);
         xms = fe_create_and_concatnate_XmString( xms, buf, out, flabel);
    }
    return xms;
}


			/*	fontIndex	skip	len	*/
#define EUCCN_LATIN1	{	0,		0,	1	}
#define EUCCN_GB2312	{	1,		0,	2	}

static fe_StringProcessTable EUCCNTable[] =
{
	/* 0x00 */	EUCCN_LATIN1,
	/* 0x01 */	EUCCN_LATIN1,
	/* 0x02 */	EUCCN_LATIN1,
	/* 0x03 */	EUCCN_LATIN1,
	/* 0x04 */	EUCCN_LATIN1,
	/* 0x05 */	EUCCN_LATIN1,
	/* 0x06 */	EUCCN_LATIN1,
	/* 0x07 */	EUCCN_LATIN1,
	/* 0x08 */	EUCCN_LATIN1,
	/* 0x09 */	EUCCN_LATIN1,
	/* 0x0a */	EUCCN_LATIN1,
	/* 0x0b */	EUCCN_LATIN1,
	/* 0x0c */	EUCCN_LATIN1,
	/* 0x0d */	EUCCN_LATIN1,
	/* 0x0e */	EUCCN_LATIN1,
	/* 0x0f */	EUCCN_LATIN1,
	/* 0x10 */	EUCCN_LATIN1,
	/* 0x11 */	EUCCN_LATIN1,
	/* 0x12 */	EUCCN_LATIN1,
	/* 0x13 */	EUCCN_LATIN1,
	/* 0x14 */	EUCCN_LATIN1,
	/* 0x15 */	EUCCN_LATIN1,
	/* 0x16 */	EUCCN_LATIN1,
	/* 0x17 */	EUCCN_LATIN1,
	/* 0x18 */	EUCCN_LATIN1,
	/* 0x19 */	EUCCN_LATIN1,
	/* 0x1a */	EUCCN_LATIN1,
	/* 0x1b */	EUCCN_LATIN1,
	/* 0x1c */	EUCCN_LATIN1,
	/* 0x1d */	EUCCN_LATIN1,
	/* 0x1e */	EUCCN_LATIN1,
	/* 0x1f */	EUCCN_LATIN1,
	/* 0x20 */	EUCCN_LATIN1,
	/* 0x21 */	EUCCN_LATIN1,
	/* 0x22 */	EUCCN_LATIN1,
	/* 0x23 */	EUCCN_LATIN1,
	/* 0x24 */	EUCCN_LATIN1,
	/* 0x25 */	EUCCN_LATIN1,
	/* 0x26 */	EUCCN_LATIN1,
	/* 0x27 */	EUCCN_LATIN1,
	/* 0x28 */	EUCCN_LATIN1,
	/* 0x29 */	EUCCN_LATIN1,
	/* 0x2a */	EUCCN_LATIN1,
	/* 0x2b */	EUCCN_LATIN1,
	/* 0x2c */	EUCCN_LATIN1,
	/* 0x2d */	EUCCN_LATIN1,
	/* 0x2e */	EUCCN_LATIN1,
	/* 0x2f */	EUCCN_LATIN1,
	/* 0x30 */	EUCCN_LATIN1,
	/* 0x31 */	EUCCN_LATIN1,
	/* 0x32 */	EUCCN_LATIN1,
	/* 0x33 */	EUCCN_LATIN1,
	/* 0x34 */	EUCCN_LATIN1,
	/* 0x35 */	EUCCN_LATIN1,
	/* 0x36 */	EUCCN_LATIN1,
	/* 0x37 */	EUCCN_LATIN1,
	/* 0x38 */	EUCCN_LATIN1,
	/* 0x39 */	EUCCN_LATIN1,
	/* 0x3a */	EUCCN_LATIN1,
	/* 0x3b */	EUCCN_LATIN1,
	/* 0x3c */	EUCCN_LATIN1,
	/* 0x3d */	EUCCN_LATIN1,
	/* 0x3e */	EUCCN_LATIN1,
	/* 0x3f */	EUCCN_LATIN1,
	/* 0x40 */	EUCCN_LATIN1,
	/* 0x41 */	EUCCN_LATIN1,
	/* 0x42 */	EUCCN_LATIN1,
	/* 0x43 */	EUCCN_LATIN1,
	/* 0x44 */	EUCCN_LATIN1,
	/* 0x45 */	EUCCN_LATIN1,
	/* 0x46 */	EUCCN_LATIN1,
	/* 0x47 */	EUCCN_LATIN1,
	/* 0x48 */	EUCCN_LATIN1,
	/* 0x49 */	EUCCN_LATIN1,
	/* 0x4a */	EUCCN_LATIN1,
	/* 0x4b */	EUCCN_LATIN1,
	/* 0x4c */	EUCCN_LATIN1,
	/* 0x4d */	EUCCN_LATIN1,
	/* 0x4e */	EUCCN_LATIN1,
	/* 0x4f */	EUCCN_LATIN1,
	/* 0x50 */	EUCCN_LATIN1,
	/* 0x51 */	EUCCN_LATIN1,
	/* 0x52 */	EUCCN_LATIN1,
	/* 0x53 */	EUCCN_LATIN1,
	/* 0x54 */	EUCCN_LATIN1,
	/* 0x55 */	EUCCN_LATIN1,
	/* 0x56 */	EUCCN_LATIN1,
	/* 0x57 */	EUCCN_LATIN1,
	/* 0x58 */	EUCCN_LATIN1,
	/* 0x59 */	EUCCN_LATIN1,
	/* 0x5a */	EUCCN_LATIN1,
	/* 0x5b */	EUCCN_LATIN1,
	/* 0x5c */	EUCCN_LATIN1,
	/* 0x5d */	EUCCN_LATIN1,
	/* 0x5e */	EUCCN_LATIN1,
	/* 0x5f */	EUCCN_LATIN1,
	/* 0x60 */	EUCCN_LATIN1,
	/* 0x61 */	EUCCN_LATIN1,
	/* 0x62 */	EUCCN_LATIN1,
	/* 0x63 */	EUCCN_LATIN1,
	/* 0x64 */	EUCCN_LATIN1,
	/* 0x65 */	EUCCN_LATIN1,
	/* 0x66 */	EUCCN_LATIN1,
	/* 0x67 */	EUCCN_LATIN1,
	/* 0x68 */	EUCCN_LATIN1,
	/* 0x69 */	EUCCN_LATIN1,
	/* 0x6a */	EUCCN_LATIN1,
	/* 0x6b */	EUCCN_LATIN1,
	/* 0x6c */	EUCCN_LATIN1,
	/* 0x6d */	EUCCN_LATIN1,
	/* 0x6e */	EUCCN_LATIN1,
	/* 0x6f */	EUCCN_LATIN1,
	/* 0x70 */	EUCCN_LATIN1,
	/* 0x71 */	EUCCN_LATIN1,
	/* 0x72 */	EUCCN_LATIN1,
	/* 0x73 */	EUCCN_LATIN1,
	/* 0x74 */	EUCCN_LATIN1,
	/* 0x75 */	EUCCN_LATIN1,
	/* 0x76 */	EUCCN_LATIN1,
	/* 0x77 */	EUCCN_LATIN1,
	/* 0x78 */	EUCCN_LATIN1,
	/* 0x79 */	EUCCN_LATIN1,
	/* 0x7a */	EUCCN_LATIN1,
	/* 0x7b */	EUCCN_LATIN1,
	/* 0x7c */	EUCCN_LATIN1,
	/* 0x7d */	EUCCN_LATIN1,
	/* 0x7e */	EUCCN_LATIN1,
	/* 0x7f */	EUCCN_LATIN1,
	/* 0x80 */	EUCCN_LATIN1,
	/* 0x81 */	EUCCN_LATIN1,
	/* 0x82 */	EUCCN_LATIN1,
	/* 0x83 */	EUCCN_LATIN1,
	/* 0x84 */	EUCCN_LATIN1,
	/* 0x85 */	EUCCN_LATIN1,
	/* 0x86 */	EUCCN_LATIN1,
	/* 0x87 */	EUCCN_LATIN1,
	/* 0x88 */	EUCCN_LATIN1,
	/* 0x89 */	EUCCN_LATIN1,
	/* 0x8a */	EUCCN_LATIN1,
	/* 0x8b */	EUCCN_LATIN1,
	/* 0x8c */	EUCCN_LATIN1,
	/* 0x8d */	EUCCN_LATIN1,
	/* 0x8e */	EUCCN_LATIN1,
	/* 0x8f */	EUCCN_LATIN1,
	/* 0x90 */	EUCCN_LATIN1,
	/* 0x91 */	EUCCN_LATIN1,
	/* 0x92 */	EUCCN_LATIN1,
	/* 0x93 */	EUCCN_LATIN1,
	/* 0x94 */	EUCCN_LATIN1,
	/* 0x95 */	EUCCN_LATIN1,
	/* 0x96 */	EUCCN_LATIN1,
	/* 0x97 */	EUCCN_LATIN1,
	/* 0x98 */	EUCCN_LATIN1,
	/* 0x99 */	EUCCN_LATIN1,
	/* 0x9a */	EUCCN_LATIN1,
	/* 0x9b */	EUCCN_LATIN1,
	/* 0x9c */	EUCCN_LATIN1,
	/* 0x9d */	EUCCN_LATIN1,
	/* 0x9e */	EUCCN_LATIN1,
	/* 0x9f */	EUCCN_LATIN1,
	/* 0xa0 */	EUCCN_LATIN1,
	/* 0xa1 */	EUCCN_GB2312,
	/* 0xa2 */	EUCCN_GB2312,
	/* 0xa3 */	EUCCN_GB2312,
	/* 0xa4 */	EUCCN_GB2312,
	/* 0xa5 */	EUCCN_GB2312,
	/* 0xa6 */	EUCCN_GB2312,
	/* 0xa7 */	EUCCN_GB2312,
	/* 0xa8 */	EUCCN_GB2312,
	/* 0xa9 */	EUCCN_GB2312,
	/* 0xaa */	EUCCN_GB2312,
	/* 0xab */	EUCCN_GB2312,
	/* 0xac */	EUCCN_GB2312,
	/* 0xad */	EUCCN_GB2312,
	/* 0xae */	EUCCN_GB2312,
	/* 0xaf */	EUCCN_GB2312,
	/* 0xb0 */	EUCCN_GB2312,
	/* 0xb1 */	EUCCN_GB2312,
	/* 0xb2 */	EUCCN_GB2312,
	/* 0xb3 */	EUCCN_GB2312,
	/* 0xb4 */	EUCCN_GB2312,
	/* 0xb5 */	EUCCN_GB2312,
	/* 0xb6 */	EUCCN_GB2312,
	/* 0xb7 */	EUCCN_GB2312,
	/* 0xb8 */	EUCCN_GB2312,
	/* 0xb9 */	EUCCN_GB2312,
	/* 0xba */	EUCCN_GB2312,
	/* 0xbb */	EUCCN_GB2312,
	/* 0xbc */	EUCCN_GB2312,
	/* 0xbd */	EUCCN_GB2312,
	/* 0xbe */	EUCCN_GB2312,
	/* 0xbf */	EUCCN_GB2312,
	/* 0xc0 */	EUCCN_GB2312,
	/* 0xc1 */	EUCCN_GB2312,
	/* 0xc2 */	EUCCN_GB2312,
	/* 0xc3 */	EUCCN_GB2312,
	/* 0xc4 */	EUCCN_GB2312,
	/* 0xc5 */	EUCCN_GB2312,
	/* 0xc6 */	EUCCN_GB2312,
	/* 0xc7 */	EUCCN_GB2312,
	/* 0xc8 */	EUCCN_GB2312,
	/* 0xc9 */	EUCCN_GB2312,
	/* 0xca */	EUCCN_GB2312,
	/* 0xcb */	EUCCN_GB2312,
	/* 0xcc */	EUCCN_GB2312,
	/* 0xcd */	EUCCN_GB2312,
	/* 0xce */	EUCCN_GB2312,
	/* 0xcf */	EUCCN_GB2312,
	/* 0xd0 */	EUCCN_GB2312,
	/* 0xd1 */	EUCCN_GB2312,
	/* 0xd2 */	EUCCN_GB2312,
	/* 0xd3 */	EUCCN_GB2312,
	/* 0xd4 */	EUCCN_GB2312,
	/* 0xd5 */	EUCCN_GB2312,
	/* 0xd6 */	EUCCN_GB2312,
	/* 0xd7 */	EUCCN_GB2312,
	/* 0xd8 */	EUCCN_GB2312,
	/* 0xd9 */	EUCCN_GB2312,
	/* 0xda */	EUCCN_GB2312,
	/* 0xdb */	EUCCN_GB2312,
	/* 0xdc */	EUCCN_GB2312,
	/* 0xdd */	EUCCN_GB2312,
	/* 0xde */	EUCCN_GB2312,
	/* 0xdf */	EUCCN_GB2312,
	/* 0xe0 */	EUCCN_GB2312,
	/* 0xe1 */	EUCCN_GB2312,
	/* 0xe2 */	EUCCN_GB2312,
	/* 0xe3 */	EUCCN_GB2312,
	/* 0xe4 */	EUCCN_GB2312,
	/* 0xe5 */	EUCCN_GB2312,
	/* 0xe6 */	EUCCN_GB2312,
	/* 0xe7 */	EUCCN_GB2312,
	/* 0xe8 */	EUCCN_GB2312,
	/* 0xe9 */	EUCCN_GB2312,
	/* 0xea */	EUCCN_GB2312,
	/* 0xeb */	EUCCN_GB2312,
	/* 0xec */	EUCCN_GB2312,
	/* 0xed */	EUCCN_GB2312,
	/* 0xee */	EUCCN_GB2312,
	/* 0xef */	EUCCN_GB2312,
	/* 0xf0 */	EUCCN_GB2312,
	/* 0xf1 */	EUCCN_GB2312,
	/* 0xf2 */	EUCCN_GB2312,
	/* 0xf3 */	EUCCN_GB2312,
	/* 0xf4 */	EUCCN_GB2312,
	/* 0xf5 */	EUCCN_GB2312,
	/* 0xf6 */	EUCCN_GB2312,
	/* 0xf7 */	EUCCN_GB2312,
	/* 0xf8 */	EUCCN_GB2312,
	/* 0xf9 */	EUCCN_GB2312,
	/* 0xfa */	EUCCN_GB2312,
	/* 0xfb */	EUCCN_GB2312,
	/* 0xfc */	EUCCN_GB2312,
	/* 0xfd */	EUCCN_GB2312,
	/* 0xfe */	EUCCN_GB2312,
	/* 0xff */	EUCCN_LATIN1,
};


static XP_Bool
fe_AreEUCCNFontsAvail(int16 win_csid)
{
	/* this needs to match the code in fe_LoadEUCCNFont */
	if ((fe_FontCharSets[CS_GB2312 & 0xff].name == NULL)
		&& (fe_FontCharSets[CS_GB2312_11 & 0xff].name == NULL))
		return FALSE;
	else
		return TRUE;
}

static fe_Font
fe_LoadEUCCNFont(MWContext *context, char *familyName, int points,
                 int sizeNum, int fontmask, int charset, int pitch,
                 int faceNum, Display *dpy)
{
	int16			cs;
	int			len;
	fe_FontGroupFont	*ret;

	len = (2 * sizeof(fe_FontGroupFont));
	ret = calloc(1, len);
	if (!ret)
	{
		return NULL;
	}
	(void) memset(ret, 0, len);

	/* this needs to match the code in fe_AreEUCCNFontsAvail */
	cs = CS_LATIN1;
	ret[0].xFont = (XFontStruct *)
            fe_LoadFont(context, &cs, familyName, points, sizeNum, fontmask);
	if (cs != CS_LATIN1)
	{
		XP_FREE(ret);
		return NULL;
	}

	cs = CS_GB2312;
	ret[1].xFont = (XFontStruct *)
            fe_LoadFont(context, &cs, familyName, points, sizeNum, fontmask);
	if (cs == CS_GB2312)
	{
		ret[1].mask1 = 0x7f;
		ret[1].mask2 = 0x7f;
	}
	else
	{
		cs = CS_GB2312_11;
		ret[1].xFont = (XFontStruct *)
                    fe_LoadFont(context, &cs, familyName, points, sizeNum,
                                fontmask);
		if (cs == CS_GB2312_11)
		{
			ret[1].mask1 = 0xff;
			ret[1].mask2 = 0xff;
		}
		else
		{
			XP_FREE(ret);
			return NULL;
		}
	}

	return (fe_Font) ret;
}

static XmFontList
fe_FontGroupGetFontList(int16 charset, fe_Font fontGroup, int numOfFonts)
{
	fe_FontGroupFont	*fonts;
        int i;
        char flabel[4];
        XmFontListEntry e;
        XmFontList fl;

	if(FALSE == fe_AreFontsAvail(charset)) 
           return NULL;

        XP_STRCPY(flabel, "f0");
	fonts = (fe_FontGroupFont *) fontGroup;

        e = XmFontListEntryCreate(flabel, 
                                  XmFONT_IS_FONT, 
                                  (XFontStruct*) fonts[0].xFont);
        flabel[1] = flabel[1] + 1;
        XP_ASSERT(NULL != e);
   
        fl = XmFontListAppendEntry(NULL, e);
        XP_ASSERT(NULL != fl);

        XmFontListEntryFree(&e);

        for(i=1; i < numOfFonts; i++, flabel[1] = flabel[1] + 1)
        {
           XFontStruct* f;

           XP_ASSERT(fonts[i].xFont);

           if(NULL != fonts[i].xFont)
             f = (XFontStruct*) fonts[i].xFont;
           else
             f = (XFontStruct*) fonts[0].xFont; /* somehow it will crash in Xt if we do not create it, fall back to latin1 */
           
           e = XmFontListEntryCreate(flabel, 
                               XmFONT_IS_FONT, 
                               f);
           XP_ASSERT(NULL != e);

           fl = XmFontListAppendEntry(fl, e);
           XP_ASSERT(NULL != fl);

           XmFontListEntryFree(&e);
        }
        return fl;
}

static XmString 
fe_EUCCNToXmString(int16 charset, fe_Font fontGroup, char * string, int len)
{
     return fe_EUCToXmString(charset, fontGroup, string, len, EUCCNTable);
}

static void
fe_EUCCNTextExtents(fe_Font font, char *string, int len, int *direction,
	int *fontAscent, int *fontDescent, XCharStruct *overall)
{
	fe_ProcessEUCString(CS_GB_8BIT, EUCCNTable, 
		NULL, 
		NULL,
		NULL, None, font, NULL, 0, 0, string, len,
		fontAscent, fontDescent, overall,
		fe_CharSetFuncsArray[FE_FONT_INFO_EUCCN].numberOfFonts);
}


static void
fe_DrawEUCCNString(Display *dpy, Drawable d, fe_Font font, GC gc, int x,
	int y, char *string, int len)
{
	fe_ProcessEUCString(CS_GB_8BIT, EUCCNTable, 
		(fe_XDrawStringFunc) XDrawString, 
		(fe_XDrawStringFunc) XDrawString16,
		dpy, d, font, gc, x, y, string, len,
		NULL, NULL, NULL,
		0);
}


static void
fe_DrawEUCCNImageString(Display *dpy, Drawable d, fe_Font font, GC gc, GC gc2,
	int x, int y, char *string, int len)
{
	fe_ProcessEUCString(CS_GB_8BIT, EUCCNTable, 
		(fe_XDrawStringFunc) XDrawImageString,
		(fe_XDrawStringFunc) XDrawImageString16,
		dpy, d, font, gc, x, y, string, len,
		NULL, NULL, NULL,
		0);
}


			/*	fontIndex	skip	len	*/
#define EUCJP_LATIN1	{	0,		0,	1	}
#define EUCJP_JISX0208	{	1,		0,	2	}
#define EUCJP_JISX0201	{	2,		1,	1	}
#define EUCJP_JISX0212	{	3,		1,	2	}

static fe_StringProcessTable EUCJPTable[] =
{
	/* 0x00 */	EUCJP_LATIN1,
	/* 0x01 */	EUCJP_LATIN1,
	/* 0x02 */	EUCJP_LATIN1,
	/* 0x03 */	EUCJP_LATIN1,
	/* 0x04 */	EUCJP_LATIN1,
	/* 0x05 */	EUCJP_LATIN1,
	/* 0x06 */	EUCJP_LATIN1,
	/* 0x07 */	EUCJP_LATIN1,
	/* 0x08 */	EUCJP_LATIN1,
	/* 0x09 */	EUCJP_LATIN1,
	/* 0x0a */	EUCJP_LATIN1,
	/* 0x0b */	EUCJP_LATIN1,
	/* 0x0c */	EUCJP_LATIN1,
	/* 0x0d */	EUCJP_LATIN1,
	/* 0x0e */	EUCJP_LATIN1,
	/* 0x0f */	EUCJP_LATIN1,
	/* 0x10 */	EUCJP_LATIN1,
	/* 0x11 */	EUCJP_LATIN1,
	/* 0x12 */	EUCJP_LATIN1,
	/* 0x13 */	EUCJP_LATIN1,
	/* 0x14 */	EUCJP_LATIN1,
	/* 0x15 */	EUCJP_LATIN1,
	/* 0x16 */	EUCJP_LATIN1,
	/* 0x17 */	EUCJP_LATIN1,
	/* 0x18 */	EUCJP_LATIN1,
	/* 0x19 */	EUCJP_LATIN1,
	/* 0x1a */	EUCJP_LATIN1,
	/* 0x1b */	EUCJP_LATIN1,
	/* 0x1c */	EUCJP_LATIN1,
	/* 0x1d */	EUCJP_LATIN1,
	/* 0x1e */	EUCJP_LATIN1,
	/* 0x1f */	EUCJP_LATIN1,
	/* 0x20 */	EUCJP_LATIN1,
	/* 0x21 */	EUCJP_LATIN1,
	/* 0x22 */	EUCJP_LATIN1,
	/* 0x23 */	EUCJP_LATIN1,
	/* 0x24 */	EUCJP_LATIN1,
	/* 0x25 */	EUCJP_LATIN1,
	/* 0x26 */	EUCJP_LATIN1,
	/* 0x27 */	EUCJP_LATIN1,
	/* 0x28 */	EUCJP_LATIN1,
	/* 0x29 */	EUCJP_LATIN1,
	/* 0x2a */	EUCJP_LATIN1,
	/* 0x2b */	EUCJP_LATIN1,
	/* 0x2c */	EUCJP_LATIN1,
	/* 0x2d */	EUCJP_LATIN1,
	/* 0x2e */	EUCJP_LATIN1,
	/* 0x2f */	EUCJP_LATIN1,
	/* 0x30 */	EUCJP_LATIN1,
	/* 0x31 */	EUCJP_LATIN1,
	/* 0x32 */	EUCJP_LATIN1,
	/* 0x33 */	EUCJP_LATIN1,
	/* 0x34 */	EUCJP_LATIN1,
	/* 0x35 */	EUCJP_LATIN1,
	/* 0x36 */	EUCJP_LATIN1,
	/* 0x37 */	EUCJP_LATIN1,
	/* 0x38 */	EUCJP_LATIN1,
	/* 0x39 */	EUCJP_LATIN1,
	/* 0x3a */	EUCJP_LATIN1,
	/* 0x3b */	EUCJP_LATIN1,
	/* 0x3c */	EUCJP_LATIN1,
	/* 0x3d */	EUCJP_LATIN1,
	/* 0x3e */	EUCJP_LATIN1,
	/* 0x3f */	EUCJP_LATIN1,
	/* 0x40 */	EUCJP_LATIN1,
	/* 0x41 */	EUCJP_LATIN1,
	/* 0x42 */	EUCJP_LATIN1,
	/* 0x43 */	EUCJP_LATIN1,
	/* 0x44 */	EUCJP_LATIN1,
	/* 0x45 */	EUCJP_LATIN1,
	/* 0x46 */	EUCJP_LATIN1,
	/* 0x47 */	EUCJP_LATIN1,
	/* 0x48 */	EUCJP_LATIN1,
	/* 0x49 */	EUCJP_LATIN1,
	/* 0x4a */	EUCJP_LATIN1,
	/* 0x4b */	EUCJP_LATIN1,
	/* 0x4c */	EUCJP_LATIN1,
	/* 0x4d */	EUCJP_LATIN1,
	/* 0x4e */	EUCJP_LATIN1,
	/* 0x4f */	EUCJP_LATIN1,
	/* 0x50 */	EUCJP_LATIN1,
	/* 0x51 */	EUCJP_LATIN1,
	/* 0x52 */	EUCJP_LATIN1,
	/* 0x53 */	EUCJP_LATIN1,
	/* 0x54 */	EUCJP_LATIN1,
	/* 0x55 */	EUCJP_LATIN1,
	/* 0x56 */	EUCJP_LATIN1,
	/* 0x57 */	EUCJP_LATIN1,
	/* 0x58 */	EUCJP_LATIN1,
	/* 0x59 */	EUCJP_LATIN1,
	/* 0x5a */	EUCJP_LATIN1,
	/* 0x5b */	EUCJP_LATIN1,
	/* 0x5c */	EUCJP_LATIN1,
	/* 0x5d */	EUCJP_LATIN1,
	/* 0x5e */	EUCJP_LATIN1,
	/* 0x5f */	EUCJP_LATIN1,
	/* 0x60 */	EUCJP_LATIN1,
	/* 0x61 */	EUCJP_LATIN1,
	/* 0x62 */	EUCJP_LATIN1,
	/* 0x63 */	EUCJP_LATIN1,
	/* 0x64 */	EUCJP_LATIN1,
	/* 0x65 */	EUCJP_LATIN1,
	/* 0x66 */	EUCJP_LATIN1,
	/* 0x67 */	EUCJP_LATIN1,
	/* 0x68 */	EUCJP_LATIN1,
	/* 0x69 */	EUCJP_LATIN1,
	/* 0x6a */	EUCJP_LATIN1,
	/* 0x6b */	EUCJP_LATIN1,
	/* 0x6c */	EUCJP_LATIN1,
	/* 0x6d */	EUCJP_LATIN1,
	/* 0x6e */	EUCJP_LATIN1,
	/* 0x6f */	EUCJP_LATIN1,
	/* 0x70 */	EUCJP_LATIN1,
	/* 0x71 */	EUCJP_LATIN1,
	/* 0x72 */	EUCJP_LATIN1,
	/* 0x73 */	EUCJP_LATIN1,
	/* 0x74 */	EUCJP_LATIN1,
	/* 0x75 */	EUCJP_LATIN1,
	/* 0x76 */	EUCJP_LATIN1,
	/* 0x77 */	EUCJP_LATIN1,
	/* 0x78 */	EUCJP_LATIN1,
	/* 0x79 */	EUCJP_LATIN1,
	/* 0x7a */	EUCJP_LATIN1,
	/* 0x7b */	EUCJP_LATIN1,
	/* 0x7c */	EUCJP_LATIN1,
	/* 0x7d */	EUCJP_LATIN1,
	/* 0x7e */	EUCJP_LATIN1,
	/* 0x7f */	EUCJP_LATIN1,
	/* 0x80 */	EUCJP_LATIN1,
	/* 0x81 */	EUCJP_LATIN1,
	/* 0x82 */	EUCJP_LATIN1,
	/* 0x83 */	EUCJP_LATIN1,
	/* 0x84 */	EUCJP_LATIN1,
	/* 0x85 */	EUCJP_LATIN1,
	/* 0x86 */	EUCJP_LATIN1,
	/* 0x87 */	EUCJP_LATIN1,
	/* 0x88 */	EUCJP_LATIN1,
	/* 0x89 */	EUCJP_LATIN1,
	/* 0x8a */	EUCJP_LATIN1,
	/* 0x8b */	EUCJP_LATIN1,
	/* 0x8c */	EUCJP_LATIN1,
	/* 0x8d */	EUCJP_LATIN1,
	/* 0x8e */	EUCJP_JISX0201,
	/* 0x8f */	EUCJP_JISX0212,
	/* 0x90 */	EUCJP_LATIN1,
	/* 0x91 */	EUCJP_LATIN1,
	/* 0x92 */	EUCJP_LATIN1,
	/* 0x93 */	EUCJP_LATIN1,
	/* 0x94 */	EUCJP_LATIN1,
	/* 0x95 */	EUCJP_LATIN1,
	/* 0x96 */	EUCJP_LATIN1,
	/* 0x97 */	EUCJP_LATIN1,
	/* 0x98 */	EUCJP_LATIN1,
	/* 0x99 */	EUCJP_LATIN1,
	/* 0x9a */	EUCJP_LATIN1,
	/* 0x9b */	EUCJP_LATIN1,
	/* 0x9c */	EUCJP_LATIN1,
	/* 0x9d */	EUCJP_LATIN1,
	/* 0x9e */	EUCJP_LATIN1,
	/* 0x9f */	EUCJP_LATIN1,
	/* 0xa0 */	EUCJP_LATIN1,
	/* 0xa1 */	EUCJP_JISX0208,
	/* 0xa2 */	EUCJP_JISX0208,
	/* 0xa3 */	EUCJP_JISX0208,
	/* 0xa4 */	EUCJP_JISX0208,
	/* 0xa5 */	EUCJP_JISX0208,
	/* 0xa6 */	EUCJP_JISX0208,
	/* 0xa7 */	EUCJP_JISX0208,
	/* 0xa8 */	EUCJP_JISX0208,
	/* 0xa9 */	EUCJP_JISX0208,
	/* 0xaa */	EUCJP_JISX0208,
	/* 0xab */	EUCJP_JISX0208,
	/* 0xac */	EUCJP_JISX0208,
	/* 0xad */	EUCJP_JISX0208,
	/* 0xae */	EUCJP_JISX0208,
	/* 0xaf */	EUCJP_JISX0208,
	/* 0xb0 */	EUCJP_JISX0208,
	/* 0xb1 */	EUCJP_JISX0208,
	/* 0xb2 */	EUCJP_JISX0208,
	/* 0xb3 */	EUCJP_JISX0208,
	/* 0xb4 */	EUCJP_JISX0208,
	/* 0xb5 */	EUCJP_JISX0208,
	/* 0xb6 */	EUCJP_JISX0208,
	/* 0xb7 */	EUCJP_JISX0208,
	/* 0xb8 */	EUCJP_JISX0208,
	/* 0xb9 */	EUCJP_JISX0208,
	/* 0xba */	EUCJP_JISX0208,
	/* 0xbb */	EUCJP_JISX0208,
	/* 0xbc */	EUCJP_JISX0208,
	/* 0xbd */	EUCJP_JISX0208,
	/* 0xbe */	EUCJP_JISX0208,
	/* 0xbf */	EUCJP_JISX0208,
	/* 0xc0 */	EUCJP_JISX0208,
	/* 0xc1 */	EUCJP_JISX0208,
	/* 0xc2 */	EUCJP_JISX0208,
	/* 0xc3 */	EUCJP_JISX0208,
	/* 0xc4 */	EUCJP_JISX0208,
	/* 0xc5 */	EUCJP_JISX0208,
	/* 0xc6 */	EUCJP_JISX0208,
	/* 0xc7 */	EUCJP_JISX0208,
	/* 0xc8 */	EUCJP_JISX0208,
	/* 0xc9 */	EUCJP_JISX0208,
	/* 0xca */	EUCJP_JISX0208,
	/* 0xcb */	EUCJP_JISX0208,
	/* 0xcc */	EUCJP_JISX0208,
	/* 0xcd */	EUCJP_JISX0208,
	/* 0xce */	EUCJP_JISX0208,
	/* 0xcf */	EUCJP_JISX0208,
	/* 0xd0 */	EUCJP_JISX0208,
	/* 0xd1 */	EUCJP_JISX0208,
	/* 0xd2 */	EUCJP_JISX0208,
	/* 0xd3 */	EUCJP_JISX0208,
	/* 0xd4 */	EUCJP_JISX0208,
	/* 0xd5 */	EUCJP_JISX0208,
	/* 0xd6 */	EUCJP_JISX0208,
	/* 0xd7 */	EUCJP_JISX0208,
	/* 0xd8 */	EUCJP_JISX0208,
	/* 0xd9 */	EUCJP_JISX0208,
	/* 0xda */	EUCJP_JISX0208,
	/* 0xdb */	EUCJP_JISX0208,
	/* 0xdc */	EUCJP_JISX0208,
	/* 0xdd */	EUCJP_JISX0208,
	/* 0xde */	EUCJP_JISX0208,
	/* 0xdf */	EUCJP_JISX0208,
	/* 0xe0 */	EUCJP_JISX0208,
	/* 0xe1 */	EUCJP_JISX0208,
	/* 0xe2 */	EUCJP_JISX0208,
	/* 0xe3 */	EUCJP_JISX0208,
	/* 0xe4 */	EUCJP_JISX0208,
	/* 0xe5 */	EUCJP_JISX0208,
	/* 0xe6 */	EUCJP_JISX0208,
	/* 0xe7 */	EUCJP_JISX0208,
	/* 0xe8 */	EUCJP_JISX0208,
	/* 0xe9 */	EUCJP_JISX0208,
	/* 0xea */	EUCJP_JISX0208,
	/* 0xeb */	EUCJP_JISX0208,
	/* 0xec */	EUCJP_JISX0208,
	/* 0xed */	EUCJP_JISX0208,
	/* 0xee */	EUCJP_JISX0208,
	/* 0xef */	EUCJP_JISX0208,
	/* 0xf0 */	EUCJP_JISX0208,
	/* 0xf1 */	EUCJP_JISX0208,
	/* 0xf2 */	EUCJP_JISX0208,
	/* 0xf3 */	EUCJP_JISX0208,
	/* 0xf4 */	EUCJP_JISX0208,
	/* 0xf5 */	EUCJP_JISX0208,
	/* 0xf6 */	EUCJP_JISX0208,
	/* 0xf7 */	EUCJP_JISX0208,
	/* 0xf8 */	EUCJP_JISX0208,
	/* 0xf9 */	EUCJP_JISX0208,
	/* 0xfa */	EUCJP_JISX0208,
	/* 0xfb */	EUCJP_JISX0208,
	/* 0xfc */	EUCJP_JISX0208,
	/* 0xfd */	EUCJP_JISX0208,
	/* 0xfe */	EUCJP_JISX0208,
	/* 0xff */	EUCJP_LATIN1,
};


static XP_Bool
fe_AreEUCJPFontsAvail(int16 win_csid)
{
	/* this needs to match the code in fe_LoadEUCJPFont */
	if ((fe_FontCharSets[CS_JISX0208 & 0xff].name == NULL)
		&& (fe_FontCharSets[CS_JISX0208_11 & 0xff].name == NULL))
		return FALSE;
	else
		return TRUE;
}

static fe_Font
fe_LoadEUCJPFont(MWContext *context, char *familyName, int points,
                 int sizeNum, int fontmask, int charset, int pitch,
                 int faceNum, Display *dpy)
{
	int16			cs;
	int			len;
	fe_FontGroupFont	*ret;

	len = (4 * sizeof(fe_FontGroupFont));
	ret = calloc(1, len);
	if (!ret)
	{
		return NULL;
	}
	(void) memset(ret, 0, len);

	/* this needs to match the code in fe_AreEUCJPFontsAvail */
	cs = CS_LATIN1;
	ret[0].xFont = (XFontStruct *)
            fe_LoadFont(context, &cs, familyName, points, sizeNum, fontmask);
	if (cs != CS_LATIN1)
	{
		XP_FREE(ret);
		return NULL;
	}

	cs = CS_JISX0208;
	ret[1].xFont = (XFontStruct *)
            fe_LoadFont(context, &cs, familyName, points, sizeNum, fontmask);
	if (cs == CS_JISX0208)
	{
		ret[1].mask1 = 0x7f;
		ret[1].mask2 = 0x7f;
	}
	else
	{
		cs = CS_JISX0208_11;
		ret[1].xFont = (XFontStruct *)
                    fe_LoadFont(context, &cs, familyName, points, sizeNum,
                                fontmask);
		if (cs == CS_JISX0208_11)
		{
			ret[1].mask1 = 0xff;
			ret[1].mask2 = 0xff;
		}
		else
		{
			XP_FREE(ret);
			return NULL;
		}
	}

	cs = CS_JISX0201;
	ret[2].xFont = (XFontStruct *)
            fe_LoadFont(context, &cs, familyName, points, sizeNum, fontmask);
	if (cs != CS_JISX0201)
	{
		ret[2].xFont = NULL;
	}

	cs = CS_JISX0212;
	ret[3].xFont = (XFontStruct *)
            fe_LoadFont(context, &cs, familyName, points, sizeNum, fontmask);
	if (cs == CS_JISX0212)
	{
		ret[3].mask1 = 0x7f;
		ret[3].mask2 = 0x7f;
	}
	else
	{
		ret[3].xFont = NULL;
	}

	return (fe_Font) ret;
}

static XmString 
fe_EUCJPToXmString(int16 charset, fe_Font fontGroup, char * string, int len)
{
     return fe_EUCToXmString(charset, fontGroup, string, len, EUCJPTable);
}
static void
fe_EUCJPTextExtents(fe_Font font, char *string, int len, int *direction,
	int *fontAscent, int *fontDescent, XCharStruct *overall)
{
	fe_ProcessEUCString(CS_EUCJP, EUCJPTable, 
		NULL, 
		NULL,
		NULL, None, font, NULL, 0, 0, string, len,
		fontAscent, fontDescent, overall,
		fe_CharSetFuncsArray[FE_FONT_INFO_EUCJP].numberOfFonts);
}


static void
fe_DrawEUCJPString(Display *dpy, Drawable d, fe_Font font, GC gc, int x,
	int y, char *string, int len)
{
	fe_ProcessEUCString(CS_EUCJP, EUCJPTable, 
		(fe_XDrawStringFunc) XDrawString, 
		(fe_XDrawStringFunc) XDrawString16,
		dpy, d, font, gc, x, y, string, len,
		NULL, NULL, NULL,
		0);
}


static void
fe_DrawEUCJPImageString(Display *dpy, Drawable d, fe_Font font, GC gc, GC gc2,
	int x, int y, char *string, int len)
{
	fe_ProcessEUCString(CS_EUCJP, EUCJPTable, 
		(fe_XDrawStringFunc) XDrawImageString,
		(fe_XDrawStringFunc) XDrawImageString16,
		dpy, d, font, gc, x, y, string, len,
		NULL, NULL, NULL,
		0);
}


			/*	fontIndex	skip	len	*/
#define EUCKR_LATIN1	{	0,		0,	1	}
#define EUCKR_KSC5601	{	1,		0,	2	}

static fe_StringProcessTable EUCKRTable[] =
{
	/* 0x00 */	EUCKR_LATIN1,
	/* 0x01 */	EUCKR_LATIN1,
	/* 0x02 */	EUCKR_LATIN1,
	/* 0x03 */	EUCKR_LATIN1,
	/* 0x04 */	EUCKR_LATIN1,
	/* 0x05 */	EUCKR_LATIN1,
	/* 0x06 */	EUCKR_LATIN1,
	/* 0x07 */	EUCKR_LATIN1,
	/* 0x08 */	EUCKR_LATIN1,
	/* 0x09 */	EUCKR_LATIN1,
	/* 0x0a */	EUCKR_LATIN1,
	/* 0x0b */	EUCKR_LATIN1,
	/* 0x0c */	EUCKR_LATIN1,
	/* 0x0d */	EUCKR_LATIN1,
	/* 0x0e */	EUCKR_LATIN1,
	/* 0x0f */	EUCKR_LATIN1,
	/* 0x10 */	EUCKR_LATIN1,
	/* 0x11 */	EUCKR_LATIN1,
	/* 0x12 */	EUCKR_LATIN1,
	/* 0x13 */	EUCKR_LATIN1,
	/* 0x14 */	EUCKR_LATIN1,
	/* 0x15 */	EUCKR_LATIN1,
	/* 0x16 */	EUCKR_LATIN1,
	/* 0x17 */	EUCKR_LATIN1,
	/* 0x18 */	EUCKR_LATIN1,
	/* 0x19 */	EUCKR_LATIN1,
	/* 0x1a */	EUCKR_LATIN1,
	/* 0x1b */	EUCKR_LATIN1,
	/* 0x1c */	EUCKR_LATIN1,
	/* 0x1d */	EUCKR_LATIN1,
	/* 0x1e */	EUCKR_LATIN1,
	/* 0x1f */	EUCKR_LATIN1,
	/* 0x20 */	EUCKR_LATIN1,
	/* 0x21 */	EUCKR_LATIN1,
	/* 0x22 */	EUCKR_LATIN1,
	/* 0x23 */	EUCKR_LATIN1,
	/* 0x24 */	EUCKR_LATIN1,
	/* 0x25 */	EUCKR_LATIN1,
	/* 0x26 */	EUCKR_LATIN1,
	/* 0x27 */	EUCKR_LATIN1,
	/* 0x28 */	EUCKR_LATIN1,
	/* 0x29 */	EUCKR_LATIN1,
	/* 0x2a */	EUCKR_LATIN1,
	/* 0x2b */	EUCKR_LATIN1,
	/* 0x2c */	EUCKR_LATIN1,
	/* 0x2d */	EUCKR_LATIN1,
	/* 0x2e */	EUCKR_LATIN1,
	/* 0x2f */	EUCKR_LATIN1,
	/* 0x30 */	EUCKR_LATIN1,
	/* 0x31 */	EUCKR_LATIN1,
	/* 0x32 */	EUCKR_LATIN1,
	/* 0x33 */	EUCKR_LATIN1,
	/* 0x34 */	EUCKR_LATIN1,
	/* 0x35 */	EUCKR_LATIN1,
	/* 0x36 */	EUCKR_LATIN1,
	/* 0x37 */	EUCKR_LATIN1,
	/* 0x38 */	EUCKR_LATIN1,
	/* 0x39 */	EUCKR_LATIN1,
	/* 0x3a */	EUCKR_LATIN1,
	/* 0x3b */	EUCKR_LATIN1,
	/* 0x3c */	EUCKR_LATIN1,
	/* 0x3d */	EUCKR_LATIN1,
	/* 0x3e */	EUCKR_LATIN1,
	/* 0x3f */	EUCKR_LATIN1,
	/* 0x40 */	EUCKR_LATIN1,
	/* 0x41 */	EUCKR_LATIN1,
	/* 0x42 */	EUCKR_LATIN1,
	/* 0x43 */	EUCKR_LATIN1,
	/* 0x44 */	EUCKR_LATIN1,
	/* 0x45 */	EUCKR_LATIN1,
	/* 0x46 */	EUCKR_LATIN1,
	/* 0x47 */	EUCKR_LATIN1,
	/* 0x48 */	EUCKR_LATIN1,
	/* 0x49 */	EUCKR_LATIN1,
	/* 0x4a */	EUCKR_LATIN1,
	/* 0x4b */	EUCKR_LATIN1,
	/* 0x4c */	EUCKR_LATIN1,
	/* 0x4d */	EUCKR_LATIN1,
	/* 0x4e */	EUCKR_LATIN1,
	/* 0x4f */	EUCKR_LATIN1,
	/* 0x50 */	EUCKR_LATIN1,
	/* 0x51 */	EUCKR_LATIN1,
	/* 0x52 */	EUCKR_LATIN1,
	/* 0x53 */	EUCKR_LATIN1,
	/* 0x54 */	EUCKR_LATIN1,
	/* 0x55 */	EUCKR_LATIN1,
	/* 0x56 */	EUCKR_LATIN1,
	/* 0x57 */	EUCKR_LATIN1,
	/* 0x58 */	EUCKR_LATIN1,
	/* 0x59 */	EUCKR_LATIN1,
	/* 0x5a */	EUCKR_LATIN1,
	/* 0x5b */	EUCKR_LATIN1,
	/* 0x5c */	EUCKR_LATIN1,
	/* 0x5d */	EUCKR_LATIN1,
	/* 0x5e */	EUCKR_LATIN1,
	/* 0x5f */	EUCKR_LATIN1,
	/* 0x60 */	EUCKR_LATIN1,
	/* 0x61 */	EUCKR_LATIN1,
	/* 0x62 */	EUCKR_LATIN1,
	/* 0x63 */	EUCKR_LATIN1,
	/* 0x64 */	EUCKR_LATIN1,
	/* 0x65 */	EUCKR_LATIN1,
	/* 0x66 */	EUCKR_LATIN1,
	/* 0x67 */	EUCKR_LATIN1,
	/* 0x68 */	EUCKR_LATIN1,
	/* 0x69 */	EUCKR_LATIN1,
	/* 0x6a */	EUCKR_LATIN1,
	/* 0x6b */	EUCKR_LATIN1,
	/* 0x6c */	EUCKR_LATIN1,
	/* 0x6d */	EUCKR_LATIN1,
	/* 0x6e */	EUCKR_LATIN1,
	/* 0x6f */	EUCKR_LATIN1,
	/* 0x70 */	EUCKR_LATIN1,
	/* 0x71 */	EUCKR_LATIN1,
	/* 0x72 */	EUCKR_LATIN1,
	/* 0x73 */	EUCKR_LATIN1,
	/* 0x74 */	EUCKR_LATIN1,
	/* 0x75 */	EUCKR_LATIN1,
	/* 0x76 */	EUCKR_LATIN1,
	/* 0x77 */	EUCKR_LATIN1,
	/* 0x78 */	EUCKR_LATIN1,
	/* 0x79 */	EUCKR_LATIN1,
	/* 0x7a */	EUCKR_LATIN1,
	/* 0x7b */	EUCKR_LATIN1,
	/* 0x7c */	EUCKR_LATIN1,
	/* 0x7d */	EUCKR_LATIN1,
	/* 0x7e */	EUCKR_LATIN1,
	/* 0x7f */	EUCKR_LATIN1,
	/* 0x80 */	EUCKR_LATIN1,
	/* 0x81 */	EUCKR_LATIN1,
	/* 0x82 */	EUCKR_LATIN1,
	/* 0x83 */	EUCKR_LATIN1,
	/* 0x84 */	EUCKR_LATIN1,
	/* 0x85 */	EUCKR_LATIN1,
	/* 0x86 */	EUCKR_LATIN1,
	/* 0x87 */	EUCKR_LATIN1,
	/* 0x88 */	EUCKR_LATIN1,
	/* 0x89 */	EUCKR_LATIN1,
	/* 0x8a */	EUCKR_LATIN1,
	/* 0x8b */	EUCKR_LATIN1,
	/* 0x8c */	EUCKR_LATIN1,
	/* 0x8d */	EUCKR_LATIN1,
	/* 0x8e */	EUCKR_LATIN1,
	/* 0x8f */	EUCKR_LATIN1,
	/* 0x90 */	EUCKR_LATIN1,
	/* 0x91 */	EUCKR_LATIN1,
	/* 0x92 */	EUCKR_LATIN1,
	/* 0x93 */	EUCKR_LATIN1,
	/* 0x94 */	EUCKR_LATIN1,
	/* 0x95 */	EUCKR_LATIN1,
	/* 0x96 */	EUCKR_LATIN1,
	/* 0x97 */	EUCKR_LATIN1,
	/* 0x98 */	EUCKR_LATIN1,
	/* 0x99 */	EUCKR_LATIN1,
	/* 0x9a */	EUCKR_LATIN1,
	/* 0x9b */	EUCKR_LATIN1,
	/* 0x9c */	EUCKR_LATIN1,
	/* 0x9d */	EUCKR_LATIN1,
	/* 0x9e */	EUCKR_LATIN1,
	/* 0x9f */	EUCKR_LATIN1,
	/* 0xa0 */	EUCKR_LATIN1,
	/* 0xa1 */	EUCKR_KSC5601,
	/* 0xa2 */	EUCKR_KSC5601,
	/* 0xa3 */	EUCKR_KSC5601,
	/* 0xa4 */	EUCKR_KSC5601,
	/* 0xa5 */	EUCKR_KSC5601,
	/* 0xa6 */	EUCKR_KSC5601,
	/* 0xa7 */	EUCKR_KSC5601,
	/* 0xa8 */	EUCKR_KSC5601,
	/* 0xa9 */	EUCKR_KSC5601,
	/* 0xaa */	EUCKR_KSC5601,
	/* 0xab */	EUCKR_KSC5601,
	/* 0xac */	EUCKR_KSC5601,
	/* 0xad */	EUCKR_KSC5601,
	/* 0xae */	EUCKR_KSC5601,
	/* 0xaf */	EUCKR_KSC5601,
	/* 0xb0 */	EUCKR_KSC5601,
	/* 0xb1 */	EUCKR_KSC5601,
	/* 0xb2 */	EUCKR_KSC5601,
	/* 0xb3 */	EUCKR_KSC5601,
	/* 0xb4 */	EUCKR_KSC5601,
	/* 0xb5 */	EUCKR_KSC5601,
	/* 0xb6 */	EUCKR_KSC5601,
	/* 0xb7 */	EUCKR_KSC5601,
	/* 0xb8 */	EUCKR_KSC5601,
	/* 0xb9 */	EUCKR_KSC5601,
	/* 0xba */	EUCKR_KSC5601,
	/* 0xbb */	EUCKR_KSC5601,
	/* 0xbc */	EUCKR_KSC5601,
	/* 0xbd */	EUCKR_KSC5601,
	/* 0xbe */	EUCKR_KSC5601,
	/* 0xbf */	EUCKR_KSC5601,
	/* 0xc0 */	EUCKR_KSC5601,
	/* 0xc1 */	EUCKR_KSC5601,
	/* 0xc2 */	EUCKR_KSC5601,
	/* 0xc3 */	EUCKR_KSC5601,
	/* 0xc4 */	EUCKR_KSC5601,
	/* 0xc5 */	EUCKR_KSC5601,
	/* 0xc6 */	EUCKR_KSC5601,
	/* 0xc7 */	EUCKR_KSC5601,
	/* 0xc8 */	EUCKR_KSC5601,
	/* 0xc9 */	EUCKR_KSC5601,
	/* 0xca */	EUCKR_KSC5601,
	/* 0xcb */	EUCKR_KSC5601,
	/* 0xcc */	EUCKR_KSC5601,
	/* 0xcd */	EUCKR_KSC5601,
	/* 0xce */	EUCKR_KSC5601,
	/* 0xcf */	EUCKR_KSC5601,
	/* 0xd0 */	EUCKR_KSC5601,
	/* 0xd1 */	EUCKR_KSC5601,
	/* 0xd2 */	EUCKR_KSC5601,
	/* 0xd3 */	EUCKR_KSC5601,
	/* 0xd4 */	EUCKR_KSC5601,
	/* 0xd5 */	EUCKR_KSC5601,
	/* 0xd6 */	EUCKR_KSC5601,
	/* 0xd7 */	EUCKR_KSC5601,
	/* 0xd8 */	EUCKR_KSC5601,
	/* 0xd9 */	EUCKR_KSC5601,
	/* 0xda */	EUCKR_KSC5601,
	/* 0xdb */	EUCKR_KSC5601,
	/* 0xdc */	EUCKR_KSC5601,
	/* 0xdd */	EUCKR_KSC5601,
	/* 0xde */	EUCKR_KSC5601,
	/* 0xdf */	EUCKR_KSC5601,
	/* 0xe0 */	EUCKR_KSC5601,
	/* 0xe1 */	EUCKR_KSC5601,
	/* 0xe2 */	EUCKR_KSC5601,
	/* 0xe3 */	EUCKR_KSC5601,
	/* 0xe4 */	EUCKR_KSC5601,
	/* 0xe5 */	EUCKR_KSC5601,
	/* 0xe6 */	EUCKR_KSC5601,
	/* 0xe7 */	EUCKR_KSC5601,
	/* 0xe8 */	EUCKR_KSC5601,
	/* 0xe9 */	EUCKR_KSC5601,
	/* 0xea */	EUCKR_KSC5601,
	/* 0xeb */	EUCKR_KSC5601,
	/* 0xec */	EUCKR_KSC5601,
	/* 0xed */	EUCKR_KSC5601,
	/* 0xee */	EUCKR_KSC5601,
	/* 0xef */	EUCKR_KSC5601,
	/* 0xf0 */	EUCKR_KSC5601,
	/* 0xf1 */	EUCKR_KSC5601,
	/* 0xf2 */	EUCKR_KSC5601,
	/* 0xf3 */	EUCKR_KSC5601,
	/* 0xf4 */	EUCKR_KSC5601,
	/* 0xf5 */	EUCKR_KSC5601,
	/* 0xf6 */	EUCKR_KSC5601,
	/* 0xf7 */	EUCKR_KSC5601,
	/* 0xf8 */	EUCKR_KSC5601,
	/* 0xf9 */	EUCKR_KSC5601,
	/* 0xfa */	EUCKR_KSC5601,
	/* 0xfb */	EUCKR_KSC5601,
	/* 0xfc */	EUCKR_KSC5601,
	/* 0xfd */	EUCKR_KSC5601,
	/* 0xfe */	EUCKR_KSC5601,
	/* 0xff */	EUCKR_LATIN1,
};


static XP_Bool
fe_AreEUCKRFontsAvail(int16 win_csid)
{
	/* this needs to match the code in fe_LoadEUCKRFont */
	if ((fe_FontCharSets[CS_KSC5601 & 0xff].name == NULL)
		&& (fe_FontCharSets[CS_KSC5601_11 & 0xff].name == NULL))
		return FALSE;
	else
		return TRUE;
}

static fe_Font
fe_LoadEUCKRFont(MWContext *context, char *familyName, int points,
                 int sizeNum, int fontmask, int charset, int pitch,
                 int faceNum, Display *dpy)
{
	int16			cs;
	int			len;
	fe_FontGroupFont	*ret;

	len = (2 * sizeof(fe_FontGroupFont));
	ret = calloc(1, len);
	if (!ret)
	{
		return NULL;
	}
	(void) memset(ret, 0, len);

	cs = CS_LATIN1;
	ret[0].xFont = (XFontStruct *)
            fe_LoadFont(context, &cs, familyName, points, sizeNum, fontmask);
	if (cs != CS_LATIN1)
	{
		XP_FREE(ret);
		return NULL;
	}

	/* this needs to match the code in fe_AreEUCKRFontsAvail */
	cs = CS_KSC5601;
	ret[1].xFont = (XFontStruct *)
            fe_LoadFont(context, &cs, familyName, points, sizeNum, fontmask);
	if (cs == CS_KSC5601)
	{
		ret[1].mask1 = 0x7f;
		ret[1].mask2 = 0x7f;
	}
	else
	{
		cs = CS_KSC5601_11;
		ret[1].xFont = (XFontStruct *)
                    fe_LoadFont(context, &cs, familyName, points, sizeNum,
                                fontmask);
		if (cs == CS_KSC5601_11)
		{
			ret[1].mask1 = 0xff;
			ret[1].mask2 = 0xff;
		}
		else
		{
			XP_FREE(ret);
			return NULL;
		}
	}

	return (fe_Font) ret;
}

static XmString 
fe_EUCKRToXmString(int16 charset, fe_Font fontGroup, char * string, int len)
{
     return fe_EUCToXmString(charset, fontGroup, string, len, EUCKRTable);
}
static void
fe_EUCKRTextExtents(fe_Font font, char *string, int len, int *direction,
	int *fontAscent, int *fontDescent, XCharStruct *overall)
{
	fe_ProcessEUCString(CS_KSC_8BIT, EUCKRTable, 
		NULL, 
		NULL,
		NULL, None, font, NULL, 0, 0, string, len,
		fontAscent, fontDescent, overall,
		fe_CharSetFuncsArray[FE_FONT_INFO_EUCKR].numberOfFonts);
}


static void
fe_DrawEUCKRString(Display *dpy, Drawable d, fe_Font font, GC gc, int x,
	int y, char *string, int len)
{
	fe_ProcessEUCString(CS_KSC_8BIT, EUCKRTable, 
		(fe_XDrawStringFunc) XDrawString, 
		(fe_XDrawStringFunc) XDrawString16,
		dpy, d, font, gc, x, y, string, len,
		NULL, NULL, NULL,
		0);
}


static void
fe_DrawEUCKRImageString(Display *dpy, Drawable d, fe_Font font, GC gc, GC gc2,
	int x, int y, char *string, int len)
{
	fe_ProcessEUCString(CS_KSC_8BIT, EUCKRTable, 
		(fe_XDrawStringFunc) XDrawImageString,
		(fe_XDrawStringFunc) XDrawImageString16,
		dpy, d, font, gc, x, y, string, len,
		NULL, NULL, NULL,
		0);
}


				/*	fontIndex	skip	len	*/
#define EUCTW_LATIN1		{	0,		0,	1	}
#define EUCTW_CNS11643_1	{	1,		0,	2	}
#define EUCTW_CNS11643_2	{	2,		2,	2	}

static fe_StringProcessTable EUCTWTable[] =
{
	/* 0x00 */	EUCTW_LATIN1,
	/* 0x01 */	EUCTW_LATIN1,
	/* 0x02 */	EUCTW_LATIN1,
	/* 0x03 */	EUCTW_LATIN1,
	/* 0x04 */	EUCTW_LATIN1,
	/* 0x05 */	EUCTW_LATIN1,
	/* 0x06 */	EUCTW_LATIN1,
	/* 0x07 */	EUCTW_LATIN1,
	/* 0x08 */	EUCTW_LATIN1,
	/* 0x09 */	EUCTW_LATIN1,
	/* 0x0a */	EUCTW_LATIN1,
	/* 0x0b */	EUCTW_LATIN1,
	/* 0x0c */	EUCTW_LATIN1,
	/* 0x0d */	EUCTW_LATIN1,
	/* 0x0e */	EUCTW_LATIN1,
	/* 0x0f */	EUCTW_LATIN1,
	/* 0x10 */	EUCTW_LATIN1,
	/* 0x11 */	EUCTW_LATIN1,
	/* 0x12 */	EUCTW_LATIN1,
	/* 0x13 */	EUCTW_LATIN1,
	/* 0x14 */	EUCTW_LATIN1,
	/* 0x15 */	EUCTW_LATIN1,
	/* 0x16 */	EUCTW_LATIN1,
	/* 0x17 */	EUCTW_LATIN1,
	/* 0x18 */	EUCTW_LATIN1,
	/* 0x19 */	EUCTW_LATIN1,
	/* 0x1a */	EUCTW_LATIN1,
	/* 0x1b */	EUCTW_LATIN1,
	/* 0x1c */	EUCTW_LATIN1,
	/* 0x1d */	EUCTW_LATIN1,
	/* 0x1e */	EUCTW_LATIN1,
	/* 0x1f */	EUCTW_LATIN1,
	/* 0x20 */	EUCTW_LATIN1,
	/* 0x21 */	EUCTW_LATIN1,
	/* 0x22 */	EUCTW_LATIN1,
	/* 0x23 */	EUCTW_LATIN1,
	/* 0x24 */	EUCTW_LATIN1,
	/* 0x25 */	EUCTW_LATIN1,
	/* 0x26 */	EUCTW_LATIN1,
	/* 0x27 */	EUCTW_LATIN1,
	/* 0x28 */	EUCTW_LATIN1,
	/* 0x29 */	EUCTW_LATIN1,
	/* 0x2a */	EUCTW_LATIN1,
	/* 0x2b */	EUCTW_LATIN1,
	/* 0x2c */	EUCTW_LATIN1,
	/* 0x2d */	EUCTW_LATIN1,
	/* 0x2e */	EUCTW_LATIN1,
	/* 0x2f */	EUCTW_LATIN1,
	/* 0x30 */	EUCTW_LATIN1,
	/* 0x31 */	EUCTW_LATIN1,
	/* 0x32 */	EUCTW_LATIN1,
	/* 0x33 */	EUCTW_LATIN1,
	/* 0x34 */	EUCTW_LATIN1,
	/* 0x35 */	EUCTW_LATIN1,
	/* 0x36 */	EUCTW_LATIN1,
	/* 0x37 */	EUCTW_LATIN1,
	/* 0x38 */	EUCTW_LATIN1,
	/* 0x39 */	EUCTW_LATIN1,
	/* 0x3a */	EUCTW_LATIN1,
	/* 0x3b */	EUCTW_LATIN1,
	/* 0x3c */	EUCTW_LATIN1,
	/* 0x3d */	EUCTW_LATIN1,
	/* 0x3e */	EUCTW_LATIN1,
	/* 0x3f */	EUCTW_LATIN1,
	/* 0x40 */	EUCTW_LATIN1,
	/* 0x41 */	EUCTW_LATIN1,
	/* 0x42 */	EUCTW_LATIN1,
	/* 0x43 */	EUCTW_LATIN1,
	/* 0x44 */	EUCTW_LATIN1,
	/* 0x45 */	EUCTW_LATIN1,
	/* 0x46 */	EUCTW_LATIN1,
	/* 0x47 */	EUCTW_LATIN1,
	/* 0x48 */	EUCTW_LATIN1,
	/* 0x49 */	EUCTW_LATIN1,
	/* 0x4a */	EUCTW_LATIN1,
	/* 0x4b */	EUCTW_LATIN1,
	/* 0x4c */	EUCTW_LATIN1,
	/* 0x4d */	EUCTW_LATIN1,
	/* 0x4e */	EUCTW_LATIN1,
	/* 0x4f */	EUCTW_LATIN1,
	/* 0x50 */	EUCTW_LATIN1,
	/* 0x51 */	EUCTW_LATIN1,
	/* 0x52 */	EUCTW_LATIN1,
	/* 0x53 */	EUCTW_LATIN1,
	/* 0x54 */	EUCTW_LATIN1,
	/* 0x55 */	EUCTW_LATIN1,
	/* 0x56 */	EUCTW_LATIN1,
	/* 0x57 */	EUCTW_LATIN1,
	/* 0x58 */	EUCTW_LATIN1,
	/* 0x59 */	EUCTW_LATIN1,
	/* 0x5a */	EUCTW_LATIN1,
	/* 0x5b */	EUCTW_LATIN1,
	/* 0x5c */	EUCTW_LATIN1,
	/* 0x5d */	EUCTW_LATIN1,
	/* 0x5e */	EUCTW_LATIN1,
	/* 0x5f */	EUCTW_LATIN1,
	/* 0x60 */	EUCTW_LATIN1,
	/* 0x61 */	EUCTW_LATIN1,
	/* 0x62 */	EUCTW_LATIN1,
	/* 0x63 */	EUCTW_LATIN1,
	/* 0x64 */	EUCTW_LATIN1,
	/* 0x65 */	EUCTW_LATIN1,
	/* 0x66 */	EUCTW_LATIN1,
	/* 0x67 */	EUCTW_LATIN1,
	/* 0x68 */	EUCTW_LATIN1,
	/* 0x69 */	EUCTW_LATIN1,
	/* 0x6a */	EUCTW_LATIN1,
	/* 0x6b */	EUCTW_LATIN1,
	/* 0x6c */	EUCTW_LATIN1,
	/* 0x6d */	EUCTW_LATIN1,
	/* 0x6e */	EUCTW_LATIN1,
	/* 0x6f */	EUCTW_LATIN1,
	/* 0x70 */	EUCTW_LATIN1,
	/* 0x71 */	EUCTW_LATIN1,
	/* 0x72 */	EUCTW_LATIN1,
	/* 0x73 */	EUCTW_LATIN1,
	/* 0x74 */	EUCTW_LATIN1,
	/* 0x75 */	EUCTW_LATIN1,
	/* 0x76 */	EUCTW_LATIN1,
	/* 0x77 */	EUCTW_LATIN1,
	/* 0x78 */	EUCTW_LATIN1,
	/* 0x79 */	EUCTW_LATIN1,
	/* 0x7a */	EUCTW_LATIN1,
	/* 0x7b */	EUCTW_LATIN1,
	/* 0x7c */	EUCTW_LATIN1,
	/* 0x7d */	EUCTW_LATIN1,
	/* 0x7e */	EUCTW_LATIN1,
	/* 0x7f */	EUCTW_LATIN1,
	/* 0x80 */	EUCTW_LATIN1,
	/* 0x81 */	EUCTW_LATIN1,
	/* 0x82 */	EUCTW_LATIN1,
	/* 0x83 */	EUCTW_LATIN1,
	/* 0x84 */	EUCTW_LATIN1,
	/* 0x85 */	EUCTW_LATIN1,
	/* 0x86 */	EUCTW_LATIN1,
	/* 0x87 */	EUCTW_LATIN1,
	/* 0x88 */	EUCTW_LATIN1,
	/* 0x89 */	EUCTW_LATIN1,
	/* 0x8a */	EUCTW_LATIN1,
	/* 0x8b */	EUCTW_LATIN1,
	/* 0x8c */	EUCTW_LATIN1,
	/* 0x8d */	EUCTW_LATIN1,
	/* 0x8e */	EUCTW_CNS11643_2,
	/* 0x8f */	EUCTW_LATIN1,
	/* 0x90 */	EUCTW_LATIN1,
	/* 0x91 */	EUCTW_LATIN1,
	/* 0x92 */	EUCTW_LATIN1,
	/* 0x93 */	EUCTW_LATIN1,
	/* 0x94 */	EUCTW_LATIN1,
	/* 0x95 */	EUCTW_LATIN1,
	/* 0x96 */	EUCTW_LATIN1,
	/* 0x97 */	EUCTW_LATIN1,
	/* 0x98 */	EUCTW_LATIN1,
	/* 0x99 */	EUCTW_LATIN1,
	/* 0x9a */	EUCTW_LATIN1,
	/* 0x9b */	EUCTW_LATIN1,
	/* 0x9c */	EUCTW_LATIN1,
	/* 0x9d */	EUCTW_LATIN1,
	/* 0x9e */	EUCTW_LATIN1,
	/* 0x9f */	EUCTW_LATIN1,
	/* 0xa0 */	EUCTW_LATIN1,
	/* 0xa1 */	EUCTW_CNS11643_1,
	/* 0xa2 */	EUCTW_CNS11643_1,
	/* 0xa3 */	EUCTW_CNS11643_1,
	/* 0xa4 */	EUCTW_CNS11643_1,
	/* 0xa5 */	EUCTW_CNS11643_1,
	/* 0xa6 */	EUCTW_CNS11643_1,
	/* 0xa7 */	EUCTW_CNS11643_1,
	/* 0xa8 */	EUCTW_CNS11643_1,
	/* 0xa9 */	EUCTW_CNS11643_1,
	/* 0xaa */	EUCTW_CNS11643_1,
	/* 0xab */	EUCTW_CNS11643_1,
	/* 0xac */	EUCTW_CNS11643_1,
	/* 0xad */	EUCTW_CNS11643_1,
	/* 0xae */	EUCTW_CNS11643_1,
	/* 0xaf */	EUCTW_CNS11643_1,
	/* 0xb0 */	EUCTW_CNS11643_1,
	/* 0xb1 */	EUCTW_CNS11643_1,
	/* 0xb2 */	EUCTW_CNS11643_1,
	/* 0xb3 */	EUCTW_CNS11643_1,
	/* 0xb4 */	EUCTW_CNS11643_1,
	/* 0xb5 */	EUCTW_CNS11643_1,
	/* 0xb6 */	EUCTW_CNS11643_1,
	/* 0xb7 */	EUCTW_CNS11643_1,
	/* 0xb8 */	EUCTW_CNS11643_1,
	/* 0xb9 */	EUCTW_CNS11643_1,
	/* 0xba */	EUCTW_CNS11643_1,
	/* 0xbb */	EUCTW_CNS11643_1,
	/* 0xbc */	EUCTW_CNS11643_1,
	/* 0xbd */	EUCTW_CNS11643_1,
	/* 0xbe */	EUCTW_CNS11643_1,
	/* 0xbf */	EUCTW_CNS11643_1,
	/* 0xc0 */	EUCTW_CNS11643_1,
	/* 0xc1 */	EUCTW_CNS11643_1,
	/* 0xc2 */	EUCTW_CNS11643_1,
	/* 0xc3 */	EUCTW_CNS11643_1,
	/* 0xc4 */	EUCTW_CNS11643_1,
	/* 0xc5 */	EUCTW_CNS11643_1,
	/* 0xc6 */	EUCTW_CNS11643_1,
	/* 0xc7 */	EUCTW_CNS11643_1,
	/* 0xc8 */	EUCTW_CNS11643_1,
	/* 0xc9 */	EUCTW_CNS11643_1,
	/* 0xca */	EUCTW_CNS11643_1,
	/* 0xcb */	EUCTW_CNS11643_1,
	/* 0xcc */	EUCTW_CNS11643_1,
	/* 0xcd */	EUCTW_CNS11643_1,
	/* 0xce */	EUCTW_CNS11643_1,
	/* 0xcf */	EUCTW_CNS11643_1,
	/* 0xd0 */	EUCTW_CNS11643_1,
	/* 0xd1 */	EUCTW_CNS11643_1,
	/* 0xd2 */	EUCTW_CNS11643_1,
	/* 0xd3 */	EUCTW_CNS11643_1,
	/* 0xd4 */	EUCTW_CNS11643_1,
	/* 0xd5 */	EUCTW_CNS11643_1,
	/* 0xd6 */	EUCTW_CNS11643_1,
	/* 0xd7 */	EUCTW_CNS11643_1,
	/* 0xd8 */	EUCTW_CNS11643_1,
	/* 0xd9 */	EUCTW_CNS11643_1,
	/* 0xda */	EUCTW_CNS11643_1,
	/* 0xdb */	EUCTW_CNS11643_1,
	/* 0xdc */	EUCTW_CNS11643_1,
	/* 0xdd */	EUCTW_CNS11643_1,
	/* 0xde */	EUCTW_CNS11643_1,
	/* 0xdf */	EUCTW_CNS11643_1,
	/* 0xe0 */	EUCTW_CNS11643_1,
	/* 0xe1 */	EUCTW_CNS11643_1,
	/* 0xe2 */	EUCTW_CNS11643_1,
	/* 0xe3 */	EUCTW_CNS11643_1,
	/* 0xe4 */	EUCTW_CNS11643_1,
	/* 0xe5 */	EUCTW_CNS11643_1,
	/* 0xe6 */	EUCTW_CNS11643_1,
	/* 0xe7 */	EUCTW_CNS11643_1,
	/* 0xe8 */	EUCTW_CNS11643_1,
	/* 0xe9 */	EUCTW_CNS11643_1,
	/* 0xea */	EUCTW_CNS11643_1,
	/* 0xeb */	EUCTW_CNS11643_1,
	/* 0xec */	EUCTW_CNS11643_1,
	/* 0xed */	EUCTW_CNS11643_1,
	/* 0xee */	EUCTW_CNS11643_1,
	/* 0xef */	EUCTW_CNS11643_1,
	/* 0xf0 */	EUCTW_CNS11643_1,
	/* 0xf1 */	EUCTW_CNS11643_1,
	/* 0xf2 */	EUCTW_CNS11643_1,
	/* 0xf3 */	EUCTW_CNS11643_1,
	/* 0xf4 */	EUCTW_CNS11643_1,
	/* 0xf5 */	EUCTW_CNS11643_1,
	/* 0xf6 */	EUCTW_CNS11643_1,
	/* 0xf7 */	EUCTW_CNS11643_1,
	/* 0xf8 */	EUCTW_CNS11643_1,
	/* 0xf9 */	EUCTW_CNS11643_1,
	/* 0xfa */	EUCTW_CNS11643_1,
	/* 0xfb */	EUCTW_CNS11643_1,
	/* 0xfc */	EUCTW_CNS11643_1,
	/* 0xfd */	EUCTW_CNS11643_1,
	/* 0xfe */	EUCTW_CNS11643_1,
	/* 0xff */	EUCTW_LATIN1,
};


static XP_Bool
fe_AreEUCTWFontsAvail(int16 win_csid)
{
	/* this needs to match the code in fe_LoadEUCTWFont */
	if (((fe_FontCharSets[CS_CNS11643_1 & 0xff].name == NULL)
		|| (fe_FontCharSets[CS_CNS11643_2 & 0xff].name == NULL))
		&& (fe_FontCharSets[CS_CNS11643_1110 & 0xff].name == NULL))
		return FALSE;
	else
		return TRUE;
}

static fe_Font
fe_LoadEUCTWFont(MWContext *context, char *familyName, int points,
                 int sizeNum, int fontmask, int charset, int pitch,
                 int faceNum, Display *dpy)
{
	int16			cs;
	int			len;
	fe_FontGroupFont	*ret;

	len = (3 * sizeof(fe_FontGroupFont));
	ret = calloc(1, len);
	if (!ret)
	{
		return NULL;
	}
	(void) memset(ret, 0, len);

	cs = CS_LATIN1;
	ret[0].xFont = (XFontStruct *)
            fe_LoadFont(context, &cs, familyName, points, sizeNum, fontmask);
	if (cs != CS_LATIN1)
	{
		XP_FREE(ret);
		return NULL;
	}

	/* this needs to match the code in fe_AreEUCTWFontsAvail */
	cs = CS_CNS11643_1;
	ret[1].xFont = (XFontStruct *)
            fe_LoadFont(context, &cs, familyName, points, sizeNum, fontmask);
	if (cs == CS_CNS11643_1)
	{
		ret[1].mask1 = 0x7f;
		ret[1].mask2 = 0x7f;
	}
	else
	{
		ret[1].xFont = NULL;
	}

	cs = CS_CNS11643_2;
	ret[2].xFont = (XFontStruct *)
            fe_LoadFont(context, &cs, familyName, points, sizeNum, fontmask);
	if (cs == CS_CNS11643_2)
	{
		ret[2].mask1 = 0x7f;
		ret[2].mask2 = 0x7f;
	}
	else
	{
		ret[2].xFont = NULL;
	}

	if ((!ret[1].xFont) || (!ret[2].xFont))
	{
		cs = CS_CNS11643_1110;
		ret[1].xFont = (XFontStruct *)
                    fe_LoadFont(context, &cs, familyName, points, sizeNum,
                                fontmask);
		if (cs == CS_CNS11643_1110)
		{
			ret[1].mask1 = 0xff;
			ret[1].mask2 = 0xff;

			ret[2].xFont = ret[1].xFont;
			ret[2].mask1 = 0xff;
			ret[2].mask2 = 0x7f;
		}
		else
		{
			XP_FREE(ret);
			return NULL;
		}
	}

	return (fe_Font) ret;
}

static XmString 
fe_EUCTWToXmString(int16 charset, fe_Font fontGroup, char * string, int len)
{
     return fe_EUCToXmString(charset, fontGroup, string, len, EUCTWTable);
}


static void
fe_EUCTWTextExtents(fe_Font font, char *string, int len, int *direction,
	int *fontAscent, int *fontDescent, XCharStruct *overall)
{
	fe_ProcessEUCString(CS_CNS_8BIT, EUCTWTable, 
		NULL, 
		NULL,
		NULL, None, font, NULL, 0, 0, string, len,
		fontAscent, fontDescent, overall,
		fe_CharSetFuncsArray[FE_FONT_INFO_EUCTW].numberOfFonts);
}


static void
fe_DrawEUCTWString(Display *dpy, Drawable d, fe_Font font, GC gc, int x,
	int y, char *string, int len)
{
	fe_ProcessEUCString(CS_CNS_8BIT, EUCTWTable, 
		(fe_XDrawStringFunc) XDrawString,
		(fe_XDrawStringFunc) XDrawString16,
		dpy, d, font, gc, x, y, string, len,
		NULL, NULL, NULL,
		0);
}


static void
fe_DrawEUCTWImageString(Display *dpy, Drawable d, fe_Font font, GC gc, GC gc2,
	int x, int y, char *string, int len)
{
	fe_ProcessEUCString(CS_CNS_8BIT, EUCTWTable, 
		(fe_XDrawStringFunc) XDrawImageString,
		(fe_XDrawStringFunc) XDrawImageString16,
		dpy, d, font, gc, x, y, string, len,
		NULL, NULL, NULL,
		0);
}


				/*	fontIndex	skip	len	*/
#define BIG5_LATIN1		{	0,		0,	1	}
#define BIG5_BIG5		{	1,		0,	2	}

static fe_StringProcessTable BIG5Table[] =
{
	/* 0x00 */	BIG5_LATIN1,
	/* 0x01 */	BIG5_LATIN1,
	/* 0x02 */	BIG5_LATIN1,
	/* 0x03 */	BIG5_LATIN1,
	/* 0x04 */	BIG5_LATIN1,
	/* 0x05 */	BIG5_LATIN1,
	/* 0x06 */	BIG5_LATIN1,
	/* 0x07 */	BIG5_LATIN1,
	/* 0x08 */	BIG5_LATIN1,
	/* 0x09 */	BIG5_LATIN1,
	/* 0x0a */	BIG5_LATIN1,
	/* 0x0b */	BIG5_LATIN1,
	/* 0x0c */	BIG5_LATIN1,
	/* 0x0d */	BIG5_LATIN1,
	/* 0x0e */	BIG5_LATIN1,
	/* 0x0f */	BIG5_LATIN1,
	/* 0x10 */	BIG5_LATIN1,
	/* 0x11 */	BIG5_LATIN1,
	/* 0x12 */	BIG5_LATIN1,
	/* 0x13 */	BIG5_LATIN1,
	/* 0x14 */	BIG5_LATIN1,
	/* 0x15 */	BIG5_LATIN1,
	/* 0x16 */	BIG5_LATIN1,
	/* 0x17 */	BIG5_LATIN1,
	/* 0x18 */	BIG5_LATIN1,
	/* 0x19 */	BIG5_LATIN1,
	/* 0x1a */	BIG5_LATIN1,
	/* 0x1b */	BIG5_LATIN1,
	/* 0x1c */	BIG5_LATIN1,
	/* 0x1d */	BIG5_LATIN1,
	/* 0x1e */	BIG5_LATIN1,
	/* 0x1f */	BIG5_LATIN1,
	/* 0x20 */	BIG5_LATIN1,
	/* 0x21 */	BIG5_LATIN1,
	/* 0x22 */	BIG5_LATIN1,
	/* 0x23 */	BIG5_LATIN1,
	/* 0x24 */	BIG5_LATIN1,
	/* 0x25 */	BIG5_LATIN1,
	/* 0x26 */	BIG5_LATIN1,
	/* 0x27 */	BIG5_LATIN1,
	/* 0x28 */	BIG5_LATIN1,
	/* 0x29 */	BIG5_LATIN1,
	/* 0x2a */	BIG5_LATIN1,
	/* 0x2b */	BIG5_LATIN1,
	/* 0x2c */	BIG5_LATIN1,
	/* 0x2d */	BIG5_LATIN1,
	/* 0x2e */	BIG5_LATIN1,
	/* 0x2f */	BIG5_LATIN1,
	/* 0x30 */	BIG5_LATIN1,
	/* 0x31 */	BIG5_LATIN1,
	/* 0x32 */	BIG5_LATIN1,
	/* 0x33 */	BIG5_LATIN1,
	/* 0x34 */	BIG5_LATIN1,
	/* 0x35 */	BIG5_LATIN1,
	/* 0x36 */	BIG5_LATIN1,
	/* 0x37 */	BIG5_LATIN1,
	/* 0x38 */	BIG5_LATIN1,
	/* 0x39 */	BIG5_LATIN1,
	/* 0x3a */	BIG5_LATIN1,
	/* 0x3b */	BIG5_LATIN1,
	/* 0x3c */	BIG5_LATIN1,
	/* 0x3d */	BIG5_LATIN1,
	/* 0x3e */	BIG5_LATIN1,
	/* 0x3f */	BIG5_LATIN1,
	/* 0x40 */	BIG5_LATIN1,
	/* 0x41 */	BIG5_LATIN1,
	/* 0x42 */	BIG5_LATIN1,
	/* 0x43 */	BIG5_LATIN1,
	/* 0x44 */	BIG5_LATIN1,
	/* 0x45 */	BIG5_LATIN1,
	/* 0x46 */	BIG5_LATIN1,
	/* 0x47 */	BIG5_LATIN1,
	/* 0x48 */	BIG5_LATIN1,
	/* 0x49 */	BIG5_LATIN1,
	/* 0x4a */	BIG5_LATIN1,
	/* 0x4b */	BIG5_LATIN1,
	/* 0x4c */	BIG5_LATIN1,
	/* 0x4d */	BIG5_LATIN1,
	/* 0x4e */	BIG5_LATIN1,
	/* 0x4f */	BIG5_LATIN1,
	/* 0x50 */	BIG5_LATIN1,
	/* 0x51 */	BIG5_LATIN1,
	/* 0x52 */	BIG5_LATIN1,
	/* 0x53 */	BIG5_LATIN1,
	/* 0x54 */	BIG5_LATIN1,
	/* 0x55 */	BIG5_LATIN1,
	/* 0x56 */	BIG5_LATIN1,
	/* 0x57 */	BIG5_LATIN1,
	/* 0x58 */	BIG5_LATIN1,
	/* 0x59 */	BIG5_LATIN1,
	/* 0x5a */	BIG5_LATIN1,
	/* 0x5b */	BIG5_LATIN1,
	/* 0x5c */	BIG5_LATIN1,
	/* 0x5d */	BIG5_LATIN1,
	/* 0x5e */	BIG5_LATIN1,
	/* 0x5f */	BIG5_LATIN1,
	/* 0x60 */	BIG5_LATIN1,
	/* 0x61 */	BIG5_LATIN1,
	/* 0x62 */	BIG5_LATIN1,
	/* 0x63 */	BIG5_LATIN1,
	/* 0x64 */	BIG5_LATIN1,
	/* 0x65 */	BIG5_LATIN1,
	/* 0x66 */	BIG5_LATIN1,
	/* 0x67 */	BIG5_LATIN1,
	/* 0x68 */	BIG5_LATIN1,
	/* 0x69 */	BIG5_LATIN1,
	/* 0x6a */	BIG5_LATIN1,
	/* 0x6b */	BIG5_LATIN1,
	/* 0x6c */	BIG5_LATIN1,
	/* 0x6d */	BIG5_LATIN1,
	/* 0x6e */	BIG5_LATIN1,
	/* 0x6f */	BIG5_LATIN1,
	/* 0x70 */	BIG5_LATIN1,
	/* 0x71 */	BIG5_LATIN1,
	/* 0x72 */	BIG5_LATIN1,
	/* 0x73 */	BIG5_LATIN1,
	/* 0x74 */	BIG5_LATIN1,
	/* 0x75 */	BIG5_LATIN1,
	/* 0x76 */	BIG5_LATIN1,
	/* 0x77 */	BIG5_LATIN1,
	/* 0x78 */	BIG5_LATIN1,
	/* 0x79 */	BIG5_LATIN1,
	/* 0x7a */	BIG5_LATIN1,
	/* 0x7b */	BIG5_LATIN1,
	/* 0x7c */	BIG5_LATIN1,
	/* 0x7d */	BIG5_LATIN1,
	/* 0x7e */	BIG5_LATIN1,
	/* 0x7f */	BIG5_LATIN1,
	/* 0x80 */	BIG5_LATIN1,
	/* 0x81 */	BIG5_LATIN1,
	/* 0x82 */	BIG5_LATIN1,
	/* 0x83 */	BIG5_LATIN1,
	/* 0x84 */	BIG5_LATIN1,
	/* 0x85 */	BIG5_LATIN1,
	/* 0x86 */	BIG5_LATIN1,
	/* 0x87 */	BIG5_LATIN1,
	/* 0x88 */	BIG5_LATIN1,
	/* 0x89 */	BIG5_LATIN1,
	/* 0x8a */	BIG5_LATIN1,
	/* 0x8b */	BIG5_LATIN1,
	/* 0x8c */	BIG5_LATIN1,
	/* 0x8d */	BIG5_LATIN1,
	/* 0x8e */	BIG5_LATIN1,
	/* 0x8f */	BIG5_LATIN1,
	/* 0x90 */	BIG5_LATIN1,
	/* 0x91 */	BIG5_LATIN1,
	/* 0x92 */	BIG5_LATIN1,
	/* 0x93 */	BIG5_LATIN1,
	/* 0x94 */	BIG5_LATIN1,
	/* 0x95 */	BIG5_LATIN1,
	/* 0x96 */	BIG5_LATIN1,
	/* 0x97 */	BIG5_LATIN1,
	/* 0x98 */	BIG5_LATIN1,
	/* 0x99 */	BIG5_LATIN1,
	/* 0x9a */	BIG5_LATIN1,
	/* 0x9b */	BIG5_LATIN1,
	/* 0x9c */	BIG5_LATIN1,
	/* 0x9d */	BIG5_LATIN1,
	/* 0x9e */	BIG5_LATIN1,
	/* 0x9f */	BIG5_LATIN1,
	/* 0xa0 */	BIG5_LATIN1,
	/* 0xa1 */	BIG5_BIG5,
	/* 0xa2 */	BIG5_BIG5,
	/* 0xa3 */	BIG5_BIG5,
	/* 0xa4 */	BIG5_BIG5,
	/* 0xa5 */	BIG5_BIG5,
	/* 0xa6 */	BIG5_BIG5,
	/* 0xa7 */	BIG5_BIG5,
	/* 0xa8 */	BIG5_BIG5,
	/* 0xa9 */	BIG5_BIG5,
	/* 0xaa */	BIG5_BIG5,
	/* 0xab */	BIG5_BIG5,
	/* 0xac */	BIG5_BIG5,
	/* 0xad */	BIG5_BIG5,
	/* 0xae */	BIG5_BIG5,
	/* 0xaf */	BIG5_BIG5,
	/* 0xb0 */	BIG5_BIG5,
	/* 0xb1 */	BIG5_BIG5,
	/* 0xb2 */	BIG5_BIG5,
	/* 0xb3 */	BIG5_BIG5,
	/* 0xb4 */	BIG5_BIG5,
	/* 0xb5 */	BIG5_BIG5,
	/* 0xb6 */	BIG5_BIG5,
	/* 0xb7 */	BIG5_BIG5,
	/* 0xb8 */	BIG5_BIG5,
	/* 0xb9 */	BIG5_BIG5,
	/* 0xba */	BIG5_BIG5,
	/* 0xbb */	BIG5_BIG5,
	/* 0xbc */	BIG5_BIG5,
	/* 0xbd */	BIG5_BIG5,
	/* 0xbe */	BIG5_BIG5,
	/* 0xbf */	BIG5_BIG5,
	/* 0xc0 */	BIG5_BIG5,
	/* 0xc1 */	BIG5_BIG5,
	/* 0xc2 */	BIG5_BIG5,
	/* 0xc3 */	BIG5_BIG5,
	/* 0xc4 */	BIG5_BIG5,
	/* 0xc5 */	BIG5_BIG5,
	/* 0xc6 */	BIG5_BIG5,
	/* 0xc7 */	BIG5_BIG5,
	/* 0xc8 */	BIG5_BIG5,
	/* 0xc9 */	BIG5_BIG5,
	/* 0xca */	BIG5_BIG5,
	/* 0xcb */	BIG5_BIG5,
	/* 0xcc */	BIG5_BIG5,
	/* 0xcd */	BIG5_BIG5,
	/* 0xce */	BIG5_BIG5,
	/* 0xcf */	BIG5_BIG5,
	/* 0xd0 */	BIG5_BIG5,
	/* 0xd1 */	BIG5_BIG5,
	/* 0xd2 */	BIG5_BIG5,
	/* 0xd3 */	BIG5_BIG5,
	/* 0xd4 */	BIG5_BIG5,
	/* 0xd5 */	BIG5_BIG5,
	/* 0xd6 */	BIG5_BIG5,
	/* 0xd7 */	BIG5_BIG5,
	/* 0xd8 */	BIG5_BIG5,
	/* 0xd9 */	BIG5_BIG5,
	/* 0xda */	BIG5_BIG5,
	/* 0xdb */	BIG5_BIG5,
	/* 0xdc */	BIG5_BIG5,
	/* 0xdd */	BIG5_BIG5,
	/* 0xde */	BIG5_BIG5,
	/* 0xdf */	BIG5_BIG5,
	/* 0xe0 */	BIG5_BIG5,
	/* 0xe1 */	BIG5_BIG5,
	/* 0xe2 */	BIG5_BIG5,
	/* 0xe3 */	BIG5_BIG5,
	/* 0xe4 */	BIG5_BIG5,
	/* 0xe5 */	BIG5_BIG5,
	/* 0xe6 */	BIG5_BIG5,
	/* 0xe7 */	BIG5_BIG5,
	/* 0xe8 */	BIG5_BIG5,
	/* 0xe9 */	BIG5_BIG5,
	/* 0xea */	BIG5_BIG5,
	/* 0xeb */	BIG5_BIG5,
	/* 0xec */	BIG5_BIG5,
	/* 0xed */	BIG5_BIG5,
	/* 0xee */	BIG5_BIG5,
	/* 0xef */	BIG5_BIG5,
	/* 0xf0 */	BIG5_BIG5,
	/* 0xf1 */	BIG5_BIG5,
	/* 0xf2 */	BIG5_BIG5,
	/* 0xf3 */	BIG5_BIG5,
	/* 0xf4 */	BIG5_BIG5,
	/* 0xf5 */	BIG5_BIG5,
	/* 0xf6 */	BIG5_BIG5,
	/* 0xf7 */	BIG5_BIG5,
	/* 0xf8 */	BIG5_BIG5,
	/* 0xf9 */	BIG5_BIG5,
	/* 0xfa */	BIG5_BIG5,
	/* 0xfb */	BIG5_BIG5,
	/* 0xfc */	BIG5_BIG5,
	/* 0xfd */	BIG5_BIG5,
	/* 0xfe */	BIG5_BIG5,
	/* 0xff */	BIG5_LATIN1,
};


static XP_Bool
fe_AreBIG5FontsAvail(int16 win_csid)
{
	/* this needs to match the code in fe_LoadBIG5Font */
	if (fe_FontCharSets[CS_X_BIG5 & 0xff].name == NULL)
		return FALSE;
	else
		return TRUE;
}

static fe_Font
fe_LoadBIG5Font(MWContext *context, char *familyName, int points,
                int sizeNum, int fontmask, int charset, int pitch,
                int faceNum, Display *dpy)
{
	int16			cs;
	int			len;
	fe_FontGroupFont	*ret;

	len = (2 * sizeof(fe_FontGroupFont));
	ret = calloc(1, len);
	if (!ret)
	{
		return NULL;
	}
	(void) memset(ret, 0, len);

	cs = CS_LATIN1;
	ret[0].xFont = (XFontStruct *)
            fe_LoadFont(context, &cs, familyName, points, sizeNum, fontmask);
	if (cs != CS_LATIN1)
	{
		XP_FREE(ret);
		return NULL;
	}

	/* this needs to match the code in fe_AreBIG5FontsAvail */
	cs = CS_X_BIG5;
	ret[1].xFont = (XFontStruct *)
            fe_LoadFont(context, &cs, familyName, points, sizeNum, fontmask);
	if (cs == CS_X_BIG5)
	{
		ret[1].mask1 = 0xff;
		ret[1].mask2 = 0xff;
	}
	else
	{
		XP_FREE(ret);
		return NULL;
	}

	return (fe_Font) ret;
}

static XmString 
fe_BIG5ToXmString(int16 charset, fe_Font fontGroup, char * string, int len)
{
     return fe_EUCToXmString(charset, fontGroup, string, len, BIG5Table);
}

static void
fe_BIG5TextExtents(fe_Font font, char *string, int len, int *direction,
	int *fontAscent, int *fontDescent, XCharStruct *overall)
{
	fe_ProcessEUCString(CS_BIG5, BIG5Table, 
		NULL,
		NULL,
		NULL, None, font, NULL, 0, 0, string, len,
		fontAscent, fontDescent, overall,
		fe_CharSetFuncsArray[FE_FONT_INFO_BIG5].numberOfFonts);
}


static void
fe_DrawBIG5String(Display *dpy, Drawable d, fe_Font font, GC gc, int x,
	int y, char *string, int len)
{
	fe_ProcessEUCString(CS_BIG5, BIG5Table, 
		(fe_XDrawStringFunc) XDrawString,
		(fe_XDrawStringFunc) XDrawString16,
		dpy, d, font, gc, x, y, string, len,
		NULL, NULL, NULL,
		0);
}


static void
fe_DrawBIG5ImageString(Display *dpy, Drawable d, fe_Font font, GC gc, GC gc2,
	int x, int y, char *string, int len)
{
	fe_ProcessEUCString(CS_BIG5, BIG5Table, 
		(fe_XDrawStringFunc) XDrawImageString,
		(fe_XDrawStringFunc) XDrawImageString16,
		dpy, d, font, gc, x, y, string, len,
		NULL, NULL, NULL,
		0);
}

int 
fe_UnicodePointToPixelSize(Display *dpy, int pointSize)
{
	int pixelSize;
	static double pointToPixelFactor;
	static XP_Bool inited = FALSE;
    char name[512], class[512];
    char *type;
    XrmValue value;

	if (!inited) {
		inited = TRUE;
		pointToPixelFactor = ((WidthOfScreen(DefaultScreenOfDisplay(dpy)) /
                (WidthMMOfScreen(DefaultScreenOfDisplay(dpy)) / 25.4)) /
				72.27) / 10;

        /*
         * Get the users resource setting
         */
        (void) PR_snprintf(name, sizeof(name), "%s.unicodeFont.screenDpi", 
                        fe_progclass);
        (void) PR_snprintf(class, sizeof(class),"%s.UnicodeFont.ScreenDpi",
                        fe_progclass);
        if (XrmGetResource(XtDatabase(dpy), name, class, &type, &value)){
			float userScreenDpi;
			if (sscanf((char *)value.addr, "%e", &userScreenDpi)) {
				pointToPixelFactor = (userScreenDpi/72.27) / 10;
			}
        }
	}
	pointSize += 4; /* round up */
	pixelSize = (int)(pointSize * pointToPixelFactor);
	return pixelSize;
}

static XP_Bool
fe_AreUnicodeFontsAvail(int16 win_csid)
{
	/*
	 * since we build unicode fonts from other fonts
	 * there is not a good way to tell what will be
	 * avail so just assume we can do it
	 */
	return TRUE;
}

/*
 * fe_LoadUnicodeFont - load (create) a Unicode Pseudo Font
 *
 * see fe_loadUnicodePseudoFonts() for information on Unicode Pseudo Fonts
 *
 */
fe_Font
fe_LoadUnicodeFont(void *not_used, char *familyName,
                   int points, int sizeNum,
         int fontmask, int charset, int pitch, int faceNum,
         Display *dpy)
{
    fe_UnicodePseudoFont *ufont;
    fe_FontFamily *unicodeFamily = NULL;
    fe_FontSize *unicodeSize;
	int pixelSize;

	/*
	 * If the familyName is specified then find it
	 * else use the selected family
	 */
	if (familyName) {
        unicodeFamily = fe_FontFindFamily(CS_UTF8, pitch, familyName);
	}
	/*
	 * If the familyName is not specified or that family not found
	 * then use the selected family
	 */
	if (!unicodeFamily) {
        unicodeFamily = fe_GetFontFamily(CS_UTF8, pitch);
		familyName = unicodeFamily->family;
	}
    unicodeSize = unicodeFamily->htmlSizes[sizeNum-1];
	pixelSize = fe_UnicodePointToPixelSize(dpy, unicodeSize->size);
    ufont = fe_LoadUnicodeFontByPixelSize(not_used, familyName, 
    				pixelSize, fontmask, charset, pitch, faceNum, dpy);

    return ufont;
}

/*
 * fe_LoadUnicodeFontByPixelSize - load (create) a Unicode Pseudo Font
 *
 * see fe_loadUnicodePseudoFonts() for information on Unicode Pseudo Fonts
 *
 */
fe_Font
fe_LoadUnicodeFontByPixelSize(void *not_used, char *familyName, int pixelSize,
         int fontmask, int charset, int pitch, int faceNum,
         Display *dpy)
{
    fe_UnicodePseudoFont *ufont;

    ufont = (fe_UnicodePseudoFont*)calloc(1, sizeof(fe_UnicodePseudoFont));
    if (!ufont) {
        return NULL;
    }
    ufont->tag = UNICODE_PSEUDO_FONT_TAG;
    ufont->family = strdup(familyName);
    ufont->dpy = dpy;
    ufont->pixelSize = pixelSize;
    ufont->fontmask = fontmask;
    ufont->pitch = pitch;
    ufont->faceNum = faceNum;
    ufont->ascent = 0;
    ufont->descent = 0;

    return ufont;
}

static XmFontList
fe_UTF8GetFontList(int16 charset, fe_Font font, int numOfFonts)
{
     fe_UnicodePseudoFont *ufont = (fe_UnicodePseudoFont *)font;
     XP_ASSERT( NULL != ufont);
     XP_ASSERT( NULL != ufont->xmfontlist);
     return XmFontListCopy(ufont->xmfontlist);
}

static XmString fe_UTF8ToXmString(int16 charset, fe_Font fontGroup, char * string, int len)
{
     XP_ASSERT(0);
     return NULL; /* to make compiler happen */
}

void
fe_freeUnicodePseudoFont(fe_Font font)
{
    fe_UnicodePseudoFont *ufont = (fe_UnicodePseudoFont *)font;
	int i_encodings;

    if (ufont->tag != UNICODE_PSEUDO_FONT_TAG) {
#ifdef DEBUG_bstell
        printf("bad ufont %s %d\n", __FILE__, __LINE__);
#endif
        return;
    }

	if (ufont->family)
		free(ufont->family);
	/*
	 * Free any scaled fonts
	 */
    for (i_encodings=0; i_encodings<INTL_CHAR_SET_MAX; i_encodings++) {
        if (ufont->xfont_scaled[i_encodings]) {
            XFreeFont(ufont->dpy, ufont->xFonts[i_encodings]);
            XP_FREE(ufont->xfont_name[i_encodings]);
		}
    }
	if (ufont->xmfontlist)
		XmFontListFree(ufont->xmfontlist);
	if (ufont->xm_fontset)
		XmFontListFree(ufont->xm_fontset);
	if (ufont->xfontset) 
		XFreeFontSet(ufont->dpy, ufont->xfontset);
	free(ufont);
}

static char *
fe_UnicodeEquivFontName(fe_UnicodePseudoFont *ufont, uint16 charsetID)
{
    XrmDatabase db;
    char name[512], class[512];
    char *csid_name, *type;
    XrmValue value;

    charsetID &= 0xFF;

    if (ufont->fontFamily[charsetID&0xFF])
        return (ufont->fontFamily[charsetID]);

    db = XtDatabase(ufont->dpy);

    csid_name = INTL_CsidToCharsetNamePt(charsetID);
    (void) PR_snprintf(name, sizeof(name), "%s.unicodeFont.%s.%s", 
                        fe_progclass, ufont->family, csid_name);
    (void) PR_snprintf(class, sizeof(class), "%s.UnicodeFont.%s.%s", 
                        fe_progclass, ufont->family, "Name");
    if (XrmGetResource(db, name, class, &type, &value))
        ufont->fontFamily[charsetID] = strdup(value.addr);
    else
        ufont->fontFamily[charsetID] = strdup(ufont->family);
    return (ufont->fontFamily[charsetID]);
}

/*
 * Rate the  Quality of the font match
 *
 * a return range 0.0 to 1.0
 * 1.0 means perfect match
 * lower numbers mean poorer match
 */
static int
fe_UnicodeFontQ(fe_UnicodePseudoFont *ufont, 
				int32 target_height, int32 actual_height,
				XP_Bool family_match, XP_Bool weight_match, XP_Bool slant_match,
				int target_pitch, XP_Bool pitch_match
				)
{
	float q = 1.0;

	/*
	 * Look at size match
	 */
	if (actual_height <= target_height)
		q *= (float)actual_height / (float)target_height;
	else
		q *= (float)target_height / (float)actual_height;

	/*
	 * Look at family match (correct font family)
	 */
	if (!family_match)
		q *= 0.8;
#ifdef DEBUG_bstell
	else
		q *= 1.0;
#endif

	/*
	 * Look at weight match (regular vs bold)
	 */
	if (!weight_match)
		q *= 0.75;

	/*
	 * Look at slant match (regular vs italic)
	 */
	if (!slant_match)
		q *= 0.5;

	/*
	 * Look at pitch match (monospaced vs proportional)
	 *
	 * Pitch doesn't mean much to most users but:
	 *    many (older) applications assume a monospaced font 
	 *    and won't work correctly with a proportional font 
	 * Hence if the target font is monospaced
	 *    we strongly want the pitch to be right
	 */
	if (!pitch_match) {
		if (target_pitch == 0) /* proportional */
			q *= 0.8;
		else /* MONO */
			q *= 0.0;
	}

	return (int)(q * 100);
}

#define IS_ORIG_PITCH(pitch) ((pitch)==0)
#define IS_ORIG_WEIGHT_FACE(face)   (((face)&1)==0)
#define IS_ORIG_SLANT_FACE(face)  (((face)&2)==0)

/*
 * fe_UnicodeFindFontInRange
 *
 * find the font for this encoding with the UnicodePseudoFont's 
 *   specified font name / slant / weight
 *   no scaling
 *   size range = minPixelSize to maxPixelSize
 *   either pitch
 */
static XFontStruct *
fe_UnicodeFindFontInRange(fe_UnicodePseudoFont *ufont, uint16 charsetID,
                    int32 maxPixelSize, int32 minPixelSize, XP_Bool any_weight,
					char **name)
{
    int pitch, i_pitch, i_pnt;
    fe_FontSize *size;
    fe_FontFamily *fontFamily;
    char *family;
	int bestFoundQ = 0;
	int thisFontQ;
	int bestFoundFaceNum;
    fe_FontSize *bestFoundSize = NULL;

    /*
     * Get the equivalent font name for this encoding
     */
    family = fe_UnicodeEquivFontName(ufont, charsetID);

    /*
     * Find the font
     */
    for (i_pitch=0; i_pitch<2; i_pitch++) {
        if (IS_ORIG_PITCH(i_pitch))
            pitch = ufont->pitch;
        else
            pitch = FE_OPPOSITE_PITCH(ufont->pitch);
        fontFamily = fe_FontFindFamily(charsetID, pitch, family);
        if (fontFamily == NULL)
            continue;
        /* scan pixel sizes for largest size that is not too big */
        for (i_pnt=fontFamily->numberOfPixelSizes-1; i_pnt>=0; i_pnt--) {
            size = &fontFamily->pixelSizes[i_pnt];
            /* stop when sizes are too small */
            if (size->size<minPixelSize)
                break;
            if (size->size>=maxPixelSize) 
                ufont->larger_fonts_avail[charsetID] = TRUE;
            if ((size->size>=minPixelSize) && (size->size<=maxPixelSize)) {
				int i_face, faceNum;
				for (i_face=0; i_face<2; i_face++) {
					if (IS_ORIG_WEIGHT_FACE(i_face))
						faceNum = ufont->faceNum;
					else {
						if (!any_weight)
							continue;
						faceNum = FE_OPPOSITE_WEIGHT_FACE(ufont->faceNum);
					}
                	/* load font if necessary */
                	if (!size->faces[faceNum]) 
				   		continue;
					thisFontQ = fe_UnicodeFontQ(ufont, 
										maxPixelSize, size->size,
										/* family_match */
										TRUE,
										IS_ORIG_WEIGHT_FACE(i_face),
										TRUE,
										ufont->pitch, IS_ORIG_PITCH(i_pitch));
					if (thisFontQ > bestFoundQ) {
						bestFoundQ = thisFontQ;
						bestFoundSize = size;
						bestFoundFaceNum = faceNum;
					}
				}
            }
        }
    }
	if (bestFoundSize != NULL) {
        if (!bestFoundSize->faces[bestFoundFaceNum]->loaded) {
            bestFoundSize->faces[bestFoundFaceNum]->loaded = TRUE;
            bestFoundSize->faces[bestFoundFaceNum]->font = 
				fe_LoadXFont(ufont->dpy,
                      bestFoundSize->faces[bestFoundFaceNum]->longXLFDFontName);
        }
        if (bestFoundSize->faces[bestFoundFaceNum]->font) {
			*name = bestFoundSize->faces[bestFoundFaceNum]->longXLFDFontName;
            return bestFoundSize->faces[bestFoundFaceNum]->font;
		}
	}
	*name = "";
    return NULL;
}


/*
 * fe_UnicodeFindFontSloppy
 *
 * find the font for this encoding with the UnicodePseudoFont's 
 *   ANY FAMILY
 */
static XFontStruct *
fe_UnicodeFindFontSloppy(fe_UnicodePseudoFont *ufont, uint16 charsetID,
                          int32 maxPixelSize, int32 minPixelSize,
                          XP_Bool allow_scaling, 
			  XP_Bool any_weight, XP_Bool any_slant,
			  char **name)
{
    int i_family, i_pitch, i_pnt, i_face;
    fe_FontPitch *fontPitch;
    fe_FontSize *size = NULL;
    fe_FontFamily *fontFamily = NULL;
    fe_FontCharSet    *fontCharset;
    XFontStruct *scaled_font;
    fe_FontSize *bestFoundSize = NULL;
    fe_FontFamily *bestFontFamily = NULL;
	int bestFoundQ = 0;
	int thisFontQ;
	int bestFoundFaceNum = 0;
    fe_FontFamily *targetFontFamily;
    char *targetFamily;

	if (minPixelSize < 1)
		minPixelSize = 1;

    fontCharset = &fe_FontCharSets[charsetID];
    /*
     * Get the equivalent font name for this encoding
     */
    targetFamily = fe_UnicodeEquivFontName(ufont, charsetID);

    /*
     * Find the font
     */
    for (i_pitch=0; i_pitch<2; i_pitch++) {
        if IS_ORIG_PITCH(i_pitch) {
            fontPitch = &fontCharset->pitches[ufont->pitch];
    		targetFontFamily = fe_FontFindFamily(charsetID, 
										ufont->pitch, targetFamily);
		}
        else {
            fontPitch = &fontCharset->pitches[FE_OPPOSITE_PITCH(ufont->pitch)];
    		targetFontFamily = fe_FontFindFamily(charsetID, 
								FE_OPPOSITE_PITCH(ufont->pitch), targetFamily);
		}
        for (i_family = 0; i_family < fontPitch->numberOfFamilies; i_family++) {
            fontFamily = &fontPitch->families[i_family];
            for (i_pnt=fontFamily->numberOfPixelSizes-1; i_pnt>=0; i_pnt--) {
                size = &fontFamily->pixelSizes[i_pnt];
				if ((charsetID==CS_LATIN1) 
					&& (size->size) && (size->size < smallestFontFoundSize))
					smallestFontFoundSize = size->size;
                /* skip sizes that are too small */
                if ((size->size) && (size->size<minPixelSize))
                    continue;
                if (size->size>=maxPixelSize) 
                    ufont->larger_fonts_avail[charsetID] = TRUE;
                if (((size->size>=minPixelSize) && (size->size<=maxPixelSize))
                    || (allow_scaling && (size->size == 0))) {
					int32 target_size;
                    for (i_face=0; i_face<4; i_face++) {
                        int faceNum = ufont->faceNum;
                        if (!IS_ORIG_WEIGHT_FACE(i_face)) {
                            if (!any_weight)
                                continue;
                            faceNum = FE_OPPOSITE_WEIGHT_FACE(faceNum);
                        }
                        if (!IS_ORIG_SLANT_FACE(i_face)) {
                            if (!any_slant)
                                continue;
                            faceNum = FE_OPPOSITE_SLANT_FACE(faceNum);
                        }
                        if (!size->faces[faceNum])
							continue;
						if (size->size) /* not scaled */
							target_size = size->size;
						else
							target_size = maxPixelSize;
						thisFontQ = fe_UnicodeFontQ(ufont, 
										maxPixelSize, target_size,
										/* family_match */
										(targetFontFamily==fontFamily),
										IS_ORIG_WEIGHT_FACE(i_face),
										IS_ORIG_SLANT_FACE(i_face),
										ufont->pitch, IS_ORIG_PITCH(i_pitch));
						if (thisFontQ > bestFoundQ) {
							bestFoundQ = thisFontQ;
							bestFoundSize = size;
							bestFoundFaceNum = faceNum;
							bestFontFamily = fontFamily;
						}
                    }
                }
            }
        }
    }
	if (bestFoundSize != NULL) {
        /* load font if necessary */
        if (bestFoundSize->size) {
            if (!bestFoundSize->faces[bestFoundFaceNum]->loaded) {
                bestFoundSize->faces[bestFoundFaceNum]->loaded = TRUE;
                bestFoundSize->faces[bestFoundFaceNum]->font = 
							fe_LoadXFont(ufont->dpy, 
                    bestFoundSize->faces[bestFoundFaceNum]->longXLFDFontName);
            }
            if (bestFoundSize->faces[bestFoundFaceNum]->font)
				*name = bestFoundSize->faces[bestFoundFaceNum]->longXLFDFontName;
                return bestFoundSize->faces[bestFoundFaceNum]->font;
            }
        else if (allow_scaling) {
            *name = PR_smprintf(bestFontFamily->pixelSizes->faces[
                      bestFoundFaceNum]->longXLFDFontName, maxPixelSize);
            scaled_font = fe_LoadXFont(ufont->dpy, *name);
            if (scaled_font)
                return scaled_font;
			else
				XP_FREE(*name);
        }
	}

	*name = "";
    return NULL;
}

/*
 * fe_UnicodeFindFontScaled
 *
 * find the font for this encoding with the UnicodePseudoFont's 
 *   specified font name / slant / weight
 *   scaled font
 *   either pitch
 */
static XFontStruct *
fe_UnicodeFindFontScaled(fe_UnicodePseudoFont *ufont, uint16 charsetID,
                        int32 maxPixelSize, char **name)
{
    int pitch, i_pitch, i_face;
    char *family;
    fe_FontFamily *fontFamily;
    XFontStruct *scaled_font;
    fe_FontFamily *bestFontFamily = NULL;
	int bestFoundQ = 0;
	int thisFontQ;
	int bestFoundFaceNum = 0;

    /*
     * Get the equivalent font name for this encoding
     */
    family = fe_UnicodeEquivFontName(ufont, charsetID);
    for (i_pitch=0; i_pitch<2; i_pitch++) {
        if (IS_ORIG_PITCH(i_pitch))
            pitch = ufont->pitch;
        else
            pitch = FE_OPPOSITE_PITCH(ufont->pitch);
        fontFamily = fe_FontFindFamily(charsetID, pitch, family);
        if (fontFamily == NULL)
            continue;
        if (fontFamily->pixelSizes->size == 0)  {
			int faceNum;
			for (i_face=0; i_face<2; i_face++) {
				if (IS_ORIG_WEIGHT_FACE(i_face))
					faceNum = ufont->faceNum;
				else
					faceNum = FE_OPPOSITE_WEIGHT_FACE(ufont->faceNum);
				if (!fontFamily->pixelSizes->faces[faceNum])
					continue;
				thisFontQ = fe_UnicodeFontQ(ufont, 
										maxPixelSize, maxPixelSize,
										TRUE, /* family_match */
										IS_ORIG_WEIGHT_FACE(i_face),
										TRUE, /* slant_match */
										ufont->pitch, IS_ORIG_PITCH(i_pitch));
				if (thisFontQ > bestFoundQ) {
					bestFoundQ = thisFontQ;
					bestFoundFaceNum = faceNum;
					bestFontFamily = fontFamily;
				}
			}
        }
    }
	if (bestFontFamily != NULL) {
        *name = PR_smprintf(bestFontFamily->pixelSizes->faces[
                              bestFoundFaceNum]->longXLFDFontName,
                              maxPixelSize);
        scaled_font = fe_LoadXFont(ufont->dpy, *name);
        if (scaled_font)
            return scaled_font;
		else
			XP_FREE(*name);
	}
	*name = "";
    return NULL;
}

static XP_Bool
fe_UnicodeCheckAllowScaling(fe_UnicodePseudoFont *ufont)
{
    XP_Bool allow_scaling;
    fe_FontFamily *unicodeFamily;
    char *server_vendor;
    static XP_Bool inited_server_info = FALSE;
    static XP_Bool is_hp_server = FALSE;
    static XP_Bool allow_hp_scaling = FALSE;
    char name[512], class[512];
    char *type;
    XrmValue value;

    /*
     * When displaying on a HP system do not scale.
     *
     * HP scaling causes the X server to "freeze"
     * which makes the system unusable.
     * Mouse delays of 20+ seconds make it very 
     * difficult to even exit the application.
     */
    if (!inited_server_info) {
        inited_server_info = TRUE;
        server_vendor = ServerVendor(ufont->dpy);
        if (strstr(server_vendor, "Hewlett-Packard")) {
            is_hp_server = TRUE;
        }
        /*
         * Get the users resource setting
         */
        (void) PR_snprintf(name, sizeof(name), "%s.unicodeFont.allowHPScaling", 
                        fe_progclass);
        (void) PR_snprintf(class, sizeof(class),"%s.UnicodeFont.AllowHPScaling",
                        fe_progclass);
        if (XrmGetResource(XtDatabase(ufont->dpy), name, class, &type, &value)){
            char *string = (char *)value.addr;
            if ((string[0]=='y') || (string[0]=='Y')
                || (string[0]=='t') || (string[0]=='T')
                || (string[0]=='1'))
                allow_hp_scaling = TRUE;
            else
                allow_hp_scaling = FALSE;
        }
    }
    if ((is_hp_server) && (!allow_hp_scaling))
        return FALSE;

    unicodeFamily = fe_GetFontFamily(CS_UTF8, ufont->pitch);
    allow_scaling = unicodeFamily->allowScaling;
    return allow_scaling;
}

static XFontStruct *
fe_UnicodeFindFont(fe_UnicodePseudoFont *ufont, uint16 encoding, 
                                                       XP_Bool *is_scaled,
													   char **name)
{
    uint16 charsetID;
    fe_FontCharSet    *fontCharset;
    int loop_timeout;
    int32 maxPixelSize;
    XFontStruct *ret_font, *scaled_font = NULL;
    XP_Bool allow_scaling;

    /* printf("encoding = %d (%d), pixelSize = %d, pitch = %d, faceNum = %d\n",
                encoding, encoding&0xFF, ufont->pixelSize, 
                ufont->pitch, ufont->faceNum); */
    /*
     * Init return value
     */
    *is_scaled = FALSE;

    /*
     * Check the encoding
     */
    charsetID = encoding & 0xFF;
    fontCharset = &fe_FontCharSets[charsetID];
    if (!fontCharset->name) {
        return NULL;
    }

    maxPixelSize = ufont->pixelSize;
    allow_scaling = fe_UnicodeCheckAllowScaling(ufont);

    /*
     * Get the best font for this size and encoding
     *
     * We loop looking for a font that will fit
     *  The reason for the loop is that after we load the font it is
     *  possible that the ascent or descent is too large.
     *  If this happens we reduce the size by that amount and try again.
     *
     * The loop count is large because:
     *  If we can only find a bestfit that is small
     *  and this bestfit is still larger than the desired size
     *  then we end up running thru the loop while maxPixelSize is reduced
     *  to the pixel that bestfit is small enough.
     *  This tends to not be efficient since the bestfit font
     *  is only loaded once.
     */
#define LOOP_TIMEOUT 100
    scaled_font = NULL;
    for (loop_timeout=0; loop_timeout<LOOP_TIMEOUT; loop_timeout++) {
        if (scaled_font != NULL) {
            XFreeFont(ufont->dpy, scaled_font);
			XP_FREE(*name);
			*name = "";
            scaled_font = NULL;
        }

        /*
         * Exact Fit (non scaled)
         * try to find:
         * the family with this size range: 100% - 95%
         * no scaling
         * correct pitch/weight/slant
         * then try the other pitch
         */
        ret_font = fe_UnicodeFindFontInRange(ufont, charsetID, 
                                        maxPixelSize, 0.95*maxPixelSize, FALSE,
										name);
        if (ret_font) {
            loop_timeout += LOOP_TIMEOUT/10 - 1;
            goto UnicodeFindFont_foundOne;
        }

        /*
         * Exact Fit (scaled)
         * try to find:
         * the family with the SCALED SIZE
         * (X bitmap scaled fonts typically look bad)
         * correct slant
         * ANY PITCH / ANY WEIGHT
         */
        if (allow_scaling) {
            scaled_font = fe_UnicodeFindFontScaled(ufont, charsetID, 
                                                maxPixelSize, name);
            if (scaled_font) {
                loop_timeout += LOOP_TIMEOUT/5 - 1;
                ret_font = scaled_font;
                goto UnicodeFindFont_foundOne;
            }
        }
    
        /*
         * Close Fit (non scaled)
         * try to find:
         * the family with this size range: 100% - 75%
         * no scaling
         * correct slant
         * ANY_WEIGHT / ANY PITCH
         */
        ret_font = fe_UnicodeFindFontInRange(ufont, charsetID, 
                                        maxPixelSize, 0.75*maxPixelSize, TRUE,
										name);
        if (ret_font) {
            loop_timeout += LOOP_TIMEOUT/10 - 1;
            goto UnicodeFindFont_foundOne;
        }

        /*
         * Okay Fit (any family)
         * try to find:
         * size range: 100% - 75%
         * correct slant
         * ANY FAMILY / ANY WEIGHT / ANY PITCH
         */
        ret_font = fe_UnicodeFindFontSloppy(ufont, charsetID, 
                         maxPixelSize, 0.75*maxPixelSize, 
                         allow_scaling, TRUE, FALSE,
						 name);
        if (ret_font) {
            loop_timeout += LOOP_TIMEOUT/10 - 1;
            goto UnicodeFindFont_foundOne;
        }
    
        /*
         * Loose Fit (non scaled)
         * try to find:
         * size range: 100% - 50%
         * ANY FAMILY / ANY WEIGHT / ANY PITCH / ANY SLANT
         */
        ret_font = fe_UnicodeFindFontSloppy(ufont, charsetID, 
                                maxPixelSize, 0.50*maxPixelSize, 
                                allow_scaling, TRUE, TRUE,
								name);
        if (ret_font) {
            loop_timeout += LOOP_TIMEOUT/10 - 1;
            goto UnicodeFindFont_foundOne;
        }
    
        /*
         * Any fit
         * try to find:
         * ANY SIZE / ANY FAMILY / ANY WEIGHT / ANY PITCH / ANY SLANT
         */
        ret_font = fe_UnicodeFindFontSloppy(ufont, charsetID, 
                                maxPixelSize, 0.0*maxPixelSize,
                                allow_scaling, TRUE, TRUE,
								name);
        if (ret_font) {
            loop_timeout += LOOP_TIMEOUT/10 - 1;
            goto UnicodeFindFont_foundOne;
        }

		/* 
		 * HUM ..., 
		 * must not be a font small enough
		 * in desperation we give them a real small font.
		 */
        ret_font = fe_UnicodeFindFontSloppy(ufont, CS_LATIN1, 
								smallestFontFoundSize, 0.0*maxPixelSize,
                                allow_scaling, TRUE, TRUE,
								name);
        if (ret_font) {
            loop_timeout += LOOP_TIMEOUT/10 - 1;
            goto UnicodeFindFont_foundOne;
        }
    
        /*
         * Gave up trying to find a font that will fit
         */
        goto UnicodeFindFont_failed;


UnicodeFindFont_foundOne:
        /*
         * if encoding is CS_LATIN1 use the font
         * else check that the font will fit
         */
        if ((encoding==CS_LATIN1) && (ufont->ascent==0) && (ufont->descent==0)){
            if ((ufont->pixelSize/10) > (ret_font->ascent+ret_font->descent))
                ret_font->ascent = (ufont->pixelSize/10) - ret_font->descent;
            ufont->ascent  = ret_font->ascent;
            ufont->descent = ret_font->descent;
        }
        else {
            if (ret_font->ascent > ufont->ascent) {
                /* printf("ascent too big (%d), reduce by %d\n",
                        ufont->pixelSize, ret_font->ascent - ufont->ascent); */
                maxPixelSize -= (ret_font->ascent - ufont->ascent) * 10;
                if (maxPixelSize > 20) /* continue unless something wrong */
                    continue;
            }
            if (ret_font->descent > ufont->descent) {
                /* printf("descent too big (%d), reduce by %d\n",
                                    ret_font->descent - ufont->descent); */
                maxPixelSize -= (ret_font->descent - ufont->descent) * 10;
                if (maxPixelSize > 20) /* continue unless something wrong */
                    continue;
            }
        }
        if (scaled_font != NULL)
            *is_scaled = TRUE;
        return ret_font;
    }
UnicodeFindFont_failed:
    /*
     * did not find any fit
     */
    if (encoding == CS_LATIN1) {
        /* if we got here something is wrong with fonts */
        XFontStruct *xfont = (XFontStruct *)fe_FixedFont;
        ufont->ascent = xfont->ascent;
        ufont->descent = xfont->descent;
        return fe_FixedFont;
    }
    return NULL;
}

static XFontStruct *
fe_UnicodeInitXfont(fe_UnicodePseudoFont *ufont, uint16 encoding)
{
    XmFontListEntry flentry;
    uint16 charset = encoding&0xFF;

    if (ufont->tag != UNICODE_PSEUDO_FONT_TAG) {
#ifdef DEBUG_bstell
        printf("bad ufont %s %d\n", __FILE__, __LINE__);
#endif
                return fe_FixedFont; /* fallback */
    }

   /*
    * Time to load the font
    */
    ufont->xfont_inited[charset] = TRUE;
    ufont->xFonts[charset] = fe_UnicodeFindFont(ufont, encoding, 
									&ufont->xfont_scaled[charset],
									&ufont->xfont_name[charset]);
    /*
     * Add this font to the XmFontList
     */
    if (ufont->xFonts[charset]) {
        flentry = XmFontListEntryCreate(INTL_CsidToCharsetNamePt(encoding), 
                                       XmFONT_IS_FONT, ufont->xFonts[charset]);
        ufont->xmfontlist = XmFontListAppendEntry(ufont->xmfontlist, flentry);
        XmFontListEntryFree(&flentry);
    }
    return ufont->xFonts[charset];
}

XFontStruct *
fe_UnicodeGetXfont(fe_UnicodePseudoFont *ufont, uint16 encoding)
{
    uint16 charset = encoding&0xFF;

    if (ufont->tag != UNICODE_PSEUDO_FONT_TAG) {
#ifdef DEBUG_bstell
        printf("bad ufont %s %d\n", __FILE__, __LINE__);
#endif
                return fe_FixedFont; /* fallback */
    }

    /*
     * If the xfont is already there return it
     */
    if (ufont->xfont_inited[charset])
        return ufont->xFonts[charset];

    /*
     * Make sure CS_LATIN1 loaded so the
     * ascender/descender info is set
     */
    if (encoding != CS_LATIN1) {
        if (ufont->xfont_inited[CS_LATIN1] == FALSE)
                        fe_UnicodeInitXfont(ufont, CS_LATIN1);
    }

    /*
     * Load the font
     */
    fe_UnicodeInitXfont(ufont, encoding);
    return ufont->xFonts[charset];
}

XmFontList 
XUPF_GetXmFontList(fe_Font font)
{
    fe_UnicodePseudoFont *ufont = (fe_UnicodePseudoFont *)font;

    if ((ufont==NULL) || (ufont->tag != UNICODE_PSEUDO_FONT_TAG)) {
        return NULL;
    }
    return ufont->xmfontlist;
}

/*
 * create a XmFontList with one XFontSet for XmText widgets
 * since they can only handle a single locale.
 */
XmFontList 
XUPF_GetXmFontSet(fe_Font font)
{
    fe_UnicodePseudoFont *ufont = (fe_UnicodePseudoFont *)font;
	int16 *csidList;
	int i;
	char *fontNameList = NULL;
	char **missingCharSets;
	int missingCharSetCount;
	char *missingCharString;
	XmFontListEntry flentry;


	/* check for bad inputs */
    if ((ufont==NULL) || (ufont->tag != UNICODE_PSEUDO_FONT_TAG)) {
        return NULL;
    }

	/* if it has already been created just use it */
	if (ufont->xm_fontset)
		return ufont->xm_fontset;

   /*
	* get the list of charset we need
	*/
	csidList = INTL_GetXCharSetIDs(ufont->dpy);
	if (csidList == NULL)
		return NULL;

   /*
	* build the list of fontSet names
	*/
	for( i=0; csidList[i] != 0; i++ ) {
		char *fontName;
		char *newFontNameList;
		(void)fe_UnicodeGetXfont(ufont, csidList[i]);
		fontName = ufont->xfont_name[csidList[i]&0xff];

		if ((fontName==NULL) || (strlen(fontName)==0)) {
			continue;
		}
 
		if (fontNameList == NULL)
			newFontNameList = strdup(fontName);
		else
			newFontNameList = PR_smprintf("%s,\n%s", fontNameList, fontName);

		if (!newFontNameList) {
			continue;
		}
		if (fontNameList != NULL)
			free(fontNameList);
		fontNameList = newFontNameList;
	}
	free(csidList);

   /*
	* create the XFontSet
	*/
	ufont->xfontset = XCreateFontSet(ufont->dpy, fontNameList, &missingCharSets,
                          &missingCharSetCount, &missingCharString);

	flentry = XmFontListEntryCreate(XmFONTLIST_DEFAULT_TAG, XmFONT_IS_FONTSET,
										ufont->xfontset);
	ufont->xm_fontset = XmFontListAppendEntry(NULL, flentry);
	XmFontListEntryFree(&flentry);
	return ufont->xm_fontset;

}

int
XUPF_JavaPointToPixelSize(Display *dpy, int pointSize)
{
	static XP_Bool inited = FALSE;
	static XP_Bool use_point_sizing;
	static double pointToPixelFactor = (72.27/72.27)/10;
    char name[512], class[512];
    char *type;
    XrmValue value;

	if (!inited) {
		inited = TRUE;
        /*
         * Get the users resource setting
         */
        (void) PR_snprintf(name, sizeof(name), "%s.javaFont.usePointSizing", 
                        fe_progclass);
        (void) PR_snprintf(class, sizeof(class),"%s.JavaFont.UsePointSizing",
                        fe_progclass);
        if (XrmGetResource(XtDatabase(dpy), name, class, &type, &value)){
            char *string = (char *)value.addr;
            if ((string[0]=='y') || (string[0]=='Y')
                || (string[0]=='t') || (string[0]=='T')
                || (string[0]=='1'))
                use_point_sizing = TRUE;
            else
                use_point_sizing = FALSE;
        }
        (void) PR_snprintf(name, sizeof(name), "%s.javaFont.screenDpi", 
                        fe_progclass);
        (void) PR_snprintf(class, sizeof(class),"%s.JavaFont.ScreenDpi",
                        fe_progclass);
        if (XrmGetResource(XtDatabase(dpy), name, class, &type, &value)){
			float userScreenDpi;
			if (sscanf((char *)value.addr, "%e", &userScreenDpi)) {
				pointToPixelFactor = (userScreenDpi/72.27)/10;
			}
        }
	}
	if (use_point_sizing)
		return (fe_UnicodePointToPixelSize(dpy, pointSize));
	else {
	    pointSize += 4; /* round up */
		return (int)(pointSize * pointToPixelFactor);
	}
}

void
fe_UnicodeConvertToPlaceHolder(fe_UnicodePseudoFont *ufont, 
                        int16 *encoding, XFontStruct **xfont,
                        unsigned char *segment, int seg_data_len)
{
	/* unsigned char c; */
	int i;

	/*
	 * Handle errors
	 */
#if 0
	if (*encoding == -1) /* not utf8 */
		c = '?';
	else if (!*xfont) /* only bigger fonts available */
		c = '?';
	else /* no font at all for this encoding */
		c = '?';
#endif /* 0 */
	for (i=0; i< seg_data_len; i++) {
		segment[i] = ((unsigned char) '?') /* c */;
	}
	*encoding = CS_LATIN1;
	*xfont = fe_UnicodeGetXfont(ufont, CS_LATIN1);
}

/*
 * fe_UTF8TextExtents - Get the Text Extents for a UTF8 Unicode string
 *
 * Parse the string into locally displayable encoded segments
 * and sum up the extents for the segments
 *
 * If there are errors dummy up some space for those characters
 * so we can display something.
 * hopefully the user will see the garbage and try a different encoding
 */
void
fe_UTF8TextExtents(fe_Font font, char *string, int len, int *direction,
    int *fontAscent, int *fontDescent, XCharStruct *overall)
{
    fe_UnicodePseudoFont *ufont = (fe_UnicodePseudoFont *)font;
    unsigned char segment[X11STRING_LIMIT*6];
    int16 encoding;
    int parsed_cnt = 0;
    int this_parsed_cnt, seg_data_len;
    int ascent, descent, this_direction;
    Dimension width;
    XFontStruct *xfont;
    XCharStruct this_overall;


    if ((ufont==NULL) || (ufont->tag != UNICODE_PSEUDO_FONT_TAG)) {
        /* something is wrong. I will just return a guess */
        overall->ascent = *fontAscent = 14;
        overall->descent = *fontDescent = 3;
        overall->lbearing = 0;
        overall->rbearing = 0;
        overall->width = len*9;
        return;
    }

    /*
     * initialize the values
     */
    *fontAscent = 0;
    *fontDescent = 0;
    overall->lbearing = 0;
    overall->rbearing = 0;
    overall->width = 0;
    overall->ascent = 0;
    overall->descent = 0;

    /*
     * Break up the unicode string into locally sizeable encoded segments
     */
    ascent = 0;
    descent = 0;
    width = 0;
    while (1) {
        /* get a single encoding string */
        this_parsed_cnt = utf8_to_local_encoding(string+parsed_cnt, 
                                        len-parsed_cnt, 
                                        segment, sizeof(segment),
                                        &seg_data_len, &encoding);
        if (this_parsed_cnt < 1) /* no more input data */
            break;

        /*
         * Get the font for this segment
         */
        if (encoding >= 0)
            xfont = fe_UnicodeGetXfont(ufont, encoding);
		else
			xfont = NULL;

		/*
		 * Handle errors
		 */
		if ((encoding < 0) || (!xfont)) {
            fe_UnicodeConvertToPlaceHolder(ufont, &encoding, &xfont,
                            segment, seg_data_len);
		}

        /*
         * Get the size metrics for this segment
         */
        if (IS_16BIT_ENCODING(encoding)) {
            XTextExtents16(xfont, (XChar2b*)segment, seg_data_len/2,
                &this_direction, &ascent, &descent, &this_overall);
        }
        else {
            XTextExtents(xfont, segment, seg_data_len,
                &this_direction, &ascent, &descent, &this_overall);
        }

        /*
         * sum up the width so far
         * height (ascent/descent) comes from the theoritical size
         */
        parsed_cnt += this_parsed_cnt;
        *direction = this_direction; /* which segment should I use ? */
        if ((this_overall.lbearing+overall->width) < overall->lbearing)
            overall->lbearing = this_overall.lbearing + overall->width;
        overall->width += this_overall.width;
        overall->rbearing += this_overall.rbearing;
    }

    /*
     * Set the height from the theoritical size
     */
    *fontAscent  = ufont->ascent;
    *fontDescent = ufont->descent + 1;
    overall->ascent = ufont->ascent;
    overall->descent = ufont->descent + 1;
}


static void
fe_DisplayUTF8String(XP_Bool imageString, Display *dpy, Drawable d, 
              fe_Font font, GC gc, GC gc2, int x, int y, char *string, int len)
{
    fe_UnicodePseudoFont *ufont = (fe_UnicodePseudoFont *)font;
    unsigned char segment[X11STRING_LIMIT*6];
    int parsed_cnt = 0;
    int16 encoding, charset;
    int this_parsed_cnt, seg_data_len;
    int ascent, descent, this_direction;
    XCharStruct this_overall;
    XFontStruct *xfont;

    if ((ufont==NULL) || (ufont->tag != UNICODE_PSEUDO_FONT_TAG)) {
        return;
    }
    if (!gc) {
        return;
    }
    while (1) {
        /*
         * get a single encoding string
         */
        this_parsed_cnt = utf8_to_local_encoding(string+parsed_cnt, 
                                        len-parsed_cnt, 
                                        segment, sizeof(segment),
                                        &seg_data_len, &encoding);
        if (this_parsed_cnt < 1)
            break;

        parsed_cnt += this_parsed_cnt;

        /*
         * Set the font for this encoding
         */
        if (encoding>0)
            xfont = fe_UnicodeGetXfont(ufont, encoding);
		else
			xfont = NULL;

		/*
		 * Handle errors
		 */
		if ((encoding < 0) || (!xfont)) {
            fe_UnicodeConvertToPlaceHolder(ufont, &encoding, &xfont,
                            segment, seg_data_len);
		}

        if (IS_16BIT_ENCODING(encoding))
            seg_data_len /= 2;
        XSetFont(dpy, gc, xfont->fid);
        charset = encoding &0xFF;
        if (IS_16BIT_ENCODING(encoding)) {
            /* get the real base line / descent */
            XTextExtents16(ufont->xFonts[charset], (XChar2b*)segment, 
                seg_data_len, &this_direction, &ascent, &descent,
                &this_overall);
            if (imageString)
                XFillRectangle(dpy, d, gc2, x, y-ufont->ascent, 
                        this_overall.width, ufont->ascent+ufont->descent);
            XDrawString16(dpy, d, gc, x, y, (XChar2b*)segment,seg_data_len);
        }
        else {
            XTextExtents(ufont->xFonts[charset], segment, seg_data_len,
                        &this_direction, &ascent, &descent, &this_overall);
            if (imageString)
                XFillRectangle(dpy, d, gc2, x, y-ufont->ascent, 
                        this_overall.width, ufont->ascent+ufont->descent);
            XDrawString(dpy, d, gc, x, y, segment, seg_data_len);
        }
        x += this_overall.width;
    }
}


void
fe_DrawUTF8String(Display *dpy, Drawable d, fe_Font font, GC gc, int x,
    int y, char *string, int len)
{
    fe_DisplayUTF8String(FALSE, dpy, d, font, gc, NULL, x, y, string, len);
}

static void
fe_DrawUTF8StringImage(Display *dpy, Drawable d, fe_Font font, GC gc, GC gc2,
    int x, int y, char *string, int len)
{
    fe_DisplayUTF8String(TRUE, dpy, d, font, gc, gc2, x, y, string, len);
}

int
fe_DrawUCS2String(Display *dpy, Drawable d, fe_Font font, GC gc, int x,
    int y, uint16 *string, int len)
{
    unsigned char *utf8p;
    int fontAscent, fontDescent, direction; 
    XCharStruct overall;
 
   /*
    * Convert from UCS2 to UTF8
    */
    utf8p = INTL_UCS2ToUTF8(string, len);
    if (utf8p == NULL) {
        return -1;
    }
    fe_DisplayUTF8String(FALSE, dpy, d, font, gc, NULL, x, y, 
						utf8p, strlen(utf8p));
    fe_UTF8TextExtents(font, utf8p, strlen(utf8p), &direction,
                            &fontAscent, &fontDescent, &overall);
    free(utf8p);
    return overall.width;
}

void
fe_UCS2TextExtents(fe_Font font, uint16 *string, int len, int *direction, 
    			int *fontAscent, int *fontDescent, XCharStruct *overall)
{
    unsigned char *utf8p;
 
   /*
    * Convert from UCS2 to UTF8
    */
    utf8p = INTL_UCS2ToUTF8(string, len);
    if (utf8p == NULL) {
	*direction = 0;
	*fontAscent = 0;
	*fontDescent = 0;
    	overall->width = 0;
        return;
    }
    fe_UTF8TextExtents(font, utf8p, strlen(utf8p), direction,
                            fontAscent, fontDescent, overall);
    free(utf8p);
}


XmString
XUPF_UCS2ToXmString(uint16 *uniChars, int32 length, fe_Font font, 
						XmFontList *fontList)
{
	fe_UnicodePseudoFont *ufont = (fe_UnicodePseudoFont *)font;
    unsigned char *utf8p;
	XmString xmstring;
 
	if ((ufont==NULL) || (ufont->tag != UNICODE_PSEUDO_FONT_TAG)) {
		/* something is wrong. */
		return NULL;
	}
   /*
    * Convert from UCS2 to UTF8
    */
    if (length) {
		utf8p = INTL_UCS2ToUTF8(uniChars, length);
    	if (utf8p == NULL) {
        	return NULL;
    	}
	}
	else
		utf8p = XP_STRDUP("");
	xmstring = fe_utf8_to_XmString(ufont, utf8p, strlen(utf8p), fontList);
    free(utf8p);
	return xmstring;
}

fe_Font
XUPF_LoadDefaultFont(Display *dpy)
{
    fe_UnicodePseudoFont *ufont;

	ufont = fe_LoadUnicodeFont(NULL, "helvetica", 0, 4, 0, CS_LATIN1,
                                   0, 0, dpy);
	return ufont;
}

/*
 * fe_utf8_to_XmString - Convert a utf8 string to a XmString
 *
 * Parse the utf8 string into locally displayable encoded segments
 * and add each segment onto a XmString
 *
 * If there are errors display something.
 * hopefully the user will see the garbage and try a different encoding
 */
XmString
fe_utf8_to_XmString(fe_Font font, char *string, int len, XmFontList *fontList)
{
	fe_UnicodePseudoFont *ufont = (fe_UnicodePseudoFont *)font;
	unsigned char segment[X11STRING_LIMIT*6];
	int16 encoding;
	char *encoding_name;
	int parsed_cnt = 0;
	int this_parsed_cnt, seg_data_len;
	XmString xm_string = NULL;
	XmString this_xm_seg, old_xm_string;
	XFontStruct *xfont;


	if ((ufont==NULL) || (ufont->tag != UNICODE_PSEUDO_FONT_TAG)) {
		/* something is wrong. I will just return a guess */
		return NULL;
	}

	/*
	 * Break up the unicode string into locally sizeable encoded segments
	 */
	while (1) {
		/* get a single encoding string */
		this_parsed_cnt = utf8_to_local_encoding(string+parsed_cnt, 
										len-parsed_cnt, 
										segment, sizeof(segment),
										&seg_data_len, &encoding);
		if (this_parsed_cnt < 1) /* no more input data */
			break;

		parsed_cnt += this_parsed_cnt;

		/*
		 * Get update the XmFontList
		 */
		if (encoding >= 0)
			xfont = fe_UnicodeGetXfont(ufont, encoding);
		else
			xfont = NULL;

		/*
		 * Handle errors
		 */
		if ((encoding < 0) || (!xfont)) {
            fe_UnicodeConvertToPlaceHolder(ufont, &encoding, &xfont,
                            segment, seg_data_len);
		}

		/*
		* Add this component to the XmString
		*/
		encoding_name = INTL_CsidToCharsetNamePt(encoding);
		this_xm_seg = XmStringCreateLtoR(segment, encoding_name);
		if (xm_string) {
			old_xm_string = xm_string;
			xm_string = XmStringConcat(old_xm_string, this_xm_seg);
			XmStringFree(old_xm_string);
			XmStringFree(this_xm_seg);
		}
		else
			xm_string = this_xm_seg;
	}

	/*
	 * handle empty string
	 */
	if (xm_string==NULL) {
		(void)fe_UnicodeGetXfont(ufont, CS_LATIN1);
		xm_string = XmStringCreateSimple("");
	}

	*fontList = ufont->xmfontlist;
	return xm_string;
}

/********************************************************************
  New Code
 ********************************************************************/
/*
 * these values can be changed to whatever is convenient for Java
 */
enum
{
	INTL_FontStyleNormal,
	INTL_FontStyleBold,
	INTL_FontStyleItalic,
	INTL_FontStyleBoldItalic
};


static XFontStruct *
intl_GetFontFace(Display *display, int sizeNum, fe_FontSize *size, int faceNum,
	char **fontName)
{
	fe_FontFace	*face;
	int		i;
	char		*name;
	XFontStruct	*ret;

	for (i = 0; i < 2; i++, faceNum = 0)
	{
		face = size->faces[faceNum];
		if (!face)
		{
			continue;
		}
		if (face->font)
		{
			if (fontName)
			{
				if (size->size)
				{
					*fontName =
						strdup(face->longXLFDFontName);
				}
				else
				{
					*fontName = PR_smprintf(
						face->longXLFDFontName,
						sizeNum);
				}
			}
			return face->font;
		}
		else
		{
			if (size->size)
			{
				name = strdup(face->longXLFDFontName);
			}
			else
			{
				name = PR_smprintf(face->longXLFDFontName,
					sizeNum);
			}
			if (!name)
			{
				return NULL;
			}
			ret = fe_LoadXFont(display, name);
			if (ret)
			{
				face->font = ret;
				if (fontName)
				{
					*fontName = name;
				}
				return ret;
			}
		}
	}

	return NULL;
}


static XFontStruct *
intl_GetFontSize(Display *display, fe_FontFamily *family, int sizeNum,
	int faceNum, char **fontName)
{
	int		closestSize = 0;
	int		firstSize;
	int		i;
	double		minDist;
	double		newDist;
	XFontStruct	*ret;
	fe_FontSize	*size;

	if (!family->pixelSizes)
	{
		return NULL;
	}

	if (family->pixelSizes->size)
	{
		firstSize = 0;
	}
	else
	{
		if (family->numberOfPixelSizes == 1)
		{
			return intl_GetFontFace(display, sizeNum,
				family->pixelSizes, faceNum, fontName);
		}
		firstSize = 1;
	}

	minDist = (1E+36);
	for (i = firstSize; i < family->numberOfPixelSizes; i++)
	{
		size = &family->pixelSizes[i];
		newDist = ((sizeNum - size->size) * (sizeNum - size->size));
		if (newDist < minDist)
		{
			minDist = newDist;
			closestSize = i;
		}
		else
		{
			break;
		}
	}

	for (i = 0; i < family->numberOfPixelSizes; i++)
	{
		if (closestSize - i >= firstSize)
		{
			size = &family->pixelSizes[closestSize - i];
			ret = intl_GetFontFace(display, size->size, size,
				faceNum, fontName);
			if (ret)
			{
				return ret;
			}
		}
		if (closestSize + i < family->numberOfPixelSizes)
		{
			size = &family->pixelSizes[closestSize + i];
			ret = intl_GetFontFace(display, size->size, size,
				faceNum, fontName);
			if (ret)
			{
				return ret;
			}
		}
	}

	if (!family->pixelSizes->size)
	{
		return intl_GetFontFace(display, sizeNum, family->pixelSizes,
			faceNum, fontName);
	}

	return NULL;
}


XFontStruct *
intl_GetFont(Display *display, int16 characterSet, char *familyName,
	char *foundry, int sizeNum, int style, char **fontName)
{
	fe_FontCharSet	*charset;
	int		faceNum;
	fe_FontFamily	*family = NULL;
	int		i;
	int		j;
	fe_FontPitch	*pitch;
	XFontStruct	*ret;


	/*
	 * check the charset
	 */
        characterSet &= 0x00ff;
	if ((0 > characterSet) || (characterSet >= INTL_CHAR_SET_MAX))
	{
		return NULL;
	}
	if (fe_CharSetInfoArray[characterSet].type == FE_FONT_TYPE_GROUP)
	{
		return NULL;
	}
	if (!fe_FontCharSets[characterSet].name)
	{
		return NULL;
	}


	/*
	 * check the family
	 */
	if (!familyName)
	{
		familyName = "";
	}


	/*
	 * check the foundry
	 */
	if (!foundry)
	{
		foundry = "";
	}


	/*
	 * check the size
	 */
	if (sizeNum <= 0)
	{
		return NULL;
	}


	/*
	 * check the style
	 */
	switch (style)
	{
	case INTL_FontStyleNormal:
		faceNum = 0;
		break;
	case INTL_FontStyleBold:
		faceNum = 1;
		break;
	case INTL_FontStyleItalic:
		faceNum = 2;
		break;
	case INTL_FontStyleBoldItalic:
		faceNum = 3;
		break;
	default:
		return NULL;
	}


	charset = &fe_FontCharSets[characterSet];

	/*
	 * iterate over the pitches (proportional and fixed)
	 * and for each pitch, look for the requested family and foundry
	 */
	for (i = 0; i < 2; i++)
	{
		pitch = &charset->pitches[i];
		for (j = 0; j < pitch->numberOfFamilies; j++)
		{
			family = &pitch->families[j];
			if ((!strcmp(family->family, familyName)) &&
				(!strcmp(family->foundry, foundry)))
			{
				ret = intl_GetFontSize(display, family,
					sizeNum, faceNum, fontName);
				if (ret)
				{
					return ret;
				}
			}
		}
	}

	/*
	 * couldn't find the requested family/foundry pair
	 * so try matching just the family
	 */
	for (i = 0; i < 2; i++)
	{
		pitch = &charset->pitches[i];
		for (j = 0; j < pitch->numberOfFamilies; j++)
		{
			family = &pitch->families[j];
			if (!strcmp(family->family, familyName))
			{
				ret = intl_GetFontSize(display, family,
					sizeNum, faceNum, fontName);
				if (ret)
				{
					return ret;
				}
			}
		}
	}

	/*
	 * couldn't find the requested family
	 * so let's try the one selected in the UI
	 */
	for (i = 0; i < 2; i++)
	{
		pitch = &charset->pitches[i];
		for (j = 0; j < pitch->numberOfFamilies; j++)
		{
			family = &pitch->families[j];
			if (family->selected)
			{
				break;
			}
			else
			{
				family = NULL;
			}
		}
		if (family)
		{
			ret = intl_GetFontSize(display, family, sizeNum,
				faceNum, fontName);
			if (ret)
			{
				return ret;
			}
		}
	}

	/*
	 * if we couldn't load the selected family
	 * we try all of the families in turn
	 */
	for (i = 0; i < 2; i++)
	{
		pitch = &charset->pitches[i];
		for (j = 0; j < pitch->numberOfFamilies; j++)
		{
			family = &pitch->families[j];
			ret = intl_GetFontSize(display, family, sizeNum,
				faceNum, fontName);
			if (ret)
			{
				return ret;
			}
		}
	}

	return NULL;
}


XFontStruct *
INTL_GetFont(Display *display, int16 characterSet, char *familyName,
	char *foundry, int sizeNum, int style)
{
	return intl_GetFont(display, characterSet, familyName, foundry,
		sizeNum, style, NULL);
}


static int16 *
INTL_GetXCharSetIDs(Display *dpy)
{
	unsigned char	*charset;
	int		len;
	int16		*p;
	int16		*ret;

	ret = NULL;

	if (!fe_LocaleCharSets)
	{
		fe_GetLocaleCharSets(dpy);
		if (!fe_LocaleCharSets)
		{
			ret = (int16 *) malloc(2 * sizeof(int16));
			if (!ret)
			{
				return NULL;
			}
			ret[0] = CS_LATIN1;
			ret[1] = 0;
			return ret;
		}
	}

	len = 0;
	charset = fe_LocaleCharSets;
	while (*charset)
	{
		len++;
		charset++;
	}

	ret = (int16 *) malloc((len + 1) * sizeof(int16));
	if (!ret)
	{
		return NULL;
	}

	p = ret;
	charset = fe_LocaleCharSets;
	while (*charset)
	{
		*p++ = fe_CharSetInfoArray[*charset++].charsetID;
	}
	*p = 0;

	return ret;
}


char *
INTL_GetXFontName(Display *display, int16 characterSet, char *familyName,
	char *foundry, int sizeNum, int style)
{
	char	*fontName;

	fontName = NULL;

	(void) intl_GetFont(display, characterSet, familyName, foundry,
		sizeNum, style, &fontName);

	return fontName;
}
