+/*
+
+Copyright (c) 1986, 1987 by Hewlett-Packard Company
+Copyright (c) 1986, 1987 by the Massachusetts Institute of Technology
+
+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 name of M.I.T. not be used in
+advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+HEWLETT-PACKARD MAKES NO WARRANTY OF ANY KIND WITH REGARD
+TO THIS SOFWARE, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. Hewlett-Packard shall not be liable for errors
+contained herein or direct, indirect, special, incidental or
+consequential damages in connection with the furnishing,
+performance, or use of this material.
+
+This software is not subject to any license of the American
+Telephone and Telegraph Company or of the Regents of the
+University of California.
+
+*/
+/***********************************************************************
+ * file: hpByteBlt.c
+ *
+ * Byte-Per-Pixel 68000 (and hopefully Spectrum) bit/byte order
+ * image transfer routines. Specifically:
+ * hpGetByteImage
+ *
+ * Hewlett Packard -- Corvallis Workstation Operation
+ * Project -- port of X11 to HP9000
+ * Harry Phinney -- MTS
+ *
+ *
+ */
+
+#include "X.h"
+#include "Xprotostr.h"
+
+#include "cfb.h"
+#include "gcstruct.h"
+#include "pixmapstr.h"
+#include "windowstr.h"
+#include "scrnintstr.h"
+#include "mi.h"
+#include "regionstr.h"
+#include "Xmd.h"
+#include "servermd.h"
+
+static unsigned char masks[8] = { 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80 };
+#if 0
+static unsigned char trailMasks[8] = { 0x80, 0x40, 0x20, 0x10, 0x8, 0x4,
+ 0x2, 0x1 };
+
+static unsigned long bmap[32] = {
+ 0x00000001, 0x00000002, 0x00000004, 0x00000008,
+ 0x00000010, 0x00000020, 0x00000040, 0x00000080,
+ 0x00000100, 0x00000200, 0x00000400, 0x00000800,
+ 0x00001000, 0x00002000, 0x00004000, 0x00008000,
+ 0x00010000, 0x00020000, 0x00040000, 0x00080000,
+ 0x00100000, 0x00200000, 0x00400000, 0x00800000,
+ 0x01000000, 0x02000000, 0x04000000, 0x08000000,
+ 0x10000000, 0x20000000, 0x40000000, 0x80000000 };
+#endif
+
+static unsigned long rbmap[32] = {
+ 0x80000000, 0x40000000, 0x20000000, 0x10000000,
+ 0x08000000, 0x04000000, 0x02000000, 0x01000000,
+ 0x00800000, 0x00400000, 0x00200000, 0x00100000,
+ 0x00080000, 0x00040000, 0x00020000, 0x00010000,
+ 0x00008000, 0x00004000, 0x00002000, 0x00001000,
+ 0x00000800, 0x00000400, 0x00000200, 0x00000100,
+ 0x00000080, 0x00000040, 0x00000020, 0x00000010,
+ 0x00000008, 0x00000004, 0x00000002, 0x00000001 };
+
+
+/* hpGetPlane -- gets a bitmap representing one plane of pDraw
+ * A helper used for XY format GetImage
+ * No clever strategy here, we grab a scanline at a time, pull out the
+ * bits and then stuff them in a 1 bit deep map.
+ * This is a significantly modified version of miGetPlane. The arguments
+ * are different, as here we pass in the start address within the source
+ * pixmap, instead of the sx and sy within the pixmap, and we pass in the
+ * stride that will get us to the next line - either the pixmap width or
+ * the screen width depending on whether the pixmap is in framebuffer or
+ * main memory.
+ */
+unsigned long *
+hpGetPlane(pDraw, planeNum, startAddr, w, h, stride, result)
+ DrawablePtr pDraw;
+ int planeNum; /* number of the bitPlane */
+ unsigned char * startAddr;
+ int w, h;
+ int stride; /* stride to get to next line */
+ unsigned long *result;
+{
+ register int i, j;
+ int k, widthInBytes;
+ register CARD32 bits;
+ CARD8 *pCharsOut;
+ register unsigned char *pixAddr;
+ register unsigned char pixel;
+
+ if (pDraw->depth != 8)
+ FatalError("hpGetPlane: invalid depth\n");
+ widthInBytes = PixmapBytePad(w, 1);
+ if (!result)
+ result = (unsigned long *)xalloc(h * widthInBytes);
+
+ for (i = 0; i < h; i++)
+ {
+ pCharsOut = ((unsigned char *)result) + i * widthInBytes;
+ pixAddr = startAddr + i * (stride);
+ k = 0;
+ bits = 0;
+ for (j = 0; j < w; j++)
+ {
+ pixel = *pixAddr++;
+ if (BITMAP_BIT_ORDER == LSBFirst)
+ bits = (bits << 1) | ((pixel >> planeNum) & 1);
+ else
+ {
+#ifdef notdef /* more portable, but slower code */
+ bits |= ((pixel >> planeNum) & 1) << ((BITMAP_SCANLINE_UNIT - 1)
+ - k);
+#else /* faster, but less portable code */
+ if (pixel & masks[planeNum]) bits |= rbmap[k];
+#endif
+ }
+ k++;
+ if (BITMAP_SCANLINE_UNIT == k)
+ {
+ switch (BITMAP_SCANLINE_UNIT)
+ {
+ case 8:
+ *pCharsOut++ = (CARD8)bits; break;
+ case 16:
+ *(CARD16 *)pCharsOut = (CARD16) bits;
+ pCharsOut += sizeof(CARD16);
+ break;
+ case 32:
+ *(CARD32 *)pCharsOut = bits;
+ pCharsOut += sizeof(CARD32);
+ break;
+ }
+ k = bits = 0;
+ }
+ }
+
+#define ORBITs(type,ptr,bits) *(type *)ptr = (type)bits
+
+ if (k) /* trailing bits */
+ {
+ switch (BITMAP_SCANLINE_UNIT)
+ {
+ case 8:
+ ORBITs(CARD8, pCharsOut,bits);
+ break;
+ case 16:
+ ORBITs(CARD16,pCharsOut,bits);
+ break;
+ case 32:
+ ORBITs(CARD32,pCharsOut,bits); break;
+ }
+ }
+ }
+ return(result);
+}
+
+/* hpGetByteImage -- public entry for the GetImage Request
+ * We're getting the image into a memory buffer.
+ * Since we know what an hp byte-deep framebuffer looks like, we can do
+ * this much faster than miGetImage.
+ *
+ * two different strategies are used, depending on whether we're getting the
+ * image in Z format or XY format
+ * Z format:
+ * For each row
+ * For each column
+ * Read the pixel into pdst
+ * If planeMask is not all ones (yech)
+ * For each row
+ * For each column
+ * Mask the unwanted bits
+ *
+ * XY format:
+ * Call hpGetBytePlane (see above in this file)
+ *
+ *
+ */
+void
+hpGetByteImage(pDraw, sx, sy, w, h, format, planeMask, pdstLine)
+ DrawablePtr pDraw;
+ int sx, sy, w, h;
+ unsigned int format;
+ unsigned long planeMask;
+ pointer pdstLine;
+{
+ int depth, i, linelength;
+
+ unsigned char *pSrc;
+ int widthSrc;
+ unsigned int screenPlanes = getPlanesMask(pDraw->pScreen);
+
+ if ((w == 0) || (h == 0))
+ return;
+
+ depth = pDraw->depth;
+ switch (depth)
+ {
+ case 1:
+ mfbGetImage(pDraw, sx, sy, w, h, format, planeMask, pdstLine);
+ return;
+ case 8:
+ break;
+ default:
+ miGetImage(pDraw, sx, sy, w, h, format, planeMask, pdstLine);
+ return;
+ }
+
+ if (!(planeMask &= screenPlanes))
+ return;
+
+ linelength = PixmapBytePad(w, depth);
+ if (pDraw->type == DRAWABLE_WINDOW)
+ {
+ sx += pDraw->x;
+ sy += pDraw->y;
+ widthSrc = (int) getPrivScreenPtr(pDraw->pScreen)->stride;
+ pSrc = (unsigned char *)
+ getPrivScreenPtr(pDraw->pScreen)->bits + sx + sy * widthSrc;
+ }
+ else
+ { /* we're getting from a pixmap */
+ hpPrivPixmapPtr pPrivPix =
+ (hpPrivPixmapPtr)((PixmapPtr) pDraw)->devPrivate.ptr;
+
+ if (((PixmapPtr)pDraw)->devKind == PIXMAP_FRAME_BUFFER)
+ {
+ sx += pPrivPix->pChunk->x;
+ sy += pPrivPix->pChunk->y;
+ widthSrc = (int) getPrivScreenPtr(pDraw->pScreen)->stride;
+ pSrc = (unsigned char *)
+ getPrivScreenPtr(pDraw->pScreen)->bits + sx + sy * widthSrc;
+ }
+ else
+ { /* main memory pixmap */
+ widthSrc = (int) pPrivPix->stride;
+ pSrc = (unsigned char *) pPrivPix->bits + sx + sy * widthSrc;
+ }
+ }
+ if (format == ZPixmap)
+ {
+ WAIT_READY_TO_RENDER(pDraw->pScreen);
+
+ for (i = 0; i < h; i++)
+ { /* for each row */
+ register int j;
+ register unsigned char *pByteDst;
+ register unsigned char *pSrcByte;
+
+ pSrcByte = pSrc + i * widthSrc;
+ pByteDst = ((unsigned char *)pdstLine) + i * linelength;
+
+ for (j = 0; j < w; j++)
+ { /* for each pixel in row */
+ *pByteDst++ = *pSrcByte++ & planeMask;
+ }
+ }
+ }
+ else
+ {
+ int planes = Ones(screenPlanes);
+ int planeSize = PixmapBytePad(w, 1) * h;
+
+ for (i = planes - 1; i >= 0; i--)
+ if (planeMask & (1 << i))
+ {
+ (void) hpGetPlane(pDraw, i, pSrc, w, h, widthSrc, pdstLine);
+ pdstLine += planeSize;
+ }
+ }
+}
+
+
+/* hpPutByteImage -- public entry for the PutImage Request
+ * This is here to try to make XY pixmap puts work reasonably on
+ * our byte-deep framebuffers.
+ */
+void
+hpPutByteImage(pDraw, pGC, depth, dstx, dsty, w, h, srcOffset, format, pImage)
+ DrawablePtr pDraw;
+ GCPtr pGC;
+ int depth, dstx, dsty, w, h, srcOffset;
+ unsigned int format;
+ unsigned char *pImage;
+{
+ unsigned long planeMask = pGC->planemask;
+ int i;
+ unsigned int planeSize, srcStride, widthDst, garbageBits, bits;
+ CARD8 *psrc, *psrcLine, *psrcBase, *pdstBase, *pdstLine, *pdst;
+ RegionPtr pRegion;
+ unsigned int alu;
+ register BoxPtr pBox;
+ unsigned int numBoxes;
+ CARD8 srcByte;
+ unsigned int rows;
+ unsigned int pixels;
+
+ if ((w == 0) || (h == 0))
+ return;
+
+ planeMask &= getPlanesMask(pDraw->pScreen);
+
+ if ((format == ZPixmap) ||
+ ((pDraw->type == DRAWABLE_PIXMAP) &&
+ (((PixmapPtr)(pDraw))->devKind == PIXMAP_HOST_MEMORY)))
+ {
+ /*
+ * mi seems to work for ZPixmaps
+ * and my code doesn't work for main-memory pixmaps since
+ * I rely on the hardware plane-enable
+ */
+ miPutImage(pDraw, pGC, depth, dstx, dsty, w, h, srcOffset,
+ format, pImage);
+ return;
+ }
+
+ alu = pGC->alu;
+ pRegion = ((cfbPrivGC *)
+ (pGC->devPrivates[cfbGCPrivateIndex].ptr))->pCompositeClip;
+ pBox = REGION_RECTS(pRegion);
+ numBoxes = REGION_NUM_RECTS(pRegion);
+
+ dstx += pDraw->x;
+ dsty += pDraw->y;
+ if (pDraw->type == DRAWABLE_WINDOW)
+ {
+ widthDst = (unsigned int)
+ getPrivScreenPtr(pDraw->pScreen)->stride;
+ pdstBase = (CARD8 *)
+ getPrivScreenPtr(pDraw->pScreen)->bits;
+ }
+ else
+ {
+ widthDst = (unsigned int)
+ (((hpPrivPixmapPtr)(((PixmapPtr)pDraw)->devPrivate.ptr))->stride);
+ pdstBase = (CARD8 *)
+ (((hpPrivPixmapPtr)(((PixmapPtr)pDraw)->devPrivate.ptr))->bits);
+ }
+
+ srcStride = PixmapBytePad(w, 1);
+ planeSize = h * srcStride;
+
+ while(numBoxes--)
+ {
+ int clippedWidth = w - srcOffset;
+ int clippedHeight = h;
+ int startx = dstx;
+ int starty = dsty;
+ int dx = 0, dy = 0;
+ CARD8 *pdstBox = pdstBase;
+
+ psrcBase = (CARD8 *)pImage;
+
+ /*
+ * clip the height
+ */
+ if (dsty < pBox->y1)
+ {
+ dy = pBox->y1 - dsty;
+ clippedHeight -= dy;
+ if (clippedHeight <= 0)
+ {
+ pBox++;
+ continue;
+ }
+ starty = pBox->y1;
+ }
+ if (starty+clippedHeight > pBox->y2)
+ {
+ clippedHeight = pBox->y2 - starty;
+ if (clippedHeight <= 0)
+ {
+ pBox++;
+ continue;
+ }
+ }
+ /*
+ * clip the width
+ */
+ if (dstx < pBox->x1)
+ {
+ dx = pBox->x1 - dstx;
+ clippedWidth -= dx;
+ if (clippedWidth <= 0)
+ {
+ pBox++;
+ continue;
+ }
+ startx = pBox->x1;
+ }
+ if (startx+clippedWidth > pBox->x2)
+ {
+ clippedWidth = pBox->x2 - startx;
+ if (clippedWidth <= 0)
+ {
+ pBox++;
+ continue;
+ }
+ }
+
+ if (!clippedWidth || !clippedHeight)
+ {
+ pBox++;
+ continue;
+ }
+
+ /*
+ * get address of the first destination pixel
+ */
+ pdstBox += startx + starty * widthDst;
+ /*
+ * get address of the first source bytes with useful bits
+ */
+ psrcBase += srcStride * dy + (srcOffset + dx) / 8;
+ garbageBits = (srcOffset + dx) % 8;
+
+ if (depth == 1)
+ {
+ /*
+ * XYBitmap code
+ */
+ unsigned int fore = pGC->fgPixel;
+ unsigned int back = pGC->bgPixel;
+
+ rows = clippedHeight;
+ pixels = clippedWidth;
+ /*
+ * write enable the one plane we want to alter
+ */
+ SET_REGISTERS_FOR_WRITING(pDraw->pScreen, planeMask, alu);
+
+ psrcLine = psrcBase;
+ pdstLine = pdstBox;
+ while (rows--)
+ {
+ psrc = psrcLine;
+ pdst = pdstLine;
+ srcByte = *psrc++ << garbageBits;
+ bits = 8 - garbageBits;
+
+ while (pixels--)
+ {
+ if (srcByte & 0x80)
+ *pdst++ = fore;
+ else
+ *pdst++ = back;
+ if (--bits)
+ srcByte <<= 1;
+ else
+ {
+ bits = 8;
+ srcByte = *psrc++;
+ }
+ }
+ pixels = clippedWidth;
+ psrcLine += srcStride;
+ pdstLine += widthDst;
+ }
+ }
+ else
+ {
+ for (i = 1 << (depth - 1); i > 0; i >>= 1, psrcBase += planeSize)
+ {
+ if (i & planeMask)
+ {
+ rows = clippedHeight;
+ pixels = clippedWidth;
+
+ /*
+ * write enable the one plane we want to alter
+ */
+ SET_REGISTERS_FOR_WRITING(pDraw->pScreen, i, alu);
+
+ psrcLine = psrcBase;
+ pdstLine = pdstBox;
+ while (rows--)
+ {
+ psrc = psrcLine;
+ pdst = pdstLine;
+ srcByte = *psrc++ << garbageBits;
+ bits = 8 - garbageBits;
+
+ while (pixels--)
+ {
+ if (srcByte & 0x80)
+ *pdst++ = 0xff;
+ else
+ *pdst++ = 0x00;
+ if (--bits)
+ srcByte <<= 1;
+ else
+ {
+ bits = 8;
+ srcByte = *psrc++;
+ }
+ }
+ pixels = clippedWidth;
+ psrcLine += srcStride;
+ pdstLine += widthDst;
+ }
+ }
+ }
+ }
+ pBox++;
+ }
+ SET_REGISTERS_FOR_WRITING(pDraw->pScreen, 0xff, alu);
+}
+