mibitblt.c revision 35c4bbdf
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 2505b261ecSmrgCopyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. 2605b261ecSmrg 2705b261ecSmrg All Rights Reserved 2805b261ecSmrg 2935c4bbdfSmrgPermission to use, copy, modify, and distribute this software and its 3035c4bbdfSmrgdocumentation for any purpose and without fee is hereby granted, 3105b261ecSmrgprovided that the above copyright notice appear in all copies and that 3235c4bbdfSmrgboth that copyright notice and this permission notice appear in 3305b261ecSmrgsupporting documentation, and that the name of Digital not be 3405b261ecSmrgused in advertising or publicity pertaining to distribution of the 3535c4bbdfSmrgsoftware without specific, written prior permission. 3605b261ecSmrg 3705b261ecSmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 3805b261ecSmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 3905b261ecSmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 4005b261ecSmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 4105b261ecSmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 4205b261ecSmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 4305b261ecSmrgSOFTWARE. 4405b261ecSmrg 4505b261ecSmrg******************************************************************/ 4605b261ecSmrg/* Author: Todd Newman (aided and abetted by Mr. Drewry) */ 4705b261ecSmrg 4805b261ecSmrg#ifdef HAVE_DIX_CONFIG_H 4905b261ecSmrg#include <dix-config.h> 5005b261ecSmrg#endif 5105b261ecSmrg 5205b261ecSmrg#include <X11/X.h> 5305b261ecSmrg#include <X11/Xprotostr.h> 5405b261ecSmrg 5505b261ecSmrg#include "misc.h" 5605b261ecSmrg#include "gcstruct.h" 5705b261ecSmrg#include "pixmapstr.h" 5805b261ecSmrg#include "windowstr.h" 5905b261ecSmrg#include "scrnintstr.h" 6005b261ecSmrg#include "mi.h" 6105b261ecSmrg#include "regionstr.h" 6205b261ecSmrg#include <X11/Xmd.h> 6305b261ecSmrg#include "servermd.h" 6405b261ecSmrg 6535c4bbdfSmrg#ifndef HAVE_FFS 6605b261ecSmrgextern int ffs(int); 6705b261ecSmrg#endif 6805b261ecSmrg 6935c4bbdfSmrg/* MICOPYAREA -- public entry for the CopyArea request 7005b261ecSmrg * For each rectangle in the source region 7105b261ecSmrg * get the pixels with GetSpans 7205b261ecSmrg * set them in the destination with SetSpans 7305b261ecSmrg * We let SetSpans worry about clipping to the destination. 7405b261ecSmrg */ 7535c4bbdfSmrg_X_COLD RegionPtr 7635c4bbdfSmrgmiCopyArea(DrawablePtr pSrcDrawable, 7735c4bbdfSmrg DrawablePtr pDstDrawable, 7835c4bbdfSmrg GCPtr pGC, 7935c4bbdfSmrg int xIn, int yIn, int widthSrc, int heightSrc, int xOut, int yOut) 8005b261ecSmrg{ 8135c4bbdfSmrg DDXPointPtr ppt, pptFirst; 8235c4bbdfSmrg unsigned int *pwidthFirst, *pwidth, *pbits; 8335c4bbdfSmrg BoxRec srcBox, *prect; 8435c4bbdfSmrg 8535c4bbdfSmrg /* may be a new region, or just a copy */ 8635c4bbdfSmrg RegionPtr prgnSrcClip; 8735c4bbdfSmrg 8835c4bbdfSmrg /* non-0 if we've created a src clip */ 8935c4bbdfSmrg RegionPtr prgnExposed; 9035c4bbdfSmrg int realSrcClip = 0; 9135c4bbdfSmrg int srcx, srcy, dstx, dsty, i, j, y, width, height, xMin, xMax, yMin, yMax; 9235c4bbdfSmrg unsigned int *ordering; 9335c4bbdfSmrg int numRects; 9435c4bbdfSmrg BoxPtr boxes; 9505b261ecSmrg 9605b261ecSmrg srcx = xIn + pSrcDrawable->x; 9705b261ecSmrg srcy = yIn + pSrcDrawable->y; 9805b261ecSmrg 9905b261ecSmrg /* If the destination isn't realized, this is easy */ 10005b261ecSmrg if (pDstDrawable->type == DRAWABLE_WINDOW && 10135c4bbdfSmrg !((WindowPtr) pDstDrawable)->realized) 10235c4bbdfSmrg return NULL; 10305b261ecSmrg 10405b261ecSmrg /* clip the source */ 10535c4bbdfSmrg if (pSrcDrawable->type == DRAWABLE_PIXMAP) { 10635c4bbdfSmrg BoxRec box; 10705b261ecSmrg 10835c4bbdfSmrg box.x1 = pSrcDrawable->x; 10935c4bbdfSmrg box.y1 = pSrcDrawable->y; 11035c4bbdfSmrg box.x2 = pSrcDrawable->x + (int) pSrcDrawable->width; 11135c4bbdfSmrg box.y2 = pSrcDrawable->y + (int) pSrcDrawable->height; 11205b261ecSmrg 11335c4bbdfSmrg prgnSrcClip = RegionCreate(&box, 1); 11435c4bbdfSmrg realSrcClip = 1; 11505b261ecSmrg } 11635c4bbdfSmrg else { 11735c4bbdfSmrg if (pGC->subWindowMode == IncludeInferiors) { 11835c4bbdfSmrg prgnSrcClip = NotClippedByChildren((WindowPtr) pSrcDrawable); 11935c4bbdfSmrg realSrcClip = 1; 12035c4bbdfSmrg } 12135c4bbdfSmrg else 12235c4bbdfSmrg prgnSrcClip = &((WindowPtr) pSrcDrawable)->clipList; 12305b261ecSmrg } 12405b261ecSmrg 12505b261ecSmrg /* If the src drawable is a window, we need to translate the srcBox so 12605b261ecSmrg * that we can compare it with the window's clip region later on. */ 12705b261ecSmrg srcBox.x1 = srcx; 12805b261ecSmrg srcBox.y1 = srcy; 12935c4bbdfSmrg srcBox.x2 = srcx + widthSrc; 13035c4bbdfSmrg srcBox.y2 = srcy + heightSrc; 13105b261ecSmrg 13205b261ecSmrg dstx = xOut; 13305b261ecSmrg dsty = yOut; 13435c4bbdfSmrg if (pGC->miTranslate) { 13535c4bbdfSmrg dstx += pDstDrawable->x; 13635c4bbdfSmrg dsty += pDstDrawable->y; 13705b261ecSmrg } 13805b261ecSmrg 13935c4bbdfSmrg pptFirst = ppt = xallocarray(heightSrc, sizeof(DDXPointRec)); 14035c4bbdfSmrg pwidthFirst = pwidth = xallocarray(heightSrc, sizeof(unsigned int)); 1416747b715Smrg numRects = RegionNumRects(prgnSrcClip); 1426747b715Smrg boxes = RegionRects(prgnSrcClip); 14335c4bbdfSmrg ordering = xallocarray(numRects, sizeof(unsigned int)); 14435c4bbdfSmrg if (!pptFirst || !pwidthFirst || !ordering) { 14535c4bbdfSmrg free(ordering); 14635c4bbdfSmrg free(pwidthFirst); 14735c4bbdfSmrg free(pptFirst); 14835c4bbdfSmrg return NULL; 14905b261ecSmrg } 15005b261ecSmrg 15105b261ecSmrg /* If not the same drawable then order of move doesn't matter. 15205b261ecSmrg Following assumes that boxes are sorted from top 15305b261ecSmrg to bottom and left to right. 15435c4bbdfSmrg */ 15505b261ecSmrg if ((pSrcDrawable != pDstDrawable) && 15635c4bbdfSmrg ((pGC->subWindowMode != IncludeInferiors) || 15735c4bbdfSmrg (pSrcDrawable->type == DRAWABLE_PIXMAP) || 15835c4bbdfSmrg (pDstDrawable->type == DRAWABLE_PIXMAP))) 15935c4bbdfSmrg for (i = 0; i < numRects; i++) 16005b261ecSmrg ordering[i] = i; 16135c4bbdfSmrg else { /* within same drawable, must sequence moves carefully! */ 16235c4bbdfSmrg if (dsty <= srcBox.y1) { /* Scroll up or stationary vertical. 16335c4bbdfSmrg Vertical order OK */ 16435c4bbdfSmrg if (dstx <= srcBox.x1) /* Scroll left or stationary horizontal. 16535c4bbdfSmrg Horizontal order OK as well */ 16635c4bbdfSmrg for (i = 0; i < numRects; i++) 16735c4bbdfSmrg ordering[i] = i; 16835c4bbdfSmrg else { /* scroll right. must reverse horizontal banding of rects. */ 16935c4bbdfSmrg for (i = 0, j = 1, xMax = 0; i < numRects; j = i + 1, xMax = i) { 17035c4bbdfSmrg /* find extent of current horizontal band */ 17135c4bbdfSmrg y = boxes[i].y1; /* band has this y coordinate */ 17235c4bbdfSmrg while ((j < numRects) && (boxes[j].y1 == y)) 17335c4bbdfSmrg j++; 17435c4bbdfSmrg /* reverse the horizontal band in the output ordering */ 17535c4bbdfSmrg for (j--; j >= xMax; j--, i++) 17635c4bbdfSmrg ordering[i] = j; 17735c4bbdfSmrg } 17835c4bbdfSmrg } 17905b261ecSmrg } 18035c4bbdfSmrg else { /* Scroll down. Must reverse vertical banding. */ 18135c4bbdfSmrg if (dstx < srcBox.x1) { /* Scroll left. Horizontal order OK. */ 18235c4bbdfSmrg for (i = numRects - 1, j = i - 1, yMin = i, yMax = 0; 18335c4bbdfSmrg i >= 0; j = i - 1, yMin = i) { 18435c4bbdfSmrg /* find extent of current horizontal band */ 18535c4bbdfSmrg y = boxes[i].y1; /* band has this y coordinate */ 18635c4bbdfSmrg while ((j >= 0) && (boxes[j].y1 == y)) 18735c4bbdfSmrg j--; 18835c4bbdfSmrg /* reverse the horizontal band in the output ordering */ 18935c4bbdfSmrg for (j++; j <= yMin; j++, i--, yMax++) 19035c4bbdfSmrg ordering[yMax] = j; 19135c4bbdfSmrg } 19235c4bbdfSmrg } 19335c4bbdfSmrg else /* Scroll right or horizontal stationary. 19435c4bbdfSmrg Reverse horizontal order as well (if stationary, horizontal 19535c4bbdfSmrg order can be swapped without penalty and this is faster 19635c4bbdfSmrg to compute). */ 19735c4bbdfSmrg for (i = 0, j = numRects - 1; i < numRects; i++, j--) 19835c4bbdfSmrg ordering[i] = j; 19905b261ecSmrg } 20005b261ecSmrg } 20135c4bbdfSmrg 20235c4bbdfSmrg for (i = 0; i < numRects; i++) { 20305b261ecSmrg prect = &boxes[ordering[i]]; 20435c4bbdfSmrg xMin = max(prect->x1, srcBox.x1); 20535c4bbdfSmrg xMax = min(prect->x2, srcBox.x2); 20635c4bbdfSmrg yMin = max(prect->y1, srcBox.y1); 20735c4bbdfSmrg yMax = min(prect->y2, srcBox.y2); 20835c4bbdfSmrg /* is there anything visible here? */ 20935c4bbdfSmrg if (xMax <= xMin || yMax <= yMin) 21035c4bbdfSmrg continue; 21105b261ecSmrg 21205b261ecSmrg ppt = pptFirst; 21335c4bbdfSmrg pwidth = pwidthFirst; 21435c4bbdfSmrg y = yMin; 21535c4bbdfSmrg height = yMax - yMin; 21635c4bbdfSmrg width = xMax - xMin; 21735c4bbdfSmrg 21835c4bbdfSmrg for (j = 0; j < height; j++) { 21935c4bbdfSmrg /* We must untranslate before calling GetSpans */ 22035c4bbdfSmrg ppt->x = xMin; 22135c4bbdfSmrg ppt++->y = y++; 22235c4bbdfSmrg *pwidth++ = width; 22335c4bbdfSmrg } 22435c4bbdfSmrg pbits = xallocarray(height, PixmapBytePad(width, pSrcDrawable->depth)); 22535c4bbdfSmrg if (pbits) { 22635c4bbdfSmrg (*pSrcDrawable->pScreen->GetSpans) (pSrcDrawable, width, pptFirst, 22735c4bbdfSmrg (int *) pwidthFirst, height, 22835c4bbdfSmrg (char *) pbits); 22935c4bbdfSmrg ppt = pptFirst; 23035c4bbdfSmrg pwidth = pwidthFirst; 23135c4bbdfSmrg xMin -= (srcx - dstx); 23235c4bbdfSmrg y = yMin - (srcy - dsty); 23335c4bbdfSmrg for (j = 0; j < height; j++) { 23435c4bbdfSmrg ppt->x = xMin; 23535c4bbdfSmrg ppt++->y = y++; 23635c4bbdfSmrg *pwidth++ = width; 23735c4bbdfSmrg } 23835c4bbdfSmrg 23935c4bbdfSmrg (*pGC->ops->SetSpans) (pDstDrawable, pGC, (char *) pbits, pptFirst, 24035c4bbdfSmrg (int *) pwidthFirst, height, TRUE); 24135c4bbdfSmrg free(pbits); 24235c4bbdfSmrg } 24305b261ecSmrg } 24405b261ecSmrg prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC, xIn, yIn, 24535c4bbdfSmrg widthSrc, heightSrc, xOut, yOut); 24635c4bbdfSmrg if (realSrcClip) 24735c4bbdfSmrg RegionDestroy(prgnSrcClip); 24835c4bbdfSmrg 2496747b715Smrg free(ordering); 2506747b715Smrg free(pwidthFirst); 2516747b715Smrg free(pptFirst); 25205b261ecSmrg return prgnExposed; 25305b261ecSmrg} 25405b261ecSmrg 25505b261ecSmrg/* MIGETPLANE -- gets a bitmap representing one plane of pDraw 25635c4bbdfSmrg * A helper used for CopyPlane and XY format GetImage 25705b261ecSmrg * No clever strategy here, we grab a scanline at a time, pull out the 25805b261ecSmrg * bits and then stuff them in a 1 bit deep map. 25905b261ecSmrg */ 26005b261ecSmrg/* 26105b261ecSmrg * This should be replaced with something more general. mi shouldn't have to 26205b261ecSmrg * care about such things as scanline padding et alia. 26305b261ecSmrg */ 26435c4bbdfSmrg_X_COLD static MiBits * 26535c4bbdfSmrgmiGetPlane(DrawablePtr pDraw, int planeNum, /* number of the bitPlane */ 26635c4bbdfSmrg int sx, int sy, int w, int h, MiBits * result) 26705b261ecSmrg{ 26835c4bbdfSmrg int i, j, k, width, bitsPerPixel, widthInBytes; 26935c4bbdfSmrg DDXPointRec pt = { 0, 0 }; 27035c4bbdfSmrg MiBits pixel; 27135c4bbdfSmrg MiBits bit; 27235c4bbdfSmrg unsigned char *pCharsOut = NULL; 27305b261ecSmrg 27405b261ecSmrg#if BITMAP_SCANLINE_UNIT == 8 27505b261ecSmrg#define OUT_TYPE unsigned char 27605b261ecSmrg#endif 27705b261ecSmrg#if BITMAP_SCANLINE_UNIT == 16 27805b261ecSmrg#define OUT_TYPE CARD16 27905b261ecSmrg#endif 28005b261ecSmrg#if BITMAP_SCANLINE_UNIT == 32 28105b261ecSmrg#define OUT_TYPE CARD32 28205b261ecSmrg#endif 28305b261ecSmrg#if BITMAP_SCANLINE_UNIT == 64 28405b261ecSmrg#define OUT_TYPE CARD64 28505b261ecSmrg#endif 28605b261ecSmrg 28735c4bbdfSmrg OUT_TYPE *pOut; 28835c4bbdfSmrg int delta = 0; 28905b261ecSmrg 29005b261ecSmrg sx += pDraw->x; 29105b261ecSmrg sy += pDraw->y; 29205b261ecSmrg widthInBytes = BitmapBytePad(w); 29335c4bbdfSmrg if (!result) 2946747b715Smrg result = calloc(h, widthInBytes); 29505b261ecSmrg if (!result) 29635c4bbdfSmrg return NULL; 29705b261ecSmrg bitsPerPixel = pDraw->bitsPerPixel; 29805b261ecSmrg pOut = (OUT_TYPE *) result; 29935c4bbdfSmrg if (bitsPerPixel == 1) { 30035c4bbdfSmrg pCharsOut = (unsigned char *) result; 30135c4bbdfSmrg width = w; 30205b261ecSmrg } 30335c4bbdfSmrg else { 30435c4bbdfSmrg delta = (widthInBytes / (BITMAP_SCANLINE_UNIT / 8)) - 30535c4bbdfSmrg (w / BITMAP_SCANLINE_UNIT); 30635c4bbdfSmrg width = 1; 30705b261ecSmrg#if IMAGE_BYTE_ORDER == MSBFirst 30835c4bbdfSmrg planeNum += (32 - bitsPerPixel); 30905b261ecSmrg#endif 31005b261ecSmrg } 31105b261ecSmrg pt.y = sy; 31235c4bbdfSmrg for (i = h; --i >= 0; pt.y++) { 31335c4bbdfSmrg pt.x = sx; 31435c4bbdfSmrg if (bitsPerPixel == 1) { 31535c4bbdfSmrg (*pDraw->pScreen->GetSpans) (pDraw, width, &pt, &width, 1, 31635c4bbdfSmrg (char *) pCharsOut); 31735c4bbdfSmrg pCharsOut += widthInBytes; 31835c4bbdfSmrg } 31935c4bbdfSmrg else { 32035c4bbdfSmrg k = 0; 32135c4bbdfSmrg for (j = w; --j >= 0; pt.x++) { 32235c4bbdfSmrg /* Fetch the next pixel */ 32335c4bbdfSmrg (*pDraw->pScreen->GetSpans) (pDraw, width, &pt, &width, 1, 32435c4bbdfSmrg (char *) &pixel); 32535c4bbdfSmrg /* 32635c4bbdfSmrg * Now get the bit and insert into a bitmap in XY format. 32735c4bbdfSmrg */ 32835c4bbdfSmrg bit = (pixel >> planeNum) & 1; 32905b261ecSmrg#if 0 33035c4bbdfSmrg /* XXX assuming bit order == byte order */ 33105b261ecSmrg#if BITMAP_BIT_ORDER == LSBFirst 33235c4bbdfSmrg bit <<= k; 33305b261ecSmrg#else 33435c4bbdfSmrg bit <<= ((BITMAP_SCANLINE_UNIT - 1) - k); 33505b261ecSmrg#endif 33605b261ecSmrg#else 33735c4bbdfSmrg /* XXX assuming byte order == LSBFirst */ 33835c4bbdfSmrg if (screenInfo.bitmapBitOrder == LSBFirst) 33935c4bbdfSmrg bit <<= k; 34035c4bbdfSmrg else 34135c4bbdfSmrg bit <<= ((screenInfo.bitmapScanlineUnit - 1) - 34235c4bbdfSmrg (k % screenInfo.bitmapScanlineUnit)) + 34335c4bbdfSmrg ((k / screenInfo.bitmapScanlineUnit) * 34435c4bbdfSmrg screenInfo.bitmapScanlineUnit); 34505b261ecSmrg#endif 34635c4bbdfSmrg *pOut |= (OUT_TYPE) bit; 34735c4bbdfSmrg k++; 34835c4bbdfSmrg if (k == BITMAP_SCANLINE_UNIT) { 34935c4bbdfSmrg pOut++; 35035c4bbdfSmrg k = 0; 35135c4bbdfSmrg } 35235c4bbdfSmrg } 35335c4bbdfSmrg pOut += delta; 35435c4bbdfSmrg } 35505b261ecSmrg } 3566747b715Smrg return result; 35705b261ecSmrg 35805b261ecSmrg} 35905b261ecSmrg 36005b261ecSmrg/* MIOPQSTIPDRAWABLE -- use pbits as an opaque stipple for pDraw. 36135c4bbdfSmrg * Drawing through the clip mask we SetSpans() the bits into a 36205b261ecSmrg * bitmap and stipple those bits onto the destination drawable by doing a 36335c4bbdfSmrg * PolyFillRect over the whole drawable, 36405b261ecSmrg * then we invert the bitmap by copying it onto itself with an alu of 36505b261ecSmrg * GXinvert, invert the foreground/background colors of the gc, and draw 36605b261ecSmrg * the background bits. 36705b261ecSmrg * Note how the clipped out bits of the bitmap are always the background 36805b261ecSmrg * color so that the stipple never causes FillRect to draw them. 36905b261ecSmrg */ 37035c4bbdfSmrg_X_COLD static void 37105b261ecSmrgmiOpqStipDrawable(DrawablePtr pDraw, GCPtr pGC, RegionPtr prgnSrc, 37235c4bbdfSmrg MiBits * pbits, int srcx, int w, int h, int dstx, int dsty) 37305b261ecSmrg{ 37435c4bbdfSmrg int oldfill, i; 37505b261ecSmrg unsigned long oldfg; 37635c4bbdfSmrg int *pwidth, *pwidthFirst; 37735c4bbdfSmrg ChangeGCVal gcv[6]; 37835c4bbdfSmrg PixmapPtr pStipple, pPixmap; 37935c4bbdfSmrg DDXPointRec oldOrg; 38035c4bbdfSmrg GCPtr pGCT; 38105b261ecSmrg DDXPointPtr ppt, pptFirst; 38205b261ecSmrg xRectangle rect; 38335c4bbdfSmrg RegionPtr prgnSrcClip; 38405b261ecSmrg 38505b261ecSmrg pPixmap = (*pDraw->pScreen->CreatePixmap) 38635c4bbdfSmrg (pDraw->pScreen, w + srcx, h, 1, CREATE_PIXMAP_USAGE_SCRATCH); 38705b261ecSmrg if (!pPixmap) 38835c4bbdfSmrg return; 38905b261ecSmrg 39005b261ecSmrg /* Put the image into a 1 bit deep pixmap */ 39105b261ecSmrg pGCT = GetScratchGC(1, pDraw->pScreen); 39235c4bbdfSmrg if (!pGCT) { 39335c4bbdfSmrg (*pDraw->pScreen->DestroyPixmap) (pPixmap); 39435c4bbdfSmrg return; 39505b261ecSmrg } 39605b261ecSmrg /* First set the whole pixmap to 0 */ 39705b261ecSmrg gcv[0].val = 0; 3986747b715Smrg ChangeGC(NullClient, pGCT, GCBackground, gcv); 39935c4bbdfSmrg ValidateGC((DrawablePtr) pPixmap, pGCT); 40035c4bbdfSmrg miClearDrawable((DrawablePtr) pPixmap, pGCT); 40135c4bbdfSmrg ppt = pptFirst = xallocarray(h, sizeof(DDXPointRec)); 40235c4bbdfSmrg pwidth = pwidthFirst = xallocarray(h, sizeof(int)); 40335c4bbdfSmrg if (!pptFirst || !pwidthFirst) { 40435c4bbdfSmrg free(pwidthFirst); 40535c4bbdfSmrg free(pptFirst); 40635c4bbdfSmrg FreeScratchGC(pGCT); 40735c4bbdfSmrg return; 40805b261ecSmrg } 40905b261ecSmrg 41005b261ecSmrg /* we need a temporary region because ChangeClip must be assumed 41105b261ecSmrg to destroy what it's sent. note that this means we don't 41205b261ecSmrg have to free prgnSrcClip ourselves. 41335c4bbdfSmrg */ 4146747b715Smrg prgnSrcClip = RegionCreate(NULL, 0); 4156747b715Smrg RegionCopy(prgnSrcClip, prgnSrc); 4166747b715Smrg RegionTranslate(prgnSrcClip, srcx, 0); 41735c4bbdfSmrg (*pGCT->funcs->ChangeClip) (pGCT, CT_REGION, prgnSrcClip, 0); 41835c4bbdfSmrg ValidateGC((DrawablePtr) pPixmap, pGCT); 41905b261ecSmrg 42005b261ecSmrg /* Since we know pDraw is always a pixmap, we never need to think 42105b261ecSmrg * about translation here */ 42235c4bbdfSmrg for (i = 0; i < h; i++) { 42335c4bbdfSmrg ppt->x = 0; 42435c4bbdfSmrg ppt++->y = i; 42535c4bbdfSmrg *pwidth++ = w + srcx; 42605b261ecSmrg } 42705b261ecSmrg 42835c4bbdfSmrg (*pGCT->ops->SetSpans) ((DrawablePtr) pPixmap, pGCT, (char *) pbits, 42935c4bbdfSmrg pptFirst, pwidthFirst, h, TRUE); 4306747b715Smrg free(pwidthFirst); 4316747b715Smrg free(pptFirst); 43205b261ecSmrg 43305b261ecSmrg /* Save current values from the client GC */ 43405b261ecSmrg oldfill = pGC->fillStyle; 43505b261ecSmrg pStipple = pGC->stipple; 43635c4bbdfSmrg if (pStipple) 43705b261ecSmrg pStipple->refcnt++; 43805b261ecSmrg oldOrg = pGC->patOrg; 43905b261ecSmrg 44005b261ecSmrg /* Set a new stipple in the drawable */ 44105b261ecSmrg gcv[0].val = FillStippled; 44205b261ecSmrg gcv[1].ptr = pPixmap; 44305b261ecSmrg gcv[2].val = dstx - srcx; 44405b261ecSmrg gcv[3].val = dsty; 44505b261ecSmrg 4466747b715Smrg ChangeGC(NullClient, pGC, 44705b261ecSmrg GCFillStyle | GCStipple | GCTileStipXOrigin | GCTileStipYOrigin, 44835c4bbdfSmrg gcv); 44905b261ecSmrg ValidateGC(pDraw, pGC); 45005b261ecSmrg 45105b261ecSmrg /* Fill the drawable with the stipple. This will draw the 45205b261ecSmrg * foreground color whereever 1 bits are set, leaving everything 45305b261ecSmrg * with 0 bits untouched. Note that the part outside the clip 45405b261ecSmrg * region is all 0s. */ 45505b261ecSmrg rect.x = dstx; 45605b261ecSmrg rect.y = dsty; 45705b261ecSmrg rect.width = w; 45805b261ecSmrg rect.height = h; 45935c4bbdfSmrg (*pGC->ops->PolyFillRect) (pDraw, pGC, 1, &rect); 46005b261ecSmrg 46105b261ecSmrg /* Invert the tiling pixmap. This sets 0s for 1s and 1s for 0s, only 46205b261ecSmrg * within the clipping region, the part outside is still all 0s */ 46305b261ecSmrg gcv[0].val = GXinvert; 4646747b715Smrg ChangeGC(NullClient, pGCT, GCFunction, gcv); 46535c4bbdfSmrg ValidateGC((DrawablePtr) pPixmap, pGCT); 46635c4bbdfSmrg (*pGCT->ops->CopyArea) ((DrawablePtr) pPixmap, (DrawablePtr) pPixmap, 46735c4bbdfSmrg pGCT, 0, 0, w + srcx, h, 0, 0); 46805b261ecSmrg 46905b261ecSmrg /* Swap foreground and background colors on the GC for the drawable. 47005b261ecSmrg * Now when we fill the drawable, we will fill in the "Background" 47105b261ecSmrg * values */ 47205b261ecSmrg oldfg = pGC->fgPixel; 47305b261ecSmrg gcv[0].val = pGC->bgPixel; 47405b261ecSmrg gcv[1].val = oldfg; 47505b261ecSmrg gcv[2].ptr = pPixmap; 4766747b715Smrg ChangeGC(NullClient, pGC, GCForeground | GCBackground | GCStipple, gcv); 47705b261ecSmrg ValidateGC(pDraw, pGC); 47805b261ecSmrg /* PolyFillRect might have bashed the rectangle */ 47905b261ecSmrg rect.x = dstx; 48005b261ecSmrg rect.y = dsty; 48105b261ecSmrg rect.width = w; 48205b261ecSmrg rect.height = h; 48335c4bbdfSmrg (*pGC->ops->PolyFillRect) (pDraw, pGC, 1, &rect); 48405b261ecSmrg 48505b261ecSmrg /* Now put things back */ 48635c4bbdfSmrg if (pStipple) 48705b261ecSmrg pStipple->refcnt--; 48805b261ecSmrg gcv[0].val = oldfg; 48905b261ecSmrg gcv[1].val = pGC->fgPixel; 49005b261ecSmrg gcv[2].val = oldfill; 49105b261ecSmrg gcv[3].ptr = pStipple; 49205b261ecSmrg gcv[4].val = oldOrg.x; 49305b261ecSmrg gcv[5].val = oldOrg.y; 4946747b715Smrg ChangeGC(NullClient, pGC, 49535c4bbdfSmrg GCForeground | GCBackground | GCFillStyle | GCStipple | 49635c4bbdfSmrg GCTileStipXOrigin | GCTileStipYOrigin, gcv); 49705b261ecSmrg 49805b261ecSmrg ValidateGC(pDraw, pGC); 49905b261ecSmrg /* put what we hope is a smaller clip region back in the scratch gc */ 50035c4bbdfSmrg (*pGCT->funcs->ChangeClip) (pGCT, CT_NONE, NULL, 0); 50105b261ecSmrg FreeScratchGC(pGCT); 50235c4bbdfSmrg (*pDraw->pScreen->DestroyPixmap) (pPixmap); 50305b261ecSmrg 50405b261ecSmrg} 50505b261ecSmrg 50605b261ecSmrg/* MICOPYPLANE -- public entry for the CopyPlane request. 50735c4bbdfSmrg * strategy: 50835c4bbdfSmrg * First build up a bitmap out of the bits requested 50905b261ecSmrg * build a source clip 51035c4bbdfSmrg * Use the bitmap we've built up as a Stipple for the destination 51105b261ecSmrg */ 51235c4bbdfSmrg_X_COLD RegionPtr 51335c4bbdfSmrgmiCopyPlane(DrawablePtr pSrcDrawable, 51435c4bbdfSmrg DrawablePtr pDstDrawable, 51535c4bbdfSmrg GCPtr pGC, 51635c4bbdfSmrg int srcx, 51735c4bbdfSmrg int srcy, 51835c4bbdfSmrg int width, int height, int dstx, int dsty, unsigned long bitPlane) 51905b261ecSmrg{ 52035c4bbdfSmrg MiBits *ptile; 52135c4bbdfSmrg BoxRec box; 52235c4bbdfSmrg RegionPtr prgnSrc, prgnExposed; 52305b261ecSmrg 52405b261ecSmrg /* incorporate the source clip */ 52505b261ecSmrg 52605b261ecSmrg box.x1 = srcx + pSrcDrawable->x; 52705b261ecSmrg box.y1 = srcy + pSrcDrawable->y; 52805b261ecSmrg box.x2 = box.x1 + width; 52905b261ecSmrg box.y2 = box.y1 + height; 53005b261ecSmrg /* clip to visible drawable */ 53105b261ecSmrg if (box.x1 < pSrcDrawable->x) 53235c4bbdfSmrg box.x1 = pSrcDrawable->x; 53305b261ecSmrg if (box.y1 < pSrcDrawable->y) 53435c4bbdfSmrg box.y1 = pSrcDrawable->y; 53505b261ecSmrg if (box.x2 > pSrcDrawable->x + (int) pSrcDrawable->width) 53635c4bbdfSmrg box.x2 = pSrcDrawable->x + (int) pSrcDrawable->width; 53705b261ecSmrg if (box.y2 > pSrcDrawable->y + (int) pSrcDrawable->height) 53835c4bbdfSmrg box.y2 = pSrcDrawable->y + (int) pSrcDrawable->height; 53905b261ecSmrg if (box.x1 > box.x2) 54035c4bbdfSmrg box.x2 = box.x1; 54105b261ecSmrg if (box.y1 > box.y2) 54235c4bbdfSmrg box.y2 = box.y1; 5436747b715Smrg prgnSrc = RegionCreate(&box, 1); 54405b261ecSmrg 54505b261ecSmrg if (pSrcDrawable->type != DRAWABLE_PIXMAP) { 54635c4bbdfSmrg /* clip to visible drawable */ 54735c4bbdfSmrg 54835c4bbdfSmrg if (pGC->subWindowMode == IncludeInferiors) { 54935c4bbdfSmrg RegionPtr clipList = NotClippedByChildren((WindowPtr) pSrcDrawable); 55035c4bbdfSmrg 55135c4bbdfSmrg RegionIntersect(prgnSrc, prgnSrc, clipList); 55235c4bbdfSmrg RegionDestroy(clipList); 55335c4bbdfSmrg } 55435c4bbdfSmrg else 55535c4bbdfSmrg RegionIntersect(prgnSrc, prgnSrc, 55635c4bbdfSmrg &((WindowPtr) pSrcDrawable)->clipList); 55705b261ecSmrg } 55805b261ecSmrg 5596747b715Smrg box = *RegionExtents(prgnSrc); 5606747b715Smrg RegionTranslate(prgnSrc, -box.x1, -box.y1); 56105b261ecSmrg 56235c4bbdfSmrg if ((box.x2 > box.x1) && (box.y2 > box.y1)) { 56335c4bbdfSmrg /* minimize the size of the data extracted */ 56435c4bbdfSmrg /* note that we convert the plane mask bitPlane into a plane number */ 56535c4bbdfSmrg box.x1 -= pSrcDrawable->x; 56635c4bbdfSmrg box.x2 -= pSrcDrawable->x; 56735c4bbdfSmrg box.y1 -= pSrcDrawable->y; 56835c4bbdfSmrg box.y2 -= pSrcDrawable->y; 56935c4bbdfSmrg ptile = miGetPlane(pSrcDrawable, ffs(bitPlane) - 1, 57035c4bbdfSmrg box.x1, box.y1, 57135c4bbdfSmrg box.x2 - box.x1, box.y2 - box.y1, (MiBits *) NULL); 57235c4bbdfSmrg if (ptile) { 57335c4bbdfSmrg miOpqStipDrawable(pDstDrawable, pGC, prgnSrc, ptile, 0, 57435c4bbdfSmrg box.x2 - box.x1, box.y2 - box.y1, 57535c4bbdfSmrg dstx + box.x1 - srcx, dsty + box.y1 - srcy); 57635c4bbdfSmrg free(ptile); 57735c4bbdfSmrg } 57805b261ecSmrg } 57905b261ecSmrg prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC, srcx, srcy, 58035c4bbdfSmrg width, height, dstx, dsty); 5816747b715Smrg RegionDestroy(prgnSrc); 58205b261ecSmrg return prgnExposed; 58305b261ecSmrg} 58405b261ecSmrg 58505b261ecSmrg/* MIGETIMAGE -- public entry for the GetImage Request 58605b261ecSmrg * We're getting the image into a memory buffer. While we have to use GetSpans 58705b261ecSmrg * to read a line from the device (since we don't know what that looks like), 58805b261ecSmrg * we can just write into the destination buffer 58905b261ecSmrg * 59005b261ecSmrg * two different strategies are used, depending on whether we're getting the 59105b261ecSmrg * image in Z format or XY format 59205b261ecSmrg * Z format: 59305b261ecSmrg * Line at a time, GetSpans a line into the destination buffer, then if the 59405b261ecSmrg * planemask is not all ones, we do a SetSpans into a temporary buffer (to get 59505b261ecSmrg * bits turned off) and then another GetSpans to get stuff back (because 59605b261ecSmrg * pixmaps are opaque, and we are passed in the memory to write into). This is 59705b261ecSmrg * pretty ugly and slow but works. Life is hard. 59805b261ecSmrg * XY format: 59905b261ecSmrg * get the single plane specified in planemask 60005b261ecSmrg */ 60135c4bbdfSmrg_X_COLD void 60235c4bbdfSmrgmiGetImage(DrawablePtr pDraw, int sx, int sy, int w, int h, 60335c4bbdfSmrg unsigned int format, unsigned long planeMask, char *pDst) 60405b261ecSmrg{ 60535c4bbdfSmrg unsigned char depth; 60635c4bbdfSmrg int i, linelength, width, srcx, srcy; 60735c4bbdfSmrg DDXPointRec pt = { 0, 0 }; 60835c4bbdfSmrg PixmapPtr pPixmap = NULL; 60935c4bbdfSmrg GCPtr pGC = NULL; 61005b261ecSmrg 61105b261ecSmrg depth = pDraw->depth; 61235c4bbdfSmrg if (format == ZPixmap) { 61335c4bbdfSmrg if ((((1LL << depth) - 1) & planeMask) != (1LL << depth) - 1) { 61435c4bbdfSmrg ChangeGCVal gcv; 61535c4bbdfSmrg xPoint xpt; 61635c4bbdfSmrg 61735c4bbdfSmrg pGC = GetScratchGC(depth, pDraw->pScreen); 61835c4bbdfSmrg if (!pGC) 61935c4bbdfSmrg return; 62005b261ecSmrg pPixmap = (*pDraw->pScreen->CreatePixmap) 62135c4bbdfSmrg (pDraw->pScreen, w, 1, depth, CREATE_PIXMAP_USAGE_SCRATCH); 62235c4bbdfSmrg if (!pPixmap) { 62335c4bbdfSmrg FreeScratchGC(pGC); 62435c4bbdfSmrg return; 62535c4bbdfSmrg } 62635c4bbdfSmrg /* 62735c4bbdfSmrg * Clear the pixmap before doing anything else 62835c4bbdfSmrg */ 62935c4bbdfSmrg ValidateGC((DrawablePtr) pPixmap, pGC); 63035c4bbdfSmrg xpt.x = xpt.y = 0; 63105b261ecSmrg width = w; 63235c4bbdfSmrg (*pGC->ops->FillSpans) ((DrawablePtr) pPixmap, pGC, 1, &xpt, &width, 63335c4bbdfSmrg TRUE); 63435c4bbdfSmrg 63535c4bbdfSmrg /* alu is already GXCopy */ 63635c4bbdfSmrg gcv.val = (XID) planeMask; 63735c4bbdfSmrg ChangeGC(NullClient, pGC, GCPlaneMask, &gcv); 63835c4bbdfSmrg ValidateGC((DrawablePtr) pPixmap, pGC); 63935c4bbdfSmrg } 64005b261ecSmrg 64105b261ecSmrg linelength = PixmapBytePad(w, depth); 64235c4bbdfSmrg srcx = sx + pDraw->x; 64335c4bbdfSmrg srcy = sy + pDraw->y; 64435c4bbdfSmrg for (i = 0; i < h; i++) { 64535c4bbdfSmrg pt.x = srcx; 64635c4bbdfSmrg pt.y = srcy + i; 64735c4bbdfSmrg width = w; 64835c4bbdfSmrg (*pDraw->pScreen->GetSpans) (pDraw, w, &pt, &width, 1, pDst); 64935c4bbdfSmrg if (pPixmap) { 65035c4bbdfSmrg pt.x = 0; 65135c4bbdfSmrg pt.y = 0; 65235c4bbdfSmrg width = w; 65335c4bbdfSmrg (*pGC->ops->SetSpans) ((DrawablePtr) pPixmap, pGC, pDst, 65435c4bbdfSmrg &pt, &width, 1, TRUE); 65535c4bbdfSmrg (*pDraw->pScreen->GetSpans) ((DrawablePtr) pPixmap, w, &pt, 65635c4bbdfSmrg &width, 1, pDst); 65735c4bbdfSmrg } 65835c4bbdfSmrg pDst += linelength; 65935c4bbdfSmrg } 66035c4bbdfSmrg if (pPixmap) { 66135c4bbdfSmrg (*pGC->pScreen->DestroyPixmap) (pPixmap); 66235c4bbdfSmrg FreeScratchGC(pGC); 66335c4bbdfSmrg } 66405b261ecSmrg } 66535c4bbdfSmrg else { 66635c4bbdfSmrg (void) miGetPlane(pDraw, ffs(planeMask) - 1, sx, sy, w, h, 66735c4bbdfSmrg (MiBits *) pDst); 66805b261ecSmrg } 66905b261ecSmrg} 67005b261ecSmrg 67105b261ecSmrg/* MIPUTIMAGE -- public entry for the PutImage request 67205b261ecSmrg * Here we benefit from knowing the format of the bits pointed to by pImage, 67335c4bbdfSmrg * even if we don't know how pDraw represents them. 67435c4bbdfSmrg * Three different strategies are used depending on the format 67505b261ecSmrg * XYBitmap Format: 67605b261ecSmrg * we just use the Opaque Stipple helper function to cover the destination 67735c4bbdfSmrg * Note that this covers all the planes of the drawable with the 67805b261ecSmrg * foreground color (masked with the GC planemask) where there are 1 bits 67905b261ecSmrg * and the background color (masked with the GC planemask) where there are 68005b261ecSmrg * 0 bits 68105b261ecSmrg * XYPixmap format: 68235c4bbdfSmrg * what we're called with is a series of XYBitmaps, but we only want 68305b261ecSmrg * each XYPixmap to update 1 plane, instead of updating all of them. 68405b261ecSmrg * we set the foreground color to be all 1s and the background to all 0s 68505b261ecSmrg * then for each plane, we set the plane mask to only effect that one 68605b261ecSmrg * plane and recursive call ourself with the format set to XYBitmap 68705b261ecSmrg * (This clever idea courtesy of RGD.) 68805b261ecSmrg * ZPixmap format: 68905b261ecSmrg * This part is simple, just call SetSpans 69005b261ecSmrg */ 69135c4bbdfSmrg_X_COLD void 69235c4bbdfSmrgmiPutImage(DrawablePtr pDraw, GCPtr pGC, int depth, 69335c4bbdfSmrg int x, int y, int w, int h, int leftPad, int format, char *pImage) 69405b261ecSmrg{ 69535c4bbdfSmrg DDXPointPtr pptFirst, ppt; 69635c4bbdfSmrg int *pwidthFirst, *pwidth; 69735c4bbdfSmrg RegionPtr prgnSrc; 69835c4bbdfSmrg BoxRec box; 69935c4bbdfSmrg unsigned long oldFg, oldBg; 70035c4bbdfSmrg ChangeGCVal gcv[3]; 70135c4bbdfSmrg unsigned long oldPlanemask; 70235c4bbdfSmrg unsigned long i; 70335c4bbdfSmrg long bytesPer; 70405b261ecSmrg 70505b261ecSmrg if (!w || !h) 70635c4bbdfSmrg return; 70735c4bbdfSmrg switch (format) { 70835c4bbdfSmrg case XYBitmap: 70905b261ecSmrg 71035c4bbdfSmrg box.x1 = 0; 71135c4bbdfSmrg box.y1 = 0; 71235c4bbdfSmrg box.x2 = w; 71335c4bbdfSmrg box.y2 = h; 71435c4bbdfSmrg prgnSrc = RegionCreate(&box, 1); 71505b261ecSmrg 71605b261ecSmrg miOpqStipDrawable(pDraw, pGC, prgnSrc, (MiBits *) pImage, 71735c4bbdfSmrg leftPad, w, h, x, y); 71835c4bbdfSmrg RegionDestroy(prgnSrc); 71935c4bbdfSmrg break; 72035c4bbdfSmrg 72135c4bbdfSmrg case XYPixmap: 72235c4bbdfSmrg depth = pGC->depth; 72335c4bbdfSmrg oldPlanemask = pGC->planemask; 72435c4bbdfSmrg oldFg = pGC->fgPixel; 72535c4bbdfSmrg oldBg = pGC->bgPixel; 72635c4bbdfSmrg gcv[0].val = (XID) ~0; 72735c4bbdfSmrg gcv[1].val = (XID) 0; 72835c4bbdfSmrg ChangeGC(NullClient, pGC, GCForeground | GCBackground, gcv); 72935c4bbdfSmrg bytesPer = (long) h *BitmapBytePad(w + leftPad); 73035c4bbdfSmrg 73135c4bbdfSmrg for (i = (unsigned long) 1 << (depth - 1); i != 0; i >>= 1, pImage += bytesPer) { 73235c4bbdfSmrg if (i & oldPlanemask) { 73335c4bbdfSmrg gcv[0].val = (XID) i; 73435c4bbdfSmrg ChangeGC(NullClient, pGC, GCPlaneMask, gcv); 73535c4bbdfSmrg ValidateGC(pDraw, pGC); 73635c4bbdfSmrg (*pGC->ops->PutImage) (pDraw, pGC, 1, x, y, w, h, leftPad, 73735c4bbdfSmrg XYBitmap, (char *) pImage); 73835c4bbdfSmrg } 73935c4bbdfSmrg } 74035c4bbdfSmrg gcv[0].val = (XID) oldPlanemask; 74135c4bbdfSmrg gcv[1].val = (XID) oldFg; 74235c4bbdfSmrg gcv[2].val = (XID) oldBg; 74335c4bbdfSmrg ChangeGC(NullClient, pGC, GCPlaneMask | GCForeground | GCBackground, 74435c4bbdfSmrg gcv); 74535c4bbdfSmrg ValidateGC(pDraw, pGC); 74635c4bbdfSmrg break; 74735c4bbdfSmrg 74835c4bbdfSmrg case ZPixmap: 74935c4bbdfSmrg ppt = pptFirst = xallocarray(h, sizeof(DDXPointRec)); 75035c4bbdfSmrg pwidth = pwidthFirst = xallocarray(h, sizeof(int)); 75135c4bbdfSmrg if (!pptFirst || !pwidthFirst) { 75235c4bbdfSmrg free(pwidthFirst); 75335c4bbdfSmrg free(pptFirst); 75435c4bbdfSmrg return; 75535c4bbdfSmrg } 75635c4bbdfSmrg if (pGC->miTranslate) { 75735c4bbdfSmrg x += pDraw->x; 75835c4bbdfSmrg y += pDraw->y; 75905b261ecSmrg } 76035c4bbdfSmrg 76135c4bbdfSmrg for (i = 0; i < h; i++) { 76235c4bbdfSmrg ppt->x = x; 76335c4bbdfSmrg ppt->y = y + i; 76435c4bbdfSmrg ppt++; 76535c4bbdfSmrg *pwidth++ = w; 76635c4bbdfSmrg } 76735c4bbdfSmrg 76835c4bbdfSmrg (*pGC->ops->SetSpans) (pDraw, pGC, (char *) pImage, pptFirst, 76935c4bbdfSmrg pwidthFirst, h, TRUE); 77035c4bbdfSmrg free(pwidthFirst); 77135c4bbdfSmrg free(pptFirst); 77235c4bbdfSmrg break; 77305b261ecSmrg } 77405b261ecSmrg} 775