xref: /OK3568_Linux_fs/external/xserver/mi/micopy.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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