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