/*
 * xfont.c --
 *
 * Copyright (c) 1994 Software Research Associates, Inc. 
 * 
 */
 
#include "xlibInt.h" 

/*
 *----------------------------------------------------------------------
 * NameToLogFont
 *
 *	Converts a Windows style font name to a bunch of fields in the 
 *	LOGFONT structure
 *
 * Results:
 *	FALSE if unable to convert font, TRUE if a logical font was setup
 *----------------------------------------------------------------------
 */
static int
NameToLogFont(const char *name, LOGFONT *lplf)
{
    const char *pHead, *pTail, *lp;

    memset(lplf, '\0', sizeof(LOGFONT));


    pHead = name;
#ifdef KANJI
    pTail = (char *) _mbschr((const unsigned char *) pHead, '-');
    if (pTail == NULL) {
	return FALSE;
    }
    strncpy(lplf->lfFaceName, pHead, pTail - pHead);

    lplf->lfCharSet= ANSI_CHARSET;
    for (lp = pHead; lp != pTail; lp++) {
    	if (_ismbblead((unsigned char) *lp)) {
    	    lplf->lfCharSet= SHIFTJIS_CHARSET;
	    break;
	}
    }

    pHead = pTail + 1;

    pTail = (char *) _mbschr((const unsigned char *) pHead, '-');
    if (pTail == NULL) {
	return FALSE;
    }
#else
    pTail = strchr((const unsigned char *) pHead, '-');
    if (pTail == NULL) {
	return FALSE;
    }
    strncpy(lplf->lfFaceName, pHead, pTail - pHead);
    /* Need to handle Symbol and WingDings specially. */

    lplf->lfCharSet = ANSI_CHARSET;

    if (stricmp(lplf->lfFaceName, "Symbol") == 0) {
	lplf->lfCharSet = SYMBOL_CHARSET;
    } else if (stricmp(lplf->lfFaceName, "WingDings") == 0) {
	lplf->lfCharSet = SYMBOL_CHARSET;
    } /* Handle Dingbats? */

    pHead = pTail + 1;

    pTail = strchr((const unsigned char *) pHead, '-');
    if (pTail == NULL) {
	return FALSE;
    }
#endif
    /* Look for the weight */
    if (strstr(pHead, "Bold")) {
	lplf->lfWeight = FW_BOLD;
    } else if (strstr(pHead, "Normal")) {
	lplf->lfWeight = FW_NORMAL;
    } else if (strstr(pHead, "Medium")) {
	lplf->lfWeight = FW_MEDIUM;
    } else if (strstr(pHead, "Heavy")) {
	lplf->lfWeight = FW_HEAVY;
    } else if (strstr(pHead, "Thin")) {
	lplf->lfWeight = FW_THIN;
    } else if (strstr(pHead, "Extralight")) {
	lplf->lfWeight = FW_EXTRALIGHT;
    } else if (strstr(pHead, "Light")) {
	lplf->lfWeight = FW_LIGHT;
    } else if (strstr(pHead, "Semibold")) {
	lplf->lfWeight = FW_SEMIBOLD;
    } else if (strstr(pHead, "Extrabold")) {
	lplf->lfWeight = FW_EXTRABOLD;
    }

    /* Look for the style.  Possible styles: Italic, Oblique, and Roman */
    if (strstr(pHead, "Italic")) {
	lplf->lfItalic = 1;
    } else if (strstr(pHead, "Oblique")) {
	lplf->lfOrientation = 3600 - 150; /* 15 degree slant forward */
    }

    pHead = pTail + 1;    

    lplf->lfHeight = atoi(pHead);

    if (lplf->lfHeight <= 0) {
	return FALSE;
    }

    return TRUE;
}

/*
 *----------------------------------------------------------------------
 * XFontNameToLogFont
 *
 *	Converts an X style font name to a bunch of fields in the 
 *	LOGFONT structure.  This can handle both fully specified
 *	and wildcarded X font names.
 *
 * Results:
 *	FALSE if unable to convert font, TRUE if a logical font was setup
 *
 * Notes:
 *	J. Ousterhout once told me, "If the code is too complex, there
 *	must be an easier way."  Well, in this case, I'm absolutely positive
 *	there is an easier, more elegant way, but this horrible parser
 *	will deal with most wildcarded X fontnames.  It isn't perfect
 *	by a long shot, but if you give it a full 13 part name, you'll never
 *	have any trouble.
 *----------------------------------------------------------------------
 */
static int
XFontNameToLogFont(const char *name, LOGFONT *lplf)
{
#define TYPE_XNOTDONE	(-20)
#define TYPE_XINT	(-21)
#define TYPE_XSTRING	(-22)
#define TYPE_XSLANT	(-23)
#define TYPE_XWIDTH	(-24)
#define TYPE_XASTERISK	(-25)
#define TYPE_XQUESTION	(-26)
#define TYPE_XSPACING	(-27)
#define TYPE_XWEIGHT	(-28)
#define TYPE_XSETWIDTH	(-29)
#define TYPE_XNOTHING	(-30)

#define STOP_FLAG 0x8000
#define STOP_FLAG_MASK ~STOP_FLAG

    const char *pHead, *pTail;
    const char *pfield[15], *field[15];
    int plen[15], flen[15], ptype[15], ftype[15];
    int i, len, parsefields;

    /* For now, handle only wildcard free names.  Break up fontname into
     * the 15 different fields.  The first and last fields are left blank.
     * They are end conditions in the algorithm
     */
    pHead = pTail = name;

    if (*pTail == '-') {
	pHead++; pTail++;
    } else if (*pTail != '*') {
	return FALSE;
    }
    i = 1;
    while (*pTail != '\0' && i < 13) {
	if (*pTail == '-') {
	    plen[i] = pTail - pHead;
	    pfield[i] = pHead;
	    pTail++;
	    pHead = pTail;
	    i++;
	} else if (*pTail == '*') {
	    len = pTail - pHead;
	    if (len > 0) {
		plen[i] = pTail - pHead;
		pfield[i] = pHead;
	    } else {
		plen[i] = 1;
		pfield[i] = pHead;
		pTail++;
		if (*pTail == '-') {
		    pTail++;
		}
	    }
	    pHead = pTail;
	    i++;
	} else {
	    pTail++;
	}
    }

    if (*pTail != '\0') {
	i++;
	while (*pTail != '\0') {
	    pTail++;
	}
    }

    plen[i] = pTail - pHead;
    pfield[i] = pHead;

    parsefields = i;
    while (i < 14) {
	pfield[i] = pHead;
	plen[i] = 0;
	i++;
    }

    /* See if we have to do any pattern matching */
    if (parsefields > 14) {
	/* We have a problem. */
	return FALSE;
    } else if (parsefields == 14) {
	for (i = 1; i < 14; i++) {
	    field[i] = pfield[i];
	    flen[i] = plen[i];
	}
    } else if (parsefields < 14) {
	int j, k, nums = 0;
	int bNum;
	char c, d;
	int numDone, n, type1, type2, done, stop;

	for (i = 0; i < 15; i++) {
	    ftype[i] = TYPE_XNOTDONE;
	}

	numDone = 0;
	/* Break all the fields up in their possible types */
	ptype[0] = 0;
	numDone++;
	ptype[parsefields] = 14;
	numDone++;
	for (i = 1; i < parsefields; i++) {
	    ptype[i] = TYPE_XNOTHING;
	    if (plen[i] == 0) {
		if (i < parsefields) {
		    ptype[i] == TYPE_XQUESTION;
		}
		continue;
	    }
	    c = tolower(pfield[i][0]);
	    if (plen[i] == 1) {
		if (c == '*') {
		    ptype[i] = TYPE_XASTERISK;
		    continue;
		} else if (c == '?') {
		    ptype[i] = TYPE_XQUESTION;
		    continue;
		} else if (c == 'm' || c == 'p' || c == 'c') {
		    if (ftype[11] != TYPE_XNOTDONE) {
			return FALSE;
		    }
		    ftype[11] = i;
		    ptype[i] = 11;
		    numDone++;
		    continue;
		} else if (c == 'r' || c == 'i' || c == 'o') {
		    if (ftype[4] != TYPE_XNOTDONE) {
			return FALSE;
		    }
		    ftype[4] = i;
		    ptype[i] = 4;
		    numDone++;
		    continue;
		}
	    }

	    if (plen[i] == 2) {
		d = tolower(pfield[i][1]);
		if ((c == 'r' && d == 'i') ||
		    (c == 'r' && d == 'o') ||
		    (c == 'o' && d == 't'))
		{
		    if (ftype[4] != TYPE_XNOTDONE) {
			return FALSE;
		    }
		    ftype[4] = i;
		    ptype[i] = 4;
		    numDone++;
		    continue;
		}
	    }

	    bNum = TRUE;
	    for (j = 0; j < plen[i]; j++) {
		if (! isdigit(pfield[i][j])) {
		    bNum = FALSE;
		    break;
		}
	    }
	    if (bNum) {
		ptype[i] = TYPE_XINT;
		nums++;
		continue;
	    }

	    if (plen[i] == 4 && strnicmp(pfield[i], "bold", plen[i]) == 0) {
		if (ftype[3] != TYPE_XNOTDONE) {
		    return FALSE;
		}
		ftype[3] = i;
		ptype[i] = 3;
		numDone++;
		continue;
	    }

	    if (plen[i] == 6 && strnicmp(pfield[i], "medium", plen[i]) == 0) {
		if (ftype[3] != TYPE_XNOTDONE) {
		    return FALSE;
		}
		ftype[3] = i;
		ptype[i] = 3;
		numDone++;
		continue;
	    }

	    if (plen[i] == 6 && strnicmp(pfield[i], "normal", plen[i]) == 0) {
		if (ftype[5] != TYPE_XNOTDONE) {
		    return FALSE;
		}
		ftype[5] = i;
		ptype[i] = 5;
		numDone++;
		continue;
	    }

	    ptype[i] = TYPE_XSTRING;
	}

    FillIn:
	while (1) {
	    if (numDone == parsefields + 1) {
		break;
	    }

	    /* If this is the last asterisk, fill in all to end once we
	     * have a fixed position.  If it is the first asterisk, fill
	     * in to the beginning
	     */
	    n = 0;
	    /* This loop fills in as many single items as possible */
	    for (i = 0; i <= parsefields; i++) {
		k = i;
		type1 = ptype[k];
		stop = type1 & STOP_FLAG;
		type2 = ptype[k-1];
		done = (type2 >= 0);
		while (type1 >= 0 && !stop && !done) {
		    j = (ptype[k] & STOP_FLAG_MASK) - 1;
		    k--;

		    if (j < 0) {
			return FALSE;
		    }
		    ftype[j] = k;
		    ptype[k] = j;
		    numDone++; n++;

		    /* Need to be able to handle multiple asterisks.
		     * The last in the row gets the STOP_FLAG
		     */
		    if (i > 0) {
			type1 = type2;
			type2 = ptype[k-1];

			if (type1 == TYPE_XASTERISK &&
			    type2 != TYPE_XASTERISK)
			{
			    ptype[k] |= STOP_FLAG;
			    break;
			}
			type1 = ptype[k];
			stop = type1 & STOP_FLAG;
			done = (type2 >= 0);
		    } else {
			break;
		    }
		}

		k = i;
		type1 = ptype[k];
		stop = type1 & STOP_FLAG;
		type2 = ptype[k+1];
		done = (type2 >= 0);
		while (type1 >= 0 && !stop && !done) {
		    j = (ptype[k] & STOP_FLAG_MASK) + 1;
		    k++;

		    if (j > 14) {
			return FALSE;
		    }
		    ftype[j] = k;
		    ptype[k] = j;
		    numDone++; n++;

		    /* Need to be able to handle multiple asterisks.
		     * The last in the row gets the STOP_FLAG
		     */
		    if (i < 14) {
			type1 = type2;
			type2 = ptype[k+1];

			if (type1 == TYPE_XASTERISK &&
			    type2 != TYPE_XASTERISK)
			{
			    ptype[k] |= STOP_FLAG;
			    break;
			}

			type1 = ptype[k];
			stop = type1 & STOP_FLAG;
			done = (type2 >= 0);

		    } else {
			break;
		    }
		}
	    }

	    if (numDone == parsefields + 1) {
		break;
	    }

	    /* We've filled as many as we can based on what we had, see if
	     * we can go further by some more analysis.  This part could
	     * really use some extra intelligence.  It is extremely stupid
	     * and can be easily fooled.  Luckily, no one should try to fool
	     * it very often.
	     */
	    for (i = 1; i < parsefields; i++) {
		if (ptype[i] == TYPE_XINT) {
		    int val;
		    val = atoi(pfield[i]);
		    if (i < 11 &&
			ptype[i+1] == TYPE_XINT &&
			ptype[i+2] == TYPE_XINT &&
			ptype[i+3] == TYPE_XINT &&
			ftype[7] < 0)
		    {
			ftype[7] = i;
			ptype[i] = 7;
			goto breakOut;
		    }

		    if ((val % 10) != 0 && val < 20 &&
			ftype[7] < 0)
		    {
			ftype[7] = i;
			ptype[i] = 7;
			numDone++; n++;
			goto breakOut;
		    }
		    if (i < 12 &&
			ptype[i+1] == TYPE_XINT &&
			ptype[i+2] == TYPE_XINT &&
			ftype[8] < 0)
		    {
			ftype[8] = i;
			ptype[i] = 8;
			numDone++; n++;
			goto breakOut;
		    }
		    if (val == 75 && ptype[i+1] == TYPE_XINT &&
			atoi(pfield[i+1]) == 75 &&
			ftype[9] < 0)
		    {
			ftype[9] = i;
			ptype[i] = 9;
			numDone++; n++;
			goto breakOut;
		    }
		    if (ftype[8] < 0) {
			ftype[8] = i;
			ptype[i] = 8;
			numDone++; n++;
			goto breakOut;
		    }
		    if (ftype[9] < 0) {
			ftype[9] = i;
			ptype[i] = 9;
			numDone++; n++;
			goto breakOut;
		    }
		    if (ftype[10] < 0) {
			ftype[10] = i;
			ptype[i] = 10;
			numDone++; n++;
			goto breakOut;
		    }
		    if (ftype[11] < 0) {
			ftype[11] = i;
			ptype[i] = 11;
			numDone++; n++;
			goto breakOut;
		    }
		}
	    }

	    if (0) {
	    breakOut:
		continue;
	    }

	    /* Did we find anything this time through */
	    if (n == 0) {
		break;
	    }
	}
	if (numDone != parsefields + 1) {
	    /* This part needs to be redone */
	    for (i = 1; i < parsefields; i++) {
		if ((ptype[i] & STOP_FLAG_MASK) && ftype[i] < 0) {
		    ftype[i] = i;
		    ptype[i] = i | STOP_FLAG;
		    numDone++;
		    goto FillIn;
		}
	    }
	    return FALSE;
	}

	/* If the last field was an '*', fill in the rest of the values */
	if (pfield[parsefields-1][0] == '*') {
	    j = ptype[parsefields-1] & STOP_FLAG_MASK;
	    k = ftype[j];
	    for (i = j; i < 14; i++) {
		ftype[j] = k;
	    }
	}

	j = ftype[0];
	for (i = 1; i < 14; i++) {
	    if (ftype[i] == TYPE_XNOTDONE) {
		field[i] = "*";
		flen[i] = 1;
	    } else {
		if ((ftype[i] & STOP_FLAG_MASK) <= j) {
		    return FALSE;
		}
		j = ftype[i];
		field[i] = pfield[ftype[i]];
		flen[i] = plen[ftype[i]];
	    }
	}
    }

    memset(lplf, '\0', sizeof(LOGFONT));

    /*-- Field 1: Foundary--Ignore --*/

    /*-- Field 2: Font Family --*/
    i = 2;
    if (!(flen[i] == 0 ||
	  (flen[i] == 1 && (field[i][0] == '*' || field[i][0] == '?'))))
    {
	len = (flen[i] < LF_FACESIZE) ? flen[i] : LF_FACESIZE - 1;
	strncpy(lplf->lfFaceName, field[i], len);

	/* Need to handle Symbol and WingDings specially. */
	if (stricmp(lplf->lfFaceName, "Symbol") == 0) {
	    lplf->lfCharSet = SYMBOL_CHARSET;
	} else if (stricmp(lplf->lfFaceName, "WingDings") == 0) {
	    lplf->lfCharSet = SYMBOL_CHARSET;
	} /* Handle Dingbats? */
    }

    /*-- Field 3: Weight --*/
    i = 3;
    if (!(flen[i] == 0 ||
	  (flen[i] == 1 && (field[i][0] == '*' || field[i][0] == '?'))))
    {
	if (strnicmp(field[i], "bold", flen[i]) == 0) {
	    lplf->lfWeight = FW_BOLD;
	} else {
	    lplf->lfWeight = FW_MEDIUM;
	}
    } else {
	lplf->lfWeight = FW_MEDIUM;
    }
	    
    /*-- Field 4: Slant.  By default, this will Roman --*/
    i = 4;
    if (!(flen[i] == 0 ||
	  (flen[i] == 1 && (field[i][0] == '*' || field[i][0] == '?'))))
    {

	if (strnicmp(field[i], "r", flen[i]) == 0) {
	    /* Roman.  Don't do anything */
	} else if (strnicmp(field[i], "i", flen[i]) == 0) {
	    /* Italic */
	    lplf->lfItalic = TRUE;
	} else if (strnicmp(field[i], "o", flen[i]) == 0) {
	    /* Oblique */
	    lplf->lfOrientation = 3600 - 150; /* 15 degree slant forward */
	} else if (strnicmp(field[i], "ri", flen[i]) == 0) {
	    /* Reverse Italic */
	    lplf->lfOrientation = 300;        /* 30 degree slant backward */
	} else if (strnicmp(field[i], "ro", flen[i]) == 0) {
	    /* Reverse Oblique */
	    lplf->lfOrientation = 150;        /* 30 degree slant backward */
	} else if (strnicmp(field[i], "ot", flen[i]) == 0) {
	    /* Other */
	} else {
	    return FALSE;
	}
    }

    /*-- Field 5: Set Width--Ignore --*/

    /*-- Field 6: Blank Field.  Ignore it --*/

    /*-- Field 7: Pixels.  Use this as the points if no points set --*/
    i = 7;
    if (!(flen[i] == 0 ||
	  (flen[i] == 1 && (field[i][0] == '*' || field[i][0] == '?'))))
    {
	lplf->lfHeight = atoi(field[i]);
    }

    /*-- Field 8: Points in tenths of a point --*/
    i = 8;
    if (!(flen[i] == 0 ||
	  (flen[i] == 1 && (field[i][0] == '*' || field[i][0] == '?'))))
    {
	lplf->lfHeight = (atoi(field[i]) / 10);
    }

    /*-- Field 9: Horizontal Resolution in DPI--Ignore --*/

    /*-- Field 10: Verical Resolution in DPI--Ignore --*/

    /*-- Field 11: Spacing --*/
    i = 11;
    if (!(flen[i] == 0 ||
	  (flen[i] == 1 && (field[i][0] == '*' || field[i][0] == '?'))))
    {
	if (flen[i] != 1) {
	    return FALSE;
	}
	if (field[i][0] == 'p' || field[i][0] == 'P') {
	    lplf->lfPitchAndFamily |= VARIABLE_PITCH;
	} else if (field[i][0] == 'm' || field[i][0] == 'm' ||
		   field[i][0] == 'c' || field[i][0] == 'c')
	{
	    lplf->lfPitchAndFamily |= FIXED_PITCH;
	} else {
	    return FALSE;
	}
    }

    /*-- Field 12: Average Width --*/
    i = 12;
    if (!(flen[i] == 0 ||
	  (flen[i] == 1 && (field[i][0] == '*' || field[i][0] == '?'))))
    {
	lplf->lfWidth = (atoi(field[i]) / 10);
    }

    /*-- Field 13: Character Set--Ignore --*/

    return TRUE;
}

XFontStruct *
XLoadQueryFont(Display *display, const char *name)
{
    XFontStruct *fs = (XFontStruct *)malloc(sizeof(XFontStruct));
    LOGFONT lf;
    HDC hdc;
    HFONT hfont_old;
    TEXTMETRIC tm;
    XCharStruct cs;
#define MAX_SIZE 200
    char str[MAX_SIZE];
    int object;
    int match;

    display->request++;

    memset(fs, 0, sizeof(XFontStruct));
    /* Check for X font names */
    if (name[0] == '-' || name[0] == '*') {
	if (XFontNameToLogFont(name, &lf)) {
	    fs->fid = CreateFontIndirect(&lf);
	}
    } else {
	if (strlen(name) < MAX_SIZE) {
	    strcpy(str, name);
	    strlwr(str);
	    match = 0;
	    if (strcmp(str, "system") == 0) {
		object = SYSTEM_FONT;
		match = 1;
	    } else if (strcmp(str, "systemfixed") == 0) {
		object = SYSTEM_FIXED_FONT;
		match = 1;
	    } else if (strcmp(str, "ansi") == 0) {
		object = ANSI_VAR_FONT;
		match = 1;
	    } else if (strcmp(str, "ansifixed") == 0) {
		object = ANSI_FIXED_FONT;
		match = 1;
	    } else if (strcmp(str, "device") == 0) {
		object = DEVICE_DEFAULT_FONT;
		match = 1;
	    } else if (strcmp(str, "oemfixed") == 0) {
		object = OEM_FIXED_FONT;
		match = 1;
	    }
	    if (match) {
		fs->fid = GetStockObject(object);
	    }
	}
	if (fs->fid == NULL) {
	    if (NameToLogFont(name, &lf)) {
		fs->fid = CreateFontIndirect(&lf);
	    }
	}
    }
    if (fs->fid == NULL) {
	fs->fid = GetStockObject(SYSTEM_FIXED_FONT);
    }
    hdc = CreateCompatibleDC((HDC)NULL);
    hfont_old = SelectObject( hdc, fs->fid );

    GetTextMetrics( hdc, &tm );
/*
   fs->direction = (lf.lfEscapement == 900? FontRightToLeft: FontLeftToRight);
*/
    fs->min_byte1 = fs->max_byte1 = 0;
    fs->min_char_or_byte2 = tm.tmFirstChar;
    fs->max_char_or_byte2 = tm.tmLastChar;
    fs->all_chars_exist = TRUE;
    fs->default_char = tm.tmDefaultChar;

    fs->ascent = tm.tmAscent;
    fs->descent = tm.tmDescent;
    cs.width = tm.tmAveCharWidth;
    cs.ascent = fs->ascent;
    cs.descent = fs->descent;
    cs.lbearing = 0;
    cs.rbearing = cs.width;
    fs->min_bounds = fs->max_bounds = cs;
    fs->per_char = NULL;

    if (tm.tmAveCharWidth != tm.tmMaxCharWidth) {
	int i, nchars = tm.tmLastChar - tm.tmFirstChar + 1;
	int *wbuf = (int *)malloc(sizeof(int) * nchars);
	int min_width = 30000;

	GetCharWidth(hdc, tm.tmFirstChar, tm.tmLastChar, (int *) wbuf);

	fs->per_char = (XCharStruct *)malloc(sizeof(XCharStruct) * nchars);
	for( i = 0; i < nchars ; i++ ) {
	    fs->per_char[i] = cs;
	    fs->per_char[i].width = wbuf[i];
	    if( min_width > wbuf[i] )
		min_width = wbuf[i];
	}
	fs->max_bounds.width = tm.tmMaxCharWidth;
	fs->min_bounds.width = min_width;
	/* fs->min_bounds.width = tm.tmAvgCharWidth * 2 - tm.tmMaxCharWidth;*/
    }

    SelectObject( hdc, hfont_old );
    DeleteDC( hdc );

    return fs;
}

void
XFreeFont(Display *display, XFontStruct *font_struct)
{
        display->request++;

	if( font_struct->per_char )
		free( font_struct->per_char );
	DeleteObject(font_struct->fid);
	free(font_struct);
}

Bool
XGetFontProperty(XFontStruct *dummy1, Atom dummy2, 
	unsigned long *dummy3)
{
	/* is used only for getting XA_UNDERLINE_{POSITION&THICKNESS} value
	 * in tkFont.c:TkUnderlineChars()
	 */
	return FALSE;
}

void
XTextExtents(XFontStruct *font_struct, const char *string, int nchars, 
	int *direction_return, int *ascent_return, int *descent_return, 
	XCharStruct *overall_return)
{
	HDC hdc;
	HFONT hfont_old;
	TEXTMETRIC tm;
	SIZE size;

	*direction_return = font_struct->direction;
	*ascent_return = font_struct->ascent;
	*descent_return = font_struct->descent;

	hdc = CreateCompatibleDC((HDC)NULL);
	hfont_old = SelectObject( hdc, font_struct->fid );

	GetTextMetrics( hdc, &tm );
	overall_return->ascent = tm.tmAscent;
	overall_return->descent = tm.tmDescent;
	GetTextExtentPoint( hdc, string, nchars, &size );
	overall_return->width = size.cx;
	overall_return->lbearing = 0;
	overall_return->rbearing = overall_return->width;

	SelectObject( hdc, hfont_old );
	DeleteDC( hdc );
}

int
XTextWidth(XFontStruct *font_struct, const char *string, int count)
{
	HDC hdc;
	HFONT hfont_old;
	int text_width;
	int one, two;
	SIZE size;

	hdc = GetDC((HWND)NULL);
	hfont_old = SelectObject( hdc, font_struct->fid );
	GetTextExtentPoint( hdc, "a", 1, &size );
	one = size.cx;
	GetTextExtentPoint( hdc, "aa", 2, &size );
	two = size.cx;
	GetTextExtentPoint( hdc, string, count, &size);
	text_width = size.cx;
	text_width = text_width - (one * 2 - two);
	SelectObject( hdc, hfont_old );
	ReleaseDC((HWND) NULL,  hdc );

	return text_width;
}
 
#ifdef KANJI
int
XTextWidth16(XFontStruct *font_struct, const XChar2b *string, int count)
{
    char *bp;
    char *buffer;
    XChar2b *cp;
    XChar2b *wp;
    int cnt = 0, i, result;
    BYTE c1, c2;

    cp = (XChar2b *) malloc(sizeof(XChar2b) * count);
    memcpy(cp, string, sizeof(XChar2b) * count); 
    for(i = 0, wp = cp; (wp->byte2 != 0) && (i < count); wp++, i++) {
	if (wp->byte1) {
	    c2 = wp->byte2;
	    c1 = wp->byte1;
	    wp->byte1 = (c1 - 0x21) / 2 + ((c1 <= 0x5e) ? 0x81 : 0xc1);
	    if( c1 & 1 ) {	/* odd */
		wp->byte2 = c2 + ((c2 <= 0x5f) ? 0x1f : 0x20);
	    } else {
		wp->byte2 = c2 + 0x7e;
	    }
	    cnt += 2;
	} else {
	    cnt++;
	}
    }
    buffer = (char *) malloc(cnt + 1);
    for(i = 0, wp = cp, bp = buffer;(wp->byte2 != 0) && ( i < count); wp++, i++) {
	if (_ismbblead(wp -> byte1)) {
	    *bp++ = wp -> byte1;
	    *bp++ = wp -> byte2;
	} else {
	    *bp++ = wp -> byte2;
	}
    }
    *bp	= '\0';
    result = XTextWidth(font_struct, buffer, cnt);
    free(buffer);
    free(cp);
    return result;
}
 
void
XTextExtents16(XFontStruct *font_struct, const XChar2b *string, int nchars,
	int *direction_return, int *ascent_return, int *descent_return,
	XCharStruct *overall_return)
{
    char *bp;
    char *buffer;
    XChar2b *wp;
    XChar2b *cp;
    int cnt = 0, i;
    BYTE c1, c2;

    cp = (XChar2b *) malloc(sizeof(XChar2b) * nchars);
    memcpy(cp, string, sizeof(XChar2b) * nchars); 
    for(i = 0, wp = cp; (wp->byte2 != 0) && (i < nchars); wp++, i++) {
	if (wp->byte1) {
	    c2 = wp->byte2;
	    c1 = wp->byte1;
	    wp->byte1 = (c1 - 0x21) / 2 + ((c1 <= 0x5e) ? 0x81 : 0xc1);
	    if( c1 & 1 ) {	/* odd */
		wp->byte2 = c2 + ((c2 <= 0x5f) ? 0x1f : 0x20);
	    } else {
		wp->byte2 = c2 + 0x7e;
	    }
	    cnt += 2;
	} else {
	    cnt++;
	}
    }
    buffer = (char *) malloc(cnt + 1);
    for(i = 0, wp = cp, bp = buffer;(wp->byte2 != 0) && ( i < nchars); wp++, i++) {
	if (_ismbblead(wp -> byte1)) {
	    *bp++ = wp -> byte1;
	    *bp++ = wp -> byte2;
	} else {
	    *bp++ = wp -> byte2;
	}
    }
    *bp	= '\0';
    XTextExtents(font_struct, buffer, cnt, direction_return, ascent_return,
	descent_return, overall_return);
    free(buffer);
    free(cp);
}
#endif /* KANJI */ 

