mibitblt.c revision 6747b715
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)
1076747b715Smrg	return 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
1196747b715Smrg	prgnSrcClip = RegionCreate(&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
1466747b715Smrg    pptFirst = ppt = malloc(heightSrc * sizeof(DDXPointRec));
1476747b715Smrg    pwidthFirst = pwidth = malloc(heightSrc * sizeof(unsigned int));
1486747b715Smrg    numRects = RegionNumRects(prgnSrcClip);
1496747b715Smrg    boxes = RegionRects(prgnSrcClip);
1506747b715Smrg    ordering = malloc(numRects * sizeof(unsigned int));
15105b261ecSmrg    if(!pptFirst || !pwidthFirst || !ordering)
15205b261ecSmrg    {
1536747b715Smrg       free(ordering);
1546747b715Smrg       free(pwidthFirst);
1556747b715Smrg       free(pptFirst);
1566747b715Smrg       return NULL;
15705b261ecSmrg    }
15805b261ecSmrg
15905b261ecSmrg    /* If not the same drawable then order of move doesn't matter.
16005b261ecSmrg       Following assumes that boxes are sorted from top
16105b261ecSmrg       to bottom and left to right.
16205b261ecSmrg    */
16305b261ecSmrg    if ((pSrcDrawable != pDstDrawable) &&
16405b261ecSmrg	((pGC->subWindowMode != IncludeInferiors) ||
16505b261ecSmrg	 (pSrcDrawable->type == DRAWABLE_PIXMAP) ||
16605b261ecSmrg	 (pDstDrawable->type == DRAWABLE_PIXMAP)))
16705b261ecSmrg      for (i=0; i < numRects; i++)
16805b261ecSmrg        ordering[i] = i;
16905b261ecSmrg    else { /* within same drawable, must sequence moves carefully! */
17005b261ecSmrg      if (dsty <= srcBox.y1) { /* Scroll up or stationary vertical.
17105b261ecSmrg                                  Vertical order OK */
17205b261ecSmrg        if (dstx <= srcBox.x1) /* Scroll left or stationary horizontal.
17305b261ecSmrg                                  Horizontal order OK as well */
17405b261ecSmrg          for (i=0; i < numRects; i++)
17505b261ecSmrg            ordering[i] = i;
17605b261ecSmrg        else { /* scroll right. must reverse horizontal banding of rects. */
17705b261ecSmrg          for (i=0, j=1, xMax=0; i < numRects; j=i+1, xMax=i) {
17805b261ecSmrg            /* find extent of current horizontal band */
17905b261ecSmrg            y=boxes[i].y1; /* band has this y coordinate */
18005b261ecSmrg            while ((j < numRects) && (boxes[j].y1 == y))
18105b261ecSmrg              j++;
18205b261ecSmrg            /* reverse the horizontal band in the output ordering */
18305b261ecSmrg            for (j-- ; j >= xMax; j--, i++)
18405b261ecSmrg              ordering[i] = j;
18505b261ecSmrg          }
18605b261ecSmrg        }
18705b261ecSmrg      }
18805b261ecSmrg      else { /* Scroll down. Must reverse vertical banding. */
18905b261ecSmrg        if (dstx < srcBox.x1) { /* Scroll left. Horizontal order OK. */
19005b261ecSmrg          for (i=numRects-1, j=i-1, yMin=i, yMax=0;
19105b261ecSmrg              i >= 0;
19205b261ecSmrg              j=i-1, yMin=i) {
19305b261ecSmrg            /* find extent of current horizontal band */
19405b261ecSmrg            y=boxes[i].y1; /* band has this y coordinate */
19505b261ecSmrg            while ((j >= 0) && (boxes[j].y1 == y))
19605b261ecSmrg              j--;
19705b261ecSmrg            /* reverse the horizontal band in the output ordering */
19805b261ecSmrg            for (j++ ; j <= yMin; j++, i--, yMax++)
19905b261ecSmrg              ordering[yMax] = j;
20005b261ecSmrg          }
20105b261ecSmrg        }
20205b261ecSmrg        else /* Scroll right or horizontal stationary.
20305b261ecSmrg                Reverse horizontal order as well (if stationary, horizontal
20405b261ecSmrg                order can be swapped without penalty and this is faster
20505b261ecSmrg                to compute). */
20605b261ecSmrg          for (i=0, j=numRects-1; i < numRects; i++, j--)
20705b261ecSmrg              ordering[i] = j;
20805b261ecSmrg      }
20905b261ecSmrg    }
21005b261ecSmrg
21105b261ecSmrg     for(i = 0; i < numRects; i++)
21205b261ecSmrg     {
21305b261ecSmrg        prect = &boxes[ordering[i]];
21405b261ecSmrg  	xMin = max(prect->x1, srcBox.x1);
21505b261ecSmrg  	xMax = min(prect->x2, srcBox.x2);
21605b261ecSmrg  	yMin = max(prect->y1, srcBox.y1);
21705b261ecSmrg	yMax = min(prect->y2, srcBox.y2);
21805b261ecSmrg	/* is there anything visible here? */
21905b261ecSmrg	if(xMax <= xMin || yMax <= yMin)
22005b261ecSmrg	    continue;
22105b261ecSmrg
22205b261ecSmrg        ppt = pptFirst;
22305b261ecSmrg	pwidth = pwidthFirst;
22405b261ecSmrg	y = yMin;
22505b261ecSmrg	height = yMax - yMin;
22605b261ecSmrg	width = xMax - xMin;
22705b261ecSmrg
22805b261ecSmrg	for(j = 0; j < height; j++)
22905b261ecSmrg	{
23005b261ecSmrg	    /* We must untranslate before calling GetSpans */
23105b261ecSmrg	    ppt->x = xMin;
23205b261ecSmrg	    ppt++->y = y++;
23305b261ecSmrg	    *pwidth++ = width;
23405b261ecSmrg	}
2356747b715Smrg	pbits = malloc(height * PixmapBytePad(width, pSrcDrawable->depth));
23605b261ecSmrg	if (pbits)
23705b261ecSmrg	{
23805b261ecSmrg	    (*pSrcDrawable->pScreen->GetSpans)(pSrcDrawable, width, pptFirst,
23905b261ecSmrg			(int *)pwidthFirst, height, (char *)pbits);
24005b261ecSmrg	    ppt = pptFirst;
24105b261ecSmrg	    pwidth = pwidthFirst;
24205b261ecSmrg	    xMin -= (srcx - dstx);
24305b261ecSmrg	    y = yMin - (srcy - dsty);
24405b261ecSmrg	    for(j = 0; j < height; j++)
24505b261ecSmrg	    {
24605b261ecSmrg		ppt->x = xMin;
24705b261ecSmrg		ppt++->y = y++;
24805b261ecSmrg		*pwidth++ = width;
24905b261ecSmrg	    }
25005b261ecSmrg
25105b261ecSmrg	    (*pGC->ops->SetSpans)(pDstDrawable, pGC, (char *)pbits, pptFirst,
25205b261ecSmrg				  (int *)pwidthFirst, height, TRUE);
2536747b715Smrg	    free(pbits);
25405b261ecSmrg	}
25505b261ecSmrg    }
25605b261ecSmrg    prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC, xIn, yIn,
25705b261ecSmrg		      widthSrc, heightSrc, xOut, yOut, (unsigned long)0);
25805b261ecSmrg    if(realSrcClip)
2596747b715Smrg	RegionDestroy(prgnSrcClip);
26005b261ecSmrg
2616747b715Smrg    free(ordering);
2626747b715Smrg    free(pwidthFirst);
2636747b715Smrg    free(pptFirst);
26405b261ecSmrg    return prgnExposed;
26505b261ecSmrg}
26605b261ecSmrg
26705b261ecSmrg/* MIGETPLANE -- gets a bitmap representing one plane of pDraw
26805b261ecSmrg * A helper used for CopyPlane and XY format GetImage
26905b261ecSmrg * No clever strategy here, we grab a scanline at a time, pull out the
27005b261ecSmrg * bits and then stuff them in a 1 bit deep map.
27105b261ecSmrg */
27205b261ecSmrg/*
27305b261ecSmrg * This should be replaced with something more general.  mi shouldn't have to
27405b261ecSmrg * care about such things as scanline padding et alia.
27505b261ecSmrg */
27605b261ecSmrgstatic
27705b261ecSmrgMiBits	*
27805b261ecSmrgmiGetPlane(
27905b261ecSmrg    DrawablePtr		pDraw,
28005b261ecSmrg    int			planeNum,	/* number of the bitPlane */
28105b261ecSmrg    int			sx,
28205b261ecSmrg    int			sy,
28305b261ecSmrg    int			w,
28405b261ecSmrg    int			h,
28505b261ecSmrg    MiBits	*result)
28605b261ecSmrg{
28705b261ecSmrg    int			i, j, k, width, bitsPerPixel, widthInBytes;
28805b261ecSmrg    DDXPointRec 	pt = {0, 0};
28905b261ecSmrg    MiBits	pixel;
29005b261ecSmrg    MiBits	bit;
29105b261ecSmrg    unsigned char	*pCharsOut = NULL;
29205b261ecSmrg
29305b261ecSmrg#if BITMAP_SCANLINE_UNIT == 8
29405b261ecSmrg#define OUT_TYPE unsigned char
29505b261ecSmrg#endif
29605b261ecSmrg#if BITMAP_SCANLINE_UNIT == 16
29705b261ecSmrg#define OUT_TYPE CARD16
29805b261ecSmrg#endif
29905b261ecSmrg#if BITMAP_SCANLINE_UNIT == 32
30005b261ecSmrg#define OUT_TYPE CARD32
30105b261ecSmrg#endif
30205b261ecSmrg#if BITMAP_SCANLINE_UNIT == 64
30305b261ecSmrg#define OUT_TYPE CARD64
30405b261ecSmrg#endif
30505b261ecSmrg
30605b261ecSmrg    OUT_TYPE		*pOut;
30705b261ecSmrg    int			delta = 0;
30805b261ecSmrg
30905b261ecSmrg    sx += pDraw->x;
31005b261ecSmrg    sy += pDraw->y;
31105b261ecSmrg    widthInBytes = BitmapBytePad(w);
31205b261ecSmrg    if(!result)
3136747b715Smrg        result = calloc(h, widthInBytes);
31405b261ecSmrg    if (!result)
3156747b715Smrg	return NULL;
31605b261ecSmrg    bitsPerPixel = pDraw->bitsPerPixel;
31705b261ecSmrg    pOut = (OUT_TYPE *) result;
31805b261ecSmrg    if(bitsPerPixel == 1)
31905b261ecSmrg    {
32005b261ecSmrg	pCharsOut = (unsigned char *) result;
32105b261ecSmrg    	width = w;
32205b261ecSmrg    }
32305b261ecSmrg    else
32405b261ecSmrg    {
32505b261ecSmrg	delta = (widthInBytes / (BITMAP_SCANLINE_UNIT / 8)) -
32605b261ecSmrg	    (w / BITMAP_SCANLINE_UNIT);
32705b261ecSmrg	width = 1;
32805b261ecSmrg#if IMAGE_BYTE_ORDER == MSBFirst
32905b261ecSmrg	planeNum += (32 - bitsPerPixel);
33005b261ecSmrg#endif
33105b261ecSmrg    }
33205b261ecSmrg    pt.y = sy;
33305b261ecSmrg    for (i = h; --i >= 0; pt.y++)
33405b261ecSmrg    {
33505b261ecSmrg	pt.x = sx;
33605b261ecSmrg	if(bitsPerPixel == 1)
33705b261ecSmrg	{
33805b261ecSmrg	    (*pDraw->pScreen->GetSpans)(pDraw, width, &pt, &width, 1,
33905b261ecSmrg					(char *)pCharsOut);
34005b261ecSmrg	    pCharsOut += widthInBytes;
34105b261ecSmrg	}
34205b261ecSmrg	else
34305b261ecSmrg	{
34405b261ecSmrg	    k = 0;
34505b261ecSmrg	    for(j = w; --j >= 0; pt.x++)
34605b261ecSmrg	    {
34705b261ecSmrg		/* Fetch the next pixel */
34805b261ecSmrg		(*pDraw->pScreen->GetSpans)(pDraw, width, &pt, &width, 1,
34905b261ecSmrg					    (char *)&pixel);
35005b261ecSmrg		/*
35105b261ecSmrg		 * Now get the bit and insert into a bitmap in XY format.
35205b261ecSmrg		 */
35305b261ecSmrg		bit = (pixel >> planeNum) & 1;
35405b261ecSmrg#if 0
35505b261ecSmrg		/* XXX assuming bit order == byte order */
35605b261ecSmrg#if BITMAP_BIT_ORDER == LSBFirst
35705b261ecSmrg		bit <<= k;
35805b261ecSmrg#else
35905b261ecSmrg		bit <<= ((BITMAP_SCANLINE_UNIT - 1) - k);
36005b261ecSmrg#endif
36105b261ecSmrg#else
36205b261ecSmrg		/* XXX assuming byte order == LSBFirst */
36305b261ecSmrg		if (screenInfo.bitmapBitOrder == LSBFirst)
36405b261ecSmrg			bit <<= k;
36505b261ecSmrg		else
36605b261ecSmrg			bit <<= ((screenInfo.bitmapScanlineUnit - 1) -
36705b261ecSmrg				 (k % screenInfo.bitmapScanlineUnit)) +
36805b261ecSmrg				((k / screenInfo.bitmapScanlineUnit) *
36905b261ecSmrg				 screenInfo.bitmapScanlineUnit);
37005b261ecSmrg#endif
37105b261ecSmrg		*pOut |= (OUT_TYPE) bit;
37205b261ecSmrg		k++;
37305b261ecSmrg		if (k == BITMAP_SCANLINE_UNIT)
37405b261ecSmrg		{
37505b261ecSmrg		    pOut++;
37605b261ecSmrg		    k = 0;
37705b261ecSmrg		}
37805b261ecSmrg	    }
37905b261ecSmrg	    pOut += delta;
38005b261ecSmrg	}
38105b261ecSmrg    }
3826747b715Smrg    return result;
38305b261ecSmrg
38405b261ecSmrg}
38505b261ecSmrg
38605b261ecSmrg/* MIOPQSTIPDRAWABLE -- use pbits as an opaque stipple for pDraw.
38705b261ecSmrg * Drawing through the clip mask we SetSpans() the bits into a
38805b261ecSmrg * bitmap and stipple those bits onto the destination drawable by doing a
38905b261ecSmrg * PolyFillRect over the whole drawable,
39005b261ecSmrg * then we invert the bitmap by copying it onto itself with an alu of
39105b261ecSmrg * GXinvert, invert the foreground/background colors of the gc, and draw
39205b261ecSmrg * the background bits.
39305b261ecSmrg * Note how the clipped out bits of the bitmap are always the background
39405b261ecSmrg * color so that the stipple never causes FillRect to draw them.
39505b261ecSmrg */
39605b261ecSmrgstatic void
39705b261ecSmrgmiOpqStipDrawable(DrawablePtr pDraw, GCPtr pGC, RegionPtr prgnSrc,
39805b261ecSmrg		  MiBits *pbits, int srcx, int w, int h, int dstx, int dsty)
39905b261ecSmrg{
40005b261ecSmrg    int		oldfill, i;
40105b261ecSmrg    unsigned long oldfg;
40205b261ecSmrg    int		*pwidth, *pwidthFirst;
40305b261ecSmrg    ChangeGCVal	gcv[6];
40405b261ecSmrg    PixmapPtr	pStipple, pPixmap;
40505b261ecSmrg    DDXPointRec	oldOrg;
40605b261ecSmrg    GCPtr	pGCT;
40705b261ecSmrg    DDXPointPtr ppt, pptFirst;
40805b261ecSmrg    xRectangle rect;
40905b261ecSmrg    RegionPtr	prgnSrcClip;
41005b261ecSmrg
41105b261ecSmrg    pPixmap = (*pDraw->pScreen->CreatePixmap)
4124642e01fSmrg			   (pDraw->pScreen, w + srcx, h, 1,
4134642e01fSmrg			    CREATE_PIXMAP_USAGE_SCRATCH);
41405b261ecSmrg    if (!pPixmap)
41505b261ecSmrg	return;
41605b261ecSmrg
41705b261ecSmrg    /* Put the image into a 1 bit deep pixmap */
41805b261ecSmrg    pGCT = GetScratchGC(1, pDraw->pScreen);
41905b261ecSmrg    if (!pGCT)
42005b261ecSmrg    {
42105b261ecSmrg	(*pDraw->pScreen->DestroyPixmap)(pPixmap);
42205b261ecSmrg	return;
42305b261ecSmrg    }
42405b261ecSmrg    /* First set the whole pixmap to 0 */
42505b261ecSmrg    gcv[0].val = 0;
4266747b715Smrg    ChangeGC(NullClient, pGCT, GCBackground, gcv);
42705b261ecSmrg    ValidateGC((DrawablePtr)pPixmap, pGCT);
42805b261ecSmrg    miClearDrawable((DrawablePtr)pPixmap, pGCT);
4296747b715Smrg    ppt = pptFirst = malloc(h * sizeof(DDXPointRec));
4306747b715Smrg    pwidth = pwidthFirst = malloc(h * sizeof(int));
43105b261ecSmrg    if(!pptFirst || !pwidthFirst)
43205b261ecSmrg    {
4336747b715Smrg	free(pwidthFirst);
4346747b715Smrg	free(pptFirst);
43505b261ecSmrg	FreeScratchGC(pGCT);
43605b261ecSmrg	return;
43705b261ecSmrg    }
43805b261ecSmrg
43905b261ecSmrg    /* we need a temporary region because ChangeClip must be assumed
44005b261ecSmrg       to destroy what it's sent.  note that this means we don't
44105b261ecSmrg       have to free prgnSrcClip ourselves.
44205b261ecSmrg    */
4436747b715Smrg    prgnSrcClip = RegionCreate(NULL, 0);
4446747b715Smrg    RegionCopy(prgnSrcClip, prgnSrc);
4456747b715Smrg    RegionTranslate(prgnSrcClip, srcx, 0);
44605b261ecSmrg    (*pGCT->funcs->ChangeClip)(pGCT, CT_REGION, prgnSrcClip, 0);
44705b261ecSmrg    ValidateGC((DrawablePtr)pPixmap, pGCT);
44805b261ecSmrg
44905b261ecSmrg    /* Since we know pDraw is always a pixmap, we never need to think
45005b261ecSmrg     * about translation here */
45105b261ecSmrg    for(i = 0; i < h; i++)
45205b261ecSmrg    {
45305b261ecSmrg	ppt->x = 0;
45405b261ecSmrg	ppt++->y = i;
45505b261ecSmrg	*pwidth++ = w + srcx;
45605b261ecSmrg    }
45705b261ecSmrg
45805b261ecSmrg    (*pGCT->ops->SetSpans)((DrawablePtr)pPixmap, pGCT, (char *)pbits,
45905b261ecSmrg			   pptFirst, pwidthFirst, h, TRUE);
4606747b715Smrg    free(pwidthFirst);
4616747b715Smrg    free(pptFirst);
46205b261ecSmrg
46305b261ecSmrg
46405b261ecSmrg    /* Save current values from the client GC */
46505b261ecSmrg    oldfill = pGC->fillStyle;
46605b261ecSmrg    pStipple = pGC->stipple;
46705b261ecSmrg    if(pStipple)
46805b261ecSmrg        pStipple->refcnt++;
46905b261ecSmrg    oldOrg = pGC->patOrg;
47005b261ecSmrg
47105b261ecSmrg    /* Set a new stipple in the drawable */
47205b261ecSmrg    gcv[0].val = FillStippled;
47305b261ecSmrg    gcv[1].ptr = pPixmap;
47405b261ecSmrg    gcv[2].val = dstx - srcx;
47505b261ecSmrg    gcv[3].val = dsty;
47605b261ecSmrg
4776747b715Smrg    ChangeGC(NullClient, pGC,
47805b261ecSmrg             GCFillStyle | GCStipple | GCTileStipXOrigin | GCTileStipYOrigin,
4796747b715Smrg	     gcv);
48005b261ecSmrg    ValidateGC(pDraw, pGC);
48105b261ecSmrg
48205b261ecSmrg    /* Fill the drawable with the stipple.  This will draw the
48305b261ecSmrg     * foreground color whereever 1 bits are set, leaving everything
48405b261ecSmrg     * with 0 bits untouched.  Note that the part outside the clip
48505b261ecSmrg     * region is all 0s.  */
48605b261ecSmrg    rect.x = dstx;
48705b261ecSmrg    rect.y = dsty;
48805b261ecSmrg    rect.width = w;
48905b261ecSmrg    rect.height = h;
49005b261ecSmrg    (*pGC->ops->PolyFillRect)(pDraw, pGC, 1, &rect);
49105b261ecSmrg
49205b261ecSmrg    /* Invert the tiling pixmap. This sets 0s for 1s and 1s for 0s, only
49305b261ecSmrg     * within the clipping region, the part outside is still all 0s */
49405b261ecSmrg    gcv[0].val = GXinvert;
4956747b715Smrg    ChangeGC(NullClient, pGCT, GCFunction, gcv);
49605b261ecSmrg    ValidateGC((DrawablePtr)pPixmap, pGCT);
49705b261ecSmrg    (*pGCT->ops->CopyArea)((DrawablePtr)pPixmap, (DrawablePtr)pPixmap,
49805b261ecSmrg			   pGCT, 0, 0, w + srcx, h, 0, 0);
49905b261ecSmrg
50005b261ecSmrg    /* Swap foreground and background colors on the GC for the drawable.
50105b261ecSmrg     * Now when we fill the drawable, we will fill in the "Background"
50205b261ecSmrg     * values */
50305b261ecSmrg    oldfg = pGC->fgPixel;
50405b261ecSmrg    gcv[0].val = pGC->bgPixel;
50505b261ecSmrg    gcv[1].val = oldfg;
50605b261ecSmrg    gcv[2].ptr = pPixmap;
5076747b715Smrg    ChangeGC(NullClient, pGC, GCForeground | GCBackground | GCStipple, gcv);
50805b261ecSmrg    ValidateGC(pDraw, pGC);
50905b261ecSmrg    /* PolyFillRect might have bashed the rectangle */
51005b261ecSmrg    rect.x = dstx;
51105b261ecSmrg    rect.y = dsty;
51205b261ecSmrg    rect.width = w;
51305b261ecSmrg    rect.height = h;
51405b261ecSmrg    (*pGC->ops->PolyFillRect)(pDraw, pGC, 1, &rect);
51505b261ecSmrg
51605b261ecSmrg    /* Now put things back */
51705b261ecSmrg    if(pStipple)
51805b261ecSmrg        pStipple->refcnt--;
51905b261ecSmrg    gcv[0].val = oldfg;
52005b261ecSmrg    gcv[1].val = pGC->fgPixel;
52105b261ecSmrg    gcv[2].val = oldfill;
52205b261ecSmrg    gcv[3].ptr = pStipple;
52305b261ecSmrg    gcv[4].val = oldOrg.x;
52405b261ecSmrg    gcv[5].val = oldOrg.y;
5256747b715Smrg    ChangeGC(NullClient, pGC,
52605b261ecSmrg        GCForeground | GCBackground | GCFillStyle | GCStipple |
5276747b715Smrg	GCTileStipXOrigin | GCTileStipYOrigin, gcv);
52805b261ecSmrg
52905b261ecSmrg    ValidateGC(pDraw, pGC);
53005b261ecSmrg    /* put what we hope is a smaller clip region back in the scratch gc */
53105b261ecSmrg    (*pGCT->funcs->ChangeClip)(pGCT, CT_NONE, NULL, 0);
53205b261ecSmrg    FreeScratchGC(pGCT);
53305b261ecSmrg    (*pDraw->pScreen->DestroyPixmap)(pPixmap);
53405b261ecSmrg
53505b261ecSmrg}
53605b261ecSmrg
53705b261ecSmrg/* MICOPYPLANE -- public entry for the CopyPlane request.
53805b261ecSmrg * strategy:
53905b261ecSmrg * First build up a bitmap out of the bits requested
54005b261ecSmrg * build a source clip
54105b261ecSmrg * Use the bitmap we've built up as a Stipple for the destination
54205b261ecSmrg */
5434642e01fSmrgRegionPtr
5444642e01fSmrgmiCopyPlane( DrawablePtr pSrcDrawable,
5454642e01fSmrg             DrawablePtr pDstDrawable,
5464642e01fSmrg             GCPtr pGC,
5474642e01fSmrg             int srcx,
5484642e01fSmrg             int srcy,
5494642e01fSmrg             int width,
5504642e01fSmrg             int height,
5514642e01fSmrg             int dstx,
5524642e01fSmrg             int dsty,
5534642e01fSmrg             unsigned long bitPlane)
55405b261ecSmrg{
55505b261ecSmrg    MiBits	*ptile;
55605b261ecSmrg    BoxRec 		box;
55705b261ecSmrg    RegionPtr		prgnSrc, prgnExposed;
55805b261ecSmrg
55905b261ecSmrg    /* incorporate the source clip */
56005b261ecSmrg
56105b261ecSmrg    box.x1 = srcx + pSrcDrawable->x;
56205b261ecSmrg    box.y1 = srcy + pSrcDrawable->y;
56305b261ecSmrg    box.x2 = box.x1 + width;
56405b261ecSmrg    box.y2 = box.y1 + height;
56505b261ecSmrg    /* clip to visible drawable */
56605b261ecSmrg    if (box.x1 < pSrcDrawable->x)
56705b261ecSmrg	box.x1 = pSrcDrawable->x;
56805b261ecSmrg    if (box.y1 < pSrcDrawable->y)
56905b261ecSmrg	box.y1 = pSrcDrawable->y;
57005b261ecSmrg    if (box.x2 > pSrcDrawable->x + (int) pSrcDrawable->width)
57105b261ecSmrg	box.x2 = pSrcDrawable->x + (int) pSrcDrawable->width;
57205b261ecSmrg    if (box.y2 > pSrcDrawable->y + (int) pSrcDrawable->height)
57305b261ecSmrg	box.y2 = pSrcDrawable->y + (int) pSrcDrawable->height;
57405b261ecSmrg    if (box.x1 > box.x2)
57505b261ecSmrg	box.x2 = box.x1;
57605b261ecSmrg    if (box.y1 > box.y2)
57705b261ecSmrg	box.y2 = box.y1;
5786747b715Smrg    prgnSrc = RegionCreate(&box, 1);
57905b261ecSmrg
58005b261ecSmrg    if (pSrcDrawable->type != DRAWABLE_PIXMAP) {
58105b261ecSmrg	/* clip to visible drawable */
58205b261ecSmrg
58305b261ecSmrg	if (pGC->subWindowMode == IncludeInferiors)
58405b261ecSmrg	{
58505b261ecSmrg	    RegionPtr	clipList = NotClippedByChildren ((WindowPtr) pSrcDrawable);
5866747b715Smrg	    RegionIntersect(prgnSrc, prgnSrc, clipList);
5876747b715Smrg	    RegionDestroy(clipList);
58805b261ecSmrg	} else
5896747b715Smrg	    RegionIntersect(prgnSrc, prgnSrc,
59005b261ecSmrg				       &((WindowPtr)pSrcDrawable)->clipList);
59105b261ecSmrg    }
59205b261ecSmrg
5936747b715Smrg    box = *RegionExtents(prgnSrc);
5946747b715Smrg    RegionTranslate(prgnSrc, -box.x1, -box.y1);
59505b261ecSmrg
59605b261ecSmrg    if ((box.x2 > box.x1) && (box.y2 > box.y1))
59705b261ecSmrg    {
59805b261ecSmrg	/* minimize the size of the data extracted */
59905b261ecSmrg	/* note that we convert the plane mask bitPlane into a plane number */
60005b261ecSmrg	box.x1 -= pSrcDrawable->x;
60105b261ecSmrg	box.x2 -= pSrcDrawable->x;
60205b261ecSmrg	box.y1 -= pSrcDrawable->y;
60305b261ecSmrg	box.y2 -= pSrcDrawable->y;
60405b261ecSmrg	ptile = miGetPlane(pSrcDrawable, ffs(bitPlane) - 1,
60505b261ecSmrg			   box.x1, box.y1,
60605b261ecSmrg			   box.x2 - box.x1, box.y2 - box.y1,
60705b261ecSmrg			   (MiBits *) NULL);
60805b261ecSmrg	if (ptile)
60905b261ecSmrg	{
61005b261ecSmrg	    miOpqStipDrawable(pDstDrawable, pGC, prgnSrc, ptile, 0,
61105b261ecSmrg			      box.x2 - box.x1, box.y2 - box.y1,
61205b261ecSmrg			      dstx + box.x1 - srcx, dsty + box.y1 - srcy);
6136747b715Smrg	    free(ptile);
61405b261ecSmrg	}
61505b261ecSmrg    }
61605b261ecSmrg    prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC, srcx, srcy,
61705b261ecSmrg		      width, height, dstx, dsty, bitPlane);
6186747b715Smrg    RegionDestroy(prgnSrc);
61905b261ecSmrg    return prgnExposed;
62005b261ecSmrg}
62105b261ecSmrg
62205b261ecSmrg/* MIGETIMAGE -- public entry for the GetImage Request
62305b261ecSmrg * We're getting the image into a memory buffer. While we have to use GetSpans
62405b261ecSmrg * to read a line from the device (since we don't know what that looks like),
62505b261ecSmrg * we can just write into the destination buffer
62605b261ecSmrg *
62705b261ecSmrg * two different strategies are used, depending on whether we're getting the
62805b261ecSmrg * image in Z format or XY format
62905b261ecSmrg * Z format:
63005b261ecSmrg * Line at a time, GetSpans a line into the destination buffer, then if the
63105b261ecSmrg * planemask is not all ones, we do a SetSpans into a temporary buffer (to get
63205b261ecSmrg * bits turned off) and then another GetSpans to get stuff back (because
63305b261ecSmrg * pixmaps are opaque, and we are passed in the memory to write into).  This is
63405b261ecSmrg * pretty ugly and slow but works.  Life is hard.
63505b261ecSmrg * XY format:
63605b261ecSmrg * get the single plane specified in planemask
63705b261ecSmrg */
6386747b715Smrgvoid
6394642e01fSmrgmiGetImage( DrawablePtr pDraw, int sx, int sy, int w, int h,
6404642e01fSmrg            unsigned int format, unsigned long planeMask, char *pDst)
64105b261ecSmrg{
64205b261ecSmrg    unsigned char	depth;
64305b261ecSmrg    int			i, linelength, width, srcx, srcy;
64405b261ecSmrg    DDXPointRec		pt = {0, 0};
6456747b715Smrg    PixmapPtr		pPixmap = NULL;
64605b261ecSmrg    GCPtr		pGC = NULL;
64705b261ecSmrg
64805b261ecSmrg    depth = pDraw->depth;
64905b261ecSmrg    if(format == ZPixmap)
65005b261ecSmrg    {
65105b261ecSmrg	if ( (((1<<depth)-1)&planeMask) != (1<<depth)-1 )
65205b261ecSmrg	{
6536747b715Smrg	    ChangeGCVal gcv;
65405b261ecSmrg	    xPoint pt;
65505b261ecSmrg
65605b261ecSmrg	    pGC = GetScratchGC(depth, pDraw->pScreen);
65705b261ecSmrg	    if (!pGC)
65805b261ecSmrg		return;
65905b261ecSmrg            pPixmap = (*pDraw->pScreen->CreatePixmap)
6604642e01fSmrg			       (pDraw->pScreen, w, 1, depth,
6614642e01fSmrg			        CREATE_PIXMAP_USAGE_SCRATCH);
66205b261ecSmrg	    if (!pPixmap)
66305b261ecSmrg	    {
66405b261ecSmrg		FreeScratchGC(pGC);
66505b261ecSmrg		return;
66605b261ecSmrg	    }
66705b261ecSmrg 	    /*
66805b261ecSmrg 	     * Clear the pixmap before doing anything else
66905b261ecSmrg 	     */
67005b261ecSmrg 	    ValidateGC((DrawablePtr)pPixmap, pGC);
67105b261ecSmrg 	    pt.x = pt.y = 0;
67205b261ecSmrg            width = w;
67305b261ecSmrg	    (*pGC->ops->FillSpans)((DrawablePtr)pPixmap, pGC, 1, &pt, &width,
67405b261ecSmrg				   TRUE);
67505b261ecSmrg
67605b261ecSmrg	    /* alu is already GXCopy */
6776747b715Smrg	    gcv.val = (XID)planeMask;
6786747b715Smrg	    ChangeGC(NullClient, pGC, GCPlaneMask, &gcv);
67905b261ecSmrg	    ValidateGC((DrawablePtr)pPixmap, pGC);
68005b261ecSmrg	}
68105b261ecSmrg
68205b261ecSmrg        linelength = PixmapBytePad(w, depth);
68305b261ecSmrg	srcx = sx + pDraw->x;
68405b261ecSmrg	srcy = sy + pDraw->y;
68505b261ecSmrg	for(i = 0; i < h; i++)
68605b261ecSmrg	{
68705b261ecSmrg	    pt.x = srcx;
68805b261ecSmrg	    pt.y = srcy + i;
68905b261ecSmrg	    width = w;
69005b261ecSmrg	    (*pDraw->pScreen->GetSpans)(pDraw, w, &pt, &width, 1, pDst);
69105b261ecSmrg	    if (pPixmap)
69205b261ecSmrg	    {
69305b261ecSmrg	       pt.x = 0;
69405b261ecSmrg	       pt.y = 0;
69505b261ecSmrg	       width = w;
69605b261ecSmrg	       (*pGC->ops->SetSpans)((DrawablePtr)pPixmap, pGC, pDst,
69705b261ecSmrg				     &pt, &width, 1, TRUE);
69805b261ecSmrg	       (*pDraw->pScreen->GetSpans)((DrawablePtr)pPixmap, w, &pt,
69905b261ecSmrg					   &width, 1, pDst);
70005b261ecSmrg	    }
70105b261ecSmrg	    pDst += linelength;
70205b261ecSmrg	}
70305b261ecSmrg	if (pPixmap)
70405b261ecSmrg	{
70505b261ecSmrg	    (*pGC->pScreen->DestroyPixmap)(pPixmap);
70605b261ecSmrg	    FreeScratchGC(pGC);
70705b261ecSmrg	}
70805b261ecSmrg    }
70905b261ecSmrg    else
71005b261ecSmrg    {
71105b261ecSmrg	(void) miGetPlane(pDraw, ffs(planeMask) - 1, sx, sy, w, h,
71205b261ecSmrg			  (MiBits *)pDst);
71305b261ecSmrg    }
71405b261ecSmrg}
71505b261ecSmrg
71605b261ecSmrg/* MIPUTIMAGE -- public entry for the PutImage request
71705b261ecSmrg * Here we benefit from knowing the format of the bits pointed to by pImage,
71805b261ecSmrg * even if we don't know how pDraw represents them.
71905b261ecSmrg * Three different strategies are used depending on the format
72005b261ecSmrg * XYBitmap Format:
72105b261ecSmrg * 	we just use the Opaque Stipple helper function to cover the destination
72205b261ecSmrg * 	Note that this covers all the planes of the drawable with the
72305b261ecSmrg *	foreground color (masked with the GC planemask) where there are 1 bits
72405b261ecSmrg *	and the background color (masked with the GC planemask) where there are
72505b261ecSmrg *	0 bits
72605b261ecSmrg * XYPixmap format:
72705b261ecSmrg *	what we're called with is a series of XYBitmaps, but we only want
72805b261ecSmrg *	each XYPixmap to update 1 plane, instead of updating all of them.
72905b261ecSmrg * 	we set the foreground color to be all 1s and the background to all 0s
73005b261ecSmrg *	then for each plane, we set the plane mask to only effect that one
73105b261ecSmrg *	plane and recursive call ourself with the format set to XYBitmap
73205b261ecSmrg *	(This clever idea courtesy of RGD.)
73305b261ecSmrg * ZPixmap format:
73405b261ecSmrg *	This part is simple, just call SetSpans
73505b261ecSmrg */
7366747b715Smrgvoid
7374642e01fSmrgmiPutImage( DrawablePtr pDraw, GCPtr pGC, int depth,
7384642e01fSmrg            int x, int y, int w, int h,
7394642e01fSmrg            int leftPad, int format, char *pImage)
74005b261ecSmrg{
74105b261ecSmrg    DDXPointPtr		pptFirst, ppt;
74205b261ecSmrg    int			*pwidthFirst, *pwidth;
74305b261ecSmrg    RegionPtr		prgnSrc;
74405b261ecSmrg    BoxRec		box;
74505b261ecSmrg    unsigned long	oldFg, oldBg;
7466747b715Smrg    ChangeGCVal		gcv[3];
74705b261ecSmrg    unsigned long	oldPlanemask;
74805b261ecSmrg    unsigned long	i;
74905b261ecSmrg    long		bytesPer;
75005b261ecSmrg
75105b261ecSmrg    if (!w || !h)
75205b261ecSmrg	return;
75305b261ecSmrg    switch(format)
75405b261ecSmrg    {
75505b261ecSmrg      case XYBitmap:
75605b261ecSmrg
75705b261ecSmrg	box.x1 = 0;
75805b261ecSmrg	box.y1 = 0;
75905b261ecSmrg	box.x2 = w;
76005b261ecSmrg	box.y2 = h;
7616747b715Smrg	prgnSrc = RegionCreate(&box, 1);
76205b261ecSmrg
76305b261ecSmrg        miOpqStipDrawable(pDraw, pGC, prgnSrc, (MiBits *) pImage,
76405b261ecSmrg			  leftPad, w, h, x, y);
7656747b715Smrg	RegionDestroy(prgnSrc);
76605b261ecSmrg	break;
76705b261ecSmrg
76805b261ecSmrg      case XYPixmap:
76905b261ecSmrg	depth = pGC->depth;
77005b261ecSmrg	oldPlanemask = pGC->planemask;
77105b261ecSmrg	oldFg = pGC->fgPixel;
77205b261ecSmrg	oldBg = pGC->bgPixel;
7736747b715Smrg	gcv[0].val = (XID)~0;
7746747b715Smrg	gcv[1].val = (XID)0;
7756747b715Smrg	ChangeGC(NullClient, pGC, GCForeground | GCBackground, gcv);
77605b261ecSmrg	bytesPer = (long)h * BitmapBytePad(w + leftPad);
77705b261ecSmrg
77805b261ecSmrg	for (i = 1 << (depth-1); i != 0; i >>= 1, pImage += bytesPer)
77905b261ecSmrg	{
78005b261ecSmrg	    if (i & oldPlanemask)
78105b261ecSmrg	    {
7826747b715Smrg	        gcv[0].val = (XID)i;
7836747b715Smrg	        ChangeGC(NullClient, pGC, GCPlaneMask, gcv);
78405b261ecSmrg	        ValidateGC(pDraw, pGC);
78505b261ecSmrg	        (*pGC->ops->PutImage)(pDraw, pGC, 1, x, y, w, h, leftPad,
78605b261ecSmrg			         XYBitmap, (char *)pImage);
78705b261ecSmrg	    }
78805b261ecSmrg	}
7896747b715Smrg	gcv[0].val = (XID)oldPlanemask;
7906747b715Smrg	gcv[1].val = (XID)oldFg;
7916747b715Smrg	gcv[2].val = (XID)oldBg;
7926747b715Smrg	ChangeGC(NullClient, pGC, GCPlaneMask | GCForeground | GCBackground, gcv);
79305b261ecSmrg	ValidateGC(pDraw, pGC);
79405b261ecSmrg	break;
79505b261ecSmrg
79605b261ecSmrg      case ZPixmap:
7976747b715Smrg        ppt = pptFirst = malloc(h * sizeof(DDXPointRec));
7986747b715Smrg        pwidth = pwidthFirst = malloc(h * sizeof(int));
79905b261ecSmrg	if(!pptFirst || !pwidthFirst)
80005b261ecSmrg        {
8016747b715Smrg	   free(pwidthFirst);
8026747b715Smrg           free(pptFirst);
80305b261ecSmrg           return;
80405b261ecSmrg        }
80505b261ecSmrg	if (pGC->miTranslate)
80605b261ecSmrg	{
80705b261ecSmrg	    x += pDraw->x;
80805b261ecSmrg	    y += pDraw->y;
80905b261ecSmrg	}
81005b261ecSmrg
81105b261ecSmrg	for(i = 0; i < h; i++)
81205b261ecSmrg	{
81305b261ecSmrg	    ppt->x = x;
81405b261ecSmrg	    ppt->y = y + i;
81505b261ecSmrg	    ppt++;
81605b261ecSmrg	    *pwidth++ = w;
81705b261ecSmrg	}
81805b261ecSmrg
81905b261ecSmrg	(*pGC->ops->SetSpans)(pDraw, pGC, (char *)pImage, pptFirst,
82005b261ecSmrg			      pwidthFirst, h, TRUE);
8216747b715Smrg	free(pwidthFirst);
8226747b715Smrg	free(pptFirst);
82305b261ecSmrg	break;
82405b261ecSmrg    }
82505b261ecSmrg}
826