mibitblt.c revision 6747b715
105b261ecSmrg/*********************************************************** 205b261ecSmrg 305b261ecSmrgCopyright 1987, 1998 The Open Group 405b261ecSmrg 505b261ecSmrgPermission to use, copy, modify, distribute, and sell this software and its 605b261ecSmrgdocumentation for any purpose is hereby granted without fee, provided that 705b261ecSmrgthe above copyright notice appear in all copies and that both that 805b261ecSmrgcopyright notice and this permission notice appear in supporting 905b261ecSmrgdocumentation. 1005b261ecSmrg 1105b261ecSmrgThe above copyright notice and this permission notice shall be included in 1205b261ecSmrgall copies or substantial portions of the Software. 1305b261ecSmrg 1405b261ecSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1505b261ecSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1605b261ecSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1705b261ecSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 1805b261ecSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 1905b261ecSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 2005b261ecSmrg 2105b261ecSmrgExcept as contained in this notice, the name of The Open Group shall not be 2205b261ecSmrgused in advertising or otherwise to promote the sale, use or other dealings 2305b261ecSmrgin this Software without prior written authorization from The Open Group. 2405b261ecSmrg 2505b261ecSmrg 2605b261ecSmrgCopyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. 2705b261ecSmrg 2805b261ecSmrg All Rights Reserved 2905b261ecSmrg 3005b261ecSmrgPermission to use, copy, modify, and distribute this software and its 3105b261ecSmrgdocumentation for any purpose and without fee is hereby granted, 3205b261ecSmrgprovided that the above copyright notice appear in all copies and that 3305b261ecSmrgboth that copyright notice and this permission notice appear in 3405b261ecSmrgsupporting documentation, and that the name of Digital not be 3505b261ecSmrgused in advertising or publicity pertaining to distribution of the 3605b261ecSmrgsoftware without specific, written prior permission. 3705b261ecSmrg 3805b261ecSmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 3905b261ecSmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 4005b261ecSmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 4105b261ecSmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 4205b261ecSmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 4305b261ecSmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 4405b261ecSmrgSOFTWARE. 4505b261ecSmrg 4605b261ecSmrg******************************************************************/ 4705b261ecSmrg/* Author: Todd Newman (aided and abetted by Mr. Drewry) */ 4805b261ecSmrg 4905b261ecSmrg#ifdef HAVE_DIX_CONFIG_H 5005b261ecSmrg#include <dix-config.h> 5105b261ecSmrg#endif 5205b261ecSmrg 5305b261ecSmrg#include <X11/X.h> 5405b261ecSmrg#include <X11/Xprotostr.h> 5505b261ecSmrg 5605b261ecSmrg#include "misc.h" 5705b261ecSmrg#include "gcstruct.h" 5805b261ecSmrg#include "pixmapstr.h" 5905b261ecSmrg#include "windowstr.h" 6005b261ecSmrg#include "scrnintstr.h" 6105b261ecSmrg#include "mi.h" 6205b261ecSmrg#include "regionstr.h" 6305b261ecSmrg#include <X11/Xmd.h> 6405b261ecSmrg#include "servermd.h" 6505b261ecSmrg 6605b261ecSmrg#ifndef HAS_FFS 6705b261ecSmrgextern int ffs(int); 6805b261ecSmrg#endif 6905b261ecSmrg 7005b261ecSmrg/* MICOPYAREA -- public entry for the CopyArea request 7105b261ecSmrg * For each rectangle in the source region 7205b261ecSmrg * get the pixels with GetSpans 7305b261ecSmrg * set them in the destination with SetSpans 7405b261ecSmrg * We let SetSpans worry about clipping to the destination. 7505b261ecSmrg */ 764642e01fSmrgRegionPtr 774642e01fSmrgmiCopyArea(DrawablePtr pSrcDrawable, 784642e01fSmrg DrawablePtr pDstDrawable, 794642e01fSmrg GCPtr pGC, 804642e01fSmrg int xIn, 814642e01fSmrg int yIn, 824642e01fSmrg int widthSrc, 834642e01fSmrg int heightSrc, 844642e01fSmrg int xOut, 854642e01fSmrg int yOut) 8605b261ecSmrg{ 8705b261ecSmrg DDXPointPtr ppt, pptFirst; 8805b261ecSmrg unsigned int *pwidthFirst, *pwidth, *pbits; 8905b261ecSmrg BoxRec srcBox, *prect; 9005b261ecSmrg /* may be a new region, or just a copy */ 9105b261ecSmrg RegionPtr prgnSrcClip; 9205b261ecSmrg /* non-0 if we've created a src clip */ 9305b261ecSmrg RegionPtr prgnExposed; 9405b261ecSmrg int realSrcClip = 0; 9505b261ecSmrg int srcx, srcy, dstx, dsty, i, j, y, width, height, 9605b261ecSmrg xMin, xMax, yMin, yMax; 9705b261ecSmrg unsigned int *ordering; 9805b261ecSmrg int numRects; 9905b261ecSmrg BoxPtr boxes; 10005b261ecSmrg 10105b261ecSmrg srcx = xIn + pSrcDrawable->x; 10205b261ecSmrg srcy = yIn + pSrcDrawable->y; 10305b261ecSmrg 10405b261ecSmrg /* If the destination isn't realized, this is easy */ 10505b261ecSmrg if (pDstDrawable->type == DRAWABLE_WINDOW && 10605b261ecSmrg !((WindowPtr)pDstDrawable)->realized) 1076747b715Smrg return NULL; 10805b261ecSmrg 10905b261ecSmrg /* clip the source */ 11005b261ecSmrg if (pSrcDrawable->type == DRAWABLE_PIXMAP) 11105b261ecSmrg { 11205b261ecSmrg BoxRec box; 11305b261ecSmrg 11405b261ecSmrg box.x1 = pSrcDrawable->x; 11505b261ecSmrg box.y1 = pSrcDrawable->y; 11605b261ecSmrg box.x2 = pSrcDrawable->x + (int) pSrcDrawable->width; 11705b261ecSmrg box.y2 = pSrcDrawable->y + (int) pSrcDrawable->height; 11805b261ecSmrg 1196747b715Smrg prgnSrcClip = RegionCreate(&box, 1); 12005b261ecSmrg realSrcClip = 1; 12105b261ecSmrg } 12205b261ecSmrg else 12305b261ecSmrg { 12405b261ecSmrg if (pGC->subWindowMode == IncludeInferiors) { 12505b261ecSmrg prgnSrcClip = NotClippedByChildren ((WindowPtr) pSrcDrawable); 12605b261ecSmrg realSrcClip = 1; 12705b261ecSmrg } else 12805b261ecSmrg prgnSrcClip = &((WindowPtr)pSrcDrawable)->clipList; 12905b261ecSmrg } 13005b261ecSmrg 13105b261ecSmrg /* If the src drawable is a window, we need to translate the srcBox so 13205b261ecSmrg * that we can compare it with the window's clip region later on. */ 13305b261ecSmrg srcBox.x1 = srcx; 13405b261ecSmrg srcBox.y1 = srcy; 13505b261ecSmrg srcBox.x2 = srcx + widthSrc; 13605b261ecSmrg srcBox.y2 = srcy + heightSrc; 13705b261ecSmrg 13805b261ecSmrg dstx = xOut; 13905b261ecSmrg dsty = yOut; 14005b261ecSmrg if (pGC->miTranslate) 14105b261ecSmrg { 14205b261ecSmrg dstx += pDstDrawable->x; 14305b261ecSmrg dsty += pDstDrawable->y; 14405b261ecSmrg } 14505b261ecSmrg 1466747b715Smrg pptFirst = ppt = malloc(heightSrc * sizeof(DDXPointRec)); 1476747b715Smrg pwidthFirst = pwidth = malloc(heightSrc * sizeof(unsigned int)); 1486747b715Smrg numRects = RegionNumRects(prgnSrcClip); 1496747b715Smrg boxes = RegionRects(prgnSrcClip); 1506747b715Smrg ordering = malloc(numRects * sizeof(unsigned int)); 15105b261ecSmrg if(!pptFirst || !pwidthFirst || !ordering) 15205b261ecSmrg { 1536747b715Smrg free(ordering); 1546747b715Smrg free(pwidthFirst); 1556747b715Smrg free(pptFirst); 1566747b715Smrg return NULL; 15705b261ecSmrg } 15805b261ecSmrg 15905b261ecSmrg /* If not the same drawable then order of move doesn't matter. 16005b261ecSmrg Following assumes that boxes are sorted from top 16105b261ecSmrg to bottom and left to right. 16205b261ecSmrg */ 16305b261ecSmrg if ((pSrcDrawable != pDstDrawable) && 16405b261ecSmrg ((pGC->subWindowMode != IncludeInferiors) || 16505b261ecSmrg (pSrcDrawable->type == DRAWABLE_PIXMAP) || 16605b261ecSmrg (pDstDrawable->type == DRAWABLE_PIXMAP))) 16705b261ecSmrg for (i=0; i < numRects; i++) 16805b261ecSmrg ordering[i] = i; 16905b261ecSmrg else { /* within same drawable, must sequence moves carefully! */ 17005b261ecSmrg if (dsty <= srcBox.y1) { /* Scroll up or stationary vertical. 17105b261ecSmrg Vertical order OK */ 17205b261ecSmrg if (dstx <= srcBox.x1) /* Scroll left or stationary horizontal. 17305b261ecSmrg Horizontal order OK as well */ 17405b261ecSmrg for (i=0; i < numRects; i++) 17505b261ecSmrg ordering[i] = i; 17605b261ecSmrg else { /* scroll right. must reverse horizontal banding of rects. */ 17705b261ecSmrg for (i=0, j=1, xMax=0; i < numRects; j=i+1, xMax=i) { 17805b261ecSmrg /* find extent of current horizontal band */ 17905b261ecSmrg y=boxes[i].y1; /* band has this y coordinate */ 18005b261ecSmrg while ((j < numRects) && (boxes[j].y1 == y)) 18105b261ecSmrg j++; 18205b261ecSmrg /* reverse the horizontal band in the output ordering */ 18305b261ecSmrg for (j-- ; j >= xMax; j--, i++) 18405b261ecSmrg ordering[i] = j; 18505b261ecSmrg } 18605b261ecSmrg } 18705b261ecSmrg } 18805b261ecSmrg else { /* Scroll down. Must reverse vertical banding. */ 18905b261ecSmrg if (dstx < srcBox.x1) { /* Scroll left. Horizontal order OK. */ 19005b261ecSmrg for (i=numRects-1, j=i-1, yMin=i, yMax=0; 19105b261ecSmrg i >= 0; 19205b261ecSmrg j=i-1, yMin=i) { 19305b261ecSmrg /* find extent of current horizontal band */ 19405b261ecSmrg y=boxes[i].y1; /* band has this y coordinate */ 19505b261ecSmrg while ((j >= 0) && (boxes[j].y1 == y)) 19605b261ecSmrg j--; 19705b261ecSmrg /* reverse the horizontal band in the output ordering */ 19805b261ecSmrg for (j++ ; j <= yMin; j++, i--, yMax++) 19905b261ecSmrg ordering[yMax] = j; 20005b261ecSmrg } 20105b261ecSmrg } 20205b261ecSmrg else /* Scroll right or horizontal stationary. 20305b261ecSmrg Reverse horizontal order as well (if stationary, horizontal 20405b261ecSmrg order can be swapped without penalty and this is faster 20505b261ecSmrg to compute). */ 20605b261ecSmrg for (i=0, j=numRects-1; i < numRects; i++, j--) 20705b261ecSmrg ordering[i] = j; 20805b261ecSmrg } 20905b261ecSmrg } 21005b261ecSmrg 21105b261ecSmrg for(i = 0; i < numRects; i++) 21205b261ecSmrg { 21305b261ecSmrg prect = &boxes[ordering[i]]; 21405b261ecSmrg xMin = max(prect->x1, srcBox.x1); 21505b261ecSmrg xMax = min(prect->x2, srcBox.x2); 21605b261ecSmrg yMin = max(prect->y1, srcBox.y1); 21705b261ecSmrg yMax = min(prect->y2, srcBox.y2); 21805b261ecSmrg /* is there anything visible here? */ 21905b261ecSmrg if(xMax <= xMin || yMax <= yMin) 22005b261ecSmrg continue; 22105b261ecSmrg 22205b261ecSmrg ppt = pptFirst; 22305b261ecSmrg pwidth = pwidthFirst; 22405b261ecSmrg y = yMin; 22505b261ecSmrg height = yMax - yMin; 22605b261ecSmrg width = xMax - xMin; 22705b261ecSmrg 22805b261ecSmrg for(j = 0; j < height; j++) 22905b261ecSmrg { 23005b261ecSmrg /* We must untranslate before calling GetSpans */ 23105b261ecSmrg ppt->x = xMin; 23205b261ecSmrg ppt++->y = y++; 23305b261ecSmrg *pwidth++ = width; 23405b261ecSmrg } 2356747b715Smrg pbits = malloc(height * PixmapBytePad(width, pSrcDrawable->depth)); 23605b261ecSmrg if (pbits) 23705b261ecSmrg { 23805b261ecSmrg (*pSrcDrawable->pScreen->GetSpans)(pSrcDrawable, width, pptFirst, 23905b261ecSmrg (int *)pwidthFirst, height, (char *)pbits); 24005b261ecSmrg ppt = pptFirst; 24105b261ecSmrg pwidth = pwidthFirst; 24205b261ecSmrg xMin -= (srcx - dstx); 24305b261ecSmrg y = yMin - (srcy - dsty); 24405b261ecSmrg for(j = 0; j < height; j++) 24505b261ecSmrg { 24605b261ecSmrg ppt->x = xMin; 24705b261ecSmrg ppt++->y = y++; 24805b261ecSmrg *pwidth++ = width; 24905b261ecSmrg } 25005b261ecSmrg 25105b261ecSmrg (*pGC->ops->SetSpans)(pDstDrawable, pGC, (char *)pbits, pptFirst, 25205b261ecSmrg (int *)pwidthFirst, height, TRUE); 2536747b715Smrg free(pbits); 25405b261ecSmrg } 25505b261ecSmrg } 25605b261ecSmrg prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC, xIn, yIn, 25705b261ecSmrg widthSrc, heightSrc, xOut, yOut, (unsigned long)0); 25805b261ecSmrg if(realSrcClip) 2596747b715Smrg RegionDestroy(prgnSrcClip); 26005b261ecSmrg 2616747b715Smrg free(ordering); 2626747b715Smrg free(pwidthFirst); 2636747b715Smrg free(pptFirst); 26405b261ecSmrg return prgnExposed; 26505b261ecSmrg} 26605b261ecSmrg 26705b261ecSmrg/* MIGETPLANE -- gets a bitmap representing one plane of pDraw 26805b261ecSmrg * A helper used for CopyPlane and XY format GetImage 26905b261ecSmrg * No clever strategy here, we grab a scanline at a time, pull out the 27005b261ecSmrg * bits and then stuff them in a 1 bit deep map. 27105b261ecSmrg */ 27205b261ecSmrg/* 27305b261ecSmrg * This should be replaced with something more general. mi shouldn't have to 27405b261ecSmrg * care about such things as scanline padding et alia. 27505b261ecSmrg */ 27605b261ecSmrgstatic 27705b261ecSmrgMiBits * 27805b261ecSmrgmiGetPlane( 27905b261ecSmrg DrawablePtr pDraw, 28005b261ecSmrg int planeNum, /* number of the bitPlane */ 28105b261ecSmrg int sx, 28205b261ecSmrg int sy, 28305b261ecSmrg int w, 28405b261ecSmrg int h, 28505b261ecSmrg MiBits *result) 28605b261ecSmrg{ 28705b261ecSmrg int i, j, k, width, bitsPerPixel, widthInBytes; 28805b261ecSmrg DDXPointRec pt = {0, 0}; 28905b261ecSmrg MiBits pixel; 29005b261ecSmrg MiBits bit; 29105b261ecSmrg unsigned char *pCharsOut = NULL; 29205b261ecSmrg 29305b261ecSmrg#if BITMAP_SCANLINE_UNIT == 8 29405b261ecSmrg#define OUT_TYPE unsigned char 29505b261ecSmrg#endif 29605b261ecSmrg#if BITMAP_SCANLINE_UNIT == 16 29705b261ecSmrg#define OUT_TYPE CARD16 29805b261ecSmrg#endif 29905b261ecSmrg#if BITMAP_SCANLINE_UNIT == 32 30005b261ecSmrg#define OUT_TYPE CARD32 30105b261ecSmrg#endif 30205b261ecSmrg#if BITMAP_SCANLINE_UNIT == 64 30305b261ecSmrg#define OUT_TYPE CARD64 30405b261ecSmrg#endif 30505b261ecSmrg 30605b261ecSmrg OUT_TYPE *pOut; 30705b261ecSmrg int delta = 0; 30805b261ecSmrg 30905b261ecSmrg sx += pDraw->x; 31005b261ecSmrg sy += pDraw->y; 31105b261ecSmrg widthInBytes = BitmapBytePad(w); 31205b261ecSmrg if(!result) 3136747b715Smrg result = calloc(h, widthInBytes); 31405b261ecSmrg if (!result) 3156747b715Smrg return NULL; 31605b261ecSmrg bitsPerPixel = pDraw->bitsPerPixel; 31705b261ecSmrg pOut = (OUT_TYPE *) result; 31805b261ecSmrg if(bitsPerPixel == 1) 31905b261ecSmrg { 32005b261ecSmrg pCharsOut = (unsigned char *) result; 32105b261ecSmrg width = w; 32205b261ecSmrg } 32305b261ecSmrg else 32405b261ecSmrg { 32505b261ecSmrg delta = (widthInBytes / (BITMAP_SCANLINE_UNIT / 8)) - 32605b261ecSmrg (w / BITMAP_SCANLINE_UNIT); 32705b261ecSmrg width = 1; 32805b261ecSmrg#if IMAGE_BYTE_ORDER == MSBFirst 32905b261ecSmrg planeNum += (32 - bitsPerPixel); 33005b261ecSmrg#endif 33105b261ecSmrg } 33205b261ecSmrg pt.y = sy; 33305b261ecSmrg for (i = h; --i >= 0; pt.y++) 33405b261ecSmrg { 33505b261ecSmrg pt.x = sx; 33605b261ecSmrg if(bitsPerPixel == 1) 33705b261ecSmrg { 33805b261ecSmrg (*pDraw->pScreen->GetSpans)(pDraw, width, &pt, &width, 1, 33905b261ecSmrg (char *)pCharsOut); 34005b261ecSmrg pCharsOut += widthInBytes; 34105b261ecSmrg } 34205b261ecSmrg else 34305b261ecSmrg { 34405b261ecSmrg k = 0; 34505b261ecSmrg for(j = w; --j >= 0; pt.x++) 34605b261ecSmrg { 34705b261ecSmrg /* Fetch the next pixel */ 34805b261ecSmrg (*pDraw->pScreen->GetSpans)(pDraw, width, &pt, &width, 1, 34905b261ecSmrg (char *)&pixel); 35005b261ecSmrg /* 35105b261ecSmrg * Now get the bit and insert into a bitmap in XY format. 35205b261ecSmrg */ 35305b261ecSmrg bit = (pixel >> planeNum) & 1; 35405b261ecSmrg#if 0 35505b261ecSmrg /* XXX assuming bit order == byte order */ 35605b261ecSmrg#if BITMAP_BIT_ORDER == LSBFirst 35705b261ecSmrg bit <<= k; 35805b261ecSmrg#else 35905b261ecSmrg bit <<= ((BITMAP_SCANLINE_UNIT - 1) - k); 36005b261ecSmrg#endif 36105b261ecSmrg#else 36205b261ecSmrg /* XXX assuming byte order == LSBFirst */ 36305b261ecSmrg if (screenInfo.bitmapBitOrder == LSBFirst) 36405b261ecSmrg bit <<= k; 36505b261ecSmrg else 36605b261ecSmrg bit <<= ((screenInfo.bitmapScanlineUnit - 1) - 36705b261ecSmrg (k % screenInfo.bitmapScanlineUnit)) + 36805b261ecSmrg ((k / screenInfo.bitmapScanlineUnit) * 36905b261ecSmrg screenInfo.bitmapScanlineUnit); 37005b261ecSmrg#endif 37105b261ecSmrg *pOut |= (OUT_TYPE) bit; 37205b261ecSmrg k++; 37305b261ecSmrg if (k == BITMAP_SCANLINE_UNIT) 37405b261ecSmrg { 37505b261ecSmrg pOut++; 37605b261ecSmrg k = 0; 37705b261ecSmrg } 37805b261ecSmrg } 37905b261ecSmrg pOut += delta; 38005b261ecSmrg } 38105b261ecSmrg } 3826747b715Smrg return result; 38305b261ecSmrg 38405b261ecSmrg} 38505b261ecSmrg 38605b261ecSmrg/* MIOPQSTIPDRAWABLE -- use pbits as an opaque stipple for pDraw. 38705b261ecSmrg * Drawing through the clip mask we SetSpans() the bits into a 38805b261ecSmrg * bitmap and stipple those bits onto the destination drawable by doing a 38905b261ecSmrg * PolyFillRect over the whole drawable, 39005b261ecSmrg * then we invert the bitmap by copying it onto itself with an alu of 39105b261ecSmrg * GXinvert, invert the foreground/background colors of the gc, and draw 39205b261ecSmrg * the background bits. 39305b261ecSmrg * Note how the clipped out bits of the bitmap are always the background 39405b261ecSmrg * color so that the stipple never causes FillRect to draw them. 39505b261ecSmrg */ 39605b261ecSmrgstatic void 39705b261ecSmrgmiOpqStipDrawable(DrawablePtr pDraw, GCPtr pGC, RegionPtr prgnSrc, 39805b261ecSmrg MiBits *pbits, int srcx, int w, int h, int dstx, int dsty) 39905b261ecSmrg{ 40005b261ecSmrg int oldfill, i; 40105b261ecSmrg unsigned long oldfg; 40205b261ecSmrg int *pwidth, *pwidthFirst; 40305b261ecSmrg ChangeGCVal gcv[6]; 40405b261ecSmrg PixmapPtr pStipple, pPixmap; 40505b261ecSmrg DDXPointRec oldOrg; 40605b261ecSmrg GCPtr pGCT; 40705b261ecSmrg DDXPointPtr ppt, pptFirst; 40805b261ecSmrg xRectangle rect; 40905b261ecSmrg RegionPtr prgnSrcClip; 41005b261ecSmrg 41105b261ecSmrg pPixmap = (*pDraw->pScreen->CreatePixmap) 4124642e01fSmrg (pDraw->pScreen, w + srcx, h, 1, 4134642e01fSmrg CREATE_PIXMAP_USAGE_SCRATCH); 41405b261ecSmrg if (!pPixmap) 41505b261ecSmrg return; 41605b261ecSmrg 41705b261ecSmrg /* Put the image into a 1 bit deep pixmap */ 41805b261ecSmrg pGCT = GetScratchGC(1, pDraw->pScreen); 41905b261ecSmrg if (!pGCT) 42005b261ecSmrg { 42105b261ecSmrg (*pDraw->pScreen->DestroyPixmap)(pPixmap); 42205b261ecSmrg return; 42305b261ecSmrg } 42405b261ecSmrg /* First set the whole pixmap to 0 */ 42505b261ecSmrg gcv[0].val = 0; 4266747b715Smrg ChangeGC(NullClient, pGCT, GCBackground, gcv); 42705b261ecSmrg ValidateGC((DrawablePtr)pPixmap, pGCT); 42805b261ecSmrg miClearDrawable((DrawablePtr)pPixmap, pGCT); 4296747b715Smrg ppt = pptFirst = malloc(h * sizeof(DDXPointRec)); 4306747b715Smrg pwidth = pwidthFirst = malloc(h * sizeof(int)); 43105b261ecSmrg if(!pptFirst || !pwidthFirst) 43205b261ecSmrg { 4336747b715Smrg free(pwidthFirst); 4346747b715Smrg free(pptFirst); 43505b261ecSmrg FreeScratchGC(pGCT); 43605b261ecSmrg return; 43705b261ecSmrg } 43805b261ecSmrg 43905b261ecSmrg /* we need a temporary region because ChangeClip must be assumed 44005b261ecSmrg to destroy what it's sent. note that this means we don't 44105b261ecSmrg have to free prgnSrcClip ourselves. 44205b261ecSmrg */ 4436747b715Smrg prgnSrcClip = RegionCreate(NULL, 0); 4446747b715Smrg RegionCopy(prgnSrcClip, prgnSrc); 4456747b715Smrg RegionTranslate(prgnSrcClip, srcx, 0); 44605b261ecSmrg (*pGCT->funcs->ChangeClip)(pGCT, CT_REGION, prgnSrcClip, 0); 44705b261ecSmrg ValidateGC((DrawablePtr)pPixmap, pGCT); 44805b261ecSmrg 44905b261ecSmrg /* Since we know pDraw is always a pixmap, we never need to think 45005b261ecSmrg * about translation here */ 45105b261ecSmrg for(i = 0; i < h; i++) 45205b261ecSmrg { 45305b261ecSmrg ppt->x = 0; 45405b261ecSmrg ppt++->y = i; 45505b261ecSmrg *pwidth++ = w + srcx; 45605b261ecSmrg } 45705b261ecSmrg 45805b261ecSmrg (*pGCT->ops->SetSpans)((DrawablePtr)pPixmap, pGCT, (char *)pbits, 45905b261ecSmrg pptFirst, pwidthFirst, h, TRUE); 4606747b715Smrg free(pwidthFirst); 4616747b715Smrg free(pptFirst); 46205b261ecSmrg 46305b261ecSmrg 46405b261ecSmrg /* Save current values from the client GC */ 46505b261ecSmrg oldfill = pGC->fillStyle; 46605b261ecSmrg pStipple = pGC->stipple; 46705b261ecSmrg if(pStipple) 46805b261ecSmrg pStipple->refcnt++; 46905b261ecSmrg oldOrg = pGC->patOrg; 47005b261ecSmrg 47105b261ecSmrg /* Set a new stipple in the drawable */ 47205b261ecSmrg gcv[0].val = FillStippled; 47305b261ecSmrg gcv[1].ptr = pPixmap; 47405b261ecSmrg gcv[2].val = dstx - srcx; 47505b261ecSmrg gcv[3].val = dsty; 47605b261ecSmrg 4776747b715Smrg ChangeGC(NullClient, pGC, 47805b261ecSmrg GCFillStyle | GCStipple | GCTileStipXOrigin | GCTileStipYOrigin, 4796747b715Smrg gcv); 48005b261ecSmrg ValidateGC(pDraw, pGC); 48105b261ecSmrg 48205b261ecSmrg /* Fill the drawable with the stipple. This will draw the 48305b261ecSmrg * foreground color whereever 1 bits are set, leaving everything 48405b261ecSmrg * with 0 bits untouched. Note that the part outside the clip 48505b261ecSmrg * region is all 0s. */ 48605b261ecSmrg rect.x = dstx; 48705b261ecSmrg rect.y = dsty; 48805b261ecSmrg rect.width = w; 48905b261ecSmrg rect.height = h; 49005b261ecSmrg (*pGC->ops->PolyFillRect)(pDraw, pGC, 1, &rect); 49105b261ecSmrg 49205b261ecSmrg /* Invert the tiling pixmap. This sets 0s for 1s and 1s for 0s, only 49305b261ecSmrg * within the clipping region, the part outside is still all 0s */ 49405b261ecSmrg gcv[0].val = GXinvert; 4956747b715Smrg ChangeGC(NullClient, pGCT, GCFunction, gcv); 49605b261ecSmrg ValidateGC((DrawablePtr)pPixmap, pGCT); 49705b261ecSmrg (*pGCT->ops->CopyArea)((DrawablePtr)pPixmap, (DrawablePtr)pPixmap, 49805b261ecSmrg pGCT, 0, 0, w + srcx, h, 0, 0); 49905b261ecSmrg 50005b261ecSmrg /* Swap foreground and background colors on the GC for the drawable. 50105b261ecSmrg * Now when we fill the drawable, we will fill in the "Background" 50205b261ecSmrg * values */ 50305b261ecSmrg oldfg = pGC->fgPixel; 50405b261ecSmrg gcv[0].val = pGC->bgPixel; 50505b261ecSmrg gcv[1].val = oldfg; 50605b261ecSmrg gcv[2].ptr = pPixmap; 5076747b715Smrg ChangeGC(NullClient, pGC, GCForeground | GCBackground | GCStipple, gcv); 50805b261ecSmrg ValidateGC(pDraw, pGC); 50905b261ecSmrg /* PolyFillRect might have bashed the rectangle */ 51005b261ecSmrg rect.x = dstx; 51105b261ecSmrg rect.y = dsty; 51205b261ecSmrg rect.width = w; 51305b261ecSmrg rect.height = h; 51405b261ecSmrg (*pGC->ops->PolyFillRect)(pDraw, pGC, 1, &rect); 51505b261ecSmrg 51605b261ecSmrg /* Now put things back */ 51705b261ecSmrg if(pStipple) 51805b261ecSmrg pStipple->refcnt--; 51905b261ecSmrg gcv[0].val = oldfg; 52005b261ecSmrg gcv[1].val = pGC->fgPixel; 52105b261ecSmrg gcv[2].val = oldfill; 52205b261ecSmrg gcv[3].ptr = pStipple; 52305b261ecSmrg gcv[4].val = oldOrg.x; 52405b261ecSmrg gcv[5].val = oldOrg.y; 5256747b715Smrg ChangeGC(NullClient, pGC, 52605b261ecSmrg GCForeground | GCBackground | GCFillStyle | GCStipple | 5276747b715Smrg GCTileStipXOrigin | GCTileStipYOrigin, gcv); 52805b261ecSmrg 52905b261ecSmrg ValidateGC(pDraw, pGC); 53005b261ecSmrg /* put what we hope is a smaller clip region back in the scratch gc */ 53105b261ecSmrg (*pGCT->funcs->ChangeClip)(pGCT, CT_NONE, NULL, 0); 53205b261ecSmrg FreeScratchGC(pGCT); 53305b261ecSmrg (*pDraw->pScreen->DestroyPixmap)(pPixmap); 53405b261ecSmrg 53505b261ecSmrg} 53605b261ecSmrg 53705b261ecSmrg/* MICOPYPLANE -- public entry for the CopyPlane request. 53805b261ecSmrg * strategy: 53905b261ecSmrg * First build up a bitmap out of the bits requested 54005b261ecSmrg * build a source clip 54105b261ecSmrg * Use the bitmap we've built up as a Stipple for the destination 54205b261ecSmrg */ 5434642e01fSmrgRegionPtr 5444642e01fSmrgmiCopyPlane( DrawablePtr pSrcDrawable, 5454642e01fSmrg DrawablePtr pDstDrawable, 5464642e01fSmrg GCPtr pGC, 5474642e01fSmrg int srcx, 5484642e01fSmrg int srcy, 5494642e01fSmrg int width, 5504642e01fSmrg int height, 5514642e01fSmrg int dstx, 5524642e01fSmrg int dsty, 5534642e01fSmrg unsigned long bitPlane) 55405b261ecSmrg{ 55505b261ecSmrg MiBits *ptile; 55605b261ecSmrg BoxRec box; 55705b261ecSmrg RegionPtr prgnSrc, prgnExposed; 55805b261ecSmrg 55905b261ecSmrg /* incorporate the source clip */ 56005b261ecSmrg 56105b261ecSmrg box.x1 = srcx + pSrcDrawable->x; 56205b261ecSmrg box.y1 = srcy + pSrcDrawable->y; 56305b261ecSmrg box.x2 = box.x1 + width; 56405b261ecSmrg box.y2 = box.y1 + height; 56505b261ecSmrg /* clip to visible drawable */ 56605b261ecSmrg if (box.x1 < pSrcDrawable->x) 56705b261ecSmrg box.x1 = pSrcDrawable->x; 56805b261ecSmrg if (box.y1 < pSrcDrawable->y) 56905b261ecSmrg box.y1 = pSrcDrawable->y; 57005b261ecSmrg if (box.x2 > pSrcDrawable->x + (int) pSrcDrawable->width) 57105b261ecSmrg box.x2 = pSrcDrawable->x + (int) pSrcDrawable->width; 57205b261ecSmrg if (box.y2 > pSrcDrawable->y + (int) pSrcDrawable->height) 57305b261ecSmrg box.y2 = pSrcDrawable->y + (int) pSrcDrawable->height; 57405b261ecSmrg if (box.x1 > box.x2) 57505b261ecSmrg box.x2 = box.x1; 57605b261ecSmrg if (box.y1 > box.y2) 57705b261ecSmrg box.y2 = box.y1; 5786747b715Smrg prgnSrc = RegionCreate(&box, 1); 57905b261ecSmrg 58005b261ecSmrg if (pSrcDrawable->type != DRAWABLE_PIXMAP) { 58105b261ecSmrg /* clip to visible drawable */ 58205b261ecSmrg 58305b261ecSmrg if (pGC->subWindowMode == IncludeInferiors) 58405b261ecSmrg { 58505b261ecSmrg RegionPtr clipList = NotClippedByChildren ((WindowPtr) pSrcDrawable); 5866747b715Smrg RegionIntersect(prgnSrc, prgnSrc, clipList); 5876747b715Smrg RegionDestroy(clipList); 58805b261ecSmrg } else 5896747b715Smrg RegionIntersect(prgnSrc, prgnSrc, 59005b261ecSmrg &((WindowPtr)pSrcDrawable)->clipList); 59105b261ecSmrg } 59205b261ecSmrg 5936747b715Smrg box = *RegionExtents(prgnSrc); 5946747b715Smrg RegionTranslate(prgnSrc, -box.x1, -box.y1); 59505b261ecSmrg 59605b261ecSmrg if ((box.x2 > box.x1) && (box.y2 > box.y1)) 59705b261ecSmrg { 59805b261ecSmrg /* minimize the size of the data extracted */ 59905b261ecSmrg /* note that we convert the plane mask bitPlane into a plane number */ 60005b261ecSmrg box.x1 -= pSrcDrawable->x; 60105b261ecSmrg box.x2 -= pSrcDrawable->x; 60205b261ecSmrg box.y1 -= pSrcDrawable->y; 60305b261ecSmrg box.y2 -= pSrcDrawable->y; 60405b261ecSmrg ptile = miGetPlane(pSrcDrawable, ffs(bitPlane) - 1, 60505b261ecSmrg box.x1, box.y1, 60605b261ecSmrg box.x2 - box.x1, box.y2 - box.y1, 60705b261ecSmrg (MiBits *) NULL); 60805b261ecSmrg if (ptile) 60905b261ecSmrg { 61005b261ecSmrg miOpqStipDrawable(pDstDrawable, pGC, prgnSrc, ptile, 0, 61105b261ecSmrg box.x2 - box.x1, box.y2 - box.y1, 61205b261ecSmrg dstx + box.x1 - srcx, dsty + box.y1 - srcy); 6136747b715Smrg free(ptile); 61405b261ecSmrg } 61505b261ecSmrg } 61605b261ecSmrg prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC, srcx, srcy, 61705b261ecSmrg width, height, dstx, dsty, bitPlane); 6186747b715Smrg RegionDestroy(prgnSrc); 61905b261ecSmrg return prgnExposed; 62005b261ecSmrg} 62105b261ecSmrg 62205b261ecSmrg/* MIGETIMAGE -- public entry for the GetImage Request 62305b261ecSmrg * We're getting the image into a memory buffer. While we have to use GetSpans 62405b261ecSmrg * to read a line from the device (since we don't know what that looks like), 62505b261ecSmrg * we can just write into the destination buffer 62605b261ecSmrg * 62705b261ecSmrg * two different strategies are used, depending on whether we're getting the 62805b261ecSmrg * image in Z format or XY format 62905b261ecSmrg * Z format: 63005b261ecSmrg * Line at a time, GetSpans a line into the destination buffer, then if the 63105b261ecSmrg * planemask is not all ones, we do a SetSpans into a temporary buffer (to get 63205b261ecSmrg * bits turned off) and then another GetSpans to get stuff back (because 63305b261ecSmrg * pixmaps are opaque, and we are passed in the memory to write into). This is 63405b261ecSmrg * pretty ugly and slow but works. Life is hard. 63505b261ecSmrg * XY format: 63605b261ecSmrg * get the single plane specified in planemask 63705b261ecSmrg */ 6386747b715Smrgvoid 6394642e01fSmrgmiGetImage( DrawablePtr pDraw, int sx, int sy, int w, int h, 6404642e01fSmrg unsigned int format, unsigned long planeMask, char *pDst) 64105b261ecSmrg{ 64205b261ecSmrg unsigned char depth; 64305b261ecSmrg int i, linelength, width, srcx, srcy; 64405b261ecSmrg DDXPointRec pt = {0, 0}; 6456747b715Smrg PixmapPtr pPixmap = NULL; 64605b261ecSmrg GCPtr pGC = NULL; 64705b261ecSmrg 64805b261ecSmrg depth = pDraw->depth; 64905b261ecSmrg if(format == ZPixmap) 65005b261ecSmrg { 65105b261ecSmrg if ( (((1<<depth)-1)&planeMask) != (1<<depth)-1 ) 65205b261ecSmrg { 6536747b715Smrg ChangeGCVal gcv; 65405b261ecSmrg xPoint pt; 65505b261ecSmrg 65605b261ecSmrg pGC = GetScratchGC(depth, pDraw->pScreen); 65705b261ecSmrg if (!pGC) 65805b261ecSmrg return; 65905b261ecSmrg pPixmap = (*pDraw->pScreen->CreatePixmap) 6604642e01fSmrg (pDraw->pScreen, w, 1, depth, 6614642e01fSmrg CREATE_PIXMAP_USAGE_SCRATCH); 66205b261ecSmrg if (!pPixmap) 66305b261ecSmrg { 66405b261ecSmrg FreeScratchGC(pGC); 66505b261ecSmrg return; 66605b261ecSmrg } 66705b261ecSmrg /* 66805b261ecSmrg * Clear the pixmap before doing anything else 66905b261ecSmrg */ 67005b261ecSmrg ValidateGC((DrawablePtr)pPixmap, pGC); 67105b261ecSmrg pt.x = pt.y = 0; 67205b261ecSmrg width = w; 67305b261ecSmrg (*pGC->ops->FillSpans)((DrawablePtr)pPixmap, pGC, 1, &pt, &width, 67405b261ecSmrg TRUE); 67505b261ecSmrg 67605b261ecSmrg /* alu is already GXCopy */ 6776747b715Smrg gcv.val = (XID)planeMask; 6786747b715Smrg ChangeGC(NullClient, pGC, GCPlaneMask, &gcv); 67905b261ecSmrg ValidateGC((DrawablePtr)pPixmap, pGC); 68005b261ecSmrg } 68105b261ecSmrg 68205b261ecSmrg linelength = PixmapBytePad(w, depth); 68305b261ecSmrg srcx = sx + pDraw->x; 68405b261ecSmrg srcy = sy + pDraw->y; 68505b261ecSmrg for(i = 0; i < h; i++) 68605b261ecSmrg { 68705b261ecSmrg pt.x = srcx; 68805b261ecSmrg pt.y = srcy + i; 68905b261ecSmrg width = w; 69005b261ecSmrg (*pDraw->pScreen->GetSpans)(pDraw, w, &pt, &width, 1, pDst); 69105b261ecSmrg if (pPixmap) 69205b261ecSmrg { 69305b261ecSmrg pt.x = 0; 69405b261ecSmrg pt.y = 0; 69505b261ecSmrg width = w; 69605b261ecSmrg (*pGC->ops->SetSpans)((DrawablePtr)pPixmap, pGC, pDst, 69705b261ecSmrg &pt, &width, 1, TRUE); 69805b261ecSmrg (*pDraw->pScreen->GetSpans)((DrawablePtr)pPixmap, w, &pt, 69905b261ecSmrg &width, 1, pDst); 70005b261ecSmrg } 70105b261ecSmrg pDst += linelength; 70205b261ecSmrg } 70305b261ecSmrg if (pPixmap) 70405b261ecSmrg { 70505b261ecSmrg (*pGC->pScreen->DestroyPixmap)(pPixmap); 70605b261ecSmrg FreeScratchGC(pGC); 70705b261ecSmrg } 70805b261ecSmrg } 70905b261ecSmrg else 71005b261ecSmrg { 71105b261ecSmrg (void) miGetPlane(pDraw, ffs(planeMask) - 1, sx, sy, w, h, 71205b261ecSmrg (MiBits *)pDst); 71305b261ecSmrg } 71405b261ecSmrg} 71505b261ecSmrg 71605b261ecSmrg/* MIPUTIMAGE -- public entry for the PutImage request 71705b261ecSmrg * Here we benefit from knowing the format of the bits pointed to by pImage, 71805b261ecSmrg * even if we don't know how pDraw represents them. 71905b261ecSmrg * Three different strategies are used depending on the format 72005b261ecSmrg * XYBitmap Format: 72105b261ecSmrg * we just use the Opaque Stipple helper function to cover the destination 72205b261ecSmrg * Note that this covers all the planes of the drawable with the 72305b261ecSmrg * foreground color (masked with the GC planemask) where there are 1 bits 72405b261ecSmrg * and the background color (masked with the GC planemask) where there are 72505b261ecSmrg * 0 bits 72605b261ecSmrg * XYPixmap format: 72705b261ecSmrg * what we're called with is a series of XYBitmaps, but we only want 72805b261ecSmrg * each XYPixmap to update 1 plane, instead of updating all of them. 72905b261ecSmrg * we set the foreground color to be all 1s and the background to all 0s 73005b261ecSmrg * then for each plane, we set the plane mask to only effect that one 73105b261ecSmrg * plane and recursive call ourself with the format set to XYBitmap 73205b261ecSmrg * (This clever idea courtesy of RGD.) 73305b261ecSmrg * ZPixmap format: 73405b261ecSmrg * This part is simple, just call SetSpans 73505b261ecSmrg */ 7366747b715Smrgvoid 7374642e01fSmrgmiPutImage( DrawablePtr pDraw, GCPtr pGC, int depth, 7384642e01fSmrg int x, int y, int w, int h, 7394642e01fSmrg int leftPad, int format, char *pImage) 74005b261ecSmrg{ 74105b261ecSmrg DDXPointPtr pptFirst, ppt; 74205b261ecSmrg int *pwidthFirst, *pwidth; 74305b261ecSmrg RegionPtr prgnSrc; 74405b261ecSmrg BoxRec box; 74505b261ecSmrg unsigned long oldFg, oldBg; 7466747b715Smrg ChangeGCVal gcv[3]; 74705b261ecSmrg unsigned long oldPlanemask; 74805b261ecSmrg unsigned long i; 74905b261ecSmrg long bytesPer; 75005b261ecSmrg 75105b261ecSmrg if (!w || !h) 75205b261ecSmrg return; 75305b261ecSmrg switch(format) 75405b261ecSmrg { 75505b261ecSmrg case XYBitmap: 75605b261ecSmrg 75705b261ecSmrg box.x1 = 0; 75805b261ecSmrg box.y1 = 0; 75905b261ecSmrg box.x2 = w; 76005b261ecSmrg box.y2 = h; 7616747b715Smrg prgnSrc = RegionCreate(&box, 1); 76205b261ecSmrg 76305b261ecSmrg miOpqStipDrawable(pDraw, pGC, prgnSrc, (MiBits *) pImage, 76405b261ecSmrg leftPad, w, h, x, y); 7656747b715Smrg RegionDestroy(prgnSrc); 76605b261ecSmrg break; 76705b261ecSmrg 76805b261ecSmrg case XYPixmap: 76905b261ecSmrg depth = pGC->depth; 77005b261ecSmrg oldPlanemask = pGC->planemask; 77105b261ecSmrg oldFg = pGC->fgPixel; 77205b261ecSmrg oldBg = pGC->bgPixel; 7736747b715Smrg gcv[0].val = (XID)~0; 7746747b715Smrg gcv[1].val = (XID)0; 7756747b715Smrg ChangeGC(NullClient, pGC, GCForeground | GCBackground, gcv); 77605b261ecSmrg bytesPer = (long)h * BitmapBytePad(w + leftPad); 77705b261ecSmrg 77805b261ecSmrg for (i = 1 << (depth-1); i != 0; i >>= 1, pImage += bytesPer) 77905b261ecSmrg { 78005b261ecSmrg if (i & oldPlanemask) 78105b261ecSmrg { 7826747b715Smrg gcv[0].val = (XID)i; 7836747b715Smrg ChangeGC(NullClient, pGC, GCPlaneMask, gcv); 78405b261ecSmrg ValidateGC(pDraw, pGC); 78505b261ecSmrg (*pGC->ops->PutImage)(pDraw, pGC, 1, x, y, w, h, leftPad, 78605b261ecSmrg XYBitmap, (char *)pImage); 78705b261ecSmrg } 78805b261ecSmrg } 7896747b715Smrg gcv[0].val = (XID)oldPlanemask; 7906747b715Smrg gcv[1].val = (XID)oldFg; 7916747b715Smrg gcv[2].val = (XID)oldBg; 7926747b715Smrg ChangeGC(NullClient, pGC, GCPlaneMask | GCForeground | GCBackground, gcv); 79305b261ecSmrg ValidateGC(pDraw, pGC); 79405b261ecSmrg break; 79505b261ecSmrg 79605b261ecSmrg case ZPixmap: 7976747b715Smrg ppt = pptFirst = malloc(h * sizeof(DDXPointRec)); 7986747b715Smrg pwidth = pwidthFirst = malloc(h * sizeof(int)); 79905b261ecSmrg if(!pptFirst || !pwidthFirst) 80005b261ecSmrg { 8016747b715Smrg free(pwidthFirst); 8026747b715Smrg free(pptFirst); 80305b261ecSmrg return; 80405b261ecSmrg } 80505b261ecSmrg if (pGC->miTranslate) 80605b261ecSmrg { 80705b261ecSmrg x += pDraw->x; 80805b261ecSmrg y += pDraw->y; 80905b261ecSmrg } 81005b261ecSmrg 81105b261ecSmrg for(i = 0; i < h; i++) 81205b261ecSmrg { 81305b261ecSmrg ppt->x = x; 81405b261ecSmrg ppt->y = y + i; 81505b261ecSmrg ppt++; 81605b261ecSmrg *pwidth++ = w; 81705b261ecSmrg } 81805b261ecSmrg 81905b261ecSmrg (*pGC->ops->SetSpans)(pDraw, pGC, (char *)pImage, pptFirst, 82005b261ecSmrg pwidthFirst, h, TRUE); 8216747b715Smrg free(pwidthFirst); 8226747b715Smrg free(pptFirst); 82305b261ecSmrg break; 82405b261ecSmrg } 82505b261ecSmrg} 826