fbseg.c revision 05b261ec
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
36void
37fbBresSolid (DrawablePtr    pDrawable,
38	     GCPtr	    pGC,
39	     int	    dashOffset,
40	     int	    signdx,
41	     int	    signdy,
42	     int	    axis,
43	     int	    x1,
44	     int	    y1,
45	     int	    e,
46	     int	    e1,
47	     int	    e3,
48	     int	    len)
49{
50    FbStip	*dst;
51    FbStride	dstStride;
52    int		dstBpp;
53    int		dstXoff, dstYoff;
54    FbGCPrivPtr	pPriv = fbGetGCPrivate (pGC);
55    FbStip	and = (FbStip) pPriv->and;
56    FbStip	xor = (FbStip) pPriv->xor;
57    FbStip	mask, mask0;
58    FbStip	bits;
59
60    fbGetStipDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
61    dst += ((y1 + dstYoff) * dstStride);
62    x1 = (x1 + dstXoff) * dstBpp;
63    dst += x1 >> FB_STIP_SHIFT;
64    x1 &= FB_STIP_MASK;
65    mask0 = FbStipMask(0, dstBpp);
66    mask = FbStipRight (mask0, x1);
67    if (signdx < 0)
68	mask0 = FbStipRight (mask0, FB_STIP_UNIT - dstBpp);
69    if (signdy < 0)
70	dstStride = -dstStride;
71    if (axis == X_AXIS)
72    {
73	bits = 0;
74	while (len--)
75	{
76	    bits |= mask;
77	    mask = fbBresShiftMask(mask,signdx,dstBpp);
78	    if (!mask)
79	    {
80		WRITE(dst, FbDoMaskRRop (READ(dst), and, xor, bits));
81		bits = 0;
82		dst += signdx;
83		mask = mask0;
84	    }
85	    e += e1;
86	    if (e >= 0)
87	    {
88		WRITE(dst, FbDoMaskRRop (READ(dst), and, xor, bits));
89		bits = 0;
90		dst += dstStride;
91		e += e3;
92	    }
93	}
94	if (bits)
95	    WRITE(dst, FbDoMaskRRop (READ(dst), and, xor, bits));
96    }
97    else
98    {
99	while (len--)
100	{
101	    WRITE(dst, FbDoMaskRRop (READ(dst), and, xor, mask));
102	    dst += dstStride;
103	    e += e1;
104	    if (e >= 0)
105	    {
106		e += e3;
107		mask = fbBresShiftMask(mask,signdx,dstBpp);
108		if (!mask)
109		{
110		    dst += signdx;
111		    mask = mask0;
112		}
113	    }
114	}
115    }
116
117    fbFinishAccess (pDrawable);
118}
119
120void
121fbBresDash (DrawablePtr	pDrawable,
122	    GCPtr	pGC,
123	    int		dashOffset,
124	    int		signdx,
125	    int		signdy,
126	    int		axis,
127	    int		x1,
128	    int		y1,
129	    int		e,
130	    int		e1,
131	    int		e3,
132	    int		len)
133{
134    FbStip	*dst;
135    FbStride	dstStride;
136    int		dstBpp;
137    int		dstXoff, dstYoff;
138    FbGCPrivPtr	pPriv = fbGetGCPrivate (pGC);
139    FbStip	and = (FbStip) pPriv->and;
140    FbStip	xor = (FbStip) pPriv->xor;
141    FbStip	bgand = (FbStip) pPriv->bgand;
142    FbStip	bgxor = (FbStip) pPriv->bgxor;
143    FbStip	mask, mask0;
144    FbDashDeclare;
145    int		dashlen;
146    Bool	even;
147    Bool	doOdd;
148
149    fbGetStipDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
150    doOdd = pGC->lineStyle == LineDoubleDash;
151
152    FbDashInit (pGC, pPriv, dashOffset, dashlen, even);
153
154    dst += ((y1 + dstYoff) * dstStride);
155    x1 = (x1 + dstXoff) * dstBpp;
156    dst += x1 >> FB_STIP_SHIFT;
157    x1 &= FB_STIP_MASK;
158    mask0 = FbStipMask(0, dstBpp);
159    mask = FbStipRight (mask0, x1);
160    if (signdx < 0)
161	mask0 = FbStipRight (mask0, FB_STIP_UNIT - dstBpp);
162    if (signdy < 0)
163	dstStride = -dstStride;
164    while (len--)
165    {
166	if (even)
167	    WRITE(dst, FbDoMaskRRop (READ(dst), and, xor, mask));
168	else if (doOdd)
169	    WRITE(dst, FbDoMaskRRop (READ(dst), bgand, bgxor, mask));
170	if (axis == X_AXIS)
171	{
172	    mask = fbBresShiftMask(mask,signdx,dstBpp);
173	    if (!mask)
174	    {
175		dst += signdx;
176		mask = mask0;
177	    }
178	    e += e1;
179	    if (e >= 0)
180	    {
181		dst += dstStride;
182		e += e3;
183	    }
184	}
185	else
186	{
187	    dst += dstStride;
188	    e += e1;
189	    if (e >= 0)
190	    {
191		e += e3;
192		mask = fbBresShiftMask(mask,signdx,dstBpp);
193		if (!mask)
194		{
195		    dst += signdx;
196		    mask = mask0;
197		}
198	    }
199	}
200	FbDashStep (dashlen, even);
201    }
202
203    fbFinishAccess (pDrawable);
204}
205
206void
207fbBresFill (DrawablePtr	pDrawable,
208	    GCPtr	pGC,
209	    int		dashOffset,
210	    int		signdx,
211	    int		signdy,
212	    int		axis,
213	    int		x1,
214	    int		y1,
215	    int		e,
216	    int		e1,
217	    int		e3,
218	    int		len)
219{
220    while (len--)
221    {
222	fbFill (pDrawable, pGC, x1, y1, 1, 1);
223	if (axis == X_AXIS)
224	{
225	    x1 += signdx;
226	    e += e1;
227	    if (e >= 0)
228	    {
229		e += e3;
230		y1 += signdy;
231	    }
232	}
233	else
234	{
235	    y1 += signdy;
236	    e += e1;
237	    if (e >= 0)
238	    {
239		e += e3;
240		x1 += signdx;
241	    }
242	}
243    }
244}
245
246static void
247fbSetFg (DrawablePtr	pDrawable,
248	 GCPtr		pGC,
249	 Pixel		fg)
250{
251    if (fg != pGC->fgPixel)
252    {
253	DoChangeGC (pGC, GCForeground, (XID *) &fg, FALSE);
254	ValidateGC (pDrawable, pGC);
255    }
256}
257
258void
259fbBresFillDash (DrawablePtr pDrawable,
260		GCPtr	    pGC,
261		int	    dashOffset,
262		int	    signdx,
263		int	    signdy,
264		int	    axis,
265		int	    x1,
266		int	    y1,
267		int	    e,
268		int	    e1,
269		int	    e3,
270		int	    len)
271{
272    FbGCPrivPtr	pPriv = fbGetGCPrivate (pGC);
273    FbDashDeclare;
274    int		dashlen;
275    Bool	even;
276    Bool	doOdd;
277    Bool	doBg;
278    Pixel	fg, bg;
279
280    fg = pGC->fgPixel;
281    bg = pGC->bgPixel;
282
283    /* whether to fill the odd dashes */
284    doOdd = pGC->lineStyle == LineDoubleDash;
285    /* whether to switch fg to bg when filling odd dashes */
286    doBg = doOdd && (pGC->fillStyle == FillSolid ||
287		     pGC->fillStyle == FillStippled);
288
289    /* compute current dash position */
290    FbDashInit (pGC, pPriv, dashOffset, dashlen, even);
291
292    while (len--)
293    {
294	if (even || doOdd)
295	{
296	    if (doBg)
297	    {
298		if (even)
299		    fbSetFg (pDrawable, pGC, fg);
300		else
301		    fbSetFg (pDrawable, pGC, bg);
302	    }
303	    fbFill (pDrawable, pGC, x1, y1, 1, 1);
304	}
305	if (axis == X_AXIS)
306	{
307	    x1 += signdx;
308	    e += e1;
309	    if (e >= 0)
310	    {
311		e += e3;
312		y1 += signdy;
313	    }
314	}
315	else
316	{
317	    y1 += signdy;
318	    e += e1;
319	    if (e >= 0)
320	    {
321		e += e3;
322		x1 += signdx;
323	    }
324	}
325	FbDashStep (dashlen, even);
326    }
327    if (doBg)
328	fbSetFg (pDrawable, pGC, fg);
329}
330
331#ifdef FB_24BIT
332static void
333fbBresSolid24RRop (DrawablePtr  pDrawable,
334		   GCPtr	pGC,
335		   int		dashOffset,
336		   int		signdx,
337		   int		signdy,
338		   int		axis,
339		   int		x1,
340		   int		y1,
341		   int		e,
342		   int		e1,
343		   int		e3,
344		   int		len)
345{
346    FbStip	*dst;
347    FbStride	dstStride;
348    int		dstBpp;
349    int		dstXoff, dstYoff;
350    FbGCPrivPtr	pPriv = fbGetGCPrivate (pGC);
351    FbStip	and = pPriv->and;
352    FbStip	xor = pPriv->xor;
353    FbStip	leftMask, rightMask;
354    int		nl;
355    FbStip	*d;
356    int		x;
357    int		rot;
358    FbStip	andT, xorT;
359
360    fbGetStipDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
361    dst += ((y1 + dstYoff) * dstStride);
362    x1 = (x1 + dstXoff) * 24;
363    if (signdy < 0)
364	dstStride = -dstStride;
365    signdx *= 24;
366    while (len--)
367    {
368	d = dst + (x1 >> FB_STIP_SHIFT);
369	x = x1 & FB_STIP_MASK;
370	rot = FbFirst24Rot (x);
371	andT = FbRot24Stip(and,rot);
372	xorT = FbRot24Stip(xor,rot);
373	FbMaskStip (x, 24, leftMask, nl, rightMask);
374	if (leftMask)
375	{
376	    WRITE(d, FbDoMaskRRop (READ(d), andT, xorT, leftMask));
377	    d++;
378	    andT = FbNext24Stip (andT);
379	    xorT = FbNext24Stip (xorT);
380	}
381	if (rightMask)
382	    WRITE(d, FbDoMaskRRop (READ(d), andT, xorT, rightMask));
383	if (axis == X_AXIS)
384	{
385	    x1 += signdx;
386	    e += e1;
387	    if (e >= 0)
388	    {
389		e += e3;
390		dst += dstStride;
391	    }
392	}
393	else
394	{
395	    dst += dstStride;
396	    e += e1;
397	    if (e >= 0)
398	    {
399		e += e3;
400		x1 += signdx;
401	    }
402	}
403    }
404
405    fbFinishAccess (pDrawable);
406}
407
408static void
409fbBresDash24RRop (DrawablePtr	pDrawable,
410		  GCPtr		pGC,
411		  int		dashOffset,
412		  int		signdx,
413		  int		signdy,
414		  int		axis,
415		  int		x1,
416		  int		y1,
417		  int		e,
418		  int		e1,
419		  int		e3,
420		  int		len)
421{
422    FbStip	*dst;
423    FbStride	dstStride;
424    int		dstBpp;
425    int		dstXoff, dstYoff;
426    FbGCPrivPtr	pPriv = fbGetGCPrivate (pGC);
427    FbStip	andT, xorT;
428    FbStip	fgand = pPriv->and;
429    FbStip	fgxor = pPriv->xor;
430    FbStip	bgand = pPriv->bgand;
431    FbStip	bgxor = pPriv->bgxor;
432    FbStip	leftMask, rightMask;
433    int		nl;
434    FbStip	*d;
435    int		x;
436    int		rot;
437    FbDashDeclare;
438    int		dashlen;
439    Bool	even;
440    Bool	doOdd;
441
442    fbGetStipDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
443    doOdd = pGC->lineStyle == LineDoubleDash;
444
445    /* compute current dash position */
446    FbDashInit(pGC, pPriv, dashOffset, dashlen, even);
447
448    dst += ((y1 + dstYoff) * dstStride);
449    x1 = (x1 + dstXoff) * 24;
450    if (signdy < 0)
451	dstStride = -dstStride;
452    signdx *= 24;
453    while (len--)
454    {
455	if (even || doOdd)
456	{
457	    if (even)
458	    {
459		andT = fgand;
460		xorT = fgxor;
461	    }
462	    else
463	    {
464		andT = bgand;
465		xorT = bgxor;
466	    }
467	    d = dst + (x1 >> FB_STIP_SHIFT);
468	    x = x1 & FB_STIP_MASK;
469	    rot = FbFirst24Rot (x);
470	    andT = FbRot24Stip (andT, rot);
471	    xorT = FbRot24Stip (xorT, rot);
472	    FbMaskStip (x, 24, leftMask, nl, rightMask);
473	    if (leftMask)
474	    {
475		WRITE(d, FbDoMaskRRop (READ(d), andT, xorT, leftMask));
476		d++;
477		andT = FbNext24Stip (andT);
478		xorT = FbNext24Stip (xorT);
479	    }
480	    if (rightMask)
481		WRITE(d, FbDoMaskRRop (READ(d), andT, xorT, rightMask));
482	}
483	if (axis == X_AXIS)
484	{
485	    x1 += signdx;
486	    e += e1;
487	    if (e >= 0)
488	    {
489		e += e3;
490		dst += dstStride;
491	    }
492	}
493	else
494	{
495	    dst += dstStride;
496	    e += e1;
497	    if (e >= 0)
498	    {
499		e += e3;
500		x1 += signdx;
501	    }
502	}
503	FbDashStep (dashlen, even);
504    }
505
506    fbFinishAccess (pDrawable);
507}
508#endif
509
510/*
511 * For drivers that want to bail drawing some lines, this
512 * function takes care of selecting the appropriate rasterizer
513 * based on the contents of the specified GC.
514 */
515
516FbBres *
517fbSelectBres (DrawablePtr   pDrawable,
518	      GCPtr	    pGC)
519{
520    FbGCPrivPtr	pPriv = fbGetGCPrivate(pGC);
521    int		dstBpp = pDrawable->bitsPerPixel;
522    FbBres *	bres;
523
524    if (pGC->lineStyle == LineSolid)
525    {
526	bres = fbBresFill;
527	if (pGC->fillStyle == FillSolid)
528	{
529	    bres = fbBresSolid;
530#ifdef FB_24BIT
531	    if (dstBpp == 24)
532		bres = fbBresSolid24RRop;
533#endif
534#ifndef FBNOPIXADDR
535	    if (pPriv->and == 0)
536	    {
537		switch (dstBpp) {
538		case 8:	bres = fbBresSolid8; break;
539		case 16: bres = fbBresSolid16; break;
540#ifdef FB_24BIT
541		case 24: bres = fbBresSolid24; break;
542#endif
543		case 32: bres = fbBresSolid32; break;
544		}
545	    }
546#endif
547	}
548    }
549    else
550    {
551	bres = fbBresFillDash;
552	if (pGC->fillStyle == FillSolid)
553	{
554	    bres = fbBresDash;
555#ifdef FB_24BIT
556	    if (dstBpp == 24)
557		bres = fbBresDash24RRop;
558#endif
559#ifndef FBNOPIXADDR
560	    if (pPriv->and == 0 &&
561		(pGC->lineStyle == LineOnOffDash || pPriv->bgand == 0))
562	    {
563		switch (dstBpp) {
564		case 8:	bres = fbBresDash8; break;
565		case 16: bres = fbBresDash16; break;
566#ifdef FB_24BIT
567		case 24: bres = fbBresDash24; break;
568#endif
569		case 32: bres = fbBresDash32; break;
570		}
571	    }
572#endif
573	}
574    }
575    return bres;
576}
577
578void
579fbBres (DrawablePtr	pDrawable,
580	GCPtr		pGC,
581	int		dashOffset,
582	int		signdx,
583	int		signdy,
584	int		axis,
585	int		x1,
586	int		y1,
587	int		e,
588	int		e1,
589	int		e3,
590	int		len)
591{
592    (*fbSelectBres (pDrawable, pGC)) (pDrawable, pGC, dashOffset,
593				      signdx, signdy, axis, x1, y1,
594				      e, e1, e3, len);
595}
596
597void
598fbSegment (DrawablePtr	pDrawable,
599	   GCPtr	pGC,
600	   int		x1,
601	   int		y1,
602	   int		x2,
603	   int		y2,
604	   Bool		drawLast,
605	   int		*dashOffset)
606{
607    FbBres *	bres;
608    RegionPtr	pClip = fbGetCompositeClip(pGC);
609    BoxPtr	pBox;
610    int		nBox;
611    int		adx;		/* abs values of dx and dy */
612    int		ady;
613    int		signdx;		/* sign of dx and dy */
614    int		signdy;
615    int		e, e1, e2, e3;		/* bresenham error and increments */
616    int		len;			/* length of segment */
617    int		axis;			/* major axis */
618    int		octant;
619    int		dashoff;
620    int		doff;
621    unsigned int bias = miGetZeroLineBias(pDrawable->pScreen);
622    unsigned int oc1;	/* outcode of point 1 */
623    unsigned int oc2;	/* outcode of point 2 */
624
625    nBox = REGION_NUM_RECTS (pClip);
626    pBox = REGION_RECTS (pClip);
627
628    bres = fbSelectBres (pDrawable, pGC);
629
630    CalcLineDeltas(x1, y1, x2, y2, adx, ady, signdx, signdy,
631		   1, 1, octant);
632
633    if (adx > ady)
634    {
635	axis = X_AXIS;
636	e1 = ady << 1;
637	e2 = e1 - (adx << 1);
638	e = e1 - adx;
639	len = adx;
640    }
641    else
642    {
643	axis = Y_AXIS;
644	e1 = adx << 1;
645	e2 = e1 - (ady << 1);
646	e = e1 - ady;
647	SetYMajorOctant(octant);
648	len = ady;
649    }
650
651    FIXUP_ERROR (e, octant, bias);
652
653    /*
654     * Adjust error terms to compare against zero
655     */
656    e3 = e2 - e1;
657    e = e - e1;
658
659    /* we have bresenham parameters and two points.
660       all we have to do now is clip and draw.
661    */
662
663    if (drawLast)
664	len++;
665    dashoff = *dashOffset;
666    *dashOffset = dashoff + len;
667    while(nBox--)
668    {
669	oc1 = 0;
670	oc2 = 0;
671	OUTCODES(oc1, x1, y1, pBox);
672	OUTCODES(oc2, x2, y2, pBox);
673	if ((oc1 | oc2) == 0)
674	{
675	    (*bres) (pDrawable, pGC, dashoff,
676		     signdx, signdy, axis, x1, y1,
677		     e, e1, e3, len);
678	    break;
679	}
680	else if (oc1 & oc2)
681	{
682	    pBox++;
683	}
684	else
685	{
686	    int new_x1 = x1, new_y1 = y1, new_x2 = x2, new_y2 = y2;
687	    int clip1 = 0, clip2 = 0;
688	    int clipdx, clipdy;
689	    int err;
690
691	    if (miZeroClipLine(pBox->x1, pBox->y1, pBox->x2-1,
692			       pBox->y2-1,
693			       &new_x1, &new_y1, &new_x2, &new_y2,
694			       adx, ady, &clip1, &clip2,
695			       octant, bias, oc1, oc2) == -1)
696	    {
697		pBox++;
698		continue;
699	    }
700
701	    if (axis == X_AXIS)
702		len = abs(new_x2 - new_x1);
703	    else
704		len = abs(new_y2 - new_y1);
705	    if (clip2 != 0 || drawLast)
706		len++;
707	    if (len)
708	    {
709		/* unwind bresenham error term to first point */
710		doff = dashoff;
711		err = e;
712		if (clip1)
713		{
714		    clipdx = abs(new_x1 - x1);
715		    clipdy = abs(new_y1 - y1);
716		    if (axis == X_AXIS)
717		    {
718			doff += clipdx;
719			err  += e3 * clipdy + e1 * clipdx;
720		    }
721		    else
722		    {
723			doff += clipdy;
724			err  += e3 * clipdx + e1 * clipdy;
725		    }
726		}
727		(*bres) (pDrawable, pGC, doff,
728			 signdx, signdy, axis, new_x1, new_y1,
729			 err, e1, e3, len);
730	    }
731	    pBox++;
732	}
733    } /* while (nBox--) */
734}
735