mibitblt.c revision 706f2543
1706f2543Smrg/*********************************************************** 2706f2543Smrg 3706f2543SmrgCopyright 1987, 1998 The Open Group 4706f2543Smrg 5706f2543SmrgPermission to use, copy, modify, distribute, and sell this software and its 6706f2543Smrgdocumentation for any purpose is hereby granted without fee, provided that 7706f2543Smrgthe above copyright notice appear in all copies and that both that 8706f2543Smrgcopyright notice and this permission notice appear in supporting 9706f2543Smrgdocumentation. 10706f2543Smrg 11706f2543SmrgThe above copyright notice and this permission notice shall be included in 12706f2543Smrgall copies or substantial portions of the Software. 13706f2543Smrg 14706f2543SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15706f2543SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16706f2543SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17706f2543SmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18706f2543SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19706f2543SmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20706f2543Smrg 21706f2543SmrgExcept as contained in this notice, the name of The Open Group shall not be 22706f2543Smrgused in advertising or otherwise to promote the sale, use or other dealings 23706f2543Smrgin this Software without prior written authorization from The Open Group. 24706f2543Smrg 25706f2543Smrg 26706f2543SmrgCopyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. 27706f2543Smrg 28706f2543Smrg All Rights Reserved 29706f2543Smrg 30706f2543SmrgPermission to use, copy, modify, and distribute this software and its 31706f2543Smrgdocumentation for any purpose and without fee is hereby granted, 32706f2543Smrgprovided that the above copyright notice appear in all copies and that 33706f2543Smrgboth that copyright notice and this permission notice appear in 34706f2543Smrgsupporting documentation, and that the name of Digital not be 35706f2543Smrgused in advertising or publicity pertaining to distribution of the 36706f2543Smrgsoftware without specific, written prior permission. 37706f2543Smrg 38706f2543SmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 39706f2543SmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 40706f2543SmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 41706f2543SmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 42706f2543SmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 43706f2543SmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 44706f2543SmrgSOFTWARE. 45706f2543Smrg 46706f2543Smrg******************************************************************/ 47706f2543Smrg/* Author: Todd Newman (aided and abetted by Mr. Drewry) */ 48706f2543Smrg 49706f2543Smrg#ifdef HAVE_DIX_CONFIG_H 50706f2543Smrg#include <dix-config.h> 51706f2543Smrg#endif 52706f2543Smrg 53706f2543Smrg#include <X11/X.h> 54706f2543Smrg#include <X11/Xprotostr.h> 55706f2543Smrg 56706f2543Smrg#include "misc.h" 57706f2543Smrg#include "gcstruct.h" 58706f2543Smrg#include "pixmapstr.h" 59706f2543Smrg#include "windowstr.h" 60706f2543Smrg#include "scrnintstr.h" 61706f2543Smrg#include "mi.h" 62706f2543Smrg#include "regionstr.h" 63706f2543Smrg#include <X11/Xmd.h> 64706f2543Smrg#include "servermd.h" 65706f2543Smrg 66706f2543Smrg#ifndef HAS_FFS 67706f2543Smrgextern int ffs(int); 68706f2543Smrg#endif 69706f2543Smrg 70706f2543Smrg/* MICOPYAREA -- public entry for the CopyArea request 71706f2543Smrg * For each rectangle in the source region 72706f2543Smrg * get the pixels with GetSpans 73706f2543Smrg * set them in the destination with SetSpans 74706f2543Smrg * We let SetSpans worry about clipping to the destination. 75706f2543Smrg */ 76706f2543SmrgRegionPtr 77706f2543SmrgmiCopyArea(DrawablePtr pSrcDrawable, 78706f2543Smrg DrawablePtr pDstDrawable, 79706f2543Smrg GCPtr pGC, 80706f2543Smrg int xIn, 81706f2543Smrg int yIn, 82706f2543Smrg int widthSrc, 83706f2543Smrg int heightSrc, 84706f2543Smrg int xOut, 85706f2543Smrg int yOut) 86706f2543Smrg{ 87706f2543Smrg DDXPointPtr ppt, pptFirst; 88706f2543Smrg unsigned int *pwidthFirst, *pwidth, *pbits; 89706f2543Smrg BoxRec srcBox, *prect; 90706f2543Smrg /* may be a new region, or just a copy */ 91706f2543Smrg RegionPtr prgnSrcClip; 92706f2543Smrg /* non-0 if we've created a src clip */ 93706f2543Smrg RegionPtr prgnExposed; 94706f2543Smrg int realSrcClip = 0; 95706f2543Smrg int srcx, srcy, dstx, dsty, i, j, y, width, height, 96706f2543Smrg xMin, xMax, yMin, yMax; 97706f2543Smrg unsigned int *ordering; 98706f2543Smrg int numRects; 99706f2543Smrg BoxPtr boxes; 100706f2543Smrg 101706f2543Smrg srcx = xIn + pSrcDrawable->x; 102706f2543Smrg srcy = yIn + pSrcDrawable->y; 103706f2543Smrg 104706f2543Smrg /* If the destination isn't realized, this is easy */ 105706f2543Smrg if (pDstDrawable->type == DRAWABLE_WINDOW && 106706f2543Smrg !((WindowPtr)pDstDrawable)->realized) 107706f2543Smrg return NULL; 108706f2543Smrg 109706f2543Smrg /* clip the source */ 110706f2543Smrg if (pSrcDrawable->type == DRAWABLE_PIXMAP) 111706f2543Smrg { 112706f2543Smrg BoxRec box; 113706f2543Smrg 114706f2543Smrg box.x1 = pSrcDrawable->x; 115706f2543Smrg box.y1 = pSrcDrawable->y; 116706f2543Smrg box.x2 = pSrcDrawable->x + (int) pSrcDrawable->width; 117706f2543Smrg box.y2 = pSrcDrawable->y + (int) pSrcDrawable->height; 118706f2543Smrg 119706f2543Smrg prgnSrcClip = RegionCreate(&box, 1); 120706f2543Smrg realSrcClip = 1; 121706f2543Smrg } 122706f2543Smrg else 123706f2543Smrg { 124706f2543Smrg if (pGC->subWindowMode == IncludeInferiors) { 125706f2543Smrg prgnSrcClip = NotClippedByChildren ((WindowPtr) pSrcDrawable); 126706f2543Smrg realSrcClip = 1; 127706f2543Smrg } else 128706f2543Smrg prgnSrcClip = &((WindowPtr)pSrcDrawable)->clipList; 129706f2543Smrg } 130706f2543Smrg 131706f2543Smrg /* If the src drawable is a window, we need to translate the srcBox so 132706f2543Smrg * that we can compare it with the window's clip region later on. */ 133706f2543Smrg srcBox.x1 = srcx; 134706f2543Smrg srcBox.y1 = srcy; 135706f2543Smrg srcBox.x2 = srcx + widthSrc; 136706f2543Smrg srcBox.y2 = srcy + heightSrc; 137706f2543Smrg 138706f2543Smrg dstx = xOut; 139706f2543Smrg dsty = yOut; 140706f2543Smrg if (pGC->miTranslate) 141706f2543Smrg { 142706f2543Smrg dstx += pDstDrawable->x; 143706f2543Smrg dsty += pDstDrawable->y; 144706f2543Smrg } 145706f2543Smrg 146706f2543Smrg pptFirst = ppt = malloc(heightSrc * sizeof(DDXPointRec)); 147706f2543Smrg pwidthFirst = pwidth = malloc(heightSrc * sizeof(unsigned int)); 148706f2543Smrg numRects = RegionNumRects(prgnSrcClip); 149706f2543Smrg boxes = RegionRects(prgnSrcClip); 150706f2543Smrg ordering = malloc(numRects * sizeof(unsigned int)); 151706f2543Smrg if(!pptFirst || !pwidthFirst || !ordering) 152706f2543Smrg { 153706f2543Smrg free(ordering); 154706f2543Smrg free(pwidthFirst); 155706f2543Smrg free(pptFirst); 156706f2543Smrg return NULL; 157706f2543Smrg } 158706f2543Smrg 159706f2543Smrg /* If not the same drawable then order of move doesn't matter. 160706f2543Smrg Following assumes that boxes are sorted from top 161706f2543Smrg to bottom and left to right. 162706f2543Smrg */ 163706f2543Smrg if ((pSrcDrawable != pDstDrawable) && 164706f2543Smrg ((pGC->subWindowMode != IncludeInferiors) || 165706f2543Smrg (pSrcDrawable->type == DRAWABLE_PIXMAP) || 166706f2543Smrg (pDstDrawable->type == DRAWABLE_PIXMAP))) 167706f2543Smrg for (i=0; i < numRects; i++) 168706f2543Smrg ordering[i] = i; 169706f2543Smrg else { /* within same drawable, must sequence moves carefully! */ 170706f2543Smrg if (dsty <= srcBox.y1) { /* Scroll up or stationary vertical. 171706f2543Smrg Vertical order OK */ 172706f2543Smrg if (dstx <= srcBox.x1) /* Scroll left or stationary horizontal. 173706f2543Smrg Horizontal order OK as well */ 174706f2543Smrg for (i=0; i < numRects; i++) 175706f2543Smrg ordering[i] = i; 176706f2543Smrg else { /* scroll right. must reverse horizontal banding of rects. */ 177706f2543Smrg for (i=0, j=1, xMax=0; i < numRects; j=i+1, xMax=i) { 178706f2543Smrg /* find extent of current horizontal band */ 179706f2543Smrg y=boxes[i].y1; /* band has this y coordinate */ 180706f2543Smrg while ((j < numRects) && (boxes[j].y1 == y)) 181706f2543Smrg j++; 182706f2543Smrg /* reverse the horizontal band in the output ordering */ 183706f2543Smrg for (j-- ; j >= xMax; j--, i++) 184706f2543Smrg ordering[i] = j; 185706f2543Smrg } 186706f2543Smrg } 187706f2543Smrg } 188706f2543Smrg else { /* Scroll down. Must reverse vertical banding. */ 189706f2543Smrg if (dstx < srcBox.x1) { /* Scroll left. Horizontal order OK. */ 190706f2543Smrg for (i=numRects-1, j=i-1, yMin=i, yMax=0; 191706f2543Smrg i >= 0; 192706f2543Smrg j=i-1, yMin=i) { 193706f2543Smrg /* find extent of current horizontal band */ 194706f2543Smrg y=boxes[i].y1; /* band has this y coordinate */ 195706f2543Smrg while ((j >= 0) && (boxes[j].y1 == y)) 196706f2543Smrg j--; 197706f2543Smrg /* reverse the horizontal band in the output ordering */ 198706f2543Smrg for (j++ ; j <= yMin; j++, i--, yMax++) 199706f2543Smrg ordering[yMax] = j; 200706f2543Smrg } 201706f2543Smrg } 202706f2543Smrg else /* Scroll right or horizontal stationary. 203706f2543Smrg Reverse horizontal order as well (if stationary, horizontal 204706f2543Smrg order can be swapped without penalty and this is faster 205706f2543Smrg to compute). */ 206706f2543Smrg for (i=0, j=numRects-1; i < numRects; i++, j--) 207706f2543Smrg ordering[i] = j; 208706f2543Smrg } 209706f2543Smrg } 210706f2543Smrg 211706f2543Smrg for(i = 0; i < numRects; i++) 212706f2543Smrg { 213706f2543Smrg prect = &boxes[ordering[i]]; 214706f2543Smrg xMin = max(prect->x1, srcBox.x1); 215706f2543Smrg xMax = min(prect->x2, srcBox.x2); 216706f2543Smrg yMin = max(prect->y1, srcBox.y1); 217706f2543Smrg yMax = min(prect->y2, srcBox.y2); 218706f2543Smrg /* is there anything visible here? */ 219706f2543Smrg if(xMax <= xMin || yMax <= yMin) 220706f2543Smrg continue; 221706f2543Smrg 222706f2543Smrg ppt = pptFirst; 223706f2543Smrg pwidth = pwidthFirst; 224706f2543Smrg y = yMin; 225706f2543Smrg height = yMax - yMin; 226706f2543Smrg width = xMax - xMin; 227706f2543Smrg 228706f2543Smrg for(j = 0; j < height; j++) 229706f2543Smrg { 230706f2543Smrg /* We must untranslate before calling GetSpans */ 231706f2543Smrg ppt->x = xMin; 232706f2543Smrg ppt++->y = y++; 233706f2543Smrg *pwidth++ = width; 234706f2543Smrg } 235706f2543Smrg pbits = malloc(height * PixmapBytePad(width, pSrcDrawable->depth)); 236706f2543Smrg if (pbits) 237706f2543Smrg { 238706f2543Smrg (*pSrcDrawable->pScreen->GetSpans)(pSrcDrawable, width, pptFirst, 239706f2543Smrg (int *)pwidthFirst, height, (char *)pbits); 240706f2543Smrg ppt = pptFirst; 241706f2543Smrg pwidth = pwidthFirst; 242706f2543Smrg xMin -= (srcx - dstx); 243706f2543Smrg y = yMin - (srcy - dsty); 244706f2543Smrg for(j = 0; j < height; j++) 245706f2543Smrg { 246706f2543Smrg ppt->x = xMin; 247706f2543Smrg ppt++->y = y++; 248706f2543Smrg *pwidth++ = width; 249706f2543Smrg } 250706f2543Smrg 251706f2543Smrg (*pGC->ops->SetSpans)(pDstDrawable, pGC, (char *)pbits, pptFirst, 252706f2543Smrg (int *)pwidthFirst, height, TRUE); 253706f2543Smrg free(pbits); 254706f2543Smrg } 255706f2543Smrg } 256706f2543Smrg prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC, xIn, yIn, 257706f2543Smrg widthSrc, heightSrc, xOut, yOut, (unsigned long)0); 258706f2543Smrg if(realSrcClip) 259706f2543Smrg RegionDestroy(prgnSrcClip); 260706f2543Smrg 261706f2543Smrg free(ordering); 262706f2543Smrg free(pwidthFirst); 263706f2543Smrg free(pptFirst); 264706f2543Smrg return prgnExposed; 265706f2543Smrg} 266706f2543Smrg 267706f2543Smrg/* MIGETPLANE -- gets a bitmap representing one plane of pDraw 268706f2543Smrg * A helper used for CopyPlane and XY format GetImage 269706f2543Smrg * No clever strategy here, we grab a scanline at a time, pull out the 270706f2543Smrg * bits and then stuff them in a 1 bit deep map. 271706f2543Smrg */ 272706f2543Smrg/* 273706f2543Smrg * This should be replaced with something more general. mi shouldn't have to 274706f2543Smrg * care about such things as scanline padding et alia. 275706f2543Smrg */ 276706f2543Smrgstatic 277706f2543SmrgMiBits * 278706f2543SmrgmiGetPlane( 279706f2543Smrg DrawablePtr pDraw, 280706f2543Smrg int planeNum, /* number of the bitPlane */ 281706f2543Smrg int sx, 282706f2543Smrg int sy, 283706f2543Smrg int w, 284706f2543Smrg int h, 285706f2543Smrg MiBits *result) 286706f2543Smrg{ 287706f2543Smrg int i, j, k, width, bitsPerPixel, widthInBytes; 288706f2543Smrg DDXPointRec pt = {0, 0}; 289706f2543Smrg MiBits pixel; 290706f2543Smrg MiBits bit; 291706f2543Smrg unsigned char *pCharsOut = NULL; 292706f2543Smrg 293706f2543Smrg#if BITMAP_SCANLINE_UNIT == 8 294706f2543Smrg#define OUT_TYPE unsigned char 295706f2543Smrg#endif 296706f2543Smrg#if BITMAP_SCANLINE_UNIT == 16 297706f2543Smrg#define OUT_TYPE CARD16 298706f2543Smrg#endif 299706f2543Smrg#if BITMAP_SCANLINE_UNIT == 32 300706f2543Smrg#define OUT_TYPE CARD32 301706f2543Smrg#endif 302706f2543Smrg#if BITMAP_SCANLINE_UNIT == 64 303706f2543Smrg#define OUT_TYPE CARD64 304706f2543Smrg#endif 305706f2543Smrg 306706f2543Smrg OUT_TYPE *pOut; 307706f2543Smrg int delta = 0; 308706f2543Smrg 309706f2543Smrg sx += pDraw->x; 310706f2543Smrg sy += pDraw->y; 311706f2543Smrg widthInBytes = BitmapBytePad(w); 312706f2543Smrg if(!result) 313706f2543Smrg result = calloc(h, widthInBytes); 314706f2543Smrg if (!result) 315706f2543Smrg return NULL; 316706f2543Smrg bitsPerPixel = pDraw->bitsPerPixel; 317706f2543Smrg pOut = (OUT_TYPE *) result; 318706f2543Smrg if(bitsPerPixel == 1) 319706f2543Smrg { 320706f2543Smrg pCharsOut = (unsigned char *) result; 321706f2543Smrg width = w; 322706f2543Smrg } 323706f2543Smrg else 324706f2543Smrg { 325706f2543Smrg delta = (widthInBytes / (BITMAP_SCANLINE_UNIT / 8)) - 326706f2543Smrg (w / BITMAP_SCANLINE_UNIT); 327706f2543Smrg width = 1; 328706f2543Smrg#if IMAGE_BYTE_ORDER == MSBFirst 329706f2543Smrg planeNum += (32 - bitsPerPixel); 330706f2543Smrg#endif 331706f2543Smrg } 332706f2543Smrg pt.y = sy; 333706f2543Smrg for (i = h; --i >= 0; pt.y++) 334706f2543Smrg { 335706f2543Smrg pt.x = sx; 336706f2543Smrg if(bitsPerPixel == 1) 337706f2543Smrg { 338706f2543Smrg (*pDraw->pScreen->GetSpans)(pDraw, width, &pt, &width, 1, 339706f2543Smrg (char *)pCharsOut); 340706f2543Smrg pCharsOut += widthInBytes; 341706f2543Smrg } 342706f2543Smrg else 343706f2543Smrg { 344706f2543Smrg k = 0; 345706f2543Smrg for(j = w; --j >= 0; pt.x++) 346706f2543Smrg { 347706f2543Smrg /* Fetch the next pixel */ 348706f2543Smrg (*pDraw->pScreen->GetSpans)(pDraw, width, &pt, &width, 1, 349706f2543Smrg (char *)&pixel); 350706f2543Smrg /* 351706f2543Smrg * Now get the bit and insert into a bitmap in XY format. 352706f2543Smrg */ 353706f2543Smrg bit = (pixel >> planeNum) & 1; 354706f2543Smrg#if 0 355706f2543Smrg /* XXX assuming bit order == byte order */ 356706f2543Smrg#if BITMAP_BIT_ORDER == LSBFirst 357706f2543Smrg bit <<= k; 358706f2543Smrg#else 359706f2543Smrg bit <<= ((BITMAP_SCANLINE_UNIT - 1) - k); 360706f2543Smrg#endif 361706f2543Smrg#else 362706f2543Smrg /* XXX assuming byte order == LSBFirst */ 363706f2543Smrg if (screenInfo.bitmapBitOrder == LSBFirst) 364706f2543Smrg bit <<= k; 365706f2543Smrg else 366706f2543Smrg bit <<= ((screenInfo.bitmapScanlineUnit - 1) - 367706f2543Smrg (k % screenInfo.bitmapScanlineUnit)) + 368706f2543Smrg ((k / screenInfo.bitmapScanlineUnit) * 369706f2543Smrg screenInfo.bitmapScanlineUnit); 370706f2543Smrg#endif 371706f2543Smrg *pOut |= (OUT_TYPE) bit; 372706f2543Smrg k++; 373706f2543Smrg if (k == BITMAP_SCANLINE_UNIT) 374706f2543Smrg { 375706f2543Smrg pOut++; 376706f2543Smrg k = 0; 377706f2543Smrg } 378706f2543Smrg } 379706f2543Smrg pOut += delta; 380706f2543Smrg } 381706f2543Smrg } 382706f2543Smrg return result; 383706f2543Smrg 384706f2543Smrg} 385706f2543Smrg 386706f2543Smrg/* MIOPQSTIPDRAWABLE -- use pbits as an opaque stipple for pDraw. 387706f2543Smrg * Drawing through the clip mask we SetSpans() the bits into a 388706f2543Smrg * bitmap and stipple those bits onto the destination drawable by doing a 389706f2543Smrg * PolyFillRect over the whole drawable, 390706f2543Smrg * then we invert the bitmap by copying it onto itself with an alu of 391706f2543Smrg * GXinvert, invert the foreground/background colors of the gc, and draw 392706f2543Smrg * the background bits. 393706f2543Smrg * Note how the clipped out bits of the bitmap are always the background 394706f2543Smrg * color so that the stipple never causes FillRect to draw them. 395706f2543Smrg */ 396706f2543Smrgstatic void 397706f2543SmrgmiOpqStipDrawable(DrawablePtr pDraw, GCPtr pGC, RegionPtr prgnSrc, 398706f2543Smrg MiBits *pbits, int srcx, int w, int h, int dstx, int dsty) 399706f2543Smrg{ 400706f2543Smrg int oldfill, i; 401706f2543Smrg unsigned long oldfg; 402706f2543Smrg int *pwidth, *pwidthFirst; 403706f2543Smrg ChangeGCVal gcv[6]; 404706f2543Smrg PixmapPtr pStipple, pPixmap; 405706f2543Smrg DDXPointRec oldOrg; 406706f2543Smrg GCPtr pGCT; 407706f2543Smrg DDXPointPtr ppt, pptFirst; 408706f2543Smrg xRectangle rect; 409706f2543Smrg RegionPtr prgnSrcClip; 410706f2543Smrg 411706f2543Smrg pPixmap = (*pDraw->pScreen->CreatePixmap) 412706f2543Smrg (pDraw->pScreen, w + srcx, h, 1, 413706f2543Smrg CREATE_PIXMAP_USAGE_SCRATCH); 414706f2543Smrg if (!pPixmap) 415706f2543Smrg return; 416706f2543Smrg 417706f2543Smrg /* Put the image into a 1 bit deep pixmap */ 418706f2543Smrg pGCT = GetScratchGC(1, pDraw->pScreen); 419706f2543Smrg if (!pGCT) 420706f2543Smrg { 421706f2543Smrg (*pDraw->pScreen->DestroyPixmap)(pPixmap); 422706f2543Smrg return; 423706f2543Smrg } 424706f2543Smrg /* First set the whole pixmap to 0 */ 425706f2543Smrg gcv[0].val = 0; 426706f2543Smrg ChangeGC(NullClient, pGCT, GCBackground, gcv); 427706f2543Smrg ValidateGC((DrawablePtr)pPixmap, pGCT); 428706f2543Smrg miClearDrawable((DrawablePtr)pPixmap, pGCT); 429706f2543Smrg ppt = pptFirst = malloc(h * sizeof(DDXPointRec)); 430706f2543Smrg pwidth = pwidthFirst = malloc(h * sizeof(int)); 431706f2543Smrg if(!pptFirst || !pwidthFirst) 432706f2543Smrg { 433706f2543Smrg free(pwidthFirst); 434706f2543Smrg free(pptFirst); 435706f2543Smrg FreeScratchGC(pGCT); 436706f2543Smrg return; 437706f2543Smrg } 438706f2543Smrg 439706f2543Smrg /* we need a temporary region because ChangeClip must be assumed 440706f2543Smrg to destroy what it's sent. note that this means we don't 441706f2543Smrg have to free prgnSrcClip ourselves. 442706f2543Smrg */ 443706f2543Smrg prgnSrcClip = RegionCreate(NULL, 0); 444706f2543Smrg RegionCopy(prgnSrcClip, prgnSrc); 445706f2543Smrg RegionTranslate(prgnSrcClip, srcx, 0); 446706f2543Smrg (*pGCT->funcs->ChangeClip)(pGCT, CT_REGION, prgnSrcClip, 0); 447706f2543Smrg ValidateGC((DrawablePtr)pPixmap, pGCT); 448706f2543Smrg 449706f2543Smrg /* Since we know pDraw is always a pixmap, we never need to think 450706f2543Smrg * about translation here */ 451706f2543Smrg for(i = 0; i < h; i++) 452706f2543Smrg { 453706f2543Smrg ppt->x = 0; 454706f2543Smrg ppt++->y = i; 455706f2543Smrg *pwidth++ = w + srcx; 456706f2543Smrg } 457706f2543Smrg 458706f2543Smrg (*pGCT->ops->SetSpans)((DrawablePtr)pPixmap, pGCT, (char *)pbits, 459706f2543Smrg pptFirst, pwidthFirst, h, TRUE); 460706f2543Smrg free(pwidthFirst); 461706f2543Smrg free(pptFirst); 462706f2543Smrg 463706f2543Smrg 464706f2543Smrg /* Save current values from the client GC */ 465706f2543Smrg oldfill = pGC->fillStyle; 466706f2543Smrg pStipple = pGC->stipple; 467706f2543Smrg if(pStipple) 468706f2543Smrg pStipple->refcnt++; 469706f2543Smrg oldOrg = pGC->patOrg; 470706f2543Smrg 471706f2543Smrg /* Set a new stipple in the drawable */ 472706f2543Smrg gcv[0].val = FillStippled; 473706f2543Smrg gcv[1].ptr = pPixmap; 474706f2543Smrg gcv[2].val = dstx - srcx; 475706f2543Smrg gcv[3].val = dsty; 476706f2543Smrg 477706f2543Smrg ChangeGC(NullClient, pGC, 478706f2543Smrg GCFillStyle | GCStipple | GCTileStipXOrigin | GCTileStipYOrigin, 479706f2543Smrg gcv); 480706f2543Smrg ValidateGC(pDraw, pGC); 481706f2543Smrg 482706f2543Smrg /* Fill the drawable with the stipple. This will draw the 483706f2543Smrg * foreground color whereever 1 bits are set, leaving everything 484706f2543Smrg * with 0 bits untouched. Note that the part outside the clip 485706f2543Smrg * region is all 0s. */ 486706f2543Smrg rect.x = dstx; 487706f2543Smrg rect.y = dsty; 488706f2543Smrg rect.width = w; 489706f2543Smrg rect.height = h; 490706f2543Smrg (*pGC->ops->PolyFillRect)(pDraw, pGC, 1, &rect); 491706f2543Smrg 492706f2543Smrg /* Invert the tiling pixmap. This sets 0s for 1s and 1s for 0s, only 493706f2543Smrg * within the clipping region, the part outside is still all 0s */ 494706f2543Smrg gcv[0].val = GXinvert; 495706f2543Smrg ChangeGC(NullClient, pGCT, GCFunction, gcv); 496706f2543Smrg ValidateGC((DrawablePtr)pPixmap, pGCT); 497706f2543Smrg (*pGCT->ops->CopyArea)((DrawablePtr)pPixmap, (DrawablePtr)pPixmap, 498706f2543Smrg pGCT, 0, 0, w + srcx, h, 0, 0); 499706f2543Smrg 500706f2543Smrg /* Swap foreground and background colors on the GC for the drawable. 501706f2543Smrg * Now when we fill the drawable, we will fill in the "Background" 502706f2543Smrg * values */ 503706f2543Smrg oldfg = pGC->fgPixel; 504706f2543Smrg gcv[0].val = pGC->bgPixel; 505706f2543Smrg gcv[1].val = oldfg; 506706f2543Smrg gcv[2].ptr = pPixmap; 507706f2543Smrg ChangeGC(NullClient, pGC, GCForeground | GCBackground | GCStipple, gcv); 508706f2543Smrg ValidateGC(pDraw, pGC); 509706f2543Smrg /* PolyFillRect might have bashed the rectangle */ 510706f2543Smrg rect.x = dstx; 511706f2543Smrg rect.y = dsty; 512706f2543Smrg rect.width = w; 513706f2543Smrg rect.height = h; 514706f2543Smrg (*pGC->ops->PolyFillRect)(pDraw, pGC, 1, &rect); 515706f2543Smrg 516706f2543Smrg /* Now put things back */ 517706f2543Smrg if(pStipple) 518706f2543Smrg pStipple->refcnt--; 519706f2543Smrg gcv[0].val = oldfg; 520706f2543Smrg gcv[1].val = pGC->fgPixel; 521706f2543Smrg gcv[2].val = oldfill; 522706f2543Smrg gcv[3].ptr = pStipple; 523706f2543Smrg gcv[4].val = oldOrg.x; 524706f2543Smrg gcv[5].val = oldOrg.y; 525706f2543Smrg ChangeGC(NullClient, pGC, 526706f2543Smrg GCForeground | GCBackground | GCFillStyle | GCStipple | 527706f2543Smrg GCTileStipXOrigin | GCTileStipYOrigin, gcv); 528706f2543Smrg 529706f2543Smrg ValidateGC(pDraw, pGC); 530706f2543Smrg /* put what we hope is a smaller clip region back in the scratch gc */ 531706f2543Smrg (*pGCT->funcs->ChangeClip)(pGCT, CT_NONE, NULL, 0); 532706f2543Smrg FreeScratchGC(pGCT); 533706f2543Smrg (*pDraw->pScreen->DestroyPixmap)(pPixmap); 534706f2543Smrg 535706f2543Smrg} 536706f2543Smrg 537706f2543Smrg/* MICOPYPLANE -- public entry for the CopyPlane request. 538706f2543Smrg * strategy: 539706f2543Smrg * First build up a bitmap out of the bits requested 540706f2543Smrg * build a source clip 541706f2543Smrg * Use the bitmap we've built up as a Stipple for the destination 542706f2543Smrg */ 543706f2543SmrgRegionPtr 544706f2543SmrgmiCopyPlane( DrawablePtr pSrcDrawable, 545706f2543Smrg DrawablePtr pDstDrawable, 546706f2543Smrg GCPtr pGC, 547706f2543Smrg int srcx, 548706f2543Smrg int srcy, 549706f2543Smrg int width, 550706f2543Smrg int height, 551706f2543Smrg int dstx, 552706f2543Smrg int dsty, 553706f2543Smrg unsigned long bitPlane) 554706f2543Smrg{ 555706f2543Smrg MiBits *ptile; 556706f2543Smrg BoxRec box; 557706f2543Smrg RegionPtr prgnSrc, prgnExposed; 558706f2543Smrg 559706f2543Smrg /* incorporate the source clip */ 560706f2543Smrg 561706f2543Smrg box.x1 = srcx + pSrcDrawable->x; 562706f2543Smrg box.y1 = srcy + pSrcDrawable->y; 563706f2543Smrg box.x2 = box.x1 + width; 564706f2543Smrg box.y2 = box.y1 + height; 565706f2543Smrg /* clip to visible drawable */ 566706f2543Smrg if (box.x1 < pSrcDrawable->x) 567706f2543Smrg box.x1 = pSrcDrawable->x; 568706f2543Smrg if (box.y1 < pSrcDrawable->y) 569706f2543Smrg box.y1 = pSrcDrawable->y; 570706f2543Smrg if (box.x2 > pSrcDrawable->x + (int) pSrcDrawable->width) 571706f2543Smrg box.x2 = pSrcDrawable->x + (int) pSrcDrawable->width; 572706f2543Smrg if (box.y2 > pSrcDrawable->y + (int) pSrcDrawable->height) 573706f2543Smrg box.y2 = pSrcDrawable->y + (int) pSrcDrawable->height; 574706f2543Smrg if (box.x1 > box.x2) 575706f2543Smrg box.x2 = box.x1; 576706f2543Smrg if (box.y1 > box.y2) 577706f2543Smrg box.y2 = box.y1; 578706f2543Smrg prgnSrc = RegionCreate(&box, 1); 579706f2543Smrg 580706f2543Smrg if (pSrcDrawable->type != DRAWABLE_PIXMAP) { 581706f2543Smrg /* clip to visible drawable */ 582706f2543Smrg 583706f2543Smrg if (pGC->subWindowMode == IncludeInferiors) 584706f2543Smrg { 585706f2543Smrg RegionPtr clipList = NotClippedByChildren ((WindowPtr) pSrcDrawable); 586706f2543Smrg RegionIntersect(prgnSrc, prgnSrc, clipList); 587706f2543Smrg RegionDestroy(clipList); 588706f2543Smrg } else 589706f2543Smrg RegionIntersect(prgnSrc, prgnSrc, 590706f2543Smrg &((WindowPtr)pSrcDrawable)->clipList); 591706f2543Smrg } 592706f2543Smrg 593706f2543Smrg box = *RegionExtents(prgnSrc); 594706f2543Smrg RegionTranslate(prgnSrc, -box.x1, -box.y1); 595706f2543Smrg 596706f2543Smrg if ((box.x2 > box.x1) && (box.y2 > box.y1)) 597706f2543Smrg { 598706f2543Smrg /* minimize the size of the data extracted */ 599706f2543Smrg /* note that we convert the plane mask bitPlane into a plane number */ 600706f2543Smrg box.x1 -= pSrcDrawable->x; 601706f2543Smrg box.x2 -= pSrcDrawable->x; 602706f2543Smrg box.y1 -= pSrcDrawable->y; 603706f2543Smrg box.y2 -= pSrcDrawable->y; 604706f2543Smrg ptile = miGetPlane(pSrcDrawable, ffs(bitPlane) - 1, 605706f2543Smrg box.x1, box.y1, 606706f2543Smrg box.x2 - box.x1, box.y2 - box.y1, 607706f2543Smrg (MiBits *) NULL); 608706f2543Smrg if (ptile) 609706f2543Smrg { 610706f2543Smrg miOpqStipDrawable(pDstDrawable, pGC, prgnSrc, ptile, 0, 611706f2543Smrg box.x2 - box.x1, box.y2 - box.y1, 612706f2543Smrg dstx + box.x1 - srcx, dsty + box.y1 - srcy); 613706f2543Smrg free(ptile); 614706f2543Smrg } 615706f2543Smrg } 616706f2543Smrg prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC, srcx, srcy, 617706f2543Smrg width, height, dstx, dsty, bitPlane); 618706f2543Smrg RegionDestroy(prgnSrc); 619706f2543Smrg return prgnExposed; 620706f2543Smrg} 621706f2543Smrg 622706f2543Smrg/* MIGETIMAGE -- public entry for the GetImage Request 623706f2543Smrg * We're getting the image into a memory buffer. While we have to use GetSpans 624706f2543Smrg * to read a line from the device (since we don't know what that looks like), 625706f2543Smrg * we can just write into the destination buffer 626706f2543Smrg * 627706f2543Smrg * two different strategies are used, depending on whether we're getting the 628706f2543Smrg * image in Z format or XY format 629706f2543Smrg * Z format: 630706f2543Smrg * Line at a time, GetSpans a line into the destination buffer, then if the 631706f2543Smrg * planemask is not all ones, we do a SetSpans into a temporary buffer (to get 632706f2543Smrg * bits turned off) and then another GetSpans to get stuff back (because 633706f2543Smrg * pixmaps are opaque, and we are passed in the memory to write into). This is 634706f2543Smrg * pretty ugly and slow but works. Life is hard. 635706f2543Smrg * XY format: 636706f2543Smrg * get the single plane specified in planemask 637706f2543Smrg */ 638706f2543Smrgvoid 639706f2543SmrgmiGetImage( DrawablePtr pDraw, int sx, int sy, int w, int h, 640706f2543Smrg unsigned int format, unsigned long planeMask, char *pDst) 641706f2543Smrg{ 642706f2543Smrg unsigned char depth; 643706f2543Smrg int i, linelength, width, srcx, srcy; 644706f2543Smrg DDXPointRec pt = {0, 0}; 645706f2543Smrg PixmapPtr pPixmap = NULL; 646706f2543Smrg GCPtr pGC = NULL; 647706f2543Smrg 648706f2543Smrg depth = pDraw->depth; 649706f2543Smrg if(format == ZPixmap) 650706f2543Smrg { 651706f2543Smrg if ( (((1LL<<depth)-1)&planeMask) != (1LL<<depth)-1 ) 652706f2543Smrg { 653706f2543Smrg ChangeGCVal gcv; 654706f2543Smrg xPoint pt; 655706f2543Smrg 656706f2543Smrg pGC = GetScratchGC(depth, pDraw->pScreen); 657706f2543Smrg if (!pGC) 658706f2543Smrg return; 659706f2543Smrg pPixmap = (*pDraw->pScreen->CreatePixmap) 660706f2543Smrg (pDraw->pScreen, w, 1, depth, 661706f2543Smrg CREATE_PIXMAP_USAGE_SCRATCH); 662706f2543Smrg if (!pPixmap) 663706f2543Smrg { 664706f2543Smrg FreeScratchGC(pGC); 665706f2543Smrg return; 666706f2543Smrg } 667706f2543Smrg /* 668706f2543Smrg * Clear the pixmap before doing anything else 669706f2543Smrg */ 670706f2543Smrg ValidateGC((DrawablePtr)pPixmap, pGC); 671706f2543Smrg pt.x = pt.y = 0; 672706f2543Smrg width = w; 673706f2543Smrg (*pGC->ops->FillSpans)((DrawablePtr)pPixmap, pGC, 1, &pt, &width, 674706f2543Smrg TRUE); 675706f2543Smrg 676706f2543Smrg /* alu is already GXCopy */ 677706f2543Smrg gcv.val = (XID)planeMask; 678706f2543Smrg ChangeGC(NullClient, pGC, GCPlaneMask, &gcv); 679706f2543Smrg ValidateGC((DrawablePtr)pPixmap, pGC); 680706f2543Smrg } 681706f2543Smrg 682706f2543Smrg linelength = PixmapBytePad(w, depth); 683706f2543Smrg srcx = sx + pDraw->x; 684706f2543Smrg srcy = sy + pDraw->y; 685706f2543Smrg for(i = 0; i < h; i++) 686706f2543Smrg { 687706f2543Smrg pt.x = srcx; 688706f2543Smrg pt.y = srcy + i; 689706f2543Smrg width = w; 690706f2543Smrg (*pDraw->pScreen->GetSpans)(pDraw, w, &pt, &width, 1, pDst); 691706f2543Smrg if (pPixmap) 692706f2543Smrg { 693706f2543Smrg pt.x = 0; 694706f2543Smrg pt.y = 0; 695706f2543Smrg width = w; 696706f2543Smrg (*pGC->ops->SetSpans)((DrawablePtr)pPixmap, pGC, pDst, 697706f2543Smrg &pt, &width, 1, TRUE); 698706f2543Smrg (*pDraw->pScreen->GetSpans)((DrawablePtr)pPixmap, w, &pt, 699706f2543Smrg &width, 1, pDst); 700706f2543Smrg } 701706f2543Smrg pDst += linelength; 702706f2543Smrg } 703706f2543Smrg if (pPixmap) 704706f2543Smrg { 705706f2543Smrg (*pGC->pScreen->DestroyPixmap)(pPixmap); 706706f2543Smrg FreeScratchGC(pGC); 707706f2543Smrg } 708706f2543Smrg } 709706f2543Smrg else 710706f2543Smrg { 711706f2543Smrg (void) miGetPlane(pDraw, ffs(planeMask) - 1, sx, sy, w, h, 712706f2543Smrg (MiBits *)pDst); 713706f2543Smrg } 714706f2543Smrg} 715706f2543Smrg 716706f2543Smrg/* MIPUTIMAGE -- public entry for the PutImage request 717706f2543Smrg * Here we benefit from knowing the format of the bits pointed to by pImage, 718706f2543Smrg * even if we don't know how pDraw represents them. 719706f2543Smrg * Three different strategies are used depending on the format 720706f2543Smrg * XYBitmap Format: 721706f2543Smrg * we just use the Opaque Stipple helper function to cover the destination 722706f2543Smrg * Note that this covers all the planes of the drawable with the 723706f2543Smrg * foreground color (masked with the GC planemask) where there are 1 bits 724706f2543Smrg * and the background color (masked with the GC planemask) where there are 725706f2543Smrg * 0 bits 726706f2543Smrg * XYPixmap format: 727706f2543Smrg * what we're called with is a series of XYBitmaps, but we only want 728706f2543Smrg * each XYPixmap to update 1 plane, instead of updating all of them. 729706f2543Smrg * we set the foreground color to be all 1s and the background to all 0s 730706f2543Smrg * then for each plane, we set the plane mask to only effect that one 731706f2543Smrg * plane and recursive call ourself with the format set to XYBitmap 732706f2543Smrg * (This clever idea courtesy of RGD.) 733706f2543Smrg * ZPixmap format: 734706f2543Smrg * This part is simple, just call SetSpans 735706f2543Smrg */ 736706f2543Smrgvoid 737706f2543SmrgmiPutImage( DrawablePtr pDraw, GCPtr pGC, int depth, 738706f2543Smrg int x, int y, int w, int h, 739706f2543Smrg int leftPad, int format, char *pImage) 740706f2543Smrg{ 741706f2543Smrg DDXPointPtr pptFirst, ppt; 742706f2543Smrg int *pwidthFirst, *pwidth; 743706f2543Smrg RegionPtr prgnSrc; 744706f2543Smrg BoxRec box; 745706f2543Smrg unsigned long oldFg, oldBg; 746706f2543Smrg ChangeGCVal gcv[3]; 747706f2543Smrg unsigned long oldPlanemask; 748706f2543Smrg unsigned long i; 749706f2543Smrg long bytesPer; 750706f2543Smrg 751706f2543Smrg if (!w || !h) 752706f2543Smrg return; 753706f2543Smrg switch(format) 754706f2543Smrg { 755706f2543Smrg case XYBitmap: 756706f2543Smrg 757706f2543Smrg box.x1 = 0; 758706f2543Smrg box.y1 = 0; 759706f2543Smrg box.x2 = w; 760706f2543Smrg box.y2 = h; 761706f2543Smrg prgnSrc = RegionCreate(&box, 1); 762706f2543Smrg 763706f2543Smrg miOpqStipDrawable(pDraw, pGC, prgnSrc, (MiBits *) pImage, 764706f2543Smrg leftPad, w, h, x, y); 765706f2543Smrg RegionDestroy(prgnSrc); 766706f2543Smrg break; 767706f2543Smrg 768706f2543Smrg case XYPixmap: 769706f2543Smrg depth = pGC->depth; 770706f2543Smrg oldPlanemask = pGC->planemask; 771706f2543Smrg oldFg = pGC->fgPixel; 772706f2543Smrg oldBg = pGC->bgPixel; 773706f2543Smrg gcv[0].val = (XID)~0; 774706f2543Smrg gcv[1].val = (XID)0; 775706f2543Smrg ChangeGC(NullClient, pGC, GCForeground | GCBackground, gcv); 776706f2543Smrg bytesPer = (long)h * BitmapBytePad(w + leftPad); 777706f2543Smrg 778706f2543Smrg for (i = 1 << (depth-1); i != 0; i >>= 1, pImage += bytesPer) 779706f2543Smrg { 780706f2543Smrg if (i & oldPlanemask) 781706f2543Smrg { 782706f2543Smrg gcv[0].val = (XID)i; 783706f2543Smrg ChangeGC(NullClient, pGC, GCPlaneMask, gcv); 784706f2543Smrg ValidateGC(pDraw, pGC); 785706f2543Smrg (*pGC->ops->PutImage)(pDraw, pGC, 1, x, y, w, h, leftPad, 786706f2543Smrg XYBitmap, (char *)pImage); 787706f2543Smrg } 788706f2543Smrg } 789706f2543Smrg gcv[0].val = (XID)oldPlanemask; 790706f2543Smrg gcv[1].val = (XID)oldFg; 791706f2543Smrg gcv[2].val = (XID)oldBg; 792706f2543Smrg ChangeGC(NullClient, pGC, GCPlaneMask | GCForeground | GCBackground, gcv); 793706f2543Smrg ValidateGC(pDraw, pGC); 794706f2543Smrg break; 795706f2543Smrg 796706f2543Smrg case ZPixmap: 797706f2543Smrg ppt = pptFirst = malloc(h * sizeof(DDXPointRec)); 798706f2543Smrg pwidth = pwidthFirst = malloc(h * sizeof(int)); 799706f2543Smrg if(!pptFirst || !pwidthFirst) 800706f2543Smrg { 801706f2543Smrg free(pwidthFirst); 802706f2543Smrg free(pptFirst); 803706f2543Smrg return; 804706f2543Smrg } 805706f2543Smrg if (pGC->miTranslate) 806706f2543Smrg { 807706f2543Smrg x += pDraw->x; 808706f2543Smrg y += pDraw->y; 809706f2543Smrg } 810706f2543Smrg 811706f2543Smrg for(i = 0; i < h; i++) 812706f2543Smrg { 813706f2543Smrg ppt->x = x; 814706f2543Smrg ppt->y = y + i; 815706f2543Smrg ppt++; 816706f2543Smrg *pwidth++ = w; 817706f2543Smrg } 818706f2543Smrg 819706f2543Smrg (*pGC->ops->SetSpans)(pDraw, pGC, (char *)pImage, pptFirst, 820706f2543Smrg pwidthFirst, h, TRUE); 821706f2543Smrg free(pwidthFirst); 822706f2543Smrg free(pptFirst); 823706f2543Smrg break; 824706f2543Smrg } 825706f2543Smrg} 826