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