mibitblt.c revision 4642e01f
105b261ecSmrg/***********************************************************
205b261ecSmrg
305b261ecSmrgCopyright 1987, 1998  The Open Group
405b261ecSmrg
505b261ecSmrgPermission to use, copy, modify, distribute, and sell this software and its
605b261ecSmrgdocumentation for any purpose is hereby granted without fee, provided that
705b261ecSmrgthe above copyright notice appear in all copies and that both that
805b261ecSmrgcopyright notice and this permission notice appear in supporting
905b261ecSmrgdocumentation.
1005b261ecSmrg
1105b261ecSmrgThe above copyright notice and this permission notice shall be included in
1205b261ecSmrgall copies or substantial portions of the Software.
1305b261ecSmrg
1405b261ecSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1505b261ecSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1605b261ecSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
1705b261ecSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
1805b261ecSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1905b261ecSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2005b261ecSmrg
2105b261ecSmrgExcept as contained in this notice, the name of The Open Group shall not be
2205b261ecSmrgused in advertising or otherwise to promote the sale, use or other dealings
2305b261ecSmrgin this Software without prior written authorization from The Open Group.
2405b261ecSmrg
2505b261ecSmrg
2605b261ecSmrgCopyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
2705b261ecSmrg
2805b261ecSmrg                        All Rights Reserved
2905b261ecSmrg
3005b261ecSmrgPermission to use, copy, modify, and distribute this software and its
3105b261ecSmrgdocumentation for any purpose and without fee is hereby granted,
3205b261ecSmrgprovided that the above copyright notice appear in all copies and that
3305b261ecSmrgboth that copyright notice and this permission notice appear in
3405b261ecSmrgsupporting documentation, and that the name of Digital not be
3505b261ecSmrgused in advertising or publicity pertaining to distribution of the
3605b261ecSmrgsoftware without specific, written prior permission.
3705b261ecSmrg
3805b261ecSmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
3905b261ecSmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
4005b261ecSmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
4105b261ecSmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
4205b261ecSmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
4305b261ecSmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
4405b261ecSmrgSOFTWARE.
4505b261ecSmrg
4605b261ecSmrg******************************************************************/
4705b261ecSmrg/* Author: Todd Newman  (aided and abetted by Mr. Drewry) */
4805b261ecSmrg
4905b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
5005b261ecSmrg#include <dix-config.h>
5105b261ecSmrg#endif
5205b261ecSmrg
5305b261ecSmrg#include <X11/X.h>
5405b261ecSmrg#include <X11/Xprotostr.h>
5505b261ecSmrg
5605b261ecSmrg#include "misc.h"
5705b261ecSmrg#include "gcstruct.h"
5805b261ecSmrg#include "pixmapstr.h"
5905b261ecSmrg#include "windowstr.h"
6005b261ecSmrg#include "scrnintstr.h"
6105b261ecSmrg#include "mi.h"
6205b261ecSmrg#include "regionstr.h"
6305b261ecSmrg#include <X11/Xmd.h>
6405b261ecSmrg#include "servermd.h"
6505b261ecSmrg
6605b261ecSmrg#ifndef HAS_FFS
6705b261ecSmrgextern int ffs(int);
6805b261ecSmrg#endif
6905b261ecSmrg
7005b261ecSmrg/* MICOPYAREA -- public entry for the CopyArea request
7105b261ecSmrg * For each rectangle in the source region
7205b261ecSmrg *     get the pixels with GetSpans
7305b261ecSmrg *     set them in the destination with SetSpans
7405b261ecSmrg * We let SetSpans worry about clipping to the destination.
7505b261ecSmrg */
764642e01fSmrgRegionPtr
774642e01fSmrgmiCopyArea(DrawablePtr  pSrcDrawable,
784642e01fSmrg           DrawablePtr  pDstDrawable,
794642e01fSmrg           GCPtr        pGC,
804642e01fSmrg           int          xIn,
814642e01fSmrg           int          yIn,
824642e01fSmrg           int          widthSrc,
834642e01fSmrg           int          heightSrc,
844642e01fSmrg           int          xOut,
854642e01fSmrg           int          yOut)
8605b261ecSmrg{
8705b261ecSmrg    DDXPointPtr		ppt, pptFirst;
8805b261ecSmrg    unsigned int	*pwidthFirst, *pwidth, *pbits;
8905b261ecSmrg    BoxRec 		srcBox, *prect;
9005b261ecSmrg    			/* may be a new region, or just a copy */
9105b261ecSmrg    RegionPtr 		prgnSrcClip;
9205b261ecSmrg    			/* non-0 if we've created a src clip */
9305b261ecSmrg    RegionPtr		prgnExposed;
9405b261ecSmrg    int 		realSrcClip = 0;
9505b261ecSmrg    int			srcx, srcy, dstx, dsty, i, j, y, width, height,
9605b261ecSmrg    			xMin, xMax, yMin, yMax;
9705b261ecSmrg    unsigned int	*ordering;
9805b261ecSmrg    int			numRects;
9905b261ecSmrg    BoxPtr		boxes;
10005b261ecSmrg
10105b261ecSmrg    srcx = xIn + pSrcDrawable->x;
10205b261ecSmrg    srcy = yIn + pSrcDrawable->y;
10305b261ecSmrg
10405b261ecSmrg    /* If the destination isn't realized, this is easy */
10505b261ecSmrg    if (pDstDrawable->type == DRAWABLE_WINDOW &&
10605b261ecSmrg	!((WindowPtr)pDstDrawable)->realized)
10705b261ecSmrg	return (RegionPtr)NULL;
10805b261ecSmrg
10905b261ecSmrg    /* clip the source */
11005b261ecSmrg    if (pSrcDrawable->type == DRAWABLE_PIXMAP)
11105b261ecSmrg    {
11205b261ecSmrg	BoxRec box;
11305b261ecSmrg
11405b261ecSmrg	box.x1 = pSrcDrawable->x;
11505b261ecSmrg	box.y1 = pSrcDrawable->y;
11605b261ecSmrg	box.x2 = pSrcDrawable->x + (int) pSrcDrawable->width;
11705b261ecSmrg	box.y2 = pSrcDrawable->y + (int) pSrcDrawable->height;
11805b261ecSmrg
11905b261ecSmrg	prgnSrcClip = REGION_CREATE(pGC->pScreen, &box, 1);
12005b261ecSmrg	realSrcClip = 1;
12105b261ecSmrg    }
12205b261ecSmrg    else
12305b261ecSmrg    {
12405b261ecSmrg	if (pGC->subWindowMode == IncludeInferiors) {
12505b261ecSmrg	    prgnSrcClip = NotClippedByChildren ((WindowPtr) pSrcDrawable);
12605b261ecSmrg	    realSrcClip = 1;
12705b261ecSmrg	} else
12805b261ecSmrg	    prgnSrcClip = &((WindowPtr)pSrcDrawable)->clipList;
12905b261ecSmrg    }
13005b261ecSmrg
13105b261ecSmrg    /* If the src drawable is a window, we need to translate the srcBox so
13205b261ecSmrg     * that we can compare it with the window's clip region later on. */
13305b261ecSmrg    srcBox.x1 = srcx;
13405b261ecSmrg    srcBox.y1 = srcy;
13505b261ecSmrg    srcBox.x2 = srcx  + widthSrc;
13605b261ecSmrg    srcBox.y2 = srcy  + heightSrc;
13705b261ecSmrg
13805b261ecSmrg    dstx = xOut;
13905b261ecSmrg    dsty = yOut;
14005b261ecSmrg    if (pGC->miTranslate)
14105b261ecSmrg    {
14205b261ecSmrg	dstx += pDstDrawable->x;
14305b261ecSmrg	dsty += pDstDrawable->y;
14405b261ecSmrg    }
14505b261ecSmrg
14605b261ecSmrg    pptFirst = ppt = (DDXPointPtr)
1474642e01fSmrg        xalloc(heightSrc * sizeof(DDXPointRec));
14805b261ecSmrg    pwidthFirst = pwidth = (unsigned int *)
1494642e01fSmrg        xalloc(heightSrc * sizeof(unsigned int));
15005b261ecSmrg    numRects = REGION_NUM_RECTS(prgnSrcClip);
15105b261ecSmrg    boxes = REGION_RECTS(prgnSrcClip);
15205b261ecSmrg    ordering = (unsigned int *)
1534642e01fSmrg        xalloc(numRects * sizeof(unsigned int));
15405b261ecSmrg    if(!pptFirst || !pwidthFirst || !ordering)
15505b261ecSmrg    {
15605b261ecSmrg       if (ordering)
1574642e01fSmrg	   xfree(ordering);
15805b261ecSmrg       if (pwidthFirst)
1594642e01fSmrg           xfree(pwidthFirst);
16005b261ecSmrg       if (pptFirst)
1614642e01fSmrg           xfree(pptFirst);
16205b261ecSmrg       return (RegionPtr)NULL;
16305b261ecSmrg    }
16405b261ecSmrg
16505b261ecSmrg    /* If not the same drawable then order of move doesn't matter.
16605b261ecSmrg       Following assumes that boxes are sorted from top
16705b261ecSmrg       to bottom and left to right.
16805b261ecSmrg    */
16905b261ecSmrg    if ((pSrcDrawable != pDstDrawable) &&
17005b261ecSmrg	((pGC->subWindowMode != IncludeInferiors) ||
17105b261ecSmrg	 (pSrcDrawable->type == DRAWABLE_PIXMAP) ||
17205b261ecSmrg	 (pDstDrawable->type == DRAWABLE_PIXMAP)))
17305b261ecSmrg      for (i=0; i < numRects; i++)
17405b261ecSmrg        ordering[i] = i;
17505b261ecSmrg    else { /* within same drawable, must sequence moves carefully! */
17605b261ecSmrg      if (dsty <= srcBox.y1) { /* Scroll up or stationary vertical.
17705b261ecSmrg                                  Vertical order OK */
17805b261ecSmrg        if (dstx <= srcBox.x1) /* Scroll left or stationary horizontal.
17905b261ecSmrg                                  Horizontal order OK as well */
18005b261ecSmrg          for (i=0; i < numRects; i++)
18105b261ecSmrg            ordering[i] = i;
18205b261ecSmrg        else { /* scroll right. must reverse horizontal banding of rects. */
18305b261ecSmrg          for (i=0, j=1, xMax=0; i < numRects; j=i+1, xMax=i) {
18405b261ecSmrg            /* find extent of current horizontal band */
18505b261ecSmrg            y=boxes[i].y1; /* band has this y coordinate */
18605b261ecSmrg            while ((j < numRects) && (boxes[j].y1 == y))
18705b261ecSmrg              j++;
18805b261ecSmrg            /* reverse the horizontal band in the output ordering */
18905b261ecSmrg            for (j-- ; j >= xMax; j--, i++)
19005b261ecSmrg              ordering[i] = j;
19105b261ecSmrg          }
19205b261ecSmrg        }
19305b261ecSmrg      }
19405b261ecSmrg      else { /* Scroll down. Must reverse vertical banding. */
19505b261ecSmrg        if (dstx < srcBox.x1) { /* Scroll left. Horizontal order OK. */
19605b261ecSmrg          for (i=numRects-1, j=i-1, yMin=i, yMax=0;
19705b261ecSmrg              i >= 0;
19805b261ecSmrg              j=i-1, yMin=i) {
19905b261ecSmrg            /* find extent of current horizontal band */
20005b261ecSmrg            y=boxes[i].y1; /* band has this y coordinate */
20105b261ecSmrg            while ((j >= 0) && (boxes[j].y1 == y))
20205b261ecSmrg              j--;
20305b261ecSmrg            /* reverse the horizontal band in the output ordering */
20405b261ecSmrg            for (j++ ; j <= yMin; j++, i--, yMax++)
20505b261ecSmrg              ordering[yMax] = j;
20605b261ecSmrg          }
20705b261ecSmrg        }
20805b261ecSmrg        else /* Scroll right or horizontal stationary.
20905b261ecSmrg                Reverse horizontal order as well (if stationary, horizontal
21005b261ecSmrg                order can be swapped without penalty and this is faster
21105b261ecSmrg                to compute). */
21205b261ecSmrg          for (i=0, j=numRects-1; i < numRects; i++, j--)
21305b261ecSmrg              ordering[i] = j;
21405b261ecSmrg      }
21505b261ecSmrg    }
21605b261ecSmrg
21705b261ecSmrg     for(i = 0; i < numRects; i++)
21805b261ecSmrg     {
21905b261ecSmrg        prect = &boxes[ordering[i]];
22005b261ecSmrg  	xMin = max(prect->x1, srcBox.x1);
22105b261ecSmrg  	xMax = min(prect->x2, srcBox.x2);
22205b261ecSmrg  	yMin = max(prect->y1, srcBox.y1);
22305b261ecSmrg	yMax = min(prect->y2, srcBox.y2);
22405b261ecSmrg	/* is there anything visible here? */
22505b261ecSmrg	if(xMax <= xMin || yMax <= yMin)
22605b261ecSmrg	    continue;
22705b261ecSmrg
22805b261ecSmrg        ppt = pptFirst;
22905b261ecSmrg	pwidth = pwidthFirst;
23005b261ecSmrg	y = yMin;
23105b261ecSmrg	height = yMax - yMin;
23205b261ecSmrg	width = xMax - xMin;
23305b261ecSmrg
23405b261ecSmrg	for(j = 0; j < height; j++)
23505b261ecSmrg	{
23605b261ecSmrg	    /* We must untranslate before calling GetSpans */
23705b261ecSmrg	    ppt->x = xMin;
23805b261ecSmrg	    ppt++->y = y++;
23905b261ecSmrg	    *pwidth++ = width;
24005b261ecSmrg	}
24105b261ecSmrg	pbits = (unsigned int *)xalloc(height * PixmapBytePad(width,
24205b261ecSmrg					     pSrcDrawable->depth));
24305b261ecSmrg	if (pbits)
24405b261ecSmrg	{
24505b261ecSmrg	    (*pSrcDrawable->pScreen->GetSpans)(pSrcDrawable, width, pptFirst,
24605b261ecSmrg			(int *)pwidthFirst, height, (char *)pbits);
24705b261ecSmrg	    ppt = pptFirst;
24805b261ecSmrg	    pwidth = pwidthFirst;
24905b261ecSmrg	    xMin -= (srcx - dstx);
25005b261ecSmrg	    y = yMin - (srcy - dsty);
25105b261ecSmrg	    for(j = 0; j < height; j++)
25205b261ecSmrg	    {
25305b261ecSmrg		ppt->x = xMin;
25405b261ecSmrg		ppt++->y = y++;
25505b261ecSmrg		*pwidth++ = width;
25605b261ecSmrg	    }
25705b261ecSmrg
25805b261ecSmrg	    (*pGC->ops->SetSpans)(pDstDrawable, pGC, (char *)pbits, pptFirst,
25905b261ecSmrg				  (int *)pwidthFirst, height, TRUE);
26005b261ecSmrg	    xfree(pbits);
26105b261ecSmrg	}
26205b261ecSmrg    }
26305b261ecSmrg    prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC, xIn, yIn,
26405b261ecSmrg		      widthSrc, heightSrc, xOut, yOut, (unsigned long)0);
26505b261ecSmrg    if(realSrcClip)
26605b261ecSmrg	REGION_DESTROY(pGC->pScreen, prgnSrcClip);
26705b261ecSmrg
2684642e01fSmrg    xfree(ordering);
2694642e01fSmrg    xfree(pwidthFirst);
2704642e01fSmrg    xfree(pptFirst);
27105b261ecSmrg    return prgnExposed;
27205b261ecSmrg}
27305b261ecSmrg
27405b261ecSmrg/* MIGETPLANE -- gets a bitmap representing one plane of pDraw
27505b261ecSmrg * A helper used for CopyPlane and XY format GetImage
27605b261ecSmrg * No clever strategy here, we grab a scanline at a time, pull out the
27705b261ecSmrg * bits and then stuff them in a 1 bit deep map.
27805b261ecSmrg */
27905b261ecSmrg/*
28005b261ecSmrg * This should be replaced with something more general.  mi shouldn't have to
28105b261ecSmrg * care about such things as scanline padding et alia.
28205b261ecSmrg */
28305b261ecSmrgstatic
28405b261ecSmrgMiBits	*
28505b261ecSmrgmiGetPlane(
28605b261ecSmrg    DrawablePtr		pDraw,
28705b261ecSmrg    int			planeNum,	/* number of the bitPlane */
28805b261ecSmrg    int			sx,
28905b261ecSmrg    int			sy,
29005b261ecSmrg    int			w,
29105b261ecSmrg    int			h,
29205b261ecSmrg    MiBits	*result)
29305b261ecSmrg{
29405b261ecSmrg    int			i, j, k, width, bitsPerPixel, widthInBytes;
29505b261ecSmrg    DDXPointRec 	pt = {0, 0};
29605b261ecSmrg    MiBits	pixel;
29705b261ecSmrg    MiBits	bit;
29805b261ecSmrg    unsigned char	*pCharsOut = NULL;
29905b261ecSmrg
30005b261ecSmrg#if BITMAP_SCANLINE_UNIT == 8
30105b261ecSmrg#define OUT_TYPE unsigned char
30205b261ecSmrg#endif
30305b261ecSmrg#if BITMAP_SCANLINE_UNIT == 16
30405b261ecSmrg#define OUT_TYPE CARD16
30505b261ecSmrg#endif
30605b261ecSmrg#if BITMAP_SCANLINE_UNIT == 32
30705b261ecSmrg#define OUT_TYPE CARD32
30805b261ecSmrg#endif
30905b261ecSmrg#if BITMAP_SCANLINE_UNIT == 64
31005b261ecSmrg#define OUT_TYPE CARD64
31105b261ecSmrg#endif
31205b261ecSmrg
31305b261ecSmrg    OUT_TYPE		*pOut;
31405b261ecSmrg    int			delta = 0;
31505b261ecSmrg
31605b261ecSmrg    sx += pDraw->x;
31705b261ecSmrg    sy += pDraw->y;
31805b261ecSmrg    widthInBytes = BitmapBytePad(w);
31905b261ecSmrg    if(!result)
3204642e01fSmrg        result = xcalloc(h, widthInBytes);
32105b261ecSmrg    if (!result)
32205b261ecSmrg	return (MiBits *)NULL;
32305b261ecSmrg    bitsPerPixel = pDraw->bitsPerPixel;
32405b261ecSmrg    pOut = (OUT_TYPE *) result;
32505b261ecSmrg    if(bitsPerPixel == 1)
32605b261ecSmrg    {
32705b261ecSmrg	pCharsOut = (unsigned char *) result;
32805b261ecSmrg    	width = w;
32905b261ecSmrg    }
33005b261ecSmrg    else
33105b261ecSmrg    {
33205b261ecSmrg	delta = (widthInBytes / (BITMAP_SCANLINE_UNIT / 8)) -
33305b261ecSmrg	    (w / BITMAP_SCANLINE_UNIT);
33405b261ecSmrg	width = 1;
33505b261ecSmrg#if IMAGE_BYTE_ORDER == MSBFirst
33605b261ecSmrg	planeNum += (32 - bitsPerPixel);
33705b261ecSmrg#endif
33805b261ecSmrg    }
33905b261ecSmrg    pt.y = sy;
34005b261ecSmrg    for (i = h; --i >= 0; pt.y++)
34105b261ecSmrg    {
34205b261ecSmrg	pt.x = sx;
34305b261ecSmrg	if(bitsPerPixel == 1)
34405b261ecSmrg	{
34505b261ecSmrg	    (*pDraw->pScreen->GetSpans)(pDraw, width, &pt, &width, 1,
34605b261ecSmrg					(char *)pCharsOut);
34705b261ecSmrg	    pCharsOut += widthInBytes;
34805b261ecSmrg	}
34905b261ecSmrg	else
35005b261ecSmrg	{
35105b261ecSmrg	    k = 0;
35205b261ecSmrg	    for(j = w; --j >= 0; pt.x++)
35305b261ecSmrg	    {
35405b261ecSmrg		/* Fetch the next pixel */
35505b261ecSmrg		(*pDraw->pScreen->GetSpans)(pDraw, width, &pt, &width, 1,
35605b261ecSmrg					    (char *)&pixel);
35705b261ecSmrg		/*
35805b261ecSmrg		 * Now get the bit and insert into a bitmap in XY format.
35905b261ecSmrg		 */
36005b261ecSmrg		bit = (pixel >> planeNum) & 1;
36105b261ecSmrg#if 0
36205b261ecSmrg		/* XXX assuming bit order == byte order */
36305b261ecSmrg#if BITMAP_BIT_ORDER == LSBFirst
36405b261ecSmrg		bit <<= k;
36505b261ecSmrg#else
36605b261ecSmrg		bit <<= ((BITMAP_SCANLINE_UNIT - 1) - k);
36705b261ecSmrg#endif
36805b261ecSmrg#else
36905b261ecSmrg		/* XXX assuming byte order == LSBFirst */
37005b261ecSmrg		if (screenInfo.bitmapBitOrder == LSBFirst)
37105b261ecSmrg			bit <<= k;
37205b261ecSmrg		else
37305b261ecSmrg			bit <<= ((screenInfo.bitmapScanlineUnit - 1) -
37405b261ecSmrg				 (k % screenInfo.bitmapScanlineUnit)) +
37505b261ecSmrg				((k / screenInfo.bitmapScanlineUnit) *
37605b261ecSmrg				 screenInfo.bitmapScanlineUnit);
37705b261ecSmrg#endif
37805b261ecSmrg		*pOut |= (OUT_TYPE) bit;
37905b261ecSmrg		k++;
38005b261ecSmrg		if (k == BITMAP_SCANLINE_UNIT)
38105b261ecSmrg		{
38205b261ecSmrg		    pOut++;
38305b261ecSmrg		    k = 0;
38405b261ecSmrg		}
38505b261ecSmrg	    }
38605b261ecSmrg	    pOut += delta;
38705b261ecSmrg	}
38805b261ecSmrg    }
38905b261ecSmrg    return(result);
39005b261ecSmrg
39105b261ecSmrg}
39205b261ecSmrg
39305b261ecSmrg/* MIOPQSTIPDRAWABLE -- use pbits as an opaque stipple for pDraw.
39405b261ecSmrg * Drawing through the clip mask we SetSpans() the bits into a
39505b261ecSmrg * bitmap and stipple those bits onto the destination drawable by doing a
39605b261ecSmrg * PolyFillRect over the whole drawable,
39705b261ecSmrg * then we invert the bitmap by copying it onto itself with an alu of
39805b261ecSmrg * GXinvert, invert the foreground/background colors of the gc, and draw
39905b261ecSmrg * the background bits.
40005b261ecSmrg * Note how the clipped out bits of the bitmap are always the background
40105b261ecSmrg * color so that the stipple never causes FillRect to draw them.
40205b261ecSmrg */
40305b261ecSmrgstatic void
40405b261ecSmrgmiOpqStipDrawable(DrawablePtr pDraw, GCPtr pGC, RegionPtr prgnSrc,
40505b261ecSmrg		  MiBits *pbits, int srcx, int w, int h, int dstx, int dsty)
40605b261ecSmrg{
40705b261ecSmrg    int		oldfill, i;
40805b261ecSmrg    unsigned long oldfg;
40905b261ecSmrg    int		*pwidth, *pwidthFirst;
41005b261ecSmrg    ChangeGCVal	gcv[6];
41105b261ecSmrg    PixmapPtr	pStipple, pPixmap;
41205b261ecSmrg    DDXPointRec	oldOrg;
41305b261ecSmrg    GCPtr	pGCT;
41405b261ecSmrg    DDXPointPtr ppt, pptFirst;
41505b261ecSmrg    xRectangle rect;
41605b261ecSmrg    RegionPtr	prgnSrcClip;
41705b261ecSmrg
41805b261ecSmrg    pPixmap = (*pDraw->pScreen->CreatePixmap)
4194642e01fSmrg			   (pDraw->pScreen, w + srcx, h, 1,
4204642e01fSmrg			    CREATE_PIXMAP_USAGE_SCRATCH);
42105b261ecSmrg    if (!pPixmap)
42205b261ecSmrg	return;
42305b261ecSmrg
42405b261ecSmrg    /* Put the image into a 1 bit deep pixmap */
42505b261ecSmrg    pGCT = GetScratchGC(1, pDraw->pScreen);
42605b261ecSmrg    if (!pGCT)
42705b261ecSmrg    {
42805b261ecSmrg	(*pDraw->pScreen->DestroyPixmap)(pPixmap);
42905b261ecSmrg	return;
43005b261ecSmrg    }
43105b261ecSmrg    /* First set the whole pixmap to 0 */
43205b261ecSmrg    gcv[0].val = 0;
43305b261ecSmrg    dixChangeGC(NullClient, pGCT, GCBackground, NULL, gcv);
43405b261ecSmrg    ValidateGC((DrawablePtr)pPixmap, pGCT);
43505b261ecSmrg    miClearDrawable((DrawablePtr)pPixmap, pGCT);
4364642e01fSmrg    ppt = pptFirst = (DDXPointPtr)xalloc(h * sizeof(DDXPointRec));
4374642e01fSmrg    pwidth = pwidthFirst = (int *)xalloc(h * sizeof(int));
43805b261ecSmrg    if(!pptFirst || !pwidthFirst)
43905b261ecSmrg    {
4404642e01fSmrg	if (pwidthFirst) xfree(pwidthFirst);
4414642e01fSmrg	if (pptFirst) xfree(pptFirst);
44205b261ecSmrg	FreeScratchGC(pGCT);
44305b261ecSmrg	return;
44405b261ecSmrg    }
44505b261ecSmrg
44605b261ecSmrg    /* we need a temporary region because ChangeClip must be assumed
44705b261ecSmrg       to destroy what it's sent.  note that this means we don't
44805b261ecSmrg       have to free prgnSrcClip ourselves.
44905b261ecSmrg    */
45005b261ecSmrg    prgnSrcClip = REGION_CREATE(pGCT->pScreen, NULL, 0);
45105b261ecSmrg    REGION_COPY(pGCT->pScreen, prgnSrcClip, prgnSrc);
45205b261ecSmrg    REGION_TRANSLATE(pGCT->pScreen, prgnSrcClip, srcx, 0);
45305b261ecSmrg    (*pGCT->funcs->ChangeClip)(pGCT, CT_REGION, prgnSrcClip, 0);
45405b261ecSmrg    ValidateGC((DrawablePtr)pPixmap, pGCT);
45505b261ecSmrg
45605b261ecSmrg    /* Since we know pDraw is always a pixmap, we never need to think
45705b261ecSmrg     * about translation here */
45805b261ecSmrg    for(i = 0; i < h; i++)
45905b261ecSmrg    {
46005b261ecSmrg	ppt->x = 0;
46105b261ecSmrg	ppt++->y = i;
46205b261ecSmrg	*pwidth++ = w + srcx;
46305b261ecSmrg    }
46405b261ecSmrg
46505b261ecSmrg    (*pGCT->ops->SetSpans)((DrawablePtr)pPixmap, pGCT, (char *)pbits,
46605b261ecSmrg			   pptFirst, pwidthFirst, h, TRUE);
4674642e01fSmrg    xfree(pwidthFirst);
4684642e01fSmrg    xfree(pptFirst);
46905b261ecSmrg
47005b261ecSmrg
47105b261ecSmrg    /* Save current values from the client GC */
47205b261ecSmrg    oldfill = pGC->fillStyle;
47305b261ecSmrg    pStipple = pGC->stipple;
47405b261ecSmrg    if(pStipple)
47505b261ecSmrg        pStipple->refcnt++;
47605b261ecSmrg    oldOrg = pGC->patOrg;
47705b261ecSmrg
47805b261ecSmrg    /* Set a new stipple in the drawable */
47905b261ecSmrg    gcv[0].val = FillStippled;
48005b261ecSmrg    gcv[1].ptr = pPixmap;
48105b261ecSmrg    gcv[2].val = dstx - srcx;
48205b261ecSmrg    gcv[3].val = dsty;
48305b261ecSmrg
48405b261ecSmrg    dixChangeGC(NullClient, pGC,
48505b261ecSmrg             GCFillStyle | GCStipple | GCTileStipXOrigin | GCTileStipYOrigin,
48605b261ecSmrg	     NULL, gcv);
48705b261ecSmrg    ValidateGC(pDraw, pGC);
48805b261ecSmrg
48905b261ecSmrg    /* Fill the drawable with the stipple.  This will draw the
49005b261ecSmrg     * foreground color whereever 1 bits are set, leaving everything
49105b261ecSmrg     * with 0 bits untouched.  Note that the part outside the clip
49205b261ecSmrg     * region is all 0s.  */
49305b261ecSmrg    rect.x = dstx;
49405b261ecSmrg    rect.y = dsty;
49505b261ecSmrg    rect.width = w;
49605b261ecSmrg    rect.height = h;
49705b261ecSmrg    (*pGC->ops->PolyFillRect)(pDraw, pGC, 1, &rect);
49805b261ecSmrg
49905b261ecSmrg    /* Invert the tiling pixmap. This sets 0s for 1s and 1s for 0s, only
50005b261ecSmrg     * within the clipping region, the part outside is still all 0s */
50105b261ecSmrg    gcv[0].val = GXinvert;
50205b261ecSmrg    dixChangeGC(NullClient, pGCT, GCFunction, NULL, gcv);
50305b261ecSmrg    ValidateGC((DrawablePtr)pPixmap, pGCT);
50405b261ecSmrg    (*pGCT->ops->CopyArea)((DrawablePtr)pPixmap, (DrawablePtr)pPixmap,
50505b261ecSmrg			   pGCT, 0, 0, w + srcx, h, 0, 0);
50605b261ecSmrg
50705b261ecSmrg    /* Swap foreground and background colors on the GC for the drawable.
50805b261ecSmrg     * Now when we fill the drawable, we will fill in the "Background"
50905b261ecSmrg     * values */
51005b261ecSmrg    oldfg = pGC->fgPixel;
51105b261ecSmrg    gcv[0].val = pGC->bgPixel;
51205b261ecSmrg    gcv[1].val = oldfg;
51305b261ecSmrg    gcv[2].ptr = pPixmap;
51405b261ecSmrg    dixChangeGC(NullClient, pGC, GCForeground | GCBackground | GCStipple,
51505b261ecSmrg		NULL, gcv);
51605b261ecSmrg    ValidateGC(pDraw, pGC);
51705b261ecSmrg    /* PolyFillRect might have bashed the rectangle */
51805b261ecSmrg    rect.x = dstx;
51905b261ecSmrg    rect.y = dsty;
52005b261ecSmrg    rect.width = w;
52105b261ecSmrg    rect.height = h;
52205b261ecSmrg    (*pGC->ops->PolyFillRect)(pDraw, pGC, 1, &rect);
52305b261ecSmrg
52405b261ecSmrg    /* Now put things back */
52505b261ecSmrg    if(pStipple)
52605b261ecSmrg        pStipple->refcnt--;
52705b261ecSmrg    gcv[0].val = oldfg;
52805b261ecSmrg    gcv[1].val = pGC->fgPixel;
52905b261ecSmrg    gcv[2].val = oldfill;
53005b261ecSmrg    gcv[3].ptr = pStipple;
53105b261ecSmrg    gcv[4].val = oldOrg.x;
53205b261ecSmrg    gcv[5].val = oldOrg.y;
53305b261ecSmrg    dixChangeGC(NullClient, pGC,
53405b261ecSmrg        GCForeground | GCBackground | GCFillStyle | GCStipple |
53505b261ecSmrg	GCTileStipXOrigin | GCTileStipYOrigin, NULL, gcv);
53605b261ecSmrg
53705b261ecSmrg    ValidateGC(pDraw, pGC);
53805b261ecSmrg    /* put what we hope is a smaller clip region back in the scratch gc */
53905b261ecSmrg    (*pGCT->funcs->ChangeClip)(pGCT, CT_NONE, NULL, 0);
54005b261ecSmrg    FreeScratchGC(pGCT);
54105b261ecSmrg    (*pDraw->pScreen->DestroyPixmap)(pPixmap);
54205b261ecSmrg
54305b261ecSmrg}
54405b261ecSmrg
54505b261ecSmrg/* MICOPYPLANE -- public entry for the CopyPlane request.
54605b261ecSmrg * strategy:
54705b261ecSmrg * First build up a bitmap out of the bits requested
54805b261ecSmrg * build a source clip
54905b261ecSmrg * Use the bitmap we've built up as a Stipple for the destination
55005b261ecSmrg */
5514642e01fSmrgRegionPtr
5524642e01fSmrgmiCopyPlane( DrawablePtr pSrcDrawable,
5534642e01fSmrg             DrawablePtr pDstDrawable,
5544642e01fSmrg             GCPtr pGC,
5554642e01fSmrg             int srcx,
5564642e01fSmrg             int srcy,
5574642e01fSmrg             int width,
5584642e01fSmrg             int height,
5594642e01fSmrg             int dstx,
5604642e01fSmrg             int dsty,
5614642e01fSmrg             unsigned long bitPlane)
56205b261ecSmrg{
56305b261ecSmrg    MiBits	*ptile;
56405b261ecSmrg    BoxRec 		box;
56505b261ecSmrg    RegionPtr		prgnSrc, prgnExposed;
56605b261ecSmrg
56705b261ecSmrg    /* incorporate the source clip */
56805b261ecSmrg
56905b261ecSmrg    box.x1 = srcx + pSrcDrawable->x;
57005b261ecSmrg    box.y1 = srcy + pSrcDrawable->y;
57105b261ecSmrg    box.x2 = box.x1 + width;
57205b261ecSmrg    box.y2 = box.y1 + height;
57305b261ecSmrg    /* clip to visible drawable */
57405b261ecSmrg    if (box.x1 < pSrcDrawable->x)
57505b261ecSmrg	box.x1 = pSrcDrawable->x;
57605b261ecSmrg    if (box.y1 < pSrcDrawable->y)
57705b261ecSmrg	box.y1 = pSrcDrawable->y;
57805b261ecSmrg    if (box.x2 > pSrcDrawable->x + (int) pSrcDrawable->width)
57905b261ecSmrg	box.x2 = pSrcDrawable->x + (int) pSrcDrawable->width;
58005b261ecSmrg    if (box.y2 > pSrcDrawable->y + (int) pSrcDrawable->height)
58105b261ecSmrg	box.y2 = pSrcDrawable->y + (int) pSrcDrawable->height;
58205b261ecSmrg    if (box.x1 > box.x2)
58305b261ecSmrg	box.x2 = box.x1;
58405b261ecSmrg    if (box.y1 > box.y2)
58505b261ecSmrg	box.y2 = box.y1;
58605b261ecSmrg    prgnSrc = REGION_CREATE(pGC->pScreen, &box, 1);
58705b261ecSmrg
58805b261ecSmrg    if (pSrcDrawable->type != DRAWABLE_PIXMAP) {
58905b261ecSmrg	/* clip to visible drawable */
59005b261ecSmrg
59105b261ecSmrg	if (pGC->subWindowMode == IncludeInferiors)
59205b261ecSmrg	{
59305b261ecSmrg	    RegionPtr	clipList = NotClippedByChildren ((WindowPtr) pSrcDrawable);
59405b261ecSmrg	    REGION_INTERSECT(pGC->pScreen, prgnSrc, prgnSrc, clipList);
59505b261ecSmrg	    REGION_DESTROY(pGC->pScreen, clipList);
59605b261ecSmrg	} else
59705b261ecSmrg	    REGION_INTERSECT(pGC->pScreen, prgnSrc, prgnSrc,
59805b261ecSmrg				       &((WindowPtr)pSrcDrawable)->clipList);
59905b261ecSmrg    }
60005b261ecSmrg
60105b261ecSmrg    box = *REGION_EXTENTS(pGC->pScreen, prgnSrc);
60205b261ecSmrg    REGION_TRANSLATE(pGC->pScreen, prgnSrc, -box.x1, -box.y1);
60305b261ecSmrg
60405b261ecSmrg    if ((box.x2 > box.x1) && (box.y2 > box.y1))
60505b261ecSmrg    {
60605b261ecSmrg	/* minimize the size of the data extracted */
60705b261ecSmrg	/* note that we convert the plane mask bitPlane into a plane number */
60805b261ecSmrg	box.x1 -= pSrcDrawable->x;
60905b261ecSmrg	box.x2 -= pSrcDrawable->x;
61005b261ecSmrg	box.y1 -= pSrcDrawable->y;
61105b261ecSmrg	box.y2 -= pSrcDrawable->y;
61205b261ecSmrg	ptile = miGetPlane(pSrcDrawable, ffs(bitPlane) - 1,
61305b261ecSmrg			   box.x1, box.y1,
61405b261ecSmrg			   box.x2 - box.x1, box.y2 - box.y1,
61505b261ecSmrg			   (MiBits *) NULL);
61605b261ecSmrg	if (ptile)
61705b261ecSmrg	{
61805b261ecSmrg	    miOpqStipDrawable(pDstDrawable, pGC, prgnSrc, ptile, 0,
61905b261ecSmrg			      box.x2 - box.x1, box.y2 - box.y1,
62005b261ecSmrg			      dstx + box.x1 - srcx, dsty + box.y1 - srcy);
62105b261ecSmrg	    xfree(ptile);
62205b261ecSmrg	}
62305b261ecSmrg    }
62405b261ecSmrg    prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC, srcx, srcy,
62505b261ecSmrg		      width, height, dstx, dsty, bitPlane);
62605b261ecSmrg    REGION_DESTROY(pGC->pScreen, prgnSrc);
62705b261ecSmrg    return prgnExposed;
62805b261ecSmrg}
62905b261ecSmrg
63005b261ecSmrg/* MIGETIMAGE -- public entry for the GetImage Request
63105b261ecSmrg * We're getting the image into a memory buffer. While we have to use GetSpans
63205b261ecSmrg * to read a line from the device (since we don't know what that looks like),
63305b261ecSmrg * we can just write into the destination buffer
63405b261ecSmrg *
63505b261ecSmrg * two different strategies are used, depending on whether we're getting the
63605b261ecSmrg * image in Z format or XY format
63705b261ecSmrg * Z format:
63805b261ecSmrg * Line at a time, GetSpans a line into the destination buffer, then if the
63905b261ecSmrg * planemask is not all ones, we do a SetSpans into a temporary buffer (to get
64005b261ecSmrg * bits turned off) and then another GetSpans to get stuff back (because
64105b261ecSmrg * pixmaps are opaque, and we are passed in the memory to write into).  This is
64205b261ecSmrg * pretty ugly and slow but works.  Life is hard.
64305b261ecSmrg * XY format:
64405b261ecSmrg * get the single plane specified in planemask
64505b261ecSmrg */
64605b261ecSmrg_X_EXPORT void
6474642e01fSmrgmiGetImage( DrawablePtr pDraw, int sx, int sy, int w, int h,
6484642e01fSmrg            unsigned int format, unsigned long planeMask, char *pDst)
64905b261ecSmrg{
65005b261ecSmrg    unsigned char	depth;
65105b261ecSmrg    int			i, linelength, width, srcx, srcy;
65205b261ecSmrg    DDXPointRec		pt = {0, 0};
65305b261ecSmrg    XID			gcv[2];
65405b261ecSmrg    PixmapPtr		pPixmap = (PixmapPtr)NULL;
65505b261ecSmrg    GCPtr		pGC = NULL;
65605b261ecSmrg
65705b261ecSmrg    depth = pDraw->depth;
65805b261ecSmrg    if(format == ZPixmap)
65905b261ecSmrg    {
66005b261ecSmrg	if ( (((1<<depth)-1)&planeMask) != (1<<depth)-1 )
66105b261ecSmrg	{
66205b261ecSmrg	    xPoint pt;
66305b261ecSmrg
66405b261ecSmrg	    pGC = GetScratchGC(depth, pDraw->pScreen);
66505b261ecSmrg	    if (!pGC)
66605b261ecSmrg		return;
66705b261ecSmrg            pPixmap = (*pDraw->pScreen->CreatePixmap)
6684642e01fSmrg			       (pDraw->pScreen, w, 1, depth,
6694642e01fSmrg			        CREATE_PIXMAP_USAGE_SCRATCH);
67005b261ecSmrg	    if (!pPixmap)
67105b261ecSmrg	    {
67205b261ecSmrg		FreeScratchGC(pGC);
67305b261ecSmrg		return;
67405b261ecSmrg	    }
67505b261ecSmrg 	    /*
67605b261ecSmrg 	     * Clear the pixmap before doing anything else
67705b261ecSmrg 	     */
67805b261ecSmrg 	    ValidateGC((DrawablePtr)pPixmap, pGC);
67905b261ecSmrg 	    pt.x = pt.y = 0;
68005b261ecSmrg            width = w;
68105b261ecSmrg	    (*pGC->ops->FillSpans)((DrawablePtr)pPixmap, pGC, 1, &pt, &width,
68205b261ecSmrg				   TRUE);
68305b261ecSmrg
68405b261ecSmrg	    /* alu is already GXCopy */
68505b261ecSmrg	    gcv[0] = (XID)planeMask;
68605b261ecSmrg	    DoChangeGC(pGC, GCPlaneMask, gcv, 0);
68705b261ecSmrg	    ValidateGC((DrawablePtr)pPixmap, pGC);
68805b261ecSmrg	}
68905b261ecSmrg
69005b261ecSmrg        linelength = PixmapBytePad(w, depth);
69105b261ecSmrg	srcx = sx + pDraw->x;
69205b261ecSmrg	srcy = sy + pDraw->y;
69305b261ecSmrg	for(i = 0; i < h; i++)
69405b261ecSmrg	{
69505b261ecSmrg	    pt.x = srcx;
69605b261ecSmrg	    pt.y = srcy + i;
69705b261ecSmrg	    width = w;
69805b261ecSmrg	    (*pDraw->pScreen->GetSpans)(pDraw, w, &pt, &width, 1, pDst);
69905b261ecSmrg	    if (pPixmap)
70005b261ecSmrg	    {
70105b261ecSmrg	       pt.x = 0;
70205b261ecSmrg	       pt.y = 0;
70305b261ecSmrg	       width = w;
70405b261ecSmrg	       (*pGC->ops->SetSpans)((DrawablePtr)pPixmap, pGC, pDst,
70505b261ecSmrg				     &pt, &width, 1, TRUE);
70605b261ecSmrg	       (*pDraw->pScreen->GetSpans)((DrawablePtr)pPixmap, w, &pt,
70705b261ecSmrg					   &width, 1, pDst);
70805b261ecSmrg	    }
70905b261ecSmrg	    pDst += linelength;
71005b261ecSmrg	}
71105b261ecSmrg	if (pPixmap)
71205b261ecSmrg	{
71305b261ecSmrg	    (*pGC->pScreen->DestroyPixmap)(pPixmap);
71405b261ecSmrg	    FreeScratchGC(pGC);
71505b261ecSmrg	}
71605b261ecSmrg    }
71705b261ecSmrg    else
71805b261ecSmrg    {
71905b261ecSmrg	(void) miGetPlane(pDraw, ffs(planeMask) - 1, sx, sy, w, h,
72005b261ecSmrg			  (MiBits *)pDst);
72105b261ecSmrg    }
72205b261ecSmrg}
72305b261ecSmrg
72405b261ecSmrg/* MIPUTIMAGE -- public entry for the PutImage request
72505b261ecSmrg * Here we benefit from knowing the format of the bits pointed to by pImage,
72605b261ecSmrg * even if we don't know how pDraw represents them.
72705b261ecSmrg * Three different strategies are used depending on the format
72805b261ecSmrg * XYBitmap Format:
72905b261ecSmrg * 	we just use the Opaque Stipple helper function to cover the destination
73005b261ecSmrg * 	Note that this covers all the planes of the drawable with the
73105b261ecSmrg *	foreground color (masked with the GC planemask) where there are 1 bits
73205b261ecSmrg *	and the background color (masked with the GC planemask) where there are
73305b261ecSmrg *	0 bits
73405b261ecSmrg * XYPixmap format:
73505b261ecSmrg *	what we're called with is a series of XYBitmaps, but we only want
73605b261ecSmrg *	each XYPixmap to update 1 plane, instead of updating all of them.
73705b261ecSmrg * 	we set the foreground color to be all 1s and the background to all 0s
73805b261ecSmrg *	then for each plane, we set the plane mask to only effect that one
73905b261ecSmrg *	plane and recursive call ourself with the format set to XYBitmap
74005b261ecSmrg *	(This clever idea courtesy of RGD.)
74105b261ecSmrg * ZPixmap format:
74205b261ecSmrg *	This part is simple, just call SetSpans
74305b261ecSmrg */
74405b261ecSmrg_X_EXPORT void
7454642e01fSmrgmiPutImage( DrawablePtr pDraw, GCPtr pGC, int depth,
7464642e01fSmrg            int x, int y, int w, int h,
7474642e01fSmrg            int leftPad, int format, char *pImage)
74805b261ecSmrg{
74905b261ecSmrg    DDXPointPtr		pptFirst, ppt;
75005b261ecSmrg    int			*pwidthFirst, *pwidth;
75105b261ecSmrg    RegionPtr		prgnSrc;
75205b261ecSmrg    BoxRec		box;
75305b261ecSmrg    unsigned long	oldFg, oldBg;
75405b261ecSmrg    XID			gcv[3];
75505b261ecSmrg    unsigned long	oldPlanemask;
75605b261ecSmrg    unsigned long	i;
75705b261ecSmrg    long		bytesPer;
75805b261ecSmrg
75905b261ecSmrg    if (!w || !h)
76005b261ecSmrg	return;
76105b261ecSmrg    switch(format)
76205b261ecSmrg    {
76305b261ecSmrg      case XYBitmap:
76405b261ecSmrg
76505b261ecSmrg	box.x1 = 0;
76605b261ecSmrg	box.y1 = 0;
76705b261ecSmrg	box.x2 = w;
76805b261ecSmrg	box.y2 = h;
76905b261ecSmrg	prgnSrc = REGION_CREATE(pGC->pScreen, &box, 1);
77005b261ecSmrg
77105b261ecSmrg        miOpqStipDrawable(pDraw, pGC, prgnSrc, (MiBits *) pImage,
77205b261ecSmrg			  leftPad, w, h, x, y);
77305b261ecSmrg	REGION_DESTROY(pGC->pScreen, prgnSrc);
77405b261ecSmrg	break;
77505b261ecSmrg
77605b261ecSmrg      case XYPixmap:
77705b261ecSmrg	depth = pGC->depth;
77805b261ecSmrg	oldPlanemask = pGC->planemask;
77905b261ecSmrg	oldFg = pGC->fgPixel;
78005b261ecSmrg	oldBg = pGC->bgPixel;
78105b261ecSmrg	gcv[0] = (XID)~0;
78205b261ecSmrg	gcv[1] = (XID)0;
78305b261ecSmrg	DoChangeGC(pGC, GCForeground | GCBackground, gcv, 0);
78405b261ecSmrg	bytesPer = (long)h * BitmapBytePad(w + leftPad);
78505b261ecSmrg
78605b261ecSmrg	for (i = 1 << (depth-1); i != 0; i >>= 1, pImage += bytesPer)
78705b261ecSmrg	{
78805b261ecSmrg	    if (i & oldPlanemask)
78905b261ecSmrg	    {
79005b261ecSmrg	        gcv[0] = (XID)i;
79105b261ecSmrg	        DoChangeGC(pGC, GCPlaneMask, gcv, 0);
79205b261ecSmrg	        ValidateGC(pDraw, pGC);
79305b261ecSmrg	        (*pGC->ops->PutImage)(pDraw, pGC, 1, x, y, w, h, leftPad,
79405b261ecSmrg			         XYBitmap, (char *)pImage);
79505b261ecSmrg	    }
79605b261ecSmrg	}
79705b261ecSmrg	gcv[0] = (XID)oldPlanemask;
79805b261ecSmrg	gcv[1] = (XID)oldFg;
79905b261ecSmrg	gcv[2] = (XID)oldBg;
80005b261ecSmrg	DoChangeGC(pGC, GCPlaneMask | GCForeground | GCBackground, gcv, 0);
80105b261ecSmrg	ValidateGC(pDraw, pGC);
80205b261ecSmrg	break;
80305b261ecSmrg
80405b261ecSmrg      case ZPixmap:
8054642e01fSmrg    	ppt = pptFirst = (DDXPointPtr)xalloc(h * sizeof(DDXPointRec));
8064642e01fSmrg    	pwidth = pwidthFirst = (int *)xalloc(h * sizeof(int));
80705b261ecSmrg	if(!pptFirst || !pwidthFirst)
80805b261ecSmrg        {
80905b261ecSmrg	   if (pwidthFirst)
8104642e01fSmrg               xfree(pwidthFirst);
81105b261ecSmrg           if (pptFirst)
8124642e01fSmrg               xfree(pptFirst);
81305b261ecSmrg           return;
81405b261ecSmrg        }
81505b261ecSmrg	if (pGC->miTranslate)
81605b261ecSmrg	{
81705b261ecSmrg	    x += pDraw->x;
81805b261ecSmrg	    y += pDraw->y;
81905b261ecSmrg	}
82005b261ecSmrg
82105b261ecSmrg	for(i = 0; i < h; i++)
82205b261ecSmrg	{
82305b261ecSmrg	    ppt->x = x;
82405b261ecSmrg	    ppt->y = y + i;
82505b261ecSmrg	    ppt++;
82605b261ecSmrg	    *pwidth++ = w;
82705b261ecSmrg	}
82805b261ecSmrg
82905b261ecSmrg	(*pGC->ops->SetSpans)(pDraw, pGC, (char *)pImage, pptFirst,
83005b261ecSmrg			      pwidthFirst, h, TRUE);
8314642e01fSmrg	xfree(pwidthFirst);
8324642e01fSmrg	xfree(pptFirst);
83305b261ecSmrg	break;
83405b261ecSmrg    }
83505b261ecSmrg}
836