457 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			457 lines
		
	
	
		
			13 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 <stdlib.h>
 | 
						|
 | 
						|
#include "fb.h"
 | 
						|
#include "miline.h"
 | 
						|
 | 
						|
#define fbBresShiftMask(mask,dir,bpp) ((bpp == FB_STIP_UNIT) ? 0 : \
 | 
						|
					((dir < 0) ? FbStipLeft(mask,bpp) : \
 | 
						|
					 FbStipRight(mask,bpp)))
 | 
						|
 | 
						|
static void
 | 
						|
fbBresSolid(DrawablePtr pDrawable,
 | 
						|
            GCPtr pGC,
 | 
						|
            int dashOffset,
 | 
						|
            int signdx,
 | 
						|
            int signdy,
 | 
						|
            int axis, int x1, int y1, int e, int e1, int e3, int len)
 | 
						|
{
 | 
						|
    FbStip *dst;
 | 
						|
    FbStride dstStride;
 | 
						|
    int dstBpp;
 | 
						|
    int dstXoff, dstYoff;
 | 
						|
    FbGCPrivPtr pPriv = fbGetGCPrivate(pGC);
 | 
						|
    FbStip and = (FbStip) pPriv->and;
 | 
						|
    FbStip xor = (FbStip) pPriv->xor;
 | 
						|
    FbStip mask, mask0;
 | 
						|
    FbStip bits;
 | 
						|
 | 
						|
    fbGetStipDrawable(pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
 | 
						|
    dst += ((y1 + dstYoff) * dstStride);
 | 
						|
    x1 = (x1 + dstXoff) * dstBpp;
 | 
						|
    dst += x1 >> FB_STIP_SHIFT;
 | 
						|
    x1 &= FB_STIP_MASK;
 | 
						|
    mask0 = FbStipMask(0, dstBpp);
 | 
						|
    mask = FbStipRight(mask0, x1);
 | 
						|
    if (signdx < 0)
 | 
						|
        mask0 = FbStipRight(mask0, FB_STIP_UNIT - dstBpp);
 | 
						|
    if (signdy < 0)
 | 
						|
        dstStride = -dstStride;
 | 
						|
    if (axis == X_AXIS) {
 | 
						|
        bits = 0;
 | 
						|
        while (len--) {
 | 
						|
            bits |= mask;
 | 
						|
            mask = fbBresShiftMask(mask, signdx, dstBpp);
 | 
						|
            if (!mask) {
 | 
						|
                WRITE(dst, FbDoMaskRRop(READ(dst), and, xor, bits));
 | 
						|
                bits = 0;
 | 
						|
                dst += signdx;
 | 
						|
                mask = mask0;
 | 
						|
            }
 | 
						|
            e += e1;
 | 
						|
            if (e >= 0) {
 | 
						|
                if (bits) {
 | 
						|
                    WRITE(dst, FbDoMaskRRop (READ(dst), and, xor, bits));
 | 
						|
                    bits = 0;
 | 
						|
                }
 | 
						|
                dst += dstStride;
 | 
						|
                e += e3;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        if (bits)
 | 
						|
            WRITE(dst, FbDoMaskRRop(READ(dst), and, xor, bits));
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        while (len--) {
 | 
						|
            WRITE(dst, FbDoMaskRRop(READ(dst), and, xor, mask));
 | 
						|
            dst += dstStride;
 | 
						|
            e += e1;
 | 
						|
            if (e >= 0) {
 | 
						|
                e += e3;
 | 
						|
                mask = fbBresShiftMask(mask, signdx, dstBpp);
 | 
						|
                if (!mask) {
 | 
						|
                    dst += signdx;
 | 
						|
                    mask = mask0;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    fbFinishAccess(pDrawable);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
fbBresDash(DrawablePtr pDrawable,
 | 
						|
           GCPtr pGC,
 | 
						|
           int dashOffset,
 | 
						|
           int signdx,
 | 
						|
           int signdy, int axis, int x1, int y1, int e, int e1, int e3, int len)
 | 
						|
{
 | 
						|
    FbStip *dst;
 | 
						|
    FbStride dstStride;
 | 
						|
    int dstBpp;
 | 
						|
    int dstXoff, dstYoff;
 | 
						|
    FbGCPrivPtr pPriv = fbGetGCPrivate(pGC);
 | 
						|
    FbStip and = (FbStip) pPriv->and;
 | 
						|
    FbStip xor = (FbStip) pPriv->xor;
 | 
						|
    FbStip bgand = (FbStip) pPriv->bgand;
 | 
						|
    FbStip bgxor = (FbStip) pPriv->bgxor;
 | 
						|
    FbStip mask, mask0;
 | 
						|
 | 
						|
    FbDashDeclare;
 | 
						|
    int dashlen;
 | 
						|
    Bool even;
 | 
						|
    Bool doOdd;
 | 
						|
 | 
						|
    fbGetStipDrawable(pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
 | 
						|
    doOdd = pGC->lineStyle == LineDoubleDash;
 | 
						|
 | 
						|
    FbDashInit(pGC, pPriv, dashOffset, dashlen, even);
 | 
						|
 | 
						|
    dst += ((y1 + dstYoff) * dstStride);
 | 
						|
    x1 = (x1 + dstXoff) * dstBpp;
 | 
						|
    dst += x1 >> FB_STIP_SHIFT;
 | 
						|
    x1 &= FB_STIP_MASK;
 | 
						|
    mask0 = FbStipMask(0, dstBpp);
 | 
						|
    mask = FbStipRight(mask0, x1);
 | 
						|
    if (signdx < 0)
 | 
						|
        mask0 = FbStipRight(mask0, FB_STIP_UNIT - dstBpp);
 | 
						|
    if (signdy < 0)
 | 
						|
        dstStride = -dstStride;
 | 
						|
    while (len--) {
 | 
						|
        if (even)
 | 
						|
            WRITE(dst, FbDoMaskRRop(READ(dst), and, xor, mask));
 | 
						|
        else if (doOdd)
 | 
						|
            WRITE(dst, FbDoMaskRRop(READ(dst), bgand, bgxor, mask));
 | 
						|
        if (axis == X_AXIS) {
 | 
						|
            mask = fbBresShiftMask(mask, signdx, dstBpp);
 | 
						|
            if (!mask) {
 | 
						|
                dst += signdx;
 | 
						|
                mask = mask0;
 | 
						|
            }
 | 
						|
            e += e1;
 | 
						|
            if (e >= 0) {
 | 
						|
                dst += dstStride;
 | 
						|
                e += e3;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            dst += dstStride;
 | 
						|
            e += e1;
 | 
						|
            if (e >= 0) {
 | 
						|
                e += e3;
 | 
						|
                mask = fbBresShiftMask(mask, signdx, dstBpp);
 | 
						|
                if (!mask) {
 | 
						|
                    dst += signdx;
 | 
						|
                    mask = mask0;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        FbDashStep(dashlen, even);
 | 
						|
    }
 | 
						|
 | 
						|
    fbFinishAccess(pDrawable);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
fbBresFill(DrawablePtr pDrawable,
 | 
						|
           GCPtr pGC,
 | 
						|
           int dashOffset,
 | 
						|
           int signdx,
 | 
						|
           int signdy, int axis, int x1, int y1, int e, int e1, int e3, int len)
 | 
						|
{
 | 
						|
    while (len--) {
 | 
						|
        fbFill(pDrawable, pGC, x1, y1, 1, 1);
 | 
						|
        if (axis == X_AXIS) {
 | 
						|
            x1 += signdx;
 | 
						|
            e += e1;
 | 
						|
            if (e >= 0) {
 | 
						|
                e += e3;
 | 
						|
                y1 += signdy;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            y1 += signdy;
 | 
						|
            e += e1;
 | 
						|
            if (e >= 0) {
 | 
						|
                e += e3;
 | 
						|
                x1 += signdx;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
fbSetFg(DrawablePtr pDrawable, GCPtr pGC, Pixel fg)
 | 
						|
{
 | 
						|
    if (fg != pGC->fgPixel) {
 | 
						|
        ChangeGCVal val;
 | 
						|
 | 
						|
        val.val = fg;
 | 
						|
        ChangeGC(NullClient, pGC, GCForeground, &val);
 | 
						|
        ValidateGC(pDrawable, pGC);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
fbBresFillDash(DrawablePtr pDrawable,
 | 
						|
               GCPtr pGC,
 | 
						|
               int dashOffset,
 | 
						|
               int signdx,
 | 
						|
               int signdy,
 | 
						|
               int axis, int x1, int y1, int e, int e1, int e3, int len)
 | 
						|
{
 | 
						|
    FbGCPrivPtr pPriv = fbGetGCPrivate(pGC);
 | 
						|
 | 
						|
    FbDashDeclare;
 | 
						|
    int dashlen;
 | 
						|
    Bool even;
 | 
						|
    Bool doOdd;
 | 
						|
    Bool doBg;
 | 
						|
    Pixel fg, bg;
 | 
						|
 | 
						|
    fg = pGC->fgPixel;
 | 
						|
    bg = pGC->bgPixel;
 | 
						|
 | 
						|
    /* whether to fill the odd dashes */
 | 
						|
    doOdd = pGC->lineStyle == LineDoubleDash;
 | 
						|
    /* whether to switch fg to bg when filling odd dashes */
 | 
						|
    doBg = doOdd && (pGC->fillStyle == FillSolid ||
 | 
						|
                     pGC->fillStyle == FillStippled);
 | 
						|
 | 
						|
    /* compute current dash position */
 | 
						|
    FbDashInit(pGC, pPriv, dashOffset, dashlen, even);
 | 
						|
 | 
						|
    while (len--) {
 | 
						|
        if (even || doOdd) {
 | 
						|
            if (doBg) {
 | 
						|
                if (even)
 | 
						|
                    fbSetFg(pDrawable, pGC, fg);
 | 
						|
                else
 | 
						|
                    fbSetFg(pDrawable, pGC, bg);
 | 
						|
            }
 | 
						|
            fbFill(pDrawable, pGC, x1, y1, 1, 1);
 | 
						|
        }
 | 
						|
        if (axis == X_AXIS) {
 | 
						|
            x1 += signdx;
 | 
						|
            e += e1;
 | 
						|
            if (e >= 0) {
 | 
						|
                e += e3;
 | 
						|
                y1 += signdy;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            y1 += signdy;
 | 
						|
            e += e1;
 | 
						|
            if (e >= 0) {
 | 
						|
                e += e3;
 | 
						|
                x1 += signdx;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        FbDashStep(dashlen, even);
 | 
						|
    }
 | 
						|
    if (doBg)
 | 
						|
        fbSetFg(pDrawable, pGC, fg);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * For drivers that want to bail drawing some lines, this
 | 
						|
 * function takes care of selecting the appropriate rasterizer
 | 
						|
 * based on the contents of the specified GC.
 | 
						|
 */
 | 
						|
 | 
						|
static FbBres *
 | 
						|
fbSelectBres(DrawablePtr pDrawable, GCPtr pGC)
 | 
						|
{
 | 
						|
    FbGCPrivPtr pPriv = fbGetGCPrivate(pGC);
 | 
						|
    int dstBpp = pDrawable->bitsPerPixel;
 | 
						|
    FbBres *bres;
 | 
						|
 | 
						|
    if (pGC->lineStyle == LineSolid) {
 | 
						|
        bres = fbBresFill;
 | 
						|
        if (pGC->fillStyle == FillSolid) {
 | 
						|
            bres = fbBresSolid;
 | 
						|
            if (pPriv->and == 0) {
 | 
						|
                switch (dstBpp) {
 | 
						|
                case 8:
 | 
						|
                    bres = fbBresSolid8;
 | 
						|
                    break;
 | 
						|
                case 16:
 | 
						|
                    bres = fbBresSolid16;
 | 
						|
                    break;
 | 
						|
                case 32:
 | 
						|
                    bres = fbBresSolid32;
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        bres = fbBresFillDash;
 | 
						|
        if (pGC->fillStyle == FillSolid) {
 | 
						|
            bres = fbBresDash;
 | 
						|
            if (pPriv->and == 0 &&
 | 
						|
                (pGC->lineStyle == LineOnOffDash || pPriv->bgand == 0)) {
 | 
						|
                switch (dstBpp) {
 | 
						|
                case 8:
 | 
						|
                    bres = fbBresDash8;
 | 
						|
                    break;
 | 
						|
                case 16:
 | 
						|
                    bres = fbBresDash16;
 | 
						|
                    break;
 | 
						|
                case 32:
 | 
						|
                    bres = fbBresDash32;
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return bres;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
fbSegment(DrawablePtr pDrawable,
 | 
						|
          GCPtr pGC,
 | 
						|
          int x1, int y1, int x2, int y2, Bool drawLast, int *dashOffset)
 | 
						|
{
 | 
						|
    FbBres *bres;
 | 
						|
    RegionPtr pClip = fbGetCompositeClip(pGC);
 | 
						|
    BoxPtr pBox;
 | 
						|
    int nBox;
 | 
						|
    int adx;                    /* abs values of dx and dy */
 | 
						|
    int ady;
 | 
						|
    int signdx;                 /* sign of dx and dy */
 | 
						|
    int signdy;
 | 
						|
    int e, e1, e2, e3;          /* bresenham error and increments */
 | 
						|
    int len;                    /* length of segment */
 | 
						|
    int axis;                   /* major axis */
 | 
						|
    int octant;
 | 
						|
    int dashoff;
 | 
						|
    int doff;
 | 
						|
    unsigned int bias = miGetZeroLineBias(pDrawable->pScreen);
 | 
						|
    unsigned int oc1;           /* outcode of point 1 */
 | 
						|
    unsigned int oc2;           /* outcode of point 2 */
 | 
						|
 | 
						|
    nBox = RegionNumRects(pClip);
 | 
						|
    pBox = RegionRects(pClip);
 | 
						|
 | 
						|
    bres = fbSelectBres(pDrawable, pGC);
 | 
						|
 | 
						|
    CalcLineDeltas(x1, y1, x2, y2, adx, ady, signdx, signdy, 1, 1, octant);
 | 
						|
 | 
						|
    if (adx > ady) {
 | 
						|
        axis = X_AXIS;
 | 
						|
        e1 = ady << 1;
 | 
						|
        e2 = e1 - (adx << 1);
 | 
						|
        e = e1 - adx;
 | 
						|
        len = adx;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        axis = Y_AXIS;
 | 
						|
        e1 = adx << 1;
 | 
						|
        e2 = e1 - (ady << 1);
 | 
						|
        e = e1 - ady;
 | 
						|
        SetYMajorOctant(octant);
 | 
						|
        len = ady;
 | 
						|
    }
 | 
						|
 | 
						|
    FIXUP_ERROR(e, octant, bias);
 | 
						|
 | 
						|
    /*
 | 
						|
     * Adjust error terms to compare against zero
 | 
						|
     */
 | 
						|
    e3 = e2 - e1;
 | 
						|
    e = e - e1;
 | 
						|
 | 
						|
    /* we have bresenham parameters and two points.
 | 
						|
       all we have to do now is clip and draw.
 | 
						|
     */
 | 
						|
 | 
						|
    if (drawLast)
 | 
						|
        len++;
 | 
						|
    dashoff = *dashOffset;
 | 
						|
    *dashOffset = dashoff + len;
 | 
						|
    while (nBox--) {
 | 
						|
        oc1 = 0;
 | 
						|
        oc2 = 0;
 | 
						|
        OUTCODES(oc1, x1, y1, pBox);
 | 
						|
        OUTCODES(oc2, x2, y2, pBox);
 | 
						|
        if ((oc1 | oc2) == 0) {
 | 
						|
            (*bres) (pDrawable, pGC, dashoff,
 | 
						|
                     signdx, signdy, axis, x1, y1, e, e1, e3, len);
 | 
						|
            break;
 | 
						|
        }
 | 
						|
        else if (oc1 & oc2) {
 | 
						|
            pBox++;
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            int new_x1 = x1, new_y1 = y1, new_x2 = x2, new_y2 = y2;
 | 
						|
            int clip1 = 0, clip2 = 0;
 | 
						|
            int clipdx, clipdy;
 | 
						|
            int err;
 | 
						|
 | 
						|
            if (miZeroClipLine(pBox->x1, pBox->y1, pBox->x2 - 1,
 | 
						|
                               pBox->y2 - 1,
 | 
						|
                               &new_x1, &new_y1, &new_x2, &new_y2,
 | 
						|
                               adx, ady, &clip1, &clip2,
 | 
						|
                               octant, bias, oc1, oc2) == -1) {
 | 
						|
                pBox++;
 | 
						|
                continue;
 | 
						|
            }
 | 
						|
 | 
						|
            if (axis == X_AXIS)
 | 
						|
                len = abs(new_x2 - new_x1);
 | 
						|
            else
 | 
						|
                len = abs(new_y2 - new_y1);
 | 
						|
            if (clip2 != 0 || drawLast)
 | 
						|
                len++;
 | 
						|
            if (len) {
 | 
						|
                /* unwind bresenham error term to first point */
 | 
						|
                doff = dashoff;
 | 
						|
                err = e;
 | 
						|
                if (clip1) {
 | 
						|
                    clipdx = abs(new_x1 - x1);
 | 
						|
                    clipdy = abs(new_y1 - y1);
 | 
						|
                    if (axis == X_AXIS) {
 | 
						|
                        doff += clipdx;
 | 
						|
                        err += e3 * clipdy + e1 * clipdx;
 | 
						|
                    }
 | 
						|
                    else {
 | 
						|
                        doff += clipdy;
 | 
						|
                        err += e3 * clipdx + e1 * clipdy;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                (*bres) (pDrawable, pGC, doff,
 | 
						|
                         signdx, signdy, axis, new_x1, new_y1,
 | 
						|
                         err, e1, e3, len);
 | 
						|
            }
 | 
						|
            pBox++;
 | 
						|
        }
 | 
						|
    }                           /* while (nBox--) */
 | 
						|
}
 |