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 */
23 #ifdef HAVE_DIX_CONFIG_H
24 #include <dix-config.h>
25 #endif
27 #include "mi.h"
28 #include "scrnintstr.h"
29 #include "gcstruct.h"
30 #include "pixmap.h"
31 #include "pixmapstr.h"
32 #include "windowstr.h"
34 void
35 miCopyRegion (DrawablePtr pSrcDrawable,
36 DrawablePtr pDstDrawable,
37 GCPtr pGC,
38 RegionPtr pDstRegion,
39 int dx,
40 int dy,
41 miCopyProc copyProc,
42 Pixel bitPlane,
43 void *closure)
44 {
45 int careful;
46 Bool reverse;
47 Bool upsidedown;
48 BoxPtr pbox;
49 int nbox;
50 BoxPtr pboxNew1, pboxNew2, pboxBase, pboxNext, pboxTmp;
52 pbox = RegionRects(pDstRegion);
53 nbox = RegionNumRects(pDstRegion);
55 /* XXX we have to err on the side of safety when both are windows,
56 * because we don't know if IncludeInferiors is being used.
57 */
58 careful = ((pSrcDrawable == pDstDrawable) ||
59 ((pSrcDrawable->type == DRAWABLE_WINDOW) &&
60 (pDstDrawable->type == DRAWABLE_WINDOW)));
62 pboxNew1 = NULL;
63 pboxNew2 = NULL;
64 if (careful && dy < 0)
65 {
66 upsidedown = TRUE;
68 if (nbox > 1)
69 {
70 /* keep ordering in each band, reverse order of bands */
71 pboxNew1 = (BoxPtr)malloc(sizeof(BoxRec) * nbox);
72 if(!pboxNew1)
73 return;
74 pboxBase = pboxNext = pbox+nbox-1;
75 while (pboxBase >= pbox)
76 {
77 while ((pboxNext >= pbox) &&
78 (pboxBase->y1 == pboxNext->y1))
79 pboxNext--;
80 pboxTmp = pboxNext+1;
81 while (pboxTmp <= pboxBase)
82 {
83 *pboxNew1++ = *pboxTmp++;
84 }
85 pboxBase = pboxNext;
86 }
87 pboxNew1 -= nbox;
88 pbox = pboxNew1;
89 }
90 }
91 else
92 {
93 /* walk source top to bottom */
94 upsidedown = FALSE;
95 }
97 if (careful && dx < 0)
98 {
99 /* walk source right to left */
100 if (dy <= 0)
101 reverse = TRUE;
102 else
103 reverse = FALSE;
105 if (nbox > 1)
106 {
107 /* reverse order of rects in each band */
108 pboxNew2 = (BoxPtr)malloc(sizeof(BoxRec) * nbox);
109 if(!pboxNew2)
110 {
111 free(pboxNew1);
112 return;
113 }
114 pboxBase = pboxNext = pbox;
115 while (pboxBase < pbox+nbox)
116 {
117 while ((pboxNext < pbox+nbox) &&
118 (pboxNext->y1 == pboxBase->y1))
119 pboxNext++;
120 pboxTmp = pboxNext;
121 while (pboxTmp != pboxBase)
122 {
123 *pboxNew2++ = *--pboxTmp;
124 }
125 pboxBase = pboxNext;
126 }
127 pboxNew2 -= nbox;
128 pbox = pboxNew2;
129 }
130 }
131 else
132 {
133 /* walk source left to right */
134 reverse = FALSE;
135 }
137 (*copyProc) (pSrcDrawable,
138 pDstDrawable,
139 pGC,
140 pbox,
141 nbox,
142 dx, dy,
143 reverse, upsidedown, bitPlane, closure);
145 free(pboxNew1);
146 free(pboxNew2);
147 }
149 RegionPtr
150 miDoCopy (DrawablePtr pSrcDrawable,
151 DrawablePtr pDstDrawable,
152 GCPtr pGC,
153 int xIn,
154 int yIn,
155 int widthSrc,
156 int heightSrc,
157 int xOut,
158 int yOut,
159 miCopyProc copyProc,
160 Pixel bitPlane,
161 void *closure)
162 {
163 RegionPtr prgnSrcClip = NULL; /* may be a new region, or just a copy */
164 Bool freeSrcClip = FALSE;
165 RegionPtr prgnExposed = NULL;
166 RegionRec rgnDst;
167 int dx;
168 int dy;
169 int numRects;
170 int box_x1;
171 int box_y1;
172 int box_x2;
173 int box_y2;
174 Bool fastSrc = FALSE; /* for fast clipping with pixmap source */
175 Bool fastDst = FALSE; /* for fast clipping with one rect dest */
176 Bool fastExpose = FALSE; /* for fast exposures with pixmap source */
178 /* Short cut for unmapped windows */
180 if (pDstDrawable->type == DRAWABLE_WINDOW &&
181 !((WindowPtr)pDstDrawable)->realized)
182 {
183 return NULL;
184 }
186 if (pSrcDrawable->pScreen->SourceValidate)
187 {
188 (*pSrcDrawable->pScreen->SourceValidate) (pSrcDrawable, xIn, yIn, widthSrc, heightSrc,
189 pGC->subWindowMode);
190 }
192 /* Compute source clip region */
193 if (pSrcDrawable->type == DRAWABLE_PIXMAP)
194 {
195 if ((pSrcDrawable == pDstDrawable) && (pGC->clientClipType == CT_NONE))
196 prgnSrcClip = miGetCompositeClip(pGC);
197 else
198 fastSrc = TRUE;
199 }
200 else
201 {
202 if (pGC->subWindowMode == IncludeInferiors)
203 {
204 /*
205 * XFree86 DDX empties the border clip when the
206 * VT is inactive, make sure the region isn't empty
207 */
208 if (!((WindowPtr) pSrcDrawable)->parent &&
209 RegionNotEmpty(&((WindowPtr) pSrcDrawable)->borderClip))
210 {
211 /*
212 * special case bitblt from root window in
213 * IncludeInferiors mode; just like from a pixmap
214 */
215 fastSrc = TRUE;
216 }
217 else if ((pSrcDrawable == pDstDrawable) &&
218 (pGC->clientClipType == CT_NONE))
219 {
220 prgnSrcClip = miGetCompositeClip(pGC);
221 }
222 else
223 {
224 prgnSrcClip = NotClippedByChildren((WindowPtr)pSrcDrawable);
225 freeSrcClip = TRUE;
226 }
227 }
228 else
229 {
230 prgnSrcClip = &((WindowPtr)pSrcDrawable)->clipList;
231 }
232 }
234 xIn += pSrcDrawable->x;
235 yIn += pSrcDrawable->y;
237 xOut += pDstDrawable->x;
238 yOut += pDstDrawable->y;
240 box_x1 = xIn;
241 box_y1 = yIn;
242 box_x2 = xIn + widthSrc;
243 box_y2 = yIn + heightSrc;
245 dx = xIn - xOut;
246 dy = yIn - yOut;
248 /* Don't create a source region if we are doing a fast clip */
249 if (fastSrc)
250 {
251 RegionPtr cclip;
253 fastExpose = TRUE;
254 /*
255 * clip the source; if regions extend beyond the source size,
256 * make sure exposure events get sent
257 */
258 if (box_x1 < pSrcDrawable->x)
259 {
260 box_x1 = pSrcDrawable->x;
261 fastExpose = FALSE;
262 }
263 if (box_y1 < pSrcDrawable->y)
264 {
265 box_y1 = pSrcDrawable->y;
266 fastExpose = FALSE;
267 }
268 if (box_x2 > pSrcDrawable->x + (int) pSrcDrawable->width)
269 {
270 box_x2 = pSrcDrawable->x + (int) pSrcDrawable->width;
271 fastExpose = FALSE;
272 }
273 if (box_y2 > pSrcDrawable->y + (int) pSrcDrawable->height)
274 {
275 box_y2 = pSrcDrawable->y + (int) pSrcDrawable->height;
276 fastExpose = FALSE;
277 }
279 /* Translate and clip the dst to the destination composite clip */
280 box_x1 -= dx;
281 box_x2 -= dx;
282 box_y1 -= dy;
283 box_y2 -= dy;
285 /* If the destination composite clip is one rectangle we can
286 do the clip directly. Otherwise we have to create a full
287 blown region and call intersect */
289 cclip = miGetCompositeClip(pGC);
290 if (RegionNumRects(cclip) == 1)
291 {
292 BoxPtr pBox = RegionRects(cclip);
294 if (box_x1 < pBox->x1) box_x1 = pBox->x1;
295 if (box_x2 > pBox->x2) box_x2 = pBox->x2;
296 if (box_y1 < pBox->y1) box_y1 = pBox->y1;
297 if (box_y2 > pBox->y2) box_y2 = pBox->y2;
298 fastDst = TRUE;
299 }
300 }
302 /* Check to see if the region is empty */
303 if (box_x1 >= box_x2 || box_y1 >= box_y2)
304 {
305 RegionNull(&rgnDst);
306 }
307 else
308 {
309 BoxRec box;
310 box.x1 = box_x1;
311 box.y1 = box_y1;
312 box.x2 = box_x2;
313 box.y2 = box_y2;
314 RegionInit(&rgnDst, &box, 1);
315 }
317 /* Clip against complex source if needed */
318 if (!fastSrc)
319 {
320 RegionIntersect(&rgnDst, &rgnDst, prgnSrcClip);
321 RegionTranslate(&rgnDst, -dx, -dy);
322 }
324 /* Clip against complex dest if needed */
325 if (!fastDst)
326 {
327 RegionIntersect(&rgnDst, &rgnDst,
328 miGetCompositeClip(pGC));
329 }
331 /* Do bit blitting */
332 numRects = RegionNumRects(&rgnDst);
333 if (numRects && widthSrc && heightSrc)
334 miCopyRegion (pSrcDrawable, pDstDrawable, pGC,
335 &rgnDst, dx, dy, copyProc, bitPlane, closure);
337 /* Pixmap sources generate a NoExposed (we return NULL to do this) */
338 if (!fastExpose && pGC->fExpose)
339 prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC,
340 xIn - pSrcDrawable->x,
341 yIn - pSrcDrawable->y,
342 widthSrc, heightSrc,
343 xOut - pDstDrawable->x,
344 yOut - pDstDrawable->y,
345 (unsigned long) bitPlane);
346 RegionUninit(&rgnDst);
347 if (freeSrcClip)
348 RegionDestroy(prgnSrcClip);
349 return prgnExposed;
350 }