#include "X.h"
#include "Xmd.h"
#include "Xproto.h"
#include "dixfontstr.h"
#include "fontstruct.h"
#include "gcstruct.h"
#include "windowstr.h"
#include "pixmapstr.h"
#include "scrnintstr.h"
#include "regionst.h"

#include "svga.h"
#include "../../mi/mistruct.h"
#include "../../../os/msdos/msdos.h"

void svgaChangeGC();

#ifdef LITE
static void noopArc(DrawablePtr, GCPtr, int, xArc *);
#endif

static GCFuncs _near svgaGCFuncs = {
	svgaValidateGC,
	svgaChangeGC,
	svgaCopyGC,
	svgaDestroyGC,
	svgaChangeClip,
	svgaDestroyClip,
	svgaCopyClip,
				/* devPrivate */
};

static GCOps _near svgaGCOps = {
	mxFillSpans,
	svgaSetSpans,
	svgaPutImage,
	svgaCopyArea,
	svgaCopyPlane,
	miPolyPoint,
	miZeroLine,
	miPolySegment,
	miPolyRectangle,
#ifdef LITE
	noopArc,
#else
	miPolyArc,
#endif
	miFillPolygon,
	miPolyFillRect,
#ifdef LITE
	noopArc,
#else
	miPolyFillArc,
#endif
	miPolyText8,
	miPolyText16,
	miImageText8,
	miImageText16,
	svgaImageGlyphBlt,
	svgaPolyGlyphBlt,
	mxPushPixels,
	0,	/* LineHelper */
			/* devPrivate */
};

Bool
svgaCreateGC(pGC)
GCPtr pGC;
{
	svgaPrivGC *devPriv;

	pGC->funcs = &svgaGCFuncs;
	pGC->ops = &svgaGCOps;

	pGC->miTranslate = 1;
	pGC->planemask = ~0;

	devPriv = (svgaPrivGC *)pGC->devPrivates[svgaGCPrivateIndex].ptr;
	bzero(devPriv, sizeof (*devPriv));
	devPriv->movebits = copybits;
	devPriv->FillArea = copybits;
	devPriv->movebytes = copybytes;

	return TRUE;
}

char ReduceRop[16][2] = {
	{ RROP_BLACK,	RROP_BLACK },
	{ RROP_BLACK,	RROP_NOP },
	{ RROP_BLACK,	RROP_INVERT },
	{ RROP_BLACK,	RROP_WHITE },
	{ RROP_NOP,	RROP_BLACK },
	{ RROP_NOP,	RROP_NOP },
	{ RROP_NOP,	RROP_INVERT },
	{ RROP_NOP,	RROP_WHITE },
	{ RROP_INVERT,	RROP_BLACK },
	{ RROP_INVERT,	RROP_NOP },
	{ RROP_INVERT,	RROP_INVERT },
	{ RROP_INVERT,	RROP_WHITE },
	{ RROP_WHITE,	RROP_BLACK },
	{ RROP_WHITE,	RROP_NOP },
	{ RROP_WHITE,	RROP_INVERT },
	{ RROP_WHITE,	RROP_WHITE }
};

int InverseAlu[16] = {
	GXclear,
	GXandInverted,
	GXnor,
	GXcopyInverted,
	GXand,
	GXnoop,
	GXequiv,
	GXorInverted,
	GXandReverse,
	GXxor,
	GXinvert,
	GXnand,
	GXcopy,
	GXor,
	GXorReverse,
	GXset
};
	
void
svgaChangeGC(pGC, changes)
GCPtr pGC;
Mask changes;
{
}

static void (near * near bitmove[16])(u_char *, u_char *, int, int, int) = {
	clearbits,	andbits,	andReversebits,	copybits,
	andInvertedbits, noopbits,	xorbits,	orbits,
	norbits,	equivbits,	invertbits,	orReversebits,
	copyInvertedbits, orInvertedbits, nandbits,	setbits
};

static void (near * near bytemove[16])(u_char *, u_char *, int) = {
	clearbytes,	andbytes,	andReversebytes,	copybytes,
	andInvertedbytes, noopbytes,	xorbytes,	orbytes,
	norbytes,	equivbytes,	invertbytes,	orReversebytes,
	copyInvertedbytes, orInvertedbytes, nandbytes,	setbytes
};


void
svgaValidateGC(pGC, changes, pDrawable)
    GCPtr 	pGC;
    Mask 		changes;
    DrawablePtr 	pDrawable;
{
    WindowPtr pWin;
    DDXPointRec	oldOrg;		/* origin of thing GC was last used with */
    Bool win_moved;		/* window has moved since last time */
    svgaPrivGC *devPriv;
    RegionPtr clientClip = 0;

    oldOrg = pGC->lastWinOrg;
    if (pDrawable->type == DRAWABLE_WINDOW)
    {
	pWin = (WindowPtr)pDrawable;
	pGC->lastWinOrg.x = pDrawable->x;
	pGC->lastWinOrg.y = pDrawable->y;
    }
    else
    {
	pWin = (WindowPtr)NULL;
	pGC->lastWinOrg.x = 0;
	pGC->lastWinOrg.y = 0;
    }

    win_moved = (oldOrg.x != pGC->lastWinOrg.x) ||
		(oldOrg.y != pGC->lastWinOrg.y);

    devPriv = (svgaPrivGC *)(pGC->devPrivates[svgaGCPrivateIndex].ptr);

    if (pGC->fillStyle != FillSolid && changes & (GCTile|GCStipple))
	changes |= GCFillStyle;

    if (changes & GCFunction) {
	devPriv->movebits = bitmove[pGC->alu];
	devPriv->movebytes = bytemove[pGC->alu];
	devPriv->FillArea = bytemove[pGC->alu];
    }

    /*
	if the client clip is different or moved OR
	the subwindowMode has changed OR
	the window's clip has changed since the last validation
	we need to recompute the composite clip
    */

    if ((changes & (GCClipXOrigin|GCClipYOrigin|GCClipMask)) ||
	(changes & GCSubwindowMode) ||
	(pDrawable->serialNumber != (pGC->serialNumber & DRAWABLE_SERIAL_BITS))
       )
    {
	if (pGC->clientClipType != CT_NONE) {
	    if (pGC->clientClipType == CT_PIXMAP) {
#ifdef notdef
		clientClip = mfbPixmapToRegion((PixmapPtr)pGC->clientClip);
#endif
	    } else {
		clientClip = (*pGC->pScreen->RegionCreate)((BoxRec *)0,
			    REGION_NUM_RECTS((RegionPtr)pGC->clientClip));
		/* retranslate client clip */
		(* pGC->pScreen->RegionCopy)(clientClip,
					      (RegionPtr)pGC->clientClip);
	    }

	    (* pGC->pScreen->TranslateRegion)(clientClip, 
			   pGC->lastWinOrg.x + pGC->clipOrg.x,
			   pGC->lastWinOrg.y + pGC->clipOrg.y);
	}

	if (pWin)
	{
	    int freeTmpClip, freeCompClip;
	    RegionPtr pregWin;		/* clip for this window, without
					   client clip */

	    if (pGC->subWindowMode == IncludeInferiors)
	    {
	        pregWin = NotClippedByChildren(pWin);
		freeTmpClip = FREE_CC;
	    }
	    else
	    {
	        pregWin = &pWin->clipList;
		freeTmpClip = REPLACE_CC;
	    }
	    freeCompClip = devPriv->freeCompClip;

	    /* if there is no client clip, we can get by with
	       just keeping the pointer we got, and remembering
	       whether or not should destroy (or maybe re-use)
	       it later.  this way, we avoid unnecessary copying
	       of regions.  (this wins especially if many clients clip
	       by children and have no client clip.)
	    */
	    if (!clientClip)
	    {
	        if(freeCompClip == FREE_CC) 
		{
		    (* pGC->pScreen->RegionDestroy) (devPriv->pCompositeClip);
		}
	        devPriv->pCompositeClip = pregWin;
	        devPriv->freeCompClip = freeTmpClip;
	    }
	    else
	    {
	        if(freeCompClip == FREE_CC) 
		    (* pGC->pScreen->RegionDestroy) (devPriv->pCompositeClip);
		(*pGC->pScreen->Intersect)(clientClip, clientClip, pregWin);
		devPriv->pCompositeClip = clientClip;
		if (freeTmpClip == FREE_CC)
		    (* pGC->pScreen->RegionDestroy) (pregWin);
		devPriv->freeCompClip = FREE_CC;
#ifdef notdef
		/* we need one 'real' region to put into the composite
		   clip.
			if pregWin and the current composite clip 
		   are real, we can get rid of one.
			if the current composite clip is real and
		   pregWin isn't, intersect the client clip and
		   pregWin into the existing composite clip.
			if pregWin is real and the current composite
		   clip isn't, intersect pregWin with the client clip
		   and replace the composite clip with it.
			if neither is real, use clientClip just created.
		   do the intersection into it.
		*/

		if ((freeTmpClip == FREE_CC) && (freeCompClip == FREE_CC))
		{
		    (* pGC->pScreen->Intersect)(
			devPriv->pCompositeClip,
			pregWin,
			clientClip);
		    (* pGC->pScreen->RegionDestroy)(pregWin);
		}
		else if ((freeTmpClip == REPLACE_CC) && 
		        (freeCompClip == FREE_CC))
		{
		    (* pGC->pScreen->Intersect)(
			devPriv->pCompositeClip,
		        pregWin,
			clientClip);
		}
		else if ((freeTmpClip == FREE_CC) &&
		         (freeCompClip == REPLACE_CC))
		{
		    (* pGC->pScreen->Intersect)( 
		       pregWin,
		       pregWin,
		       clientClip);
		    devPriv->pCompositeClip = pregWin;
		}
		else if ((freeTmpClip == REPLACE_CC) &&
		         (freeCompClip == REPLACE_CC))
		{
		    (* pGC->pScreen->Intersect)(
			clientClip,
			clientClip,
			pregWin);
		    devPriv->pCompositeClip = clientClip;
		    clientClip = 0;
		}
		devPriv->freeCompClip = FREE_CC;
#endif
	    }
	} /* end of composite clip for a window */
	else
	{
	    BoxRec pixbounds;

	    pixbounds.x1 = 0;
	    pixbounds.y1 = 0;
	    pixbounds.x2 = pDrawable->width;
	    pixbounds.y2 = pDrawable->height;

	    if (devPriv->freeCompClip == FREE_CC)
		(* pGC->pScreen->RegionReset)(
		    devPriv->pCompositeClip, &pixbounds);
	    else
	    {
		devPriv->freeCompClip = FREE_CC;
		devPriv->pCompositeClip = 
			(* pGC->pScreen->RegionCreate)(&pixbounds, 1);
	    }

	    if (clientClip) {
		/* trival case: The pixmap size completely
		 * encloses clientClip.  In this case, the Intersect is
		 * not necessary.
		 */
		if (pixbounds.x1 <= clientClip->extents.x1 &&
		    pixbounds.x2 >= clientClip->extents.x2 &&
		    pixbounds.y1 <= clientClip->extents.y1 &&
		    pixbounds.y2 >= clientClip->extents.y2) {
			(*pGC->pScreen->RegionDestroy)(devPriv->pCompositeClip);
			devPriv->pCompositeClip = clientClip;
			devPriv->freeCompClip = FREE_CC;
		} else {
		    (* pGC->pScreen->Intersect)(
		       devPriv->pCompositeClip, 
		       devPriv->pCompositeClip,
		       clientClip);
		    (* pGC->pScreen->RegionDestroy)(clientClip);
		}
	    }
	} /* end of composite clip for pixmap */
    }
}

void
svgaCopyGC(pGC, mask, srcGC)
GCPtr pGC, srcGC;
Mask mask;
{
}

void
svgaDestroyGC(pGC)
    GC 			*pGC;
{
    svgaPrivGC *pPriv;

    pPriv = (svgaPrivGC *)(pGC->devPrivates[svgaGCPrivateIndex].ptr);
    if (pPriv->freeCompClip == FREE_CC)
	(*pGC->pScreen->RegionDestroy)(pPriv->pCompositeClip);
#ifdef notdef
    if(pPriv->pAbsClientRegion)
	(*pGC->pScreen->RegionDestroy)(pPriv->pAbsClientRegion);
#endif
}

void
svgaChangeClip(pGC, type, pvalue, nrects)
    GCPtr	pGC;
    int		type;
    pointer	pvalue;
    int		nrects;
{
    svgaDestroyClip(pGC);
    if(type == CT_PIXMAP)
    {
#ifdef notdef
	/* convert the pixmap to a region */
	pGC->clientClip = (pointer) mfbPixmapToRegion((PixmapPtr)pvalue);
	/* you wouldn't do this if you were leaving the pixmap in
	   rather than converting it.
	*/
	(*pGC->pScreen->DestroyPixmap)(pvalue);
	pGC->clientClipType = CT_REGION;
#else
	pGC->clientClip = pvalue;
	pGC->clientClipType = CT_PIXMAP;
#endif
    }
    else if (type == CT_REGION)
    {
	/* stuff the region in the GC */
	pGC->clientClip = pvalue;
	pGC->clientClipType = CT_REGION;
    }
    else if (type != CT_NONE)
    {
	pGC->clientClip = (pointer) miRectsToRegion(nrects,
		(xRectangle *)pvalue, type);
	Xfree(pvalue);
	pGC->clientClipType = CT_REGION;
    }
    pGC->stateChanges |= GCClipMask;
}

void
svgaCopyClip(pgcDst, pgcSrc)
GCPtr pgcDst, pgcSrc;
{
    RegionPtr rgn;

    /* destroy old clip */
    svgaDestroyClip(pgcDst);
    if(pgcSrc->clientClipType == CT_NONE)
	return;
    pgcDst->clientClipType = pgcSrc->clientClipType;
    if (pgcSrc->clientClipType == CT_PIXMAP) {
	pgcDst->clientClip = pgcSrc->clientClip;
	((PixmapPtr)(pgcDst->clientClip))->refcnt++;
	return;
    }
    /* Must be a REGION */
    rgn = (RegionPtr)pgcSrc->clientClip;
    rgn = (*pgcDst->pScreen->RegionCreate)((BoxRec *)0, REGION_NUM_RECTS(rgn));
    (*pgcDst->pScreen->RegionCopy)(rgn, (RegionPtr)pgcSrc->clientClip);
    pgcDst->clientClip = (pointer)rgn;
}

void
svgaDestroyClip(pGC)
    GCPtr	pGC;
{
    if(pGC->clientClipType == CT_NONE)
	return;
    if (pGC->clientClipType == CT_PIXMAP) {
	(void)svgaDestroyPixmap((PixmapPtr)(pGC->clientClip));
    }
    else
    {
	/* we know we'll never have a list of rectangles, since
	   ChangeClip immediately turns them into a region 
	*/
        (*pGC->pScreen->RegionDestroy)((RegionPtr)pGC->clientClip);
    }
    pGC->clientClip = NULL;
    pGC->clientClipType = CT_NONE;
}

#ifdef LITE
static void
noopArc(pDraw, pGC, narcs, parcs)
    DrawablePtr	pDraw;
    GCPtr	pGC;
    int		narcs;
    xArc	*parcs;
{
}
#endif
