You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

939 lines
25 KiB

/*
*
* 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.
*/
/*
* This file defines functions for drawing some primitives using
* underlying datatypes instead of masks
*/
#define isClipped(c,ul,lr) ((((c) - (ul)) | ((lr) - (c))) & 0x80008000)
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#ifdef BITSMUL
#define MUL BITSMUL
#else
#define MUL 1
#endif
#ifdef BITSSTORE
#define STORE(b,x) BITSSTORE(b,x)
#else
#define STORE(b,x) (*(b) = (x))
#endif
#ifdef BITSRROP
#define RROP(b,a,x) BITSRROP(b,a,x)
#else
#define RROP(b,a,x) (*(b) = FbDoRRop (*(b), (a), (x)))
#endif
#ifdef BITSUNIT
#define UNIT BITSUNIT
#define USE_SOLID
#else
#define UNIT BITS
#endif
/*
* Define the following before including this file:
*
* BRESSOLID name of function for drawing a solid segment
* BRESDASH name of function for drawing a dashed segment
* DOTS name of function for drawing dots
* ARC name of function for drawing a solid arc
* BITS type of underlying unit
*/
#ifdef BRESSOLID
void
BRESSOLID(DrawablePtr pDrawable,
GCPtr pGC,
int dashOffset,
int signdx,
int signdy, int axis, int x1, int y1, int e, int e1, int e3, int len)
{
FbBits *dst;
FbStride dstStride;
int dstBpp;
int dstXoff, dstYoff;
FbGCPrivPtr pPriv = fbGetGCPrivate(pGC);
UNIT *bits;
FbStride bitsStride;
FbStride majorStep, minorStep;
BITS xor = (BITS) pPriv->xor;
fbGetDrawable(pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
bits =
((UNIT *) (dst + ((y1 + dstYoff) * dstStride))) + (x1 + dstXoff) * MUL;
bitsStride = dstStride * (sizeof(FbBits) / sizeof(UNIT));
if (signdy < 0)
bitsStride = -bitsStride;
if (axis == X_AXIS) {
majorStep = signdx * MUL;
minorStep = bitsStride;
}
else {
majorStep = bitsStride;
minorStep = signdx * MUL;
}
while (len--) {
STORE(bits, xor);
bits += majorStep;
e += e1;
if (e >= 0) {
bits += minorStep;
e += e3;
}
}
}
#endif
#ifdef BRESDASH
void
BRESDASH(DrawablePtr pDrawable,
GCPtr pGC,
int dashOffset,
int signdx,
int signdy, int axis, int x1, int y1, int e, int e1, int e3, int len)
{
FbBits *dst;
FbStride dstStride;
int dstBpp;
int dstXoff, dstYoff;
FbGCPrivPtr pPriv = fbGetGCPrivate(pGC);
UNIT *bits;
FbStride bitsStride;
FbStride majorStep, minorStep;
BITS xorfg, xorbg;
FbDashDeclare;
int dashlen;
Bool even;
Bool doOdd;
fbGetDrawable(pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
doOdd = pGC->lineStyle == LineDoubleDash;
xorfg = (BITS) pPriv->xor;
xorbg = (BITS) pPriv->bgxor;
FbDashInit(pGC, pPriv, dashOffset, dashlen, even);
bits =
((UNIT *) (dst + ((y1 + dstYoff) * dstStride))) + (x1 + dstXoff) * MUL;
bitsStride = dstStride * (sizeof(FbBits) / sizeof(UNIT));
if (signdy < 0)
bitsStride = -bitsStride;
if (axis == X_AXIS) {
majorStep = signdx * MUL;
minorStep = bitsStride;
}
else {
majorStep = bitsStride;
minorStep = signdx * MUL;
}
if (dashlen >= len)
dashlen = len;
if (doOdd) {
if (!even)
goto doubleOdd;
for (;;) {
len -= dashlen;
while (dashlen--) {
STORE(bits, xorfg);
bits += majorStep;
if ((e += e1) >= 0) {
e += e3;
bits += minorStep;
}
}
if (!len)
break;
FbDashNextEven(dashlen);
if (dashlen >= len)
dashlen = len;
doubleOdd:
len -= dashlen;
while (dashlen--) {
STORE(bits, xorbg);
bits += majorStep;
if ((e += e1) >= 0) {
e += e3;
bits += minorStep;
}
}
if (!len)
break;
FbDashNextOdd(dashlen);
if (dashlen >= len)
dashlen = len;
}
}
else {
if (!even)
goto onOffOdd;
for (;;) {
len -= dashlen;
while (dashlen--) {
STORE(bits, xorfg);
bits += majorStep;
if ((e += e1) >= 0) {
e += e3;
bits += minorStep;
}
}
if (!len)
break;
FbDashNextEven(dashlen);
if (dashlen >= len)
dashlen = len;
onOffOdd:
len -= dashlen;
while (dashlen--) {
bits += majorStep;
if ((e += e1) >= 0) {
e += e3;
bits += minorStep;
}
}
if (!len)
break;
FbDashNextOdd(dashlen);
if (dashlen >= len)
dashlen = len;
}
}
}
#endif
#ifdef DOTS
void
DOTS(FbBits * dst,
FbStride dstStride,
int dstBpp,
BoxPtr pBox,
xPoint * ptsOrig,
int npt, int xorg, int yorg, int xoff, int yoff, FbBits and, FbBits xor)
{
INT32 *pts = (INT32 *) ptsOrig;
UNIT *bits = (UNIT *) dst;
UNIT *point;
BITS bxor = (BITS) xor;
BITS band = (BITS) and;
FbStride bitsStride = dstStride * (sizeof(FbBits) / sizeof(UNIT));
INT32 ul, lr;
INT32 pt;
ul = coordToInt(pBox->x1 - xorg, pBox->y1 - yorg);
lr = coordToInt(pBox->x2 - xorg - 1, pBox->y2 - yorg - 1);
bits += bitsStride * (yorg + yoff) + (xorg + xoff) * MUL;
if (and == 0) {
while (npt--) {
pt = *pts++;
if (!isClipped(pt, ul, lr)) {
point = bits + intToY(pt) * bitsStride + intToX(pt) * MUL;
STORE(point, bxor);
}
}
}
else {
while (npt--) {
pt = *pts++;
if (!isClipped(pt, ul, lr)) {
point = bits + intToY(pt) * bitsStride + intToX(pt) * MUL;
RROP(point, band, bxor);
}
}
}
}
#endif
#ifdef ARC
#define ARCCOPY(d) STORE(d,xorBits)
#define ARCRROP(d) RROP(d,andBits,xorBits)
void
ARC(FbBits * dst,
FbStride dstStride,
int dstBpp, xArc * arc, int drawX, int drawY, FbBits and, FbBits xor)
{
UNIT *bits;
FbStride bitsStride;
miZeroArcRec info;
Bool do360;
int x;
UNIT *yorgp, *yorgop;
BITS andBits, xorBits;
int yoffset, dyoffset;
int y, a, b, d, mask;
int k1, k3, dx, dy;
bits = (UNIT *) dst;
bitsStride = dstStride * (sizeof(FbBits) / sizeof(UNIT));
andBits = (BITS) and;
xorBits = (BITS) xor;
do360 = miZeroArcSetup(arc, &info, TRUE);
yorgp = bits + ((info.yorg + drawY) * bitsStride);
yorgop = bits + ((info.yorgo + drawY) * bitsStride);
info.xorg = (info.xorg + drawX) * MUL;
info.xorgo = (info.xorgo + drawX) * MUL;
MIARCSETUP();
yoffset = y ? bitsStride : 0;
dyoffset = 0;
mask = info.initialMask;
if (!(arc->width & 1)) {
if (andBits == 0) {
if (mask & 2)
ARCCOPY(yorgp + info.xorgo);
if (mask & 8)
ARCCOPY(yorgop + info.xorgo);
}
else {
if (mask & 2)
ARCRROP(yorgp + info.xorgo);
if (mask & 8)
ARCRROP(yorgop + info.xorgo);
}
}
if (!info.end.x || !info.end.y) {
mask = info.end.mask;
info.end = info.altend;
}
if (do360 && (arc->width == arc->height) && !(arc->width & 1)) {
int xoffset = bitsStride;
UNIT *yorghb = yorgp + (info.h * bitsStride) + info.xorg;
UNIT *yorgohb = yorghb - info.h * MUL;
yorgp += info.xorg;
yorgop += info.xorg;
yorghb += info.h * MUL;
while (1) {
if (andBits == 0) {
ARCCOPY(yorgp + yoffset + x * MUL);
ARCCOPY(yorgp + yoffset - x * MUL);
ARCCOPY(yorgop - yoffset - x * MUL);
ARCCOPY(yorgop - yoffset + x * MUL);
}
else {
ARCRROP(yorgp + yoffset + x * MUL);
ARCRROP(yorgp + yoffset - x * MUL);
ARCRROP(yorgop - yoffset - x * MUL);
ARCRROP(yorgop - yoffset + x * MUL);
}
if (a < 0)
break;
if (andBits == 0) {
ARCCOPY(yorghb - xoffset - y * MUL);
ARCCOPY(yorgohb - xoffset + y * MUL);
ARCCOPY(yorgohb + xoffset + y * MUL);
ARCCOPY(yorghb + xoffset - y * MUL);
}
else {
ARCRROP(yorghb - xoffset - y * MUL);
ARCRROP(yorgohb - xoffset + y * MUL);
ARCRROP(yorgohb + xoffset + y * MUL);
ARCRROP(yorghb + xoffset - y * MUL);
}
xoffset += bitsStride;
MIARCCIRCLESTEP(yoffset += bitsStride;
);
}
yorgp -= info.xorg;
yorgop -= info.xorg;
x = info.w;
yoffset = info.h * bitsStride;
}
else if (do360) {
while (y < info.h || x < info.w) {
MIARCOCTANTSHIFT(dyoffset = bitsStride;
);
if (andBits == 0) {
ARCCOPY(yorgp + yoffset + info.xorg + x * MUL);
ARCCOPY(yorgp + yoffset + info.xorgo - x * MUL);
ARCCOPY(yorgop - yoffset + info.xorgo - x * MUL);
ARCCOPY(yorgop - yoffset + info.xorg + x * MUL);
}
else {
ARCRROP(yorgp + yoffset + info.xorg + x * MUL);
ARCRROP(yorgp + yoffset + info.xorgo - x * MUL);
ARCRROP(yorgop - yoffset + info.xorgo - x * MUL);
ARCRROP(yorgop - yoffset + info.xorg + x * MUL);
}
MIARCSTEP(yoffset += dyoffset;
, yoffset += bitsStride;
);
}
}
else {
while (y < info.h || x < info.w) {
MIARCOCTANTSHIFT(dyoffset = bitsStride;
);
if ((x == info.start.x) || (y == info.start.y)) {
mask = info.start.mask;
info.start = info.altstart;
}
if (andBits == 0) {
if (mask & 1)
ARCCOPY(yorgp + yoffset + info.xorg + x * MUL);
if (mask & 2)
ARCCOPY(yorgp + yoffset + info.xorgo - x * MUL);
if (mask & 4)
ARCCOPY(yorgop - yoffset + info.xorgo - x * MUL);
if (mask & 8)
ARCCOPY(yorgop - yoffset + info.xorg + x * MUL);
}
else {
if (mask & 1)
ARCRROP(yorgp + yoffset + info.xorg + x * MUL);
if (mask & 2)
ARCRROP(yorgp + yoffset + info.xorgo - x * MUL);
if (mask & 4)
ARCRROP(yorgop - yoffset + info.xorgo - x * MUL);
if (mask & 8)
ARCRROP(yorgop - yoffset + info.xorg + x * MUL);
}
if ((x == info.end.x) || (y == info.end.y)) {
mask = info.end.mask;
info.end = info.altend;
}
MIARCSTEP(yoffset += dyoffset;
, yoffset += bitsStride;
);
}
}
if ((x == info.start.x) || (y == info.start.y))
mask = info.start.mask;
if (andBits == 0) {
if (mask & 1)
ARCCOPY(yorgp + yoffset + info.xorg + x * MUL);
if (mask & 4)
ARCCOPY(yorgop - yoffset + info.xorgo - x * MUL);
if (arc->height & 1) {
if (mask & 2)
ARCCOPY(yorgp + yoffset + info.xorgo - x * MUL);
if (mask & 8)
ARCCOPY(yorgop - yoffset + info.xorg + x * MUL);
}
}
else {
if (mask & 1)
ARCRROP(yorgp + yoffset + info.xorg + x * MUL);
if (mask & 4)
ARCRROP(yorgop - yoffset + info.xorgo - x * MUL);
if (arc->height & 1) {
if (mask & 2)
ARCRROP(yorgp + yoffset + info.xorgo - x * MUL);
if (mask & 8)
ARCRROP(yorgop - yoffset + info.xorg + x * MUL);
}
}
}
#undef ARCCOPY
#undef ARCRROP
#endif
#ifdef GLYPH
#if BITMAP_BIT_ORDER == LSBFirst
# define WRITE_ADDR1(n) (n)
# define WRITE_ADDR2(n) (n)
# define WRITE_ADDR4(n) (n)
#else
# define WRITE_ADDR1(n) ((n) ^ 3)
# define WRITE_ADDR2(n) ((n) ^ 2)
# define WRITE_ADDR4(n) ((n))
#endif
#define WRITE1(d,n,fg) ((d)[WRITE_ADDR1(n)] = (BITS) (fg))
#ifdef BITS2
# define WRITE2(d,n,fg) (*((BITS2 *) &((d)[WRITE_ADDR2(n)])) = (BITS2) (fg))
#else
# define WRITE2(d,n,fg) WRITE1(d,(n)+1,WRITE1(d,n,fg))
#endif
#ifdef BITS4
# define WRITE4(d,n,fg) (*((BITS4 *) &((d)[WRITE_ADDR4(n)])) = (BITS4) (fg))
#else
# define WRITE4(d,n,fg) WRITE2(d,(n)+2,WRITE2(d,n,fg))
#endif
void
GLYPH(FbBits * dstBits,
FbStride dstStride,
int dstBpp, FbStip * stipple, FbBits fg, int x, int height)
{
int lshift;
FbStip bits;
BITS *dstLine;
BITS *dst;
int n;
int shift;
dstLine = (BITS *) dstBits;
dstLine += x & ~3;
dstStride *= (sizeof(FbBits) / sizeof(BITS));
shift = x & 3;
lshift = 4 - shift;
while (height--) {
bits = *stipple++;
dst = (BITS *) dstLine;
n = lshift;
while (bits) {
switch (FbStipMoveLsb(FbLeftStipBits(bits, n), 4, n)) {
case 0:
break;
case 1:
WRITE1(dst, 0, fg);
break;
case 2:
WRITE1(dst, 1, fg);
break;
case 3:
WRITE2(dst, 0, fg);
break;
case 4:
WRITE1(dst, 2, fg);
break;
case 5:
WRITE1(dst, 0, fg);
WRITE1(dst, 2, fg);
break;
case 6:
WRITE1(dst, 1, fg);
WRITE1(dst, 2, fg);
break;
case 7:
WRITE2(dst, 0, fg);
WRITE1(dst, 2, fg);
break;
case 8:
WRITE1(dst, 3, fg);
break;
case 9:
WRITE1(dst, 0, fg);
WRITE1(dst, 3, fg);
break;
case 10:
WRITE1(dst, 1, fg);
WRITE1(dst, 3, fg);
break;
case 11:
WRITE2(dst, 0, fg);
WRITE1(dst, 3, fg);
break;
case 12:
WRITE2(dst, 2, fg);
break;
case 13:
WRITE1(dst, 0, fg);
WRITE2(dst, 2, fg);
break;
case 14:
WRITE1(dst, 1, fg);
WRITE2(dst, 2, fg);
break;
case 15:
WRITE4(dst, 0, fg);
break;
}
bits = FbStipLeft(bits, n);
n = 4;
dst += 4;
}
dstLine += dstStride;
}
}
#undef WRITE_ADDR1
#undef WRITE_ADDR2
#undef WRITE_ADDR4
#undef WRITE1
#undef WRITE2
#undef WRITE4
#endif
#ifdef POLYLINE
void
POLYLINE(DrawablePtr pDrawable,
GCPtr pGC, int mode, int npt, DDXPointPtr ptsOrig)
{
INT32 *pts = (INT32 *) ptsOrig;
int xoff = pDrawable->x;
int yoff = pDrawable->y;
unsigned int bias = miGetZeroLineBias(pDrawable->pScreen);
BoxPtr pBox = REGION_EXTENTS(fbGetCompositeClip(pGC));
FbBits *dst;
int dstStride;
int dstBpp;
int dstXoff, dstYoff;
UNIT *bits, *bitsBase;
FbStride bitsStride;
BITS xor = fbGetGCPrivate(pGC)->xor;
BITS and = fbGetGCPrivate(pGC)->and;
int dashoffset = 0;
INT32 ul, lr;
INT32 pt1, pt2;
int e, e1, e3, len;
int stepmajor, stepminor;
int octant;
if (mode == CoordModePrevious)
fbFixCoordModePrevious(npt, ptsOrig);
fbGetDrawable(pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
bitsStride = dstStride * (sizeof(FbBits) / sizeof(UNIT));
bitsBase =
((UNIT *) dst) + (yoff + dstYoff) * bitsStride + (xoff + dstXoff) * MUL;
ul = coordToInt(pBox->x1 - xoff, pBox->y1 - yoff);
lr = coordToInt(pBox->x2 - xoff - 1, pBox->y2 - yoff - 1);
pt1 = *pts++;
npt--;
pt2 = *pts++;
npt--;
for (;;) {
if (isClipped(pt1, ul, lr) | isClipped(pt2, ul, lr)) {
fbSegment(pDrawable, pGC,
intToX(pt1) + xoff, intToY(pt1) + yoff,
intToX(pt2) + xoff, intToY(pt2) + yoff,
npt == 0 && pGC->capStyle != CapNotLast, &dashoffset);
if (!npt)
return;
pt1 = pt2;
pt2 = *pts++;
npt--;
}
else {
bits = bitsBase + intToY(pt1) * bitsStride + intToX(pt1) * MUL;
for (;;) {
CalcLineDeltas(intToX(pt1), intToY(pt1),
intToX(pt2), intToY(pt2),
len, e1, stepmajor, stepminor, 1, bitsStride,
octant);
stepmajor *= MUL;
if (len < e1) {
e3 = len;
len = e1;
e1 = e3;
e3 = stepminor;
stepminor = stepmajor;
stepmajor = e3;
SetYMajorOctant(octant);
}
e = -len;
e1 <<= 1;
e3 = e << 1;
FIXUP_ERROR(e, octant, bias);
if (and == 0) {
while (len--) {
STORE(bits, xor);
bits += stepmajor;
e += e1;
if (e >= 0) {
bits += stepminor;
e += e3;
}
}
}
else {
while (len--) {
RROP(bits, and, xor);
bits += stepmajor;
e += e1;
if (e >= 0) {
bits += stepminor;
e += e3;
}
}
}
if (!npt) {
if (pGC->capStyle != CapNotLast &&
pt2 != *((INT32 *) ptsOrig)) {
RROP(bits, and, xor);
}
return;
}
pt1 = pt2;
pt2 = *pts++;
--npt;
if (isClipped(pt2, ul, lr))
break;
}
}
}
}
#endif
#ifdef POLYSEGMENT
void
POLYSEGMENT(DrawablePtr pDrawable, GCPtr pGC, int nseg, xSegment * pseg)
{
INT32 *pts = (INT32 *) pseg;
int xoff = pDrawable->x;
int yoff = pDrawable->y;
unsigned int bias = miGetZeroLineBias(pDrawable->pScreen);
BoxPtr pBox = REGION_EXTENTS(fbGetCompositeClip(pGC));
FbBits *dst;
int dstStride;
int dstBpp;
int dstXoff, dstYoff;
UNIT *bits, *bitsBase;
FbStride bitsStride;
FbBits xorBits = fbGetGCPrivate(pGC)->xor;
FbBits andBits = fbGetGCPrivate(pGC)->and;
BITS xor = xorBits;
BITS and = andBits;
int dashoffset = 0;
INT32 ul, lr;
INT32 pt1, pt2;
int e, e1, e3, len;
int stepmajor, stepminor;
int octant;
Bool capNotLast;
fbGetDrawable(pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
bitsStride = dstStride * (sizeof(FbBits) / sizeof(UNIT));
bitsBase =
((UNIT *) dst) + (yoff + dstYoff) * bitsStride + (xoff + dstXoff) * MUL;
ul = coordToInt(pBox->x1 - xoff, pBox->y1 - yoff);
lr = coordToInt(pBox->x2 - xoff - 1, pBox->y2 - yoff - 1);
capNotLast = pGC->capStyle == CapNotLast;
while (nseg--) {
pt1 = *pts++;
pt2 = *pts++;
if (isClipped(pt1, ul, lr) | isClipped(pt2, ul, lr)) {
fbSegment(pDrawable, pGC,
intToX(pt1) + xoff, intToY(pt1) + yoff,
intToX(pt2) + xoff, intToY(pt2) + yoff,
!capNotLast, &dashoffset);
}
else {
CalcLineDeltas(intToX(pt1), intToY(pt1),
intToX(pt2), intToY(pt2),
len, e1, stepmajor, stepminor, 1, bitsStride,
octant);
if (e1 == 0 && len > 3
#if MUL != 1
&& FbCheck24Pix(and) && FbCheck24Pix(xor)
#endif
) {
int x1, x2;
FbBits *dstLine;
int dstX, width;
FbBits startmask, endmask;
int nmiddle;
if (stepmajor < 0) {
x1 = intToX(pt2);
x2 = intToX(pt1) + 1;
if (capNotLast)
x1++;
}
else {
x1 = intToX(pt1);
x2 = intToX(pt2);
if (!capNotLast)
x2++;
}
dstX = (x1 + xoff + dstXoff) * (sizeof(UNIT) * 8 * MUL);
width = (x2 - x1) * (sizeof(UNIT) * 8 * MUL);
dstLine = dst + (intToY(pt1) + yoff + dstYoff) * dstStride;
dstLine += dstX >> FB_SHIFT;
dstX &= FB_MASK;
FbMaskBits(dstX, width, startmask, nmiddle, endmask);
if (startmask) {
*dstLine =
FbDoMaskRRop(*dstLine, andBits, xorBits, startmask);
dstLine++;
}
if (!andBits)
while (nmiddle--)
*dstLine++ = xorBits;
else
while (nmiddle--) {
*dstLine = FbDoRRop(*dstLine, andBits, xorBits);
dstLine++;
}
if (endmask)
*dstLine =
FbDoMaskRRop(*dstLine, andBits, xorBits, endmask);
}
else {
stepmajor *= MUL;
bits = bitsBase + intToY(pt1) * bitsStride + intToX(pt1) * MUL;
if (len < e1) {
e3 = len;
len = e1;
e1 = e3;
e3 = stepminor;
stepminor = stepmajor;
stepmajor = e3;
SetYMajorOctant(octant);
}
e = -len;
e1 <<= 1;
e3 = e << 1;
FIXUP_ERROR(e, octant, bias);
if (!capNotLast)
len++;
if (and == 0) {
while (len--) {
STORE(bits, xor);
bits += stepmajor;
e += e1;
if (e >= 0) {
bits += stepminor;
e += e3;
}
}
}
else {
while (len--) {
RROP(bits, and, xor);
bits += stepmajor;
e += e1;
if (e >= 0) {
bits += stepminor;
e += e3;
}
}
}
}
}
}
}
#endif
#undef MUL
#undef STORE
#undef RROP
#undef UNIT
#undef USE_SOLID
#undef isClipped