16747b715Smrg/*
26747b715Smrg * Copyright © 1998 Keith Packard
36747b715Smrg *
46747b715Smrg * Permission to use, copy, modify, distribute, and sell this software and its
56747b715Smrg * documentation for any purpose is hereby granted without fee, provided that
66747b715Smrg * the above copyright notice appear in all copies and that both that
76747b715Smrg * copyright notice and this permission notice appear in supporting
86747b715Smrg * documentation, and that the name of Keith Packard not be used in
96747b715Smrg * advertising or publicity pertaining to distribution of the software without
106747b715Smrg * specific, written prior permission.  Keith Packard makes no
116747b715Smrg * representations about the suitability of this software for any purpose.  It
126747b715Smrg * is provided "as is" without express or implied warranty.
136747b715Smrg *
146747b715Smrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
156747b715Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
166747b715Smrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
176747b715Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
186747b715Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
196747b715Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
206747b715Smrg * PERFORMANCE OF THIS SOFTWARE.
216747b715Smrg */
226747b715Smrg
236747b715Smrg#ifdef HAVE_DIX_CONFIG_H
246747b715Smrg#include <dix-config.h>
256747b715Smrg#endif
266747b715Smrg
276747b715Smrg#include "mi.h"
286747b715Smrg#include "scrnintstr.h"
296747b715Smrg#include "gcstruct.h"
306747b715Smrg#include "pixmap.h"
316747b715Smrg#include "pixmapstr.h"
326747b715Smrg#include "windowstr.h"
336747b715Smrg
346747b715Smrgvoid
3535c4bbdfSmrgmiCopyRegion(DrawablePtr pSrcDrawable,
3635c4bbdfSmrg             DrawablePtr pDstDrawable,
3735c4bbdfSmrg             GCPtr pGC,
3835c4bbdfSmrg             RegionPtr pDstRegion,
3935c4bbdfSmrg             int dx, int dy, miCopyProc copyProc, Pixel bitPlane, void *closure)
406747b715Smrg{
4135c4bbdfSmrg    int careful;
4235c4bbdfSmrg    Bool reverse;
4335c4bbdfSmrg    Bool upsidedown;
4435c4bbdfSmrg    BoxPtr pbox;
4535c4bbdfSmrg    int nbox;
4635c4bbdfSmrg    BoxPtr pboxNew1, pboxNew2, pboxBase, pboxNext, pboxTmp;
4735c4bbdfSmrg
486747b715Smrg    pbox = RegionRects(pDstRegion);
496747b715Smrg    nbox = RegionNumRects(pDstRegion);
5035c4bbdfSmrg
516747b715Smrg    /* XXX we have to err on the side of safety when both are windows,
526747b715Smrg     * because we don't know if IncludeInferiors is being used.
536747b715Smrg     */
546747b715Smrg    careful = ((pSrcDrawable == pDstDrawable) ||
5535c4bbdfSmrg               ((pSrcDrawable->type == DRAWABLE_WINDOW) &&
5635c4bbdfSmrg                (pDstDrawable->type == DRAWABLE_WINDOW)));
576747b715Smrg
586747b715Smrg    pboxNew1 = NULL;
596747b715Smrg    pboxNew2 = NULL;
6035c4bbdfSmrg    if (careful && dy < 0) {
6135c4bbdfSmrg        upsidedown = TRUE;
6235c4bbdfSmrg
6335c4bbdfSmrg        if (nbox > 1) {
6435c4bbdfSmrg            /* keep ordering in each band, reverse order of bands */
6535c4bbdfSmrg            pboxNew1 = xallocarray(nbox, sizeof(BoxRec));
6635c4bbdfSmrg            if (!pboxNew1)
6735c4bbdfSmrg                return;
6835c4bbdfSmrg            pboxBase = pboxNext = pbox + nbox - 1;
6935c4bbdfSmrg            while (pboxBase >= pbox) {
7035c4bbdfSmrg                while ((pboxNext >= pbox) && (pboxBase->y1 == pboxNext->y1))
7135c4bbdfSmrg                    pboxNext--;
7235c4bbdfSmrg                pboxTmp = pboxNext + 1;
7335c4bbdfSmrg                while (pboxTmp <= pboxBase) {
7435c4bbdfSmrg                    *pboxNew1++ = *pboxTmp++;
7535c4bbdfSmrg                }
7635c4bbdfSmrg                pboxBase = pboxNext;
7735c4bbdfSmrg            }
7835c4bbdfSmrg            pboxNew1 -= nbox;
7935c4bbdfSmrg            pbox = pboxNew1;
8035c4bbdfSmrg        }
816747b715Smrg    }
8235c4bbdfSmrg    else {
8335c4bbdfSmrg        /* walk source top to bottom */
8435c4bbdfSmrg        upsidedown = FALSE;
856747b715Smrg    }
866747b715Smrg
8735c4bbdfSmrg    if (careful && dx < 0) {
8835c4bbdfSmrg        /* walk source right to left */
8935c4bbdfSmrg        if (dy <= 0)
9035c4bbdfSmrg            reverse = TRUE;
9135c4bbdfSmrg        else
9235c4bbdfSmrg            reverse = FALSE;
9335c4bbdfSmrg
9435c4bbdfSmrg        if (nbox > 1) {
9535c4bbdfSmrg            /* reverse order of rects in each band */
9635c4bbdfSmrg            pboxNew2 = xallocarray(nbox, sizeof(BoxRec));
9735c4bbdfSmrg            if (!pboxNew2) {
9835c4bbdfSmrg                free(pboxNew1);
9935c4bbdfSmrg                return;
10035c4bbdfSmrg            }
10135c4bbdfSmrg            pboxBase = pboxNext = pbox;
10235c4bbdfSmrg            while (pboxBase < pbox + nbox) {
10335c4bbdfSmrg                while ((pboxNext < pbox + nbox) &&
10435c4bbdfSmrg                       (pboxNext->y1 == pboxBase->y1))
10535c4bbdfSmrg                    pboxNext++;
10635c4bbdfSmrg                pboxTmp = pboxNext;
10735c4bbdfSmrg                while (pboxTmp != pboxBase) {
10835c4bbdfSmrg                    *pboxNew2++ = *--pboxTmp;
10935c4bbdfSmrg                }
11035c4bbdfSmrg                pboxBase = pboxNext;
11135c4bbdfSmrg            }
11235c4bbdfSmrg            pboxNew2 -= nbox;
11335c4bbdfSmrg            pbox = pboxNew2;
11435c4bbdfSmrg        }
1156747b715Smrg    }
11635c4bbdfSmrg    else {
11735c4bbdfSmrg        /* walk source left to right */
11835c4bbdfSmrg        reverse = FALSE;
1196747b715Smrg    }
1206747b715Smrg
1216747b715Smrg    (*copyProc) (pSrcDrawable,
12235c4bbdfSmrg                 pDstDrawable,
12335c4bbdfSmrg                 pGC,
12435c4bbdfSmrg                 pbox, nbox, dx, dy, reverse, upsidedown, bitPlane, closure);
12535c4bbdfSmrg
1266747b715Smrg    free(pboxNew1);
1276747b715Smrg    free(pboxNew2);
1286747b715Smrg}
1296747b715Smrg
1306747b715SmrgRegionPtr
13135c4bbdfSmrgmiDoCopy(DrawablePtr pSrcDrawable,
13235c4bbdfSmrg         DrawablePtr pDstDrawable,
13335c4bbdfSmrg         GCPtr pGC,
13435c4bbdfSmrg         int xIn,
13535c4bbdfSmrg         int yIn,
13635c4bbdfSmrg         int widthSrc,
13735c4bbdfSmrg         int heightSrc,
13835c4bbdfSmrg         int xOut, int yOut, miCopyProc copyProc, Pixel bitPlane, void *closure)
1396747b715Smrg{
14035c4bbdfSmrg    RegionPtr prgnSrcClip = NULL;       /* may be a new region, or just a copy */
14135c4bbdfSmrg    Bool freeSrcClip = FALSE;
14235c4bbdfSmrg    RegionPtr prgnExposed = NULL;
14335c4bbdfSmrg    RegionRec rgnDst;
14435c4bbdfSmrg    int dx;
14535c4bbdfSmrg    int dy;
14635c4bbdfSmrg    int numRects;
14735c4bbdfSmrg    int box_x1;
14835c4bbdfSmrg    int box_y1;
14935c4bbdfSmrg    int box_x2;
15035c4bbdfSmrg    int box_y2;
15135c4bbdfSmrg    Bool fastSrc = FALSE;       /* for fast clipping with pixmap source */
15235c4bbdfSmrg    Bool fastDst = FALSE;       /* for fast clipping with one rect dest */
15335c4bbdfSmrg    Bool fastExpose = FALSE;    /* for fast exposures with pixmap source */
1546747b715Smrg
1556747b715Smrg    /* Short cut for unmapped windows */
1566747b715Smrg
15735c4bbdfSmrg    if (pDstDrawable->type == DRAWABLE_WINDOW &&
15835c4bbdfSmrg        !((WindowPtr) pDstDrawable)->realized) {
15935c4bbdfSmrg        return NULL;
1606747b715Smrg    }
1616747b715Smrg
162ed6184dfSmrg    (*pSrcDrawable->pScreen->SourceValidate) (pSrcDrawable, xIn, yIn,
163ed6184dfSmrg                                              widthSrc, heightSrc,
164ed6184dfSmrg                                              pGC->subWindowMode);
1656747b715Smrg
1666747b715Smrg    /* Compute source clip region */
16735c4bbdfSmrg    if (pSrcDrawable->type == DRAWABLE_PIXMAP) {
16835c4bbdfSmrg        if ((pSrcDrawable == pDstDrawable) && (!pGC->clientClip))
16935c4bbdfSmrg            prgnSrcClip = miGetCompositeClip(pGC);
17035c4bbdfSmrg        else
17135c4bbdfSmrg            fastSrc = TRUE;
1726747b715Smrg    }
17335c4bbdfSmrg    else {
17435c4bbdfSmrg        if (pGC->subWindowMode == IncludeInferiors) {
17535c4bbdfSmrg            /*
17635c4bbdfSmrg             * XFree86 DDX empties the border clip when the
17735c4bbdfSmrg             * VT is inactive, make sure the region isn't empty
17835c4bbdfSmrg             */
17935c4bbdfSmrg            if (!((WindowPtr) pSrcDrawable)->parent &&
18035c4bbdfSmrg                RegionNotEmpty(&((WindowPtr) pSrcDrawable)->borderClip)) {
18135c4bbdfSmrg                /*
18235c4bbdfSmrg                 * special case bitblt from root window in
18335c4bbdfSmrg                 * IncludeInferiors mode; just like from a pixmap
18435c4bbdfSmrg                 */
18535c4bbdfSmrg                fastSrc = TRUE;
18635c4bbdfSmrg            }
18735c4bbdfSmrg            else if ((pSrcDrawable == pDstDrawable) && (!pGC->clientClip)) {
18835c4bbdfSmrg                prgnSrcClip = miGetCompositeClip(pGC);
18935c4bbdfSmrg            }
19035c4bbdfSmrg            else {
19135c4bbdfSmrg                prgnSrcClip = NotClippedByChildren((WindowPtr) pSrcDrawable);
19235c4bbdfSmrg                freeSrcClip = TRUE;
19335c4bbdfSmrg            }
19435c4bbdfSmrg        }
19535c4bbdfSmrg        else {
19635c4bbdfSmrg            prgnSrcClip = &((WindowPtr) pSrcDrawable)->clipList;
19735c4bbdfSmrg        }
1986747b715Smrg    }
1996747b715Smrg
2006747b715Smrg    xIn += pSrcDrawable->x;
2016747b715Smrg    yIn += pSrcDrawable->y;
20235c4bbdfSmrg
2036747b715Smrg    xOut += pDstDrawable->x;
2046747b715Smrg    yOut += pDstDrawable->y;
2056747b715Smrg
2066747b715Smrg    box_x1 = xIn;
2076747b715Smrg    box_y1 = yIn;
2086747b715Smrg    box_x2 = xIn + widthSrc;
2096747b715Smrg    box_y2 = yIn + heightSrc;
2106747b715Smrg
2116747b715Smrg    dx = xIn - xOut;
2126747b715Smrg    dy = yIn - yOut;
2136747b715Smrg
2146747b715Smrg    /* Don't create a source region if we are doing a fast clip */
21535c4bbdfSmrg    if (fastSrc) {
21635c4bbdfSmrg        RegionPtr cclip;
21735c4bbdfSmrg
21835c4bbdfSmrg        fastExpose = TRUE;
21935c4bbdfSmrg        /*
22035c4bbdfSmrg         * clip the source; if regions extend beyond the source size,
22135c4bbdfSmrg         * make sure exposure events get sent
22235c4bbdfSmrg         */
22335c4bbdfSmrg        if (box_x1 < pSrcDrawable->x) {
22435c4bbdfSmrg            box_x1 = pSrcDrawable->x;
22535c4bbdfSmrg            fastExpose = FALSE;
22635c4bbdfSmrg        }
22735c4bbdfSmrg        if (box_y1 < pSrcDrawable->y) {
22835c4bbdfSmrg            box_y1 = pSrcDrawable->y;
22935c4bbdfSmrg            fastExpose = FALSE;
23035c4bbdfSmrg        }
23135c4bbdfSmrg        if (box_x2 > pSrcDrawable->x + (int) pSrcDrawable->width) {
23235c4bbdfSmrg            box_x2 = pSrcDrawable->x + (int) pSrcDrawable->width;
23335c4bbdfSmrg            fastExpose = FALSE;
23435c4bbdfSmrg        }
23535c4bbdfSmrg        if (box_y2 > pSrcDrawable->y + (int) pSrcDrawable->height) {
23635c4bbdfSmrg            box_y2 = pSrcDrawable->y + (int) pSrcDrawable->height;
23735c4bbdfSmrg            fastExpose = FALSE;
23835c4bbdfSmrg        }
23935c4bbdfSmrg
24035c4bbdfSmrg        /* Translate and clip the dst to the destination composite clip */
2416747b715Smrg        box_x1 -= dx;
2426747b715Smrg        box_x2 -= dx;
2436747b715Smrg        box_y1 -= dy;
2446747b715Smrg        box_y2 -= dy;
2456747b715Smrg
24635c4bbdfSmrg        /* If the destination composite clip is one rectangle we can
24735c4bbdfSmrg           do the clip directly.  Otherwise we have to create a full
24835c4bbdfSmrg           blown region and call intersect */
24935c4bbdfSmrg
25035c4bbdfSmrg        cclip = miGetCompositeClip(pGC);
25135c4bbdfSmrg        if (RegionNumRects(cclip) == 1) {
25235c4bbdfSmrg            BoxPtr pBox = RegionRects(cclip);
25335c4bbdfSmrg
25435c4bbdfSmrg            if (box_x1 < pBox->x1)
25535c4bbdfSmrg                box_x1 = pBox->x1;
25635c4bbdfSmrg            if (box_x2 > pBox->x2)
25735c4bbdfSmrg                box_x2 = pBox->x2;
25835c4bbdfSmrg            if (box_y1 < pBox->y1)
25935c4bbdfSmrg                box_y1 = pBox->y1;
26035c4bbdfSmrg            if (box_y2 > pBox->y2)
26135c4bbdfSmrg                box_y2 = pBox->y2;
26235c4bbdfSmrg            fastDst = TRUE;
26335c4bbdfSmrg        }
2646747b715Smrg    }
26535c4bbdfSmrg
2666747b715Smrg    /* Check to see if the region is empty */
26735c4bbdfSmrg    if (box_x1 >= box_x2 || box_y1 >= box_y2) {
26835c4bbdfSmrg        RegionNull(&rgnDst);
2696747b715Smrg    }
27035c4bbdfSmrg    else {
27135c4bbdfSmrg        BoxRec box;
27235c4bbdfSmrg
27335c4bbdfSmrg        box.x1 = box_x1;
27435c4bbdfSmrg        box.y1 = box_y1;
27535c4bbdfSmrg        box.x2 = box_x2;
27635c4bbdfSmrg        box.y2 = box_y2;
27735c4bbdfSmrg        RegionInit(&rgnDst, &box, 1);
2786747b715Smrg    }
27935c4bbdfSmrg
2806747b715Smrg    /* Clip against complex source if needed */
28135c4bbdfSmrg    if (!fastSrc) {
28235c4bbdfSmrg        RegionIntersect(&rgnDst, &rgnDst, prgnSrcClip);
28335c4bbdfSmrg        RegionTranslate(&rgnDst, -dx, -dy);
2846747b715Smrg    }
2856747b715Smrg
2866747b715Smrg    /* Clip against complex dest if needed */
28735c4bbdfSmrg    if (!fastDst) {
28835c4bbdfSmrg        RegionIntersect(&rgnDst, &rgnDst, miGetCompositeClip(pGC));
2896747b715Smrg    }
2906747b715Smrg
2916747b715Smrg    /* Do bit blitting */
2926747b715Smrg    numRects = RegionNumRects(&rgnDst);
2936747b715Smrg    if (numRects && widthSrc && heightSrc)
29435c4bbdfSmrg        miCopyRegion(pSrcDrawable, pDstDrawable, pGC,
29535c4bbdfSmrg                     &rgnDst, dx, dy, copyProc, bitPlane, closure);
2966747b715Smrg
2976747b715Smrg    /* Pixmap sources generate a NoExposed (we return NULL to do this) */
2986747b715Smrg    if (!fastExpose && pGC->fExpose)
29935c4bbdfSmrg        prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC,
30035c4bbdfSmrg                                        xIn - pSrcDrawable->x,
30135c4bbdfSmrg                                        yIn - pSrcDrawable->y,
30235c4bbdfSmrg                                        widthSrc, heightSrc,
30335c4bbdfSmrg                                        xOut - pDstDrawable->x,
30435c4bbdfSmrg                                        yOut - pDstDrawable->y);
3056747b715Smrg    RegionUninit(&rgnDst);
3066747b715Smrg    if (freeSrcClip)
30735c4bbdfSmrg        RegionDestroy(prgnSrcClip);
3086747b715Smrg    return prgnExposed;
3096747b715Smrg}
310