1428d7b3dSmrg/*
2428d7b3dSmrg * Copyright © 1998 Keith Packard
3428d7b3dSmrg * Copyright © 2012 Intel Corporation
4428d7b3dSmrg *
5428d7b3dSmrg * Permission to use, copy, modify, distribute, and sell this software and its
6428d7b3dSmrg * documentation for any purpose is hereby granted without fee, provided that
7428d7b3dSmrg * the above copyright notice appear in all copies and that both that
8428d7b3dSmrg * copyright notice and this permission notice appear in supporting
9428d7b3dSmrg * documentation, and that the name of Keith Packard not be used in
10428d7b3dSmrg * advertising or publicity pertaining to distribution of the software without
11428d7b3dSmrg * specific, written prior permission.  Keith Packard makes no
12428d7b3dSmrg * representations about the suitability of this software for any purpose.  It
13428d7b3dSmrg * is provided "as is" without express or implied warranty.
14428d7b3dSmrg *
15428d7b3dSmrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16428d7b3dSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17428d7b3dSmrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18428d7b3dSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19428d7b3dSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20428d7b3dSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
21428d7b3dSmrg * PERFORMANCE OF THIS SOFTWARE.
22428d7b3dSmrg */
23428d7b3dSmrg
24428d7b3dSmrg#include <stdlib.h>
25428d7b3dSmrg
26428d7b3dSmrg#include "fb.h"
27428d7b3dSmrg#include "fbclip.h"
28428d7b3dSmrg#include <miline.h>
29428d7b3dSmrg#include <scrnintstr.h>
30428d7b3dSmrg
31428d7b3dSmrg#define FbDashDeclare	\
32428d7b3dSmrg    unsigned char	*__dash, *__firstDash, *__lastDash
33428d7b3dSmrg
34428d7b3dSmrg#define FbDashInit(gc,pgc,dashOffset,dashlen,even) {	    \
35428d7b3dSmrg    (even) = TRUE;					    \
36428d7b3dSmrg    __firstDash = (gc)->dash;				    \
37428d7b3dSmrg    __lastDash = __firstDash + (gc)->numInDashList;	    \
38428d7b3dSmrg    (dashOffset) %= (pgc)->dashLength;		    \
39428d7b3dSmrg							    \
40428d7b3dSmrg    __dash = __firstDash;				    \
41428d7b3dSmrg    while ((dashOffset) >= ((dashlen) = *__dash)) {	    \
42428d7b3dSmrg	(dashOffset) -= (dashlen);			    \
43428d7b3dSmrg	(even) = 1-(even);				    \
44428d7b3dSmrg	if (++__dash == __lastDash)			    \
45428d7b3dSmrg	    __dash = __firstDash;			    \
46428d7b3dSmrg    }							    \
47428d7b3dSmrg    (dashlen) -= (dashOffset);				    \
48428d7b3dSmrg}
49428d7b3dSmrg
50428d7b3dSmrg#define FbDashNext(dashlen) {				    \
51428d7b3dSmrg    if (++__dash == __lastDash)				    \
52428d7b3dSmrg	__dash = __firstDash;				    \
53428d7b3dSmrg    (dashlen) = *__dash;				    \
54428d7b3dSmrg}
55428d7b3dSmrg
56428d7b3dSmrg/* as numInDashList is always even, this case can skip a test */
57428d7b3dSmrg
58428d7b3dSmrg#define FbDashNextEven(dashlen) {			    \
59428d7b3dSmrg    (dashlen) = *++__dash;				    \
60428d7b3dSmrg}
61428d7b3dSmrg
62428d7b3dSmrg#define FbDashNextOdd(dashlen)	FbDashNext(dashlen)
63428d7b3dSmrg
64428d7b3dSmrg#define FbDashStep(dashlen,even) {			    \
65428d7b3dSmrg    if (!--(dashlen)) {					    \
66428d7b3dSmrg	FbDashNext(dashlen);				    \
67428d7b3dSmrg	(even) = 1-(even);				    \
68428d7b3dSmrg    }							    \
69428d7b3dSmrg}
70428d7b3dSmrg
71428d7b3dSmrg#define fbBresShiftMask(mask,dir,bpp) ((bpp == FB_STIP_UNIT) ? 0 : \
72428d7b3dSmrg					((dir < 0) ? FbStipLeft(mask,bpp) : \
73428d7b3dSmrg					 FbStipRight(mask,bpp)))
74428d7b3dSmrg
75428d7b3dSmrgtypedef void FbBres(DrawablePtr drawable,
76428d7b3dSmrg                    GCPtr gc,
77428d7b3dSmrg                    int dashOffset,
78428d7b3dSmrg                    int sdx,
79428d7b3dSmrg                    int sdy,
80428d7b3dSmrg                    int axis, int x, int y, int e, int e1, int e3, int len);
81428d7b3dSmrg
82428d7b3dSmrg#define BRESSOLID   fbBresSolid8
83428d7b3dSmrg#define BRESSOLIDR  fbBresSolidR8
84428d7b3dSmrg#define BRESDASH    fbBresDash8
85428d7b3dSmrg#define BITS	    BYTE
86428d7b3dSmrg#define BITS2	    CARD16
87428d7b3dSmrg#define BITS4	    CARD32
88428d7b3dSmrg#include "fbsegbits.h"
89428d7b3dSmrg#undef BRESSOLID
90428d7b3dSmrg#undef BRESSOLIDR
91428d7b3dSmrg#undef BRESDASH
92428d7b3dSmrg#undef BITS
93428d7b3dSmrg#undef BITS2
94428d7b3dSmrg#undef BITS4
95428d7b3dSmrg
96428d7b3dSmrg#define BRESSOLID   fbBresSolid16
97428d7b3dSmrg#define BRESSOLIDR  fbBresSolidR16
98428d7b3dSmrg#define BRESDASH    fbBresDash16
99428d7b3dSmrg#define BITS	    CARD16
100428d7b3dSmrg#define BITS2	    CARD32
101428d7b3dSmrg#include "fbsegbits.h"
102428d7b3dSmrg#undef BRESSOLID
103428d7b3dSmrg#undef BRESSOLIDR
104428d7b3dSmrg#undef BRESDASH
105428d7b3dSmrg#undef BITS
106428d7b3dSmrg#undef BITS2
107428d7b3dSmrg
108428d7b3dSmrg#define BRESSOLID   fbBresSolid32
109428d7b3dSmrg#define BRESSOLIDR  fbBresSolidR32
110428d7b3dSmrg#define BRESDASH    fbBresDash32
111428d7b3dSmrg#define BITS	    CARD32
112428d7b3dSmrg#include "fbsegbits.h"
113428d7b3dSmrg#undef BRESSOLID
114428d7b3dSmrg#undef BRESSOLIDR
115428d7b3dSmrg#undef BRESDASH
116428d7b3dSmrg#undef BITS
117428d7b3dSmrg
118428d7b3dSmrgstatic void
119428d7b3dSmrgfbBresSolid(DrawablePtr drawable, GCPtr gc, int dashOffset,
120428d7b3dSmrg            int sdx, int sdy, int axis,
121428d7b3dSmrg	    int x1, int y1,
122428d7b3dSmrg	    int e, int e1, int e3, int len)
123428d7b3dSmrg{
124428d7b3dSmrg	FbStip *dst;
125428d7b3dSmrg	FbStride stride;
126428d7b3dSmrg	int bpp;
127428d7b3dSmrg	int dx, dy;
128428d7b3dSmrg	FbGCPrivPtr pgc = fb_gc(gc);
129428d7b3dSmrg	FbStip and = (FbStip) pgc->and;
130428d7b3dSmrg	FbStip xor = (FbStip) pgc->xor;
131428d7b3dSmrg	FbStip mask, mask0;
132428d7b3dSmrg	FbStip bits;
133428d7b3dSmrg
134428d7b3dSmrg	fbGetStipDrawable(drawable, dst, stride, bpp, dx, dy);
135428d7b3dSmrg	dst += ((y1 + dy) * stride);
136428d7b3dSmrg	x1 = (x1 + dx) * bpp;
137428d7b3dSmrg	dst += x1 >> FB_STIP_SHIFT;
138428d7b3dSmrg	x1 &= FB_STIP_MASK;
139428d7b3dSmrg	mask0 = FbStipMask(0, bpp);
140428d7b3dSmrg	mask = FbStipRight(mask0, x1);
141428d7b3dSmrg	if (sdx < 0)
142428d7b3dSmrg		mask0 = FbStipRight(mask0, FB_STIP_UNIT - bpp);
143428d7b3dSmrg	if (sdy < 0)
144428d7b3dSmrg		stride = -stride;
145428d7b3dSmrg	if (axis == X_AXIS) {
146428d7b3dSmrg		bits = 0;
147428d7b3dSmrg		while (len--) {
148428d7b3dSmrg			bits |= mask;
149428d7b3dSmrg			mask = fbBresShiftMask(mask, sdx, bpp);
150428d7b3dSmrg			if (!mask) {
151428d7b3dSmrg				WRITE(dst, FbDoMaskRRop(READ(dst), and, xor, bits));
152428d7b3dSmrg				bits = 0;
153428d7b3dSmrg				dst += sdx;
154428d7b3dSmrg				mask = mask0;
155428d7b3dSmrg			}
156428d7b3dSmrg			e += e1;
157428d7b3dSmrg			if (e >= 0) {
158428d7b3dSmrg				WRITE(dst, FbDoMaskRRop(READ(dst), and, xor, bits));
159428d7b3dSmrg				bits = 0;
160428d7b3dSmrg				dst += stride;
161428d7b3dSmrg				e += e3;
162428d7b3dSmrg			}
163428d7b3dSmrg		}
164428d7b3dSmrg		if (bits)
165428d7b3dSmrg			WRITE(dst, FbDoMaskRRop(READ(dst), and, xor, bits));
166428d7b3dSmrg	} else {
167428d7b3dSmrg		while (len--) {
168428d7b3dSmrg			WRITE(dst, FbDoMaskRRop(READ(dst), and, xor, mask));
169428d7b3dSmrg			dst += stride;
170428d7b3dSmrg			e += e1;
171428d7b3dSmrg			if (e >= 0) {
172428d7b3dSmrg				e += e3;
173428d7b3dSmrg				mask = fbBresShiftMask(mask, sdx, bpp);
174428d7b3dSmrg				if (!mask) {
175428d7b3dSmrg					dst += sdx;
176428d7b3dSmrg					mask = mask0;
177428d7b3dSmrg				}
178428d7b3dSmrg			}
179428d7b3dSmrg		}
180428d7b3dSmrg	}
181428d7b3dSmrg}
182428d7b3dSmrg
183428d7b3dSmrgstatic void
184428d7b3dSmrgfbBresDash(DrawablePtr drawable, GCPtr gc, int dashOffset,
185428d7b3dSmrg           int sdx, int sdy, int axis,
186428d7b3dSmrg	   int x1, int y1,
187428d7b3dSmrg	   int e, int e1, int e3, int len)
188428d7b3dSmrg{
189428d7b3dSmrg	FbStip *dst;
190428d7b3dSmrg	FbStride stride;
191428d7b3dSmrg	int bpp;
192428d7b3dSmrg	int dx, dy;
193428d7b3dSmrg	FbGCPrivPtr pgc = fb_gc(gc);
194428d7b3dSmrg	FbStip and = (FbStip) pgc->and;
195428d7b3dSmrg	FbStip xor = (FbStip) pgc->xor;
196428d7b3dSmrg	FbStip bgand = (FbStip) pgc->bgand;
197428d7b3dSmrg	FbStip bgxor = (FbStip) pgc->bgxor;
198428d7b3dSmrg	FbStip mask, mask0;
199428d7b3dSmrg
200428d7b3dSmrg	FbDashDeclare;
201428d7b3dSmrg	int dashlen;
202428d7b3dSmrg	bool even;
203428d7b3dSmrg	bool doOdd;
204428d7b3dSmrg
205428d7b3dSmrg	fbGetStipDrawable(drawable, dst, stride, bpp, dx, dy);
206428d7b3dSmrg	doOdd = gc->lineStyle == LineDoubleDash;
207428d7b3dSmrg
208428d7b3dSmrg	FbDashInit(gc, pgc, dashOffset, dashlen, even);
209428d7b3dSmrg
210428d7b3dSmrg	dst += ((y1 + dy) * stride);
211428d7b3dSmrg	x1 = (x1 + dx) * bpp;
212428d7b3dSmrg	dst += x1 >> FB_STIP_SHIFT;
213428d7b3dSmrg	x1 &= FB_STIP_MASK;
214428d7b3dSmrg	mask0 = FbStipMask(0, bpp);
215428d7b3dSmrg	mask = FbStipRight(mask0, x1);
216428d7b3dSmrg	if (sdx < 0)
217428d7b3dSmrg		mask0 = FbStipRight(mask0, FB_STIP_UNIT - bpp);
218428d7b3dSmrg	if (sdy < 0)
219428d7b3dSmrg		stride = -stride;
220428d7b3dSmrg	while (len--) {
221428d7b3dSmrg		if (even)
222428d7b3dSmrg			WRITE(dst, FbDoMaskRRop(READ(dst), and, xor, mask));
223428d7b3dSmrg		else if (doOdd)
224428d7b3dSmrg			WRITE(dst, FbDoMaskRRop(READ(dst), bgand, bgxor, mask));
225428d7b3dSmrg		if (axis == X_AXIS) {
226428d7b3dSmrg			mask = fbBresShiftMask(mask, sdx, bpp);
227428d7b3dSmrg			if (!mask) {
228428d7b3dSmrg				dst += sdx;
229428d7b3dSmrg				mask = mask0;
230428d7b3dSmrg			}
231428d7b3dSmrg			e += e1;
232428d7b3dSmrg			if (e >= 0) {
233428d7b3dSmrg				dst += stride;
234428d7b3dSmrg				e += e3;
235428d7b3dSmrg			}
236428d7b3dSmrg		} else {
237428d7b3dSmrg			dst += stride;
238428d7b3dSmrg			e += e1;
239428d7b3dSmrg			if (e >= 0) {
240428d7b3dSmrg				e += e3;
241428d7b3dSmrg				mask = fbBresShiftMask(mask, sdx, bpp);
242428d7b3dSmrg				if (!mask) {
243428d7b3dSmrg					dst += sdx;
244428d7b3dSmrg					mask = mask0;
245428d7b3dSmrg				}
246428d7b3dSmrg			}
247428d7b3dSmrg		}
248428d7b3dSmrg		FbDashStep(dashlen, even);
249428d7b3dSmrg	}
250428d7b3dSmrg}
251428d7b3dSmrg
252428d7b3dSmrgstatic void
253428d7b3dSmrgfbBresFill(DrawablePtr drawable, GCPtr gc, int dashOffset,
254428d7b3dSmrg           int sdx, int sdy, int axis,
255428d7b3dSmrg	   int x1, int y1,
256428d7b3dSmrg	   int e, int e1, int e3, int len)
257428d7b3dSmrg{
258428d7b3dSmrg	while (len--) {
259428d7b3dSmrg		fbFill(drawable, gc, x1, y1, 1, 1);
260428d7b3dSmrg		if (axis == X_AXIS) {
261428d7b3dSmrg			x1 += sdx;
262428d7b3dSmrg			e += e1;
263428d7b3dSmrg			if (e >= 0) {
264428d7b3dSmrg				e += e3;
265428d7b3dSmrg				y1 += sdy;
266428d7b3dSmrg			}
267428d7b3dSmrg		} else {
268428d7b3dSmrg			y1 += sdy;
269428d7b3dSmrg			e += e1;
270428d7b3dSmrg			if (e >= 0) {
271428d7b3dSmrg				e += e3;
272428d7b3dSmrg				x1 += sdx;
273428d7b3dSmrg			}
274428d7b3dSmrg		}
275428d7b3dSmrg	}
276428d7b3dSmrg}
277428d7b3dSmrg
278428d7b3dSmrgstatic void
279428d7b3dSmrgfbSetFg(DrawablePtr drawable, GCPtr gc, Pixel fg)
280428d7b3dSmrg{
281428d7b3dSmrg	if (fg != gc->fgPixel) {
282428d7b3dSmrg		gc->fgPixel = fg;
283428d7b3dSmrg		fbValidateGC(gc, GCForeground, drawable);
284428d7b3dSmrg	}
285428d7b3dSmrg}
286428d7b3dSmrg
287428d7b3dSmrgstatic void
288428d7b3dSmrgfbBresFillDash(DrawablePtr drawable,
289428d7b3dSmrg               GCPtr gc,
290428d7b3dSmrg               int dashOffset,
291428d7b3dSmrg               int sdx,
292428d7b3dSmrg               int sdy,
293428d7b3dSmrg               int axis, int x1, int y1, int e, int e1, int e3, int len)
294428d7b3dSmrg{
295428d7b3dSmrg	FbGCPrivPtr pgc = fb_gc(gc);
296428d7b3dSmrg
297428d7b3dSmrg	FbDashDeclare;
298428d7b3dSmrg	int dashlen;
299428d7b3dSmrg	bool even;
300428d7b3dSmrg	bool doOdd;
301428d7b3dSmrg	bool doBg;
302428d7b3dSmrg	Pixel fg, bg;
303428d7b3dSmrg
304428d7b3dSmrg	fg = gc->fgPixel;
305428d7b3dSmrg	bg = gc->bgPixel;
306428d7b3dSmrg
307428d7b3dSmrg	/* whether to fill the odd dashes */
308428d7b3dSmrg	doOdd = gc->lineStyle == LineDoubleDash;
309428d7b3dSmrg	/* whether to switch fg to bg when filling odd dashes */
310428d7b3dSmrg	doBg = doOdd && (gc->fillStyle == FillSolid ||
311428d7b3dSmrg			 gc->fillStyle == FillStippled);
312428d7b3dSmrg
313428d7b3dSmrg	/* compute current dash position */
314428d7b3dSmrg	FbDashInit(gc, pgc, dashOffset, dashlen, even);
315428d7b3dSmrg
316428d7b3dSmrg	while (len--) {
317428d7b3dSmrg		if (even || doOdd) {
318428d7b3dSmrg			if (doBg) {
319428d7b3dSmrg				if (even)
320428d7b3dSmrg					fbSetFg(drawable, gc, fg);
321428d7b3dSmrg				else
322428d7b3dSmrg					fbSetFg(drawable, gc, bg);
323428d7b3dSmrg			}
324428d7b3dSmrg			fbFill(drawable, gc, x1, y1, 1, 1);
325428d7b3dSmrg		}
326428d7b3dSmrg		if (axis == X_AXIS) {
327428d7b3dSmrg			x1 += sdx;
328428d7b3dSmrg			e += e1;
329428d7b3dSmrg			if (e >= 0) {
330428d7b3dSmrg				e += e3;
331428d7b3dSmrg				y1 += sdy;
332428d7b3dSmrg			}
333428d7b3dSmrg		} else {
334428d7b3dSmrg			y1 += sdy;
335428d7b3dSmrg			e += e1;
336428d7b3dSmrg			if (e >= 0) {
337428d7b3dSmrg				e += e3;
338428d7b3dSmrg				x1 += sdx;
339428d7b3dSmrg			}
340428d7b3dSmrg		}
341428d7b3dSmrg		FbDashStep(dashlen, even);
342428d7b3dSmrg	}
343428d7b3dSmrg	if (doBg)
344428d7b3dSmrg		fbSetFg(drawable, gc, fg);
345428d7b3dSmrg}
346428d7b3dSmrg
347428d7b3dSmrgstatic FbBres *
348428d7b3dSmrgfbSelectBres(DrawablePtr drawable, GCPtr gc)
349428d7b3dSmrg{
350428d7b3dSmrg	FbGCPrivPtr pgc = fb_gc(gc);
351428d7b3dSmrg	int bpp = drawable->bitsPerPixel;
352428d7b3dSmrg	FbBres *bres;
353428d7b3dSmrg
354428d7b3dSmrg	DBG(("%s: line=%d, fill=%d, and=%lx, bgand=%lx\n",
355428d7b3dSmrg	     __FUNCTION__, gc->lineStyle, gc->fillStyle,
356428d7b3dSmrg	     (long)pgc->and, (long)pgc->bgand));
357428d7b3dSmrg	assert(gc->lineWidth == 0);
358428d7b3dSmrg
359428d7b3dSmrg	if (gc->lineStyle == LineSolid) {
360428d7b3dSmrg		bres = fbBresFill;
361428d7b3dSmrg		if (gc->fillStyle == FillSolid) {
362428d7b3dSmrg			bres = fbBresSolid;
363428d7b3dSmrg			if (pgc->and == 0) {
364428d7b3dSmrg				switch (bpp) {
365428d7b3dSmrg				case 8:
366428d7b3dSmrg					bres = fbBresSolid8;
367428d7b3dSmrg					break;
368428d7b3dSmrg				case 16:
369428d7b3dSmrg					bres = fbBresSolid16;
370428d7b3dSmrg					break;
371428d7b3dSmrg				case 32:
372428d7b3dSmrg					bres = fbBresSolid32;
373428d7b3dSmrg					break;
374428d7b3dSmrg				}
375428d7b3dSmrg			} else {
376428d7b3dSmrg				switch (bpp) {
377428d7b3dSmrg				case 8:
378428d7b3dSmrg					bres = fbBresSolidR8;
379428d7b3dSmrg					break;
380428d7b3dSmrg				case 16:
381428d7b3dSmrg					bres = fbBresSolidR16;
382428d7b3dSmrg					break;
383428d7b3dSmrg				case 32:
384428d7b3dSmrg					bres = fbBresSolidR32;
385428d7b3dSmrg					break;
386428d7b3dSmrg				}
387428d7b3dSmrg			}
388428d7b3dSmrg		}
389428d7b3dSmrg	} else {
390428d7b3dSmrg		bres = fbBresFillDash;
391428d7b3dSmrg		if (gc->fillStyle == FillSolid) {
392428d7b3dSmrg			bres = fbBresDash;
393428d7b3dSmrg			if (pgc->and == 0 &&
394428d7b3dSmrg			    (gc->lineStyle == LineOnOffDash || pgc->bgand == 0)) {
395428d7b3dSmrg				switch (bpp) {
396428d7b3dSmrg				case 8:
397428d7b3dSmrg					bres = fbBresDash8;
398428d7b3dSmrg					break;
399428d7b3dSmrg				case 16:
400428d7b3dSmrg					bres = fbBresDash16;
401428d7b3dSmrg					break;
402428d7b3dSmrg				case 32:
403428d7b3dSmrg					bres = fbBresDash32;
404428d7b3dSmrg					break;
405428d7b3dSmrg				}
406428d7b3dSmrg			}
407428d7b3dSmrg		}
408428d7b3dSmrg	}
409428d7b3dSmrg	return bres;
410428d7b3dSmrg}
411428d7b3dSmrg
412428d7b3dSmrgstruct fbSegment {
413428d7b3dSmrg	FbBres *bres;
414428d7b3dSmrg	bool drawLast;
415428d7b3dSmrg	int *dashOffset;
416428d7b3dSmrg	int x1, y1, x2, y2;
417428d7b3dSmrg};
418428d7b3dSmrg
419428d7b3dSmrgstatic void
420428d7b3dSmrg_fbSegment(DrawablePtr drawable, GCPtr gc, const BoxRec *b, void *_data)
421428d7b3dSmrg{
422428d7b3dSmrg	struct fbSegment *data = _data;
423428d7b3dSmrg	const unsigned int bias = miGetZeroLineBias(drawable->pScreen);
424428d7b3dSmrg	int adx, ady;               /* abs values of dx and dy */
425428d7b3dSmrg	int sdx, sdy;               /* sign of dx and dy */
426428d7b3dSmrg	int e, e1, e2, e3;          /* bresenham error and increments */
427428d7b3dSmrg	int len, axis, octant;
428428d7b3dSmrg	int dashoff, doff;
429428d7b3dSmrg	unsigned int oc1, oc2;
430428d7b3dSmrg
431428d7b3dSmrg	DBG(("%s box=(%d, %d),(%d, %d)\n",
432428d7b3dSmrg	     __FUNCTION__, b->x1, b->y1, b->x2, b->y2));
433428d7b3dSmrg
434428d7b3dSmrg	CalcLineDeltas(data->x1, data->y1, data->x2, data->y2,
435428d7b3dSmrg		       adx, ady, sdx, sdy, 1, 1, octant);
436428d7b3dSmrg
437428d7b3dSmrg	if (adx > ady) {
438428d7b3dSmrg		axis = X_AXIS;
439428d7b3dSmrg		e1 = ady << 1;
440428d7b3dSmrg		e2 = e1 - (adx << 1);
441428d7b3dSmrg		e = e1 - adx;
442428d7b3dSmrg		len = adx;
443428d7b3dSmrg	} else {
444428d7b3dSmrg		axis = Y_AXIS;
445428d7b3dSmrg		e1 = adx << 1;
446428d7b3dSmrg		e2 = e1 - (ady << 1);
447428d7b3dSmrg		e = e1 - ady;
448428d7b3dSmrg		SetYMajorOctant(octant);
449428d7b3dSmrg		len = ady;
450428d7b3dSmrg	}
451428d7b3dSmrg
452428d7b3dSmrg	FIXUP_ERROR(e, octant, bias);
453428d7b3dSmrg
454428d7b3dSmrg	/*
455428d7b3dSmrg	 * Adjust error terms to compare against zero
456428d7b3dSmrg	 */
457428d7b3dSmrg	e3 = e2 - e1;
458428d7b3dSmrg	e = e - e1;
459428d7b3dSmrg
460428d7b3dSmrg	if (data->drawLast)
461428d7b3dSmrg		len++;
462428d7b3dSmrg	dashoff = *data->dashOffset;
463428d7b3dSmrg	*data->dashOffset = dashoff + len;
464428d7b3dSmrg
465428d7b3dSmrg	oc1 = 0;
466428d7b3dSmrg	oc2 = 0;
467428d7b3dSmrg	OUTCODES(oc1, data->x1, data->y1, b);
468428d7b3dSmrg	OUTCODES(oc2, data->x2, data->y2, b);
469428d7b3dSmrg	if ((oc1 | oc2) == 0) {
470428d7b3dSmrg		data->bres(drawable, gc, dashoff,
471428d7b3dSmrg			   sdx, sdy, axis, data->x1, data->y1, e, e1, e3, len);
472428d7b3dSmrg	} else if (oc1 & oc2) {
473428d7b3dSmrg	} else {
474428d7b3dSmrg		int new_x1 = data->x1, new_y1 = data->y1;
475428d7b3dSmrg		int new_x2 = data->x2, new_y2 = data->y2;
476428d7b3dSmrg		int clip1 = 0, clip2 = 0;
477428d7b3dSmrg		int clipdx, clipdy;
478428d7b3dSmrg		int err;
479428d7b3dSmrg
480428d7b3dSmrg		if (miZeroClipLine(b->x1, b->y1, b->x2-1, b->y2-1,
481428d7b3dSmrg				   &new_x1, &new_y1, &new_x2, &new_y2,
482428d7b3dSmrg				   adx, ady, &clip1, &clip2,
483428d7b3dSmrg				   octant, bias, oc1, oc2) == -1)
484428d7b3dSmrg			return;
485428d7b3dSmrg
486428d7b3dSmrg		if (axis == X_AXIS)
487428d7b3dSmrg			len = abs(new_x2 - new_x1);
488428d7b3dSmrg		else
489428d7b3dSmrg			len = abs(new_y2 - new_y1);
490428d7b3dSmrg		if (clip2 != 0 || data->drawLast)
491428d7b3dSmrg			len++;
492428d7b3dSmrg		if (len) {
493428d7b3dSmrg			/* unwind bresenham error term to first point */
494428d7b3dSmrg			doff = dashoff;
495428d7b3dSmrg			err = e;
496428d7b3dSmrg			if (clip1) {
497428d7b3dSmrg				clipdx = abs(new_x1 - data->x1);
498428d7b3dSmrg				clipdy = abs(new_y1 - data->y1);
499428d7b3dSmrg				if (axis == X_AXIS) {
500428d7b3dSmrg					doff += clipdx;
501428d7b3dSmrg					err += e3 * clipdy + e1 * clipdx;
502428d7b3dSmrg				} else {
503428d7b3dSmrg					doff += clipdy;
504428d7b3dSmrg					err += e3 * clipdx + e1 * clipdy;
505428d7b3dSmrg				}
506428d7b3dSmrg			}
507428d7b3dSmrg			data->bres(drawable, gc, doff,
508428d7b3dSmrg				   sdx, sdy, axis, new_x1, new_y1,
509428d7b3dSmrg				   err, e1, e3, len);
510428d7b3dSmrg		}
511428d7b3dSmrg	}
512428d7b3dSmrg}
513428d7b3dSmrg
514428d7b3dSmrgvoid
515428d7b3dSmrgfbSegment(DrawablePtr drawable, GCPtr gc,
516428d7b3dSmrg          int x1, int y1, int x2, int y2,
517428d7b3dSmrg	  bool drawLast, int *dashOffset)
518428d7b3dSmrg{
519428d7b3dSmrg	struct fbSegment data;
520428d7b3dSmrg	BoxRec box;
521428d7b3dSmrg
522428d7b3dSmrg	DBG(("%s (%d, %d), (%d, %d), drawLast?=%d\n",
523428d7b3dSmrg	     __FUNCTION__, x1, y1, x2, y2, drawLast));
524428d7b3dSmrg
525428d7b3dSmrg	/* simple overestimate of line extents for clipping */
526428d7b3dSmrg	box.x1 = x1 - 1;
527428d7b3dSmrg	box.y1 = y1 - 1;
528428d7b3dSmrg	box.x2 = x2 + 1;
529428d7b3dSmrg	box.y2 = y2 + 1;
530428d7b3dSmrg
531428d7b3dSmrg	data.x1 = x1;
532428d7b3dSmrg	data.y1 = y1;
533428d7b3dSmrg	data.x2 = x2;
534428d7b3dSmrg	data.y2 = y2;
535428d7b3dSmrg
536428d7b3dSmrg	data.dashOffset = dashOffset;
537428d7b3dSmrg	data.drawLast = drawLast;
538428d7b3dSmrg	data.bres = fbSelectBres(drawable, gc);
539428d7b3dSmrg
540428d7b3dSmrg	fbDrawableRunUnclipped(drawable, gc, &box, _fbSegment, &data);
541428d7b3dSmrg}
542428d7b3dSmrg
543428d7b3dSmrgvoid
544428d7b3dSmrgfbSegment1(DrawablePtr drawable, GCPtr gc, const BoxRec *b,
545428d7b3dSmrg	   int x1, int y1, int x2, int y2,
546428d7b3dSmrg	   bool drawLast, int *dashOffset)
547428d7b3dSmrg{
548428d7b3dSmrg	struct fbSegment data;
549428d7b3dSmrg
550428d7b3dSmrg	DBG(("%s (%d, %d), (%d, %d), drawLast?=%d\n",
551428d7b3dSmrg	     __FUNCTION__, x1, y1, x2, y2, drawLast));
552428d7b3dSmrg
553428d7b3dSmrg	data.x1 = x1;
554428d7b3dSmrg	data.y1 = y1;
555428d7b3dSmrg	data.x2 = x2;
556428d7b3dSmrg	data.y2 = y2;
557428d7b3dSmrg
558428d7b3dSmrg	data.dashOffset = dashOffset;
559428d7b3dSmrg	data.drawLast = drawLast;
560428d7b3dSmrg	data.bres = fbSelectBres(drawable, gc);
561428d7b3dSmrg
562428d7b3dSmrg	_fbSegment(drawable, gc, b, &data);
563428d7b3dSmrg}
564