mibitblt.c revision 4642e01f
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) 10705b261ecSmrg return (RegionPtr)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 11905b261ecSmrg prgnSrcClip = REGION_CREATE(pGC->pScreen, &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 14605b261ecSmrg pptFirst = ppt = (DDXPointPtr) 1474642e01fSmrg xalloc(heightSrc * sizeof(DDXPointRec)); 14805b261ecSmrg pwidthFirst = pwidth = (unsigned int *) 1494642e01fSmrg xalloc(heightSrc * sizeof(unsigned int)); 15005b261ecSmrg numRects = REGION_NUM_RECTS(prgnSrcClip); 15105b261ecSmrg boxes = REGION_RECTS(prgnSrcClip); 15205b261ecSmrg ordering = (unsigned int *) 1534642e01fSmrg xalloc(numRects * sizeof(unsigned int)); 15405b261ecSmrg if(!pptFirst || !pwidthFirst || !ordering) 15505b261ecSmrg { 15605b261ecSmrg if (ordering) 1574642e01fSmrg xfree(ordering); 15805b261ecSmrg if (pwidthFirst) 1594642e01fSmrg xfree(pwidthFirst); 16005b261ecSmrg if (pptFirst) 1614642e01fSmrg xfree(pptFirst); 16205b261ecSmrg return (RegionPtr)NULL; 16305b261ecSmrg } 16405b261ecSmrg 16505b261ecSmrg /* If not the same drawable then order of move doesn't matter. 16605b261ecSmrg Following assumes that boxes are sorted from top 16705b261ecSmrg to bottom and left to right. 16805b261ecSmrg */ 16905b261ecSmrg if ((pSrcDrawable != pDstDrawable) && 17005b261ecSmrg ((pGC->subWindowMode != IncludeInferiors) || 17105b261ecSmrg (pSrcDrawable->type == DRAWABLE_PIXMAP) || 17205b261ecSmrg (pDstDrawable->type == DRAWABLE_PIXMAP))) 17305b261ecSmrg for (i=0; i < numRects; i++) 17405b261ecSmrg ordering[i] = i; 17505b261ecSmrg else { /* within same drawable, must sequence moves carefully! */ 17605b261ecSmrg if (dsty <= srcBox.y1) { /* Scroll up or stationary vertical. 17705b261ecSmrg Vertical order OK */ 17805b261ecSmrg if (dstx <= srcBox.x1) /* Scroll left or stationary horizontal. 17905b261ecSmrg Horizontal order OK as well */ 18005b261ecSmrg for (i=0; i < numRects; i++) 18105b261ecSmrg ordering[i] = i; 18205b261ecSmrg else { /* scroll right. must reverse horizontal banding of rects. */ 18305b261ecSmrg for (i=0, j=1, xMax=0; i < numRects; j=i+1, xMax=i) { 18405b261ecSmrg /* find extent of current horizontal band */ 18505b261ecSmrg y=boxes[i].y1; /* band has this y coordinate */ 18605b261ecSmrg while ((j < numRects) && (boxes[j].y1 == y)) 18705b261ecSmrg j++; 18805b261ecSmrg /* reverse the horizontal band in the output ordering */ 18905b261ecSmrg for (j-- ; j >= xMax; j--, i++) 19005b261ecSmrg ordering[i] = j; 19105b261ecSmrg } 19205b261ecSmrg } 19305b261ecSmrg } 19405b261ecSmrg else { /* Scroll down. Must reverse vertical banding. */ 19505b261ecSmrg if (dstx < srcBox.x1) { /* Scroll left. Horizontal order OK. */ 19605b261ecSmrg for (i=numRects-1, j=i-1, yMin=i, yMax=0; 19705b261ecSmrg i >= 0; 19805b261ecSmrg j=i-1, yMin=i) { 19905b261ecSmrg /* find extent of current horizontal band */ 20005b261ecSmrg y=boxes[i].y1; /* band has this y coordinate */ 20105b261ecSmrg while ((j >= 0) && (boxes[j].y1 == y)) 20205b261ecSmrg j--; 20305b261ecSmrg /* reverse the horizontal band in the output ordering */ 20405b261ecSmrg for (j++ ; j <= yMin; j++, i--, yMax++) 20505b261ecSmrg ordering[yMax] = j; 20605b261ecSmrg } 20705b261ecSmrg } 20805b261ecSmrg else /* Scroll right or horizontal stationary. 20905b261ecSmrg Reverse horizontal order as well (if stationary, horizontal 21005b261ecSmrg order can be swapped without penalty and this is faster 21105b261ecSmrg to compute). */ 21205b261ecSmrg for (i=0, j=numRects-1; i < numRects; i++, j--) 21305b261ecSmrg ordering[i] = j; 21405b261ecSmrg } 21505b261ecSmrg } 21605b261ecSmrg 21705b261ecSmrg for(i = 0; i < numRects; i++) 21805b261ecSmrg { 21905b261ecSmrg prect = &boxes[ordering[i]]; 22005b261ecSmrg xMin = max(prect->x1, srcBox.x1); 22105b261ecSmrg xMax = min(prect->x2, srcBox.x2); 22205b261ecSmrg yMin = max(prect->y1, srcBox.y1); 22305b261ecSmrg yMax = min(prect->y2, srcBox.y2); 22405b261ecSmrg /* is there anything visible here? */ 22505b261ecSmrg if(xMax <= xMin || yMax <= yMin) 22605b261ecSmrg continue; 22705b261ecSmrg 22805b261ecSmrg ppt = pptFirst; 22905b261ecSmrg pwidth = pwidthFirst; 23005b261ecSmrg y = yMin; 23105b261ecSmrg height = yMax - yMin; 23205b261ecSmrg width = xMax - xMin; 23305b261ecSmrg 23405b261ecSmrg for(j = 0; j < height; j++) 23505b261ecSmrg { 23605b261ecSmrg /* We must untranslate before calling GetSpans */ 23705b261ecSmrg ppt->x = xMin; 23805b261ecSmrg ppt++->y = y++; 23905b261ecSmrg *pwidth++ = width; 24005b261ecSmrg } 24105b261ecSmrg pbits = (unsigned int *)xalloc(height * PixmapBytePad(width, 24205b261ecSmrg pSrcDrawable->depth)); 24305b261ecSmrg if (pbits) 24405b261ecSmrg { 24505b261ecSmrg (*pSrcDrawable->pScreen->GetSpans)(pSrcDrawable, width, pptFirst, 24605b261ecSmrg (int *)pwidthFirst, height, (char *)pbits); 24705b261ecSmrg ppt = pptFirst; 24805b261ecSmrg pwidth = pwidthFirst; 24905b261ecSmrg xMin -= (srcx - dstx); 25005b261ecSmrg y = yMin - (srcy - dsty); 25105b261ecSmrg for(j = 0; j < height; j++) 25205b261ecSmrg { 25305b261ecSmrg ppt->x = xMin; 25405b261ecSmrg ppt++->y = y++; 25505b261ecSmrg *pwidth++ = width; 25605b261ecSmrg } 25705b261ecSmrg 25805b261ecSmrg (*pGC->ops->SetSpans)(pDstDrawable, pGC, (char *)pbits, pptFirst, 25905b261ecSmrg (int *)pwidthFirst, height, TRUE); 26005b261ecSmrg xfree(pbits); 26105b261ecSmrg } 26205b261ecSmrg } 26305b261ecSmrg prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC, xIn, yIn, 26405b261ecSmrg widthSrc, heightSrc, xOut, yOut, (unsigned long)0); 26505b261ecSmrg if(realSrcClip) 26605b261ecSmrg REGION_DESTROY(pGC->pScreen, prgnSrcClip); 26705b261ecSmrg 2684642e01fSmrg xfree(ordering); 2694642e01fSmrg xfree(pwidthFirst); 2704642e01fSmrg xfree(pptFirst); 27105b261ecSmrg return prgnExposed; 27205b261ecSmrg} 27305b261ecSmrg 27405b261ecSmrg/* MIGETPLANE -- gets a bitmap representing one plane of pDraw 27505b261ecSmrg * A helper used for CopyPlane and XY format GetImage 27605b261ecSmrg * No clever strategy here, we grab a scanline at a time, pull out the 27705b261ecSmrg * bits and then stuff them in a 1 bit deep map. 27805b261ecSmrg */ 27905b261ecSmrg/* 28005b261ecSmrg * This should be replaced with something more general. mi shouldn't have to 28105b261ecSmrg * care about such things as scanline padding et alia. 28205b261ecSmrg */ 28305b261ecSmrgstatic 28405b261ecSmrgMiBits * 28505b261ecSmrgmiGetPlane( 28605b261ecSmrg DrawablePtr pDraw, 28705b261ecSmrg int planeNum, /* number of the bitPlane */ 28805b261ecSmrg int sx, 28905b261ecSmrg int sy, 29005b261ecSmrg int w, 29105b261ecSmrg int h, 29205b261ecSmrg MiBits *result) 29305b261ecSmrg{ 29405b261ecSmrg int i, j, k, width, bitsPerPixel, widthInBytes; 29505b261ecSmrg DDXPointRec pt = {0, 0}; 29605b261ecSmrg MiBits pixel; 29705b261ecSmrg MiBits bit; 29805b261ecSmrg unsigned char *pCharsOut = NULL; 29905b261ecSmrg 30005b261ecSmrg#if BITMAP_SCANLINE_UNIT == 8 30105b261ecSmrg#define OUT_TYPE unsigned char 30205b261ecSmrg#endif 30305b261ecSmrg#if BITMAP_SCANLINE_UNIT == 16 30405b261ecSmrg#define OUT_TYPE CARD16 30505b261ecSmrg#endif 30605b261ecSmrg#if BITMAP_SCANLINE_UNIT == 32 30705b261ecSmrg#define OUT_TYPE CARD32 30805b261ecSmrg#endif 30905b261ecSmrg#if BITMAP_SCANLINE_UNIT == 64 31005b261ecSmrg#define OUT_TYPE CARD64 31105b261ecSmrg#endif 31205b261ecSmrg 31305b261ecSmrg OUT_TYPE *pOut; 31405b261ecSmrg int delta = 0; 31505b261ecSmrg 31605b261ecSmrg sx += pDraw->x; 31705b261ecSmrg sy += pDraw->y; 31805b261ecSmrg widthInBytes = BitmapBytePad(w); 31905b261ecSmrg if(!result) 3204642e01fSmrg result = xcalloc(h, widthInBytes); 32105b261ecSmrg if (!result) 32205b261ecSmrg return (MiBits *)NULL; 32305b261ecSmrg bitsPerPixel = pDraw->bitsPerPixel; 32405b261ecSmrg pOut = (OUT_TYPE *) result; 32505b261ecSmrg if(bitsPerPixel == 1) 32605b261ecSmrg { 32705b261ecSmrg pCharsOut = (unsigned char *) result; 32805b261ecSmrg width = w; 32905b261ecSmrg } 33005b261ecSmrg else 33105b261ecSmrg { 33205b261ecSmrg delta = (widthInBytes / (BITMAP_SCANLINE_UNIT / 8)) - 33305b261ecSmrg (w / BITMAP_SCANLINE_UNIT); 33405b261ecSmrg width = 1; 33505b261ecSmrg#if IMAGE_BYTE_ORDER == MSBFirst 33605b261ecSmrg planeNum += (32 - bitsPerPixel); 33705b261ecSmrg#endif 33805b261ecSmrg } 33905b261ecSmrg pt.y = sy; 34005b261ecSmrg for (i = h; --i >= 0; pt.y++) 34105b261ecSmrg { 34205b261ecSmrg pt.x = sx; 34305b261ecSmrg if(bitsPerPixel == 1) 34405b261ecSmrg { 34505b261ecSmrg (*pDraw->pScreen->GetSpans)(pDraw, width, &pt, &width, 1, 34605b261ecSmrg (char *)pCharsOut); 34705b261ecSmrg pCharsOut += widthInBytes; 34805b261ecSmrg } 34905b261ecSmrg else 35005b261ecSmrg { 35105b261ecSmrg k = 0; 35205b261ecSmrg for(j = w; --j >= 0; pt.x++) 35305b261ecSmrg { 35405b261ecSmrg /* Fetch the next pixel */ 35505b261ecSmrg (*pDraw->pScreen->GetSpans)(pDraw, width, &pt, &width, 1, 35605b261ecSmrg (char *)&pixel); 35705b261ecSmrg /* 35805b261ecSmrg * Now get the bit and insert into a bitmap in XY format. 35905b261ecSmrg */ 36005b261ecSmrg bit = (pixel >> planeNum) & 1; 36105b261ecSmrg#if 0 36205b261ecSmrg /* XXX assuming bit order == byte order */ 36305b261ecSmrg#if BITMAP_BIT_ORDER == LSBFirst 36405b261ecSmrg bit <<= k; 36505b261ecSmrg#else 36605b261ecSmrg bit <<= ((BITMAP_SCANLINE_UNIT - 1) - k); 36705b261ecSmrg#endif 36805b261ecSmrg#else 36905b261ecSmrg /* XXX assuming byte order == LSBFirst */ 37005b261ecSmrg if (screenInfo.bitmapBitOrder == LSBFirst) 37105b261ecSmrg bit <<= k; 37205b261ecSmrg else 37305b261ecSmrg bit <<= ((screenInfo.bitmapScanlineUnit - 1) - 37405b261ecSmrg (k % screenInfo.bitmapScanlineUnit)) + 37505b261ecSmrg ((k / screenInfo.bitmapScanlineUnit) * 37605b261ecSmrg screenInfo.bitmapScanlineUnit); 37705b261ecSmrg#endif 37805b261ecSmrg *pOut |= (OUT_TYPE) bit; 37905b261ecSmrg k++; 38005b261ecSmrg if (k == BITMAP_SCANLINE_UNIT) 38105b261ecSmrg { 38205b261ecSmrg pOut++; 38305b261ecSmrg k = 0; 38405b261ecSmrg } 38505b261ecSmrg } 38605b261ecSmrg pOut += delta; 38705b261ecSmrg } 38805b261ecSmrg } 38905b261ecSmrg return(result); 39005b261ecSmrg 39105b261ecSmrg} 39205b261ecSmrg 39305b261ecSmrg/* MIOPQSTIPDRAWABLE -- use pbits as an opaque stipple for pDraw. 39405b261ecSmrg * Drawing through the clip mask we SetSpans() the bits into a 39505b261ecSmrg * bitmap and stipple those bits onto the destination drawable by doing a 39605b261ecSmrg * PolyFillRect over the whole drawable, 39705b261ecSmrg * then we invert the bitmap by copying it onto itself with an alu of 39805b261ecSmrg * GXinvert, invert the foreground/background colors of the gc, and draw 39905b261ecSmrg * the background bits. 40005b261ecSmrg * Note how the clipped out bits of the bitmap are always the background 40105b261ecSmrg * color so that the stipple never causes FillRect to draw them. 40205b261ecSmrg */ 40305b261ecSmrgstatic void 40405b261ecSmrgmiOpqStipDrawable(DrawablePtr pDraw, GCPtr pGC, RegionPtr prgnSrc, 40505b261ecSmrg MiBits *pbits, int srcx, int w, int h, int dstx, int dsty) 40605b261ecSmrg{ 40705b261ecSmrg int oldfill, i; 40805b261ecSmrg unsigned long oldfg; 40905b261ecSmrg int *pwidth, *pwidthFirst; 41005b261ecSmrg ChangeGCVal gcv[6]; 41105b261ecSmrg PixmapPtr pStipple, pPixmap; 41205b261ecSmrg DDXPointRec oldOrg; 41305b261ecSmrg GCPtr pGCT; 41405b261ecSmrg DDXPointPtr ppt, pptFirst; 41505b261ecSmrg xRectangle rect; 41605b261ecSmrg RegionPtr prgnSrcClip; 41705b261ecSmrg 41805b261ecSmrg pPixmap = (*pDraw->pScreen->CreatePixmap) 4194642e01fSmrg (pDraw->pScreen, w + srcx, h, 1, 4204642e01fSmrg CREATE_PIXMAP_USAGE_SCRATCH); 42105b261ecSmrg if (!pPixmap) 42205b261ecSmrg return; 42305b261ecSmrg 42405b261ecSmrg /* Put the image into a 1 bit deep pixmap */ 42505b261ecSmrg pGCT = GetScratchGC(1, pDraw->pScreen); 42605b261ecSmrg if (!pGCT) 42705b261ecSmrg { 42805b261ecSmrg (*pDraw->pScreen->DestroyPixmap)(pPixmap); 42905b261ecSmrg return; 43005b261ecSmrg } 43105b261ecSmrg /* First set the whole pixmap to 0 */ 43205b261ecSmrg gcv[0].val = 0; 43305b261ecSmrg dixChangeGC(NullClient, pGCT, GCBackground, NULL, gcv); 43405b261ecSmrg ValidateGC((DrawablePtr)pPixmap, pGCT); 43505b261ecSmrg miClearDrawable((DrawablePtr)pPixmap, pGCT); 4364642e01fSmrg ppt = pptFirst = (DDXPointPtr)xalloc(h * sizeof(DDXPointRec)); 4374642e01fSmrg pwidth = pwidthFirst = (int *)xalloc(h * sizeof(int)); 43805b261ecSmrg if(!pptFirst || !pwidthFirst) 43905b261ecSmrg { 4404642e01fSmrg if (pwidthFirst) xfree(pwidthFirst); 4414642e01fSmrg if (pptFirst) xfree(pptFirst); 44205b261ecSmrg FreeScratchGC(pGCT); 44305b261ecSmrg return; 44405b261ecSmrg } 44505b261ecSmrg 44605b261ecSmrg /* we need a temporary region because ChangeClip must be assumed 44705b261ecSmrg to destroy what it's sent. note that this means we don't 44805b261ecSmrg have to free prgnSrcClip ourselves. 44905b261ecSmrg */ 45005b261ecSmrg prgnSrcClip = REGION_CREATE(pGCT->pScreen, NULL, 0); 45105b261ecSmrg REGION_COPY(pGCT->pScreen, prgnSrcClip, prgnSrc); 45205b261ecSmrg REGION_TRANSLATE(pGCT->pScreen, prgnSrcClip, srcx, 0); 45305b261ecSmrg (*pGCT->funcs->ChangeClip)(pGCT, CT_REGION, prgnSrcClip, 0); 45405b261ecSmrg ValidateGC((DrawablePtr)pPixmap, pGCT); 45505b261ecSmrg 45605b261ecSmrg /* Since we know pDraw is always a pixmap, we never need to think 45705b261ecSmrg * about translation here */ 45805b261ecSmrg for(i = 0; i < h; i++) 45905b261ecSmrg { 46005b261ecSmrg ppt->x = 0; 46105b261ecSmrg ppt++->y = i; 46205b261ecSmrg *pwidth++ = w + srcx; 46305b261ecSmrg } 46405b261ecSmrg 46505b261ecSmrg (*pGCT->ops->SetSpans)((DrawablePtr)pPixmap, pGCT, (char *)pbits, 46605b261ecSmrg pptFirst, pwidthFirst, h, TRUE); 4674642e01fSmrg xfree(pwidthFirst); 4684642e01fSmrg xfree(pptFirst); 46905b261ecSmrg 47005b261ecSmrg 47105b261ecSmrg /* Save current values from the client GC */ 47205b261ecSmrg oldfill = pGC->fillStyle; 47305b261ecSmrg pStipple = pGC->stipple; 47405b261ecSmrg if(pStipple) 47505b261ecSmrg pStipple->refcnt++; 47605b261ecSmrg oldOrg = pGC->patOrg; 47705b261ecSmrg 47805b261ecSmrg /* Set a new stipple in the drawable */ 47905b261ecSmrg gcv[0].val = FillStippled; 48005b261ecSmrg gcv[1].ptr = pPixmap; 48105b261ecSmrg gcv[2].val = dstx - srcx; 48205b261ecSmrg gcv[3].val = dsty; 48305b261ecSmrg 48405b261ecSmrg dixChangeGC(NullClient, pGC, 48505b261ecSmrg GCFillStyle | GCStipple | GCTileStipXOrigin | GCTileStipYOrigin, 48605b261ecSmrg NULL, gcv); 48705b261ecSmrg ValidateGC(pDraw, pGC); 48805b261ecSmrg 48905b261ecSmrg /* Fill the drawable with the stipple. This will draw the 49005b261ecSmrg * foreground color whereever 1 bits are set, leaving everything 49105b261ecSmrg * with 0 bits untouched. Note that the part outside the clip 49205b261ecSmrg * region is all 0s. */ 49305b261ecSmrg rect.x = dstx; 49405b261ecSmrg rect.y = dsty; 49505b261ecSmrg rect.width = w; 49605b261ecSmrg rect.height = h; 49705b261ecSmrg (*pGC->ops->PolyFillRect)(pDraw, pGC, 1, &rect); 49805b261ecSmrg 49905b261ecSmrg /* Invert the tiling pixmap. This sets 0s for 1s and 1s for 0s, only 50005b261ecSmrg * within the clipping region, the part outside is still all 0s */ 50105b261ecSmrg gcv[0].val = GXinvert; 50205b261ecSmrg dixChangeGC(NullClient, pGCT, GCFunction, NULL, gcv); 50305b261ecSmrg ValidateGC((DrawablePtr)pPixmap, pGCT); 50405b261ecSmrg (*pGCT->ops->CopyArea)((DrawablePtr)pPixmap, (DrawablePtr)pPixmap, 50505b261ecSmrg pGCT, 0, 0, w + srcx, h, 0, 0); 50605b261ecSmrg 50705b261ecSmrg /* Swap foreground and background colors on the GC for the drawable. 50805b261ecSmrg * Now when we fill the drawable, we will fill in the "Background" 50905b261ecSmrg * values */ 51005b261ecSmrg oldfg = pGC->fgPixel; 51105b261ecSmrg gcv[0].val = pGC->bgPixel; 51205b261ecSmrg gcv[1].val = oldfg; 51305b261ecSmrg gcv[2].ptr = pPixmap; 51405b261ecSmrg dixChangeGC(NullClient, pGC, GCForeground | GCBackground | GCStipple, 51505b261ecSmrg NULL, gcv); 51605b261ecSmrg ValidateGC(pDraw, pGC); 51705b261ecSmrg /* PolyFillRect might have bashed the rectangle */ 51805b261ecSmrg rect.x = dstx; 51905b261ecSmrg rect.y = dsty; 52005b261ecSmrg rect.width = w; 52105b261ecSmrg rect.height = h; 52205b261ecSmrg (*pGC->ops->PolyFillRect)(pDraw, pGC, 1, &rect); 52305b261ecSmrg 52405b261ecSmrg /* Now put things back */ 52505b261ecSmrg if(pStipple) 52605b261ecSmrg pStipple->refcnt--; 52705b261ecSmrg gcv[0].val = oldfg; 52805b261ecSmrg gcv[1].val = pGC->fgPixel; 52905b261ecSmrg gcv[2].val = oldfill; 53005b261ecSmrg gcv[3].ptr = pStipple; 53105b261ecSmrg gcv[4].val = oldOrg.x; 53205b261ecSmrg gcv[5].val = oldOrg.y; 53305b261ecSmrg dixChangeGC(NullClient, pGC, 53405b261ecSmrg GCForeground | GCBackground | GCFillStyle | GCStipple | 53505b261ecSmrg GCTileStipXOrigin | GCTileStipYOrigin, NULL, gcv); 53605b261ecSmrg 53705b261ecSmrg ValidateGC(pDraw, pGC); 53805b261ecSmrg /* put what we hope is a smaller clip region back in the scratch gc */ 53905b261ecSmrg (*pGCT->funcs->ChangeClip)(pGCT, CT_NONE, NULL, 0); 54005b261ecSmrg FreeScratchGC(pGCT); 54105b261ecSmrg (*pDraw->pScreen->DestroyPixmap)(pPixmap); 54205b261ecSmrg 54305b261ecSmrg} 54405b261ecSmrg 54505b261ecSmrg/* MICOPYPLANE -- public entry for the CopyPlane request. 54605b261ecSmrg * strategy: 54705b261ecSmrg * First build up a bitmap out of the bits requested 54805b261ecSmrg * build a source clip 54905b261ecSmrg * Use the bitmap we've built up as a Stipple for the destination 55005b261ecSmrg */ 5514642e01fSmrgRegionPtr 5524642e01fSmrgmiCopyPlane( DrawablePtr pSrcDrawable, 5534642e01fSmrg DrawablePtr pDstDrawable, 5544642e01fSmrg GCPtr pGC, 5554642e01fSmrg int srcx, 5564642e01fSmrg int srcy, 5574642e01fSmrg int width, 5584642e01fSmrg int height, 5594642e01fSmrg int dstx, 5604642e01fSmrg int dsty, 5614642e01fSmrg unsigned long bitPlane) 56205b261ecSmrg{ 56305b261ecSmrg MiBits *ptile; 56405b261ecSmrg BoxRec box; 56505b261ecSmrg RegionPtr prgnSrc, prgnExposed; 56605b261ecSmrg 56705b261ecSmrg /* incorporate the source clip */ 56805b261ecSmrg 56905b261ecSmrg box.x1 = srcx + pSrcDrawable->x; 57005b261ecSmrg box.y1 = srcy + pSrcDrawable->y; 57105b261ecSmrg box.x2 = box.x1 + width; 57205b261ecSmrg box.y2 = box.y1 + height; 57305b261ecSmrg /* clip to visible drawable */ 57405b261ecSmrg if (box.x1 < pSrcDrawable->x) 57505b261ecSmrg box.x1 = pSrcDrawable->x; 57605b261ecSmrg if (box.y1 < pSrcDrawable->y) 57705b261ecSmrg box.y1 = pSrcDrawable->y; 57805b261ecSmrg if (box.x2 > pSrcDrawable->x + (int) pSrcDrawable->width) 57905b261ecSmrg box.x2 = pSrcDrawable->x + (int) pSrcDrawable->width; 58005b261ecSmrg if (box.y2 > pSrcDrawable->y + (int) pSrcDrawable->height) 58105b261ecSmrg box.y2 = pSrcDrawable->y + (int) pSrcDrawable->height; 58205b261ecSmrg if (box.x1 > box.x2) 58305b261ecSmrg box.x2 = box.x1; 58405b261ecSmrg if (box.y1 > box.y2) 58505b261ecSmrg box.y2 = box.y1; 58605b261ecSmrg prgnSrc = REGION_CREATE(pGC->pScreen, &box, 1); 58705b261ecSmrg 58805b261ecSmrg if (pSrcDrawable->type != DRAWABLE_PIXMAP) { 58905b261ecSmrg /* clip to visible drawable */ 59005b261ecSmrg 59105b261ecSmrg if (pGC->subWindowMode == IncludeInferiors) 59205b261ecSmrg { 59305b261ecSmrg RegionPtr clipList = NotClippedByChildren ((WindowPtr) pSrcDrawable); 59405b261ecSmrg REGION_INTERSECT(pGC->pScreen, prgnSrc, prgnSrc, clipList); 59505b261ecSmrg REGION_DESTROY(pGC->pScreen, clipList); 59605b261ecSmrg } else 59705b261ecSmrg REGION_INTERSECT(pGC->pScreen, prgnSrc, prgnSrc, 59805b261ecSmrg &((WindowPtr)pSrcDrawable)->clipList); 59905b261ecSmrg } 60005b261ecSmrg 60105b261ecSmrg box = *REGION_EXTENTS(pGC->pScreen, prgnSrc); 60205b261ecSmrg REGION_TRANSLATE(pGC->pScreen, prgnSrc, -box.x1, -box.y1); 60305b261ecSmrg 60405b261ecSmrg if ((box.x2 > box.x1) && (box.y2 > box.y1)) 60505b261ecSmrg { 60605b261ecSmrg /* minimize the size of the data extracted */ 60705b261ecSmrg /* note that we convert the plane mask bitPlane into a plane number */ 60805b261ecSmrg box.x1 -= pSrcDrawable->x; 60905b261ecSmrg box.x2 -= pSrcDrawable->x; 61005b261ecSmrg box.y1 -= pSrcDrawable->y; 61105b261ecSmrg box.y2 -= pSrcDrawable->y; 61205b261ecSmrg ptile = miGetPlane(pSrcDrawable, ffs(bitPlane) - 1, 61305b261ecSmrg box.x1, box.y1, 61405b261ecSmrg box.x2 - box.x1, box.y2 - box.y1, 61505b261ecSmrg (MiBits *) NULL); 61605b261ecSmrg if (ptile) 61705b261ecSmrg { 61805b261ecSmrg miOpqStipDrawable(pDstDrawable, pGC, prgnSrc, ptile, 0, 61905b261ecSmrg box.x2 - box.x1, box.y2 - box.y1, 62005b261ecSmrg dstx + box.x1 - srcx, dsty + box.y1 - srcy); 62105b261ecSmrg xfree(ptile); 62205b261ecSmrg } 62305b261ecSmrg } 62405b261ecSmrg prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC, srcx, srcy, 62505b261ecSmrg width, height, dstx, dsty, bitPlane); 62605b261ecSmrg REGION_DESTROY(pGC->pScreen, prgnSrc); 62705b261ecSmrg return prgnExposed; 62805b261ecSmrg} 62905b261ecSmrg 63005b261ecSmrg/* MIGETIMAGE -- public entry for the GetImage Request 63105b261ecSmrg * We're getting the image into a memory buffer. While we have to use GetSpans 63205b261ecSmrg * to read a line from the device (since we don't know what that looks like), 63305b261ecSmrg * we can just write into the destination buffer 63405b261ecSmrg * 63505b261ecSmrg * two different strategies are used, depending on whether we're getting the 63605b261ecSmrg * image in Z format or XY format 63705b261ecSmrg * Z format: 63805b261ecSmrg * Line at a time, GetSpans a line into the destination buffer, then if the 63905b261ecSmrg * planemask is not all ones, we do a SetSpans into a temporary buffer (to get 64005b261ecSmrg * bits turned off) and then another GetSpans to get stuff back (because 64105b261ecSmrg * pixmaps are opaque, and we are passed in the memory to write into). This is 64205b261ecSmrg * pretty ugly and slow but works. Life is hard. 64305b261ecSmrg * XY format: 64405b261ecSmrg * get the single plane specified in planemask 64505b261ecSmrg */ 64605b261ecSmrg_X_EXPORT void 6474642e01fSmrgmiGetImage( DrawablePtr pDraw, int sx, int sy, int w, int h, 6484642e01fSmrg unsigned int format, unsigned long planeMask, char *pDst) 64905b261ecSmrg{ 65005b261ecSmrg unsigned char depth; 65105b261ecSmrg int i, linelength, width, srcx, srcy; 65205b261ecSmrg DDXPointRec pt = {0, 0}; 65305b261ecSmrg XID gcv[2]; 65405b261ecSmrg PixmapPtr pPixmap = (PixmapPtr)NULL; 65505b261ecSmrg GCPtr pGC = NULL; 65605b261ecSmrg 65705b261ecSmrg depth = pDraw->depth; 65805b261ecSmrg if(format == ZPixmap) 65905b261ecSmrg { 66005b261ecSmrg if ( (((1<<depth)-1)&planeMask) != (1<<depth)-1 ) 66105b261ecSmrg { 66205b261ecSmrg xPoint pt; 66305b261ecSmrg 66405b261ecSmrg pGC = GetScratchGC(depth, pDraw->pScreen); 66505b261ecSmrg if (!pGC) 66605b261ecSmrg return; 66705b261ecSmrg pPixmap = (*pDraw->pScreen->CreatePixmap) 6684642e01fSmrg (pDraw->pScreen, w, 1, depth, 6694642e01fSmrg CREATE_PIXMAP_USAGE_SCRATCH); 67005b261ecSmrg if (!pPixmap) 67105b261ecSmrg { 67205b261ecSmrg FreeScratchGC(pGC); 67305b261ecSmrg return; 67405b261ecSmrg } 67505b261ecSmrg /* 67605b261ecSmrg * Clear the pixmap before doing anything else 67705b261ecSmrg */ 67805b261ecSmrg ValidateGC((DrawablePtr)pPixmap, pGC); 67905b261ecSmrg pt.x = pt.y = 0; 68005b261ecSmrg width = w; 68105b261ecSmrg (*pGC->ops->FillSpans)((DrawablePtr)pPixmap, pGC, 1, &pt, &width, 68205b261ecSmrg TRUE); 68305b261ecSmrg 68405b261ecSmrg /* alu is already GXCopy */ 68505b261ecSmrg gcv[0] = (XID)planeMask; 68605b261ecSmrg DoChangeGC(pGC, GCPlaneMask, gcv, 0); 68705b261ecSmrg ValidateGC((DrawablePtr)pPixmap, pGC); 68805b261ecSmrg } 68905b261ecSmrg 69005b261ecSmrg linelength = PixmapBytePad(w, depth); 69105b261ecSmrg srcx = sx + pDraw->x; 69205b261ecSmrg srcy = sy + pDraw->y; 69305b261ecSmrg for(i = 0; i < h; i++) 69405b261ecSmrg { 69505b261ecSmrg pt.x = srcx; 69605b261ecSmrg pt.y = srcy + i; 69705b261ecSmrg width = w; 69805b261ecSmrg (*pDraw->pScreen->GetSpans)(pDraw, w, &pt, &width, 1, pDst); 69905b261ecSmrg if (pPixmap) 70005b261ecSmrg { 70105b261ecSmrg pt.x = 0; 70205b261ecSmrg pt.y = 0; 70305b261ecSmrg width = w; 70405b261ecSmrg (*pGC->ops->SetSpans)((DrawablePtr)pPixmap, pGC, pDst, 70505b261ecSmrg &pt, &width, 1, TRUE); 70605b261ecSmrg (*pDraw->pScreen->GetSpans)((DrawablePtr)pPixmap, w, &pt, 70705b261ecSmrg &width, 1, pDst); 70805b261ecSmrg } 70905b261ecSmrg pDst += linelength; 71005b261ecSmrg } 71105b261ecSmrg if (pPixmap) 71205b261ecSmrg { 71305b261ecSmrg (*pGC->pScreen->DestroyPixmap)(pPixmap); 71405b261ecSmrg FreeScratchGC(pGC); 71505b261ecSmrg } 71605b261ecSmrg } 71705b261ecSmrg else 71805b261ecSmrg { 71905b261ecSmrg (void) miGetPlane(pDraw, ffs(planeMask) - 1, sx, sy, w, h, 72005b261ecSmrg (MiBits *)pDst); 72105b261ecSmrg } 72205b261ecSmrg} 72305b261ecSmrg 72405b261ecSmrg/* MIPUTIMAGE -- public entry for the PutImage request 72505b261ecSmrg * Here we benefit from knowing the format of the bits pointed to by pImage, 72605b261ecSmrg * even if we don't know how pDraw represents them. 72705b261ecSmrg * Three different strategies are used depending on the format 72805b261ecSmrg * XYBitmap Format: 72905b261ecSmrg * we just use the Opaque Stipple helper function to cover the destination 73005b261ecSmrg * Note that this covers all the planes of the drawable with the 73105b261ecSmrg * foreground color (masked with the GC planemask) where there are 1 bits 73205b261ecSmrg * and the background color (masked with the GC planemask) where there are 73305b261ecSmrg * 0 bits 73405b261ecSmrg * XYPixmap format: 73505b261ecSmrg * what we're called with is a series of XYBitmaps, but we only want 73605b261ecSmrg * each XYPixmap to update 1 plane, instead of updating all of them. 73705b261ecSmrg * we set the foreground color to be all 1s and the background to all 0s 73805b261ecSmrg * then for each plane, we set the plane mask to only effect that one 73905b261ecSmrg * plane and recursive call ourself with the format set to XYBitmap 74005b261ecSmrg * (This clever idea courtesy of RGD.) 74105b261ecSmrg * ZPixmap format: 74205b261ecSmrg * This part is simple, just call SetSpans 74305b261ecSmrg */ 74405b261ecSmrg_X_EXPORT void 7454642e01fSmrgmiPutImage( DrawablePtr pDraw, GCPtr pGC, int depth, 7464642e01fSmrg int x, int y, int w, int h, 7474642e01fSmrg int leftPad, int format, char *pImage) 74805b261ecSmrg{ 74905b261ecSmrg DDXPointPtr pptFirst, ppt; 75005b261ecSmrg int *pwidthFirst, *pwidth; 75105b261ecSmrg RegionPtr prgnSrc; 75205b261ecSmrg BoxRec box; 75305b261ecSmrg unsigned long oldFg, oldBg; 75405b261ecSmrg XID gcv[3]; 75505b261ecSmrg unsigned long oldPlanemask; 75605b261ecSmrg unsigned long i; 75705b261ecSmrg long bytesPer; 75805b261ecSmrg 75905b261ecSmrg if (!w || !h) 76005b261ecSmrg return; 76105b261ecSmrg switch(format) 76205b261ecSmrg { 76305b261ecSmrg case XYBitmap: 76405b261ecSmrg 76505b261ecSmrg box.x1 = 0; 76605b261ecSmrg box.y1 = 0; 76705b261ecSmrg box.x2 = w; 76805b261ecSmrg box.y2 = h; 76905b261ecSmrg prgnSrc = REGION_CREATE(pGC->pScreen, &box, 1); 77005b261ecSmrg 77105b261ecSmrg miOpqStipDrawable(pDraw, pGC, prgnSrc, (MiBits *) pImage, 77205b261ecSmrg leftPad, w, h, x, y); 77305b261ecSmrg REGION_DESTROY(pGC->pScreen, prgnSrc); 77405b261ecSmrg break; 77505b261ecSmrg 77605b261ecSmrg case XYPixmap: 77705b261ecSmrg depth = pGC->depth; 77805b261ecSmrg oldPlanemask = pGC->planemask; 77905b261ecSmrg oldFg = pGC->fgPixel; 78005b261ecSmrg oldBg = pGC->bgPixel; 78105b261ecSmrg gcv[0] = (XID)~0; 78205b261ecSmrg gcv[1] = (XID)0; 78305b261ecSmrg DoChangeGC(pGC, GCForeground | GCBackground, gcv, 0); 78405b261ecSmrg bytesPer = (long)h * BitmapBytePad(w + leftPad); 78505b261ecSmrg 78605b261ecSmrg for (i = 1 << (depth-1); i != 0; i >>= 1, pImage += bytesPer) 78705b261ecSmrg { 78805b261ecSmrg if (i & oldPlanemask) 78905b261ecSmrg { 79005b261ecSmrg gcv[0] = (XID)i; 79105b261ecSmrg DoChangeGC(pGC, GCPlaneMask, gcv, 0); 79205b261ecSmrg ValidateGC(pDraw, pGC); 79305b261ecSmrg (*pGC->ops->PutImage)(pDraw, pGC, 1, x, y, w, h, leftPad, 79405b261ecSmrg XYBitmap, (char *)pImage); 79505b261ecSmrg } 79605b261ecSmrg } 79705b261ecSmrg gcv[0] = (XID)oldPlanemask; 79805b261ecSmrg gcv[1] = (XID)oldFg; 79905b261ecSmrg gcv[2] = (XID)oldBg; 80005b261ecSmrg DoChangeGC(pGC, GCPlaneMask | GCForeground | GCBackground, gcv, 0); 80105b261ecSmrg ValidateGC(pDraw, pGC); 80205b261ecSmrg break; 80305b261ecSmrg 80405b261ecSmrg case ZPixmap: 8054642e01fSmrg ppt = pptFirst = (DDXPointPtr)xalloc(h * sizeof(DDXPointRec)); 8064642e01fSmrg pwidth = pwidthFirst = (int *)xalloc(h * sizeof(int)); 80705b261ecSmrg if(!pptFirst || !pwidthFirst) 80805b261ecSmrg { 80905b261ecSmrg if (pwidthFirst) 8104642e01fSmrg xfree(pwidthFirst); 81105b261ecSmrg if (pptFirst) 8124642e01fSmrg xfree(pptFirst); 81305b261ecSmrg return; 81405b261ecSmrg } 81505b261ecSmrg if (pGC->miTranslate) 81605b261ecSmrg { 81705b261ecSmrg x += pDraw->x; 81805b261ecSmrg y += pDraw->y; 81905b261ecSmrg } 82005b261ecSmrg 82105b261ecSmrg for(i = 0; i < h; i++) 82205b261ecSmrg { 82305b261ecSmrg ppt->x = x; 82405b261ecSmrg ppt->y = y + i; 82505b261ecSmrg ppt++; 82605b261ecSmrg *pwidth++ = w; 82705b261ecSmrg } 82805b261ecSmrg 82905b261ecSmrg (*pGC->ops->SetSpans)(pDraw, pGC, (char *)pImage, pptFirst, 83005b261ecSmrg pwidthFirst, h, TRUE); 8314642e01fSmrg xfree(pwidthFirst); 8324642e01fSmrg xfree(pptFirst); 83305b261ecSmrg break; 83405b261ecSmrg } 83505b261ecSmrg} 836