/*
 * xgraphic.c --
 *
 * Copyright (c) 1994 Software Research Associates, Inc.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose and without fee is hereby granted, provided
 * that the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of Software Research Associates not be
 * used in advertising or publicity pertaining to distribution of the
 * software without specific, written prior permission.  Software Research
 * Associates makes no representations about the suitability of this software
 * for any purpose.  It is provided "as is" without express or implied
 * warranty.
 */

#include "xlibInt.h" 

#define PI 3.14159265358979

static HBITMAP hbmpCompat1;
static HBITMAP hbmpCompat2;
static POINT *new_points;
static int local_points;



HDC
GetDrawableDC(HANDLE drawable)
{
    /* The IsWindow() function is returning true for some bitmaps
     * that we create.
     */
    if (!IsPixmap(drawable)) {
	return GetDC(drawable); 
    } else {
	HDC hdc, hdcMemory;
	hdc = GetDC((HWND) NULL);
    	hdcMemory = CreateCompatibleDC(hdc);
	ReleaseDC((HWND) NULL, hdc);
	if(hbmpCompat1 == None) 
	    hbmpCompat1 = SelectObject(hdcMemory, drawable);
	else
	    hbmpCompat2 = SelectObject(hdcMemory, drawable);
	     
	return hdcMemory;
    }
}

void 
ReleaseDrawableDC(HANDLE drawable, HDC hdc)
{
    if (!IsPixmap(drawable)) {
    	ReleaseDC(drawable, hdc);
    } else {
	if (hbmpCompat1 != None) {
    	    SelectObject(hdc, hbmpCompat1);
	    hbmpCompat1 = None;
	} else {
    	    SelectObject(hdc, hbmpCompat2);
	    hbmpCompat2 = None;
	}
	DeleteDC(hdc);
    }
}

static POINT *
XPointsToMSPoints(XPoint *points, int npoints)
{
    register int i;

    if (npoints > local_points) {
        if (new_points != NULL) {
	    free((char *) new_points);
	}
        new_points = (POINT *) malloc(sizeof(POINT) * npoints);
	if (new_points == NULL) {
	    local_points = 0;
	    return NULL;
	}
	local_points = npoints;
    }

    for (i = 0; i < npoints; i++) {
	new_points[i].x = points[i].x;
	new_points[i].y = points[i].y;
    }
    return new_points;
}

static POINT *
GetOriginalPoints(XPoint *points, int npoints)
{
    register int i;

    if (npoints > local_points) {
        if (new_points != NULL) {
	    free((char *) new_points);
	}
        new_points = (POINT *) malloc(sizeof(POINT) * npoints);
	if (new_points == NULL) {
	    local_points = 0;
	    return NULL;
	}
	local_points = npoints;
    }

    new_points[0].x = points[0].x;
    new_points[0].y = points[0].y;
    for (i = 1 ; i < npoints ; i++) {
	new_points[i].x = new_points[i-1].x + points[i].x;
	new_points[i].y = new_points[i-1].y + points[i].y;
    }
    return new_points;
}

static void
GetBoxPoints(POINT *points, int n,
	     int *left, int *top, int *right, int *bottom)
{
    int i;

    *left = *right = points[0].x;
    *top = *bottom = points[0].y;
    for (i = 1; i < n; i++) {
    	if (*left > points[i].x) *left = points[i].x;
    	if (*right < points[i].x) *right = points[i].x;
    	if (*top > points[i].y) *top = points[i].y;
    	if (*bottom < points[i].y) *bottom = points[i].y;
    }
}

static void
ShiftPoints(POINT *points, int n, int x, int y)
{
    int i;

    for (i = 0; i < n; i++, points++) {
    	points->x -= x;
    	points->y -= y;
    }
}

/*
 * XDrawSegments
 */
void
XDrawSegments(Display *display, Drawable d, GC gc, XSegment *segments, int nsegments)
{
    HDC hdc;
    HPEN hpen, hpenPrev;
    POINT oldpos;
    HDC hdcMem;
    HBITMAP hbmp, hbmpPrev;
    HBRUSH hbrPat, hbrPrev;
    int width, height;
    int seg;
    int x1, y1, x2, y2;

    display->request++;

    hdc = GetDrawableDC(d);
    SetROP2(hdc, gc->function);

    hpen = CreatePen(gc->line_style, gc->line_width, gc->foreground);

    if ((gc->fill_style == FillStippled ||
	 gc->fill_style == FillOpaqueStippled)
	&& gc->stipple != None)
    {
	hdcMem = CreateCompatibleDC(hdc);
	hbrPat = CreatePatternBrush(gc->stipple);
	SetBkMode(hdcMem, TRANSPARENT);
	SetBrushOrgEx(hdc, gc->ts_x_origin % 8, gc->ts_y_origin % 8, NULL);
	hbrPrev = SelectObject(hdc, hbrPat);

	for (seg = 0; seg < nsegments; seg++) {
	    x1 = segments[seg].x1;
	    x2 = segments[seg].x2;
	    y1 = segments[seg].y1;
	    y2 = segments[seg].y2;

	    width = max(x1, x2) + 30;
	    height = max(y1, y2) + 30;

	    hbmp = CreateCompatibleBitmap(hdc, width, height);
	    hbmpPrev = SelectObject(hdcMem, hbmp);
	    hpenPrev = SelectObject(hdcMem, hpen);

	    PatBlt(hdcMem, 0, 0, width, height, BLACKNESS);
	    MoveToEx(hdcMem, x1, y1, &oldpos);
	    LineTo(hdcMem, x2, y2);

	    BitBlt(hdc, 0, 0, width, height, hdcMem, 0, 0, 0x00AE0B06);

	    PatBlt(hdcMem, 0, 0, width, height, WHITENESS);
	    MoveToEx(hdcMem, x1, y1, &oldpos);
	    LineTo(hdcMem, x2, y2);

	    BitBlt(hdc, 0, 0, width, height, hdcMem, 0, 0, 0x00A803A9);

	    DeleteObject(SelectObject(hdcMem, hpenPrev));
	    DeleteObject(SelectObject(hdcMem, hbmpPrev));
	}
	DeleteObject(SelectObject(hdc, hbrPrev));
	DeleteDC(hdcMem);
    } else {
	for (seg = 0; seg < nsegments; seg++) {
	    x1 = segments[seg].x1;
	    x2 = segments[seg].x2;
	    y1 = segments[seg].y1;
	    y2 = segments[seg].y2;

	    hpenPrev = SelectObject(hdc, hpen);
	    MoveToEx(hdc, x1, y1, &oldpos);
	    LineTo(hdc, x2, y2);
	    DeleteObject(SelectObject(hdc, hpenPrev));
	}
    }
    ReleaseDrawableDC(d, hdc);
}

/*
 *  XDrawLine
 *
 */

void
XDrawLine(Display *display, Drawable d, GC gc, int x1, int y1, int x2, int y2)
{
    XSegment segment;

    segment.x1 = x1;
    segment.y1 = y1;
    segment.x2 = x2;
    segment.y2 = y2;
    XDrawSegments(display, d, gc, &segment, 1);
}

/*
 *  XDrawLines
 *
 */

void
XDrawLines(display, d, gc, points, npoints, mode)
Display *display;
Drawable d;
GC gc;
XPoint points[];
int npoints, mode;
{
    HDC hdc;
    HPEN hpen, hpenPrev;
    POINT *xp;

    display->request++;

    hdc = GetDrawableDC(d);
    SetROP2(hdc, gc->function);

    hpen = CreatePen(gc->line_style, gc->line_width, gc->foreground);

    xp = (mode == CoordModePrevious)?
	GetOriginalPoints(points, npoints): XPointsToMSPoints(points, npoints);
    if (xp == NULL) return;
    if ((gc->fill_style == FillStippled || gc->fill_style == FillOpaqueStippled)
	    && gc->stipple != None)
    {
	HDC hdcMem;
	HBITMAP hbmp, hbmpPrev;
	HBRUSH hbrPat, hbrPrevPat;
	int x, y, width, height;

	GetBoxPoints(xp, npoints, &x, &y, &width, &height);
	x -= gc->line_width;
	y -= gc->line_width;
	ShiftPoints(xp, npoints, x, y);
	width -= x-1 - gc->line_width * 2;
	height -= y-1 - gc->line_width * 2;

	hdcMem = CreateCompatibleDC(hdc);
	SetBkMode(hdcMem, TRANSPARENT);
	hbmp = CreateCompatibleBitmap(hdc, width, height);
	hbmpPrev = SelectObject(hdcMem, hbmp);
	hpenPrev = SelectObject(hdcMem, hpen);

	hbrPat = CreatePatternBrush(gc->stipple);
	SetBrushOrgEx(hdc, gc->ts_x_origin % 8, gc->ts_y_origin % 8, NULL);
	hbrPrevPat = SelectObject(hdc, hbrPat);

	PatBlt(hdcMem, 0, 0, width, height, BLACKNESS);
	Polyline(hdcMem, xp, npoints);

	BitBlt(hdc, x, y, width, height, hdcMem, 0, 0, 0x00AE0B09);

	PatBlt(hdcMem, 0, 0, width, height, WHITENESS);
	Polyline(hdcMem, xp, npoints);
	BitBlt(hdc, x, y, width, height, hdcMem, 0, 0, 0x00A803A9);
	DeleteObject(SelectObject(hdc, hbrPrevPat));

	DeleteObject(SelectObject(hdcMem, hpenPrev));
	DeleteObject(SelectObject(hdcMem, hbmpPrev));
	DeleteDC(hdcMem);
    } else {
	hpenPrev = SelectObject(hdc, hpen);
	Polyline(hdc, xp, npoints);
	DeleteObject(SelectObject(hdc, hpenPrev));
    }
    ReleaseDrawableDC(d, hdc);
}


static void
DrawOrFillArc(display, d, gc, x, y, width, height, angle1, angle2, fill)
Display *display;
Drawable d;
GC gc;
int x, y; /* left top */
unsigned int width, height;
int angle1;	/* angle1: three-o'clock (deg*64) */
int angle2; 	/* angle2: relative (deg*64) */
int fill; /* ==0 draw, !=0 fill */
{
    HDC hdc;
    HPEN hpen, hpenPrev;
    HBRUSH hbr, hbrPrev;
    int xr, yr, xstart, ystart, xend, yend;
    double radian_start, radian_end, radian_tmp;

	hdc = GetDrawableDC(d);

    if(width % 2 == 1)
	xr = width / 2;
    else
	xr = (width - 1) / 2;

    if (height % 2 == 1)
	yr = height / 2;
    else
	yr = (height - 1) / 2;

    radian_start = (double)angle1 / 64 * PI / 180;
    radian_end = (double)(angle1+angle2) / 64 * PI / 180;
    if( angle2 < 0 ) {
	radian_tmp = radian_start;
	radian_start = radian_end;
	radian_end = radian_tmp;
    }

    xstart = x + (int)( (double)xr * (1+cos(radian_start)) );
    ystart = y + (int)( (double)yr * (1-sin(radian_start)) );
    xend = x + (int)( (double)xr * (1+cos(radian_end)) );
    yend = y + (int)( (double)yr * (1-sin(radian_end)) );

    SetROP2(hdc, gc->function);


    if( !fill ) {
	hpen = CreatePen(gc->line_style, gc->line_width, gc->foreground);
	hpenPrev = SelectObject(hdc, hpen);
	Arc(hdc, x, y, x + width, y + height, xstart, ystart, xend, yend);
	DeleteObject(SelectObject(hdc, hpenPrev));
    }
    else {

	hpen = CreatePen(PS_SOLID, 1, gc->foreground);
	hbr = CreateSolidBrush(gc->foreground);

	if ((gc->fill_style == FillStippled || gc->fill_style == FillOpaqueStippled)
		&& gc->stipple != None) {
	    HDC hdcMem;
	    HBITMAP hbmp, hbmpPrev;
	    HBRUSH hbrPat, hbrPrevPat;
	
	    hdcMem = CreateCompatibleDC(hdc);
	    SetBkMode(hdcMem, TRANSPARENT);
	    hbmp = CreateCompatibleBitmap(hdc, width, height);
	    hbmpPrev = SelectObject(hdcMem, hbmp);
	    hpenPrev = SelectObject(hdcMem, hpen);
	    hbrPrev = SelectObject(hdcMem, hbr);

	    PatBlt(hdcMem, 0, 0, width, height, BLACKNESS);
	    if ( gc->arc_mode == ArcChord ) {
	    	Chord(hdcMem, 0, 0, width, height, xstart - x, ystart -y, xend-x, yend-y);
	    } else {
	    	Pie(hdcMem, 0, 0, width, height, xstart-x , ystart-y, xend-x, yend-y);
	    }

	    hbrPat = CreatePatternBrush(gc->stipple);
	    SetBrushOrgEx(hdc, gc->ts_x_origin % 8, gc->ts_y_origin % 8, NULL);
	    hbrPrevPat = SelectObject(hdc, hbrPat);
	    BitBlt(hdc, x , y, width, height, hdcMem, 0, 0, 0x00AE0B06);

	    PatBlt(hdcMem, 0, 0, width, height, WHITENESS);
	    if ( gc->arc_mode == ArcChord ) {
	    	Chord(hdcMem, 0, 0, width, height, xstart - x, ystart -y, xend-x, yend-y);
	    } else {
	    	Pie(hdcMem, 0, 0, width, height, xstart-x , ystart-y, xend-x, yend-y);
	    }
	    BitBlt(hdc, x , y, width, height, hdcMem, 0, 0, 0x00A803A9);


	    DeleteObject(SelectObject(hdc, hbrPrevPat));

	    DeleteObject(SelectObject(hdcMem, hpenPrev));
	    DeleteObject(SelectObject(hdcMem, hbrPrev));
	    DeleteObject(SelectObject(hdcMem, hbmpPrev));
	    DeleteDC(hdcMem);

	} else {
	    hpenPrev = SelectObject(hdc, hpen);
	    hbrPrev = SelectObject(hdc, hbr);
	    if ( gc->arc_mode == ArcChord ) {
	        Chord(hdc, x, y, x + width, y + height, xstart, ystart, xend, yend);
	    } else if ( gc->arc_mode == ArcPieSlice ) {
	       Pie(hdc, x, y, x + width, y + height, xstart, ystart, xend, yend);
	    }
	    DeleteObject(SelectObject(hdc, hpenPrev));
	    DeleteObject(SelectObject(hdc, hbrPrev));
	}
    }
    ReleaseDrawableDC(d, hdc);
}

void
XDrawArc(display, d, gc, x, y, width, height, angle1, angle2)
Display *display;
Drawable d;
GC gc;
int x, y;
unsigned int width, height;
int angle1, angle2;
{
    display->request++;

    DrawOrFillArc(display, d, gc, x, y, width, height, angle1, angle2, 0);
}

void 
XFillArc(display, d, gc, x, y, width, height, angle1, angle2)
Display *display;
Drawable d;
GC gc;
int x, y;
unsigned int width, height;
int angle1, angle2;
{
    display->request++;

    DrawOrFillArc(display, d, gc, x, y, width, height, angle1, angle2, 1);
}


void
XFillPolygon(display, d, gc, points, n, shape, mode)
Display *display;
Drawable d;
GC gc;
XPoint *points;
int n, shape, mode;
{
    HDC hdc;
    HPEN hpen, hpenPrev;
    HBRUSH hbr, hbrPrev;
    POINT *xp;

    display->request++;

    hdc = GetDrawableDC(d);
    SetROP2(hdc, gc->function);
    SetPolyFillMode(hdc, gc->fill_rule);

    hpen = CreatePen(PS_NULL, 0, gc->foreground);
    hbr = CreateSolidBrush(gc->foreground);


    xp = (mode == CoordModePrevious)?
	GetOriginalPoints(points, n):XPointsToMSPoints(points, n);
    if (xp == NULL) return;
    if ((gc->fill_style == FillStippled || gc->fill_style == FillOpaqueStippled)
	    && gc->stipple != None)
    {
	HDC hdcMem;
	HBITMAP hbmp, hbmpPrev;
	HBRUSH hbrPat, hbrpatPrev;
	int x, y, width, height;

	GetBoxPoints(xp, n, &x, &y, &width, &height);
	ShiftPoints(xp, n, x, y);
	width -= x-1;
	height -= y-1;

	hdcMem = CreateCompatibleDC(hdc);
	SetBkMode(hdcMem, TRANSPARENT);
	hbmp = CreateCompatibleBitmap(hdc, width, height);
	hbmpPrev = SelectObject(hdcMem, hbmp);
	hpenPrev = SelectObject(hdcMem, hpen);
	hbrPrev = SelectObject(hdcMem, hbr);

	hbrPat = CreatePatternBrush(gc->stipple);
	SetBrushOrgEx(hdc, gc->ts_x_origin % 8, gc->ts_y_origin % 8, NULL);
	hbrpatPrev = SelectObject(hdc, hbrPat);

	PatBlt(hdcMem, 0, 0, width, height, BLACKNESS);
	Polygon(hdcMem, xp, n);
	BitBlt(hdc, x, y, width, height, hdcMem, 0, 0, 0x00AE0B09);

	PatBlt(hdcMem, 0, 0, width, height, WHITENESS);
	Polygon(hdcMem, xp, n);
	BitBlt(hdc, x, y, width, height, hdcMem, 0, 0, 0x00A803A9);

	DeleteObject(SelectObject(hdc, hbrpatPrev));

	DeleteObject(SelectObject(hdcMem, hpenPrev));
	DeleteObject(SelectObject(hdcMem, hbrPrev));
	DeleteObject(SelectObject(hdcMem, hbmpPrev));
	DeleteDC(hdcMem);
     } else {
	hpenPrev = SelectObject(hdc, hpen);
	hbrPrev = SelectObject(hdc, hbr);
	Polygon(hdc, xp, n);
	DeleteObject(SelectObject(hdc, hpenPrev));
	DeleteObject(SelectObject(hdc, hbrPrev));
    }
    ReleaseDrawableDC(d, hdc);
}

void  
XDrawRectangle(display, d, gc, x, y, width, height)
Display *display;
Drawable d;
GC gc;
int x, y;
unsigned int width, height;
{
    HDC hdc;
    HPEN hPen, hPrevPen;
    POINT points[5];

    display->request++;

    points[0].x = points[1].x = points[4].x = x; 
    points[2].x = points[3].x = x + width;
    points[0].y = points[3].y = points[4].y = y;
    points[1].y = points[2].y = y + height;

    hdc = GetDrawableDC(d);
    SetROP2(hdc, gc->function);
    hPen = CreatePen(gc->line_style, gc->line_width, gc->foreground);
    hPrevPen = SelectObject(hdc, hPen);
    Polyline(hdc, points, 5);
    DeleteObject(SelectObject(hdc, hPrevPen));
    ReleaseDrawableDC(d, hdc);
}

void
XFillRectangle(Display *display, Drawable d, GC gc, int x, int y, 
	       unsigned int width, unsigned int height)
{
    XRectangle rectangle;
    rectangle.x = x;
    rectangle.y = y;
    rectangle.width = width;
    rectangle.height = height;
    XFillRectangles(display, d, gc, &rectangle, 1);
}

void
XFillRectangles(Display *display, Drawable d, GC gc, XRectangle *rectangles,
		int nrectangles)
{
    HDC hdc;
    HBRUSH hbr, hbrPrev;
    HDC hdcMem;
    HBITMAP hbmp, hbmpPrev;
    HBRUSH hbrPat, hbrPrevPat;
    HPEN hpen, hpenPrev;
    int rect;
    int width, height;
    int x, y;

    display->request++;

    hdc = GetDrawableDC(d);
    SetROP2(hdc, gc->function);

    hbr = CreateSolidBrush(gc->foreground);
    if ((gc->fill_style == FillStippled ||
	 gc->fill_style == FillOpaqueStippled)
	&& gc->stipple != None)
    {
	hdcMem = CreateCompatibleDC(hdc);
	hbrPrev = SelectObject(hdcMem, hbr);
	SetBkMode(hdcMem, TRANSPARENT);
	hbrPat = CreatePatternBrush(gc->stipple);
	SetBrushOrgEx(hdc, gc->ts_x_origin % 8, gc->ts_y_origin % 8, NULL);
	hbrPrevPat = SelectObject(hdc, hbrPat);

	for (rect = 0; rect < nrectangles; rect++) {
	    width = rectangles[rect].width;
	    height = rectangles[rect].height;
	    x = rectangles[rect].x;
	    y = rectangles[rect].y;

	    hbmp = CreateCompatibleBitmap(hdc, width, height);
	    hbmpPrev = SelectObject(hdcMem, hbmp);

	    PatBlt(hdcMem, 0, 0, width, height, BLACKNESS);
	    Rectangle(hdcMem, 0, 0, width, height );
	    BitBlt(hdc, x, y, width, height, hdcMem, 0, 0, 0x00AE0B09);

	    PatBlt(hdcMem, 0, 0, width, height, WHITENESS);
	    Rectangle(hdcMem, 0, 0, width, height );
	    BitBlt(hdc, x, y, width, height, hdcMem, 0, 0, 0x00A803A9);

	    DeleteObject(hbmp);
	    DeleteDC(hdcMem);
	}
	SelectObject(hdc, hbrPrevPat);
	DeleteObject(hbrPat);
    } else {

	hpen = CreatePen(PS_SOLID, 1, gc->foreground);
	hpenPrev = SelectObject(hdc, hpen);
	hbrPrev = SelectObject(hdc, hbr);
	for (rect = 0; rect < nrectangles; rect++) {
	    width = rectangles[rect].width;
	    height = rectangles[rect].height;
	    x = rectangles[rect].x;
	    y = rectangles[rect].y;

	    Rectangle(hdc, x, y, x + width, y + height );
	}
	DeleteObject(SelectObject(hdc, hpenPrev));
	SelectObject(hdc, hbrPrev);
    }
	
    DeleteObject(hbr);
    ReleaseDrawableDC(d, hdc);
}

/* XXX: This routine can be sped up by not drawing into an offscreen bitmap
 * unless there is a stipple active
 */
static void
DrawStringUtil(Display *display, Drawable d, GC gc, int x, int y,
	       const char *string, int length, int imageString)
{
    HDC hdc, hdcMem;
    HBITMAP hbmp, hbmpPrev;
    HBRUSH hbr, hbrPrev;
    HFONT hfontPrev;
    SIZE sz;
    TEXTMETRIC tm;

    hdc = GetDrawableDC(d);
    SetROP2(hdc, gc->function);

    if ((gc->fill_style == FillStippled
	 || gc->fill_style == FillOpaqueStippled)
	&& gc->stipple != None)
    {
	hdcMem = CreateCompatibleDC(hdc);

	if (gc->font != None) {
	    hfontPrev = SelectObject(hdcMem, gc->font);
	}
	GetTextExtentPoint(hdcMem, string, length, &sz);
	GetTextMetrics(hdcMem, &tm);
	hbmp = CreateCompatibleBitmap(hdc, sz.cx + 10, sz.cy + 10);
	hbmpPrev = SelectObject(hdcMem, hbmp);
	SetTextAlign(hdcMem, TA_LEFT | TA_TOP);
	SetTextColor(hdcMem, gc->foreground);

	hbr = CreatePatternBrush(gc->stipple);
	SetBrushOrgEx(hdc, gc->ts_x_origin % 8, gc->ts_y_origin % 8, NULL);

	if (imageString) {
	    SetBkMode(hdcMem, OPAQUE);
	    SetBkColor(hdcMem, gc->background);
	} else {
	    SetBkMode(hdcMem, TRANSPARENT);
	    SetBkColor(hdcMem, RGB(0, 0, 0));
	}
	PatBlt(hdcMem, 0, 0, sz.cx+10, sz.cy+10, BLACKNESS);
	TextOut(hdcMem, 0, 0, string, length);

	hbrPrev = SelectObject(hdc, hbr);
	BitBlt(hdc, x, y - tm.tmAscent, sz.cx, sz.cy, hdcMem, 0, 0, 0x00AE0B06); 

	PatBlt(hdcMem, 0, 0, sz.cx+10, sz.cy+10, WHITENESS);
	SetBkColor(hdcMem, RGB(255, 255, 255));
	TextOut(hdcMem, 0, 0, string, length);

	BitBlt(hdc, x, y - tm.tmAscent, sz.cx, sz.cy, hdcMem, 0, 0, 0x00A803A9); 
	hbr = SelectObject(hdc, hbrPrev);
	DeleteObject(hbr);

	if (gc->font != None) {
	    SelectObject(hdcMem, hfontPrev);
	}
	DeleteObject(SelectObject(hdcMem, hbmpPrev));
	DeleteDC(hdcMem);
    } else {
	SetTextAlign(hdc, TA_LEFT | TA_TOP);
	SetTextColor(hdc, gc->foreground);
	if (imageString) {
	    SetBkMode(hdc, OPAQUE);
	    SetBkColor(hdc, gc->background);
	} else {
	    SetBkMode(hdc, TRANSPARENT);
	}
	if (gc->font != None) {
	    hfontPrev = SelectObject(hdc, gc->font);
	}

	GetTextMetrics(hdc, &tm);
	TextOut(hdc, x, y - tm.tmAscent, string, length);

	if (gc->font != None) {
	    SelectObject(hdc, hfontPrev);
	}
    }
    ReleaseDrawableDC(d, hdc);
}
    
void 
XDrawString(Display *display, Drawable d, GC gc, int x, int y,
	    const char *string, int length)
{
    display->request++;

    DrawStringUtil(display, d, gc, x, y, string, length, 0);
}

void 
XDrawImageString(Display *display, Drawable d, GC gc, int x, int y,
	    const char *string, int length)
{
    display->request++;

    DrawStringUtil(display, d, gc, x, y, string, length, 1);
}

#ifdef KANJI 
void 
XDrawString16(display, d, gc, x, y, string, length)
Display *display;
Drawable d;
GC gc;
int x, y;
const XChar2b *string;
int length;
{
    char *bp;
    char *buffer;
    XChar2b *wp;
    XChar2b *cp;
    int cnt = 0, i;
    BYTE c1, c2;

    display->request++;

    cp = (XChar2b *) malloc(sizeof(XChar2b) * length);
    memcpy(cp, string, sizeof(XChar2b) * length); 
    for(i = 0, wp = cp;  (wp->byte2 != 0) && (i < length); 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 < length); wp++, i++) {
	if (_ismbblead(wp -> byte1)) {
	    *bp++ = wp -> byte1;
	    *bp++ = wp -> byte2;
	} else {
	    *bp++ = wp -> byte2;
	}
    }
    *bp = '\0';    	
    XDrawString(display, d, gc, x, y, buffer, cnt);
    free(buffer);
    free(cp);
}
#endif /* KANJI */ 
