/*********************************************************** Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts, and the Massachusetts Institute of Technology, Cambridge, Massachusetts. All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the names of Digital or MIT not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************/ /* $Header: mibitblt.c,v 1.30 87/06/14 19:00:30 todd Exp $ */ #include "X.h" #include "Xprotostr.h" #include "misc.h" #include "gcstruct.h" #include "pixmapstr.h" #include "windowstr.h" #include "scrnintstr.h" #include "mi.h" #include "regionstr.h" #include "Xmd.h" #include "maskbits.h" #include "opaque.h" #if BITMAP_BIT_ORDER == LSBFirst #define SHIFTOP << #else #define SHIFTOP >> #endif /* CopyArea and CopyPlane for generic display build a list of source points, get the scanlines into a buffer set the scanlines from the buffer do graphics exposures free the buffer and lists of src points and widths */ extern void miOpqStipDrawable(); void miCopyArea(pSrcDrawable, pDstDrawable, pGC, xIn, yIn, widthSrc, heightSrc, xOut, yOut) register DrawablePtr pSrcDrawable; register DrawablePtr pDstDrawable; GCPtr pGC; int xIn, yIn; int widthSrc, heightSrc; int xOut, yOut; { DDXPointPtr ppt, pptFirst; unsigned int *pwidthFirst, *pwidth, *pbits; BoxRec srcBox, *prect; /* may be a new region, or just a copy */ RegionPtr prgnSrcClip; /* non-0 if we've created a src clip */ int realSrcClip = 0; int srcx, srcy, dstx, dsty, i, j, y, width, height, xMin, xMax, yMin, yMax; /* clip the left and top edges of the source */ if (xIn < 0) { widthSrc += xIn; srcx = 0; } else srcx = xIn; if (yIn < 0) { heightSrc += yIn; yIn = 0; } else srcy = yIn; /* clip the source */ if (pSrcDrawable->type == DRAWABLE_PIXMAP) { BoxRec box; box.x1 = 0; box.y1 = 0; box.x2 = ((PixmapPtr)pSrcDrawable)->width; box.y2 = ((PixmapPtr)pSrcDrawable)->height; prgnSrcClip = (*pGC->pScreen->RegionCreate)(&box, 1); realSrcClip = 1; } else { srcx += ((WindowPtr)pSrcDrawable)->absCorner.x; srcy += ((WindowPtr)pSrcDrawable)->absCorner.y; prgnSrcClip = ((WindowPtr)pSrcDrawable)->clipList; } srcBox.x1 = srcx; srcBox.y1 = srcy; srcBox.x2 = srcx + widthSrc; srcBox.y2 = srcy + heightSrc; if (pGC->miTranslate && (pDstDrawable->type == DRAWABLE_WINDOW) ) { dstx = xOut + ((WindowPtr)pDstDrawable)->absCorner.x; dsty = yOut + ((WindowPtr)pDstDrawable)->absCorner.y; } else { dstx = xOut; dsty = yOut; } pptFirst = ppt = (DDXPointPtr) ALLOCATE_LOCAL(heightSrc * sizeof(DDXPointRec)); pwidthFirst = pwidth = (unsigned int *) ALLOCATE_LOCAL(heightSrc * sizeof(unsigned int)); if(!pptFirst || !pwidthFirst) { if (pptFirst) DEALLOCATE_LOCAL(pptFirst); if (pwidthFirst) DEALLOCATE_LOCAL(pwidthFirst); return; } prect = prgnSrcClip->rects; for(i = 0; i < prgnSrcClip->numRects; i++, prect++) { xMin = max(prect->x1, srcBox.x1); xMax = min(prect->x2, srcBox.x2); yMin = max(prect->y1, srcBox.y1); yMax = min(prect->y2, srcBox.y2); /* is there anything visible here? */ if(xMax <= xMin || yMax <= yMin) continue; ppt = pptFirst; pwidth = pwidthFirst; y = yMin; height = yMax - yMin; width = xMax - xMin; for(j = 0; j < height; j++) { ppt->x = xMin; ppt++->y = y++; *pwidth++ = width; } pbits = (*pSrcDrawable->pScreen->GetSpans)(pSrcDrawable, width, pptFirst, pwidthFirst, height); ppt = pptFirst; pwidth = pwidthFirst; xMin -= (srcx - dstx); y = yMin - (srcy - dsty); for(j = 0; j < height; j++) { ppt->x = xMin; ppt++->y = y++; *pwidth++ = width; } (*pGC->SetSpans)(pDstDrawable, pGC, pbits, pptFirst, pwidthFirst, height, TRUE); Xfree(pbits); } miHandleExposures(pSrcDrawable, pDstDrawable, pGC, xIn, yIn, widthSrc, heightSrc, xOut, yOut); if(realSrcClip) (*pGC->pScreen->RegionDestroy)(prgnSrcClip); DEALLOCATE_LOCAL(pptFirst); DEALLOCATE_LOCAL(pwidthFirst); } unsigned char * miGetPlane(pDraw, bitPlane, sx, sy, w, h, result) DrawablePtr pDraw; int bitPlane; int sx, sy, w, h; unsigned char *result; { int i, j, k, depth, width, bitsPerPixel, widthInBytes; DDXPointRec pt; unsigned int *pline; unsigned int bit; unsigned char *pCharsOut; CARD16 *pShortsOut; CARD32 *pLongsOut; depth = pDraw->depth; if(pDraw->type == DRAWABLE_PIXMAP) { w = min(w, ((PixmapPtr)pDraw)->width); h = min(h, ((PixmapPtr)pDraw)->height); } else { w = min(w, ((WindowPtr)pDraw)->clientWinSize.width); h = min(h, ((WindowPtr)pDraw)->clientWinSize.height); } widthInBytes = PixmapBytePad(w, depth); if(!result) result = (unsigned char *)Xalloc(h * widthInBytes); bitsPerPixel = GetBitsPerPixel(depth); if (pDraw->type == DRAWABLE_WINDOW) { sx += ((WindowPtr)pDraw)->absCorner.x; sy += ((WindowPtr)pDraw)->absCorner.y; } bzero(result, h * widthInBytes); if(BITMAP_SCANLINE_UNIT == 8) pCharsOut = (unsigned char *) result; else if(BITMAP_SCANLINE_UNIT == 16) pShortsOut = (CARD16 *) result; else if(BITMAP_SCANLINE_UNIT == 32) pLongsOut = (CARD32 *) result; if(bitsPerPixel == 1) pCharsOut = (unsigned char *) result; for(i = sy; i < sy + h; i++) { if(bitsPerPixel == 1) { pt.x = sx; pt.y = i; width = w; pline = (*pDraw->pScreen->GetSpans)(pDraw, width, &pt, &width, 1); bcopy(pline, pCharsOut, (w + 7)/8); pCharsOut += widthInBytes; Xfree(pline); } else { k = 0; for(j = 0; j < w; j++) { pt.x = sx + j; pt.y = i; width = 1; /* Fetch the next pixel */ pline = (*pDraw->pScreen->GetSpans)(pDraw, width, &pt, &width, 1); /* Use a macro in Xmd.h to grab the appropriate bit */ bit = (unsigned int) GetBitFromPixel(*pline, bitPlane, depth); /* Now insert that bit into a bitmap in XY format */ SCRRIGHT(bit, k); if(BITMAP_SCANLINE_UNIT == 8) { *pCharsOut |= (unsigned char) bit; k = (++k == 8) ? pCharsOut++, 0 : k; } else if(BITMAP_SCANLINE_UNIT == 16) { *pShortsOut |= (CARD16) bit; k = (++k == 16) ? pShortsOut++, 0 : k; } if(BITMAP_SCANLINE_UNIT == 32) { *pLongsOut |= (CARD32) bit; k = (++k == 32) ? pLongsOut++, 0 : k; } Xfree(pline); } } } return(result); } GetBitsPerPixel(depth) int depth; { int i; for(i = 0; i < screenInfo.numPixmapFormats; i++) { if(screenInfo.formats[i].depth == depth) { return (screenInfo.formats[i].bitsPerPixel); } } return(1); } void miCopyPlane(pSrcDrawable, pDstDrawable, pGC, srcx, srcy, width, height, dstx, dsty, bitPlane) DrawablePtr pSrcDrawable; DrawablePtr pDstDrawable; GCPtr pGC; int srcx, srcy; int width, height; int dstx, dsty; int bitPlane; { unsigned char *ptile; BoxRec box; RegionPtr prgnSrc; /* strategy: * First build up a bitmap out of the bits requested * build a source clip * Use the bitmap we've built up as a Stipple for the destination */ /* clip the left and top edges of the source */ if (srcx < 0) { width += srcx; srcx = 0; } if (srcy < 0) { height += srcy; srcy = 0; } /* incorporate the source clip */ if (pSrcDrawable->type != DRAWABLE_PIXMAP) { box.x1 = ((WindowPtr)pSrcDrawable)->absCorner.x; box.y1 = ((WindowPtr)pSrcDrawable)->absCorner.y; box.x2 = box.x1 + width; box.y2 = box.y1 + height; prgnSrc = (*pGC->pScreen->RegionCreate)(&box, 1); (*pGC->pScreen->Intersect) (prgnSrc, prgnSrc, ((WindowPtr)pSrcDrawable)->clipList); (*pGC->pScreen->TranslateRegion)(prgnSrc, -((WindowPtr)pSrcDrawable)->absCorner.x, -((WindowPtr)pSrcDrawable)->absCorner.y); } else { box.x1 = 0; box.y1 = 0; box.x2 = ((PixmapPtr)pSrcDrawable)->width; box.y2 = ((PixmapPtr)pSrcDrawable)->height; prgnSrc = (*pGC->pScreen->RegionCreate)(&box, 1); } ptile = miGetPlane(pSrcDrawable, bitPlane, srcx, srcy, width, height, (unsigned char *) NULL); miOpqStipDrawable(pDstDrawable, pGC, prgnSrc, (unsigned int *)ptile, 0, width, height, dstx, dsty); miHandleExposures(pSrcDrawable, pDstDrawable, pGC, srcx, srcy, width, height, dstx, dsty); Xfree(ptile); (*pGC->pScreen->RegionDestroy)(prgnSrc); } void miOpqStipDrawable(pDraw, pGC, prgnSrc, pbits, srcx, w, h, dstx, dsty) DrawablePtr pDraw; GCPtr pGC; RegionPtr prgnSrc; unsigned int *pbits; int srcx, w, h, dstx, dsty; { int oldfill, oldfg, i; PixmapPtr pStipple, pPixmap; DDXPointRec oldOrg; GCPtr pGCT; DDXPointPtr ppt, pptFirst; int *pwidth, *pwidthFirst; xRectangle rect; long gcv[6]; pPixmap = (PixmapPtr)(*pDraw->pScreen->CreatePixmap) (pDraw->pScreen, w, h, 1); if (!pPixmap) { ErrorF( "miOpqStipDrawable can't make temp pixmap\n"); return; } /* Put the image into a 1 bit deep pixmap */ pGCT = GetScratchGC(1, pDraw->pScreen); /* First set the whole pixmap to 0 */ ValidateGC((DrawablePtr)pPixmap, pGCT); ClearDrawable((DrawablePtr)pPixmap, pGCT, w, h); ppt = pptFirst = (DDXPointPtr)ALLOCATE_LOCAL(h * sizeof(DDXPointRec)); pwidth = pwidthFirst = (int *)ALLOCATE_LOCAL(h * sizeof(int)); if(!ppt || !pwidth) { DEALLOCATE_LOCAL(pwidthFirst); DEALLOCATE_LOCAL(pptFirst); FreeScratchGC(pGCT); return; } (*pGCT->ChangeClip)(pGCT, CT_REGION, prgnSrc, 0); ValidateGC((DrawablePtr)pPixmap, pGCT); for(i = 0; i < h; i++) { ppt->x = srcx; ppt++->y = i; *pwidth++ = w; } (*pGC->SetSpans)(pPixmap, pGCT, pbits, pptFirst, pwidthFirst, h, TRUE); /* Save current values from the client GC */ oldfill = pGC->fillStyle; pStipple = pGC->stipple; oldOrg = pGC->patOrg; /* Set a new stipple in the drawable */ gcv[0] = FillStippled; gcv[1] = (int) pPixmap; gcv[2] = dstx; gcv[3] = dsty; ChangeGC(pGC, GCFillStyle | GCStipple | GCTileStipXOrigin | GCTileStipYOrigin, gcv); ValidateGC(pDraw, pGC); /* Fill the drawable with the stipple. This will draw the * foreground color whereever 1 bits are set, leaving everything * with 0 bits untouched. Note that the part outside the clip * region is all 0s. */ rect.x = dstx; rect.y = dsty; rect.width = w; rect.height = h; (*pGC->PolyFillRect)(pDraw, pGC, 1, &rect); /* Invert the tiling pixmap. This sets 0s for 1s and 1s for 0s, only * within the clipping region, the part outside is still all 0s */ ChangeGC(pGCT, GCFunction, gcv); ValidateGC((DrawablePtr)pPixmap, pGCT); (*pGCT->CopyArea)(pPixmap, pPixmap, pGCT, 0, 0, w, h, 0, 0); /* Swap foreground and background colors on the GC for the drawable. * Now when we fill the drawable, we will fill in the "Background" * values */ oldfg = pGC->fgPixel; gcv[0] = pGC->bgPixel; gcv[1] = oldfg; gcv[2] = (int) pPixmap; ChangeGC(pGC, GCForeground | GCBackground | GCStipple, gcv); ValidateGC(pDraw, pGC); /* PolyFillRect might have bashed the rectangle */ rect.x = dstx; rect.y = dsty; rect.width = w; rect.height = h; (*pGC->PolyFillRect)(pDraw, pGC, 1, &rect); /* Now put things back */ gcv[0] = oldfg; gcv[1] = pGC->fgPixel; gcv[2] = oldfill; gcv[3] = (int) pStipple; gcv[4] = oldOrg.x; gcv[5] = oldOrg.y; ChangeGC(pGC, GCForeground | GCBackground | GCFillStyle | GCStipple | GCTileStipXOrigin | GCTileStipYOrigin, gcv); ValidateGC(pDraw, pGC); Xfree(pPixmap); FreeScratchGC(pGCT); } void miGetImage(pDraw, sx, sy, w, h, format, planeMask, pdstLine) DrawablePtr pDraw; int sx, sy, w, h; unsigned int format; unsigned int planeMask; unsigned char *pdstLine; { int depth, i, linelength, fg, width; DDXPointRec pt; unsigned int *pbits, curplane; long gcv[2]; PixmapPtr pPixmap; xRectangle rect; GCPtr pGC; depth = pDraw->depth; if(format == ZPixmap) { pGC = GetScratchGC(depth, pDraw->pScreen); pPixmap = (PixmapPtr)(*pDraw->pScreen->CreatePixmap) (pDraw->pScreen, w, h, depth); fg = pGC->fgPixel; rect.x = 0; rect.y = 0; rect.width = w; rect.height = h; gcv[0] = GXcopy; gcv[1] = 0; ChangeGC(pGC, GCFunction | GCForeground, gcv); ValidateGC((DrawablePtr)pPixmap, pGC); (*pGC->PolyFillRect)(pPixmap, pGC, 1, &rect); gcv[0] = planeMask; gcv[1] = fg; ChangeGC(pGC, GCPlaneMask | GCForeground, gcv); ValidateGC((DrawablePtr)pPixmap, pGC); (*pGC->CopyArea) (pDraw, pPixmap, pGC, sx, sy, w, h, 0, 0); linelength = PixmapBytePad(w, depth); for(i = 0; i < h; i++) { pt.x = 0; pt.y = i; width = w; pbits = (*pDraw->pScreen->GetSpans)(pPixmap, w, &pt, &width, 1); bcopy(pbits, pdstLine, linelength); pdstLine += linelength; Xfree(pbits); } (*pGC->pScreen->DestroyPixmap)(pPixmap); } else { linelength = PixmapBytePad(w, 1); curplane = 1 << (depth - 1); while(curplane) { if(curplane & planeMask) { pdstLine = miGetPlane(pDraw, depth - 1, sx, sy, w, h, pdstLine); pdstLine += linelength; } curplane >>= 1; } } } void miPutImage(pDraw, pGC, depth, x, y, w, h, leftPad, format, pImage) DrawablePtr pDraw; GCPtr pGC; int depth, x, y, w, h, leftPad; unsigned int format; unsigned char *pImage; { DDXPointPtr pptFirst, ppt; int *pwidthFirst, *pwidth, i; RegionPtr prgnSrc; BoxRec box; int oldFg, oldBg, oldPlanemask; long gcv[3]; switch(format) { case XYBitmap: box.x1 = 0; box.y1 = 0; box.x2 = w; box.y2 = h; prgnSrc = (*pGC->pScreen->RegionCreate)(&box, 1); miOpqStipDrawable(pDraw, pGC, prgnSrc, (unsigned int *)pImage, leftPad, (w - leftPad), h, x, y); (*pGC->pScreen->RegionDestroy)(prgnSrc); break; case XYPixmap: depth = pGC->depth; oldPlanemask = pGC->planemask; oldFg = pGC->fgPixel; oldBg = pGC->bgPixel; gcv[0] = ~0; gcv[1] = 0; ChangeGC(pGC, GCForeground | GCBackground, gcv); for (i = depth-1; i >=0; i--) { ChangeGC(pGC, GCPlaneMask, gcv); ValidateGC(pDraw, pGC); (*pGC->PutImage)(pDraw, pGC, 1, x, y, w, h, leftPad, XYBitmap, pImage); pImage += h * PixmapBytePad(w, 1); } gcv[0] = oldPlanemask; gcv[1] = oldFg; gcv[2] = oldBg; ChangeGC(pGC, GCPlaneMask | GCForeground | GCBackground, gcv); break; case ZPixmap: ppt = pptFirst = (DDXPointPtr)ALLOCATE_LOCAL(h * sizeof(DDXPointRec)); pwidth = pwidthFirst = (int *)ALLOCATE_LOCAL(h * sizeof(int)); if(!ppt || !pwidth) { if (ppt) DEALLOCATE_LOCAL(ppt); else if (pwidth) DEALLOCATE_LOCAL(pwidthFirst); return; } if ((pDraw->type == DRAWABLE_WINDOW) && (pGC->miTranslate)) { x += ((WindowPtr)(pDraw))->absCorner.x; y += ((WindowPtr)(pDraw))->absCorner.y; } for(i = 0; i < h; i++) { ppt->x = x; ppt->y = y + i; ppt++; *pwidth++ = w; } (*pGC->SetSpans)(pDraw, pGC, pImage, pptFirst, pwidthFirst, h, TRUE); DEALLOCATE_LOCAL(pptFirst); DEALLOCATE_LOCAL(pwidthFirst); break; } }