1/*
2 * Copyright © 1998 Keith Packard
3 * Copyright © 2012 Intel Corporation
4 *
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of Keith Packard not be used in
10 * advertising or publicity pertaining to distribution of the software without
11 * specific, written prior permission.  Keith Packard makes no
12 * representations about the suitability of this software for any purpose.  It
13 * is provided "as is" without express or implied warranty.
14 *
15 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
21 * PERFORMANCE OF THIS SOFTWARE.
22 */
23
24#define isClipped(c,ul,lr)  (((c) | ((c) - (ul)) | ((lr) - (c))) & 0x80008000)
25#define RROP(b,a,x)	WRITE((b), FbDoRRop (READ(b), (a), (x)))
26
27static void
28POLYLINE(DrawablePtr drawable, GCPtr gc, int mode, int n_0, DDXPointPtr pt_0)
29{
30	int xoff = drawable->x;
31	int yoff = drawable->y;
32	unsigned int bias = miGetZeroLineBias(drawable->pScreen);
33	const BoxRec *clip = region_rects(gc->pCompositeClip);
34	const BoxRec *const last_clip = clip + region_num_rects(gc->pCompositeClip);
35
36	FbBits *dst;
37	int dstStride;
38	int dstBpp;
39	int dstXoff, dstYoff;
40
41	BITS *bits, *bitsBase;
42	FbStride bitsStride;
43	BITS xor = fb_gc(gc)->xor;
44	BITS and = fb_gc(gc)->and;
45
46
47	int e, e1, e3, len;
48	int stepmajor, stepminor;
49	int octant;
50
51	if (mode == CoordModePrevious)
52		fbFixCoordModePrevious(n_0, pt_0);
53
54	fbGetDrawable(drawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
55	bitsStride = dstStride * (sizeof(FbBits) / sizeof(BITS));
56	bitsBase = ((BITS *) dst) + (yoff + dstYoff) * bitsStride + (xoff + dstXoff);
57
58	DBG(("%s: processing %ld clip boxes\n", __FUNCTION__, (long)(last_clip - clip)));
59	do {
60		INT32 *pt = (INT32 *)pt_0;
61		int n = n_0;
62		INT32 pt1, pt2;
63
64		INT32 ul = coordToInt(clip->x1 - xoff, clip->y1 - yoff);
65		INT32 lr = coordToInt(clip->x2 - xoff - 1, clip->y2 - yoff - 1);
66
67		DBG(("%s: clip box=(%d, %d), (%d, %d)\n", __FUNCTION__, clip->x1, clip->y1, clip->x2, clip->y2));
68
69		pt1 = *pt++; n--;
70		pt2 = *pt++; n--;
71		for (;;) {
72			if (isClipped(pt1, ul, lr) | isClipped(pt2, ul, lr)) {
73				int dashoffset = 0;
74				fbSegment1(drawable, gc, clip,
75					  intToX(pt1) + xoff, intToY(pt1) + yoff,
76					  intToX(pt2) + xoff, intToY(pt2) + yoff,
77					  n == 0 && gc->capStyle != CapNotLast, &dashoffset);
78				if (!n)
79					goto next_clip;
80
81				pt1 = pt2;
82				pt2 = *pt++;
83				n--;
84			} else {
85				bits = bitsBase + intToY(pt1) * bitsStride + intToX(pt1);
86				for (;;) {
87					CalcLineDeltas(intToX(pt1), intToY(pt1),
88						       intToX(pt2), intToY(pt2),
89						       len, e1, stepmajor, stepminor, 1, bitsStride,
90						       octant);
91					if (len < e1) {
92						e3 = len;
93						len = e1;
94						e1 = e3;
95
96						e3 = stepminor;
97						stepminor = stepmajor;
98						stepmajor = e3;
99						SetYMajorOctant(octant);
100					}
101					e = -len;
102					e1 <<= 1;
103					e3 = e << 1;
104					FIXUP_ERROR(e, octant, bias);
105					if (and == 0) {
106						while (len--) {
107							WRITE(bits, xor);
108							bits += stepmajor;
109							e += e1;
110							if (e >= 0) {
111								bits += stepminor;
112								e += e3;
113							}
114						}
115					} else {
116						while (len--) {
117							RROP(bits, and, xor);
118							bits += stepmajor;
119							e += e1;
120							if (e >= 0) {
121								bits += stepminor;
122								e += e3;
123							}
124						}
125					}
126					if (!n) {
127						if (gc->capStyle != CapNotLast &&
128						    pt2 != *((INT32 *)pt_0)) {
129							RROP(bits, and, xor);
130						}
131						goto next_clip;
132					}
133					pt1 = pt2;
134					pt2 = *pt++;
135					--n;
136					if (isClipped(pt2, ul, lr))
137						break;
138				}
139			}
140		}
141next_clip: (void)clip;
142	} while (++clip != last_clip);
143}
144
145static void
146POLYSEGMENT(DrawablePtr drawable, GCPtr gc, int n_0, xSegment *seg_0)
147{
148	int xoff = drawable->x;
149	int yoff = drawable->y;
150	unsigned int bias = miGetZeroLineBias(drawable->pScreen);
151	const BoxRec *clip = region_rects(gc->pCompositeClip);
152	const BoxRec *const last_clip = clip + region_num_rects(gc->pCompositeClip);
153
154	FbBits *dst;
155	int dstStride;
156	int dstBpp;
157	int dstXoff, dstYoff;
158
159	BITS *bits, *bitsBase;
160	FbStride bitsStride;
161	FbBits xor = fb_gc(gc)->xor;
162	FbBits and = fb_gc(gc)->and;
163
164	int e, e1, e3, len;
165	int stepmajor, stepminor;
166	int octant;
167	bool capNotLast = gc->capStyle == CapNotLast;
168
169	fbGetDrawable(drawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
170	bitsStride = dstStride * (sizeof(FbBits) / sizeof(BITS));
171	bitsBase =
172		((BITS *) dst) + (yoff + dstYoff) * bitsStride + (xoff + dstXoff);
173
174	DBG(("%s: processing %ld clip boxes\n", __FUNCTION__, (long)(last_clip - clip)));
175	do {
176		INT32 ul = coordToInt(clip->x1 - xoff, clip->y1 - yoff);
177		INT32 lr = coordToInt(clip->x2 - xoff - 1, clip->y2 - yoff - 1);
178		uint64_t *pt = (uint64_t *)seg_0;
179		int n = n_0;
180
181		DBG(("%s: clip box=(%d, %d), (%d, %d)\n", __FUNCTION__, clip->x1, clip->y1, clip->x2, clip->y2));
182
183		while (n--) {
184			union {
185				int32_t pt32[2];
186				uint64_t pt64;
187			} u;
188
189			u.pt64 = *pt++;
190			if (isClipped(u.pt32[0], ul, lr) | isClipped(u.pt32[1], ul, lr)) {
191				int dashoffset = 0;
192				fbSegment1(drawable, gc, clip,
193					  intToX(u.pt32[0]) + xoff, intToY(u.pt32[0]) + yoff,
194					  intToX(u.pt32[1]) + xoff, intToY(u.pt32[1]) + yoff,
195					  !capNotLast, &dashoffset);
196			} else {
197				CalcLineDeltas(intToX(u.pt32[0]), intToY(u.pt32[0]),
198					       intToX(u.pt32[1]), intToY(u.pt32[1]),
199					       len, e1, stepmajor, stepminor, 1, bitsStride,
200					       octant);
201				if (e1 == 0 && len > 3) {
202					int x1, x2;
203					FbBits *dstLine;
204					int dstX, width;
205					FbBits startmask, endmask;
206					int nmiddle;
207
208					if (stepmajor < 0) {
209						x1 = intToX(u.pt32[1]);
210						x2 = intToX(u.pt32[0]) + 1;
211						if (capNotLast)
212							x1++;
213					} else {
214						x1 = intToX(u.pt32[0]);
215						x2 = intToX(u.pt32[1]);
216						if (!capNotLast)
217							x2++;
218					}
219					dstX = (x1 + xoff + dstXoff) * (sizeof(BITS) * 8);
220					width = (x2 - x1) * (sizeof(BITS) * 8);
221
222					dstLine = dst + (intToY(u.pt32[0]) + yoff + dstYoff) * dstStride;
223					dstLine += dstX >> FB_SHIFT;
224					dstX &= FB_MASK;
225					FbMaskBits(dstX, width, startmask, nmiddle, endmask);
226					if (startmask) {
227						WRITE(dstLine,
228						      FbDoMaskRRop(READ(dstLine), and, xor,
229								   startmask));
230						dstLine++;
231					}
232					if (!and)
233						while (nmiddle--)
234							WRITE(dstLine++, xor);
235					else
236						while (nmiddle--) {
237							WRITE(dstLine,
238							      FbDoRRop(READ(dstLine), and, xor));
239							dstLine++;
240						}
241					if (endmask)
242						WRITE(dstLine,
243						      FbDoMaskRRop(READ(dstLine), and, xor,
244								   endmask));
245				} else {
246					bits = bitsBase + intToY(u.pt32[0]) * bitsStride + intToX(u.pt32[0]);
247					if (len < e1) {
248						e3 = len;
249						len = e1;
250						e1 = e3;
251
252						e3 = stepminor;
253						stepminor = stepmajor;
254						stepmajor = e3;
255						SetYMajorOctant(octant);
256					}
257					e = -len;
258					e1 <<= 1;
259					e3 = e << 1;
260					FIXUP_ERROR(e, octant, bias);
261					if (!capNotLast)
262						len++;
263					if (and == 0) {
264						while (len--) {
265							WRITE(bits, xor);
266							bits += stepmajor;
267							e += e1;
268							if (e >= 0) {
269								bits += stepminor;
270								e += e3;
271							}
272						}
273					} else {
274						while (len--) {
275							RROP(bits, and, xor);
276							bits += stepmajor;
277							e += e1;
278							if (e >= 0) {
279								bits += stepminor;
280								e += e3;
281							}
282						}
283					}
284				}
285			}
286		}
287	} while (++clip != last_clip);
288}
289
290#undef RROP
291#undef isClipped
292