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 34void 35miCopyRegion (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; 51 52 pbox = RegionRects(pDstRegion); 53 nbox = RegionNumRects(pDstRegion); 54 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))); 61 62 pboxNew1 = NULL; 63 pboxNew2 = NULL; 64 if (careful && dy < 0) 65 { 66 upsidedown = TRUE; 67 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 } 96 97 if (careful && dx < 0) 98 { 99 /* walk source right to left */ 100 if (dy <= 0) 101 reverse = TRUE; 102 else 103 reverse = FALSE; 104 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 } 136 137 (*copyProc) (pSrcDrawable, 138 pDstDrawable, 139 pGC, 140 pbox, 141 nbox, 142 dx, dy, 143 reverse, upsidedown, bitPlane, closure); 144 145 free(pboxNew1); 146 free(pboxNew2); 147} 148 149RegionPtr 150miDoCopy (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 */ 177 178 /* Short cut for unmapped windows */ 179 180 if (pDstDrawable->type == DRAWABLE_WINDOW && 181 !((WindowPtr)pDstDrawable)->realized) 182 { 183 return NULL; 184 } 185 186 if (pSrcDrawable->pScreen->SourceValidate) 187 { 188 (*pSrcDrawable->pScreen->SourceValidate) (pSrcDrawable, xIn, yIn, widthSrc, heightSrc, 189 pGC->subWindowMode); 190 } 191 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 } 233 234 xIn += pSrcDrawable->x; 235 yIn += pSrcDrawable->y; 236 237 xOut += pDstDrawable->x; 238 yOut += pDstDrawable->y; 239 240 box_x1 = xIn; 241 box_y1 = yIn; 242 box_x2 = xIn + widthSrc; 243 box_y2 = yIn + heightSrc; 244 245 dx = xIn - xOut; 246 dy = yIn - yOut; 247 248 /* Don't create a source region if we are doing a fast clip */ 249 if (fastSrc) 250 { 251 RegionPtr cclip; 252 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 } 278 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; 284 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 */ 288 289 cclip = miGetCompositeClip(pGC); 290 if (RegionNumRects(cclip) == 1) 291 { 292 BoxPtr pBox = RegionRects(cclip); 293 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 } 301 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 } 316 317 /* Clip against complex source if needed */ 318 if (!fastSrc) 319 { 320 RegionIntersect(&rgnDst, &rgnDst, prgnSrcClip); 321 RegionTranslate(&rgnDst, -dx, -dy); 322 } 323 324 /* Clip against complex dest if needed */ 325 if (!fastDst) 326 { 327 RegionIntersect(&rgnDst, &rgnDst, 328 miGetCompositeClip(pGC)); 329 } 330 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); 336 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} 351