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