| 1 | /*********************************************************** |
| 2 | |
| 3 | Copyright 1987, 1998 The Open Group |
| 4 | |
| 5 | Permission to use, copy, modify, distribute, and sell this software and its |
| 6 | documentation for any purpose is hereby granted without fee, provided that |
| 7 | the above copyright notice appear in all copies and that both that |
| 8 | copyright notice and this permission notice appear in supporting |
| 9 | documentation. |
| 10 | |
| 11 | The above copyright notice and this permission notice shall be included in |
| 12 | all copies or substantial portions of the Software. |
| 13 | |
| 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| 17 | OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN |
| 18 | AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
| 19 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| 20 | |
| 21 | Except as contained in this notice, the name of The Open Group shall not be |
| 22 | used in advertising or otherwise to promote the sale, use or other dealings |
| 23 | in this Software without prior written authorization from The Open Group. |
| 24 | |
| 25 | Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. |
| 26 | |
| 27 | All Rights Reserved |
| 28 | |
| 29 | Permission to use, copy, modify, and distribute this software and its |
| 30 | documentation for any purpose and without fee is hereby granted, |
| 31 | provided that the above copyright notice appear in all copies and that |
| 32 | both that copyright notice and this permission notice appear in |
| 33 | supporting documentation, and that the name of Digital not be |
| 34 | used in advertising or publicity pertaining to distribution of the |
| 35 | software without specific, written prior permission. |
| 36 | |
| 37 | DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING |
| 38 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL |
| 39 | DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR |
| 40 | ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, |
| 41 | WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, |
| 42 | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS |
| 43 | SOFTWARE. |
| 44 | |
| 45 | ******************************************************************/ |
| 46 | /* Author: Todd Newman (aided and abetted by Mr. Drewry) */ |
| 47 | |
| 48 | #ifdef HAVE_DIX_CONFIG_H |
| 49 | #include <dix-config.h> |
| 50 | #endif |
| 51 | |
| 52 | #include <X11/X.h> |
| 53 | #include <X11/Xprotostr.h> |
| 54 | |
| 55 | #include "misc.h" |
| 56 | #include "gcstruct.h" |
| 57 | #include "pixmapstr.h" |
| 58 | #include "windowstr.h" |
| 59 | #include "scrnintstr.h" |
| 60 | #include "mi.h" |
| 61 | #include "regionstr.h" |
| 62 | #include <X11/Xmd.h> |
| 63 | #include "servermd.h" |
| 64 | |
| 65 | #ifndef HAVE_FFS |
| 66 | extern int ffs(int); |
| 67 | #endif |
| 68 | |
| 69 | /* MICOPYAREA -- public entry for the CopyArea request |
| 70 | * For each rectangle in the source region |
| 71 | * get the pixels with GetSpans |
| 72 | * set them in the destination with SetSpans |
| 73 | * We let SetSpans worry about clipping to the destination. |
| 74 | */ |
| 75 | RegionPtr |
| 76 | miCopyArea(DrawablePtr pSrcDrawable, |
| 77 | DrawablePtr pDstDrawable, |
| 78 | GCPtr pGC, |
| 79 | int xIn, int yIn, int widthSrc, int heightSrc, int xOut, int yOut) |
| 80 | { |
| 81 | DDXPointPtr ppt, pptFirst; |
| 82 | unsigned int *pwidthFirst, *pwidth, *pbits; |
| 83 | BoxRec srcBox, *prect; |
| 84 | |
| 85 | /* may be a new region, or just a copy */ |
| 86 | RegionPtr prgnSrcClip; |
| 87 | |
| 88 | /* non-0 if we've created a src clip */ |
| 89 | RegionPtr prgnExposed; |
| 90 | int realSrcClip = 0; |
| 91 | int srcx, srcy, dstx, dsty, i, j, y, width, height, xMin, xMax, yMin, yMax; |
| 92 | unsigned int *ordering; |
| 93 | int numRects; |
| 94 | BoxPtr boxes; |
| 95 | |
| 96 | srcx = xIn + pSrcDrawable->x; |
| 97 | srcy = yIn + pSrcDrawable->y; |
| 98 | |
| 99 | /* If the destination isn't realized, this is easy */ |
| 100 | if (pDstDrawable->type == DRAWABLE_WINDOW && |
| 101 | !((WindowPtr) pDstDrawable)->realized) |
| 102 | return NULL; |
| 103 | |
| 104 | /* clip the source */ |
| 105 | if (pSrcDrawable->type == DRAWABLE_PIXMAP) { |
| 106 | BoxRec box; |
| 107 | |
| 108 | box.x1 = pSrcDrawable->x; |
| 109 | box.y1 = pSrcDrawable->y; |
| 110 | box.x2 = pSrcDrawable->x + (int) pSrcDrawable->width; |
| 111 | box.y2 = pSrcDrawable->y + (int) pSrcDrawable->height; |
| 112 | |
| 113 | prgnSrcClip = RegionCreate(&box, 1); |
| 114 | realSrcClip = 1; |
| 115 | } |
| 116 | else { |
| 117 | if (pGC->subWindowMode == IncludeInferiors) { |
| 118 | prgnSrcClip = NotClippedByChildren((WindowPtr) pSrcDrawable); |
| 119 | realSrcClip = 1; |
| 120 | } |
| 121 | else |
| 122 | prgnSrcClip = &((WindowPtr) pSrcDrawable)->clipList; |
| 123 | } |
| 124 | |
| 125 | /* If the src drawable is a window, we need to translate the srcBox so |
| 126 | * that we can compare it with the window's clip region later on. */ |
| 127 | srcBox.x1 = srcx; |
| 128 | srcBox.y1 = srcy; |
| 129 | srcBox.x2 = srcx + widthSrc; |
| 130 | srcBox.y2 = srcy + heightSrc; |
| 131 | |
| 132 | dstx = xOut; |
| 133 | dsty = yOut; |
| 134 | if (pGC->miTranslate) { |
| 135 | dstx += pDstDrawable->x; |
| 136 | dsty += pDstDrawable->y; |
| 137 | } |
| 138 | |
| 139 | pptFirst = ppt = malloc(heightSrc * sizeof(DDXPointRec)); |
| 140 | pwidthFirst = pwidth = malloc(heightSrc * sizeof(unsigned int)); |
| 141 | numRects = RegionNumRects(prgnSrcClip); |
| 142 | boxes = RegionRects(prgnSrcClip); |
| 143 | ordering = malloc(numRects * sizeof(unsigned int)); |
| 144 | if (!pptFirst || !pwidthFirst || !ordering) { |
| 145 | free(ordering); |
| 146 | free(pwidthFirst); |
| 147 | free(pptFirst); |
| 148 | return NULL; |
| 149 | } |
| 150 | |
| 151 | /* If not the same drawable then order of move doesn't matter. |
| 152 | Following assumes that boxes are sorted from top |
| 153 | to bottom and left to right. |
| 154 | */ |
| 155 | if ((pSrcDrawable != pDstDrawable) && |
| 156 | ((pGC->subWindowMode != IncludeInferiors) || |
| 157 | (pSrcDrawable->type == DRAWABLE_PIXMAP) || |
| 158 | (pDstDrawable->type == DRAWABLE_PIXMAP))) |
| 159 | for (i = 0; i < numRects; i++) |
| 160 | ordering[i] = i; |
| 161 | else { /* within same drawable, must sequence moves carefully! */ |
| 162 | if (dsty <= srcBox.y1) { /* Scroll up or stationary vertical. |
| 163 | Vertical order OK */ |
| 164 | if (dstx <= srcBox.x1) /* Scroll left or stationary horizontal. |
| 165 | Horizontal order OK as well */ |
| 166 | for (i = 0; i < numRects; i++) |
| 167 | ordering[i] = i; |
| 168 | else { /* scroll right. must reverse horizontal banding of rects. */ |
| 169 | for (i = 0, j = 1, xMax = 0; i < numRects; j = i + 1, xMax = i) { |
| 170 | /* find extent of current horizontal band */ |
| 171 | y = boxes[i].y1; /* band has this y coordinate */ |
| 172 | while ((j < numRects) && (boxes[j].y1 == y)) |
| 173 | j++; |
| 174 | /* reverse the horizontal band in the output ordering */ |
| 175 | for (j--; j >= xMax; j--, i++) |
| 176 | ordering[i] = j; |
| 177 | } |
| 178 | } |
| 179 | } |
| 180 | else { /* Scroll down. Must reverse vertical banding. */ |
| 181 | if (dstx < srcBox.x1) { /* Scroll left. Horizontal order OK. */ |
| 182 | for (i = numRects - 1, j = i - 1, yMin = i, yMax = 0; |
| 183 | i >= 0; j = i - 1, yMin = i) { |
| 184 | /* find extent of current horizontal band */ |
| 185 | y = boxes[i].y1; /* band has this y coordinate */ |
| 186 | while ((j >= 0) && (boxes[j].y1 == y)) |
| 187 | j--; |
| 188 | /* reverse the horizontal band in the output ordering */ |
| 189 | for (j++; j <= yMin; j++, i--, yMax++) |
| 190 | ordering[yMax] = j; |
| 191 | } |
| 192 | } |
| 193 | else /* Scroll right or horizontal stationary. |
| 194 | Reverse horizontal order as well (if stationary, horizontal |
| 195 | order can be swapped without penalty and this is faster |
| 196 | to compute). */ |
| 197 | for (i = 0, j = numRects - 1; i < numRects; i++, j--) |
| 198 | ordering[i] = j; |
| 199 | } |
| 200 | } |
| 201 | |
| 202 | for (i = 0; i < numRects; i++) { |
| 203 | prect = &boxes[ordering[i]]; |
| 204 | xMin = max(prect->x1, srcBox.x1); |
| 205 | xMax = min(prect->x2, srcBox.x2); |
| 206 | yMin = max(prect->y1, srcBox.y1); |
| 207 | yMax = min(prect->y2, srcBox.y2); |
| 208 | /* is there anything visible here? */ |
| 209 | if (xMax <= xMin || yMax <= yMin) |
| 210 | continue; |
| 211 | |
| 212 | ppt = pptFirst; |
| 213 | pwidth = pwidthFirst; |
| 214 | y = yMin; |
| 215 | height = yMax - yMin; |
| 216 | width = xMax - xMin; |
| 217 | |
| 218 | for (j = 0; j < height; j++) { |
| 219 | /* We must untranslate before calling GetSpans */ |
| 220 | ppt->x = xMin; |
| 221 | ppt++->y = y++; |
| 222 | *pwidth++ = width; |
| 223 | } |
| 224 | pbits = malloc(height * PixmapBytePad(width, pSrcDrawable->depth)); |
| 225 | if (pbits) { |
| 226 | (*pSrcDrawable->pScreen->GetSpans) (pSrcDrawable, width, pptFirst, |
| 227 | (int *) pwidthFirst, height, |
| 228 | (char *) pbits); |
| 229 | ppt = pptFirst; |
| 230 | pwidth = pwidthFirst; |
| 231 | xMin -= (srcx - dstx); |
| 232 | y = yMin - (srcy - dsty); |
| 233 | for (j = 0; j < height; j++) { |
| 234 | ppt->x = xMin; |
| 235 | ppt++->y = y++; |
| 236 | *pwidth++ = width; |
| 237 | } |
| 238 | |
| 239 | (*pGC->ops->SetSpans) (pDstDrawable, pGC, (char *) pbits, pptFirst, |
| 240 | (int *) pwidthFirst, height, TRUE); |
| 241 | free(pbits); |
| 242 | } |
| 243 | } |
| 244 | prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC, xIn, yIn, |
| 245 | widthSrc, heightSrc, xOut, yOut, |
| 246 | (unsigned long) 0); |
| 247 | if (realSrcClip) |
| 248 | RegionDestroy(prgnSrcClip); |
| 249 | |
| 250 | free(ordering); |
| 251 | free(pwidthFirst); |
| 252 | free(pptFirst); |
| 253 | return prgnExposed; |
| 254 | } |
| 255 | |
| 256 | /* MIGETPLANE -- gets a bitmap representing one plane of pDraw |
| 257 | * A helper used for CopyPlane and XY format GetImage |
| 258 | * No clever strategy here, we grab a scanline at a time, pull out the |
| 259 | * bits and then stuff them in a 1 bit deep map. |
| 260 | */ |
| 261 | /* |
| 262 | * This should be replaced with something more general. mi shouldn't have to |
| 263 | * care about such things as scanline padding et alia. |
| 264 | */ |
| 265 | static |
| 266 | MiBits * |
| 267 | miGetPlane(DrawablePtr pDraw, int planeNum, /* number of the bitPlane */ |
| 268 | int sx, int sy, int w, int h, MiBits * result) |
| 269 | { |
| 270 | int i, j, k, width, bitsPerPixel, widthInBytes; |
| 271 | DDXPointRec pt = { 0, 0 }; |
| 272 | MiBits pixel; |
| 273 | MiBits bit; |
| 274 | unsigned char *pCharsOut = NULL; |
| 275 | |
| 276 | #if BITMAP_SCANLINE_UNIT == 8 |
| 277 | #define OUT_TYPE unsigned char |
| 278 | #endif |
| 279 | #if BITMAP_SCANLINE_UNIT == 16 |
| 280 | #define OUT_TYPE CARD16 |
| 281 | #endif |
| 282 | #if BITMAP_SCANLINE_UNIT == 32 |
| 283 | #define OUT_TYPE CARD32 |
| 284 | #endif |
| 285 | #if BITMAP_SCANLINE_UNIT == 64 |
| 286 | #define OUT_TYPE CARD64 |
| 287 | #endif |
| 288 | |
| 289 | OUT_TYPE *pOut; |
| 290 | int delta = 0; |
| 291 | |
| 292 | sx += pDraw->x; |
| 293 | sy += pDraw->y; |
| 294 | widthInBytes = BitmapBytePad(w); |
| 295 | if (!result) |
| 296 | result = calloc(h, widthInBytes); |
| 297 | if (!result) |
| 298 | return NULL; |
| 299 | bitsPerPixel = pDraw->bitsPerPixel; |
| 300 | pOut = (OUT_TYPE *) result; |
| 301 | if (bitsPerPixel == 1) { |
| 302 | pCharsOut = (unsigned char *) result; |
| 303 | width = w; |
| 304 | } |
| 305 | else { |
| 306 | delta = (widthInBytes / (BITMAP_SCANLINE_UNIT / 8)) - |
| 307 | (w / BITMAP_SCANLINE_UNIT); |
| 308 | width = 1; |
| 309 | #if IMAGE_BYTE_ORDER == MSBFirst |
| 310 | planeNum += (32 - bitsPerPixel); |
| 311 | #endif |
| 312 | } |
| 313 | pt.y = sy; |
| 314 | for (i = h; --i >= 0; pt.y++) { |
| 315 | pt.x = sx; |
| 316 | if (bitsPerPixel == 1) { |
| 317 | (*pDraw->pScreen->GetSpans) (pDraw, width, &pt, &width, 1, |
| 318 | (char *) pCharsOut); |
| 319 | pCharsOut += widthInBytes; |
| 320 | } |
| 321 | else { |
| 322 | k = 0; |
| 323 | for (j = w; --j >= 0; pt.x++) { |
| 324 | /* Fetch the next pixel */ |
| 325 | (*pDraw->pScreen->GetSpans) (pDraw, width, &pt, &width, 1, |
| 326 | (char *) &pixel); |
| 327 | /* |
| 328 | * Now get the bit and insert into a bitmap in XY format. |
| 329 | */ |
| 330 | bit = (pixel >> planeNum) & 1; |
| 331 | #if 0 |
| 332 | /* XXX assuming bit order == byte order */ |
| 333 | #if BITMAP_BIT_ORDER == LSBFirst |
| 334 | bit <<= k; |
| 335 | #else |
| 336 | bit <<= ((BITMAP_SCANLINE_UNIT - 1) - k); |
| 337 | #endif |
| 338 | #else |
| 339 | /* XXX assuming byte order == LSBFirst */ |
| 340 | if (screenInfo.bitmapBitOrder == LSBFirst) |
| 341 | bit <<= k; |
| 342 | else |
| 343 | bit <<= ((screenInfo.bitmapScanlineUnit - 1) - |
| 344 | (k % screenInfo.bitmapScanlineUnit)) + |
| 345 | ((k / screenInfo.bitmapScanlineUnit) * |
| 346 | screenInfo.bitmapScanlineUnit); |
| 347 | #endif |
| 348 | *pOut |= (OUT_TYPE) bit; |
| 349 | k++; |
| 350 | if (k == BITMAP_SCANLINE_UNIT) { |
| 351 | pOut++; |
| 352 | k = 0; |
| 353 | } |
| 354 | } |
| 355 | pOut += delta; |
| 356 | } |
| 357 | } |
| 358 | return result; |
| 359 | |
| 360 | } |
| 361 | |
| 362 | /* MIOPQSTIPDRAWABLE -- use pbits as an opaque stipple for pDraw. |
| 363 | * Drawing through the clip mask we SetSpans() the bits into a |
| 364 | * bitmap and stipple those bits onto the destination drawable by doing a |
| 365 | * PolyFillRect over the whole drawable, |
| 366 | * then we invert the bitmap by copying it onto itself with an alu of |
| 367 | * GXinvert, invert the foreground/background colors of the gc, and draw |
| 368 | * the background bits. |
| 369 | * Note how the clipped out bits of the bitmap are always the background |
| 370 | * color so that the stipple never causes FillRect to draw them. |
| 371 | */ |
| 372 | static void |
| 373 | miOpqStipDrawable(DrawablePtr pDraw, GCPtr pGC, RegionPtr prgnSrc, |
| 374 | MiBits * pbits, int srcx, int w, int h, int dstx, int dsty) |
| 375 | { |
| 376 | int oldfill, i; |
| 377 | unsigned long oldfg; |
| 378 | int *pwidth, *pwidthFirst; |
| 379 | ChangeGCVal gcv[6]; |
| 380 | PixmapPtr pStipple, pPixmap; |
| 381 | DDXPointRec oldOrg; |
| 382 | GCPtr pGCT; |
| 383 | DDXPointPtr ppt, pptFirst; |
| 384 | xRectangle rect; |
| 385 | RegionPtr prgnSrcClip; |
| 386 | |
| 387 | pPixmap = (*pDraw->pScreen->CreatePixmap) |
| 388 | (pDraw->pScreen, w + srcx, h, 1, CREATE_PIXMAP_USAGE_SCRATCH); |
| 389 | if (!pPixmap) |
| 390 | return; |
| 391 | |
| 392 | /* Put the image into a 1 bit deep pixmap */ |
| 393 | pGCT = GetScratchGC(1, pDraw->pScreen); |
| 394 | if (!pGCT) { |
| 395 | (*pDraw->pScreen->DestroyPixmap) (pPixmap); |
| 396 | return; |
| 397 | } |
| 398 | /* First set the whole pixmap to 0 */ |
| 399 | gcv[0].val = 0; |
| 400 | ChangeGC(NullClient, pGCT, GCBackground, gcv); |
| 401 | ValidateGC((DrawablePtr) pPixmap, pGCT); |
| 402 | miClearDrawable((DrawablePtr) pPixmap, pGCT); |
| 403 | ppt = pptFirst = malloc(h * sizeof(DDXPointRec)); |
| 404 | pwidth = pwidthFirst = malloc(h * sizeof(int)); |
| 405 | if (!pptFirst || !pwidthFirst) { |
| 406 | free(pwidthFirst); |
| 407 | free(pptFirst); |
| 408 | FreeScratchGC(pGCT); |
| 409 | return; |
| 410 | } |
| 411 | |
| 412 | /* we need a temporary region because ChangeClip must be assumed |
| 413 | to destroy what it's sent. note that this means we don't |
| 414 | have to free prgnSrcClip ourselves. |
| 415 | */ |
| 416 | prgnSrcClip = RegionCreate(NULL, 0); |
| 417 | RegionCopy(prgnSrcClip, prgnSrc); |
| 418 | RegionTranslate(prgnSrcClip, srcx, 0); |
| 419 | (*pGCT->funcs->ChangeClip) (pGCT, CT_REGION, prgnSrcClip, 0); |
| 420 | ValidateGC((DrawablePtr) pPixmap, pGCT); |
| 421 | |
| 422 | /* Since we know pDraw is always a pixmap, we never need to think |
| 423 | * about translation here */ |
| 424 | for (i = 0; i < h; i++) { |
| 425 | ppt->x = 0; |
| 426 | ppt++->y = i; |
| 427 | *pwidth++ = w + srcx; |
| 428 | } |
| 429 | |
| 430 | (*pGCT->ops->SetSpans) ((DrawablePtr) pPixmap, pGCT, (char *) pbits, |
| 431 | pptFirst, pwidthFirst, h, TRUE); |
| 432 | free(pwidthFirst); |
| 433 | free(pptFirst); |
| 434 | |
| 435 | /* Save current values from the client GC */ |
| 436 | oldfill = pGC->fillStyle; |
| 437 | pStipple = pGC->stipple; |
| 438 | if (pStipple) |
| 439 | pStipple->refcnt++; |
| 440 | oldOrg = pGC->patOrg; |
| 441 | |
| 442 | /* Set a new stipple in the drawable */ |
| 443 | gcv[0].val = FillStippled; |
| 444 | gcv[1].ptr = pPixmap; |
| 445 | gcv[2].val = dstx - srcx; |
| 446 | gcv[3].val = dsty; |
| 447 | |
| 448 | ChangeGC(NullClient, pGC, |
| 449 | GCFillStyle | GCStipple | GCTileStipXOrigin | GCTileStipYOrigin, |
| 450 | gcv); |
| 451 | ValidateGC(pDraw, pGC); |
| 452 | |
| 453 | /* Fill the drawable with the stipple. This will draw the |
| 454 | * foreground color whereever 1 bits are set, leaving everything |
| 455 | * with 0 bits untouched. Note that the part outside the clip |
| 456 | * region is all 0s. */ |
| 457 | rect.x = dstx; |
| 458 | rect.y = dsty; |
| 459 | rect.width = w; |
| 460 | rect.height = h; |
| 461 | (*pGC->ops->PolyFillRect) (pDraw, pGC, 1, &rect); |
| 462 | |
| 463 | /* Invert the tiling pixmap. This sets 0s for 1s and 1s for 0s, only |
| 464 | * within the clipping region, the part outside is still all 0s */ |
| 465 | gcv[0].val = GXinvert; |
| 466 | ChangeGC(NullClient, pGCT, GCFunction, gcv); |
| 467 | ValidateGC((DrawablePtr) pPixmap, pGCT); |
| 468 | (*pGCT->ops->CopyArea) ((DrawablePtr) pPixmap, (DrawablePtr) pPixmap, |
| 469 | pGCT, 0, 0, w + srcx, h, 0, 0); |
| 470 | |
| 471 | /* Swap foreground and background colors on the GC for the drawable. |
| 472 | * Now when we fill the drawable, we will fill in the "Background" |
| 473 | * values */ |
| 474 | oldfg = pGC->fgPixel; |
| 475 | gcv[0].val = pGC->bgPixel; |
| 476 | gcv[1].val = oldfg; |
| 477 | gcv[2].ptr = pPixmap; |
| 478 | ChangeGC(NullClient, pGC, GCForeground | GCBackground | GCStipple, gcv); |
| 479 | ValidateGC(pDraw, pGC); |
| 480 | /* PolyFillRect might have bashed the rectangle */ |
| 481 | rect.x = dstx; |
| 482 | rect.y = dsty; |
| 483 | rect.width = w; |
| 484 | rect.height = h; |
| 485 | (*pGC->ops->PolyFillRect) (pDraw, pGC, 1, &rect); |
| 486 | |
| 487 | /* Now put things back */ |
| 488 | if (pStipple) |
| 489 | pStipple->refcnt--; |
| 490 | gcv[0].val = oldfg; |
| 491 | gcv[1].val = pGC->fgPixel; |
| 492 | gcv[2].val = oldfill; |
| 493 | gcv[3].ptr = pStipple; |
| 494 | gcv[4].val = oldOrg.x; |
| 495 | gcv[5].val = oldOrg.y; |
| 496 | ChangeGC(NullClient, pGC, |
| 497 | GCForeground | GCBackground | GCFillStyle | GCStipple | |
| 498 | GCTileStipXOrigin | GCTileStipYOrigin, gcv); |
| 499 | |
| 500 | ValidateGC(pDraw, pGC); |
| 501 | /* put what we hope is a smaller clip region back in the scratch gc */ |
| 502 | (*pGCT->funcs->ChangeClip) (pGCT, CT_NONE, NULL, 0); |
| 503 | FreeScratchGC(pGCT); |
| 504 | (*pDraw->pScreen->DestroyPixmap) (pPixmap); |
| 505 | |
| 506 | } |
| 507 | |
| 508 | /* MICOPYPLANE -- public entry for the CopyPlane request. |
| 509 | * strategy: |
| 510 | * First build up a bitmap out of the bits requested |
| 511 | * build a source clip |
| 512 | * Use the bitmap we've built up as a Stipple for the destination |
| 513 | */ |
| 514 | RegionPtr |
| 515 | miCopyPlane(DrawablePtr pSrcDrawable, |
| 516 | DrawablePtr pDstDrawable, |
| 517 | GCPtr pGC, |
| 518 | int srcx, |
| 519 | int srcy, |
| 520 | int width, int height, int dstx, int dsty, unsigned long bitPlane) |
| 521 | { |
| 522 | MiBits *ptile; |
| 523 | BoxRec box; |
| 524 | RegionPtr prgnSrc, prgnExposed; |
| 525 | |
| 526 | /* incorporate the source clip */ |
| 527 | |
| 528 | box.x1 = srcx + pSrcDrawable->x; |
| 529 | box.y1 = srcy + pSrcDrawable->y; |
| 530 | box.x2 = box.x1 + width; |
| 531 | box.y2 = box.y1 + height; |
| 532 | /* clip to visible drawable */ |
| 533 | if (box.x1 < pSrcDrawable->x) |
| 534 | box.x1 = pSrcDrawable->x; |
| 535 | if (box.y1 < pSrcDrawable->y) |
| 536 | box.y1 = pSrcDrawable->y; |
| 537 | if (box.x2 > pSrcDrawable->x + (int) pSrcDrawable->width) |
| 538 | box.x2 = pSrcDrawable->x + (int) pSrcDrawable->width; |
| 539 | if (box.y2 > pSrcDrawable->y + (int) pSrcDrawable->height) |
| 540 | box.y2 = pSrcDrawable->y + (int) pSrcDrawable->height; |
| 541 | if (box.x1 > box.x2) |
| 542 | box.x2 = box.x1; |
| 543 | if (box.y1 > box.y2) |
| 544 | box.y2 = box.y1; |
| 545 | prgnSrc = RegionCreate(&box, 1); |
| 546 | |
| 547 | if (pSrcDrawable->type != DRAWABLE_PIXMAP) { |
| 548 | /* clip to visible drawable */ |
| 549 | |
| 550 | if (pGC->subWindowMode == IncludeInferiors) { |
| 551 | RegionPtr clipList = NotClippedByChildren((WindowPtr) pSrcDrawable); |
| 552 | |
| 553 | RegionIntersect(prgnSrc, prgnSrc, clipList); |
| 554 | RegionDestroy(clipList); |
| 555 | } |
| 556 | else |
| 557 | RegionIntersect(prgnSrc, prgnSrc, |
| 558 | &((WindowPtr) pSrcDrawable)->clipList); |
| 559 | } |
| 560 | |
| 561 | box = *RegionExtents(prgnSrc); |
| 562 | RegionTranslate(prgnSrc, -box.x1, -box.y1); |
| 563 | |
| 564 | if ((box.x2 > box.x1) && (box.y2 > box.y1)) { |
| 565 | /* minimize the size of the data extracted */ |
| 566 | /* note that we convert the plane mask bitPlane into a plane number */ |
| 567 | box.x1 -= pSrcDrawable->x; |
| 568 | box.x2 -= pSrcDrawable->x; |
| 569 | box.y1 -= pSrcDrawable->y; |
| 570 | box.y2 -= pSrcDrawable->y; |
| 571 | ptile = miGetPlane(pSrcDrawable, ffs(bitPlane) - 1, |
| 572 | box.x1, box.y1, |
| 573 | box.x2 - box.x1, box.y2 - box.y1, (MiBits *) NULL); |
| 574 | if (ptile) { |
| 575 | miOpqStipDrawable(pDstDrawable, pGC, prgnSrc, ptile, 0, |
| 576 | box.x2 - box.x1, box.y2 - box.y1, |
| 577 | dstx + box.x1 - srcx, dsty + box.y1 - srcy); |
| 578 | free(ptile); |
| 579 | } |
| 580 | } |
| 581 | prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC, srcx, srcy, |
| 582 | width, height, dstx, dsty, bitPlane); |
| 583 | RegionDestroy(prgnSrc); |
| 584 | return prgnExposed; |
| 585 | } |
| 586 | |
| 587 | /* MIGETIMAGE -- public entry for the GetImage Request |
| 588 | * We're getting the image into a memory buffer. While we have to use GetSpans |
| 589 | * to read a line from the device (since we don't know what that looks like), |
| 590 | * we can just write into the destination buffer |
| 591 | * |
| 592 | * two different strategies are used, depending on whether we're getting the |
| 593 | * image in Z format or XY format |
| 594 | * Z format: |
| 595 | * Line at a time, GetSpans a line into the destination buffer, then if the |
| 596 | * planemask is not all ones, we do a SetSpans into a temporary buffer (to get |
| 597 | * bits turned off) and then another GetSpans to get stuff back (because |
| 598 | * pixmaps are opaque, and we are passed in the memory to write into). This is |
| 599 | * pretty ugly and slow but works. Life is hard. |
| 600 | * XY format: |
| 601 | * get the single plane specified in planemask |
| 602 | */ |
| 603 | void |
| 604 | miGetImage(DrawablePtr pDraw, int sx, int sy, int w, int h, |
| 605 | unsigned int format, unsigned long planeMask, char *pDst) |
| 606 | { |
| 607 | unsigned char depth; |
| 608 | int i, linelength, width, srcx, srcy; |
| 609 | DDXPointRec pt = { 0, 0 }; |
| 610 | PixmapPtr pPixmap = NULL; |
| 611 | GCPtr pGC = NULL; |
| 612 | |
| 613 | depth = pDraw->depth; |
| 614 | if (format == ZPixmap) { |
| 615 | if ((((1LL << depth) - 1) & planeMask) != (1LL << depth) - 1) { |
| 616 | ChangeGCVal gcv; |
| 617 | xPoint xpt; |
| 618 | |
| 619 | pGC = GetScratchGC(depth, pDraw->pScreen); |
| 620 | if (!pGC) |
| 621 | return; |
| 622 | pPixmap = (*pDraw->pScreen->CreatePixmap) |
| 623 | (pDraw->pScreen, w, 1, depth, CREATE_PIXMAP_USAGE_SCRATCH); |
| 624 | if (!pPixmap) { |
| 625 | FreeScratchGC(pGC); |
| 626 | return; |
| 627 | } |
| 628 | /* |
| 629 | * Clear the pixmap before doing anything else |
| 630 | */ |
| 631 | ValidateGC((DrawablePtr) pPixmap, pGC); |
| 632 | xpt.x = xpt.y = 0; |
| 633 | width = w; |
| 634 | (*pGC->ops->FillSpans) ((DrawablePtr) pPixmap, pGC, 1, &xpt, &width, |
| 635 | TRUE); |
| 636 | |
| 637 | /* alu is already GXCopy */ |
| 638 | gcv.val = (XID) planeMask; |
| 639 | ChangeGC(NullClient, pGC, GCPlaneMask, &gcv); |
| 640 | ValidateGC((DrawablePtr) pPixmap, pGC); |
| 641 | } |
| 642 | |
| 643 | linelength = PixmapBytePad(w, depth); |
| 644 | srcx = sx + pDraw->x; |
| 645 | srcy = sy + pDraw->y; |
| 646 | for (i = 0; i < h; i++) { |
| 647 | pt.x = srcx; |
| 648 | pt.y = srcy + i; |
| 649 | width = w; |
| 650 | (*pDraw->pScreen->GetSpans) (pDraw, w, &pt, &width, 1, pDst); |
| 651 | if (pPixmap) { |
| 652 | pt.x = 0; |
| 653 | pt.y = 0; |
| 654 | width = w; |
| 655 | (*pGC->ops->SetSpans) ((DrawablePtr) pPixmap, pGC, pDst, |
| 656 | &pt, &width, 1, TRUE); |
| 657 | (*pDraw->pScreen->GetSpans) ((DrawablePtr) pPixmap, w, &pt, |
| 658 | &width, 1, pDst); |
| 659 | } |
| 660 | pDst += linelength; |
| 661 | } |
| 662 | if (pPixmap) { |
| 663 | (*pGC->pScreen->DestroyPixmap) (pPixmap); |
| 664 | FreeScratchGC(pGC); |
| 665 | } |
| 666 | } |
| 667 | else { |
| 668 | (void) miGetPlane(pDraw, ffs(planeMask) - 1, sx, sy, w, h, |
| 669 | (MiBits *) pDst); |
| 670 | } |
| 671 | } |
| 672 | |
| 673 | /* MIPUTIMAGE -- public entry for the PutImage request |
| 674 | * Here we benefit from knowing the format of the bits pointed to by pImage, |
| 675 | * even if we don't know how pDraw represents them. |
| 676 | * Three different strategies are used depending on the format |
| 677 | * XYBitmap Format: |
| 678 | * we just use the Opaque Stipple helper function to cover the destination |
| 679 | * Note that this covers all the planes of the drawable with the |
| 680 | * foreground color (masked with the GC planemask) where there are 1 bits |
| 681 | * and the background color (masked with the GC planemask) where there are |
| 682 | * 0 bits |
| 683 | * XYPixmap format: |
| 684 | * what we're called with is a series of XYBitmaps, but we only want |
| 685 | * each XYPixmap to update 1 plane, instead of updating all of them. |
| 686 | * we set the foreground color to be all 1s and the background to all 0s |
| 687 | * then for each plane, we set the plane mask to only effect that one |
| 688 | * plane and recursive call ourself with the format set to XYBitmap |
| 689 | * (This clever idea courtesy of RGD.) |
| 690 | * ZPixmap format: |
| 691 | * This part is simple, just call SetSpans |
| 692 | */ |
| 693 | void |
| 694 | miPutImage(DrawablePtr pDraw, GCPtr pGC, int depth, |
| 695 | int x, int y, int w, int h, int leftPad, int format, char *pImage) |
| 696 | { |
| 697 | DDXPointPtr pptFirst, ppt; |
| 698 | int *pwidthFirst, *pwidth; |
| 699 | RegionPtr prgnSrc; |
| 700 | BoxRec box; |
| 701 | unsigned long oldFg, oldBg; |
| 702 | ChangeGCVal gcv[3]; |
| 703 | unsigned long oldPlanemask; |
| 704 | unsigned long i; |
| 705 | long bytesPer; |
| 706 | |
| 707 | if (!w || !h) |
| 708 | return; |
| 709 | switch (format) { |
| 710 | case XYBitmap: |
| 711 | |
| 712 | box.x1 = 0; |
| 713 | box.y1 = 0; |
| 714 | box.x2 = w; |
| 715 | box.y2 = h; |
| 716 | prgnSrc = RegionCreate(&box, 1); |
| 717 | |
| 718 | miOpqStipDrawable(pDraw, pGC, prgnSrc, (MiBits *) pImage, |
| 719 | leftPad, w, h, x, y); |
| 720 | RegionDestroy(prgnSrc); |
| 721 | break; |
| 722 | |
| 723 | case XYPixmap: |
| 724 | depth = pGC->depth; |
| 725 | oldPlanemask = pGC->planemask; |
| 726 | oldFg = pGC->fgPixel; |
| 727 | oldBg = pGC->bgPixel; |
| 728 | gcv[0].val = (XID) ~0; |
| 729 | gcv[1].val = (XID) 0; |
| 730 | ChangeGC(NullClient, pGC, GCForeground | GCBackground, gcv); |
| 731 | bytesPer = (long) h *BitmapBytePad(w + leftPad); |
| 732 | |
| 733 | for (i = 1 << (depth - 1); i != 0; i >>= 1, pImage += bytesPer) { |
| 734 | if (i & oldPlanemask) { |
| 735 | gcv[0].val = (XID) i; |
| 736 | ChangeGC(NullClient, pGC, GCPlaneMask, gcv); |
| 737 | ValidateGC(pDraw, pGC); |
| 738 | (*pGC->ops->PutImage) (pDraw, pGC, 1, x, y, w, h, leftPad, |
| 739 | XYBitmap, (char *) pImage); |
| 740 | } |
| 741 | } |
| 742 | gcv[0].val = (XID) oldPlanemask; |
| 743 | gcv[1].val = (XID) oldFg; |
| 744 | gcv[2].val = (XID) oldBg; |
| 745 | ChangeGC(NullClient, pGC, GCPlaneMask | GCForeground | GCBackground, |
| 746 | gcv); |
| 747 | ValidateGC(pDraw, pGC); |
| 748 | break; |
| 749 | |
| 750 | case ZPixmap: |
| 751 | ppt = pptFirst = malloc(h * sizeof(DDXPointRec)); |
| 752 | pwidth = pwidthFirst = malloc(h * sizeof(int)); |
| 753 | if (!pptFirst || !pwidthFirst) { |
| 754 | free(pwidthFirst); |
| 755 | free(pptFirst); |
| 756 | return; |
| 757 | } |
| 758 | if (pGC->miTranslate) { |
| 759 | x += pDraw->x; |
| 760 | y += pDraw->y; |
| 761 | } |
| 762 | |
| 763 | for (i = 0; i < h; i++) { |
| 764 | ppt->x = x; |
| 765 | ppt->y = y + i; |
| 766 | ppt++; |
| 767 | *pwidth++ = w; |
| 768 | } |
| 769 | |
| 770 | (*pGC->ops->SetSpans) (pDraw, pGC, (char *) pImage, pptFirst, |
| 771 | pwidthFirst, h, TRUE); |
| 772 | free(pwidthFirst); |
| 773 | free(pptFirst); |
| 774 | break; |
| 775 | } |
| 776 | } |