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#include "fb.h"
25
26/*
27 * This is a slight abuse of the preprocessor to generate repetitive
28 * code, the idea is to generate code for each case of a copy-mode
29 * transparent stipple
30 */
31#define LaneCases1(c,a) \
32	case c: while (n--) { FbLaneCase(c,a); a++; } break
33#define LaneCases2(c,a)	    LaneCases1(c,a); LaneCases1(c+1,a)
34#define LaneCases4(c,a)	    LaneCases2(c,a); LaneCases2(c+2,a)
35#define LaneCases8(c,a)	    LaneCases4(c,a); LaneCases4(c+4,a)
36#define LaneCases16(c,a)    LaneCases8(c,a); LaneCases8(c+8,a)
37
38#define LaneCases(a)	    LaneCases16(0,a)
39
40/*
41 * Repeat a transparent stipple across a scanline n times
42 */
43
44void
45fbTransparentSpan(FbBits * dst, FbBits stip, FbBits fgxor, int n)
46{
47	FbStip s;
48
49	s = ((FbStip) (stip) & 0x01);
50	s |= ((FbStip) (stip >> 8) & 0x02);
51	s |= ((FbStip) (stip >> 16) & 0x04);
52	s |= ((FbStip) (stip >> 24) & 0x08);
53	switch (s) {
54		LaneCases(dst);
55	}
56}
57
58static void
59fbEvenStipple(FbBits *dst, FbStride dstStride, int dstX, int dstBpp,
60              int width, int height,
61              FbStip *stip, FbStride stipStride,
62              int stipHeight,
63              FbBits fgand, FbBits fgxor, FbBits bgand, FbBits bgxor,
64	      int xRot, int yRot)
65{
66	FbBits startmask, endmask;
67	FbBits mask, and, xor;
68	int nmiddle, n;
69	FbStip *s, *stipEnd, bits;
70	int rot, stipX, stipY;
71	int pixelsPerDst;
72	const FbBits *fbBits;
73	Bool transparent;
74	int startbyte, endbyte;
75
76	/*
77	 * Check for a transparent stipple (stencil)
78	 */
79	transparent = FALSE;
80	if (dstBpp >= 8 && fgand == 0 && bgand == FB_ALLONES && bgxor == 0)
81		transparent = TRUE;
82
83	pixelsPerDst = FB_UNIT / dstBpp;
84	/*
85	 * Adjust dest pointers
86	 */
87	dst += dstX >> FB_SHIFT;
88	dstX &= FB_MASK;
89	FbMaskBitsBytes(dstX, width, fgand == 0 && bgand == 0,
90			startmask, startbyte, nmiddle, endmask, endbyte);
91
92	if (startmask)
93		dstStride--;
94	dstStride -= nmiddle;
95
96	xRot *= dstBpp;
97	/*
98	 * Compute stip start scanline and rotation parameters
99	 */
100	stipEnd = stip + stipStride * stipHeight;
101	modulus(-yRot, stipHeight, stipY);
102	s = stip + stipStride * stipY;
103	modulus(-xRot, FB_UNIT, stipX);
104	rot = stipX;
105
106	/*
107	 * Get pointer to stipple mask array for this depth
108	 */
109	/* fbStippleTable covers all valid bpp (4,8,16,32) */
110	fbBits = fbStippleTable[pixelsPerDst];
111
112	while (height--) {
113		/*
114		 * Extract stipple bits for this scanline;
115		 */
116		bits = READ(s);
117		s += stipStride;
118		if (s == stipEnd)
119			s = stip;
120		mask = fbBits[FbLeftStipBits(bits, pixelsPerDst)];
121		/*
122		 * Rotate into position and compute reduced rop values
123		 */
124		mask = FbRotLeft(mask, rot);
125		and = (fgand & mask) | (bgand & ~mask);
126		xor = (fgxor & mask) | (bgxor & ~mask);
127
128		if (transparent) {
129			if (startmask) {
130				fbTransparentSpan(dst, mask & startmask, fgxor, 1);
131				dst++;
132			}
133			fbTransparentSpan(dst, mask, fgxor, nmiddle);
134			dst += nmiddle;
135			if (endmask)
136				fbTransparentSpan(dst, mask & endmask, fgxor, 1);
137		} else {
138			/*
139			 * Fill scanline
140			 */
141			if (startmask) {
142				FbDoLeftMaskByteRRop(dst, startbyte, startmask, and, xor);
143				dst++;
144			}
145			n = nmiddle;
146			if (!and)
147				while (n--)
148					WRITE(dst++, xor);
149			else {
150				while (n--) {
151					WRITE(dst, FbDoRRop(READ(dst), and, xor));
152					dst++;
153				}
154			}
155			if (endmask)
156				FbDoRightMaskByteRRop(dst, endbyte, endmask, and, xor);
157		}
158		dst += dstStride;
159	}
160}
161
162static void
163fbOddStipple(FbBits *dst, FbStride dstStride, int dstX, int dstBpp,
164             int width, int height,
165             FbStip *stip, FbStride stipStride,
166             int stipWidth, int stipHeight,
167             FbBits fgand, FbBits fgxor, FbBits bgand, FbBits bgxor,
168	     int xRot, int yRot)
169{
170	int stipX, stipY, sx;
171	int widthTmp;
172	int h, w;
173	int x, y;
174
175	modulus(-yRot, stipHeight, stipY);
176	modulus(dstX / dstBpp - xRot, stipWidth, stipX);
177	y = 0;
178	while (height) {
179		h = stipHeight - stipY;
180		if (h > height)
181			h = height;
182		height -= h;
183		widthTmp = width;
184		x = dstX;
185		sx = stipX;
186		while (widthTmp) {
187			w = (stipWidth - sx) * dstBpp;
188			if (w > widthTmp)
189				w = widthTmp;
190			widthTmp -= w;
191			fbBltOne(stip + stipY * stipStride,
192				 stipStride,
193				 sx,
194				 dst + y * dstStride,
195				 dstStride, x, dstBpp, w, h, fgand, fgxor, bgand, bgxor);
196			x += w;
197			sx = 0;
198		}
199		y += h;
200		stipY = 0;
201	}
202}
203
204void
205fbStipple(FbBits *dst, FbStride dstStride, int dstX, int dstBpp,
206          int width, int height,
207          FbStip *stip, FbStride stipStride,
208          int stipWidth, int stipHeight, Bool even,
209          FbBits fgand, FbBits fgxor, FbBits bgand, FbBits bgxor,
210	  int xRot, int yRot)
211{
212	DBG(("%s stipple=%dx%d, size=%dx%d\n",
213	     __FUNCTION__, stipWidth, stipHeight, width, height));
214
215	if (even)
216		fbEvenStipple(dst, dstStride, dstX, dstBpp, width, height,
217			      stip, stipStride, stipHeight,
218			      fgand, fgxor, bgand, bgxor, xRot, yRot);
219	else
220		fbOddStipple(dst, dstStride, dstX, dstBpp, width, height,
221			     stip, stipStride, stipWidth, stipHeight,
222			     fgand, fgxor, bgand, bgxor, xRot, yRot);
223}
224