First import
[xorg_rtime.git] / xorg-server-1.4 / cfb / cfbline.c
blob84c089a73edc1a31a8e097cb595e8fad83a3b6c6
1 /***********************************************************
3 Copyright 1987, 1998 The Open Group
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.
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
26 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
28 All Rights Reserved
30 Permission to use, copy, modify, and distribute this software and its
31 documentation for any purpose and without fee is hereby granted,
32 provided that the above copyright notice appear in all copies and that
33 both that copyright notice and this permission notice appear in
34 supporting documentation, and that the name of Digital not be
35 used in advertising or publicity pertaining to distribution of the
36 software without specific, written prior permission.
38 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
39 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
40 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
41 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
42 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
43 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
44 SOFTWARE.
46 ******************************************************************/
47 #ifdef HAVE_DIX_CONFIG_H
48 #include <dix-config.h>
49 #endif
51 #include <stdlib.h>
52 #include <X11/X.h>
54 #include "gcstruct.h"
55 #include "windowstr.h"
56 #include "pixmapstr.h"
57 #include "regionstr.h"
58 #include "scrnintstr.h"
59 #include "mistruct.h"
61 #include "cfb.h"
62 #include "cfbmskbits.h"
63 #include "miline.h"
65 /* single-pixel lines on a color frame buffer
67 NON-SLOPED LINES
68 horizontal lines are always drawn left to right; we have to
69 move the endpoints right by one after they're swapped.
70 horizontal lines will be confined to a single band of a
71 region. the code finds that band (giving up if the lower
72 bound of the band is above the line we're drawing); then it
73 finds the first box in that band that contains part of the
74 line. we clip the line to subsequent boxes in that band.
75 vertical lines are always drawn top to bottom (y-increasing.)
76 this requires adding one to the y-coordinate of each endpoint
77 after swapping.
79 SLOPED LINES
80 when clipping a sloped line, we bring the second point inside
81 the clipping box, rather than one beyond it, and then add 1 to
82 the length of the line before drawing it. this lets us use
83 the same box for finding the outcodes for both endpoints. since
84 the equation for clipping the second endpoint to an edge gives us
85 1 beyond the edge, we then have to move the point towards the
86 first point by one step on the major axis.
87 eventually, there will be a diagram here to explain what's going
88 on. the method uses Cohen-Sutherland outcodes to determine
89 outsideness, and a method similar to Pike's layers for doing the
90 actual clipping.
94 void
95 #ifdef POLYSEGMENT
96 cfbSegmentSS (pDrawable, pGC, nseg, pSeg)
97 DrawablePtr pDrawable;
98 GCPtr pGC;
99 int nseg;
100 register xSegment *pSeg;
101 #else
102 cfbLineSS (pDrawable, pGC, mode, npt, pptInit)
103 DrawablePtr pDrawable;
104 GCPtr pGC;
105 int mode; /* Origin or Previous */
106 int npt; /* number of points */
107 DDXPointPtr pptInit;
108 #endif
110 int nboxInit;
111 register int nbox;
112 BoxPtr pboxInit;
113 register BoxPtr pbox;
114 #ifndef POLYSEGMENT
115 register DDXPointPtr ppt; /* pointer to list of translated points */
116 #endif
118 unsigned int oc1; /* outcode of point 1 */
119 unsigned int oc2; /* outcode of point 2 */
121 CfbBits *addrl; /* address of destination pixmap */
122 int nlwidth; /* width in longwords of destination pixmap */
123 int xorg, yorg; /* origin of window */
125 int adx; /* abs values of dx and dy */
126 int ady;
127 int signdx; /* sign of dx and dy */
128 int signdy;
129 int e, e1, e2; /* bresenham error and increments */
130 int len; /* length of segment */
131 int axis; /* major axis */
132 int octant;
133 unsigned int bias = miGetZeroLineBias(pDrawable->pScreen);
135 /* a bunch of temporaries */
136 int tmp;
137 register int y1, y2;
138 register int x1, x2;
139 RegionPtr cclip;
140 cfbPrivGCPtr devPriv;
141 CfbBits xor, and;
142 int alu;
144 devPriv = cfbGetGCPrivate(pGC);
145 cclip = pGC->pCompositeClip;
146 pboxInit = REGION_RECTS(cclip);
147 nboxInit = REGION_NUM_RECTS(cclip);
149 cfbGetLongWidthAndPointer (pDrawable, nlwidth, addrl)
151 alu = devPriv->rop;
152 xor = devPriv->xor;
153 and = devPriv->and;
154 xorg = pDrawable->x;
155 yorg = pDrawable->y;
156 #ifdef POLYSEGMENT
157 while (nseg--)
158 #else
159 ppt = pptInit;
160 x2 = ppt->x + xorg;
161 y2 = ppt->y + yorg;
162 while(--npt)
163 #endif
165 nbox = nboxInit;
166 pbox = pboxInit;
168 #ifdef POLYSEGMENT
169 x1 = pSeg->x1 + xorg;
170 y1 = pSeg->y1 + yorg;
171 x2 = pSeg->x2 + xorg;
172 y2 = pSeg->y2 + yorg;
173 pSeg++;
174 #else
175 x1 = x2;
176 y1 = y2;
177 ++ppt;
178 if (mode == CoordModePrevious)
180 xorg = x1;
181 yorg = y1;
183 x2 = ppt->x + xorg;
184 y2 = ppt->y + yorg;
185 #endif
187 if (x1 == x2) /* vertical line */
189 /* make the line go top to bottom of screen, keeping
190 endpoint semantics
192 if (y1 > y2)
194 register int tmp;
196 tmp = y2;
197 y2 = y1 + 1;
198 y1 = tmp + 1;
199 #ifdef POLYSEGMENT
200 if (pGC->capStyle != CapNotLast)
201 y1--;
202 #endif
204 #ifdef POLYSEGMENT
205 else if (pGC->capStyle != CapNotLast)
206 y2++;
207 #endif
208 /* get to first band that might contain part of line */
209 while ((nbox) && (pbox->y2 <= y1))
211 pbox++;
212 nbox--;
215 if (nbox)
217 /* stop when lower edge of box is beyond end of line */
218 while((nbox) && (y2 >= pbox->y1))
220 if ((x1 >= pbox->x1) && (x1 < pbox->x2))
222 int y1t, y2t;
223 /* this box has part of the line in it */
224 y1t = max(y1, pbox->y1);
225 y2t = min(y2, pbox->y2);
226 if (y1t != y2t)
228 cfbVertS (alu, and, xor,
229 addrl, nlwidth,
230 x1, y1t, y2t-y1t);
233 nbox--;
234 pbox++;
237 #ifndef POLYSEGMENT
238 y2 = ppt->y + yorg;
239 #endif
241 else if (y1 == y2) /* horizontal line */
243 /* force line from left to right, keeping
244 endpoint semantics
246 if (x1 > x2)
248 register int tmp;
250 tmp = x2;
251 x2 = x1 + 1;
252 x1 = tmp + 1;
253 #ifdef POLYSEGMENT
254 if (pGC->capStyle != CapNotLast)
255 x1--;
256 #endif
258 #ifdef POLYSEGMENT
259 else if (pGC->capStyle != CapNotLast)
260 x2++;
261 #endif
263 /* find the correct band */
264 while( (nbox) && (pbox->y2 <= y1))
266 pbox++;
267 nbox--;
270 /* try to draw the line, if we haven't gone beyond it */
271 if ((nbox) && (pbox->y1 <= y1))
273 /* when we leave this band, we're done */
274 tmp = pbox->y1;
275 while((nbox) && (pbox->y1 == tmp))
277 int x1t, x2t;
279 if (pbox->x2 <= x1)
281 /* skip boxes until one might contain start point */
282 nbox--;
283 pbox++;
284 continue;
287 /* stop if left of box is beyond right of line */
288 if (pbox->x1 >= x2)
290 nbox = 0;
291 break;
294 x1t = max(x1, pbox->x1);
295 x2t = min(x2, pbox->x2);
296 if (x1t != x2t)
298 cfbHorzS (alu, and, xor,
299 addrl, nlwidth,
300 x1t, y1, x2t-x1t);
302 nbox--;
303 pbox++;
306 #ifndef POLYSEGMENT
307 x2 = ppt->x + xorg;
308 #endif
310 else /* sloped line */
312 CalcLineDeltas(x1, y1, x2, y2, adx, ady, signdx, signdy,
313 1, 1, octant);
315 if (adx > ady)
317 axis = X_AXIS;
318 e1 = ady << 1;
319 e2 = e1 - (adx << 1);
320 e = e1 - adx;
322 else
324 axis = Y_AXIS;
325 e1 = adx << 1;
326 e2 = e1 - (ady << 1);
327 e = e1 - ady;
328 SetYMajorOctant(octant);
331 FIXUP_ERROR(e, octant, bias);
333 /* we have bresenham parameters and two points.
334 all we have to do now is clip and draw.
337 while(nbox--)
339 oc1 = 0;
340 oc2 = 0;
341 OUTCODES(oc1, x1, y1, pbox);
342 OUTCODES(oc2, x2, y2, pbox);
343 if ((oc1 | oc2) == 0)
345 if (axis == X_AXIS)
346 len = adx;
347 else
348 len = ady;
349 #ifdef POLYSEGMENT
350 if (pGC->capStyle != CapNotLast)
351 len++;
352 #endif
353 cfbBresS (alu, and, xor,
354 addrl, nlwidth,
355 signdx, signdy, axis, x1, y1,
356 e, e1, e2, len);
357 break;
359 else if (oc1 & oc2)
361 pbox++;
363 else
365 int new_x1 = x1, new_y1 = y1, new_x2 = x2, new_y2 = y2;
366 int clip1 = 0, clip2 = 0;
367 int clipdx, clipdy;
368 int err;
370 if (miZeroClipLine(pbox->x1, pbox->y1, pbox->x2-1,
371 pbox->y2-1,
372 &new_x1, &new_y1, &new_x2, &new_y2,
373 adx, ady, &clip1, &clip2,
374 octant, bias, oc1, oc2) == -1)
376 pbox++;
377 continue;
380 if (axis == X_AXIS)
381 len = abs(new_x2 - new_x1);
382 else
383 len = abs(new_y2 - new_y1);
384 #ifdef POLYSEGMENT
385 if (clip2 != 0 || pGC->capStyle != CapNotLast)
386 len++;
387 #else
388 len += (clip2 != 0);
389 #endif
390 if (len)
392 /* unwind bresenham error term to first point */
393 if (clip1)
395 clipdx = abs(new_x1 - x1);
396 clipdy = abs(new_y1 - y1);
397 if (axis == X_AXIS)
398 err = e+((clipdy*e2) + ((clipdx-clipdy)*e1));
399 else
400 err = e+((clipdx*e2) + ((clipdy-clipdx)*e1));
402 else
403 err = e;
404 cfbBresS(alu, and, xor,
405 addrl, nlwidth,
406 signdx, signdy, axis, new_x1, new_y1,
407 err, e1, e2, len);
409 pbox++;
411 } /* while (nbox--) */
412 } /* sloped line */
413 } /* while (nline--) */
415 #ifndef POLYSEGMENT
416 /* paint the last point if the end style isn't CapNotLast.
417 (Assume that a projecting, butt, or round cap that is one
418 pixel wide is the same as the single pixel of the endpoint.)
421 if ((pGC->capStyle != CapNotLast) &&
422 ((ppt->x + xorg != pptInit->x + pDrawable->x) ||
423 (ppt->y + yorg != pptInit->y + pDrawable->y) ||
424 (ppt == pptInit + 1)))
426 nbox = nboxInit;
427 pbox = pboxInit;
428 while (nbox--)
430 if ((x2 >= pbox->x1) &&
431 (y2 >= pbox->y1) &&
432 (x2 < pbox->x2) &&
433 (y2 < pbox->y2))
435 CfbBits mask;
436 CfbBits scrbits;
438 #if PSZ == 24
439 mask = cfbmask[(x2 & 3)<<1];
440 addrl += (y2 * nlwidth) + ((x2*3) >> 2);
441 #else
442 mask = cfbmask[x2 & PIM];
443 addrl += (y2 * nlwidth) + (x2 >> PWSH);
444 #endif
445 scrbits = *addrl;
446 *addrl = (scrbits & ~mask) |
447 (DoRRop (scrbits, and, xor) & mask);
448 break;
450 else
451 pbox++;
454 #endif
458 * Draw dashed 1-pixel lines.
461 void
462 #ifdef POLYSEGMENT
463 cfbSegmentSD (pDrawable, pGC, nseg, pSeg)
464 DrawablePtr pDrawable;
465 register GCPtr pGC;
466 int nseg;
467 register xSegment *pSeg;
468 #else
469 cfbLineSD( pDrawable, pGC, mode, npt, pptInit)
470 DrawablePtr pDrawable;
471 register GCPtr pGC;
472 int mode; /* Origin or Previous */
473 int npt; /* number of points */
474 DDXPointPtr pptInit;
475 #endif
477 int nboxInit;
478 register int nbox;
479 BoxPtr pboxInit;
480 register BoxPtr pbox;
481 #ifndef POLYSEGMENT
482 register DDXPointPtr ppt; /* pointer to list of translated points */
483 #endif
485 register unsigned int oc1; /* outcode of point 1 */
486 register unsigned int oc2; /* outcode of point 2 */
488 CfbBits *addrl; /* address of destination pixmap */
489 int nlwidth; /* width in longwords of destination pixmap */
490 int xorg, yorg; /* origin of window */
492 int adx; /* abs values of dx and dy */
493 int ady;
494 int signdx; /* sign of dx and dy */
495 int signdy;
496 int e, e1, e2; /* bresenham error and increments */
497 int len; /* length of segment */
498 int axis; /* major axis */
499 int octant;
500 unsigned int bias = miGetZeroLineBias(pDrawable->pScreen);
501 int x1, x2, y1, y2;
502 RegionPtr cclip;
503 cfbRRopRec rrops[2];
504 unsigned char *pDash;
505 int dashOffset;
506 int numInDashList;
507 int dashIndex;
508 int isDoubleDash;
509 int dashIndexTmp, dashOffsetTmp;
510 int unclippedlen;
511 cfbPrivGCPtr devPriv;
513 devPriv = cfbGetGCPrivate(pGC);
514 cclip = pGC->pCompositeClip;
515 rrops[0].rop = devPriv->rop;
516 rrops[0].and = devPriv->and;
517 rrops[0].xor = devPriv->xor;
518 if (pGC->alu == GXcopy)
520 rrops[1].rop = GXcopy;
521 rrops[1].and = 0;
522 rrops[1].xor = PFILL (pGC->bgPixel);
524 else
526 rrops[1].rop = cfbReduceRasterOp (pGC->alu,
527 pGC->bgPixel, pGC->planemask,
528 &rrops[1].and, &rrops[1].xor);
530 pboxInit = REGION_RECTS(cclip);
531 nboxInit = REGION_NUM_RECTS(cclip);
533 cfbGetLongWidthAndPointer (pDrawable, nlwidth, addrl)
535 /* compute initial dash values */
537 pDash = (unsigned char *) pGC->dash;
538 numInDashList = pGC->numInDashList;
539 isDoubleDash = (pGC->lineStyle == LineDoubleDash);
540 dashIndex = 0;
541 dashOffset = 0;
542 miStepDash ((int)pGC->dashOffset, &dashIndex, pDash,
543 numInDashList, &dashOffset);
545 xorg = pDrawable->x;
546 yorg = pDrawable->y;
547 #ifdef POLYSEGMENT
548 while (nseg--)
549 #else
550 ppt = pptInit;
551 x2 = ppt->x + xorg;
552 y2 = ppt->y + yorg;
553 while(--npt)
554 #endif
556 nbox = nboxInit;
557 pbox = pboxInit;
559 #ifdef POLYSEGMENT
560 x1 = pSeg->x1 + xorg;
561 y1 = pSeg->y1 + yorg;
562 x2 = pSeg->x2 + xorg;
563 y2 = pSeg->y2 + yorg;
564 pSeg++;
565 #else
566 x1 = x2;
567 y1 = y2;
568 ++ppt;
569 if (mode == CoordModePrevious)
571 xorg = x1;
572 yorg = y1;
574 x2 = ppt->x + xorg;
575 y2 = ppt->y + yorg;
576 #endif
578 CalcLineDeltas(x1, y1, x2, y2, adx, ady, signdx, signdy, 1, 1, octant);
580 if (adx > ady)
582 axis = X_AXIS;
583 e1 = ady << 1;
584 e2 = e1 - (adx << 1);
585 e = e1 - adx;
586 unclippedlen = adx;
588 else
590 axis = Y_AXIS;
591 e1 = adx << 1;
592 e2 = e1 - (ady << 1);
593 e = e1 - ady;
594 unclippedlen = ady;
595 SetYMajorOctant(octant);
598 FIXUP_ERROR(e, octant, bias);
600 /* we have bresenham parameters and two points.
601 all we have to do now is clip and draw.
604 while(nbox--)
606 oc1 = 0;
607 oc2 = 0;
608 OUTCODES(oc1, x1, y1, pbox);
609 OUTCODES(oc2, x2, y2, pbox);
610 if ((oc1 | oc2) == 0)
612 #ifdef POLYSEGMENT
613 if (pGC->capStyle != CapNotLast)
614 unclippedlen++;
615 dashIndexTmp = dashIndex;
616 dashOffsetTmp = dashOffset;
617 cfbBresD (rrops,
618 &dashIndexTmp, pDash, numInDashList,
619 &dashOffsetTmp, isDoubleDash,
620 addrl, nlwidth,
621 signdx, signdy, axis, x1, y1,
622 e, e1, e2, unclippedlen);
623 break;
624 #else
625 cfbBresD (rrops,
626 &dashIndex, pDash, numInDashList,
627 &dashOffset, isDoubleDash,
628 addrl, nlwidth,
629 signdx, signdy, axis, x1, y1,
630 e, e1, e2, unclippedlen);
631 goto dontStep;
632 #endif
634 else if (oc1 & oc2)
636 pbox++;
638 else /* have to clip */
640 int new_x1 = x1, new_y1 = y1, new_x2 = x2, new_y2 = y2;
641 int clip1 = 0, clip2 = 0;
642 int clipdx, clipdy;
643 int err;
645 if (miZeroClipLine(pbox->x1, pbox->y1, pbox->x2-1,
646 pbox->y2-1,
647 &new_x1, &new_y1, &new_x2, &new_y2,
648 adx, ady, &clip1, &clip2,
649 octant, bias, oc1, oc2) == -1)
651 pbox++;
652 continue;
655 dashIndexTmp = dashIndex;
656 dashOffsetTmp = dashOffset;
658 if (clip1)
660 int dlen;
662 if (axis == X_AXIS)
663 dlen = abs(new_x1 - x1);
664 else
665 dlen = abs(new_y1 - y1);
666 miStepDash (dlen, &dashIndexTmp, pDash,
667 numInDashList, &dashOffsetTmp);
670 if (axis == X_AXIS)
671 len = abs(new_x2 - new_x1);
672 else
673 len = abs(new_y2 - new_y1);
674 #ifdef POLYSEGMENT
675 if (clip2 != 0 || pGC->capStyle != CapNotLast)
676 len++;
677 #else
678 len += (clip2 != 0);
679 #endif
680 if (len)
682 /* unwind bresenham error term to first point */
683 if (clip1)
685 clipdx = abs(new_x1 - x1);
686 clipdy = abs(new_y1 - y1);
687 if (axis == X_AXIS)
688 err = e+((clipdy*e2) + ((clipdx-clipdy)*e1));
689 else
690 err = e+((clipdx*e2) + ((clipdy-clipdx)*e1));
692 else
693 err = e;
694 cfbBresD (rrops,
695 &dashIndexTmp, pDash, numInDashList,
696 &dashOffsetTmp, isDoubleDash,
697 addrl, nlwidth,
698 signdx, signdy, axis, new_x1, new_y1,
699 err, e1, e2, len);
701 pbox++;
703 } /* while (nbox--) */
704 #ifndef POLYSEGMENT
706 * walk the dash list around to the next line
708 miStepDash (unclippedlen, &dashIndex, pDash,
709 numInDashList, &dashOffset);
710 dontStep: ;
711 #endif
712 } /* while (nline--) */
714 #ifndef POLYSEGMENT
715 /* paint the last point if the end style isn't CapNotLast.
716 (Assume that a projecting, butt, or round cap that is one
717 pixel wide is the same as the single pixel of the endpoint.)
720 if ((pGC->capStyle != CapNotLast) &&
721 ((dashIndex & 1) == 0 || isDoubleDash) &&
722 ((ppt->x + xorg != pptInit->x + pDrawable->x) ||
723 (ppt->y + yorg != pptInit->y + pDrawable->y) ||
724 (ppt == pptInit + 1)))
726 nbox = nboxInit;
727 pbox = pboxInit;
728 while (nbox--)
730 if ((x2 >= pbox->x1) &&
731 (y2 >= pbox->y1) &&
732 (x2 < pbox->x2) &&
733 (y2 < pbox->y2))
735 CfbBits mask;
736 int pix;
738 pix = 0;
739 if (dashIndex & 1)
740 pix = 1;
741 #if PSZ == 24
742 mask = cfbmask[(x2 & 3)<<1];
743 addrl += (y2 * nlwidth) + ((x2 *3)>> 2);
744 #else
745 mask = cfbmask[x2 & PIM];
746 addrl += (y2 * nlwidth) + (x2 >> PWSH);
747 #endif
748 *addrl = DoMaskRRop (*addrl, rrops[pix].and, rrops[pix].xor, mask);
749 break;
751 else
752 pbox++;
755 #endif