#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 "servermd.h"
RegionPtr
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;
RegionPtr prgnSrcClip;
RegionPtr prgnExposed;
int realSrcClip = 0;
int srcx, srcy, dstx, dsty, i, j, y, width, height,
xMin, xMax, yMin, yMax;
unsigned int *ordering;
int numRects;
BoxPtr boxes;
srcx = xIn + pSrcDrawable->x;
srcy = yIn + pSrcDrawable->y;
if (pDstDrawable->type == DRAWABLE_WINDOW &&
!((WindowPtr)pDstDrawable)->realized)
return (RegionPtr)NULL;
if (pSrcDrawable->type == DRAWABLE_PIXMAP)
{
BoxRec box;
box.x1 = pSrcDrawable->x;
box.y1 = pSrcDrawable->y;
box.x2 = pSrcDrawable->x + (int) pSrcDrawable->width;
box.y2 = pSrcDrawable->y + (int) pSrcDrawable->height;
prgnSrcClip = REGION_CREATE(pGC->pScreen, &box, 1);
realSrcClip = 1;
}
else
{
if (pGC->subWindowMode == IncludeInferiors) {
prgnSrcClip = NotClippedByChildren ((WindowPtr) pSrcDrawable);
realSrcClip = 1;
} else
prgnSrcClip = &((WindowPtr)pSrcDrawable)->clipList;
}
srcBox.x1 = srcx;
srcBox.y1 = srcy;
srcBox.x2 = srcx + widthSrc;
srcBox.y2 = srcy + heightSrc;
dstx = xOut;
dsty = yOut;
if (pGC->miTranslate)
{
dstx += pDstDrawable->x;
dsty += pDstDrawable->y;
}
pptFirst = ppt = (DDXPointPtr)
ALLOCATE_LOCAL(heightSrc * sizeof(DDXPointRec));
pwidthFirst = pwidth = (unsigned int *)
ALLOCATE_LOCAL(heightSrc * sizeof(unsigned int));
numRects = REGION_NUM_RECTS(prgnSrcClip);
boxes = REGION_RECTS(prgnSrcClip);
ordering = (unsigned int *)
ALLOCATE_LOCAL(numRects * sizeof(unsigned int));
if(!pptFirst || !pwidthFirst || !ordering)
{
if (ordering)
DEALLOCATE_LOCAL(ordering);
if (pwidthFirst)
DEALLOCATE_LOCAL(pwidthFirst);
if (pptFirst)
DEALLOCATE_LOCAL(pptFirst);
return (RegionPtr)NULL;
}
if ((pSrcDrawable != pDstDrawable) &&
((pGC->subWindowMode != IncludeInferiors) ||
(pSrcDrawable->type == DRAWABLE_PIXMAP) ||
(pDstDrawable->type == DRAWABLE_PIXMAP)))
for (i=0; i < numRects; i++)
ordering[i] = i;
else {
if (dsty <= srcBox.y1) {
if (dstx <= srcBox.x1)
for (i=0; i < numRects; i++)
ordering[i] = i;
else {
for (i=0, j=1, xMax=0; i < numRects; j=i+1, xMax=i) {
y=boxes[i].y1;
while ((j < numRects) && (boxes[j].y1 == y))
j++;
for (j-- ; j >= xMax; j--, i++)
ordering[i] = j;
}
}
}
else {
if (dstx < srcBox.x1) {
for (i=numRects-1, j=i-1, yMin=i, yMax=0;
i >= 0;
j=i-1, yMin=i) {
y=boxes[i].y1;
while ((j >= 0) && (boxes[j].y1 == y))
j--;
for (j++ ; j <= yMin; j++, i--, yMax++)
ordering[yMax] = j;
}
}
else
for (i=0, j=numRects-1; i < numRects; i++, j--)
ordering[i] = j;
}
}
for(i = 0; i < numRects; i++)
{
prect = &boxes[ordering[i]];
xMin = max(prect->x1, srcBox.x1);
xMax = min(prect->x2, srcBox.x2);
yMin = max(prect->y1, srcBox.y1);
yMax = min(prect->y2, srcBox.y2);
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 = (unsigned int *)xalloc(height * PixmapBytePad(width,
pSrcDrawable->depth));
if (pbits)
{
(*pSrcDrawable->pScreen->GetSpans)(pSrcDrawable, width, pptFirst,
(int *)pwidthFirst, height, (char *)pbits);
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->ops->SetSpans)(pDstDrawable, pGC, (char *)pbits, pptFirst,
(int *)pwidthFirst, height, TRUE);
xfree(pbits);
}
}
prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC, xIn, yIn,
widthSrc, heightSrc, xOut, yOut, (unsigned long)0);
if(realSrcClip)
REGION_DESTROY(pGC->pScreen, prgnSrcClip);
DEALLOCATE_LOCAL(ordering);
DEALLOCATE_LOCAL(pwidthFirst);
DEALLOCATE_LOCAL(pptFirst);
return prgnExposed;
}
static
MiBits *
miGetPlane(
DrawablePtr pDraw,
int planeNum,
int sx,
int sy,
int w,
int h,
MiBits *result)
{
int i, j, k, width, bitsPerPixel, widthInBytes;
DDXPointRec pt = {0, 0};
MiBits pixel;
MiBits bit;
unsigned char *pCharsOut = NULL;
#if BITMAP_SCANLINE_UNIT == 8
#define OUT_TYPE unsigned char
#endif
#if BITMAP_SCANLINE_UNIT == 16
#define OUT_TYPE CARD16
#endif
#if BITMAP_SCANLINE_UNIT == 32
#define OUT_TYPE CARD32
#endif
#if BITMAP_SCANLINE_UNIT == 64
#define OUT_TYPE CARD64
#endif
OUT_TYPE *pOut;
int delta = 0;
sx += pDraw->x;
sy += pDraw->y;
widthInBytes = BitmapBytePad(w);
if(!result)
result = (MiBits *)xalloc(h * widthInBytes);
if (!result)
return (MiBits *)NULL;
bitsPerPixel = pDraw->bitsPerPixel;
bzero((char *)result, h * widthInBytes);
pOut = (OUT_TYPE *) result;
if(bitsPerPixel == 1)
{
pCharsOut = (unsigned char *) result;
width = w;
}
else
{
delta = (widthInBytes / (BITMAP_SCANLINE_UNIT / 8)) -
(w / BITMAP_SCANLINE_UNIT);
width = 1;
#if IMAGE_BYTE_ORDER == MSBFirst
planeNum += (32 - bitsPerPixel);
#endif
}
pt.y = sy;
for (i = h; --i >= 0; pt.y++)
{
pt.x = sx;
if(bitsPerPixel == 1)
{
(*pDraw->pScreen->GetSpans)(pDraw, width, &pt, &width, 1,
(char *)pCharsOut);
pCharsOut += widthInBytes;
}
else
{
k = 0;
for(j = w; --j >= 0; pt.x++)
{
(*pDraw->pScreen->GetSpans)(pDraw, width, &pt, &width, 1,
(char *)&pixel);
bit = (pixel >> planeNum) & 1;
#ifndef XFree86Server
#if BITMAP_BIT_ORDER == LSBFirst
bit <<= k;
#else
bit <<= ((BITMAP_SCANLINE_UNIT - 1) - k);
#endif
#else
if (screenInfo.bitmapBitOrder == LSBFirst)
bit <<= k;
else
bit <<= ((screenInfo.bitmapScanlineUnit - 1) -
(k % screenInfo.bitmapScanlineUnit)) +
((k / screenInfo.bitmapScanlineUnit) *
screenInfo.bitmapScanlineUnit);
#endif
*pOut |= (OUT_TYPE) bit;
k++;
if (k == BITMAP_SCANLINE_UNIT)
{
pOut++;
k = 0;
}
}
pOut += delta;
}
}
return(result);
}
void
miOpqStipDrawable(pDraw, pGC, prgnSrc, pbits, srcx, w, h, dstx, dsty)
DrawablePtr pDraw;
GCPtr pGC;
RegionPtr prgnSrc;
MiBits *pbits;
int srcx, w, h, dstx, dsty;
{
int oldfill, i;
unsigned long oldfg;
int *pwidth, *pwidthFirst;
ChangeGCVal gcv[6];
PixmapPtr pStipple, pPixmap;
DDXPointRec oldOrg;
GCPtr pGCT;
DDXPointPtr ppt, pptFirst;
xRectangle rect;
RegionPtr prgnSrcClip;
pPixmap = (*pDraw->pScreen->CreatePixmap)
(pDraw->pScreen, w + srcx, h, 1);
if (!pPixmap)
return;
pGCT = GetScratchGC(1, pDraw->pScreen);
if (!pGCT)
{
(*pDraw->pScreen->DestroyPixmap)(pPixmap);
return;
}
gcv[0].val = 0;
dixChangeGC(NullClient, pGCT, GCBackground, NULL, gcv);
ValidateGC((DrawablePtr)pPixmap, pGCT);
miClearDrawable((DrawablePtr)pPixmap, pGCT);
ppt = pptFirst = (DDXPointPtr)ALLOCATE_LOCAL(h * sizeof(DDXPointRec));
pwidth = pwidthFirst = (int *)ALLOCATE_LOCAL(h * sizeof(int));
if(!pptFirst || !pwidthFirst)
{
if (pwidthFirst) DEALLOCATE_LOCAL(pwidthFirst);
if (pptFirst) DEALLOCATE_LOCAL(pptFirst);
FreeScratchGC(pGCT);
return;
}
prgnSrcClip = REGION_CREATE(pGCT->pScreen, NULL, 0);
REGION_COPY(pGCT->pScreen, prgnSrcClip, prgnSrc);
REGION_TRANSLATE(pGCT->pScreen, prgnSrcClip, srcx, 0);
(*pGCT->funcs->ChangeClip)(pGCT, CT_REGION, prgnSrcClip, 0);
ValidateGC((DrawablePtr)pPixmap, pGCT);
for(i = 0; i < h; i++)
{
ppt->x = 0;
ppt++->y = i;
*pwidth++ = w + srcx;
}
(*pGCT->ops->SetSpans)((DrawablePtr)pPixmap, pGCT, (char *)pbits,
pptFirst, pwidthFirst, h, TRUE);
DEALLOCATE_LOCAL(pwidthFirst);
DEALLOCATE_LOCAL(pptFirst);
oldfill = pGC->fillStyle;
pStipple = pGC->stipple;
if(pStipple)
pStipple->refcnt++;
oldOrg = pGC->patOrg;
gcv[0].val = FillStippled;
gcv[1].ptr = pPixmap;
gcv[2].val = dstx - srcx;
gcv[3].val = dsty;
dixChangeGC(NullClient, pGC,
GCFillStyle | GCStipple | GCTileStipXOrigin | GCTileStipYOrigin,
NULL, gcv);
ValidateGC(pDraw, pGC);
rect.x = dstx;
rect.y = dsty;
rect.width = w;
rect.height = h;
(*pGC->ops->PolyFillRect)(pDraw, pGC, 1, &rect);
gcv[0].val = GXinvert;
dixChangeGC(NullClient, pGCT, GCFunction, NULL, gcv);
ValidateGC((DrawablePtr)pPixmap, pGCT);
(*pGCT->ops->CopyArea)((DrawablePtr)pPixmap, (DrawablePtr)pPixmap,
pGCT, 0, 0, w + srcx, h, 0, 0);
oldfg = pGC->fgPixel;
gcv[0].val = pGC->bgPixel;
gcv[1].val = oldfg;
gcv[2].ptr = pPixmap;
dixChangeGC(NullClient, pGC, GCForeground | GCBackground | GCStipple,
NULL, gcv);
ValidateGC(pDraw, pGC);
rect.x = dstx;
rect.y = dsty;
rect.width = w;
rect.height = h;
(*pGC->ops->PolyFillRect)(pDraw, pGC, 1, &rect);
if(pStipple)
pStipple->refcnt--;
gcv[0].val = oldfg;
gcv[1].val = pGC->fgPixel;
gcv[2].val = oldfill;
gcv[3].ptr = pStipple;
gcv[4].val = oldOrg.x;
gcv[5].val = oldOrg.y;
dixChangeGC(NullClient, pGC,
GCForeground | GCBackground | GCFillStyle | GCStipple |
GCTileStipXOrigin | GCTileStipYOrigin, NULL, gcv);
ValidateGC(pDraw, pGC);
(*pGCT->funcs->ChangeClip)(pGCT, CT_NONE, NULL, 0);
FreeScratchGC(pGCT);
(*pDraw->pScreen->DestroyPixmap)(pPixmap);
}
RegionPtr
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;
unsigned long bitPlane;
{
MiBits *ptile;
BoxRec box;
RegionPtr prgnSrc, prgnExposed;
box.x1 = srcx + pSrcDrawable->x;
box.y1 = srcy + pSrcDrawable->y;
box.x2 = box.x1 + width;
box.y2 = box.y1 + height;
if (box.x1 < pSrcDrawable->x)
box.x1 = pSrcDrawable->x;
if (box.y1 < pSrcDrawable->y)
box.y1 = pSrcDrawable->y;
if (box.x2 > pSrcDrawable->x + (int) pSrcDrawable->width)
box.x2 = pSrcDrawable->x + (int) pSrcDrawable->width;
if (box.y2 > pSrcDrawable->y + (int) pSrcDrawable->height)
box.y2 = pSrcDrawable->y + (int) pSrcDrawable->height;
if (box.x1 > box.x2)
box.x2 = box.x1;
if (box.y1 > box.y2)
box.y2 = box.y1;
prgnSrc = REGION_CREATE(pGC->pScreen, &box, 1);
if (pSrcDrawable->type != DRAWABLE_PIXMAP) {
if (pGC->subWindowMode == IncludeInferiors)
{
RegionPtr clipList = NotClippedByChildren ((WindowPtr) pSrcDrawable);
REGION_INTERSECT(pGC->pScreen, prgnSrc, prgnSrc, clipList);
REGION_DESTROY(pGC->pScreen, clipList);
} else
REGION_INTERSECT(pGC->pScreen, prgnSrc, prgnSrc,
&((WindowPtr)pSrcDrawable)->clipList);
}
box = *REGION_EXTENTS(pGC->pScreen, prgnSrc);
REGION_TRANSLATE(pGC->pScreen, prgnSrc, -box.x1, -box.y1);
if ((box.x2 > box.x1) && (box.y2 > box.y1))
{
box.x1 -= pSrcDrawable->x;
box.x2 -= pSrcDrawable->x;
box.y1 -= pSrcDrawable->y;
box.y2 -= pSrcDrawable->y;
ptile = miGetPlane(pSrcDrawable, ffs(bitPlane) - 1,
box.x1, box.y1,
box.x2 - box.x1, box.y2 - box.y1,
(MiBits *) NULL);
if (ptile)
{
miOpqStipDrawable(pDstDrawable, pGC, prgnSrc, ptile, 0,
box.x2 - box.x1, box.y2 - box.y1,
dstx + box.x1 - srcx, dsty + box.y1 - srcy);
xfree(ptile);
}
}
prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC, srcx, srcy,
width, height, dstx, dsty, bitPlane);
REGION_DESTROY(pGC->pScreen, prgnSrc);
return prgnExposed;
}
void
miGetImage(pDraw, sx, sy, w, h, format, planeMask, pDst)
DrawablePtr pDraw;
int sx, sy, w, h;
unsigned int format;
unsigned long planeMask;
char * pDst;
{
unsigned char depth;
int i, linelength, width, srcx, srcy;
DDXPointRec pt = {0, 0};
XID gcv[2];
PixmapPtr pPixmap = (PixmapPtr)NULL;
GCPtr pGC = NULL;
depth = pDraw->depth;
if(format == ZPixmap)
{
if ( (((1<<depth)-1)&planeMask) != (1<<depth)-1 )
{
xPoint pt;
pGC = GetScratchGC(depth, pDraw->pScreen);
if (!pGC)
return;
pPixmap = (*pDraw->pScreen->CreatePixmap)
(pDraw->pScreen, w, 1, depth);
if (!pPixmap)
{
FreeScratchGC(pGC);
return;
}
ValidateGC((DrawablePtr)pPixmap, pGC);
pt.x = pt.y = 0;
width = w;
(*pGC->ops->FillSpans)((DrawablePtr)pPixmap, pGC, 1, &pt, &width,
TRUE);
gcv[0] = (XID)planeMask;
DoChangeGC(pGC, GCPlaneMask, gcv, 0);
ValidateGC((DrawablePtr)pPixmap, pGC);
}
linelength = PixmapBytePad(w, depth);
srcx = sx + pDraw->x;
srcy = sy + pDraw->y;
for(i = 0; i < h; i++)
{
pt.x = srcx;
pt.y = srcy + i;
width = w;
(*pDraw->pScreen->GetSpans)(pDraw, w, &pt, &width, 1, pDst);
if (pPixmap)
{
pt.x = 0;
pt.y = 0;
width = w;
(*pGC->ops->SetSpans)((DrawablePtr)pPixmap, pGC, pDst,
&pt, &width, 1, TRUE);
(*pDraw->pScreen->GetSpans)((DrawablePtr)pPixmap, w, &pt,
&width, 1, pDst);
}
pDst += linelength;
}
if (pPixmap)
{
(*pGC->pScreen->DestroyPixmap)(pPixmap);
FreeScratchGC(pGC);
}
}
else
{
(void) miGetPlane(pDraw, ffs(planeMask) - 1, sx, sy, w, h,
(MiBits *)pDst);
}
}
void
miPutImage(pDraw, pGC, depth, x, y, w, h, leftPad, format, pImage)
DrawablePtr pDraw;
GCPtr pGC;
int depth, x, y, w, h, leftPad;
int format;
char *pImage;
{
DDXPointPtr pptFirst, ppt;
int *pwidthFirst, *pwidth;
RegionPtr prgnSrc;
BoxRec box;
unsigned long oldFg, oldBg;
XID gcv[3];
unsigned long oldPlanemask;
unsigned long i;
long bytesPer;
if (!w || !h)
return;
switch(format)
{
case XYBitmap:
box.x1 = 0;
box.y1 = 0;
box.x2 = w;
box.y2 = h;
prgnSrc = REGION_CREATE(pGC->pScreen, &box, 1);
miOpqStipDrawable(pDraw, pGC, prgnSrc, (MiBits *) pImage,
leftPad, w, h, x, y);
REGION_DESTROY(pGC->pScreen, prgnSrc);
break;
case XYPixmap:
depth = pGC->depth;
oldPlanemask = pGC->planemask;
oldFg = pGC->fgPixel;
oldBg = pGC->bgPixel;
gcv[0] = (XID)~0;
gcv[1] = (XID)0;
DoChangeGC(pGC, GCForeground | GCBackground, gcv, 0);
bytesPer = (long)h * BitmapBytePad(w + leftPad);
for (i = 1 << (depth-1); i != 0; i >>= 1, pImage += bytesPer)
{
if (i & oldPlanemask)
{
gcv[0] = (XID)i;
DoChangeGC(pGC, GCPlaneMask, gcv, 0);
ValidateGC(pDraw, pGC);
(*pGC->ops->PutImage)(pDraw, pGC, 1, x, y, w, h, leftPad,
XYBitmap, (char *)pImage);
}
}
gcv[0] = (XID)oldPlanemask;
gcv[1] = (XID)oldFg;
gcv[2] = (XID)oldBg;
DoChangeGC(pGC, GCPlaneMask | GCForeground | GCBackground, gcv, 0);
ValidateGC(pDraw, pGC);
break;
case ZPixmap:
ppt = pptFirst = (DDXPointPtr)ALLOCATE_LOCAL(h * sizeof(DDXPointRec));
pwidth = pwidthFirst = (int *)ALLOCATE_LOCAL(h * sizeof(int));
if(!pptFirst || !pwidthFirst)
{
if (pwidthFirst)
DEALLOCATE_LOCAL(pwidthFirst);
if (pptFirst)
DEALLOCATE_LOCAL(pptFirst);
return;
}
if (pGC->miTranslate)
{
x += pDraw->x;
y += pDraw->y;
}
for(i = 0; i < h; i++)
{
ppt->x = x;
ppt->y = y + i;
ppt++;
*pwidth++ = w;
}
(*pGC->ops->SetSpans)(pDraw, pGC, (char *)pImage, pptFirst,
pwidthFirst, h, TRUE);
DEALLOCATE_LOCAL(pwidthFirst);
DEALLOCATE_LOCAL(pptFirst);
break;
}
}