xserver-multidpi/cfb/cfbbitblt.c

1456 lines
38 KiB
C

/*
* cfb copy area
*/
/*
Copyright 1989, 1998 The Open Group
Permission to use, copy, modify, distribute, and sell this software and its
documentation for any purpose is hereby granted without fee, provided that
the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of The Open Group shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from The Open Group.
Author: Keith Packard
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <stdlib.h>
#include <X11/X.h>
#include <X11/Xmd.h>
#include <X11/Xproto.h>
#include "gcstruct.h"
#include "windowstr.h"
#include "scrnintstr.h"
#include "pixmapstr.h"
#include "regionstr.h"
#include "mi.h"
#include "cfb.h"
#include "cfbmskbits.h"
#include "cfb8bit.h"
#include "fastblt.h"
#define MFB_CONSTS_ONLY
#include "maskbits.h"
#if PSZ == 8
#define cfbCopyPlane1toN cfbCopyPlane1to8
#define cfbCopyPlaneNto1 cfbCopyPlane8to1
#else
static unsigned int FgPixel, BgPixel;
# if PSZ == 16
#define cfbCopyPlane1toN cfbCopyPlane1to16
#define cfbCopyPlaneNto1 cfbCopyPlane16to1
# endif
# if PSZ == 24
#define cfbCopyPlane1toN cfbCopyPlane1to24
#define cfbCopyPlaneNto1 cfbCopyPlane24to1
# endif
# if PSZ == 32
#define cfbCopyPlane1toN cfbCopyPlane1to32
#define cfbCopyPlaneNto1 cfbCopyPlane32to1
# endif
#endif
/* cfbBitBltcfb == cfbCopyPlaneExpand */
RegionPtr
cfbBitBlt (
register DrawablePtr pSrcDrawable,
register DrawablePtr pDstDrawable,
GC *pGC,
int srcx, int srcy,
int width, int height,
int dstx, int dsty,
void (*doBitBlt)(
DrawablePtr /*pSrc*/,
DrawablePtr /*pDst*/,
int /*alu*/,
RegionPtr /*prgnDst*/,
DDXPointPtr /*pptSrc*/,
unsigned long /*planemask*/),
unsigned long bitPlane)
{
RegionPtr prgnSrcClip = NULL; /* may be a new region, or just a copy */
Bool freeSrcClip = FALSE;
RegionPtr prgnExposed;
RegionRec rgnDst;
DDXPointPtr pptSrc;
register DDXPointPtr ppt;
register BoxPtr pbox;
int i;
register int dx;
register int dy;
xRectangle origSource;
DDXPointRec origDest;
int numRects;
BoxRec fastBox;
int fastClip = 0; /* for fast clipping with pixmap source */
int fastExpose = 0; /* for fast exposures with pixmap source */
origSource.x = srcx;
origSource.y = srcy;
origSource.width = width;
origSource.height = height;
origDest.x = dstx;
origDest.y = dsty;
if ((pSrcDrawable != pDstDrawable) &&
pSrcDrawable->pScreen->SourceValidate)
{
(*pSrcDrawable->pScreen->SourceValidate) (pSrcDrawable, srcx, srcy, width, height);
}
srcx += pSrcDrawable->x;
srcy += pSrcDrawable->y;
/* clip the source */
if (pSrcDrawable->type == DRAWABLE_PIXMAP)
{
if ((pSrcDrawable == pDstDrawable) &&
(pGC->clientClipType == CT_NONE))
{
prgnSrcClip = cfbGetCompositeClip(pGC);
}
else
{
fastClip = 1;
}
}
else
{
if (pGC->subWindowMode == IncludeInferiors)
{
/*
* XFree86 DDX empties the border clip when the
* VT is inactive
*/
if (!((WindowPtr) pSrcDrawable)->parent &&
REGION_NOTEMPTY (pSrcDrawable->pScreen,
&((WindowPtr) pSrcDrawable)->borderClip))
{
/*
* special case bitblt from root window in
* IncludeInferiors mode; just like from a pixmap
*/
fastClip = 1;
}
else if ((pSrcDrawable == pDstDrawable) &&
(pGC->clientClipType == CT_NONE))
{
prgnSrcClip = cfbGetCompositeClip(pGC);
}
else
{
prgnSrcClip = NotClippedByChildren((WindowPtr)pSrcDrawable);
freeSrcClip = TRUE;
}
}
else
{
prgnSrcClip = &((WindowPtr)pSrcDrawable)->clipList;
}
}
fastBox.x1 = srcx;
fastBox.y1 = srcy;
fastBox.x2 = srcx + width;
fastBox.y2 = srcy + height;
/* Don't create a source region if we are doing a fast clip */
if (fastClip)
{
fastExpose = 1;
/*
* clip the source; if regions extend beyond the source size,
* make sure exposure events get sent
*/
if (fastBox.x1 < pSrcDrawable->x)
{
fastBox.x1 = pSrcDrawable->x;
fastExpose = 0;
}
if (fastBox.y1 < pSrcDrawable->y)
{
fastBox.y1 = pSrcDrawable->y;
fastExpose = 0;
}
if (fastBox.x2 > pSrcDrawable->x + (int) pSrcDrawable->width)
{
fastBox.x2 = pSrcDrawable->x + (int) pSrcDrawable->width;
fastExpose = 0;
}
if (fastBox.y2 > pSrcDrawable->y + (int) pSrcDrawable->height)
{
fastBox.y2 = pSrcDrawable->y + (int) pSrcDrawable->height;
fastExpose = 0;
}
}
else
{
REGION_INIT(pGC->pScreen, &rgnDst, &fastBox, 1);
REGION_INTERSECT(pGC->pScreen, &rgnDst, &rgnDst, prgnSrcClip);
}
dstx += pDstDrawable->x;
dsty += pDstDrawable->y;
if (pDstDrawable->type == DRAWABLE_WINDOW)
{
if (!((WindowPtr)pDstDrawable)->realized)
{
if (!fastClip)
REGION_UNINIT(pGC->pScreen, &rgnDst);
if (freeSrcClip)
REGION_DESTROY(pGC->pScreen, prgnSrcClip);
return NULL;
}
}
dx = srcx - dstx;
dy = srcy - dsty;
/* Translate and clip the dst to the destination composite clip */
if (fastClip)
{
RegionPtr cclip;
/* Translate the region directly */
fastBox.x1 -= dx;
fastBox.x2 -= dx;
fastBox.y1 -= dy;
fastBox.y2 -= dy;
/* If the destination composite clip is one rectangle we can
do the clip directly. Otherwise we have to create a full
blown region and call intersect */
/* XXX because CopyPlane uses this routine for 8-to-1 bit
* copies, this next line *must* also correctly fetch the
* composite clip from an mfb gc
*/
cclip = cfbGetCompositeClip(pGC);
if (REGION_NUM_RECTS(cclip) == 1)
{
BoxPtr pBox = REGION_RECTS(cclip);
if (fastBox.x1 < pBox->x1) fastBox.x1 = pBox->x1;
if (fastBox.x2 > pBox->x2) fastBox.x2 = pBox->x2;
if (fastBox.y1 < pBox->y1) fastBox.y1 = pBox->y1;
if (fastBox.y2 > pBox->y2) fastBox.y2 = pBox->y2;
/* Check to see if the region is empty */
if (fastBox.x1 >= fastBox.x2 || fastBox.y1 >= fastBox.y2)
{
REGION_NULL(pGC->pScreen, &rgnDst);
}
else
{
REGION_INIT(pGC->pScreen, &rgnDst, &fastBox, 1);
}
}
else
{
/* We must turn off fastClip now, since we must create
a full blown region. It is intersected with the
composite clip below. */
fastClip = 0;
REGION_INIT(pGC->pScreen, &rgnDst, &fastBox,1);
}
}
else
{
REGION_TRANSLATE(pGC->pScreen, &rgnDst, -dx, -dy);
}
if (!fastClip)
{
REGION_INTERSECT(pGC->pScreen, &rgnDst,
&rgnDst,
cfbGetCompositeClip(pGC));
}
/* Do bit blitting */
numRects = REGION_NUM_RECTS(&rgnDst);
if (numRects && width && height)
{
if(!(pptSrc = (DDXPointPtr)xalloc(numRects *
sizeof(DDXPointRec))))
{
REGION_UNINIT(pGC->pScreen, &rgnDst);
if (freeSrcClip)
REGION_DESTROY(pGC->pScreen, prgnSrcClip);
return NULL;
}
pbox = REGION_RECTS(&rgnDst);
ppt = pptSrc;
for (i = numRects; --i >= 0; pbox++, ppt++)
{
ppt->x = pbox->x1 + dx;
ppt->y = pbox->y1 + dy;
}
(*doBitBlt) (pSrcDrawable, pDstDrawable, pGC->alu, &rgnDst, pptSrc, pGC->planemask);
xfree(pptSrc);
}
prgnExposed = NULL;
if (pGC->fExpose)
{
/* Pixmap sources generate a NoExposed (we return NULL to do this) */
if (!fastExpose)
prgnExposed =
miHandleExposures(pSrcDrawable, pDstDrawable, pGC,
origSource.x, origSource.y,
(int)origSource.width,
(int)origSource.height,
origDest.x, origDest.y, bitPlane);
}
REGION_UNINIT(pGC->pScreen, &rgnDst);
if (freeSrcClip)
REGION_DESTROY(pGC->pScreen, prgnSrcClip);
return prgnExposed;
}
RegionPtr
cfbCopyPlaneReduce (
register DrawablePtr pSrcDrawable,
register DrawablePtr pDstDrawable,
GC *pGC,
int srcx, int srcy,
int width, int height,
int dstx, int dsty,
void (*doCopyPlane)(
DrawablePtr /*pSrc*/,
DrawablePtr /*pDst*/,
int /*alu*/,
RegionPtr /*prgnDst*/,
DDXPointPtr /*pptSrc*/,
unsigned long /*planemask*/,
unsigned long /*bitPlane*/),
unsigned long bitPlane)
{
RegionPtr prgnSrcClip = NULL; /* may be a new region, or just a copy */
Bool freeSrcClip = FALSE;
RegionPtr prgnExposed;
RegionRec rgnDst;
DDXPointPtr pptSrc;
register DDXPointPtr ppt;
register BoxPtr pbox;
int i;
register int dx;
register int dy;
xRectangle origSource;
DDXPointRec origDest;
int numRects;
BoxRec fastBox;
int fastClip = 0; /* for fast clipping with pixmap source */
int fastExpose = 0; /* for fast exposures with pixmap source */
origSource.x = srcx;
origSource.y = srcy;
origSource.width = width;
origSource.height = height;
origDest.x = dstx;
origDest.y = dsty;
if ((pSrcDrawable != pDstDrawable) &&
pSrcDrawable->pScreen->SourceValidate)
{
(*pSrcDrawable->pScreen->SourceValidate) (pSrcDrawable, srcx, srcy, width, height);
}
srcx += pSrcDrawable->x;
srcy += pSrcDrawable->y;
/* clip the source */
if (pSrcDrawable->type == DRAWABLE_PIXMAP)
{
if ((pSrcDrawable == pDstDrawable) &&
(pGC->clientClipType == CT_NONE))
{
prgnSrcClip = cfbGetCompositeClip(pGC);
}
else
{
fastClip = 1;
}
}
else
{
if (pGC->subWindowMode == IncludeInferiors)
{
/*
* XFree86 DDX empties the border clip when the
* VT is inactive
*/
if (!((WindowPtr) pSrcDrawable)->parent &&
REGION_NOTEMPTY (pSrcDrawable->pScreen,
&((WindowPtr) pSrcDrawable)->borderClip))
{
/*
* special case bitblt from root window in
* IncludeInferiors mode; just like from a pixmap
*/
fastClip = 1;
}
else if ((pSrcDrawable == pDstDrawable) &&
(pGC->clientClipType == CT_NONE))
{
prgnSrcClip = cfbGetCompositeClip(pGC);
}
else
{
prgnSrcClip = NotClippedByChildren((WindowPtr)pSrcDrawable);
freeSrcClip = TRUE;
}
}
else
{
prgnSrcClip = &((WindowPtr)pSrcDrawable)->clipList;
}
}
fastBox.x1 = srcx;
fastBox.y1 = srcy;
fastBox.x2 = srcx + width;
fastBox.y2 = srcy + height;
/* Don't create a source region if we are doing a fast clip */
if (fastClip)
{
fastExpose = 1;
/*
* clip the source; if regions extend beyond the source size,
* make sure exposure events get sent
*/
if (fastBox.x1 < pSrcDrawable->x)
{
fastBox.x1 = pSrcDrawable->x;
fastExpose = 0;
}
if (fastBox.y1 < pSrcDrawable->y)
{
fastBox.y1 = pSrcDrawable->y;
fastExpose = 0;
}
if (fastBox.x2 > pSrcDrawable->x + (int) pSrcDrawable->width)
{
fastBox.x2 = pSrcDrawable->x + (int) pSrcDrawable->width;
fastExpose = 0;
}
if (fastBox.y2 > pSrcDrawable->y + (int) pSrcDrawable->height)
{
fastBox.y2 = pSrcDrawable->y + (int) pSrcDrawable->height;
fastExpose = 0;
}
}
else
{
REGION_INIT(pGC->pScreen, &rgnDst, &fastBox, 1);
REGION_INTERSECT(pGC->pScreen, &rgnDst, &rgnDst, prgnSrcClip);
}
dstx += pDstDrawable->x;
dsty += pDstDrawable->y;
if (pDstDrawable->type == DRAWABLE_WINDOW)
{
if (!((WindowPtr)pDstDrawable)->realized)
{
if (!fastClip)
REGION_UNINIT(pGC->pScreen, &rgnDst);
if (freeSrcClip)
REGION_DESTROY(pGC->pScreen, prgnSrcClip);
return NULL;
}
}
dx = srcx - dstx;
dy = srcy - dsty;
/* Translate and clip the dst to the destination composite clip */
if (fastClip)
{
RegionPtr cclip;
/* Translate the region directly */
fastBox.x1 -= dx;
fastBox.x2 -= dx;
fastBox.y1 -= dy;
fastBox.y2 -= dy;
/* If the destination composite clip is one rectangle we can
do the clip directly. Otherwise we have to create a full
blown region and call intersect */
/* XXX because CopyPlane uses this routine for 8-to-1 bit
* copies, this next line *must* also correctly fetch the
* composite clip from an mfb gc
*/
cclip = cfbGetCompositeClip(pGC);
if (REGION_NUM_RECTS(cclip) == 1)
{
BoxPtr pBox = REGION_RECTS(cclip);
if (fastBox.x1 < pBox->x1) fastBox.x1 = pBox->x1;
if (fastBox.x2 > pBox->x2) fastBox.x2 = pBox->x2;
if (fastBox.y1 < pBox->y1) fastBox.y1 = pBox->y1;
if (fastBox.y2 > pBox->y2) fastBox.y2 = pBox->y2;
/* Check to see if the region is empty */
if (fastBox.x1 >= fastBox.x2 || fastBox.y1 >= fastBox.y2)
{
REGION_NULL(pGC->pScreen, &rgnDst);
}
else
{
REGION_INIT(pGC->pScreen, &rgnDst, &fastBox, 1);
}
}
else
{
/* We must turn off fastClip now, since we must create
a full blown region. It is intersected with the
composite clip below. */
fastClip = 0;
REGION_INIT(pGC->pScreen, &rgnDst, &fastBox, 1);
}
}
else
{
REGION_TRANSLATE(pGC->pScreen, &rgnDst, -dx, -dy);
}
if (!fastClip)
{
REGION_INTERSECT(pGC->pScreen, &rgnDst,
&rgnDst,
cfbGetCompositeClip(pGC));
}
/* Do bit blitting */
numRects = REGION_NUM_RECTS(&rgnDst);
if (numRects && width && height)
{
if(!(pptSrc = (DDXPointPtr)xalloc(numRects *
sizeof(DDXPointRec))))
{
REGION_UNINIT(pGC->pScreen, &rgnDst);
if (freeSrcClip)
REGION_DESTROY(pGC->pScreen, prgnSrcClip);
return NULL;
}
pbox = REGION_RECTS(&rgnDst);
ppt = pptSrc;
for (i = numRects; --i >= 0; pbox++, ppt++)
{
ppt->x = pbox->x1 + dx;
ppt->y = pbox->y1 + dy;
}
(*doCopyPlane) (pSrcDrawable, pDstDrawable, pGC->alu, &rgnDst, pptSrc, pGC->planemask, bitPlane);
xfree(pptSrc);
}
prgnExposed = NULL;
if (pGC->fExpose)
{
/* Pixmap sources generate a NoExposed (we return NULL to do this) */
if (!fastExpose)
prgnExposed =
miHandleExposures(pSrcDrawable, pDstDrawable, pGC,
origSource.x, origSource.y,
(int)origSource.width,
(int)origSource.height,
origDest.x, origDest.y, bitPlane);
}
REGION_UNINIT(pGC->pScreen, &rgnDst);
if (freeSrcClip)
REGION_DESTROY(pGC->pScreen, prgnSrcClip);
return prgnExposed;
}
void
cfbDoBitblt (pSrc, pDst, alu, prgnDst, pptSrc, planemask)
DrawablePtr pSrc, pDst;
int alu;
RegionPtr prgnDst;
DDXPointPtr pptSrc;
unsigned long planemask;
{
void (*doBitBlt)(
DrawablePtr /*pSrc*/,
DrawablePtr /*pDst*/,
int /*alu*/,
RegionPtr /*prgnDst*/,
DDXPointPtr /*pptSrc*/,
unsigned long /*planemask*/)
= cfbDoBitbltGeneral;
if ((planemask & PMSK) == PMSK) {
switch (alu) {
case GXcopy:
doBitBlt = cfbDoBitbltCopy;
break;
case GXxor:
doBitBlt = cfbDoBitbltXor;
break;
case GXor:
doBitBlt = cfbDoBitbltOr;
break;
}
}
(*doBitBlt) (pSrc, pDst, alu, prgnDst, pptSrc, planemask);
}
RegionPtr
cfbCopyArea(pSrcDrawable, pDstDrawable,
pGC, srcx, srcy, width, height, dstx, dsty)
register DrawablePtr pSrcDrawable;
register DrawablePtr pDstDrawable;
GC *pGC;
int srcx, srcy;
int width, height;
int dstx, dsty;
{
void (*doBitBlt) (
DrawablePtr /*pSrc*/,
DrawablePtr /*pDst*/,
int /*alu*/,
RegionPtr /*prgnDst*/,
DDXPointPtr /*pptSrc*/,
unsigned long /*planemask*/);
doBitBlt = cfbDoBitbltCopy;
if (pGC->alu != GXcopy || (pGC->planemask & PMSK) != PMSK)
{
doBitBlt = cfbDoBitbltGeneral;
if ((pGC->planemask & PMSK) == PMSK)
{
switch (pGC->alu) {
case GXxor:
doBitBlt = cfbDoBitbltXor;
break;
case GXor:
doBitBlt = cfbDoBitbltOr;
break;
}
}
}
return cfbBitBlt (pSrcDrawable, pDstDrawable,
pGC, srcx, srcy, width, height, dstx, dsty, doBitBlt, 0L);
}
#if PSZ == 8
void
cfbCopyPlane1to8 (pSrcDrawable, pDstDrawable, rop, prgnDst, pptSrc, planemask)
DrawablePtr pSrcDrawable; /* must be a bitmap */
DrawablePtr pDstDrawable; /* must be depth 8 drawable */
int rop; /* not used; caller must call cfb8CheckOpaqueStipple
* beforehand to get cfb8StippleRRop set correctly */
RegionPtr prgnDst; /* region in destination to draw to;
* screen relative coords. if dest is a window;
* drawable relative if dest is a pixmap */
DDXPointPtr pptSrc; /* drawable relative src coords to copy from;
* must be one point for each box in prgnDst */
unsigned long planemask; /* to apply to destination writes */
{
int srcx, srcy; /* upper left corner of box being copied in source */
int dstx, dsty; /* upper left corner of box being copied in dest */
int width, height; /* in pixels, unpadded, of box being copied */
int xoffSrc; /* bit # in leftmost word of row from which copying starts */
int xoffDst; /* byte # in leftmost word of row from which copying starts */
CfbBits *psrcBase, *pdstBase; /* start of drawable's pixel data */
int widthSrc; /* # of groups of 32 pixels (1 bit/pixel) in src bitmap*/
int widthDst; /* # of groups of 4 pixels (8 bits/pixel) in dst */
CfbBits *psrcLine, *pdstLine; /* steps a row at a time thru src/dst;
* may point into middle of row */
register CfbBits *psrc, *pdst; /* steps within the row */
register CfbBits bits, tmp; /* bits from source */
register int leftShift;
register int rightShift;
CfbBits startmask; /* left edge pixel mask */
CfbBits endmask; /* right edge pixel mask */
register int nlMiddle; /* number of words in middle of the row to draw */
register int nl;
int firstoff = 0;
int secondoff = 0;
CfbBits src;
int nbox; /* number of boxes in region to copy */
BoxPtr pbox; /* steps thru boxes in region */
int pixelsRemainingOnRightEdge; /* # pixels to be drawn on a row after
* the main "middle" loop */
cfbGetLongWidthAndPointer (pSrcDrawable, widthSrc, psrcBase)
cfbGetLongWidthAndPointer (pDstDrawable, widthDst, pdstBase)
nbox = REGION_NUM_RECTS(prgnDst);
pbox = REGION_RECTS(prgnDst);
while (nbox--)
{
dstx = pbox->x1;
dsty = pbox->y1;
srcx = pptSrc->x;
srcy = pptSrc->y;
width = pbox->x2 - pbox->x1;
height = pbox->y2 - pbox->y1;
pbox++;
pptSrc++;
psrcLine = psrcBase + srcy * widthSrc + (srcx >> MFB_PWSH);
pdstLine = pdstBase + dsty * widthDst + (dstx >> PWSH);
xoffSrc = srcx & MFB_PIM; /* finds starting bit in src */
xoffDst = dstx & PIM; /* finds starting byte in dst */
/* compute startmask, endmask, nlMiddle */
if (xoffDst + width < PPW) /* XXX should this be '<= PPW' ? */
{ /* the copy only affects one word per row in destination */
maskpartialbits(dstx, width, startmask);
endmask = 0; /* nothing on right edge */
nlMiddle = 0; /* nothing in middle */
}
else
{ /* the copy will affect multiple words per row in destination */
maskbits(dstx, width, startmask, endmask, nlMiddle);
}
/*
* compute constants for the first four bits to be
* copied. This avoids troubles with partial first
* writes, and difficult shift computation
*/
if (startmask)
{
firstoff = xoffSrc - xoffDst;
if (firstoff > (MFB_PPW-PPW))
secondoff = MFB_PPW - firstoff;
if (xoffDst)
{
srcx += (PPW-xoffDst);
xoffSrc = srcx & MFB_PIM;
}
}
leftShift = xoffSrc;
rightShift = MFB_PPW - leftShift;
pixelsRemainingOnRightEdge = (nlMiddle & 7) * PPW +
((dstx + width) & PIM);
/* setup is done; now let's move some bits */
/* caller must call cfb8CheckOpaqueStipple before this function
* to set cfb8StippleRRop!
*/
if (cfb8StippleRRop == GXcopy)
{
while (height--)
{ /* one iteration of this loop copies one row */
psrc = psrcLine;
pdst = pdstLine;
psrcLine += widthSrc;
pdstLine += widthDst;
bits = *psrc++;
if (startmask)
{
if (firstoff < 0)
tmp = BitRight (bits, -firstoff);
else
{
tmp = BitLeft (bits, firstoff);
/*
* need a more cautious test for partialmask
* case...
*/
if (firstoff >= (MFB_PPW-PPW))
{
bits = *psrc++;
if (firstoff != (MFB_PPW-PPW))
tmp |= BitRight (bits, secondoff);
}
}
*pdst = (*pdst & ~startmask) | (GetPixelGroup(tmp) & startmask);
pdst++;
}
nl = nlMiddle;
while (nl >= 8)
{
nl -= 8;
tmp = BitLeft(bits, leftShift);
bits = *psrc++;
if (rightShift != MFB_PPW)
tmp |= BitRight(bits, rightShift);
#ifdef FAST_CONSTANT_OFFSET_MODE
# define StorePixels(pdst,o,pixels) (pdst)[o] = (pixels)
# define EndStep(pdst,o) (pdst) += (o)
# define StoreRopPixels(pdst,o,and,xor) (pdst)[o] = DoRRop((pdst)[o],and,xor);
#else
# define StorePixels(pdst,o,pixels) *(pdst)++ = (pixels)
# define EndStep(pdst,o)
# define StoreRopPixels(pdst,o,and,xor) *(pdst) = DoRRop(*(pdst),and,xor); (pdst)++;
#endif
#define Step(c) NextBitGroup(c);
#define StoreBitsPlain(o,c) StorePixels(pdst,o,GetPixelGroup(c))
#define StoreRopBitsPlain(o,c) StoreRopPixels(pdst,o,\
cfb8StippleAnd[GetBitGroup(c)], \
cfb8StippleXor[GetBitGroup(c)])
#define StoreBits0(c) StoreBitsPlain(0,c)
#define StoreRopBits0(c) StoreRopBitsPlain(0,c)
#if (BITMAP_BIT_ORDER == MSBFirst)
# define StoreBits(o,c) StoreBitsPlain(o,c)
# define StoreRopBits(o,c) StoreRopBitsPlain(o,c)
# define FirstStep(c) Step(c)
#else /* BITMAP_BIT_ORDER == LSBFirst */
#if PGSZ == 64
# define StoreBits(o,c) StorePixels(pdst,o, (cfb8Pixels[c & 0xff]))
# define StoreRopBits(o,c) StoreRopPixels(pdst,o, \
(cfb8StippleAnd[c & 0xff]), \
(cfb8StippleXor[c & 0xff]))
# define FirstStep(c) c = BitLeft (c, 8);
#else
/* 0x3c is 0xf << 2 (4 bits, long word) */
# define StoreBits(o,c) StorePixels(pdst,o,*((CfbBits *)\
(((char *) cfb8Pixels) + (c & 0x3c))))
# define StoreRopBits(o,c) StoreRopPixels(pdst,o, \
*((CfbBits *) (((char *) cfb8StippleAnd) + (c & 0x3c))), \
*((CfbBits *) (((char *) cfb8StippleXor) + (c & 0x3c))))
# define FirstStep(c) c = BitLeft (c, 2);
#endif /* PGSZ */
#endif /* BITMAP_BIT_ORDER */
StoreBits0(tmp); FirstStep(tmp);
StoreBits(1,tmp); Step(tmp);
StoreBits(2,tmp); Step(tmp);
StoreBits(3,tmp); Step(tmp);
StoreBits(4,tmp); Step(tmp);
StoreBits(5,tmp); Step(tmp);
StoreBits(6,tmp); Step(tmp);
StoreBits(7,tmp); EndStep (pdst,8);
}
/* do rest of middle and partial word on right edge */
if (pixelsRemainingOnRightEdge)
{
tmp = BitLeft(bits, leftShift);
if (pixelsRemainingOnRightEdge > rightShift)
{
bits = *psrc++;
tmp |= BitRight (bits, rightShift);
}
EndStep (pdst, nl);
switch (nl)
{
case 7:
StoreBitsPlain(-7,tmp); Step(tmp);
case 6:
StoreBitsPlain(-6,tmp); Step(tmp);
case 5:
StoreBitsPlain(-5,tmp); Step(tmp);
case 4:
StoreBitsPlain(-4,tmp); Step(tmp);
case 3:
StoreBitsPlain(-3,tmp); Step(tmp);
case 2:
StoreBitsPlain(-2,tmp); Step(tmp);
case 1:
StoreBitsPlain(-1,tmp); Step(tmp);
}
if (endmask)
*pdst = (*pdst & ~endmask) | (GetPixelGroup(tmp) & endmask);
}
}
}
else /* cfb8StippleRRop != GXcopy */
{
while (height--)
{ /* one iteration of this loop copies one row */
psrc = psrcLine;
pdst = pdstLine;
psrcLine += widthSrc;
pdstLine += widthDst;
bits = *psrc++;
/* do partial word on left edge */
if (startmask)
{
if (firstoff < 0)
tmp = BitRight (bits, -firstoff);
else
{
tmp = BitLeft (bits, firstoff);
if (firstoff >= (MFB_PPW-PPW))
{
bits = *psrc++;
if (firstoff != (MFB_PPW-PPW))
tmp |= BitRight (bits, secondoff);
}
}
src = GetBitGroup(tmp);
*pdst = MaskRRopPixels (*pdst, src, startmask);
pdst++;
}
/* do middle of row */
nl = nlMiddle;
while (nl >= 8)
{
nl -= 8;
tmp = BitLeft(bits, leftShift);
bits = *psrc++;
if (rightShift != MFB_PPW)
tmp |= BitRight(bits, rightShift);
StoreRopBits0(tmp); FirstStep(tmp);
StoreRopBits(1,tmp); Step(tmp);
StoreRopBits(2,tmp); Step(tmp);
StoreRopBits(3,tmp); Step(tmp);
StoreRopBits(4,tmp); Step(tmp);
StoreRopBits(5,tmp); Step(tmp);
StoreRopBits(6,tmp); Step(tmp);
StoreRopBits(7,tmp); EndStep(pdst,8);
}
/* do rest of middle and partial word on right edge */
if (pixelsRemainingOnRightEdge)
{
tmp = BitLeft(bits, leftShift);
if (pixelsRemainingOnRightEdge > rightShift)
{
bits = *psrc++; /* XXX purify abr here */
tmp |= BitRight (bits, rightShift);
}
while (nl--)
{
src = GetBitGroup (tmp);
*pdst = RRopPixels (*pdst, src);
pdst++;
NextBitGroup(tmp);
}
if (endmask)
{
src = GetBitGroup (tmp);
*pdst = MaskRRopPixels (*pdst, src, endmask);
}
}
} /* end copy one row */
} /* end alu is non-copy-mode case */
} /* end iteration over region boxes */
}
#else /* PSZ == 8 */
#define mfbmaskbits(x, w, startmask, endmask, nlw) \
startmask = mfbGetstarttab((x)&0x1f); \
endmask = mfbGetendtab(((x)+(w)) & 0x1f); \
if (startmask) \
nlw = (((w) - (32 - ((x)&0x1f))) >> 5); \
else \
nlw = (w) >> 5;
#define mfbmaskpartialbits(x, w, mask) \
mask = mfbGetpartmasks((x)&0x1f,(w)&0x1f);
#define LeftMost 0
#define StepBit(bit, inc) ((bit) += (inc))
#define GetBits(psrc, nBits, curBit, bitPos, bits) {\
bits = 0; \
while (nBits--) \
{ \
bits |= ((*psrc++ >> bitPos) & 1) << curBit; \
StepBit (curBit, 1); \
} \
}
/******************************************************************/
static void
#if PSZ == 16
cfbCopyPlane1to16
#endif
#if PSZ == 24
cfbCopyPlane1to24
#endif
#if PSZ == 32
cfbCopyPlane1to32
#endif
(
DrawablePtr pSrcDrawable,
DrawablePtr pDstDrawable,
int rop,
RegionPtr prgnDst,
DDXPointPtr pptSrc,
unsigned long planemask)
{
int srcx, srcy, dstx, dsty;
int width, height;
int xoffSrc;
CfbBits *psrcBase, *pdstBase;
int widthSrc, widthDst;
unsigned int *psrcLine;
register unsigned int *psrc;
#if PSZ == 16
unsigned short *pdstLine;
register unsigned short *pdst;
#endif
#if PSZ == 32
unsigned int *pdstLine;
register unsigned int *pdst;
#endif
#if PSZ == 24
unsigned char *pdstLine;
register unsigned char *pdst;
#endif
register unsigned int bits, tmp;
register unsigned int fgpixel, bgpixel;
register unsigned int src;
#if PSZ == 24
register unsigned int dst;
#endif
register int leftShift, rightShift;
register int i, nl;
int nbox;
BoxPtr pbox;
int result;
#if PSZ == 16
unsigned int doublet[4]; /* Pixel values for 16bpp expansion. */
#endif
#if PSZ == 32
unsigned int doublet[8]; /* Pixel values for 32bpp expansion */
#endif
fgpixel = FgPixel & planemask;
bgpixel = BgPixel & planemask;
#if PSZ == 16
if (rop == GXcopy && (planemask & PMSK) == PMSK) {
doublet[0] = bgpixel | (bgpixel << 16);
doublet[1] = fgpixel | (bgpixel << 16);
doublet[2] = bgpixel | (fgpixel << 16);
doublet[3] = fgpixel | (fgpixel << 16);
}
#endif
#if PSZ == 32
if (rop == GXcopy && (planemask & PMSK) == PMSK) {
doublet[0] = bgpixel; doublet[1] = bgpixel;
doublet[2] = fgpixel; doublet[3] = bgpixel;
doublet[4] = bgpixel; doublet[5] = fgpixel;
doublet[6] = fgpixel; doublet[7] = fgpixel;
}
#endif
/* must explicitly ask for "int" widths, as code below expects it */
/* on some machines (Alpha), "long" and "int" are not the same size */
cfbGetTypedWidthAndPointer (pSrcDrawable, widthSrc, psrcBase, int, CfbBits)
cfbGetTypedWidthAndPointer (pDstDrawable, widthDst, pdstBase, int, CfbBits)
#if PSZ == 16
widthDst <<= 1;
#endif
#if PSZ == 24
widthDst <<= 2;
#endif
nbox = REGION_NUM_RECTS(prgnDst);
pbox = REGION_RECTS(prgnDst);
while (nbox--)
{
dstx = pbox->x1;
dsty = pbox->y1;
srcx = pptSrc->x;
srcy = pptSrc->y;
width = pbox->x2 - pbox->x1;
height = pbox->y2 - pbox->y1;
pbox++;
pptSrc++;
psrcLine = (unsigned int *)psrcBase + srcy * widthSrc + (srcx >> 5);
#if PSZ == 16
pdstLine = (unsigned short *)pdstBase + dsty * widthDst + dstx;
#endif
#if PSZ == 24
pdstLine = (unsigned char *)pdstBase + dsty * widthDst + dstx * 3;
#endif
#if PSZ == 32
pdstLine = (unsigned int *)pdstBase + dsty * widthDst + dstx;
#endif
xoffSrc = srcx & 0x1f;
/*
* compute constants for the first four bits to be
* copied. This avoids troubles with partial first
* writes, and difficult shift computation
*/
leftShift = xoffSrc;
rightShift = 32 - leftShift;
if (rop == GXcopy && (planemask & PMSK) == PMSK)
{
while (height--)
{
psrc = psrcLine;
pdst = pdstLine;
psrcLine += widthSrc;
pdstLine += widthDst;
bits = *psrc++;
nl = width;
while (nl >= 32)
{
tmp = BitLeft(bits, leftShift);
bits = *psrc++;
if (rightShift != 32)
tmp |= BitRight(bits, rightShift);
i = 0;
#if PSZ == 16
/*
* I've thrown in some optimization to at least write
* some aligned 32-bit words instead of 16-bit shorts.
*/
if ((unsigned long)psrc & 2) {
/* Write unaligned 16-bit word at left edge. */
if (tmp & 0x01)
*pdst = fgpixel;
else
*pdst = bgpixel;
pdst++;
i++;
}
while (i <= 24)
{
unsigned tmpbits = tmp >> i;
*(unsigned int *)pdst = doublet[tmpbits & 0x03];
*(unsigned int *)(pdst + 2) =
doublet[(tmpbits >> 2) & 0x03];
*(unsigned int *)(pdst + 4) =
doublet[(tmpbits >> 4) & 0x03];
*(unsigned int *)(pdst + 6) =
doublet[(tmpbits >> 6) & 0x03];
pdst += 8; /* Advance four 32-bit words. */
i += 8;
}
while (i <= 30)
{
*(unsigned int *)pdst =
doublet[(tmp >> i) & 0x03];
pdst += 2; /* Advance one 32-bit word. */
i += 2;
}
if (i == 31) {
if ((tmp >> 31) & 0x01)
*pdst = fgpixel;
else
*pdst = bgpixel;
pdst++;
}
#endif
#if PSZ == 24
while (i < 32) {
if ((tmp >> i) & 0x01) {
*pdst = fgpixel;
*(pdst + 1) = fgpixel >> 8;
*(pdst + 2) = fgpixel >> 16;
}
else {
*pdst = bgpixel;
*(pdst + 1) = bgpixel >> 8;
*(pdst + 2) = bgpixel >> 16;
}
pdst += 3;
i++;
}
#endif
#if PSZ == 32
while (i <= 28) {
int pair;
pair = (tmp >> i) & 0x03;
*pdst = doublet[pair * 2];
*(pdst + 1) = doublet[pair * 2 + 1];
pair = (tmp >> (i + 2)) & 0x03;
*(pdst + 2) = doublet[pair * 2];
*(pdst + 3) = doublet[pair * 2 + 1];
pdst += 4;
i += 4;
}
while (i < 32) {
*pdst = ((tmp >> i) & 0x01) ? fgpixel : bgpixel;
pdst++;
i++;
}
#endif
nl -= 32;
}
if (nl)
{
tmp = BitLeft(bits, leftShift);
/*
* better condition needed -- mustn't run
* off the end of the source...
*/
if (rightShift != 32)
{
bits = *psrc++;
tmp |= BitRight (bits, rightShift);
}
i = 32;
while (nl--)
{
--i;
#if PSZ == 24
if ((tmp >> (31 - i)) & 0x01) {
*pdst = fgpixel;
*(pdst + 1) = fgpixel >> 8;
*(pdst + 2) = fgpixel >> 16;
}
else {
*pdst = bgpixel;
*(pdst + 1) = bgpixel >> 8;
*(pdst + 2) = bgpixel >> 16;
}
pdst += 3;
#else
*pdst = ((tmp >> (31 - i)) & 0x01) ? fgpixel : bgpixel;
pdst++;
#endif
}
}
}
}
else
{
while (height--)
{
psrc = psrcLine;
pdst = pdstLine;
psrcLine += widthSrc;
pdstLine += widthDst;
bits = *psrc++;
nl = width;
while (nl >= 32)
{
tmp = BitLeft(bits, leftShift);
bits = *psrc++;
if (rightShift != 32)
tmp |= BitRight(bits, rightShift);
i = 32;
while (i--)
{
src = ((tmp >> (31 - i)) & 0x01) ? fgpixel : bgpixel;
#if PSZ == 24
dst = *pdst;
dst |= (*(pdst + 1)) << 8;
dst |= (*(pdst + 2)) << 16;
DoRop (result, rop, src, dst);
*pdst = (dst & ~planemask) |
(result & planemask);
*(pdst+1) = ((dst & ~planemask) >> 8) |
((result & planemask) >> 8);
*(pdst+2) = ((dst & ~planemask) >> 16) |
((result & planemask) >> 16);
pdst += 3;
#else
DoRop (result, rop, src, *pdst);
*pdst = (*pdst & ~planemask) |
(result & planemask);
pdst++;
#endif
}
nl -= 32;
}
if (nl)
{
tmp = BitLeft(bits, leftShift);
/*
* better condition needed -- mustn't run
* off the end of the source...
*/
if (rightShift != 32)
{
bits = *psrc++;
tmp |= BitRight (bits, rightShift);
}
i = 32;
while (nl--)
{
--i;
src = ((tmp >> (31 - i)) & 0x01) ? fgpixel : bgpixel;
#if PSZ == 24
dst = *pdst;
dst |= (*(pdst + 1)) << 8;
dst |= (*(pdst + 2)) << 16;
DoRop (result, rop, src, dst);
*pdst = (dst & ~planemask) |
(result & planemask);
*(pdst+1) = ((dst & ~planemask) >> 8) |
((result & planemask) >> 8);
*(pdst+2) = ((dst & ~planemask) >> 16) |
((result & planemask) >> 16);
pdst += 3;
#else
DoRop (result, rop, src, *pdst);
*pdst = (*pdst & ~planemask) |
(result & planemask);
pdst++;
#endif
}
}
}
}
}
}
#endif /* PSZ == 8 */
/* shared among all different cfb depths through linker magic */
RegionPtr cfbCopyPlane(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;
{
RegionPtr ret;
#if IMAGE_BYTE_ORDER == LSBFirst
void (*doCopyPlaneExpand)(
DrawablePtr /*pSrc*/,
DrawablePtr /*pDst*/,
int /*alu*/,
RegionPtr /*prgnDst*/,
DDXPointPtr /*pptSrc*/,
unsigned long /*planemask*/);
if (pSrcDrawable->bitsPerPixel == 1 && pDstDrawable->bitsPerPixel == PSZ)
{
if (bitPlane == 1)
{
doCopyPlaneExpand = cfbCopyPlane1toN;
#if PSZ == 8
cfb8CheckOpaqueStipple (pGC->alu,
pGC->fgPixel, pGC->bgPixel,
pGC->planemask);
#else
FgPixel = pGC->fgPixel;
BgPixel = pGC->bgPixel;
#endif
ret = cfbCopyPlaneExpand (pSrcDrawable, pDstDrawable,
pGC, srcx, srcy, width, height, dstx, dsty, doCopyPlaneExpand, bitPlane);
}
else
ret = miHandleExposures (pSrcDrawable, pDstDrawable,
pGC, srcx, srcy, width, height, dstx, dsty, bitPlane);
}
else if (pSrcDrawable->bitsPerPixel == PSZ && pDstDrawable->bitsPerPixel == 1)
{
int oldalu;
oldalu = pGC->alu;
if ((pGC->fgPixel & 1) == 0 && (pGC->bgPixel&1) == 1)
pGC->alu = mfbGetInverseAlu(pGC->alu);
else if ((pGC->fgPixel & 1) == (pGC->bgPixel & 1))
pGC->alu = mfbReduceRop(pGC->alu, pGC->fgPixel);
ret = cfbCopyPlaneReduce(pSrcDrawable, pDstDrawable,
pGC, srcx, srcy, width, height, dstx, dsty,
cfbCopyPlaneNto1, bitPlane);
pGC->alu = oldalu;
}
else if (pSrcDrawable->bitsPerPixel == PSZ && pDstDrawable->bitsPerPixel == PSZ)
{
PixmapPtr pBitmap;
ScreenPtr pScreen = pSrcDrawable->pScreen;
GCPtr pGC1;
pBitmap = (*pScreen->CreatePixmap) (pScreen, width, height, 1,
CREATE_PIXMAP_USAGE_SCRATCH);
if (!pBitmap)
return NULL;
pGC1 = GetScratchGC (1, pScreen);
if (!pGC1)
{
(*pScreen->DestroyPixmap) (pBitmap);
return NULL;
}
/*
* don't need to set pGC->fgPixel,bgPixel as copyPlaneNto1
* ignores pixel values, expecting the rop to "do the
* right thing", which GXcopy will.
*/
ValidateGC ((DrawablePtr) pBitmap, pGC1);
/* no exposures here, scratch GC's don't get graphics expose */
cfbCopyPlaneReduce(pSrcDrawable, (DrawablePtr) pBitmap,
pGC1, srcx, srcy, width, height, 0, 0,
cfbCopyPlaneNto1, bitPlane);
#if PSZ == 8
cfb8CheckOpaqueStipple (pGC->alu,
pGC->fgPixel, pGC->bgPixel,
pGC->planemask);
#else
FgPixel = pGC->fgPixel;
BgPixel = pGC->bgPixel;
#endif
/* no exposures here, copy bits from inside a pixmap */
cfbCopyPlaneExpand((DrawablePtr) pBitmap, pDstDrawable, pGC,
0, 0, width, height, dstx, dsty, cfbCopyPlane1toN, 1);
FreeScratchGC (pGC1);
(*pScreen->DestroyPixmap) (pBitmap);
/* compute resultant exposures */
ret = miHandleExposures (pSrcDrawable, pDstDrawable, pGC,
srcx, srcy, width, height,
dstx, dsty, bitPlane);
}
else
#endif
ret = miCopyPlane (pSrcDrawable, pDstDrawable,
pGC, srcx, srcy, width, height, dstx, dsty, bitPlane);
return ret;
}