micopy.c revision 35c4bbdf
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
16235c4bbdfSmrg    if (pSrcDrawable->pScreen->SourceValidate) {
16335c4bbdfSmrg        (*pSrcDrawable->pScreen->SourceValidate) (pSrcDrawable, xIn, yIn,
16435c4bbdfSmrg                                                  widthSrc, heightSrc,
16535c4bbdfSmrg                                                  pGC->subWindowMode);
1666747b715Smrg    }
1676747b715Smrg
1686747b715Smrg    /* Compute source clip region */
16935c4bbdfSmrg    if (pSrcDrawable->type == DRAWABLE_PIXMAP) {
17035c4bbdfSmrg        if ((pSrcDrawable == pDstDrawable) && (!pGC->clientClip))
17135c4bbdfSmrg            prgnSrcClip = miGetCompositeClip(pGC);
17235c4bbdfSmrg        else
17335c4bbdfSmrg            fastSrc = TRUE;
1746747b715Smrg    }
17535c4bbdfSmrg    else {
17635c4bbdfSmrg        if (pGC->subWindowMode == IncludeInferiors) {
17735c4bbdfSmrg            /*
17835c4bbdfSmrg             * XFree86 DDX empties the border clip when the
17935c4bbdfSmrg             * VT is inactive, make sure the region isn't empty
18035c4bbdfSmrg             */
18135c4bbdfSmrg            if (!((WindowPtr) pSrcDrawable)->parent &&
18235c4bbdfSmrg                RegionNotEmpty(&((WindowPtr) pSrcDrawable)->borderClip)) {
18335c4bbdfSmrg                /*
18435c4bbdfSmrg                 * special case bitblt from root window in
18535c4bbdfSmrg                 * IncludeInferiors mode; just like from a pixmap
18635c4bbdfSmrg                 */
18735c4bbdfSmrg                fastSrc = TRUE;
18835c4bbdfSmrg            }
18935c4bbdfSmrg            else if ((pSrcDrawable == pDstDrawable) && (!pGC->clientClip)) {
19035c4bbdfSmrg                prgnSrcClip = miGetCompositeClip(pGC);
19135c4bbdfSmrg            }
19235c4bbdfSmrg            else {
19335c4bbdfSmrg                prgnSrcClip = NotClippedByChildren((WindowPtr) pSrcDrawable);
19435c4bbdfSmrg                freeSrcClip = TRUE;
19535c4bbdfSmrg            }
19635c4bbdfSmrg        }
19735c4bbdfSmrg        else {
19835c4bbdfSmrg            prgnSrcClip = &((WindowPtr) pSrcDrawable)->clipList;
19935c4bbdfSmrg        }
2006747b715Smrg    }
2016747b715Smrg
2026747b715Smrg    xIn += pSrcDrawable->x;
2036747b715Smrg    yIn += pSrcDrawable->y;
20435c4bbdfSmrg
2056747b715Smrg    xOut += pDstDrawable->x;
2066747b715Smrg    yOut += pDstDrawable->y;
2076747b715Smrg
2086747b715Smrg    box_x1 = xIn;
2096747b715Smrg    box_y1 = yIn;
2106747b715Smrg    box_x2 = xIn + widthSrc;
2116747b715Smrg    box_y2 = yIn + heightSrc;
2126747b715Smrg
2136747b715Smrg    dx = xIn - xOut;
2146747b715Smrg    dy = yIn - yOut;
2156747b715Smrg
2166747b715Smrg    /* Don't create a source region if we are doing a fast clip */
21735c4bbdfSmrg    if (fastSrc) {
21835c4bbdfSmrg        RegionPtr cclip;
21935c4bbdfSmrg
22035c4bbdfSmrg        fastExpose = TRUE;
22135c4bbdfSmrg        /*
22235c4bbdfSmrg         * clip the source; if regions extend beyond the source size,
22335c4bbdfSmrg         * make sure exposure events get sent
22435c4bbdfSmrg         */
22535c4bbdfSmrg        if (box_x1 < pSrcDrawable->x) {
22635c4bbdfSmrg            box_x1 = pSrcDrawable->x;
22735c4bbdfSmrg            fastExpose = FALSE;
22835c4bbdfSmrg        }
22935c4bbdfSmrg        if (box_y1 < pSrcDrawable->y) {
23035c4bbdfSmrg            box_y1 = pSrcDrawable->y;
23135c4bbdfSmrg            fastExpose = FALSE;
23235c4bbdfSmrg        }
23335c4bbdfSmrg        if (box_x2 > pSrcDrawable->x + (int) pSrcDrawable->width) {
23435c4bbdfSmrg            box_x2 = pSrcDrawable->x + (int) pSrcDrawable->width;
23535c4bbdfSmrg            fastExpose = FALSE;
23635c4bbdfSmrg        }
23735c4bbdfSmrg        if (box_y2 > pSrcDrawable->y + (int) pSrcDrawable->height) {
23835c4bbdfSmrg            box_y2 = pSrcDrawable->y + (int) pSrcDrawable->height;
23935c4bbdfSmrg            fastExpose = FALSE;
24035c4bbdfSmrg        }
24135c4bbdfSmrg
24235c4bbdfSmrg        /* Translate and clip the dst to the destination composite clip */
2436747b715Smrg        box_x1 -= dx;
2446747b715Smrg        box_x2 -= dx;
2456747b715Smrg        box_y1 -= dy;
2466747b715Smrg        box_y2 -= dy;
2476747b715Smrg
24835c4bbdfSmrg        /* If the destination composite clip is one rectangle we can
24935c4bbdfSmrg           do the clip directly.  Otherwise we have to create a full
25035c4bbdfSmrg           blown region and call intersect */
25135c4bbdfSmrg
25235c4bbdfSmrg        cclip = miGetCompositeClip(pGC);
25335c4bbdfSmrg        if (RegionNumRects(cclip) == 1) {
25435c4bbdfSmrg            BoxPtr pBox = RegionRects(cclip);
25535c4bbdfSmrg
25635c4bbdfSmrg            if (box_x1 < pBox->x1)
25735c4bbdfSmrg                box_x1 = pBox->x1;
25835c4bbdfSmrg            if (box_x2 > pBox->x2)
25935c4bbdfSmrg                box_x2 = pBox->x2;
26035c4bbdfSmrg            if (box_y1 < pBox->y1)
26135c4bbdfSmrg                box_y1 = pBox->y1;
26235c4bbdfSmrg            if (box_y2 > pBox->y2)
26335c4bbdfSmrg                box_y2 = pBox->y2;
26435c4bbdfSmrg            fastDst = TRUE;
26535c4bbdfSmrg        }
2666747b715Smrg    }
26735c4bbdfSmrg
2686747b715Smrg    /* Check to see if the region is empty */
26935c4bbdfSmrg    if (box_x1 >= box_x2 || box_y1 >= box_y2) {
27035c4bbdfSmrg        RegionNull(&rgnDst);
2716747b715Smrg    }
27235c4bbdfSmrg    else {
27335c4bbdfSmrg        BoxRec box;
27435c4bbdfSmrg
27535c4bbdfSmrg        box.x1 = box_x1;
27635c4bbdfSmrg        box.y1 = box_y1;
27735c4bbdfSmrg        box.x2 = box_x2;
27835c4bbdfSmrg        box.y2 = box_y2;
27935c4bbdfSmrg        RegionInit(&rgnDst, &box, 1);
2806747b715Smrg    }
28135c4bbdfSmrg
2826747b715Smrg    /* Clip against complex source if needed */
28335c4bbdfSmrg    if (!fastSrc) {
28435c4bbdfSmrg        RegionIntersect(&rgnDst, &rgnDst, prgnSrcClip);
28535c4bbdfSmrg        RegionTranslate(&rgnDst, -dx, -dy);
2866747b715Smrg    }
2876747b715Smrg
2886747b715Smrg    /* Clip against complex dest if needed */
28935c4bbdfSmrg    if (!fastDst) {
29035c4bbdfSmrg        RegionIntersect(&rgnDst, &rgnDst, miGetCompositeClip(pGC));
2916747b715Smrg    }
2926747b715Smrg
2936747b715Smrg    /* Do bit blitting */
2946747b715Smrg    numRects = RegionNumRects(&rgnDst);
2956747b715Smrg    if (numRects && widthSrc && heightSrc)
29635c4bbdfSmrg        miCopyRegion(pSrcDrawable, pDstDrawable, pGC,
29735c4bbdfSmrg                     &rgnDst, dx, dy, copyProc, bitPlane, closure);
2986747b715Smrg
2996747b715Smrg    /* Pixmap sources generate a NoExposed (we return NULL to do this) */
3006747b715Smrg    if (!fastExpose && pGC->fExpose)
30135c4bbdfSmrg        prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC,
30235c4bbdfSmrg                                        xIn - pSrcDrawable->x,
30335c4bbdfSmrg                                        yIn - pSrcDrawable->y,
30435c4bbdfSmrg                                        widthSrc, heightSrc,
30535c4bbdfSmrg                                        xOut - pDstDrawable->x,
30635c4bbdfSmrg                                        yOut - pDstDrawable->y);
3076747b715Smrg    RegionUninit(&rgnDst);
3086747b715Smrg    if (freeSrcClip)
30935c4bbdfSmrg        RegionDestroy(prgnSrcClip);
3106747b715Smrg    return prgnExposed;
3116747b715Smrg}
312