1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright © 1998 Keith Packard
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Permission to use, copy, modify, distribute, and sell this software and its
5*4882a593Smuzhiyun * documentation for any purpose is hereby granted without fee, provided that
6*4882a593Smuzhiyun * the above copyright notice appear in all copies and that both that
7*4882a593Smuzhiyun * copyright notice and this permission notice appear in supporting
8*4882a593Smuzhiyun * documentation, and that the name of Keith Packard not be used in
9*4882a593Smuzhiyun * advertising or publicity pertaining to distribution of the software without
10*4882a593Smuzhiyun * specific, written prior permission. Keith Packard makes no
11*4882a593Smuzhiyun * representations about the suitability of this software for any purpose. It
12*4882a593Smuzhiyun * is provided "as is" without express or implied warranty.
13*4882a593Smuzhiyun *
14*4882a593Smuzhiyun * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15*4882a593Smuzhiyun * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16*4882a593Smuzhiyun * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17*4882a593Smuzhiyun * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18*4882a593Smuzhiyun * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19*4882a593Smuzhiyun * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20*4882a593Smuzhiyun * PERFORMANCE OF THIS SOFTWARE.
21*4882a593Smuzhiyun */
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun #ifdef HAVE_DIX_CONFIG_H
24*4882a593Smuzhiyun #include <dix-config.h>
25*4882a593Smuzhiyun #endif
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun #include "mi.h"
28*4882a593Smuzhiyun #include "scrnintstr.h"
29*4882a593Smuzhiyun #include "gcstruct.h"
30*4882a593Smuzhiyun #include "pixmap.h"
31*4882a593Smuzhiyun #include "pixmapstr.h"
32*4882a593Smuzhiyun #include "windowstr.h"
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun void
miCopyRegion(DrawablePtr pSrcDrawable,DrawablePtr pDstDrawable,GCPtr pGC,RegionPtr pDstRegion,int dx,int dy,miCopyProc copyProc,Pixel bitPlane,void * closure)35*4882a593Smuzhiyun miCopyRegion(DrawablePtr pSrcDrawable,
36*4882a593Smuzhiyun DrawablePtr pDstDrawable,
37*4882a593Smuzhiyun GCPtr pGC,
38*4882a593Smuzhiyun RegionPtr pDstRegion,
39*4882a593Smuzhiyun int dx, int dy, miCopyProc copyProc, Pixel bitPlane, void *closure)
40*4882a593Smuzhiyun {
41*4882a593Smuzhiyun int careful;
42*4882a593Smuzhiyun Bool reverse;
43*4882a593Smuzhiyun Bool upsidedown;
44*4882a593Smuzhiyun BoxPtr pbox;
45*4882a593Smuzhiyun int nbox;
46*4882a593Smuzhiyun BoxPtr pboxNew1, pboxNew2, pboxBase, pboxNext, pboxTmp;
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun pbox = RegionRects(pDstRegion);
49*4882a593Smuzhiyun nbox = RegionNumRects(pDstRegion);
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun /* XXX we have to err on the side of safety when both are windows,
52*4882a593Smuzhiyun * because we don't know if IncludeInferiors is being used.
53*4882a593Smuzhiyun */
54*4882a593Smuzhiyun careful = ((pSrcDrawable == pDstDrawable) ||
55*4882a593Smuzhiyun ((pSrcDrawable->type == DRAWABLE_WINDOW) &&
56*4882a593Smuzhiyun (pDstDrawable->type == DRAWABLE_WINDOW)));
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun pboxNew1 = NULL;
59*4882a593Smuzhiyun pboxNew2 = NULL;
60*4882a593Smuzhiyun if (careful && dy < 0) {
61*4882a593Smuzhiyun upsidedown = TRUE;
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun if (nbox > 1) {
64*4882a593Smuzhiyun /* keep ordering in each band, reverse order of bands */
65*4882a593Smuzhiyun pboxNew1 = xallocarray(nbox, sizeof(BoxRec));
66*4882a593Smuzhiyun if (!pboxNew1)
67*4882a593Smuzhiyun return;
68*4882a593Smuzhiyun pboxBase = pboxNext = pbox + nbox - 1;
69*4882a593Smuzhiyun while (pboxBase >= pbox) {
70*4882a593Smuzhiyun while ((pboxNext >= pbox) && (pboxBase->y1 == pboxNext->y1))
71*4882a593Smuzhiyun pboxNext--;
72*4882a593Smuzhiyun pboxTmp = pboxNext + 1;
73*4882a593Smuzhiyun while (pboxTmp <= pboxBase) {
74*4882a593Smuzhiyun *pboxNew1++ = *pboxTmp++;
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun pboxBase = pboxNext;
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun pboxNew1 -= nbox;
79*4882a593Smuzhiyun pbox = pboxNew1;
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun else {
83*4882a593Smuzhiyun /* walk source top to bottom */
84*4882a593Smuzhiyun upsidedown = FALSE;
85*4882a593Smuzhiyun }
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun if (careful && dx < 0) {
88*4882a593Smuzhiyun /* walk source right to left */
89*4882a593Smuzhiyun if (dy <= 0)
90*4882a593Smuzhiyun reverse = TRUE;
91*4882a593Smuzhiyun else
92*4882a593Smuzhiyun reverse = FALSE;
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun if (nbox > 1) {
95*4882a593Smuzhiyun /* reverse order of rects in each band */
96*4882a593Smuzhiyun pboxNew2 = xallocarray(nbox, sizeof(BoxRec));
97*4882a593Smuzhiyun if (!pboxNew2) {
98*4882a593Smuzhiyun free(pboxNew1);
99*4882a593Smuzhiyun return;
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun pboxBase = pboxNext = pbox;
102*4882a593Smuzhiyun while (pboxBase < pbox + nbox) {
103*4882a593Smuzhiyun while ((pboxNext < pbox + nbox) &&
104*4882a593Smuzhiyun (pboxNext->y1 == pboxBase->y1))
105*4882a593Smuzhiyun pboxNext++;
106*4882a593Smuzhiyun pboxTmp = pboxNext;
107*4882a593Smuzhiyun while (pboxTmp != pboxBase) {
108*4882a593Smuzhiyun *pboxNew2++ = *--pboxTmp;
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun pboxBase = pboxNext;
111*4882a593Smuzhiyun }
112*4882a593Smuzhiyun pboxNew2 -= nbox;
113*4882a593Smuzhiyun pbox = pboxNew2;
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun else {
117*4882a593Smuzhiyun /* walk source left to right */
118*4882a593Smuzhiyun reverse = FALSE;
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun (*copyProc) (pSrcDrawable,
122*4882a593Smuzhiyun pDstDrawable,
123*4882a593Smuzhiyun pGC,
124*4882a593Smuzhiyun pbox, nbox, dx, dy, reverse, upsidedown, bitPlane, closure);
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun free(pboxNew1);
127*4882a593Smuzhiyun free(pboxNew2);
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun RegionPtr
miDoCopy(DrawablePtr pSrcDrawable,DrawablePtr pDstDrawable,GCPtr pGC,int xIn,int yIn,int widthSrc,int heightSrc,int xOut,int yOut,miCopyProc copyProc,Pixel bitPlane,void * closure)131*4882a593Smuzhiyun miDoCopy(DrawablePtr pSrcDrawable,
132*4882a593Smuzhiyun DrawablePtr pDstDrawable,
133*4882a593Smuzhiyun GCPtr pGC,
134*4882a593Smuzhiyun int xIn,
135*4882a593Smuzhiyun int yIn,
136*4882a593Smuzhiyun int widthSrc,
137*4882a593Smuzhiyun int heightSrc,
138*4882a593Smuzhiyun int xOut, int yOut, miCopyProc copyProc, Pixel bitPlane, void *closure)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun RegionPtr prgnSrcClip = NULL; /* may be a new region, or just a copy */
141*4882a593Smuzhiyun Bool freeSrcClip = FALSE;
142*4882a593Smuzhiyun RegionPtr prgnExposed = NULL;
143*4882a593Smuzhiyun RegionRec rgnDst;
144*4882a593Smuzhiyun int dx;
145*4882a593Smuzhiyun int dy;
146*4882a593Smuzhiyun int numRects;
147*4882a593Smuzhiyun int box_x1;
148*4882a593Smuzhiyun int box_y1;
149*4882a593Smuzhiyun int box_x2;
150*4882a593Smuzhiyun int box_y2;
151*4882a593Smuzhiyun Bool fastSrc = FALSE; /* for fast clipping with pixmap source */
152*4882a593Smuzhiyun Bool fastDst = FALSE; /* for fast clipping with one rect dest */
153*4882a593Smuzhiyun Bool fastExpose = FALSE; /* for fast exposures with pixmap source */
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun /* Short cut for unmapped windows */
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun if (pDstDrawable->type == DRAWABLE_WINDOW &&
158*4882a593Smuzhiyun !((WindowPtr) pDstDrawable)->realized) {
159*4882a593Smuzhiyun return NULL;
160*4882a593Smuzhiyun }
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun if (pSrcDrawable->pScreen->SourceValidate) {
163*4882a593Smuzhiyun (*pSrcDrawable->pScreen->SourceValidate) (pSrcDrawable, xIn, yIn,
164*4882a593Smuzhiyun widthSrc, heightSrc,
165*4882a593Smuzhiyun pGC->subWindowMode);
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun /* Compute source clip region */
169*4882a593Smuzhiyun if (pSrcDrawable->type == DRAWABLE_PIXMAP) {
170*4882a593Smuzhiyun if ((pSrcDrawable == pDstDrawable) && (!pGC->clientClip))
171*4882a593Smuzhiyun prgnSrcClip = miGetCompositeClip(pGC);
172*4882a593Smuzhiyun else
173*4882a593Smuzhiyun fastSrc = TRUE;
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun else {
176*4882a593Smuzhiyun if (pGC->subWindowMode == IncludeInferiors) {
177*4882a593Smuzhiyun /*
178*4882a593Smuzhiyun * XFree86 DDX empties the border clip when the
179*4882a593Smuzhiyun * VT is inactive, make sure the region isn't empty
180*4882a593Smuzhiyun */
181*4882a593Smuzhiyun if (!((WindowPtr) pSrcDrawable)->parent &&
182*4882a593Smuzhiyun RegionNotEmpty(&((WindowPtr) pSrcDrawable)->borderClip)) {
183*4882a593Smuzhiyun /*
184*4882a593Smuzhiyun * special case bitblt from root window in
185*4882a593Smuzhiyun * IncludeInferiors mode; just like from a pixmap
186*4882a593Smuzhiyun */
187*4882a593Smuzhiyun fastSrc = TRUE;
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun else if ((pSrcDrawable == pDstDrawable) && (!pGC->clientClip)) {
190*4882a593Smuzhiyun prgnSrcClip = miGetCompositeClip(pGC);
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun else {
193*4882a593Smuzhiyun prgnSrcClip = NotClippedByChildren((WindowPtr) pSrcDrawable);
194*4882a593Smuzhiyun freeSrcClip = TRUE;
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun else {
198*4882a593Smuzhiyun prgnSrcClip = &((WindowPtr) pSrcDrawable)->clipList;
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun xIn += pSrcDrawable->x;
203*4882a593Smuzhiyun yIn += pSrcDrawable->y;
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun xOut += pDstDrawable->x;
206*4882a593Smuzhiyun yOut += pDstDrawable->y;
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun box_x1 = xIn;
209*4882a593Smuzhiyun box_y1 = yIn;
210*4882a593Smuzhiyun box_x2 = xIn + widthSrc;
211*4882a593Smuzhiyun box_y2 = yIn + heightSrc;
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun dx = xIn - xOut;
214*4882a593Smuzhiyun dy = yIn - yOut;
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun /* Don't create a source region if we are doing a fast clip */
217*4882a593Smuzhiyun if (fastSrc) {
218*4882a593Smuzhiyun RegionPtr cclip;
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun fastExpose = TRUE;
221*4882a593Smuzhiyun /*
222*4882a593Smuzhiyun * clip the source; if regions extend beyond the source size,
223*4882a593Smuzhiyun * make sure exposure events get sent
224*4882a593Smuzhiyun */
225*4882a593Smuzhiyun if (box_x1 < pSrcDrawable->x) {
226*4882a593Smuzhiyun box_x1 = pSrcDrawable->x;
227*4882a593Smuzhiyun fastExpose = FALSE;
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun if (box_y1 < pSrcDrawable->y) {
230*4882a593Smuzhiyun box_y1 = pSrcDrawable->y;
231*4882a593Smuzhiyun fastExpose = FALSE;
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun if (box_x2 > pSrcDrawable->x + (int) pSrcDrawable->width) {
234*4882a593Smuzhiyun box_x2 = pSrcDrawable->x + (int) pSrcDrawable->width;
235*4882a593Smuzhiyun fastExpose = FALSE;
236*4882a593Smuzhiyun }
237*4882a593Smuzhiyun if (box_y2 > pSrcDrawable->y + (int) pSrcDrawable->height) {
238*4882a593Smuzhiyun box_y2 = pSrcDrawable->y + (int) pSrcDrawable->height;
239*4882a593Smuzhiyun fastExpose = FALSE;
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun /* Translate and clip the dst to the destination composite clip */
243*4882a593Smuzhiyun box_x1 -= dx;
244*4882a593Smuzhiyun box_x2 -= dx;
245*4882a593Smuzhiyun box_y1 -= dy;
246*4882a593Smuzhiyun box_y2 -= dy;
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun /* If the destination composite clip is one rectangle we can
249*4882a593Smuzhiyun do the clip directly. Otherwise we have to create a full
250*4882a593Smuzhiyun blown region and call intersect */
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun cclip = miGetCompositeClip(pGC);
253*4882a593Smuzhiyun if (RegionNumRects(cclip) == 1) {
254*4882a593Smuzhiyun BoxPtr pBox = RegionRects(cclip);
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun if (box_x1 < pBox->x1)
257*4882a593Smuzhiyun box_x1 = pBox->x1;
258*4882a593Smuzhiyun if (box_x2 > pBox->x2)
259*4882a593Smuzhiyun box_x2 = pBox->x2;
260*4882a593Smuzhiyun if (box_y1 < pBox->y1)
261*4882a593Smuzhiyun box_y1 = pBox->y1;
262*4882a593Smuzhiyun if (box_y2 > pBox->y2)
263*4882a593Smuzhiyun box_y2 = pBox->y2;
264*4882a593Smuzhiyun fastDst = TRUE;
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun
268*4882a593Smuzhiyun /* Check to see if the region is empty */
269*4882a593Smuzhiyun if (box_x1 >= box_x2 || box_y1 >= box_y2) {
270*4882a593Smuzhiyun RegionNull(&rgnDst);
271*4882a593Smuzhiyun }
272*4882a593Smuzhiyun else {
273*4882a593Smuzhiyun BoxRec box;
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun box.x1 = box_x1;
276*4882a593Smuzhiyun box.y1 = box_y1;
277*4882a593Smuzhiyun box.x2 = box_x2;
278*4882a593Smuzhiyun box.y2 = box_y2;
279*4882a593Smuzhiyun RegionInit(&rgnDst, &box, 1);
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun /* Clip against complex source if needed */
283*4882a593Smuzhiyun if (!fastSrc) {
284*4882a593Smuzhiyun RegionIntersect(&rgnDst, &rgnDst, prgnSrcClip);
285*4882a593Smuzhiyun RegionTranslate(&rgnDst, -dx, -dy);
286*4882a593Smuzhiyun }
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun /* Clip against complex dest if needed */
289*4882a593Smuzhiyun if (!fastDst) {
290*4882a593Smuzhiyun RegionIntersect(&rgnDst, &rgnDst, miGetCompositeClip(pGC));
291*4882a593Smuzhiyun }
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun /* Do bit blitting */
294*4882a593Smuzhiyun numRects = RegionNumRects(&rgnDst);
295*4882a593Smuzhiyun if (numRects && widthSrc && heightSrc)
296*4882a593Smuzhiyun miCopyRegion(pSrcDrawable, pDstDrawable, pGC,
297*4882a593Smuzhiyun &rgnDst, dx, dy, copyProc, bitPlane, closure);
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun /* Pixmap sources generate a NoExposed (we return NULL to do this) */
300*4882a593Smuzhiyun if (!fastExpose && pGC->fExpose)
301*4882a593Smuzhiyun prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC,
302*4882a593Smuzhiyun xIn - pSrcDrawable->x,
303*4882a593Smuzhiyun yIn - pSrcDrawable->y,
304*4882a593Smuzhiyun widthSrc, heightSrc,
305*4882a593Smuzhiyun xOut - pDstDrawable->x,
306*4882a593Smuzhiyun yOut - pDstDrawable->y);
307*4882a593Smuzhiyun RegionUninit(&rgnDst);
308*4882a593Smuzhiyun if (freeSrcClip)
309*4882a593Smuzhiyun RegionDestroy(prgnSrcClip);
310*4882a593Smuzhiyun return prgnExposed;
311*4882a593Smuzhiyun }
312