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