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
2505b261ecSmrgCopyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
2605b261ecSmrg
2705b261ecSmrg                        All Rights Reserved
2805b261ecSmrg
2935c4bbdfSmrgPermission to use, copy, modify, and distribute this software and its
3035c4bbdfSmrgdocumentation for any purpose and without fee is hereby granted,
3105b261ecSmrgprovided that the above copyright notice appear in all copies and that
3235c4bbdfSmrgboth that copyright notice and this permission notice appear in
3305b261ecSmrgsupporting documentation, and that the name of Digital not be
3405b261ecSmrgused in advertising or publicity pertaining to distribution of the
3535c4bbdfSmrgsoftware without specific, written prior permission.
3605b261ecSmrg
3705b261ecSmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
3805b261ecSmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
3905b261ecSmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
4005b261ecSmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
4105b261ecSmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
4205b261ecSmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
4305b261ecSmrgSOFTWARE.
4405b261ecSmrg
4505b261ecSmrg******************************************************************/
4605b261ecSmrg/* Author: Todd Newman  (aided and abetted by Mr. Drewry) */
4705b261ecSmrg
4805b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
4905b261ecSmrg#include <dix-config.h>
5005b261ecSmrg#endif
5105b261ecSmrg
5205b261ecSmrg#include <X11/X.h>
5305b261ecSmrg#include <X11/Xprotostr.h>
5405b261ecSmrg
5505b261ecSmrg#include "misc.h"
5605b261ecSmrg#include "gcstruct.h"
5705b261ecSmrg#include "pixmapstr.h"
5805b261ecSmrg#include "windowstr.h"
5905b261ecSmrg#include "scrnintstr.h"
6005b261ecSmrg#include "mi.h"
6105b261ecSmrg#include "regionstr.h"
6205b261ecSmrg#include <X11/Xmd.h>
6305b261ecSmrg#include "servermd.h"
6405b261ecSmrg
65ed6184dfSmrg#ifdef __MINGW32__
66ed6184dfSmrg#define ffs __builtin_ffs
67ed6184dfSmrg#endif
68ed6184dfSmrg
6935c4bbdfSmrg/* MICOPYAREA -- public entry for the CopyArea request
7005b261ecSmrg * For each rectangle in the source region
7105b261ecSmrg *     get the pixels with GetSpans
7205b261ecSmrg *     set them in the destination with SetSpans
7305b261ecSmrg * We let SetSpans worry about clipping to the destination.
7405b261ecSmrg */
7535c4bbdfSmrg_X_COLD RegionPtr
7635c4bbdfSmrgmiCopyArea(DrawablePtr pSrcDrawable,
7735c4bbdfSmrg           DrawablePtr pDstDrawable,
7835c4bbdfSmrg           GCPtr pGC,
7935c4bbdfSmrg           int xIn, int yIn, int widthSrc, int heightSrc, int xOut, int yOut)
8005b261ecSmrg{
8135c4bbdfSmrg    DDXPointPtr ppt, pptFirst;
8235c4bbdfSmrg    unsigned int *pwidthFirst, *pwidth, *pbits;
8335c4bbdfSmrg    BoxRec srcBox, *prect;
8435c4bbdfSmrg
8535c4bbdfSmrg    /* may be a new region, or just a copy */
8635c4bbdfSmrg    RegionPtr prgnSrcClip;
8735c4bbdfSmrg
8835c4bbdfSmrg    /* non-0 if we've created a src clip */
8935c4bbdfSmrg    RegionPtr prgnExposed;
9035c4bbdfSmrg    int realSrcClip = 0;
9135c4bbdfSmrg    int srcx, srcy, dstx, dsty, i, j, y, width, height, xMin, xMax, yMin, yMax;
9235c4bbdfSmrg    unsigned int *ordering;
9335c4bbdfSmrg    int numRects;
9435c4bbdfSmrg    BoxPtr boxes;
9505b261ecSmrg
9605b261ecSmrg    srcx = xIn + pSrcDrawable->x;
9705b261ecSmrg    srcy = yIn + pSrcDrawable->y;
9805b261ecSmrg
9905b261ecSmrg    /* If the destination isn't realized, this is easy */
10005b261ecSmrg    if (pDstDrawable->type == DRAWABLE_WINDOW &&
10135c4bbdfSmrg        !((WindowPtr) pDstDrawable)->realized)
10235c4bbdfSmrg        return NULL;
10305b261ecSmrg
10405b261ecSmrg    /* clip the source */
10535c4bbdfSmrg    if (pSrcDrawable->type == DRAWABLE_PIXMAP) {
10635c4bbdfSmrg        BoxRec box;
10705b261ecSmrg
10835c4bbdfSmrg        box.x1 = pSrcDrawable->x;
10935c4bbdfSmrg        box.y1 = pSrcDrawable->y;
11035c4bbdfSmrg        box.x2 = pSrcDrawable->x + (int) pSrcDrawable->width;
11135c4bbdfSmrg        box.y2 = pSrcDrawable->y + (int) pSrcDrawable->height;
11205b261ecSmrg
11335c4bbdfSmrg        prgnSrcClip = RegionCreate(&box, 1);
11435c4bbdfSmrg        realSrcClip = 1;
11505b261ecSmrg    }
11635c4bbdfSmrg    else {
11735c4bbdfSmrg        if (pGC->subWindowMode == IncludeInferiors) {
11835c4bbdfSmrg            prgnSrcClip = NotClippedByChildren((WindowPtr) pSrcDrawable);
11935c4bbdfSmrg            realSrcClip = 1;
12035c4bbdfSmrg        }
12135c4bbdfSmrg        else
12235c4bbdfSmrg            prgnSrcClip = &((WindowPtr) pSrcDrawable)->clipList;
12305b261ecSmrg    }
12405b261ecSmrg
12505b261ecSmrg    /* If the src drawable is a window, we need to translate the srcBox so
12605b261ecSmrg     * that we can compare it with the window's clip region later on. */
12705b261ecSmrg    srcBox.x1 = srcx;
12805b261ecSmrg    srcBox.y1 = srcy;
12935c4bbdfSmrg    srcBox.x2 = srcx + widthSrc;
13035c4bbdfSmrg    srcBox.y2 = srcy + heightSrc;
13105b261ecSmrg
13205b261ecSmrg    dstx = xOut;
13305b261ecSmrg    dsty = yOut;
13435c4bbdfSmrg    if (pGC->miTranslate) {
13535c4bbdfSmrg        dstx += pDstDrawable->x;
13635c4bbdfSmrg        dsty += pDstDrawable->y;
13705b261ecSmrg    }
13805b261ecSmrg
13935c4bbdfSmrg    pptFirst = ppt = xallocarray(heightSrc, sizeof(DDXPointRec));
14035c4bbdfSmrg    pwidthFirst = pwidth = xallocarray(heightSrc, sizeof(unsigned int));
1416747b715Smrg    numRects = RegionNumRects(prgnSrcClip);
1426747b715Smrg    boxes = RegionRects(prgnSrcClip);
14335c4bbdfSmrg    ordering = xallocarray(numRects, sizeof(unsigned int));
14435c4bbdfSmrg    if (!pptFirst || !pwidthFirst || !ordering) {
14535c4bbdfSmrg        free(ordering);
14635c4bbdfSmrg        free(pwidthFirst);
14735c4bbdfSmrg        free(pptFirst);
1481b5d61b8Smrg        if (realSrcClip)
1491b5d61b8Smrg            RegionDestroy(prgnSrcClip);
15035c4bbdfSmrg        return NULL;
15105b261ecSmrg    }
15205b261ecSmrg
15305b261ecSmrg    /* If not the same drawable then order of move doesn't matter.
15405b261ecSmrg       Following assumes that boxes are sorted from top
15505b261ecSmrg       to bottom and left to right.
15635c4bbdfSmrg     */
15705b261ecSmrg    if ((pSrcDrawable != pDstDrawable) &&
15835c4bbdfSmrg        ((pGC->subWindowMode != IncludeInferiors) ||
15935c4bbdfSmrg         (pSrcDrawable->type == DRAWABLE_PIXMAP) ||
16035c4bbdfSmrg         (pDstDrawable->type == DRAWABLE_PIXMAP)))
16135c4bbdfSmrg        for (i = 0; i < numRects; i++)
16205b261ecSmrg            ordering[i] = i;
16335c4bbdfSmrg    else {                      /* within same drawable, must sequence moves carefully! */
16435c4bbdfSmrg        if (dsty <= srcBox.y1) {        /* Scroll up or stationary vertical.
16535c4bbdfSmrg                                           Vertical order OK */
16635c4bbdfSmrg            if (dstx <= srcBox.x1)      /* Scroll left or stationary horizontal.
16735c4bbdfSmrg                                           Horizontal order OK as well */
16835c4bbdfSmrg                for (i = 0; i < numRects; i++)
16935c4bbdfSmrg                    ordering[i] = i;
17035c4bbdfSmrg            else {              /* scroll right. must reverse horizontal banding of rects. */
17135c4bbdfSmrg                for (i = 0, j = 1, xMax = 0; i < numRects; j = i + 1, xMax = i) {
17235c4bbdfSmrg                    /* find extent of current horizontal band */
17335c4bbdfSmrg                    y = boxes[i].y1;    /* band has this y coordinate */
17435c4bbdfSmrg                    while ((j < numRects) && (boxes[j].y1 == y))
17535c4bbdfSmrg                        j++;
17635c4bbdfSmrg                    /* reverse the horizontal band in the output ordering */
17735c4bbdfSmrg                    for (j--; j >= xMax; j--, i++)
17835c4bbdfSmrg                        ordering[i] = j;
17935c4bbdfSmrg                }
18035c4bbdfSmrg            }
18105b261ecSmrg        }
18235c4bbdfSmrg        else {                  /* Scroll down. Must reverse vertical banding. */
18335c4bbdfSmrg            if (dstx < srcBox.x1) {     /* Scroll left. Horizontal order OK. */
18435c4bbdfSmrg                for (i = numRects - 1, j = i - 1, yMin = i, yMax = 0;
18535c4bbdfSmrg                     i >= 0; j = i - 1, yMin = i) {
18635c4bbdfSmrg                    /* find extent of current horizontal band */
18735c4bbdfSmrg                    y = boxes[i].y1;    /* band has this y coordinate */
18835c4bbdfSmrg                    while ((j >= 0) && (boxes[j].y1 == y))
18935c4bbdfSmrg                        j--;
19035c4bbdfSmrg                    /* reverse the horizontal band in the output ordering */
19135c4bbdfSmrg                    for (j++; j <= yMin; j++, i--, yMax++)
19235c4bbdfSmrg                        ordering[yMax] = j;
19335c4bbdfSmrg                }
19435c4bbdfSmrg            }
19535c4bbdfSmrg            else                /* Scroll right or horizontal stationary.
19635c4bbdfSmrg                                   Reverse horizontal order as well (if stationary, horizontal
19735c4bbdfSmrg                                   order can be swapped without penalty and this is faster
19835c4bbdfSmrg                                   to compute). */
19935c4bbdfSmrg                for (i = 0, j = numRects - 1; i < numRects; i++, j--)
20035c4bbdfSmrg                    ordering[i] = j;
20105b261ecSmrg        }
20205b261ecSmrg    }
20335c4bbdfSmrg
20435c4bbdfSmrg    for (i = 0; i < numRects; i++) {
20505b261ecSmrg        prect = &boxes[ordering[i]];
20635c4bbdfSmrg        xMin = max(prect->x1, srcBox.x1);
20735c4bbdfSmrg        xMax = min(prect->x2, srcBox.x2);
20835c4bbdfSmrg        yMin = max(prect->y1, srcBox.y1);
20935c4bbdfSmrg        yMax = min(prect->y2, srcBox.y2);
21035c4bbdfSmrg        /* is there anything visible here? */
21135c4bbdfSmrg        if (xMax <= xMin || yMax <= yMin)
21235c4bbdfSmrg            continue;
21305b261ecSmrg
21405b261ecSmrg        ppt = pptFirst;
21535c4bbdfSmrg        pwidth = pwidthFirst;
21635c4bbdfSmrg        y = yMin;
21735c4bbdfSmrg        height = yMax - yMin;
21835c4bbdfSmrg        width = xMax - xMin;
21935c4bbdfSmrg
22035c4bbdfSmrg        for (j = 0; j < height; j++) {
22135c4bbdfSmrg            /* We must untranslate before calling GetSpans */
22235c4bbdfSmrg            ppt->x = xMin;
22335c4bbdfSmrg            ppt++->y = y++;
22435c4bbdfSmrg            *pwidth++ = width;
22535c4bbdfSmrg        }
22635c4bbdfSmrg        pbits = xallocarray(height, PixmapBytePad(width, pSrcDrawable->depth));
22735c4bbdfSmrg        if (pbits) {
22835c4bbdfSmrg            (*pSrcDrawable->pScreen->GetSpans) (pSrcDrawable, width, pptFirst,
22935c4bbdfSmrg                                                (int *) pwidthFirst, height,
23035c4bbdfSmrg                                                (char *) pbits);
23135c4bbdfSmrg            ppt = pptFirst;
23235c4bbdfSmrg            pwidth = pwidthFirst;
23335c4bbdfSmrg            xMin -= (srcx - dstx);
23435c4bbdfSmrg            y = yMin - (srcy - dsty);
23535c4bbdfSmrg            for (j = 0; j < height; j++) {
23635c4bbdfSmrg                ppt->x = xMin;
23735c4bbdfSmrg                ppt++->y = y++;
23835c4bbdfSmrg                *pwidth++ = width;
23935c4bbdfSmrg            }
24035c4bbdfSmrg
24135c4bbdfSmrg            (*pGC->ops->SetSpans) (pDstDrawable, pGC, (char *) pbits, pptFirst,
24235c4bbdfSmrg                                   (int *) pwidthFirst, height, TRUE);
24335c4bbdfSmrg            free(pbits);
24435c4bbdfSmrg        }
24505b261ecSmrg    }
24605b261ecSmrg    prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC, xIn, yIn,
24735c4bbdfSmrg                                    widthSrc, heightSrc, xOut, yOut);
24835c4bbdfSmrg    if (realSrcClip)
24935c4bbdfSmrg        RegionDestroy(prgnSrcClip);
25035c4bbdfSmrg
2516747b715Smrg    free(ordering);
2526747b715Smrg    free(pwidthFirst);
2536747b715Smrg    free(pptFirst);
25405b261ecSmrg    return prgnExposed;
25505b261ecSmrg}
25605b261ecSmrg
25705b261ecSmrg/* MIGETPLANE -- gets a bitmap representing one plane of pDraw
25835c4bbdfSmrg * A helper used for CopyPlane and XY format GetImage
25905b261ecSmrg * No clever strategy here, we grab a scanline at a time, pull out the
26005b261ecSmrg * bits and then stuff them in a 1 bit deep map.
26105b261ecSmrg */
26205b261ecSmrg/*
26305b261ecSmrg * This should be replaced with something more general.  mi shouldn't have to
26405b261ecSmrg * care about such things as scanline padding et alia.
26505b261ecSmrg */
26635c4bbdfSmrg_X_COLD static MiBits *
26735c4bbdfSmrgmiGetPlane(DrawablePtr pDraw, int planeNum,     /* number of the bitPlane */
26835c4bbdfSmrg           int sx, int sy, int w, int h, MiBits * result)
26905b261ecSmrg{
27035c4bbdfSmrg    int i, j, k, width, bitsPerPixel, widthInBytes;
27135c4bbdfSmrg    DDXPointRec pt = { 0, 0 };
27235c4bbdfSmrg    MiBits pixel;
27335c4bbdfSmrg    MiBits bit;
27435c4bbdfSmrg    unsigned char *pCharsOut = NULL;
27505b261ecSmrg
27605b261ecSmrg#if BITMAP_SCANLINE_UNIT == 8
27705b261ecSmrg#define OUT_TYPE unsigned char
27805b261ecSmrg#endif
27905b261ecSmrg#if BITMAP_SCANLINE_UNIT == 16
28005b261ecSmrg#define OUT_TYPE CARD16
28105b261ecSmrg#endif
28205b261ecSmrg#if BITMAP_SCANLINE_UNIT == 32
28305b261ecSmrg#define OUT_TYPE CARD32
28405b261ecSmrg#endif
28505b261ecSmrg#if BITMAP_SCANLINE_UNIT == 64
28605b261ecSmrg#define OUT_TYPE CARD64
28705b261ecSmrg#endif
28805b261ecSmrg
28935c4bbdfSmrg    OUT_TYPE *pOut;
29035c4bbdfSmrg    int delta = 0;
29105b261ecSmrg
29205b261ecSmrg    sx += pDraw->x;
29305b261ecSmrg    sy += pDraw->y;
29405b261ecSmrg    widthInBytes = BitmapBytePad(w);
29535c4bbdfSmrg    if (!result)
2966747b715Smrg        result = calloc(h, widthInBytes);
29705b261ecSmrg    if (!result)
29835c4bbdfSmrg        return NULL;
29905b261ecSmrg    bitsPerPixel = pDraw->bitsPerPixel;
30005b261ecSmrg    pOut = (OUT_TYPE *) result;
30135c4bbdfSmrg    if (bitsPerPixel == 1) {
30235c4bbdfSmrg        pCharsOut = (unsigned char *) result;
30335c4bbdfSmrg        width = w;
30405b261ecSmrg    }
30535c4bbdfSmrg    else {
30635c4bbdfSmrg        delta = (widthInBytes / (BITMAP_SCANLINE_UNIT / 8)) -
30735c4bbdfSmrg            (w / BITMAP_SCANLINE_UNIT);
30835c4bbdfSmrg        width = 1;
30905b261ecSmrg#if IMAGE_BYTE_ORDER == MSBFirst
31035c4bbdfSmrg        planeNum += (32 - bitsPerPixel);
31105b261ecSmrg#endif
31205b261ecSmrg    }
31305b261ecSmrg    pt.y = sy;
31435c4bbdfSmrg    for (i = h; --i >= 0; pt.y++) {
31535c4bbdfSmrg        pt.x = sx;
31635c4bbdfSmrg        if (bitsPerPixel == 1) {
31735c4bbdfSmrg            (*pDraw->pScreen->GetSpans) (pDraw, width, &pt, &width, 1,
31835c4bbdfSmrg                                         (char *) pCharsOut);
31935c4bbdfSmrg            pCharsOut += widthInBytes;
32035c4bbdfSmrg        }
32135c4bbdfSmrg        else {
32235c4bbdfSmrg            k = 0;
32335c4bbdfSmrg            for (j = w; --j >= 0; pt.x++) {
32435c4bbdfSmrg                /* Fetch the next pixel */
32535c4bbdfSmrg                (*pDraw->pScreen->GetSpans) (pDraw, width, &pt, &width, 1,
32635c4bbdfSmrg                                             (char *) &pixel);
32735c4bbdfSmrg                /*
32835c4bbdfSmrg                 * Now get the bit and insert into a bitmap in XY format.
32935c4bbdfSmrg                 */
33035c4bbdfSmrg                bit = (pixel >> planeNum) & 1;
33105b261ecSmrg#if 0
33235c4bbdfSmrg                /* XXX assuming bit order == byte order */
33305b261ecSmrg#if BITMAP_BIT_ORDER == LSBFirst
33435c4bbdfSmrg                bit <<= k;
33505b261ecSmrg#else
33635c4bbdfSmrg                bit <<= ((BITMAP_SCANLINE_UNIT - 1) - k);
33705b261ecSmrg#endif
33805b261ecSmrg#else
33935c4bbdfSmrg                /* XXX assuming byte order == LSBFirst */
34035c4bbdfSmrg                if (screenInfo.bitmapBitOrder == LSBFirst)
34135c4bbdfSmrg                    bit <<= k;
34235c4bbdfSmrg                else
34335c4bbdfSmrg                    bit <<= ((screenInfo.bitmapScanlineUnit - 1) -
34435c4bbdfSmrg                             (k % screenInfo.bitmapScanlineUnit)) +
34535c4bbdfSmrg                        ((k / screenInfo.bitmapScanlineUnit) *
34635c4bbdfSmrg                         screenInfo.bitmapScanlineUnit);
34705b261ecSmrg#endif
34835c4bbdfSmrg                *pOut |= (OUT_TYPE) bit;
34935c4bbdfSmrg                k++;
35035c4bbdfSmrg                if (k == BITMAP_SCANLINE_UNIT) {
35135c4bbdfSmrg                    pOut++;
35235c4bbdfSmrg                    k = 0;
35335c4bbdfSmrg                }
35435c4bbdfSmrg            }
35535c4bbdfSmrg            pOut += delta;
35635c4bbdfSmrg        }
35705b261ecSmrg    }
3586747b715Smrg    return result;
35905b261ecSmrg
36005b261ecSmrg}
36105b261ecSmrg
36205b261ecSmrg/* MIOPQSTIPDRAWABLE -- use pbits as an opaque stipple for pDraw.
36335c4bbdfSmrg * Drawing through the clip mask we SetSpans() the bits into a
36405b261ecSmrg * bitmap and stipple those bits onto the destination drawable by doing a
36535c4bbdfSmrg * PolyFillRect over the whole drawable,
36605b261ecSmrg * then we invert the bitmap by copying it onto itself with an alu of
36705b261ecSmrg * GXinvert, invert the foreground/background colors of the gc, and draw
36805b261ecSmrg * the background bits.
36905b261ecSmrg * Note how the clipped out bits of the bitmap are always the background
37005b261ecSmrg * color so that the stipple never causes FillRect to draw them.
37105b261ecSmrg */
37235c4bbdfSmrg_X_COLD static void
37305b261ecSmrgmiOpqStipDrawable(DrawablePtr pDraw, GCPtr pGC, RegionPtr prgnSrc,
37435c4bbdfSmrg                  MiBits * pbits, int srcx, int w, int h, int dstx, int dsty)
37505b261ecSmrg{
37635c4bbdfSmrg    int oldfill, i;
37705b261ecSmrg    unsigned long oldfg;
37835c4bbdfSmrg    int *pwidth, *pwidthFirst;
37935c4bbdfSmrg    ChangeGCVal gcv[6];
38035c4bbdfSmrg    PixmapPtr pStipple, pPixmap;
38135c4bbdfSmrg    DDXPointRec oldOrg;
38235c4bbdfSmrg    GCPtr pGCT;
38305b261ecSmrg    DDXPointPtr ppt, pptFirst;
38405b261ecSmrg    xRectangle rect;
38535c4bbdfSmrg    RegionPtr prgnSrcClip;
38605b261ecSmrg
38705b261ecSmrg    pPixmap = (*pDraw->pScreen->CreatePixmap)
38835c4bbdfSmrg        (pDraw->pScreen, w + srcx, h, 1, CREATE_PIXMAP_USAGE_SCRATCH);
38905b261ecSmrg    if (!pPixmap)
39035c4bbdfSmrg        return;
39105b261ecSmrg
39205b261ecSmrg    /* Put the image into a 1 bit deep pixmap */
39305b261ecSmrg    pGCT = GetScratchGC(1, pDraw->pScreen);
39435c4bbdfSmrg    if (!pGCT) {
39535c4bbdfSmrg        (*pDraw->pScreen->DestroyPixmap) (pPixmap);
39635c4bbdfSmrg        return;
39705b261ecSmrg    }
39805b261ecSmrg    /* First set the whole pixmap to 0 */
39905b261ecSmrg    gcv[0].val = 0;
4006747b715Smrg    ChangeGC(NullClient, pGCT, GCBackground, gcv);
40135c4bbdfSmrg    ValidateGC((DrawablePtr) pPixmap, pGCT);
40235c4bbdfSmrg    miClearDrawable((DrawablePtr) pPixmap, pGCT);
40335c4bbdfSmrg    ppt = pptFirst = xallocarray(h, sizeof(DDXPointRec));
40435c4bbdfSmrg    pwidth = pwidthFirst = xallocarray(h, sizeof(int));
40535c4bbdfSmrg    if (!pptFirst || !pwidthFirst) {
40635c4bbdfSmrg        free(pwidthFirst);
40735c4bbdfSmrg        free(pptFirst);
40835c4bbdfSmrg        FreeScratchGC(pGCT);
40935c4bbdfSmrg        return;
41005b261ecSmrg    }
41105b261ecSmrg
41205b261ecSmrg    /* we need a temporary region because ChangeClip must be assumed
41305b261ecSmrg       to destroy what it's sent.  note that this means we don't
41405b261ecSmrg       have to free prgnSrcClip ourselves.
41535c4bbdfSmrg     */
4166747b715Smrg    prgnSrcClip = RegionCreate(NULL, 0);
4176747b715Smrg    RegionCopy(prgnSrcClip, prgnSrc);
4186747b715Smrg    RegionTranslate(prgnSrcClip, srcx, 0);
41935c4bbdfSmrg    (*pGCT->funcs->ChangeClip) (pGCT, CT_REGION, prgnSrcClip, 0);
42035c4bbdfSmrg    ValidateGC((DrawablePtr) pPixmap, pGCT);
42105b261ecSmrg
42205b261ecSmrg    /* Since we know pDraw is always a pixmap, we never need to think
42305b261ecSmrg     * about translation here */
42435c4bbdfSmrg    for (i = 0; i < h; i++) {
42535c4bbdfSmrg        ppt->x = 0;
42635c4bbdfSmrg        ppt++->y = i;
42735c4bbdfSmrg        *pwidth++ = w + srcx;
42805b261ecSmrg    }
42905b261ecSmrg
43035c4bbdfSmrg    (*pGCT->ops->SetSpans) ((DrawablePtr) pPixmap, pGCT, (char *) pbits,
43135c4bbdfSmrg                            pptFirst, pwidthFirst, h, TRUE);
4326747b715Smrg    free(pwidthFirst);
4336747b715Smrg    free(pptFirst);
43405b261ecSmrg
43505b261ecSmrg    /* Save current values from the client GC */
43605b261ecSmrg    oldfill = pGC->fillStyle;
43705b261ecSmrg    pStipple = pGC->stipple;
43835c4bbdfSmrg    if (pStipple)
43905b261ecSmrg        pStipple->refcnt++;
44005b261ecSmrg    oldOrg = pGC->patOrg;
44105b261ecSmrg
44205b261ecSmrg    /* Set a new stipple in the drawable */
44305b261ecSmrg    gcv[0].val = FillStippled;
44405b261ecSmrg    gcv[1].ptr = pPixmap;
44505b261ecSmrg    gcv[2].val = dstx - srcx;
44605b261ecSmrg    gcv[3].val = dsty;
44705b261ecSmrg
4486747b715Smrg    ChangeGC(NullClient, pGC,
44905b261ecSmrg             GCFillStyle | GCStipple | GCTileStipXOrigin | GCTileStipYOrigin,
45035c4bbdfSmrg             gcv);
45105b261ecSmrg    ValidateGC(pDraw, pGC);
45205b261ecSmrg
45305b261ecSmrg    /* Fill the drawable with the stipple.  This will draw the
454ed6184dfSmrg     * foreground color wherever 1 bits are set, leaving everything
45505b261ecSmrg     * with 0 bits untouched.  Note that the part outside the clip
45605b261ecSmrg     * region is all 0s.  */
45705b261ecSmrg    rect.x = dstx;
45805b261ecSmrg    rect.y = dsty;
45905b261ecSmrg    rect.width = w;
46005b261ecSmrg    rect.height = h;
46135c4bbdfSmrg    (*pGC->ops->PolyFillRect) (pDraw, pGC, 1, &rect);
46205b261ecSmrg
46305b261ecSmrg    /* Invert the tiling pixmap. This sets 0s for 1s and 1s for 0s, only
46405b261ecSmrg     * within the clipping region, the part outside is still all 0s */
46505b261ecSmrg    gcv[0].val = GXinvert;
4666747b715Smrg    ChangeGC(NullClient, pGCT, GCFunction, gcv);
46735c4bbdfSmrg    ValidateGC((DrawablePtr) pPixmap, pGCT);
46835c4bbdfSmrg    (*pGCT->ops->CopyArea) ((DrawablePtr) pPixmap, (DrawablePtr) pPixmap,
46935c4bbdfSmrg                            pGCT, 0, 0, w + srcx, h, 0, 0);
47005b261ecSmrg
47105b261ecSmrg    /* Swap foreground and background colors on the GC for the drawable.
47205b261ecSmrg     * Now when we fill the drawable, we will fill in the "Background"
47305b261ecSmrg     * values */
47405b261ecSmrg    oldfg = pGC->fgPixel;
47505b261ecSmrg    gcv[0].val = pGC->bgPixel;
47605b261ecSmrg    gcv[1].val = oldfg;
47705b261ecSmrg    gcv[2].ptr = pPixmap;
4786747b715Smrg    ChangeGC(NullClient, pGC, GCForeground | GCBackground | GCStipple, gcv);
47905b261ecSmrg    ValidateGC(pDraw, pGC);
48005b261ecSmrg    /* PolyFillRect might have bashed the rectangle */
48105b261ecSmrg    rect.x = dstx;
48205b261ecSmrg    rect.y = dsty;
48305b261ecSmrg    rect.width = w;
48405b261ecSmrg    rect.height = h;
48535c4bbdfSmrg    (*pGC->ops->PolyFillRect) (pDraw, pGC, 1, &rect);
48605b261ecSmrg
48705b261ecSmrg    /* Now put things back */
48835c4bbdfSmrg    if (pStipple)
48905b261ecSmrg        pStipple->refcnt--;
49005b261ecSmrg    gcv[0].val = oldfg;
49105b261ecSmrg    gcv[1].val = pGC->fgPixel;
49205b261ecSmrg    gcv[2].val = oldfill;
49305b261ecSmrg    gcv[3].ptr = pStipple;
49405b261ecSmrg    gcv[4].val = oldOrg.x;
49505b261ecSmrg    gcv[5].val = oldOrg.y;
4966747b715Smrg    ChangeGC(NullClient, pGC,
49735c4bbdfSmrg             GCForeground | GCBackground | GCFillStyle | GCStipple |
49835c4bbdfSmrg             GCTileStipXOrigin | GCTileStipYOrigin, gcv);
49905b261ecSmrg
50005b261ecSmrg    ValidateGC(pDraw, pGC);
50105b261ecSmrg    /* put what we hope is a smaller clip region back in the scratch gc */
50235c4bbdfSmrg    (*pGCT->funcs->ChangeClip) (pGCT, CT_NONE, NULL, 0);
50305b261ecSmrg    FreeScratchGC(pGCT);
50435c4bbdfSmrg    (*pDraw->pScreen->DestroyPixmap) (pPixmap);
50505b261ecSmrg
50605b261ecSmrg}
50705b261ecSmrg
50805b261ecSmrg/* MICOPYPLANE -- public entry for the CopyPlane request.
50935c4bbdfSmrg * strategy:
51035c4bbdfSmrg * First build up a bitmap out of the bits requested
51105b261ecSmrg * build a source clip
51235c4bbdfSmrg * Use the bitmap we've built up as a Stipple for the destination
51305b261ecSmrg */
51435c4bbdfSmrg_X_COLD RegionPtr
51535c4bbdfSmrgmiCopyPlane(DrawablePtr pSrcDrawable,
51635c4bbdfSmrg            DrawablePtr pDstDrawable,
51735c4bbdfSmrg            GCPtr pGC,
51835c4bbdfSmrg            int srcx,
51935c4bbdfSmrg            int srcy,
52035c4bbdfSmrg            int width, int height, int dstx, int dsty, unsigned long bitPlane)
52105b261ecSmrg{
52235c4bbdfSmrg    MiBits *ptile;
52335c4bbdfSmrg    BoxRec box;
52435c4bbdfSmrg    RegionPtr prgnSrc, prgnExposed;
52505b261ecSmrg
52605b261ecSmrg    /* incorporate the source clip */
52705b261ecSmrg
52805b261ecSmrg    box.x1 = srcx + pSrcDrawable->x;
52905b261ecSmrg    box.y1 = srcy + pSrcDrawable->y;
53005b261ecSmrg    box.x2 = box.x1 + width;
53105b261ecSmrg    box.y2 = box.y1 + height;
53205b261ecSmrg    /* clip to visible drawable */
53305b261ecSmrg    if (box.x1 < pSrcDrawable->x)
53435c4bbdfSmrg        box.x1 = pSrcDrawable->x;
53505b261ecSmrg    if (box.y1 < pSrcDrawable->y)
53635c4bbdfSmrg        box.y1 = pSrcDrawable->y;
53705b261ecSmrg    if (box.x2 > pSrcDrawable->x + (int) pSrcDrawable->width)
53835c4bbdfSmrg        box.x2 = pSrcDrawable->x + (int) pSrcDrawable->width;
53905b261ecSmrg    if (box.y2 > pSrcDrawable->y + (int) pSrcDrawable->height)
54035c4bbdfSmrg        box.y2 = pSrcDrawable->y + (int) pSrcDrawable->height;
54105b261ecSmrg    if (box.x1 > box.x2)
54235c4bbdfSmrg        box.x2 = box.x1;
54305b261ecSmrg    if (box.y1 > box.y2)
54435c4bbdfSmrg        box.y2 = box.y1;
5456747b715Smrg    prgnSrc = RegionCreate(&box, 1);
54605b261ecSmrg
54705b261ecSmrg    if (pSrcDrawable->type != DRAWABLE_PIXMAP) {
54835c4bbdfSmrg        /* clip to visible drawable */
54935c4bbdfSmrg
55035c4bbdfSmrg        if (pGC->subWindowMode == IncludeInferiors) {
55135c4bbdfSmrg            RegionPtr clipList = NotClippedByChildren((WindowPtr) pSrcDrawable);
55235c4bbdfSmrg
55335c4bbdfSmrg            RegionIntersect(prgnSrc, prgnSrc, clipList);
55435c4bbdfSmrg            RegionDestroy(clipList);
55535c4bbdfSmrg        }
55635c4bbdfSmrg        else
55735c4bbdfSmrg            RegionIntersect(prgnSrc, prgnSrc,
55835c4bbdfSmrg                            &((WindowPtr) pSrcDrawable)->clipList);
55905b261ecSmrg    }
56005b261ecSmrg
5616747b715Smrg    box = *RegionExtents(prgnSrc);
5626747b715Smrg    RegionTranslate(prgnSrc, -box.x1, -box.y1);
56305b261ecSmrg
56435c4bbdfSmrg    if ((box.x2 > box.x1) && (box.y2 > box.y1)) {
56535c4bbdfSmrg        /* minimize the size of the data extracted */
56635c4bbdfSmrg        /* note that we convert the plane mask bitPlane into a plane number */
56735c4bbdfSmrg        box.x1 -= pSrcDrawable->x;
56835c4bbdfSmrg        box.x2 -= pSrcDrawable->x;
56935c4bbdfSmrg        box.y1 -= pSrcDrawable->y;
57035c4bbdfSmrg        box.y2 -= pSrcDrawable->y;
57135c4bbdfSmrg        ptile = miGetPlane(pSrcDrawable, ffs(bitPlane) - 1,
57235c4bbdfSmrg                           box.x1, box.y1,
57335c4bbdfSmrg                           box.x2 - box.x1, box.y2 - box.y1, (MiBits *) NULL);
57435c4bbdfSmrg        if (ptile) {
57535c4bbdfSmrg            miOpqStipDrawable(pDstDrawable, pGC, prgnSrc, ptile, 0,
57635c4bbdfSmrg                              box.x2 - box.x1, box.y2 - box.y1,
57735c4bbdfSmrg                              dstx + box.x1 - srcx, dsty + box.y1 - srcy);
57835c4bbdfSmrg            free(ptile);
57935c4bbdfSmrg        }
58005b261ecSmrg    }
58105b261ecSmrg    prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC, srcx, srcy,
58235c4bbdfSmrg                                    width, height, dstx, dsty);
5836747b715Smrg    RegionDestroy(prgnSrc);
58405b261ecSmrg    return prgnExposed;
58505b261ecSmrg}
58605b261ecSmrg
58705b261ecSmrg/* MIGETIMAGE -- public entry for the GetImage Request
58805b261ecSmrg * We're getting the image into a memory buffer. While we have to use GetSpans
58905b261ecSmrg * to read a line from the device (since we don't know what that looks like),
59005b261ecSmrg * we can just write into the destination buffer
59105b261ecSmrg *
59205b261ecSmrg * two different strategies are used, depending on whether we're getting the
59305b261ecSmrg * image in Z format or XY format
59405b261ecSmrg * Z format:
59505b261ecSmrg * Line at a time, GetSpans a line into the destination buffer, then if the
59605b261ecSmrg * planemask is not all ones, we do a SetSpans into a temporary buffer (to get
59705b261ecSmrg * bits turned off) and then another GetSpans to get stuff back (because
59805b261ecSmrg * pixmaps are opaque, and we are passed in the memory to write into).  This is
59905b261ecSmrg * pretty ugly and slow but works.  Life is hard.
60005b261ecSmrg * XY format:
60105b261ecSmrg * get the single plane specified in planemask
60205b261ecSmrg */
60335c4bbdfSmrg_X_COLD void
60435c4bbdfSmrgmiGetImage(DrawablePtr pDraw, int sx, int sy, int w, int h,
60535c4bbdfSmrg           unsigned int format, unsigned long planeMask, char *pDst)
60605b261ecSmrg{
60735c4bbdfSmrg    unsigned char depth;
60835c4bbdfSmrg    int i, linelength, width, srcx, srcy;
60935c4bbdfSmrg    DDXPointRec pt = { 0, 0 };
61035c4bbdfSmrg    PixmapPtr pPixmap = NULL;
61135c4bbdfSmrg    GCPtr pGC = NULL;
61205b261ecSmrg
61305b261ecSmrg    depth = pDraw->depth;
61435c4bbdfSmrg    if (format == ZPixmap) {
61535c4bbdfSmrg        if ((((1LL << depth) - 1) & planeMask) != (1LL << depth) - 1) {
61635c4bbdfSmrg            ChangeGCVal gcv;
61735c4bbdfSmrg            xPoint xpt;
61835c4bbdfSmrg
61935c4bbdfSmrg            pGC = GetScratchGC(depth, pDraw->pScreen);
62035c4bbdfSmrg            if (!pGC)
62135c4bbdfSmrg                return;
62205b261ecSmrg            pPixmap = (*pDraw->pScreen->CreatePixmap)
62335c4bbdfSmrg                (pDraw->pScreen, w, 1, depth, CREATE_PIXMAP_USAGE_SCRATCH);
62435c4bbdfSmrg            if (!pPixmap) {
62535c4bbdfSmrg                FreeScratchGC(pGC);
62635c4bbdfSmrg                return;
62735c4bbdfSmrg            }
62835c4bbdfSmrg            /*
62935c4bbdfSmrg             * Clear the pixmap before doing anything else
63035c4bbdfSmrg             */
63135c4bbdfSmrg            ValidateGC((DrawablePtr) pPixmap, pGC);
63235c4bbdfSmrg            xpt.x = xpt.y = 0;
63305b261ecSmrg            width = w;
63435c4bbdfSmrg            (*pGC->ops->FillSpans) ((DrawablePtr) pPixmap, pGC, 1, &xpt, &width,
63535c4bbdfSmrg                                    TRUE);
63635c4bbdfSmrg
63735c4bbdfSmrg            /* alu is already GXCopy */
63835c4bbdfSmrg            gcv.val = (XID) planeMask;
63935c4bbdfSmrg            ChangeGC(NullClient, pGC, GCPlaneMask, &gcv);
64035c4bbdfSmrg            ValidateGC((DrawablePtr) pPixmap, pGC);
64135c4bbdfSmrg        }
64205b261ecSmrg
64305b261ecSmrg        linelength = PixmapBytePad(w, depth);
64435c4bbdfSmrg        srcx = sx + pDraw->x;
64535c4bbdfSmrg        srcy = sy + pDraw->y;
64635c4bbdfSmrg        for (i = 0; i < h; i++) {
64735c4bbdfSmrg            pt.x = srcx;
64835c4bbdfSmrg            pt.y = srcy + i;
64935c4bbdfSmrg            width = w;
65035c4bbdfSmrg            (*pDraw->pScreen->GetSpans) (pDraw, w, &pt, &width, 1, pDst);
65135c4bbdfSmrg            if (pPixmap) {
65235c4bbdfSmrg                pt.x = 0;
65335c4bbdfSmrg                pt.y = 0;
65435c4bbdfSmrg                width = w;
65535c4bbdfSmrg                (*pGC->ops->SetSpans) ((DrawablePtr) pPixmap, pGC, pDst,
65635c4bbdfSmrg                                       &pt, &width, 1, TRUE);
65735c4bbdfSmrg                (*pDraw->pScreen->GetSpans) ((DrawablePtr) pPixmap, w, &pt,
65835c4bbdfSmrg                                             &width, 1, pDst);
65935c4bbdfSmrg            }
66035c4bbdfSmrg            pDst += linelength;
66135c4bbdfSmrg        }
66235c4bbdfSmrg        if (pPixmap) {
66335c4bbdfSmrg            (*pGC->pScreen->DestroyPixmap) (pPixmap);
66435c4bbdfSmrg            FreeScratchGC(pGC);
66535c4bbdfSmrg        }
66605b261ecSmrg    }
66735c4bbdfSmrg    else {
66835c4bbdfSmrg        (void) miGetPlane(pDraw, ffs(planeMask) - 1, sx, sy, w, h,
66935c4bbdfSmrg                          (MiBits *) pDst);
67005b261ecSmrg    }
67105b261ecSmrg}
67205b261ecSmrg
67305b261ecSmrg/* MIPUTIMAGE -- public entry for the PutImage request
67405b261ecSmrg * Here we benefit from knowing the format of the bits pointed to by pImage,
67535c4bbdfSmrg * even if we don't know how pDraw represents them.
67635c4bbdfSmrg * Three different strategies are used depending on the format
67705b261ecSmrg * XYBitmap Format:
67805b261ecSmrg * 	we just use the Opaque Stipple helper function to cover the destination
67935c4bbdfSmrg * 	Note that this covers all the planes of the drawable with the
68005b261ecSmrg *	foreground color (masked with the GC planemask) where there are 1 bits
68105b261ecSmrg *	and the background color (masked with the GC planemask) where there are
68205b261ecSmrg *	0 bits
68305b261ecSmrg * XYPixmap format:
68435c4bbdfSmrg *	what we're called with is a series of XYBitmaps, but we only want
68505b261ecSmrg *	each XYPixmap to update 1 plane, instead of updating all of them.
68605b261ecSmrg * 	we set the foreground color to be all 1s and the background to all 0s
68705b261ecSmrg *	then for each plane, we set the plane mask to only effect that one
68805b261ecSmrg *	plane and recursive call ourself with the format set to XYBitmap
68905b261ecSmrg *	(This clever idea courtesy of RGD.)
69005b261ecSmrg * ZPixmap format:
69105b261ecSmrg *	This part is simple, just call SetSpans
69205b261ecSmrg */
69335c4bbdfSmrg_X_COLD void
69435c4bbdfSmrgmiPutImage(DrawablePtr pDraw, GCPtr pGC, int depth,
69535c4bbdfSmrg           int x, int y, int w, int h, int leftPad, int format, char *pImage)
69605b261ecSmrg{
69735c4bbdfSmrg    DDXPointPtr pptFirst, ppt;
69835c4bbdfSmrg    int *pwidthFirst, *pwidth;
69935c4bbdfSmrg    RegionPtr prgnSrc;
70035c4bbdfSmrg    BoxRec box;
70135c4bbdfSmrg    unsigned long oldFg, oldBg;
70235c4bbdfSmrg    ChangeGCVal gcv[3];
70335c4bbdfSmrg    unsigned long oldPlanemask;
70435c4bbdfSmrg    unsigned long i;
70535c4bbdfSmrg    long bytesPer;
70605b261ecSmrg
70705b261ecSmrg    if (!w || !h)
70835c4bbdfSmrg        return;
70935c4bbdfSmrg    switch (format) {
71035c4bbdfSmrg    case XYBitmap:
71105b261ecSmrg
71235c4bbdfSmrg        box.x1 = 0;
71335c4bbdfSmrg        box.y1 = 0;
71435c4bbdfSmrg        box.x2 = w;
71535c4bbdfSmrg        box.y2 = h;
71635c4bbdfSmrg        prgnSrc = RegionCreate(&box, 1);
71705b261ecSmrg
71805b261ecSmrg        miOpqStipDrawable(pDraw, pGC, prgnSrc, (MiBits *) pImage,
71935c4bbdfSmrg                          leftPad, w, h, x, y);
72035c4bbdfSmrg        RegionDestroy(prgnSrc);
72135c4bbdfSmrg        break;
72235c4bbdfSmrg
72335c4bbdfSmrg    case XYPixmap:
72435c4bbdfSmrg        depth = pGC->depth;
72535c4bbdfSmrg        oldPlanemask = pGC->planemask;
72635c4bbdfSmrg        oldFg = pGC->fgPixel;
72735c4bbdfSmrg        oldBg = pGC->bgPixel;
72835c4bbdfSmrg        gcv[0].val = (XID) ~0;
72935c4bbdfSmrg        gcv[1].val = (XID) 0;
73035c4bbdfSmrg        ChangeGC(NullClient, pGC, GCForeground | GCBackground, gcv);
73135c4bbdfSmrg        bytesPer = (long) h *BitmapBytePad(w + leftPad);
73235c4bbdfSmrg
73335c4bbdfSmrg        for (i = (unsigned long) 1 << (depth - 1); i != 0; i >>= 1, pImage += bytesPer) {
73435c4bbdfSmrg            if (i & oldPlanemask) {
73535c4bbdfSmrg                gcv[0].val = (XID) i;
73635c4bbdfSmrg                ChangeGC(NullClient, pGC, GCPlaneMask, gcv);
73735c4bbdfSmrg                ValidateGC(pDraw, pGC);
73835c4bbdfSmrg                (*pGC->ops->PutImage) (pDraw, pGC, 1, x, y, w, h, leftPad,
73935c4bbdfSmrg                                       XYBitmap, (char *) pImage);
74035c4bbdfSmrg            }
74135c4bbdfSmrg        }
74235c4bbdfSmrg        gcv[0].val = (XID) oldPlanemask;
74335c4bbdfSmrg        gcv[1].val = (XID) oldFg;
74435c4bbdfSmrg        gcv[2].val = (XID) oldBg;
74535c4bbdfSmrg        ChangeGC(NullClient, pGC, GCPlaneMask | GCForeground | GCBackground,
74635c4bbdfSmrg                 gcv);
74735c4bbdfSmrg        ValidateGC(pDraw, pGC);
74835c4bbdfSmrg        break;
74935c4bbdfSmrg
75035c4bbdfSmrg    case ZPixmap:
75135c4bbdfSmrg        ppt = pptFirst = xallocarray(h, sizeof(DDXPointRec));
75235c4bbdfSmrg        pwidth = pwidthFirst = xallocarray(h, sizeof(int));
75335c4bbdfSmrg        if (!pptFirst || !pwidthFirst) {
75435c4bbdfSmrg            free(pwidthFirst);
75535c4bbdfSmrg            free(pptFirst);
75635c4bbdfSmrg            return;
75735c4bbdfSmrg        }
75835c4bbdfSmrg        if (pGC->miTranslate) {
75935c4bbdfSmrg            x += pDraw->x;
76035c4bbdfSmrg            y += pDraw->y;
76105b261ecSmrg        }
76235c4bbdfSmrg
76335c4bbdfSmrg        for (i = 0; i < h; i++) {
76435c4bbdfSmrg            ppt->x = x;
76535c4bbdfSmrg            ppt->y = y + i;
76635c4bbdfSmrg            ppt++;
76735c4bbdfSmrg            *pwidth++ = w;
76835c4bbdfSmrg        }
76935c4bbdfSmrg
77035c4bbdfSmrg        (*pGC->ops->SetSpans) (pDraw, pGC, (char *) pImage, pptFirst,
77135c4bbdfSmrg                               pwidthFirst, h, TRUE);
77235c4bbdfSmrg        free(pwidthFirst);
77335c4bbdfSmrg        free(pptFirst);
77435c4bbdfSmrg        break;
77505b261ecSmrg    }
77605b261ecSmrg}
777