Edit

IABSD.fr/xenocara/xserver/fb/fbseg.c

Branch :

  • Show log

    Commit

  • Author : matthieu
    Date : 2019-07-27 07:57:06
    Hash : a77e9959
    Message : Update to xserver 1.20.5. Tested by jsg@

  • xserver/fb/fbseg.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--) */
    }