diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2012-07-06 15:22:26 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2012-07-08 21:34:21 +0100 |
commit | e3e58123d36924c760ab6f58a7155a040422e91d (patch) | |
tree | 683b2db2d53d8abe790d34e431ddc7747d5639ff /src/sna/fb/fbseg.c | |
parent | 5d2f88fd9972c62c87098ddc7fee7b6f0cea0fdb (diff) |
sna: Fixup fb wrapper
To accommodate changes in the Xserver and avoid breakage; would have been
much easier had the fb been exported in the first place.
Diffstat (limited to 'src/sna/fb/fbseg.c')
-rw-r--r-- | src/sna/fb/fbseg.c | 563 |
1 files changed, 563 insertions, 0 deletions
diff --git a/src/sna/fb/fbseg.c b/src/sna/fb/fbseg.c new file mode 100644 index 00000000..5b8173f0 --- /dev/null +++ b/src/sna/fb/fbseg.c @@ -0,0 +1,563 @@ +/* + * Copyright © 1998 Keith Packard + * Copyright © 2012 Intel Corporation + * + * 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. + */ + +#include <stdlib.h> + +#include "fb.h" +#include "fbclip.h" +#include <mi.h> +#include <miline.h> +#include <scrnintstr.h> + +#define FbDashDeclare \ + unsigned char *__dash, *__firstDash, *__lastDash + +#define FbDashInit(gc,pgc,dashOffset,dashlen,even) { \ + (even) = TRUE; \ + __firstDash = (gc)->dash; \ + __lastDash = __firstDash + (gc)->numInDashList; \ + (dashOffset) %= (pgc)->dashLength; \ + \ + __dash = __firstDash; \ + while ((dashOffset) >= ((dashlen) = *__dash)) { \ + (dashOffset) -= (dashlen); \ + (even) = 1-(even); \ + if (++__dash == __lastDash) \ + __dash = __firstDash; \ + } \ + (dashlen) -= (dashOffset); \ +} + +#define FbDashNext(dashlen) { \ + if (++__dash == __lastDash) \ + __dash = __firstDash; \ + (dashlen) = *__dash; \ +} + +/* as numInDashList is always even, this case can skip a test */ + +#define FbDashNextEven(dashlen) { \ + (dashlen) = *++__dash; \ +} + +#define FbDashNextOdd(dashlen) FbDashNext(dashlen) + +#define FbDashStep(dashlen,even) { \ + if (!--(dashlen)) { \ + FbDashNext(dashlen); \ + (even) = 1-(even); \ + } \ +} + +#define fbBresShiftMask(mask,dir,bpp) ((bpp == FB_STIP_UNIT) ? 0 : \ + ((dir < 0) ? FbStipLeft(mask,bpp) : \ + FbStipRight(mask,bpp))) + +typedef void FbBres(DrawablePtr drawable, + GCPtr gc, + int dashOffset, + int sdx, + int sdy, + int axis, int x, int y, int e, int e1, int e3, int len); + +#define BRESSOLID fbBresSolid8 +#define BRESSOLIDR fbBresSolidR8 +#define BRESDASH fbBresDash8 +#define BITS BYTE +#define BITS2 CARD16 +#define BITS4 CARD32 +#include "fbsegbits.h" +#undef BRESSOLID +#undef BRESSOLIDR +#undef BRESDASH +#undef BITS +#undef BITS2 +#undef BITS4 + +#define BRESSOLID fbBresSolid16 +#define BRESSOLIDR fbBresSolidR16 +#define BRESDASH fbBresDash16 +#define BITS CARD16 +#define BITS2 CARD32 +#include "fbsegbits.h" +#undef BRESSOLID +#undef BRESSOLIDR +#undef BRESDASH +#undef BITS +#undef BITS2 + +#define BRESSOLID fbBresSolid32 +#define BRESSOLIDR fbBresSolidR32 +#define BRESDASH fbBresDash32 +#define BITS CARD32 +#include "fbsegbits.h" +#undef BRESSOLID +#undef BRESSOLIDR +#undef BRESDASH +#undef BITS + +static void +fbBresSolid(DrawablePtr drawable, GCPtr gc, int dashOffset, + int sdx, int sdy, int axis, + int x1, int y1, + int e, int e1, int e3, int len) +{ + FbStip *dst; + FbStride stride; + int bpp; + int dx, dy; + FbGCPrivPtr pgc = fb_gc(gc); + FbStip and = (FbStip) pgc->and; + FbStip xor = (FbStip) pgc->xor; + FbStip mask, mask0; + FbStip bits; + + fbGetStipDrawable(drawable, dst, stride, bpp, dx, dy); + dst += ((y1 + dy) * stride); + x1 = (x1 + dx) * bpp; + dst += x1 >> FB_STIP_SHIFT; + x1 &= FB_STIP_MASK; + mask0 = FbStipMask(0, bpp); + mask = FbStipRight(mask0, x1); + if (sdx < 0) + mask0 = FbStipRight(mask0, FB_STIP_UNIT - bpp); + if (sdy < 0) + stride = -stride; + if (axis == X_AXIS) { + bits = 0; + while (len--) { + bits |= mask; + mask = fbBresShiftMask(mask, sdx, bpp); + if (!mask) { + WRITE(dst, FbDoMaskRRop(READ(dst), and, xor, bits)); + bits = 0; + dst += sdx; + mask = mask0; + } + e += e1; + if (e >= 0) { + WRITE(dst, FbDoMaskRRop(READ(dst), and, xor, bits)); + bits = 0; + dst += stride; + e += e3; + } + } + if (bits) + WRITE(dst, FbDoMaskRRop(READ(dst), and, xor, bits)); + } else { + while (len--) { + WRITE(dst, FbDoMaskRRop(READ(dst), and, xor, mask)); + dst += stride; + e += e1; + if (e >= 0) { + e += e3; + mask = fbBresShiftMask(mask, sdx, bpp); + if (!mask) { + dst += sdx; + mask = mask0; + } + } + } + } +} + +static void +fbBresDash(DrawablePtr drawable, GCPtr gc, int dashOffset, + int sdx, int sdy, int axis, + int x1, int y1, + int e, int e1, int e3, int len) +{ + FbStip *dst; + FbStride stride; + int bpp; + int dx, dy; + FbGCPrivPtr pgc = fb_gc(gc); + FbStip and = (FbStip) pgc->and; + FbStip xor = (FbStip) pgc->xor; + FbStip bgand = (FbStip) pgc->bgand; + FbStip bgxor = (FbStip) pgc->bgxor; + FbStip mask, mask0; + + FbDashDeclare; + int dashlen; + bool even; + bool doOdd; + + fbGetStipDrawable(drawable, dst, stride, bpp, dx, dy); + doOdd = gc->lineStyle == LineDoubleDash; + + FbDashInit(gc, pgc, dashOffset, dashlen, even); + + dst += ((y1 + dy) * stride); + x1 = (x1 + dx) * bpp; + dst += x1 >> FB_STIP_SHIFT; + x1 &= FB_STIP_MASK; + mask0 = FbStipMask(0, bpp); + mask = FbStipRight(mask0, x1); + if (sdx < 0) + mask0 = FbStipRight(mask0, FB_STIP_UNIT - bpp); + if (sdy < 0) + stride = -stride; + 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, sdx, bpp); + if (!mask) { + dst += sdx; + mask = mask0; + } + e += e1; + if (e >= 0) { + dst += stride; + e += e3; + } + } else { + dst += stride; + e += e1; + if (e >= 0) { + e += e3; + mask = fbBresShiftMask(mask, sdx, bpp); + if (!mask) { + dst += sdx; + mask = mask0; + } + } + } + FbDashStep(dashlen, even); + } +} + +static void +fbBresFill(DrawablePtr drawable, GCPtr gc, int dashOffset, + int sdx, int sdy, int axis, + int x1, int y1, + int e, int e1, int e3, int len) +{ + while (len--) { + fbFill(drawable, gc, x1, y1, 1, 1); + if (axis == X_AXIS) { + x1 += sdx; + e += e1; + if (e >= 0) { + e += e3; + y1 += sdy; + } + } else { + y1 += sdy; + e += e1; + if (e >= 0) { + e += e3; + x1 += sdx; + } + } + } +} + +static void +fbSetFg(DrawablePtr drawable, GCPtr gc, Pixel fg) +{ + if (fg != gc->fgPixel) { + gc->fgPixel = fg; + fbValidateGC(gc, GCForeground, drawable); + } +} + +static void +fbBresFillDash(DrawablePtr drawable, + GCPtr gc, + int dashOffset, + int sdx, + int sdy, + int axis, int x1, int y1, int e, int e1, int e3, int len) +{ + FbGCPrivPtr pgc = fb_gc(gc); + + FbDashDeclare; + int dashlen; + bool even; + bool doOdd; + bool doBg; + Pixel fg, bg; + + fg = gc->fgPixel; + bg = gc->bgPixel; + + /* whether to fill the odd dashes */ + doOdd = gc->lineStyle == LineDoubleDash; + /* whether to switch fg to bg when filling odd dashes */ + doBg = doOdd && (gc->fillStyle == FillSolid || + gc->fillStyle == FillStippled); + + /* compute current dash position */ + FbDashInit(gc, pgc, dashOffset, dashlen, even); + + while (len--) { + if (even || doOdd) { + if (doBg) { + if (even) + fbSetFg(drawable, gc, fg); + else + fbSetFg(drawable, gc, bg); + } + fbFill(drawable, gc, x1, y1, 1, 1); + } + if (axis == X_AXIS) { + x1 += sdx; + e += e1; + if (e >= 0) { + e += e3; + y1 += sdy; + } + } else { + y1 += sdy; + e += e1; + if (e >= 0) { + e += e3; + x1 += sdx; + } + } + FbDashStep(dashlen, even); + } + if (doBg) + fbSetFg(drawable, gc, fg); +} + +static FbBres * +fbSelectBres(DrawablePtr drawable, GCPtr gc) +{ + FbGCPrivPtr pgc = fb_gc(gc); + int bpp = drawable->bitsPerPixel; + FbBres *bres; + + DBG(("%s: line=%d, fill=%d, and=%lx, bgand=%lx\n", + __FUNCTION__, gc->lineStyle, gc->fillStyle, pgc->and, pgc->bgand)); + assert(gc->lineWidth == 0); + + if (gc->lineStyle == LineSolid) { + bres = fbBresFill; + if (gc->fillStyle == FillSolid) { + bres = fbBresSolid; + if (pgc->and == 0) { + switch (bpp) { + case 8: + bres = fbBresSolid8; + break; + case 16: + bres = fbBresSolid16; + break; + case 32: + bres = fbBresSolid32; + break; + } + } else { + switch (bpp) { + case 8: + bres = fbBresSolidR8; + break; + case 16: + bres = fbBresSolidR16; + break; + case 32: + bres = fbBresSolidR32; + break; + } + } + } + } else { + bres = fbBresFillDash; + if (gc->fillStyle == FillSolid) { + bres = fbBresDash; + if (pgc->and == 0 && + (gc->lineStyle == LineOnOffDash || pgc->bgand == 0)) { + switch (bpp) { + case 8: + bres = fbBresDash8; + break; + case 16: + bres = fbBresDash16; + break; + case 32: + bres = fbBresDash32; + break; + } + } + } + } + return bres; +} + +struct fbSegment { + FbBres *bres; + bool drawLast; + int *dashOffset; + int x1, y1, x2, y2; +}; + +static void +_fbSegment(DrawablePtr drawable, GCPtr gc, const BoxRec *b, void *_data) +{ + struct fbSegment *data = _data; + const unsigned int bias = miGetZeroLineBias(drawable->pScreen); + int adx, ady; /* abs values of dx and dy */ + int sdx, sdy; /* sign of dx and dy */ + int e, e1, e2, e3; /* bresenham error and increments */ + int len, axis, octant; + int dashoff, doff; + unsigned int oc1, oc2; + + DBG(("%s box=(%d, %d),(%d, %d)\n", + __FUNCTION__, b->x1, b->y1, b->x2, b->y2)); + + CalcLineDeltas(data->x1, data->y1, data->x2, data->y2, + adx, ady, sdx, sdy, 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; + + if (data->drawLast) + len++; + dashoff = *data->dashOffset; + *data->dashOffset = dashoff + len; + + oc1 = 0; + oc2 = 0; + OUTCODES(oc1, data->x1, data->y1, b); + OUTCODES(oc2, data->x2, data->y2, b); + if ((oc1 | oc2) == 0) { + data->bres(drawable, gc, dashoff, + sdx, sdy, axis, data->x1, data->y1, e, e1, e3, len); + } else if (oc1 & oc2) { + } else { + int new_x1 = data->x1, new_y1 = data->y1; + int new_x2 = data->x2, new_y2 = data->y2; + int clip1 = 0, clip2 = 0; + int clipdx, clipdy; + int err; + + if (miZeroClipLine(b->x1, b->y1, b->x2-1, b->y2-1, + &new_x1, &new_y1, &new_x2, &new_y2, + adx, ady, &clip1, &clip2, + octant, bias, oc1, oc2) == -1) + return; + + if (axis == X_AXIS) + len = abs(new_x2 - new_x1); + else + len = abs(new_y2 - new_y1); + if (clip2 != 0 || data->drawLast) + len++; + if (len) { + /* unwind bresenham error term to first point */ + doff = dashoff; + err = e; + if (clip1) { + clipdx = abs(new_x1 - data->x1); + clipdy = abs(new_y1 - data->y1); + if (axis == X_AXIS) { + doff += clipdx; + err += e3 * clipdy + e1 * clipdx; + } else { + doff += clipdy; + err += e3 * clipdx + e1 * clipdy; + } + } + data->bres(drawable, gc, doff, + sdx, sdy, axis, new_x1, new_y1, + err, e1, e3, len); + } + } +} + +void +fbSegment(DrawablePtr drawable, GCPtr gc, + int x1, int y1, int x2, int y2, + bool drawLast, int *dashOffset) +{ + struct fbSegment data; + BoxRec box; + + DBG(("%s (%d, %d), (%d, %d), drawLast?=%d\n", + __FUNCTION__, x1, y1, x2, y2, drawLast)); + + /* simple overestimate of line extents for clipping */ + box.x1 = x1 - 1; + box.y1 = y1 - 1; + box.x2 = x2 + 1; + box.y2 = y2 + 1; + + data.x1 = x1; + data.y1 = y1; + data.x2 = x2; + data.y2 = y2; + + data.dashOffset = dashOffset; + data.drawLast = drawLast; + data.bres = fbSelectBres(drawable, gc); + + fbDrawableRunUnclipped(drawable, gc, &box, _fbSegment, &data); +} + +void +fbSegment1(DrawablePtr drawable, GCPtr gc, const BoxRec *b, + int x1, int y1, int x2, int y2, + bool drawLast, int *dashOffset) +{ + struct fbSegment data; + + DBG(("%s (%d, %d), (%d, %d), drawLast?=%d\n", + __FUNCTION__, x1, y1, x2, y2, drawLast)); + + data.x1 = x1; + data.y1 = y1; + data.x2 = x2; + data.y2 = y2; + + data.dashOffset = dashOffset; + data.drawLast = drawLast; + data.bres = fbSelectBres(drawable, gc); + + _fbSegment(drawable, gc, b, &data); +} |