micopy.c revision 6747b715
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
356747b715SmrgmiCopyRegion (DrawablePtr   pSrcDrawable,
366747b715Smrg	      DrawablePtr   pDstDrawable,
376747b715Smrg	      GCPtr	    pGC,
386747b715Smrg	      RegionPtr	    pDstRegion,
396747b715Smrg	      int	    dx,
406747b715Smrg	      int	    dy,
416747b715Smrg	      miCopyProc    copyProc,
426747b715Smrg	      Pixel	    bitPlane,
436747b715Smrg	      void	    *closure)
446747b715Smrg{
456747b715Smrg    int		careful;
466747b715Smrg    Bool	reverse;
476747b715Smrg    Bool	upsidedown;
486747b715Smrg    BoxPtr	pbox;
496747b715Smrg    int		nbox;
506747b715Smrg    BoxPtr	pboxNew1, pboxNew2, pboxBase, pboxNext, pboxTmp;
516747b715Smrg
526747b715Smrg    pbox = RegionRects(pDstRegion);
536747b715Smrg    nbox = RegionNumRects(pDstRegion);
546747b715Smrg
556747b715Smrg    /* XXX we have to err on the side of safety when both are windows,
566747b715Smrg     * because we don't know if IncludeInferiors is being used.
576747b715Smrg     */
586747b715Smrg    careful = ((pSrcDrawable == pDstDrawable) ||
596747b715Smrg	       ((pSrcDrawable->type == DRAWABLE_WINDOW) &&
606747b715Smrg		(pDstDrawable->type == DRAWABLE_WINDOW)));
616747b715Smrg
626747b715Smrg    pboxNew1 = NULL;
636747b715Smrg    pboxNew2 = NULL;
646747b715Smrg    if (careful && dy < 0)
656747b715Smrg    {
666747b715Smrg	upsidedown = TRUE;
676747b715Smrg
686747b715Smrg	if (nbox > 1)
696747b715Smrg	{
706747b715Smrg	    /* keep ordering in each band, reverse order of bands */
716747b715Smrg	    pboxNew1 = (BoxPtr)malloc(sizeof(BoxRec) * nbox);
726747b715Smrg	    if(!pboxNew1)
736747b715Smrg		return;
746747b715Smrg	    pboxBase = pboxNext = pbox+nbox-1;
756747b715Smrg	    while (pboxBase >= pbox)
766747b715Smrg	    {
776747b715Smrg		while ((pboxNext >= pbox) &&
786747b715Smrg		       (pboxBase->y1 == pboxNext->y1))
796747b715Smrg		    pboxNext--;
806747b715Smrg		pboxTmp = pboxNext+1;
816747b715Smrg		while (pboxTmp <= pboxBase)
826747b715Smrg		{
836747b715Smrg		    *pboxNew1++ = *pboxTmp++;
846747b715Smrg		}
856747b715Smrg		pboxBase = pboxNext;
866747b715Smrg	    }
876747b715Smrg	    pboxNew1 -= nbox;
886747b715Smrg	    pbox = pboxNew1;
896747b715Smrg	}
906747b715Smrg    }
916747b715Smrg    else
926747b715Smrg    {
936747b715Smrg	/* walk source top to bottom */
946747b715Smrg	upsidedown = FALSE;
956747b715Smrg    }
966747b715Smrg
976747b715Smrg    if (careful && dx < 0)
986747b715Smrg    {
996747b715Smrg	/* walk source right to left */
1006747b715Smrg	if (dy <= 0)
1016747b715Smrg	    reverse = TRUE;
1026747b715Smrg	else
1036747b715Smrg	    reverse = FALSE;
1046747b715Smrg
1056747b715Smrg	if (nbox > 1)
1066747b715Smrg	{
1076747b715Smrg	    /* reverse order of rects in each band */
1086747b715Smrg	    pboxNew2 = (BoxPtr)malloc(sizeof(BoxRec) * nbox);
1096747b715Smrg	    if(!pboxNew2)
1106747b715Smrg	    {
1116747b715Smrg		free(pboxNew1);
1126747b715Smrg		return;
1136747b715Smrg	    }
1146747b715Smrg	    pboxBase = pboxNext = pbox;
1156747b715Smrg	    while (pboxBase < pbox+nbox)
1166747b715Smrg	    {
1176747b715Smrg		while ((pboxNext < pbox+nbox) &&
1186747b715Smrg		       (pboxNext->y1 == pboxBase->y1))
1196747b715Smrg		    pboxNext++;
1206747b715Smrg		pboxTmp = pboxNext;
1216747b715Smrg		while (pboxTmp != pboxBase)
1226747b715Smrg		{
1236747b715Smrg		    *pboxNew2++ = *--pboxTmp;
1246747b715Smrg		}
1256747b715Smrg		pboxBase = pboxNext;
1266747b715Smrg	    }
1276747b715Smrg	    pboxNew2 -= nbox;
1286747b715Smrg	    pbox = pboxNew2;
1296747b715Smrg	}
1306747b715Smrg    }
1316747b715Smrg    else
1326747b715Smrg    {
1336747b715Smrg	/* walk source left to right */
1346747b715Smrg	reverse = FALSE;
1356747b715Smrg    }
1366747b715Smrg
1376747b715Smrg    (*copyProc) (pSrcDrawable,
1386747b715Smrg		 pDstDrawable,
1396747b715Smrg		 pGC,
1406747b715Smrg		 pbox,
1416747b715Smrg		 nbox,
1426747b715Smrg		 dx, dy,
1436747b715Smrg		 reverse, upsidedown, bitPlane, closure);
1446747b715Smrg
1456747b715Smrg    free(pboxNew1);
1466747b715Smrg    free(pboxNew2);
1476747b715Smrg}
1486747b715Smrg
1496747b715SmrgRegionPtr
1506747b715SmrgmiDoCopy (DrawablePtr	pSrcDrawable,
1516747b715Smrg	  DrawablePtr	pDstDrawable,
1526747b715Smrg	  GCPtr		pGC,
1536747b715Smrg	  int		xIn,
1546747b715Smrg	  int		yIn,
1556747b715Smrg	  int		widthSrc,
1566747b715Smrg	  int		heightSrc,
1576747b715Smrg	  int		xOut,
1586747b715Smrg	  int		yOut,
1596747b715Smrg	  miCopyProc	copyProc,
1606747b715Smrg	  Pixel		bitPlane,
1616747b715Smrg	  void		*closure)
1626747b715Smrg{
1636747b715Smrg    RegionPtr	prgnSrcClip = NULL; /* may be a new region, or just a copy */
1646747b715Smrg    Bool	freeSrcClip = FALSE;
1656747b715Smrg    RegionPtr	prgnExposed = NULL;
1666747b715Smrg    RegionRec	rgnDst;
1676747b715Smrg    int		dx;
1686747b715Smrg    int		dy;
1696747b715Smrg    int		numRects;
1706747b715Smrg    int         box_x1;
1716747b715Smrg    int         box_y1;
1726747b715Smrg    int         box_x2;
1736747b715Smrg    int         box_y2;
1746747b715Smrg    Bool	fastSrc = FALSE;    /* for fast clipping with pixmap source */
1756747b715Smrg    Bool	fastDst = FALSE;    /* for fast clipping with one rect dest */
1766747b715Smrg    Bool	fastExpose = FALSE; /* for fast exposures with pixmap source */
1776747b715Smrg
1786747b715Smrg    /* Short cut for unmapped windows */
1796747b715Smrg
1806747b715Smrg    if (pDstDrawable->type == DRAWABLE_WINDOW &&
1816747b715Smrg	!((WindowPtr)pDstDrawable)->realized)
1826747b715Smrg    {
1836747b715Smrg	return NULL;
1846747b715Smrg    }
1856747b715Smrg
1866747b715Smrg    if ((pSrcDrawable != pDstDrawable) &&
1876747b715Smrg	pSrcDrawable->pScreen->SourceValidate)
1886747b715Smrg    {
1896747b715Smrg	(*pSrcDrawable->pScreen->SourceValidate) (pSrcDrawable, xIn, yIn, widthSrc, heightSrc);
1906747b715Smrg    }
1916747b715Smrg
1926747b715Smrg    /* Compute source clip region */
1936747b715Smrg    if (pSrcDrawable->type == DRAWABLE_PIXMAP)
1946747b715Smrg    {
1956747b715Smrg	if ((pSrcDrawable == pDstDrawable) && (pGC->clientClipType == CT_NONE))
1966747b715Smrg	    prgnSrcClip = miGetCompositeClip(pGC);
1976747b715Smrg	else
1986747b715Smrg	    fastSrc = TRUE;
1996747b715Smrg    }
2006747b715Smrg    else
2016747b715Smrg    {
2026747b715Smrg	if (pGC->subWindowMode == IncludeInferiors)
2036747b715Smrg	{
2046747b715Smrg	    /*
2056747b715Smrg	     * XFree86 DDX empties the border clip when the
2066747b715Smrg	     * VT is inactive, make sure the region isn't empty
2076747b715Smrg	     */
2086747b715Smrg	    if (!((WindowPtr) pSrcDrawable)->parent &&
2096747b715Smrg		RegionNotEmpty(&((WindowPtr) pSrcDrawable)->borderClip))
2106747b715Smrg	    {
2116747b715Smrg		/*
2126747b715Smrg		 * special case bitblt from root window in
2136747b715Smrg		 * IncludeInferiors mode; just like from a pixmap
2146747b715Smrg		 */
2156747b715Smrg		fastSrc = TRUE;
2166747b715Smrg	    }
2176747b715Smrg	    else if ((pSrcDrawable == pDstDrawable) &&
2186747b715Smrg		     (pGC->clientClipType == CT_NONE))
2196747b715Smrg	    {
2206747b715Smrg		prgnSrcClip = miGetCompositeClip(pGC);
2216747b715Smrg	    }
2226747b715Smrg	    else
2236747b715Smrg	    {
2246747b715Smrg		prgnSrcClip = NotClippedByChildren((WindowPtr)pSrcDrawable);
2256747b715Smrg		freeSrcClip = TRUE;
2266747b715Smrg	    }
2276747b715Smrg	}
2286747b715Smrg	else
2296747b715Smrg	{
2306747b715Smrg	    prgnSrcClip = &((WindowPtr)pSrcDrawable)->clipList;
2316747b715Smrg	}
2326747b715Smrg    }
2336747b715Smrg
2346747b715Smrg    xIn += pSrcDrawable->x;
2356747b715Smrg    yIn += pSrcDrawable->y;
2366747b715Smrg
2376747b715Smrg    xOut += pDstDrawable->x;
2386747b715Smrg    yOut += pDstDrawable->y;
2396747b715Smrg
2406747b715Smrg    box_x1 = xIn;
2416747b715Smrg    box_y1 = yIn;
2426747b715Smrg    box_x2 = xIn + widthSrc;
2436747b715Smrg    box_y2 = yIn + heightSrc;
2446747b715Smrg
2456747b715Smrg    dx = xIn - xOut;
2466747b715Smrg    dy = yIn - yOut;
2476747b715Smrg
2486747b715Smrg    /* Don't create a source region if we are doing a fast clip */
2496747b715Smrg    if (fastSrc)
2506747b715Smrg    {
2516747b715Smrg	RegionPtr cclip;
2526747b715Smrg
2536747b715Smrg	fastExpose = TRUE;
2546747b715Smrg	/*
2556747b715Smrg	 * clip the source; if regions extend beyond the source size,
2566747b715Smrg 	 * make sure exposure events get sent
2576747b715Smrg	 */
2586747b715Smrg	if (box_x1 < pSrcDrawable->x)
2596747b715Smrg	{
2606747b715Smrg	    box_x1 = pSrcDrawable->x;
2616747b715Smrg	    fastExpose = FALSE;
2626747b715Smrg	}
2636747b715Smrg	if (box_y1 < pSrcDrawable->y)
2646747b715Smrg	{
2656747b715Smrg	    box_y1 = pSrcDrawable->y;
2666747b715Smrg	    fastExpose = FALSE;
2676747b715Smrg	}
2686747b715Smrg	if (box_x2 > pSrcDrawable->x + (int) pSrcDrawable->width)
2696747b715Smrg	{
2706747b715Smrg	    box_x2 = pSrcDrawable->x + (int) pSrcDrawable->width;
2716747b715Smrg	    fastExpose = FALSE;
2726747b715Smrg	}
2736747b715Smrg	if (box_y2 > pSrcDrawable->y + (int) pSrcDrawable->height)
2746747b715Smrg	{
2756747b715Smrg	    box_y2 = pSrcDrawable->y + (int) pSrcDrawable->height;
2766747b715Smrg	    fastExpose = FALSE;
2776747b715Smrg	}
2786747b715Smrg
2796747b715Smrg	/* Translate and clip the dst to the destination composite clip */
2806747b715Smrg        box_x1 -= dx;
2816747b715Smrg        box_x2 -= dx;
2826747b715Smrg        box_y1 -= dy;
2836747b715Smrg        box_y2 -= dy;
2846747b715Smrg
2856747b715Smrg	/* If the destination composite clip is one rectangle we can
2866747b715Smrg	   do the clip directly.  Otherwise we have to create a full
2876747b715Smrg	   blown region and call intersect */
2886747b715Smrg
2896747b715Smrg	cclip = miGetCompositeClip(pGC);
2906747b715Smrg        if (RegionNumRects(cclip) == 1)
2916747b715Smrg        {
2926747b715Smrg	    BoxPtr pBox = RegionRects(cclip);
2936747b715Smrg
2946747b715Smrg	    if (box_x1 < pBox->x1) box_x1 = pBox->x1;
2956747b715Smrg	    if (box_x2 > pBox->x2) box_x2 = pBox->x2;
2966747b715Smrg	    if (box_y1 < pBox->y1) box_y1 = pBox->y1;
2976747b715Smrg	    if (box_y2 > pBox->y2) box_y2 = pBox->y2;
2986747b715Smrg	    fastDst = TRUE;
2996747b715Smrg	}
3006747b715Smrg    }
3016747b715Smrg
3026747b715Smrg    /* Check to see if the region is empty */
3036747b715Smrg    if (box_x1 >= box_x2 || box_y1 >= box_y2)
3046747b715Smrg    {
3056747b715Smrg	RegionNull(&rgnDst);
3066747b715Smrg    }
3076747b715Smrg    else
3086747b715Smrg    {
3096747b715Smrg        BoxRec	box;
3106747b715Smrg	box.x1 = box_x1;
3116747b715Smrg	box.y1 = box_y1;
3126747b715Smrg	box.x2 = box_x2;
3136747b715Smrg	box.y2 = box_y2;
3146747b715Smrg	RegionInit(&rgnDst, &box, 1);
3156747b715Smrg    }
3166747b715Smrg
3176747b715Smrg    /* Clip against complex source if needed */
3186747b715Smrg    if (!fastSrc)
3196747b715Smrg    {
3206747b715Smrg	RegionIntersect(&rgnDst, &rgnDst, prgnSrcClip);
3216747b715Smrg	RegionTranslate(&rgnDst, -dx, -dy);
3226747b715Smrg    }
3236747b715Smrg
3246747b715Smrg    /* Clip against complex dest if needed */
3256747b715Smrg    if (!fastDst)
3266747b715Smrg    {
3276747b715Smrg	RegionIntersect(&rgnDst, &rgnDst,
3286747b715Smrg			 miGetCompositeClip(pGC));
3296747b715Smrg    }
3306747b715Smrg
3316747b715Smrg    /* Do bit blitting */
3326747b715Smrg    numRects = RegionNumRects(&rgnDst);
3336747b715Smrg    if (numRects && widthSrc && heightSrc)
3346747b715Smrg	miCopyRegion (pSrcDrawable, pDstDrawable, pGC,
3356747b715Smrg		      &rgnDst, dx, dy, copyProc, bitPlane, closure);
3366747b715Smrg
3376747b715Smrg    /* Pixmap sources generate a NoExposed (we return NULL to do this) */
3386747b715Smrg    if (!fastExpose && pGC->fExpose)
3396747b715Smrg	prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC,
3406747b715Smrg					xIn - pSrcDrawable->x,
3416747b715Smrg					yIn - pSrcDrawable->y,
3426747b715Smrg					widthSrc, heightSrc,
3436747b715Smrg					xOut - pDstDrawable->x,
3446747b715Smrg					yOut - pDstDrawable->y,
3456747b715Smrg					(unsigned long) bitPlane);
3466747b715Smrg    RegionUninit(&rgnDst);
3476747b715Smrg    if (freeSrcClip)
3486747b715Smrg	RegionDestroy(prgnSrcClip);
3496747b715Smrg    return prgnExposed;
3506747b715Smrg}
351