/* $XFree86: xc/programs/Xserver/hw/xfree86/xaa/xaaStipple.c,v 1.11 2001/10/28 03:34:04 tsi Exp $ */

#ifdef HAVE_XORG_CONFIG_H
#include <xorg-config.h>
#endif

#include "xaa.h"
#include "xaalocal.h"
#include "xaacexp.h"
#include "xf86.h"

static CARD32* StipplePowerOfTwo(CARD32*, CARD32*, int, int, int);
static CARD32* StipplePowerOfTwo_Inverted(CARD32*, CARD32*, int, int, int);
static CARD32* StippleUpTo32(CARD32*, CARD32*, int, int, int);
static CARD32* StippleUpTo32_Inverted(CARD32*, CARD32*, int, int, int);
static CARD32* StippleOver32(CARD32*, CARD32*, int, int, int);
static CARD32* StippleOver32_Inverted(CARD32*, CARD32*, int, int, int);

#ifdef TRIPLE_BITS
#define stipple_scanline_func EXPNAME(XAAStippleScanlineFunc3)
#define stipple_get_scanline_func EXPNAME(XAAGetStippleScanlineFunc3)
#else
#define stipple_scanline_func EXPNAME(XAAStippleScanlineFunc)
#define stipple_get_scanline_func EXPNAME(XAAGetStippleScanlineFunc)
#endif

StippleScanlineProcPtr stipple_scanline_func[6] = {
   StipplePowerOfTwo,
   StippleUpTo32,
   StippleOver32,
   StipplePowerOfTwo_Inverted,
   StippleUpTo32_Inverted,
   StippleOver32_Inverted
};

StippleScanlineProcPtr *stipple_get_scanline_func(void) {
   return stipple_scanline_func;
}

#ifdef FIXEDBASE
# define DEST(i)	*dest
# define RETURN(i)	return(dest)
#else
# define DEST(i)	dest[i]
# define RETURN(i)	return(dest + i)
#endif


/* TRIPLE_BITS pattern expansion */
#ifdef TRIPLE_BITS
#define EXPAND_PAT \
	CARD32 pat1 = byte_expand3[pat & 0xFF], \
	       pat2 = byte_expand3[(pat & 0xFF00) >> 8], \
	       pat3 = byte_expand3[(pat & 0xFF0000) >> 16], \
	       pat4 = byte_expand3[(pat & 0xFF000000) >> 24], \
	       patA = pat1 | (pat2 << 24), \
	       patB = (pat2 >> 8) | (pat3 << 16), \
	       patC = (pat3 >> 16) | (pat4 << 8)
#ifdef FIXED_BASE
#define WRITE_PAT1 { \
	*dest = patA; }
#define WRITE_PAT2 { \
	*dest = patA; \
	*dest = patB; }
#define WRITE_PAT3 { \
	*dest = patA; \
	*dest = patB; \
	*dest = patC; }
#else
#define WRITE_PAT1 { \
	*(dest++) = patA; }
#define WRITE_PAT2 { \
	*(dest) = patA; \
	*(dest + 1) = patB; \
	dest += 2; }
#define WRITE_PAT3 { \
	*(dest) = patA; \
	*(dest + 1) = patB; \
	*(dest + 2) = patC; \
	dest += 3; }
#endif
#endif


#if !defined(FIXEDBASE) && !defined(MSBFIRST) && !defined(TRIPLE_BITS)

unsigned int XAAShiftMasks[32] = {
  /* gcc is rather pedantic about SHIFT_R(0xFFFFFFFF,32) */
          0x00000000    , SHIFT_R(0xFFFFFFFF,31),
  SHIFT_R(0xFFFFFFFF,30), SHIFT_R(0xFFFFFFFF,29),
  SHIFT_R(0xFFFFFFFF,28), SHIFT_R(0xFFFFFFFF,27),
  SHIFT_R(0xFFFFFFFF,26), SHIFT_R(0xFFFFFFFF,25),
  SHIFT_R(0xFFFFFFFF,24), SHIFT_R(0xFFFFFFFF,23),
  SHIFT_R(0xFFFFFFFF,22), SHIFT_R(0xFFFFFFFF,21),
  SHIFT_R(0xFFFFFFFF,20), SHIFT_R(0xFFFFFFFF,19),
  SHIFT_R(0xFFFFFFFF,18), SHIFT_R(0xFFFFFFFF,17),
  SHIFT_R(0xFFFFFFFF,16), SHIFT_R(0xFFFFFFFF,15),
  SHIFT_R(0xFFFFFFFF,14), SHIFT_R(0xFFFFFFFF,13),
  SHIFT_R(0xFFFFFFFF,12), SHIFT_R(0xFFFFFFFF,11),
  SHIFT_R(0xFFFFFFFF,10), SHIFT_R(0xFFFFFFFF,9),
  SHIFT_R(0xFFFFFFFF,8),  SHIFT_R(0xFFFFFFFF,7),
  SHIFT_R(0xFFFFFFFF,6),  SHIFT_R(0xFFFFFFFF,5),
  SHIFT_R(0xFFFFFFFF,4),  SHIFT_R(0xFFFFFFFF,3),
  SHIFT_R(0xFFFFFFFF,2),  SHIFT_R(0xFFFFFFFF,1)
};

#endif

void 
#ifdef TRIPLE_BITS
EXPNAME(XAAFillColorExpandRects3)(
#else
EXPNAME(XAAFillColorExpandRects)(
#endif
   ScrnInfoPtr pScrn,
   int fg, int bg, int rop,
   unsigned int planemask,
   int nBox,
   BoxPtr pBox,
   int xorg, int yorg,
   PixmapPtr pPix
){
    XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn);
    CARD32 *base;
    Bool TwoPass = FALSE, FirstPass = TRUE;
    StippleScanlineProcPtr StippleFunc, FirstFunc, SecondFunc;
    int stipplewidth = pPix->drawable.width;
    int stippleheight = pPix->drawable.height;
    int srcwidth = pPix->devKind;
    int dwords, srcy, srcx, funcNo = 2, h;
    unsigned char *src = (unsigned char*)pPix->devPrivate.ptr;
    unsigned char *srcp;
    int flag;

    if(stipplewidth <= 32) {
	if(stipplewidth & (stipplewidth - 1))	
	  funcNo = 1;
	else	
	  funcNo = 0;
    } 
    StippleFunc = stipple_scanline_func[funcNo];
    SecondFunc = stipple_scanline_func[funcNo];
    FirstFunc = stipple_scanline_func[funcNo + 3];

#ifdef TRIPLE_BITS
    if((bg == -1) || 
	(!(infoRec->CPUToScreenColorExpandFillFlags & TRANSPARENCY_ONLY) &&
	(!(infoRec->CPUToScreenColorExpandFillFlags & RGB_EQUAL) ||
	(CHECK_RGB_EQUAL(bg))))) {
#else
    if((bg == -1) || 
	!(infoRec->CPUToScreenColorExpandFillFlags & TRANSPARENCY_ONLY)) {
#endif
	/* one pass */
    } else if((rop == GXcopy) && infoRec->FillSolidRects) {
	/* one pass but we fill background rects first */
	(*infoRec->FillSolidRects)(pScrn, bg, rop, planemask, nBox, pBox);
	bg = -1;
    } else {
	/* gotta do two passes */
	TwoPass = TRUE;
    }

    if(!TwoPass)
	(*infoRec->SetupForCPUToScreenColorExpandFill)(
					pScrn, fg, bg, rop, planemask);

    while(nBox--) {
#ifdef TRIPLE_BITS
	dwords = (3 * (pBox->x2 - pBox->x1) + 31) >> 5;
#else
	dwords = (pBox->x2 - pBox->x1 + 31) >> 5;
#endif

SECOND_PASS:
	if(TwoPass) {
	    (*infoRec->SetupForCPUToScreenColorExpandFill)(pScrn, 
			(FirstPass) ? bg : fg, -1, rop, planemask);
	    StippleFunc = (FirstPass) ? FirstFunc : SecondFunc;
	}

	h = pBox->y2 - pBox->y1;
	flag = (infoRec->CPUToScreenColorExpandFillFlags 
		& CPU_TRANSFER_PAD_QWORD) && ((dwords * h) & 0x01);

        (*infoRec->SubsequentCPUToScreenColorExpandFill)(
			pScrn, pBox->x1, pBox->y1,
 			pBox->x2 - pBox->x1, h, 0);

	base = (CARD32*)infoRec->ColorExpandBase;

	srcy = (pBox->y1 - yorg) % stippleheight;
	if(srcy < 0) srcy += stippleheight;
	srcx = (pBox->x1 - xorg) % stipplewidth;
	if(srcx < 0) srcx += stipplewidth;

	srcp = (srcwidth * srcy) + src;
	
#ifndef FIXEDBASE
	if((dwords * h) <= infoRec->ColorExpandRange) {
	   while(h--) {
		base = (*StippleFunc)(
			base, (CARD32*)srcp, srcx, stipplewidth, dwords);
		srcy++;
		srcp += srcwidth;
		if (srcy >= stippleheight) {
		   srcy = 0;
		   srcp = src;
		}
	   }
	} else
#endif
	   while(h--) {
		(*StippleFunc)(base, (CARD32*)srcp, srcx, stipplewidth, dwords);
		srcy++;
		srcp += srcwidth;
		if (srcy >= stippleheight) {
		   srcy = 0;
		   srcp = src;
		}
	   }
    
	  if (flag) {
	      base = (CARD32*)infoRec->ColorExpandBase;
	      base[0] = 0x00000000;
	  }

	if(TwoPass) {
	   if(FirstPass) {
		FirstPass = FALSE;
		goto SECOND_PASS;
	   } else FirstPass = TRUE;
	}

	pBox++;
     }

    if(infoRec->CPUToScreenColorExpandFillFlags & SYNC_AFTER_COLOR_EXPAND) 
	(*infoRec->Sync)(pScrn);
    else SET_SYNC_FLAG(infoRec);
}



void 
#ifdef TRIPLE_BITS
EXPNAME(XAAFillColorExpandSpans3)(
#else
EXPNAME(XAAFillColorExpandSpans)(
#endif
   ScrnInfoPtr pScrn,
   int fg, int bg, int rop,
   unsigned int planemask,
   int n,
   DDXPointPtr ppt,
   int *pwidth,
   int fSorted,
   int xorg, int yorg,
   PixmapPtr pPix
){
    XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn);
    CARD32 *base;
    Bool TwoPass = FALSE, FirstPass = TRUE;
    StippleScanlineProcPtr StippleFunc, FirstFunc, SecondFunc;
    int stipplewidth = pPix->drawable.width;
    int stippleheight = pPix->drawable.height;
    int dwords, srcy, srcx, funcNo = 2;
    unsigned char *srcp;

    if(stipplewidth <= 32) {
	if(stipplewidth & (stipplewidth - 1))	
	  funcNo = 1;
	else	
	  funcNo = 0;
    } 
    StippleFunc = stipple_scanline_func[funcNo];
    SecondFunc = stipple_scanline_func[funcNo];
    FirstFunc = stipple_scanline_func[funcNo + 3];

#ifdef TRIPLE_BITS
    if((bg == -1) || 
	(!(infoRec->CPUToScreenColorExpandFillFlags & TRANSPARENCY_ONLY) &&
	(!(infoRec->CPUToScreenColorExpandFillFlags & RGB_EQUAL) ||
	(CHECK_RGB_EQUAL(bg))))) {
#else
    if((bg == -1) || 
	!(infoRec->CPUToScreenColorExpandFillFlags & TRANSPARENCY_ONLY)) {
#endif
	/* one pass */
    } else if((rop == GXcopy) && infoRec->FillSolidSpans) {
	/* one pass but we fill background rects first */
	(*infoRec->FillSolidSpans)(
		pScrn, bg, rop, planemask, n, ppt, pwidth, fSorted);
	bg = -1;
    } else {
	/* gotta do two passes */
	TwoPass = TRUE;
    }

    if(!TwoPass)
	(*infoRec->SetupForCPUToScreenColorExpandFill)(
				pScrn, fg, bg, rop, planemask);

    while(n--) {
#ifdef TRIPLE_BITS
	dwords = (3 * *pwidth + 31) >> 5;
#else
	dwords = (*pwidth + 31) >> 5;
#endif

	srcy = (ppt->y - yorg) % stippleheight;
	if(srcy < 0) srcy += stippleheight;
	srcx = (ppt->x - xorg) % stipplewidth;
	if(srcx < 0) srcx += stipplewidth;

	srcp = (pPix->devKind * srcy) + (unsigned char*)pPix->devPrivate.ptr;

SECOND_PASS:
	if(TwoPass) {
	    (*infoRec->SetupForCPUToScreenColorExpandFill)(pScrn, 
			(FirstPass) ? bg : fg, -1, rop, planemask);
	    StippleFunc = (FirstPass) ? FirstFunc : SecondFunc;
	}

        (*infoRec->SubsequentCPUToScreenColorExpandFill)(pScrn, ppt->x, ppt->y,
 			*pwidth, 1, 0);

	base = (CARD32*)infoRec->ColorExpandBase;

	(*StippleFunc)(base, (CARD32*)srcp, srcx, stipplewidth, dwords);
    
	if((infoRec->CPUToScreenColorExpandFillFlags & CPU_TRANSFER_PAD_QWORD) 
			&& (dwords & 0x01)) {
	    base = (CARD32*)infoRec->ColorExpandBase;
	    base[0] = 0x00000000;
    	}

	if(TwoPass) {
	   if(FirstPass) {
		FirstPass = FALSE;
		goto SECOND_PASS;
	   } else FirstPass = TRUE;
	}

	ppt++; pwidth++;
     }

    if(infoRec->CPUToScreenColorExpandFillFlags & SYNC_AFTER_COLOR_EXPAND) 
	(*infoRec->Sync)(pScrn);
    else SET_SYNC_FLAG(infoRec);
}


#ifndef FIXEDBASE

void 
#ifdef TRIPLE_BITS
EXPNAME(XAAFillScanlineColorExpandRects3)(
#else
EXPNAME(XAAFillScanlineColorExpandRects)(
#endif
   ScrnInfoPtr pScrn,
   int fg, int bg, int rop,
   unsigned int planemask,
   int nBox,
   BoxPtr pBox,
   int xorg, int yorg,
   PixmapPtr pPix
){
    XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn);
    CARD32 *base;
    Bool TwoPass = FALSE, FirstPass = TRUE;
    StippleScanlineProcPtr StippleFunc, FirstFunc, SecondFunc;
    int stipplewidth = pPix->drawable.width;
    int stippleheight = pPix->drawable.height;
    int srcwidth = pPix->devKind;
    int dwords, srcy, srcx, funcNo = 2, bufferNo, h;
    unsigned char *src = pPix->devPrivate.ptr;
    unsigned char *srcp;

    if(stipplewidth <= 32) {
	if(stipplewidth & (stipplewidth - 1))	
	  funcNo = 1;
	else	
	  funcNo = 0;
    } 
    StippleFunc = stipple_scanline_func[funcNo];
    SecondFunc = stipple_scanline_func[funcNo];
    FirstFunc = stipple_scanline_func[funcNo + 3];

#ifdef TRIPLE_BITS
    if((bg == -1) || 
      (!(infoRec->ScanlineCPUToScreenColorExpandFillFlags & TRANSPARENCY_ONLY) &&
      (!(infoRec->ScanlineCPUToScreenColorExpandFillFlags & RGB_EQUAL) ||
      (CHECK_RGB_EQUAL(bg))))) {
#else
    if((bg == -1) || 
      !(infoRec->ScanlineCPUToScreenColorExpandFillFlags & TRANSPARENCY_ONLY)) {
#endif
	/* one pass */
    } else if((rop == GXcopy) && infoRec->FillSolidRects) {
	/* one pass but we fill background rects first */
	(*infoRec->FillSolidRects)(pScrn, bg, rop, planemask, nBox, pBox);
	bg = -1;
    } else {
	/* gotta do two passes */
	TwoPass = TRUE;
    }

    if(!TwoPass)
	(*infoRec->SetupForScanlineCPUToScreenColorExpandFill)(
				pScrn, fg, bg, rop, planemask);

    while(nBox--) {
#ifdef TRIPLE_BITS
	dwords = (3 * (pBox->x2 - pBox->x1) + 31) >> 5;
#else
	dwords = (pBox->x2 - pBox->x1 + 31) >> 5;
#endif

SECOND_PASS:
	if(TwoPass) {
	    (*infoRec->SetupForScanlineCPUToScreenColorExpandFill)(pScrn, 
			(FirstPass) ? bg : fg, -1, rop, planemask);
	    StippleFunc = (FirstPass) ? FirstFunc : SecondFunc;
	}

	h = pBox->y2 - pBox->y1;

        (*infoRec->SubsequentScanlineCPUToScreenColorExpandFill)(
		pScrn, pBox->x1, pBox->y1, pBox->x2 - pBox->x1, h, 0);

	bufferNo = 0;

	srcy = (pBox->y1 - yorg) % stippleheight;
	if(srcy < 0) srcy += stippleheight;
	srcx = (pBox->x1 - xorg) % stipplewidth;
	if(srcx < 0) srcx += stipplewidth;

	srcp = (srcwidth * srcy) + src;

	while(h--) {
   	    base = (CARD32*)infoRec->ScanlineColorExpandBuffers[bufferNo];
	    (*StippleFunc)(base, (CARD32*)srcp, srcx, stipplewidth, dwords);
	    (*infoRec->SubsequentColorExpandScanline)(pScrn, bufferNo++);
	    if(bufferNo >= infoRec->NumScanlineColorExpandBuffers)
		bufferNo = 0;
	    srcy++;
	    srcp += srcwidth;
	    if (srcy >= stippleheight) {
		srcy = 0;
		srcp = src;
	    }
	}
    
	if(TwoPass) {
	   if(FirstPass) {
		FirstPass = FALSE;
		goto SECOND_PASS;
	   } else FirstPass = TRUE;
	}

	pBox++;
     }

     SET_SYNC_FLAG(infoRec);
}

void 
#ifdef TRIPLE_BITS
EXPNAME(XAAFillScanlineColorExpandSpans3)(
#else
EXPNAME(XAAFillScanlineColorExpandSpans)(
#endif
   ScrnInfoPtr pScrn,
   int fg, int bg, int rop,
   unsigned int planemask,
   int n,
   DDXPointPtr ppt,
   int *pwidth,
   int fSorted,
   int xorg, int yorg,
   PixmapPtr pPix
){
    XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn);
    CARD32 *base;
    Bool TwoPass = FALSE, FirstPass = TRUE;
    StippleScanlineProcPtr StippleFunc, FirstFunc, SecondFunc;
    int stipplewidth = pPix->drawable.width;
    int stippleheight = pPix->drawable.height;
    int dwords, srcy, srcx, funcNo = 2;
    unsigned char *srcp;

    if(stipplewidth <= 32) {
	if(stipplewidth & (stipplewidth - 1))	
	  funcNo = 1;
	else	
	  funcNo = 0;
    } 
    StippleFunc = stipple_scanline_func[funcNo];
    SecondFunc = stipple_scanline_func[funcNo];
    FirstFunc = stipple_scanline_func[funcNo + 3];

#ifdef TRIPLE_BITS
    if((bg == -1) || 
      (!(infoRec->ScanlineCPUToScreenColorExpandFillFlags & TRANSPARENCY_ONLY) &&
      (!(infoRec->ScanlineCPUToScreenColorExpandFillFlags & RGB_EQUAL) ||
      (CHECK_RGB_EQUAL(bg))))) {
#else
    if((bg == -1) || 
      !(infoRec->ScanlineCPUToScreenColorExpandFillFlags & TRANSPARENCY_ONLY)) {
#endif
	/* one pass */
    } else if((rop == GXcopy) && infoRec->FillSolidSpans) {
	/* one pass but we fill background rects first */
	(*infoRec->FillSolidSpans)(
		pScrn, bg, rop, planemask, n, ppt, pwidth, fSorted);
	bg = -1;
    } else {
	/* gotta do two passes */
	TwoPass = TRUE;
    }

    if(!TwoPass)
	(*infoRec->SetupForScanlineCPUToScreenColorExpandFill)(
				pScrn, fg, bg, rop, planemask);


    while(n--) {
#ifdef TRIPLE_BITS
	dwords = (3 * *pwidth + 31) >> 5;
#else
	dwords = (*pwidth + 31) >> 5;
#endif

	srcy = (ppt->y - yorg) % stippleheight;
	if(srcy < 0) srcy += stippleheight;
	srcx = (ppt->x - xorg) % stipplewidth;
	if(srcx < 0) srcx += stipplewidth;

	srcp = (pPix->devKind * srcy) + (unsigned char*)pPix->devPrivate.ptr;

SECOND_PASS:
	if(TwoPass) {
	    (*infoRec->SetupForScanlineCPUToScreenColorExpandFill)(pScrn, 
			(FirstPass) ? bg : fg, -1, rop, planemask);
	    StippleFunc = (FirstPass) ? FirstFunc : SecondFunc;
	}

        (*infoRec->SubsequentScanlineCPUToScreenColorExpandFill)(
				pScrn, ppt->x, ppt->y, *pwidth, 1, 0);

	base = (CARD32*)infoRec->ScanlineColorExpandBuffers[0];

	(*StippleFunc)(base, (CARD32*)srcp, srcx, stipplewidth, dwords);
	(*infoRec->SubsequentColorExpandScanline)(pScrn, 0);
    
	if(TwoPass) {
	   if(FirstPass) {
		FirstPass = FALSE;
		goto SECOND_PASS;
	   } else FirstPass = TRUE;
	}

	ppt++; pwidth++;
     }

     SET_SYNC_FLAG(infoRec);
}

#endif

static CARD32 *
StipplePowerOfTwo(
   CARD32* dest, CARD32* src, 
   int shift, int width, int dwords
){
    CARD32 pat = *src;
    if(width < 32) {
	pat &= XAAShiftMasks[width];
	while(width < 32) {
	    pat |= SHIFT_L(pat,width);
	    width <<= 1;
	}
    }
   
    if(shift)
	pat = SHIFT_R(pat,shift) | SHIFT_L(pat,32 - shift);

#ifdef MSBFIRST
    pat = SWAP_BITS_IN_BYTES(pat);    
#endif

#ifdef TRIPLE_BITS
    {
	EXPAND_PAT;

	while(dwords >= 3) {
	    WRITE_PAT3;
	    dwords -= 3;
	}
	if (dwords == 2) {
	    WRITE_PAT2;
	} else if (dwords == 1) {
	    WRITE_PAT1;
	}

	return dest;
    }
#else /* TRIPLE_BITS */
   while(dwords >= 4) {
	DEST(0) = pat;
	DEST(1) = pat;
	DEST(2) = pat;
	DEST(3) = pat;
	dwords -= 4;
#ifndef FIXEDBASE
	dest += 4;
#endif
   }
   
   if(!dwords) return dest;
   DEST(0) = pat;
   if(dwords == 1) RETURN(1);
   DEST(1) = pat;
   if(dwords == 2) RETURN(2);
   DEST(2) = pat;
   RETURN(3);
#endif /* TRIPLE_BITS */
}

static CARD32 *
StipplePowerOfTwo_Inverted(
   CARD32* dest, CARD32* src, 
   int shift, int width, int dwords
){
    CARD32 pat = *src;
    if(width < 32) {
	pat &= XAAShiftMasks[width];
	while(width < 32) {
	    pat |= SHIFT_L(pat,width);
	    width <<= 1;
	}
    }
   
    if(shift)
	pat = SHIFT_R(pat,shift) | SHIFT_L(pat,32 - shift);

#ifdef MSBFIRST
    pat = SWAP_BITS_IN_BYTES(pat);    
#endif

   pat = ~pat;

#ifdef TRIPLE_BITS
    {
	EXPAND_PAT;

	while(dwords >= 3) {
	    WRITE_PAT3;
	    dwords -= 3;
	}
	if (dwords == 2) {
	    WRITE_PAT2;
	} else if (dwords == 1) {
	    WRITE_PAT1;
	}

	return dest;
    }
#else /* TRIPLE_BITS */
   while(dwords >= 4) {
	DEST(0) = pat;
	DEST(1) = pat;
	DEST(2) = pat;
	DEST(3) = pat;
	dwords -= 4;
#ifndef FIXEDBASE
	dest += 4;
#endif
   }
   
   if(!dwords) return dest;
   DEST(0) = pat;
   if(dwords == 1) RETURN(1);
   DEST(1) = pat;
   if(dwords == 2) RETURN(2);
   DEST(2) = pat;
   RETURN(3);
#endif /* TRIPLE_BITS */
}


static CARD32 *
StippleUpTo32(
   CARD32* base, CARD32* src, 
   int shift, int width, int dwords
){
    CARD32 pat = *src & XAAShiftMasks[width];

    while(width <= 15) {
	pat |= SHIFT_L(pat,width);
	width <<= 1;
    }
    pat |= SHIFT_L(pat,width);

    while(dwords--) {
	CARD32 bits = SHIFT_R(pat,shift) | SHIFT_L(pat,width-shift);
#ifdef TRIPLE_BITS
	if(dwords >= 2) {
	    WRITE_BITS3(bits);
	    dwords -= 2;
	} else if(dwords > 0) {
	    WRITE_BITS2(bits);
	    dwords--;
	} else {
	    WRITE_BITS1(bits);
	}
#else
	WRITE_BITS(bits);
#endif

	shift += 32;
	shift %= width;
    }
    return base;
}


static CARD32 *
StippleUpTo32_Inverted(
   CARD32* base, CARD32* src, 
   int shift, int width, int dwords
){
    CARD32 pat = *src & XAAShiftMasks[width];

    while(width <= 15) {
	pat |= SHIFT_L(pat,width);
	width <<= 1;
    }
    pat |= SHIFT_L(pat,width);

    while(dwords--) {
	CARD32 bits = ~(SHIFT_R(pat,shift) | SHIFT_L(pat,width-shift));
#ifdef TRIPLE_BITS
	if(dwords >= 2) {
	    WRITE_BITS3(bits);
	    dwords -= 2;
	} else if(dwords > 0) {
	    WRITE_BITS2(bits);
	    dwords--;
	} else {
	    WRITE_BITS1(bits);
	}
#else
	WRITE_BITS(bits);
#endif

	shift += 32;
	shift %= width;
    }
    return base;
}


static CARD32 *
StippleOver32(
   CARD32* base, CARD32* src, 
   int offset, int width, int dwords
){
   CARD32* srcp;
   CARD32 bits;
   int bitsleft, shift, usable;   

   while(dwords--) {
        bitsleft = width - offset;
        srcp = src + (offset >> 5);
        shift = offset & 31;
        usable = 32 - shift;

        if(bitsleft < 32) {
            if(bitsleft <= usable) {
                 bits = SHIFT_L(*src,bitsleft) | 
                       (SHIFT_R(*srcp,shift) & XAAShiftMasks[bitsleft]);
            } else {
                 bits = SHIFT_L(*src,bitsleft) |
                       (SHIFT_L(srcp[1],usable) & XAAShiftMasks[bitsleft]) |
                       (SHIFT_R(*srcp,shift) & XAAShiftMasks[usable]);
            }
        }
        else if(shift)
            bits = SHIFT_R(*srcp,shift) | SHIFT_L(srcp[1],usable);
        else
            bits = *srcp;

#ifdef TRIPLE_BITS
	if(dwords >= 2) {
	    WRITE_BITS3(bits);
	    dwords -= 2;
	} else if(dwords > 0) {
	    WRITE_BITS2(bits);
	    dwords--;
	} else {
	    WRITE_BITS1(bits);
	}
#else
	WRITE_BITS(bits);
#endif

	offset += 32;
	offset %= width;
   }
   return base;
}


static CARD32 *
StippleOver32_Inverted(
   CARD32* base, CARD32* src, 
   int offset, int width, int dwords
){
   CARD32* srcp;
   CARD32 bits;
   int bitsleft, shift, usable;

   while(dwords--) {
        bitsleft = width - offset;
        srcp = src + (offset >> 5);
        shift = offset & 31;
        usable = 32 - shift;

        if(bitsleft < 32) {
            if(bitsleft <= usable) {
                 bits = SHIFT_L(*src,bitsleft) |
                       (SHIFT_R(*srcp,shift) & XAAShiftMasks[bitsleft]);
            } else {
                 bits = SHIFT_L(*src,bitsleft) |
                       (SHIFT_L(srcp[1],usable) & XAAShiftMasks[bitsleft]) |
                       (SHIFT_R(*srcp,shift) & XAAShiftMasks[usable]);
            }
        }
        else if(shift)
            bits = SHIFT_R(*srcp,shift) | SHIFT_L(srcp[1],usable);
        else
            bits = *srcp;

	bits = ~bits;

#ifdef TRIPLE_BITS
	if(dwords >= 2) {
	    WRITE_BITS3(bits);
	    dwords -= 2;
	} else if(dwords > 0) {
	    WRITE_BITS2(bits);
	    dwords--;
	} else {
	    WRITE_BITS1(bits);
	}
#else
	WRITE_BITS(bits);
#endif

	offset += 32;
	offset %= width;
   }
   return base;
}
