1 /*
2 * Copyright © 1998 Keith Packard
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of Keith Packard not be used in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific, written prior permission. Keith Packard makes no
11 * representations about the suitability of this software for any purpose. It
12 * is provided "as is" without express or implied warranty.
13 *
14 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
21 */
22
23 #ifdef HAVE_DIX_CONFIG_H
24 #include <dix-config.h>
25 #endif
26
27 #include <stdlib.h>
28
29 #include "fb.h"
30 #include "miline.h"
31
32 #define fbBresShiftMask(mask,dir,bpp) ((bpp == FB_STIP_UNIT) ? 0 : \
33 ((dir < 0) ? FbStipLeft(mask,bpp) : \
34 FbStipRight(mask,bpp)))
35
36 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)37 fbBresSolid(DrawablePtr pDrawable,
38 GCPtr pGC,
39 int dashOffset,
40 int signdx,
41 int signdy,
42 int axis, int x1, int y1, int e, int e1, int e3, int len)
43 {
44 FbStip *dst;
45 FbStride dstStride;
46 int dstBpp;
47 int dstXoff, dstYoff;
48 FbGCPrivPtr pPriv = fbGetGCPrivate(pGC);
49 FbStip and = (FbStip) pPriv->and;
50 FbStip xor = (FbStip) pPriv->xor;
51 FbStip mask, mask0;
52 FbStip bits;
53
54 fbGetStipDrawable(pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
55 dst += ((y1 + dstYoff) * dstStride);
56 x1 = (x1 + dstXoff) * dstBpp;
57 dst += x1 >> FB_STIP_SHIFT;
58 x1 &= FB_STIP_MASK;
59 mask0 = FbStipMask(0, dstBpp);
60 mask = FbStipRight(mask0, x1);
61 if (signdx < 0)
62 mask0 = FbStipRight(mask0, FB_STIP_UNIT - dstBpp);
63 if (signdy < 0)
64 dstStride = -dstStride;
65 if (axis == X_AXIS) {
66 bits = 0;
67 while (len--) {
68 bits |= mask;
69 mask = fbBresShiftMask(mask, signdx, dstBpp);
70 if (!mask) {
71 WRITE(dst, FbDoMaskRRop(READ(dst), and, xor, bits));
72 bits = 0;
73 dst += signdx;
74 mask = mask0;
75 }
76 e += e1;
77 if (e >= 0) {
78 if (bits) {
79 WRITE(dst, FbDoMaskRRop (READ(dst), and, xor, bits));
80 bits = 0;
81 }
82 dst += dstStride;
83 e += e3;
84 }
85 }
86 if (bits)
87 WRITE(dst, FbDoMaskRRop(READ(dst), and, xor, bits));
88 }
89 else {
90 while (len--) {
91 WRITE(dst, FbDoMaskRRop(READ(dst), and, xor, mask));
92 dst += dstStride;
93 e += e1;
94 if (e >= 0) {
95 e += e3;
96 mask = fbBresShiftMask(mask, signdx, dstBpp);
97 if (!mask) {
98 dst += signdx;
99 mask = mask0;
100 }
101 }
102 }
103 }
104
105 fbFinishAccess(pDrawable);
106 }
107
108 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)109 fbBresDash(DrawablePtr pDrawable,
110 GCPtr pGC,
111 int dashOffset,
112 int signdx,
113 int signdy, int axis, int x1, int y1, int e, int e1, int e3, int len)
114 {
115 FbStip *dst;
116 FbStride dstStride;
117 int dstBpp;
118 int dstXoff, dstYoff;
119 FbGCPrivPtr pPriv = fbGetGCPrivate(pGC);
120 FbStip and = (FbStip) pPriv->and;
121 FbStip xor = (FbStip) pPriv->xor;
122 FbStip bgand = (FbStip) pPriv->bgand;
123 FbStip bgxor = (FbStip) pPriv->bgxor;
124 FbStip mask, mask0;
125
126 FbDashDeclare;
127 int dashlen;
128 Bool even;
129 Bool doOdd;
130
131 fbGetStipDrawable(pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
132 doOdd = pGC->lineStyle == LineDoubleDash;
133
134 FbDashInit(pGC, pPriv, dashOffset, dashlen, even);
135
136 dst += ((y1 + dstYoff) * dstStride);
137 x1 = (x1 + dstXoff) * dstBpp;
138 dst += x1 >> FB_STIP_SHIFT;
139 x1 &= FB_STIP_MASK;
140 mask0 = FbStipMask(0, dstBpp);
141 mask = FbStipRight(mask0, x1);
142 if (signdx < 0)
143 mask0 = FbStipRight(mask0, FB_STIP_UNIT - dstBpp);
144 if (signdy < 0)
145 dstStride = -dstStride;
146 while (len--) {
147 if (even)
148 WRITE(dst, FbDoMaskRRop(READ(dst), and, xor, mask));
149 else if (doOdd)
150 WRITE(dst, FbDoMaskRRop(READ(dst), bgand, bgxor, mask));
151 if (axis == X_AXIS) {
152 mask = fbBresShiftMask(mask, signdx, dstBpp);
153 if (!mask) {
154 dst += signdx;
155 mask = mask0;
156 }
157 e += e1;
158 if (e >= 0) {
159 dst += dstStride;
160 e += e3;
161 }
162 }
163 else {
164 dst += dstStride;
165 e += e1;
166 if (e >= 0) {
167 e += e3;
168 mask = fbBresShiftMask(mask, signdx, dstBpp);
169 if (!mask) {
170 dst += signdx;
171 mask = mask0;
172 }
173 }
174 }
175 FbDashStep(dashlen, even);
176 }
177
178 fbFinishAccess(pDrawable);
179 }
180
181 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)182 fbBresFill(DrawablePtr pDrawable,
183 GCPtr pGC,
184 int dashOffset,
185 int signdx,
186 int signdy, int axis, int x1, int y1, int e, int e1, int e3, int len)
187 {
188 while (len--) {
189 fbFill(pDrawable, pGC, x1, y1, 1, 1);
190 if (axis == X_AXIS) {
191 x1 += signdx;
192 e += e1;
193 if (e >= 0) {
194 e += e3;
195 y1 += signdy;
196 }
197 }
198 else {
199 y1 += signdy;
200 e += e1;
201 if (e >= 0) {
202 e += e3;
203 x1 += signdx;
204 }
205 }
206 }
207 }
208
209 static void
fbSetFg(DrawablePtr pDrawable,GCPtr pGC,Pixel fg)210 fbSetFg(DrawablePtr pDrawable, GCPtr pGC, Pixel fg)
211 {
212 if (fg != pGC->fgPixel) {
213 ChangeGCVal val;
214
215 val.val = fg;
216 ChangeGC(NullClient, pGC, GCForeground, &val);
217 ValidateGC(pDrawable, pGC);
218 }
219 }
220
221 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)222 fbBresFillDash(DrawablePtr pDrawable,
223 GCPtr pGC,
224 int dashOffset,
225 int signdx,
226 int signdy,
227 int axis, int x1, int y1, int e, int e1, int e3, int len)
228 {
229 FbGCPrivPtr pPriv = fbGetGCPrivate(pGC);
230
231 FbDashDeclare;
232 int dashlen;
233 Bool even;
234 Bool doOdd;
235 Bool doBg;
236 Pixel fg, bg;
237
238 fg = pGC->fgPixel;
239 bg = pGC->bgPixel;
240
241 /* whether to fill the odd dashes */
242 doOdd = pGC->lineStyle == LineDoubleDash;
243 /* whether to switch fg to bg when filling odd dashes */
244 doBg = doOdd && (pGC->fillStyle == FillSolid ||
245 pGC->fillStyle == FillStippled);
246
247 /* compute current dash position */
248 FbDashInit(pGC, pPriv, dashOffset, dashlen, even);
249
250 while (len--) {
251 if (even || doOdd) {
252 if (doBg) {
253 if (even)
254 fbSetFg(pDrawable, pGC, fg);
255 else
256 fbSetFg(pDrawable, pGC, bg);
257 }
258 fbFill(pDrawable, pGC, x1, y1, 1, 1);
259 }
260 if (axis == X_AXIS) {
261 x1 += signdx;
262 e += e1;
263 if (e >= 0) {
264 e += e3;
265 y1 += signdy;
266 }
267 }
268 else {
269 y1 += signdy;
270 e += e1;
271 if (e >= 0) {
272 e += e3;
273 x1 += signdx;
274 }
275 }
276 FbDashStep(dashlen, even);
277 }
278 if (doBg)
279 fbSetFg(pDrawable, pGC, fg);
280 }
281
282 /*
283 * For drivers that want to bail drawing some lines, this
284 * function takes care of selecting the appropriate rasterizer
285 * based on the contents of the specified GC.
286 */
287
288 static FbBres *
fbSelectBres(DrawablePtr pDrawable,GCPtr pGC)289 fbSelectBres(DrawablePtr pDrawable, GCPtr pGC)
290 {
291 FbGCPrivPtr pPriv = fbGetGCPrivate(pGC);
292 int dstBpp = pDrawable->bitsPerPixel;
293 FbBres *bres;
294
295 if (pGC->lineStyle == LineSolid) {
296 bres = fbBresFill;
297 if (pGC->fillStyle == FillSolid) {
298 bres = fbBresSolid;
299 if (pPriv->and == 0) {
300 switch (dstBpp) {
301 case 8:
302 bres = fbBresSolid8;
303 break;
304 case 16:
305 bres = fbBresSolid16;
306 break;
307 case 32:
308 bres = fbBresSolid32;
309 break;
310 }
311 }
312 }
313 }
314 else {
315 bres = fbBresFillDash;
316 if (pGC->fillStyle == FillSolid) {
317 bres = fbBresDash;
318 if (pPriv->and == 0 &&
319 (pGC->lineStyle == LineOnOffDash || pPriv->bgand == 0)) {
320 switch (dstBpp) {
321 case 8:
322 bres = fbBresDash8;
323 break;
324 case 16:
325 bres = fbBresDash16;
326 break;
327 case 32:
328 bres = fbBresDash32;
329 break;
330 }
331 }
332 }
333 }
334 return bres;
335 }
336
337 void
fbSegment(DrawablePtr pDrawable,GCPtr pGC,int x1,int y1,int x2,int y2,Bool drawLast,int * dashOffset)338 fbSegment(DrawablePtr pDrawable,
339 GCPtr pGC,
340 int x1, int y1, int x2, int y2, Bool drawLast, int *dashOffset)
341 {
342 FbBres *bres;
343 RegionPtr pClip = fbGetCompositeClip(pGC);
344 BoxPtr pBox;
345 int nBox;
346 int adx; /* abs values of dx and dy */
347 int ady;
348 int signdx; /* sign of dx and dy */
349 int signdy;
350 int e, e1, e2, e3; /* bresenham error and increments */
351 int len; /* length of segment */
352 int axis; /* major axis */
353 int octant;
354 int dashoff;
355 int doff;
356 unsigned int bias = miGetZeroLineBias(pDrawable->pScreen);
357 unsigned int oc1; /* outcode of point 1 */
358 unsigned int oc2; /* outcode of point 2 */
359
360 nBox = RegionNumRects(pClip);
361 pBox = RegionRects(pClip);
362
363 bres = fbSelectBres(pDrawable, pGC);
364
365 CalcLineDeltas(x1, y1, x2, y2, adx, ady, signdx, signdy, 1, 1, octant);
366
367 if (adx > ady) {
368 axis = X_AXIS;
369 e1 = ady << 1;
370 e2 = e1 - (adx << 1);
371 e = e1 - adx;
372 len = adx;
373 }
374 else {
375 axis = Y_AXIS;
376 e1 = adx << 1;
377 e2 = e1 - (ady << 1);
378 e = e1 - ady;
379 SetYMajorOctant(octant);
380 len = ady;
381 }
382
383 FIXUP_ERROR(e, octant, bias);
384
385 /*
386 * Adjust error terms to compare against zero
387 */
388 e3 = e2 - e1;
389 e = e - e1;
390
391 /* we have bresenham parameters and two points.
392 all we have to do now is clip and draw.
393 */
394
395 if (drawLast)
396 len++;
397 dashoff = *dashOffset;
398 *dashOffset = dashoff + len;
399 while (nBox--) {
400 oc1 = 0;
401 oc2 = 0;
402 OUTCODES(oc1, x1, y1, pBox);
403 OUTCODES(oc2, x2, y2, pBox);
404 if ((oc1 | oc2) == 0) {
405 (*bres) (pDrawable, pGC, dashoff,
406 signdx, signdy, axis, x1, y1, e, e1, e3, len);
407 break;
408 }
409 else if (oc1 & oc2) {
410 pBox++;
411 }
412 else {
413 int new_x1 = x1, new_y1 = y1, new_x2 = x2, new_y2 = y2;
414 int clip1 = 0, clip2 = 0;
415 int clipdx, clipdy;
416 int err;
417
418 if (miZeroClipLine(pBox->x1, pBox->y1, pBox->x2 - 1,
419 pBox->y2 - 1,
420 &new_x1, &new_y1, &new_x2, &new_y2,
421 adx, ady, &clip1, &clip2,
422 octant, bias, oc1, oc2) == -1) {
423 pBox++;
424 continue;
425 }
426
427 if (axis == X_AXIS)
428 len = abs(new_x2 - new_x1);
429 else
430 len = abs(new_y2 - new_y1);
431 if (clip2 != 0 || drawLast)
432 len++;
433 if (len) {
434 /* unwind bresenham error term to first point */
435 doff = dashoff;
436 err = e;
437 if (clip1) {
438 clipdx = abs(new_x1 - x1);
439 clipdy = abs(new_y1 - y1);
440 if (axis == X_AXIS) {
441 doff += clipdx;
442 err += e3 * clipdy + e1 * clipdx;
443 }
444 else {
445 doff += clipdy;
446 err += e3 * clipdx + e1 * clipdy;
447 }
448 }
449 (*bres) (pDrawable, pGC, doff,
450 signdx, signdy, axis, new_x1, new_y1,
451 err, e1, e3, len);
452 }
453 pBox++;
454 }
455 } /* while (nBox--) */
456 }
457