/*
 * vga256 copy area
 */

/*

Copyright (c) 1989  X Consortium

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Except as contained in this notice, the name of the X Consortium shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from the X Consortium.

Author: Keith Packard

*/
/* $XConsortium: vgabitblt.c,v 1.1 94/10/13 13:04:50 kaleb Exp $ */
/* $XFree86: xc/programs/Xserver/hw/xfree86/vga256/vga/vgabitblt.c,v 3.1 1995/01/28 16:14:20 dawes Exp $ */

#include	"vga256.h"
#include	"fastblt.h"
#define MFB_CONSTS_ONLY
#include "maskbits.h"

RegionPtr
vga256BitBlt(pSrcDrawable, pDstDrawable,
            pGC, srcx, srcy, width, height, dstx, dsty, doBitBlt, bitPlane)
    register DrawablePtr pSrcDrawable;
    register DrawablePtr pDstDrawable;
    GC *pGC;
    int srcx, srcy;
    int width, height;
    int dstx, dsty;
    void (*doBitBlt)(
#if NeedFunctionPrototypes
DrawablePtr,
DrawablePtr,
int,
RegionPtr,
DDXPointPtr,
unsigned long,
unsigned long
#endif
);
    unsigned long bitPlane;
{
    RegionPtr prgnSrcClip;	/* may be a new region, or just a copy */
    Bool freeSrcClip = FALSE;

    RegionPtr prgnExposed;
    RegionRec rgnDst;
    DDXPointPtr pptSrc;
    register DDXPointPtr ppt;
    register BoxPtr pbox;
    int i;
    register int dx;
    register int dy;
    xRectangle origSource;
    DDXPointRec origDest;
    int numRects;
    BoxRec fastBox;
    int fastClip = 0;		/* for fast clipping with pixmap source */
    int fastExpose = 0;		/* for fast exposures with pixmap source */

    origSource.x = srcx;
    origSource.y = srcy;
    origSource.width = width;
    origSource.height = height;
    origDest.x = dstx;
    origDest.y = dsty;

    if ((pSrcDrawable != pDstDrawable) &&
	pSrcDrawable->pScreen->SourceValidate)
    {
	(*pSrcDrawable->pScreen->SourceValidate) (pSrcDrawable, srcx, srcy, width, height);
    }

    srcx += pSrcDrawable->x;
    srcy += pSrcDrawable->y;

    /* clip the source */

    if (pSrcDrawable->type == DRAWABLE_PIXMAP)
    {
	if ((pSrcDrawable == pDstDrawable) &&
	    (pGC->clientClipType == CT_NONE))
	{
	    prgnSrcClip = cfbGetCompositeClip(pGC);
	}
	else
	{
	    fastClip = 1;
	}
    }
    else
    {
	if (pGC->subWindowMode == IncludeInferiors)
	{
	    if (!((WindowPtr) pSrcDrawable)->parent)
	    {
		/*
		 * special case bitblt from root window in
		 * IncludeInferiors mode; just like from a pixmap
		 */
		fastClip = 1;
	    }
	    else if ((pSrcDrawable == pDstDrawable) &&
		(pGC->clientClipType == CT_NONE))
	    {
		prgnSrcClip = cfbGetCompositeClip(pGC);
	    }
	    else
	    {
		prgnSrcClip = NotClippedByChildren((WindowPtr)pSrcDrawable);
		freeSrcClip = TRUE;
	    }
	}
	else
	{
	    prgnSrcClip = &((WindowPtr)pSrcDrawable)->clipList;
	}
    }

    fastBox.x1 = srcx;
    fastBox.y1 = srcy;
    fastBox.x2 = srcx + width;
    fastBox.y2 = srcy + height;

    /* Don't create a source region if we are doing a fast clip */
    if (fastClip)
    {
	fastExpose = 1;
	/*
	 * clip the source; if regions extend beyond the source size,
 	 * make sure exposure events get sent
	 */
	if (fastBox.x1 < pSrcDrawable->x)
	{
	    fastBox.x1 = pSrcDrawable->x;
	    fastExpose = 0;
	}
	if (fastBox.y1 < pSrcDrawable->y)
	{
	    fastBox.y1 = pSrcDrawable->y;
	    fastExpose = 0;
	}
	if (fastBox.x2 > pSrcDrawable->x + (int) pSrcDrawable->width)
	{
	    fastBox.x2 = pSrcDrawable->x + (int) pSrcDrawable->width;
	    fastExpose = 0;
	}
	if (fastBox.y2 > pSrcDrawable->y + (int) pSrcDrawable->height)
	{
	    fastBox.y2 = pSrcDrawable->y + (int) pSrcDrawable->height;
	    fastExpose = 0;
	}
    }
    else
    {
	REGION_INIT(pGC->pScreen, &rgnDst, &fastBox, 1);
	REGION_INTERSECT(pGC->pScreen, &rgnDst, &rgnDst, prgnSrcClip);
    }

    dstx += pDstDrawable->x;
    dsty += pDstDrawable->y;

    if (pDstDrawable->type == DRAWABLE_WINDOW)
    {
	if (!((WindowPtr)pDstDrawable)->realized)
	{
	    if (!fastClip)
		REGION_UNINIT(pGC->pScreen, &rgnDst);
	    if (freeSrcClip)
		REGION_DESTROY(pGC->pScreen, prgnSrcClip);
	    return NULL;
	}
    }

    dx = srcx - dstx;
    dy = srcy - dsty;

    /* Translate and clip the dst to the destination composite clip */
    if (fastClip)
    {
	RegionPtr cclip;

        /* Translate the region directly */
        fastBox.x1 -= dx;
        fastBox.x2 -= dx;
        fastBox.y1 -= dy;
        fastBox.y2 -= dy;

	/* If the destination composite clip is one rectangle we can
	   do the clip directly.  Otherwise we have to create a full
	   blown region and call intersect */

	/* XXX because CopyPlane uses this routine for 8-to-1 bit
	 * copies, this next line *must* also correctly fetch the
	 * composite clip from an mfb gc
	 */

	cclip = cfbGetCompositeClip(pGC);
        if (REGION_NUM_RECTS(cclip) == 1)
        {
	    BoxPtr pBox = REGION_RECTS(cclip);

	    if (fastBox.x1 < pBox->x1) fastBox.x1 = pBox->x1;
	    if (fastBox.x2 > pBox->x2) fastBox.x2 = pBox->x2;
	    if (fastBox.y1 < pBox->y1) fastBox.y1 = pBox->y1;
	    if (fastBox.y2 > pBox->y2) fastBox.y2 = pBox->y2;

	    /* Check to see if the region is empty */
	    if (fastBox.x1 >= fastBox.x2 || fastBox.y1 >= fastBox.y2)
	    {
		REGION_INIT(pGC->pScreen, &rgnDst, NullBox, 0);
	    }
	    else
	    {
		REGION_INIT(pGC->pScreen, &rgnDst, &fastBox, 1);
	    }
	}
        else
	{
	    /* We must turn off fastClip now, since we must create
	       a full blown region.  It is intersected with the
	       composite clip below. */
	    fastClip = 0;
	    REGION_INIT(pGC->pScreen, &rgnDst, &fastBox,1);
	}
    }
    else
    {
        REGION_TRANSLATE(pGC->pScreen, &rgnDst, -dx, -dy);
    }

    if (!fastClip)
    {
	REGION_INTERSECT(pGC->pScreen, &rgnDst,
				   &rgnDst,
				   cfbGetCompositeClip(pGC));
    }

    /* Do bit blitting */
    numRects = REGION_NUM_RECTS(&rgnDst);
    if (numRects && width && height)
    {
	if(!(pptSrc = (DDXPointPtr)ALLOCATE_LOCAL(numRects *
						  sizeof(DDXPointRec))))
	{
	    REGION_UNINIT(pGC->pScreen, &rgnDst);
	    if (freeSrcClip)
		REGION_DESTROY(pGC->pScreen, prgnSrcClip);
	    return NULL;
	}
	pbox = REGION_RECTS(&rgnDst);
	ppt = pptSrc;
	for (i = numRects; --i >= 0; pbox++, ppt++)
	{
	    ppt->x = pbox->x1 + dx;
	    ppt->y = pbox->y1 + dy;
	}

        (*doBitBlt) (pSrcDrawable, pDstDrawable, pGC->alu, &rgnDst, pptSrc, pGC->planemask, bitPlane);
	DEALLOCATE_LOCAL(pptSrc);
    }

    prgnExposed = NULL;
    if (cfbGetGCPrivate(pGC)->fExpose)
    {
        /* Pixmap sources generate a NoExposed (we return NULL to do this) */
        if (!fastExpose)
	    prgnExposed =
		miHandleExposures(pSrcDrawable, pDstDrawable, pGC,
				  origSource.x, origSource.y,
				  (int)origSource.width,
				  (int)origSource.height,
				  origDest.x, origDest.y, bitPlane);
    }
    REGION_UNINIT(pGC->pScreen, &rgnDst);
    if (freeSrcClip)
	REGION_DESTROY(pGC->pScreen, prgnSrcClip);
    return prgnExposed;
}
void
vga256DoBitblt (pSrc, pDst, alu, prgnDst, pptSrc, planemask)
    DrawablePtr	    pSrc, pDst;
    int		    alu;
    RegionPtr	    prgnDst;
    DDXPointPtr	    pptSrc;
    unsigned long   planemask;
{
    void (*blt)(
#if NeedFunctionPrototypes
DrawablePtr,
DrawablePtr,
int,
RegionPtr,
DDXPointPtr,
unsigned long
#endif
) = vga256DoBitbltGeneral;
    if ((planemask & PMSK) == PMSK) {
	switch (alu) {
	case GXcopy:
	    blt = vga256LowlevFuncs.doBitbltCopy;
	    break;
	case GXxor:
	    blt = vga256DoBitbltXor;
	    break;
	case GXor:
	    blt = vga256DoBitbltOr;
	    break;
	}
    }
    (*blt) (pSrc, pDst, alu, prgnDst, pptSrc, planemask);
    return;
}

RegionPtr
vga256CopyArea(pSrcDrawable, pDstDrawable,
            pGC, srcx, srcy, width, height, dstx, dsty)
    register DrawablePtr pSrcDrawable;
    register DrawablePtr pDstDrawable;
    GC *pGC;
    int srcx, srcy;
    int width, height;
    int dstx, dsty;
{
    void (*localDoBitBlt)(
#if NeedFunctionPrototypes
DrawablePtr,
DrawablePtr,
int,
RegionPtr,
DDXPointPtr,
unsigned long
#endif
);
/*
    localDoBitBlt = doBitBlt ? doBitBlt : vga256LowlevFuncs.doBitbltCopy;
    doBitBlt = vga256LowlevFuncs.doBitbltCopy;

    if (localDoBitBlt == vga256LowlevFuncs.doBitbltCopy)
    {
*/
    localDoBitBlt = vga256LowlevFuncs.doBitbltCopy;
	if (pGC->alu != GXcopy || (pGC->planemask & PMSK) != PMSK)
	{
	    localDoBitBlt = vga256DoBitbltGeneral;
	    if ((pGC->planemask & PMSK) == PMSK)
	    {
		switch (pGC->alu) {
		case GXxor:
		    localDoBitBlt = vga256DoBitbltXor;
		    break;
		case GXor:
		    localDoBitBlt = vga256DoBitbltOr;
		    break;
		}
	    }
	}
/*
    }
*/

    return cfbBitBlt (pSrcDrawable, pDstDrawable,
            pGC, srcx, srcy, width, height, dstx, dsty, localDoBitBlt, 0L);
}

void
vga256CopyPlane1to8 (pSrcDrawable, pDstDrawable, rop, prgnDst, pptSrc, planemask, bitPlane)
    DrawablePtr pSrcDrawable;
    DrawablePtr pDstDrawable;
    int rop;
    RegionPtr prgnDst;
    DDXPointPtr pptSrc;
    unsigned long planemask;
    unsigned long bitPlane;
{
    int	srcx, srcy;	/* upper left corner of box being copied in source */
    int dstx, dsty;	/* upper left corner of box being copied in dest */
    int width, height;	/* in pixels, unpadded, of box being copied */
    int xoffSrc; /* bit # in leftmost word of row from which copying starts */
    int xoffDst; /* byte # in leftmost word of row from which copying starts */
    unsigned long *psrcBase, *pdstBase; /* start of drawable's pixel data */
    int	widthSrc;    /* # of groups of 32 pixels (1 bit/pixel) in src bitmap*/
    int widthDst;    /* # of groups of 4 pixels (8 bits/pixel) in dst */
    unsigned long *psrcLine, *pdstLine; /* steps a row at a time thru src/dst; 
					 * may point into middle of row */
    register unsigned long *psrc, *pdst; /* steps within the row */
    register unsigned long bits, tmp;	 /* bits from source */
    register int leftShift;
    register int rightShift;
    unsigned long startmask;		/* left edge pixel mask */
    unsigned long endmask;		/* right edge pixel mask */
    register int nlMiddle;   /* number of words in middle of the row to draw */
    register int nl;
    int firstoff;
    int secondoff;
    unsigned long src;
    int nbox;		/* number of boxes in region to copy */
    BoxPtr  pbox;	/* steps thru boxes in region */
    int pixelsRemainingOnRightEdge; /* # pixels to be drawn on a row after
				     * the main "middle" loop */

    cfbGetLongWidthAndPointer (pSrcDrawable, widthSrc, psrcBase)
    cfbGetLongWidthAndPointer (pDstDrawable, widthDst, pdstBase)

    BANK_FLAG(pdstBase)

    nbox = REGION_NUM_RECTS(prgnDst);
    pbox = REGION_RECTS(prgnDst);
    while (nbox--)
    {
	dstx = pbox->x1;
	dsty = pbox->y1;
	srcx = pptSrc->x;
	srcy = pptSrc->y;
	width = pbox->x2 - pbox->x1;
	height = pbox->y2 - pbox->y1;
	pbox++;
	pptSrc++;

	psrcLine = psrcBase + srcy * widthSrc + (srcx >> MFB_PWSH);
	pdstLine = pdstBase + dsty * widthDst + (dstx >> PWSH);
	xoffSrc = srcx & MFB_PIM; /* finds starting bit in src */
	xoffDst = dstx & PIM;  /* finds starting byte in dst */

	/* compute startmask, endmask, nlMiddle */

	if (xoffDst + width < PPW) /* XXX should this be '<= PPW' ? */
	{ /* the copy only affects one word per row in destination */
	    maskpartialbits(dstx, width, startmask);
	    endmask = 0;
	    nlMiddle = 0;
	}
	else
	{ /* the copy will affect multiple words per row in destination */
	    maskbits(dstx, width, startmask, endmask, nlMiddle);
	}

	/*
	 * compute constants for the first four bits to be
	 * copied.  This avoids troubles with partial first
	 * writes, and difficult shift computation
	 */
	if (startmask)
	{
	    firstoff = xoffSrc - xoffDst;
	    if (firstoff > (MFB_PPW-PPW))
		secondoff = MFB_PPW - firstoff;
	    if (xoffDst)
	    {
	    	srcx += (PPW-xoffDst);
	    	dstx += (PPW-xoffDst);
	    	xoffSrc = srcx & MFB_PIM;
	    }
	}
	leftShift = xoffSrc;
	rightShift = MFB_PPW - leftShift;

	pixelsRemainingOnRightEdge = (nlMiddle & 7) * PPW +
                                        ((dstx + width) & PIM);

        /* setup is done; now let's move some bits */

        /* caller must call cfb8CheckOpaqueStipple before this function
         * to set cfb8StippleRRop!
         */

	if (cfb8StippleRRop == GXcopy)
	{
	    while (height--)
	    { /* one iteration of this loop copies one row */
	    	psrc = psrcLine;
	    	pdst = pdstLine;
		SETRW(pdst);
	    	psrcLine += widthSrc;
	    	pdstLine += widthDst;
	    	bits = *psrc++;
	    	if (startmask)
	    	{
		    if (firstoff < 0)
		    	tmp = BitRight (bits, -firstoff);
		    else
		    {
		    	tmp = BitLeft (bits, firstoff);
			/*
			 * need a more cautious test for partialmask
			 * case...
			 */
		    	if (firstoff >= (MFB_PPW-PPW))
		    	{
			    bits = *psrc++;
			    if (firstoff != (MFB_PPW-PPW))
				tmp |= BitRight (bits, secondoff);
		    	}
		    }
		    *pdst = (*pdst & ~startmask) | (GetPixelGroup(tmp) & startmask);
		    pdst++;
		    CHECKRWO(pdst);
	    	}
	    	nl = nlMiddle;
	    	while (nl >= 8)
	    	{
		    nl -= 8;
		    tmp = BitLeft(bits, leftShift);
		    bits = *psrc++;
		    if (rightShift != MFB_PPW)
		    	tmp |= BitRight(bits, rightShift);

#ifdef FAST_CONSTANT_OFFSET_MODE
# define StorePixels(pdst,o,pixels)	(pdst)[o] = (pixels)
# define EndStep(pdst,o)		(pdst) += (o)
# define StoreRopPixels(pdst,o,and,xor)	(pdst)[o] = DoRRop((pdst)[o],and,xor);
#else
# define StorePixels(pdst,o,pixels)	*(pdst)++ = (pixels); CHECKRWO(pdst)
# define EndStep(pdst,o)
# define StoreRopPixels(pdst,o,and,xor)	*(pdst) = DoRRop(*(pdst),and,xor); (pdst)++; CHECKRWO(pdst);
#endif

#define Step(c)			NextBitGroup(c);
#define StoreBitsPlain(o,c)	StorePixels(pdst,o,GetPixelGroup(c))
#define StoreRopBitsPlain(o,c)	StoreRopPixels(pdst,o,\
					cfb8StippleAnd[GetBitGroup(c)], \
					cfb8StippleXor[GetBitGroup(c)])
#define StoreBits0(c)		StoreBitsPlain(0,c)
#define StoreRopBits0(c)	StoreRopBitsPlain(0,c)

#if (BITMAP_BIT_ORDER == MSBFirst)
# define StoreBits(o,c)	StoreBitsPlain(o,c)
# define StoreRopBits(o,c)  StoreRopBitsPlain(o,c)
# define FirstStep(c)	Step(c)
#else
# define StoreBits(o,c)	StorePixels(pdst,o,*((unsigned long *)\
			    (((char *) cfb8Pixels) + (c & 0x3c))))
# define StoreRopBits(o,c)  StoreRopPixels(pdst,o, \
	    *((unsigned long *) (((char *) cfb8StippleAnd) + (c & 0x3c))), \
	    *((unsigned long *) (((char *) cfb8StippleXor) + (c & 0x3c))))
# define FirstStep(c)	c = BitLeft (c, 2);
#endif

		    StoreBits0(tmp);	FirstStep(tmp);
		    StoreBits(1,tmp);	Step(tmp);
		    StoreBits(2,tmp);	Step(tmp);
		    StoreBits(3,tmp);	Step(tmp);
		    StoreBits(4,tmp);	Step(tmp);
		    StoreBits(5,tmp);	Step(tmp);
		    StoreBits(6,tmp);	Step(tmp);
		    StoreBits(7,tmp);   EndStep (pdst,8);
	    	}

                /* do rest of middle and partial word on right edge */

                if (pixelsRemainingOnRightEdge)
                {
		    tmp = BitLeft(bits, leftShift);

		    if (pixelsRemainingOnRightEdge > rightShift)
		    {
		    	bits = *psrc++;
		    	tmp |= BitRight (bits, rightShift);
		    }
		    EndStep (pdst, nl);
		    switch (nl)
		    {
		    case 7:
			StoreBitsPlain(-7,tmp);	Step(tmp);
		    case 6:
			StoreBitsPlain(-6,tmp);	Step(tmp);
		    case 5:
			StoreBitsPlain(-5,tmp);	Step(tmp);
		    case 4:
			StoreBitsPlain(-4,tmp);	Step(tmp);
		    case 3:
			StoreBitsPlain(-3,tmp);	Step(tmp);
		    case 2:
			StoreBitsPlain(-2,tmp);	Step(tmp);
		    case 1:
			StoreBitsPlain(-1,tmp);	Step(tmp);
		    }
		    if (endmask)
		    	*pdst = *pdst & ~endmask | GetPixelGroup(tmp) & endmask;
	    	}
	    }
	}
	else /* cfb8StippleRRop != GXcopy */
	{
	    while (height--)
	    { /* one iteration of this loop copies one row */
	    	psrc = psrcLine;
	    	pdst = pdstLine;
		SETRW(pdst);
	    	psrcLine += widthSrc;
	    	pdstLine += widthDst;
	    	bits = *psrc++;

                /* do partial word on left edge */

	    	if (startmask)
	    	{
		    if (firstoff < 0)
		    	tmp = BitRight (bits, -firstoff);
		    else
		    {
		    	tmp = BitLeft (bits, firstoff);
		    	if (firstoff >= (MFB_PPW-PPW))
		    	{
			    bits = *psrc++;
			    if (firstoff != (MFB_PPW-PPW))
				tmp |= BitRight (bits, secondoff);
		    	}
		    }
		    src = GetBitGroup(tmp);
		    *pdst = MaskRRopPixels (*pdst, src, startmask);
		    pdst++;
		    CHECKRWO(pdst);
	    	}

                /* do middle of row */

	    	nl = nlMiddle;
		while (nl >= 8)
		{
		    nl -= 8;
		    tmp = BitLeft(bits, leftShift);
		    bits = *psrc++;
		    if (rightShift != MFB_PPW)
			tmp |= BitRight(bits, rightShift);
		    StoreRopBits0(tmp);	FirstStep(tmp);
		    StoreRopBits(1,tmp);	Step(tmp);
		    StoreRopBits(2,tmp);	Step(tmp);
		    StoreRopBits(3,tmp);	Step(tmp);
		    StoreRopBits(4,tmp);	Step(tmp);
		    StoreRopBits(5,tmp);	Step(tmp);
		    StoreRopBits(6,tmp);	Step(tmp);
		    StoreRopBits(7,tmp);	EndStep(pdst,8);
		}

                /* do rest of middle and partial word on right edge */

                if (pixelsRemainingOnRightEdge)
                {
		    tmp = BitLeft(bits, leftShift);

		    if (pixelsRemainingOnRightEdge > rightShift)
		    {
		    	bits = *psrc++;
		    	tmp |= BitRight (bits, rightShift);
		    }
		    while (nl--)
		    {
			src = GetBitGroup (tmp);
			*pdst = RRopPixels (*pdst, src);
		    	pdst++;
			CHECKRWO(pdst);
			NextBitGroup(tmp);
		    }
		    if (endmask)
		    {
			src = GetBitGroup (tmp);
			*pdst = MaskRRopPixels (*pdst, src, endmask);
		    }
	    	}
	    } /* end copy one row */
	} /* end alu is non-copy-mode case */
    } /* end iteration over region boxes */
}


RegionPtr vga256CopyPlane(pSrcDrawable, pDstDrawable,
	    pGC, srcx, srcy, width, height, dstx, dsty, bitPlane)
    DrawablePtr 	pSrcDrawable;
    DrawablePtr		pDstDrawable;
    GCPtr		pGC;
    int 		srcx, srcy;
    int 		width, height;
    int 		dstx, dsty;
    unsigned long	bitPlane;
{
    RegionPtr	ret;

    /*
     * If nothing is going to touch the frame buffer, then just use
     * the regular cfb routines. They should be faster.
     */
    if ( (pSrcDrawable->type != DRAWABLE_WINDOW) &&
	 (pDstDrawable->type != DRAWABLE_WINDOW))
	return cfbCopyPlane(pSrcDrawable, pDstDrawable,
            			pGC, srcx, srcy, width, height,
				dstx, dsty, bitPlane);

    if (pSrcDrawable->bitsPerPixel == 1 && pDstDrawable->bitsPerPixel == 8)
    {
    	if (bitPlane == 1)
	{
	    cfb8CheckOpaqueStipple (pGC->alu,
				    pGC->fgPixel, pGC->bgPixel,
				    pGC->planemask);
    	    ret = cfbBitBlt (pSrcDrawable, pDstDrawable,
	    	    pGC, srcx, srcy, width, height, dstx, dsty,
		    vga256LowlevFuncs.copyPlane1to8, bitPlane);
	}
	else
	    ret = miHandleExposures (pSrcDrawable, pDstDrawable,
	    	pGC, srcx, srcy, width, height, dstx, dsty, bitPlane);
    }
    else if (pSrcDrawable->bitsPerPixel == 8 && pDstDrawable->bitsPerPixel == 1)
    {
	extern	int InverseAlu[16];
	int oldalu;

	oldalu = pGC->alu;
    	if ((pGC->fgPixel & 1) == 0 && (pGC->bgPixel&1) == 1)
	    pGC->alu = InverseAlu[pGC->alu];
    	else if ((pGC->fgPixel & 1) == (pGC->bgPixel & 1))
	    pGC->alu = mfbReduceRop(pGC->alu, pGC->fgPixel);
	ret = cfbBitBlt (pSrcDrawable, pDstDrawable,
		    	    pGC, srcx, srcy, width, height, dstx, dsty,
			    vga256CopyPlane8to1, bitPlane);
	pGC->alu = oldalu;
    }
    else if (pSrcDrawable->bitsPerPixel == 8 && pDstDrawable->bitsPerPixel == 8)
    {
	PixmapPtr	pBitmap;
	ScreenPtr	pScreen = pSrcDrawable->pScreen;
	GCPtr		pGC1;

	pBitmap = (*pScreen->CreatePixmap) (pScreen, width, height, 1);
	if (!pBitmap)
	    return NULL;
	pGC1 = GetScratchGC (1, pScreen);
	if (!pGC1)
	{
	    (*pScreen->DestroyPixmap) (pBitmap);
	    return NULL;
	}
	/*
	 * don't need to set pGC->fgPixel,bgPixel as copyPlane8to1
	 * ignores pixel values, expecting the rop to "do the
	 * right thing", which GXcopy will.
	 */
	ValidateGC ((DrawablePtr) pBitmap, pGC1);
	/* no exposures here, scratch GC's don't get graphics expose */
	cfbBitBlt (pSrcDrawable, (DrawablePtr) pBitmap,
		      pGC1, srcx, srcy, width, height, 0, 0,
		      vga256CopyPlane8to1, bitPlane);
	cfb8CheckOpaqueStipple (pGC->alu,
				pGC->fgPixel, pGC->bgPixel,
				pGC->planemask);
	/* no exposures here, copy bits from inside a pixmap */
	cfbBitBlt ((DrawablePtr) pBitmap, pDstDrawable, pGC,
			0, 0, width, height, dstx, dsty,
			vga256LowlevFuncs.copyPlane1to8, 1L);
	FreeScratchGC (pGC1);
	(*pScreen->DestroyPixmap) (pBitmap);
	/* compute resultant exposures */
	ret = miHandleExposures (pSrcDrawable, pDstDrawable, pGC,
				 srcx, srcy, width, height,
				 dstx, dsty, bitPlane);
    }
    else
	ErrorF( "vga256CopyPlane(). Unhandled combinations of bitsPerPixel\n");
    return ret;
}
