/* * 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) | ((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) WRITE((b), (x)) #endif #ifdef BITSRROP #define RROP(b,a,x) BITSRROP(b,a,x) #else #define RROP(b,a,x) WRITE((b), FbDoRRop (READ(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; } } fbFinishAccess (pDrawable); } #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; } } fbFinishAccess (pDrawable); } #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) WRITE(d + WRITE_ADDR1(n), (BITS) (fg)) #ifdef BITS2 # define WRITE2(d,n,fg) WRITE((BITS2 *) &((d)[WRITE_ADDR2(n)]), (BITS2) (fg)) #else # define WRITE2(d,n,fg) (WRITE1(d,n,fg), WRITE1(d,(n)+1,fg)) #endif #ifdef BITS4 # define WRITE4(d,n,fg) WRITE((BITS4 *) &((d)[WRITE_ADDR4(n)]), (BITS4) (fg)) #else # define WRITE4(d,n,fg) (WRITE2(d,n,fg), WRITE2(d,(n)+2,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 = RegionExtents(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) { fbFinishAccess (pDrawable); 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); } fbFinishAccess (pDrawable); return; } pt1 = pt2; pt2 = *pts++; --npt; if (isClipped (pt2, ul, lr)) break; } } } fbFinishAccess (pDrawable); } #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 = RegionExtents(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) { WRITE(dstLine, FbDoMaskRRop (READ(dstLine), andBits, xorBits, startmask)); dstLine++; } if (!andBits) while (nmiddle--) WRITE(dstLine++, xorBits); else while (nmiddle--) { WRITE(dstLine, FbDoRRop (READ(dstLine), andBits, xorBits)); dstLine++; } if (endmask) WRITE(dstLine, FbDoMaskRRop (READ(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; } } } } } } fbFinishAccess (pDrawable); } #endif #undef MUL #undef STORE #undef RROP #undef UNIT #undef USE_SOLID #undef isClipped