TinyX/fb/fbstipple.c

278 lines
7.7 KiB
C

/*
*
* Copyright © 1998 Keith Packard
*
* 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, and that the name of Keith Packard not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Keith Packard makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL KEITH PACKARD 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.
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include "fb.h"
/*
* This is a slight abuse of the preprocessor to generate repetitive
* code, the idea is to generate code for each case of a copy-mode
* transparent stipple
*/
#define LaneCases1(c,a) case c: \
while (n--) { (void)FbLaneCase(c,a); a++; } \
break
#define LaneCases2(c,a) LaneCases1(c,a); LaneCases1(c+1,a)
#define LaneCases4(c,a) LaneCases2(c,a); LaneCases2(c+2,a)
#define LaneCases8(c,a) LaneCases4(c,a); LaneCases4(c+4,a)
#define LaneCases16(c,a) LaneCases8(c,a); LaneCases8(c+8,a)
#define LaneCases32(c,a) LaneCases16(c,a); LaneCases16(c+16,a)
#define LaneCases64(c,a) LaneCases32(c,a); LaneCases32(c+32,a)
#define LaneCases128(c,a) LaneCases64(c,a); LaneCases64(c+64,a)
#define LaneCases256(c,a) LaneCases128(c,a); LaneCases128(c+128,a)
#if FB_SHIFT == 6
#define LaneCases(a) LaneCases256(0,a)
#endif
#if FB_SHIFT == 5
#define LaneCases(a) LaneCases16(0,a)
#endif
/*
* Repeat a transparent stipple across a scanline n times
*/
void
fbTransparentSpan(FbBits * dst, FbBits stip, FbBits fgxor, int n)
{
FbStip s;
s = ((FbStip) (stip) & 0x01);
s |= ((FbStip) (stip >> 8) & 0x02);
s |= ((FbStip) (stip >> 16) & 0x04);
s |= ((FbStip) (stip >> 24) & 0x08);
#if FB_SHIFT > 5
s |= ((FbStip) (stip >> 32) & 0x10);
s |= ((FbStip) (stip >> 40) & 0x20);
s |= ((FbStip) (stip >> 48) & 0x40);
s |= ((FbStip) (stip >> 56) & 0x80);
#endif
switch (s) {
LaneCases(dst);
}
}
void
fbEvenStipple(FbBits * dst,
FbStride dstStride,
int dstX,
int dstBpp,
int width,
int height,
FbStip * stip,
FbStride stipStride,
int stipHeight,
FbBits fgand,
FbBits fgxor, FbBits bgand, FbBits bgxor, int xRot, int yRot)
{
FbBits startmask, endmask;
FbBits mask, and, xor;
int nmiddle, n;
FbStip *s, *stipEnd, bits;
int rot, stipX, stipY;
int pixelsPerDst;
const FbBits *fbBits;
Bool transparent;
int startbyte, endbyte;
/*
* Check for a transparent stipple (stencil)
*/
transparent = FALSE;
if (dstBpp >= 8 && fgand == 0 && bgand == FB_ALLONES && bgxor == 0)
transparent = TRUE;
pixelsPerDst = FB_UNIT / dstBpp;
/*
* Adjust dest pointers
*/
dst += dstX >> FB_SHIFT;
dstX &= FB_MASK;
FbMaskBitsBytes(dstX, width, fgand == 0 && bgand == 0,
startmask, startbyte, nmiddle, endmask, endbyte);
if (startmask)
dstStride--;
dstStride -= nmiddle;
xRot *= dstBpp;
/*
* Compute stip start scanline and rotation parameters
*/
stipEnd = stip + stipStride * stipHeight;
modulus(-yRot, stipHeight, stipY);
s = stip + stipStride * stipY;
modulus(-xRot, FB_UNIT, stipX);
rot = stipX;
/*
* Get pointer to stipple mask array for this depth
*/
/* fbStippleTable covers all valid bpp (4,8,16,32) */
fbBits = fbStippleTable[pixelsPerDst];
while (height--) {
/*
* Extract stipple bits for this scanline;
*/
bits = *s;
s += stipStride;
if (s == stipEnd)
s = stip;
#if FB_UNIT > 32
if (pixelsPerDst == 16)
mask = FbStipple16Bits(FbLeftStipBits(bits, 16));
else
#endif
mask = fbBits[FbLeftStipBits(bits, pixelsPerDst)];
/*
* Rotate into position and compute reduced rop values
*/
mask = FbRotLeft(mask, rot);
and = (fgand & mask) | (bgand & ~mask);
xor = (fgxor & mask) | (bgxor & ~mask);
if (transparent) {
if (startmask) {
fbTransparentSpan(dst, mask & startmask, fgxor, 1);
dst++;
}
fbTransparentSpan(dst, mask, fgxor, nmiddle);
dst += nmiddle;
if (endmask)
fbTransparentSpan(dst, mask & endmask, fgxor, 1);
}
else
{
/*
* Fill scanline
*/
if (startmask) {
FbDoLeftMaskByteRRop(dst, startbyte, startmask, and, xor);
dst++;
}
n = nmiddle;
if (!and)
while (n--)
*dst++ = xor;
else {
while (n--) {
*dst = FbDoRRop(*dst, and, xor);
dst++;
}
}
if (endmask)
FbDoRightMaskByteRRop(dst, endbyte, endmask, and, xor);
}
dst += dstStride;
}
}
void
fbOddStipple(FbBits * dst,
FbStride dstStride,
int dstX,
int dstBpp,
int width,
int height,
FbStip * stip,
FbStride stipStride,
int stipWidth,
int stipHeight,
FbBits fgand,
FbBits fgxor, FbBits bgand, FbBits bgxor, int xRot, int yRot)
{
int stipX, stipY, sx;
int widthTmp;
int h, w;
int x, y;
modulus(-yRot, stipHeight, stipY);
modulus(dstX / dstBpp - xRot, stipWidth, stipX);
y = 0;
while (height) {
h = stipHeight - stipY;
if (h > height)
h = height;
height -= h;
widthTmp = width;
x = dstX;
sx = stipX;
while (widthTmp) {
w = (stipWidth - sx) * dstBpp;
if (w > widthTmp)
w = widthTmp;
widthTmp -= w;
fbBltOne(stip + stipY * stipStride,
stipStride,
sx,
dst + y * dstStride,
dstStride, x, dstBpp, w, h, fgand, fgxor, bgand, bgxor);
x += w;
sx = 0;
}
y += h;
stipY = 0;
}
}
void
fbStipple(FbBits * dst,
FbStride dstStride,
int dstX,
int dstBpp,
int width,
int height,
FbStip * stip,
FbStride stipStride,
int stipWidth,
int stipHeight,
Bool even,
FbBits fgand,
FbBits fgxor, FbBits bgand, FbBits bgxor, int xRot, int yRot)
{
if (even)
fbEvenStipple(dst, dstStride, dstX, dstBpp, width, height,
stip, stipStride, stipHeight,
fgand, fgxor, bgand, bgxor, xRot, yRot);
else
fbOddStipple(dst, dstStride, dstX, dstBpp, width, height,
stip, stipStride, stipWidth, stipHeight,
fgand, fgxor, bgand, bgxor, xRot, yRot);
}