First import
[xorg_rtime.git] / xorg-server-1.4 / afb / afbline.c
blob9e2e4b9f42889a2121978b4a46844435698b5ffb
1 /***********************************************************
3 Copyright (c) 1987 X Consortium
5 Permission is hereby granted, free of charge, to any person obtaining a copy
6 of this software and associated documentation files (the "Software"), to deal
7 in the Software without restriction, including without limitation the rights
8 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 copies of the Software, and to permit persons to whom the Software is
10 furnished to do so, subject to the following conditions:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 Except as contained in this notice, the name of the X Consortium shall not be
23 used in advertising or otherwise to promote the sale, use or other dealings
24 in this Software without prior written authorization from the X Consortium.
27 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
29 All Rights Reserved
31 Permission to use, copy, modify, and distribute this software and its
32 documentation for any purpose and without fee is hereby granted,
33 provided that the above copyright notice appear in all copies and that
34 both that copyright notice and this permission notice appear in
35 supporting documentation, and that the name of Digital not be
36 used in advertising or publicity pertaining to distribution of the
37 software without specific, written prior permission.
39 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
40 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
41 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
42 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
43 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
44 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
45 SOFTWARE.
47 ******************************************************************/
49 #ifdef HAVE_DIX_CONFIG_H
50 #include <dix-config.h>
51 #endif
53 #include <X11/X.h>
54 #include <stdlib.h>
56 #include "gcstruct.h"
57 #include "windowstr.h"
58 #include "pixmapstr.h"
59 #include "regionstr.h"
60 #include "scrnintstr.h"
61 #include "mistruct.h"
63 #include "afb.h"
64 #include "maskbits.h"
65 #include "miline.h"
67 /* single-pixel lines on a color frame buffer
69 NON-SLOPED LINES
70 horizontal lines are always drawn left to right; we have to
71 move the endpoints right by one after they're swapped.
72 horizontal lines will be confined to a single band of a
73 region. the code finds that band (giving up if the lower
74 bound of the band is above the line we're drawing); then it
75 finds the first box in that band that contains part of the
76 line. we clip the line to subsequent boxes in that band.
77 vertical lines are always drawn top to bottom (y-increasing.)
78 this requires adding one to the y-coordinate of each endpoint
79 after swapping.
81 SLOPED LINES
82 when clipping a sloped line, we bring the second point inside
83 the clipping box, rather than one beyond it, and then add 1 to
84 the length of the line before drawing it. this lets us use
85 the same box for finding the outcodes for both endpoints. since
86 the equation for clipping the second endpoint to an edge gives us
87 1 beyond the edge, we then have to move the point towards the
88 first point by one step on the major axis.
89 eventually, there will be a diagram here to explain what's going
90 on. the method uses Cohen-Sutherland outcodes to determine
91 outsideness, and a method similar to Pike's layers for doing the
92 actual clipping.
96 void
97 #ifdef POLYSEGMENT
98 afbSegmentSS(pDrawable, pGC, nseg, pSeg)
99 DrawablePtr pDrawable;
100 GCPtr pGC;
101 int nseg;
102 register xSegment *pSeg;
103 #else
104 afbLineSS(pDrawable, pGC, mode, npt, pptInit)
105 DrawablePtr pDrawable;
106 GCPtr pGC;
107 int mode; /* Origin or Previous */
108 int npt; /* number of points */
109 DDXPointPtr pptInit;
110 #endif
112 int nboxInit;
113 register int nbox;
114 BoxPtr pboxInit;
115 register BoxPtr pbox;
116 #ifndef POLYSEGMENT
117 register DDXPointPtr ppt; /* pointer to list of translated points */
118 #endif
120 unsigned int oc1; /* outcode of point 1 */
121 unsigned int oc2; /* outcode of point 2 */
123 PixelType *addrlBase; /* pointer to start of drawable */
124 int nlwidth; /* width in longwords of destination pixmap */
125 int xorg, yorg; /* origin of window */
127 int adx; /* abs values of dx and dy */
128 int ady;
129 int signdx; /* sign of dx and dy */
130 int signdy;
131 int e, e1, e2; /* bresenham error and increments */
132 int len; /* length of segment */
133 int axis; /* major axis */
134 int octant;
135 unsigned int bias = miGetZeroLineBias(pDrawable->pScreen);
136 int depthDst;
137 #ifndef POLYSEGMENT
138 PixelType *addrl; /* address of destination pixmap */
139 int d;
140 #endif
141 int sizeDst;
142 unsigned char *rrops;
144 /* a bunch of temporaries */
145 register int y1, y2;
146 register int x1, x2;
147 RegionPtr cclip;
149 cclip = pGC->pCompositeClip;
150 rrops = ((afbPrivGC *)(pGC->devPrivates[afbGCPrivateIndex].ptr))->rrops;
151 pboxInit = REGION_RECTS(cclip);
152 nboxInit = REGION_NUM_RECTS(cclip);
154 afbGetPixelWidthSizeDepthAndPointer(pDrawable, nlwidth, sizeDst, depthDst,
155 addrlBase);
157 xorg = pDrawable->x;
158 yorg = pDrawable->y;
159 #ifdef POLYSEGMENT
160 while (nseg--)
161 #else
162 ppt = pptInit;
163 x2 = ppt->x + xorg;
164 y2 = ppt->y + yorg;
165 while(--npt)
166 #endif
168 nbox = nboxInit;
169 pbox = pboxInit;
171 #ifdef POLYSEGMENT
172 x1 = pSeg->x1 + xorg;
173 y1 = pSeg->y1 + yorg;
174 x2 = pSeg->x2 + xorg;
175 y2 = pSeg->y2 + yorg;
176 pSeg++;
177 #else
178 x1 = x2;
179 y1 = y2;
180 ++ppt;
181 if (mode == CoordModePrevious) {
182 xorg = x1;
183 yorg = y1;
185 x2 = ppt->x + xorg;
186 y2 = ppt->y + yorg;
187 #endif
189 if (x1 == x2) /* vertical line */
191 /* make the line go top to bottom of screen, keeping
192 endpoint semantics
194 if (y1 > y2) {
195 register int tmp;
197 tmp = y2;
198 y2 = y1 + 1;
199 y1 = tmp + 1;
200 #ifdef POLYSEGMENT
201 if (pGC->capStyle != CapNotLast)
202 y1--;
203 #endif
205 #ifdef POLYSEGMENT
206 else if (pGC->capStyle != CapNotLast)
207 y2++;
208 #endif
209 /* get to first band that might contain part of line */
210 while ((nbox) && (pbox->y2 <= y1)) {
211 pbox++;
212 nbox--;
215 if (nbox) {
216 /* stop when lower edge of box is beyond end of line */
217 while((nbox) && (y2 >= pbox->y1)) {
218 if ((x1 >= pbox->x1) && (x1 < pbox->x2)) {
219 int y1t, y2t;
220 /* this box has part of the line in it */
221 y1t = max(y1, pbox->y1);
222 y2t = min(y2, pbox->y2);
223 if (y1t != y2t)
224 afbVertS(addrlBase, nlwidth, sizeDst, depthDst, x1, y1t,
225 y2t-y1t, rrops); /* @@@ NEXT PLANE PASSED @@@ */
227 nbox--;
228 pbox++;
231 #ifndef POLYSEGMENT
232 y2 = ppt->y + yorg;
233 #endif
234 } else if (y1 == y2) /* horizontal line */ {
235 /* force line from left to right, keeping
236 endpoint semantics
238 if (x1 > x2) {
239 register int tmp;
241 tmp = x2;
242 x2 = x1 + 1;
243 x1 = tmp + 1;
244 #ifdef POLYSEGMENT
245 if (pGC->capStyle != CapNotLast)
246 x1--;
247 #endif
249 #ifdef POLYSEGMENT
250 else if (pGC->capStyle != CapNotLast)
251 x2++;
252 #endif
254 /* find the correct band */
255 while( (nbox) && (pbox->y2 <= y1)) {
256 pbox++;
257 nbox--;
260 /* try to draw the line, if we haven't gone beyond it */
261 if ((nbox) && (pbox->y1 <= y1)) {
262 int tmp;
264 /* when we leave this band, we're done */
265 tmp = pbox->y1;
266 while((nbox) && (pbox->y1 == tmp)) {
267 int x1t, x2t;
269 if (pbox->x2 <= x1) {
270 /* skip boxes until one might contain start point */
271 nbox--;
272 pbox++;
273 continue;
276 /* stop if left of box is beyond right of line */
277 if (pbox->x1 >= x2) {
278 nbox = 0;
279 break;
282 x1t = max(x1, pbox->x1);
283 x2t = min(x2, pbox->x2);
284 if (x1t != x2t)
285 afbHorzS(addrlBase, nlwidth, sizeDst, depthDst, x1t, y1,
286 x2t-x1t, rrops); /* @@@ NEXT PLANE PASSED @@@ */
287 nbox--;
288 pbox++;
291 #ifndef POLYSEGMENT
292 x2 = ppt->x + xorg;
293 #endif
295 else /* sloped line */
297 CalcLineDeltas(x1, y1, x2, y2, adx, ady,
298 signdx, signdy, 1, 1, octant);
300 if (adx > ady) {
301 axis = X_AXIS;
302 e1 = ady << 1;
303 e2 = e1 - (adx << 1);
304 e = e1 - adx;
305 } else {
306 axis = Y_AXIS;
307 e1 = adx << 1;
308 e2 = e1 - (ady << 1);
309 e = e1 - ady;
310 SetYMajorOctant(octant);
313 FIXUP_ERROR(e, octant, bias);
315 /* we have bresenham parameters and two points.
316 all we have to do now is clip and draw.
319 while(nbox--) {
320 oc1 = 0;
321 oc2 = 0;
322 OUTCODES(oc1, x1, y1, pbox);
323 OUTCODES(oc2, x2, y2, pbox);
324 if ((oc1 | oc2) == 0) {
325 if (axis == X_AXIS)
326 len = adx;
327 else
328 len = ady;
329 #ifdef POLYSEGMENT
330 if (pGC->capStyle != CapNotLast)
331 len++;
332 #endif
333 afbBresS(addrlBase, nlwidth, sizeDst, depthDst, signdx, signdy,
334 axis, x1, y1, e, e1, e2, len, rrops); /* @@@ NEXT PLANE PASSED @@@ */
335 break;
336 } else if (oc1 & oc2) {
337 pbox++;
338 } else {
339 int new_x1 = x1, new_y1 = y1, new_x2 = x2, new_y2 = y2;
340 int clip1 = 0, clip2 = 0;
341 int clipdx, clipdy;
342 int err;
344 if (miZeroClipLine(pbox->x1, pbox->y1, pbox->x2-1,
345 pbox->y2-1,
346 &new_x1, &new_y1, &new_x2, &new_y2,
347 adx, ady, &clip1, &clip2,
348 octant, bias, oc1, oc2) == -1) {
349 pbox++;
350 continue;
353 if (axis == X_AXIS)
354 len = abs(new_x2 - new_x1);
355 else
356 len = abs(new_y2 - new_y1);
357 #ifdef POLYSEGMENT
358 if (clip2 != 0 || pGC->capStyle != CapNotLast)
359 len++;
360 #else
361 len += (clip2 != 0);
362 #endif
363 if (len) {
364 /* unwind bresenham error term to first point */
365 if (clip1) {
366 clipdx = abs(new_x1 - x1);
367 clipdy = abs(new_y1 - y1);
368 if (axis == X_AXIS)
369 err = e+((clipdy*e2) + ((clipdx-clipdy)*e1));
370 else
371 err = e+((clipdx*e2) + ((clipdy-clipdx)*e1));
373 else
374 err = e;
375 afbBresS(addrlBase, nlwidth, sizeDst, depthDst, signdx,
376 signdy, axis, new_x1, new_y1, err, e1, e2, len,
377 rrops); /* @@@ NEXT PLANE PASSED @@@ */
379 pbox++;
381 } /* while (nbox--) */
382 } /* sloped line */
383 } /* while (nline--) */
385 #ifndef POLYSEGMENT
387 /* paint the last point if the end style isn't CapNotLast.
388 (Assume that a projecting, butt, or round cap that is one
389 pixel wide is the same as the single pixel of the endpoint.)
392 if ((pGC->capStyle != CapNotLast) &&
393 ((ppt->x + xorg != pptInit->x + pDrawable->x) ||
394 (ppt->y + yorg != pptInit->y + pDrawable->y) ||
395 (ppt == pptInit + 1))) {
396 nbox = nboxInit;
397 pbox = pboxInit;
398 while (nbox--) {
399 if ((x2 >= pbox->x1) && (y2 >= pbox->y1) && (x2 < pbox->x2) &&
400 (y2 < pbox->y2)) {
401 for (d = 0; d < depthDst; d++) {
402 addrl = afbScanline(addrlBase, x2, y2, nlwidth);
403 addrlBase += sizeDst; /* @@@ NEXT PLANE @@@ */
405 switch(rrops[d]) {
406 case RROP_BLACK:
407 *addrl &= mfbGetrmask(x2 & PIM);
408 break;
409 case RROP_WHITE:
410 *addrl |= mfbGetmask(x2 & PIM);
411 break;
412 case RROP_INVERT:
413 *addrl ^= mfbGetmask(x2 & PIM);
414 break;
415 case RROP_NOP:
416 break;
417 } /* switch */
418 } /* for (d = ...) */
419 break;
420 } else
421 pbox++;
424 #endif
428 * Draw dashed 1-pixel lines.
431 void
432 #ifdef POLYSEGMENT
433 afbSegmentSD(pDrawable, pGC, nseg, pSeg)
434 DrawablePtr pDrawable;
435 register GCPtr pGC;
436 int nseg;
437 register xSegment *pSeg;
438 #else
439 afbLineSD(pDrawable, pGC, mode, npt, pptInit)
440 DrawablePtr pDrawable;
441 register GCPtr pGC;
442 int mode; /* Origin or Previous */
443 int npt; /* number of points */
444 DDXPointPtr pptInit;
445 #endif
447 int nboxInit;
448 register int nbox;
449 BoxPtr pboxInit;
450 register BoxPtr pbox;
451 #ifndef POLYSEGMENT
452 register DDXPointPtr ppt; /* pointer to list of translated points */
453 #endif
455 register unsigned int oc1; /* outcode of point 1 */
456 register unsigned int oc2; /* outcode of point 2 */
458 PixelType *addrlBase; /* address of destination pixmap */
459 int nlwidth; /* width in longwords of destination pixmap */
460 int sizeDst;
461 int depthDst;
462 int xorg, yorg; /* origin of window */
464 int adx; /* abs values of dx and dy */
465 int ady;
466 int signdx; /* sign of dx and dy */
467 int signdy;
468 int e, e1, e2; /* bresenham error and increments */
469 int len; /* length of segment */
470 int axis; /* major axis */
471 int octant;
472 unsigned int bias = miGetZeroLineBias(pDrawable->pScreen);
473 int x1, x2, y1, y2;
474 RegionPtr cclip;
475 unsigned char *rrops;
476 unsigned char bgrrops[AFB_MAX_DEPTH];
477 unsigned char *pDash;
478 int dashOffset;
479 int numInDashList;
480 int dashIndex;
481 int isDoubleDash;
482 int dashIndexTmp, dashOffsetTmp;
483 int unclippedlen;
484 #ifndef POLYSEGMENT
485 PixelType *addrl;
486 int d;
487 #endif
489 cclip = pGC->pCompositeClip;
490 rrops = ((afbPrivGC *)(pGC->devPrivates[afbGCPrivateIndex].ptr))->rrops;
491 pboxInit = REGION_RECTS(cclip);
492 nboxInit = REGION_NUM_RECTS(cclip);
494 afbGetPixelWidthSizeDepthAndPointer(pDrawable, nlwidth, sizeDst, depthDst,
495 addrlBase);
497 /* compute initial dash values */
499 pDash = (unsigned char *) pGC->dash;
500 numInDashList = pGC->numInDashList;
501 isDoubleDash = (pGC->lineStyle == LineDoubleDash);
502 dashIndex = 0;
503 dashOffset = 0;
504 miStepDash ((int)pGC->dashOffset, &dashIndex, pDash,
505 numInDashList, &dashOffset);
507 if (isDoubleDash)
508 afbReduceRop (pGC->alu, pGC->bgPixel, pGC->planemask, pGC->depth,
509 bgrrops);
511 xorg = pDrawable->x;
512 yorg = pDrawable->y;
513 #ifdef POLYSEGMENT
514 while (nseg--)
515 #else
516 ppt = pptInit;
517 x2 = ppt->x + xorg;
518 y2 = ppt->y + yorg;
519 while(--npt)
520 #endif
522 nbox = nboxInit;
523 pbox = pboxInit;
525 #ifdef POLYSEGMENT
526 x1 = pSeg->x1 + xorg;
527 y1 = pSeg->y1 + yorg;
528 x2 = pSeg->x2 + xorg;
529 y2 = pSeg->y2 + yorg;
530 pSeg++;
531 #else
532 x1 = x2;
533 y1 = y2;
534 ++ppt;
535 if (mode == CoordModePrevious) {
536 xorg = x1;
537 yorg = y1;
539 x2 = ppt->x + xorg;
540 y2 = ppt->y + yorg;
541 #endif
543 CalcLineDeltas(x1, y1, x2, y2, adx, ady, signdx, signdy,
544 1, 1, octant);
546 if (adx > ady) {
547 axis = X_AXIS;
548 e1 = ady << 1;
549 e2 = e1 - (adx << 1);
550 e = e1 - adx;
551 unclippedlen = adx;
552 } else {
553 axis = Y_AXIS;
554 e1 = adx << 1;
555 e2 = e1 - (ady << 1);
556 e = e1 - ady;
557 unclippedlen = ady;
558 SetYMajorOctant(octant);
561 FIXUP_ERROR(e, octant, bias);
563 /* we have bresenham parameters and two points.
564 all we have to do now is clip and draw.
567 while(nbox--) {
568 oc1 = 0;
569 oc2 = 0;
570 OUTCODES(oc1, x1, y1, pbox);
571 OUTCODES(oc2, x2, y2, pbox);
572 if ((oc1 | oc2) == 0) {
573 #ifdef POLYSEGMENT
574 if (pGC->capStyle != CapNotLast)
575 unclippedlen++;
576 dashIndexTmp = dashIndex;
577 dashOffsetTmp = dashOffset;
578 afbBresD(&dashIndexTmp, pDash, numInDashList, &dashOffsetTmp,
579 isDoubleDash, addrlBase, nlwidth, sizeDst, depthDst,
580 signdx, signdy, axis, x1, y1, e, e1, e2, unclippedlen,
581 rrops, bgrrops); /* @@@ NEXT PLANE PASSED @@@ */
582 break;
583 #else
584 afbBresD(&dashIndex, pDash, numInDashList, &dashOffset,
585 isDoubleDash, addrlBase, nlwidth, sizeDst, depthDst,
586 signdx, signdy, axis, x1, y1, e, e1, e2, unclippedlen,
587 rrops, bgrrops); /* @@@ NEXT PLANE PASSED @@@ */
588 goto dontStep;
589 #endif
590 } else if (oc1 & oc2) {
591 pbox++;
592 } else /* have to clip */ {
593 int new_x1 = x1, new_y1 = y1, new_x2 = x2, new_y2 = y2;
594 int clip1 = 0, clip2 = 0;
595 int clipdx, clipdy;
596 int err;
598 if (miZeroClipLine(pbox->x1, pbox->y1, pbox->x2-1, pbox->y2-1,
599 &new_x1, &new_y1, &new_x2, &new_y2,
600 adx, ady, &clip1, &clip2,
601 octant, bias, oc1, oc2) == -1) {
602 pbox++;
603 continue;
605 dashIndexTmp = dashIndex;
606 dashOffsetTmp = dashOffset;
607 if (clip1) {
608 int dlen;
610 if (axis == X_AXIS)
611 dlen = abs(new_x1 - x1);
612 else
613 dlen = abs(new_y1 - y1);
614 miStepDash (dlen, &dashIndexTmp, pDash,
615 numInDashList, &dashOffsetTmp);
617 if (axis == X_AXIS)
618 len = abs(new_x2 - new_x1);
619 else
620 len = abs(new_y2 - new_y1);
621 #ifdef POLYSEGMENT
622 if (clip2 != 0 || pGC->capStyle != CapNotLast)
623 len++;
624 #else
625 len += (clip2 != 0);
626 #endif
627 if (len) {
628 /* unwind bresenham error term to first point */
629 if (clip1) {
630 clipdx = abs(new_x1 - x1);
631 clipdy = abs(new_y1 - y1);
632 if (axis == X_AXIS)
633 err = e+((clipdy*e2) + ((clipdx-clipdy)*e1));
634 else
635 err = e+((clipdx*e2) + ((clipdy-clipdx)*e1));
637 else
638 err = e;
639 afbBresD(&dashIndexTmp, pDash, numInDashList, &dashOffsetTmp,
640 isDoubleDash, addrlBase, nlwidth, sizeDst, depthDst,
641 signdx, signdy, axis, new_x1, new_y1, err, e1, e2,
642 len, rrops, bgrrops); /* @@@ NEXT PLANE PASSED @@@ */
644 pbox++;
646 } /* while (nbox--) */
647 #ifndef POLYSEGMENT
649 * walk the dash list around to the next line
651 miStepDash (unclippedlen, &dashIndex, pDash,
652 numInDashList, &dashOffset);
653 dontStep: ;
654 #endif
655 } /* while (nline--) */
657 #ifndef POLYSEGMENT
658 /* paint the last point if the end style isn't CapNotLast.
659 (Assume that a projecting, butt, or round cap that is one
660 pixel wide is the same as the single pixel of the endpoint.)
663 if ((pGC->capStyle != CapNotLast) &&
664 ((dashIndex & 1) == 0 || isDoubleDash) &&
665 ((ppt->x + xorg != pptInit->x + pDrawable->x) ||
666 (ppt->y + yorg != pptInit->y + pDrawable->y) ||
667 (ppt == pptInit + 1))) {
668 nbox = nboxInit;
669 pbox = pboxInit;
670 while (nbox--) {
671 if ((x2 >= pbox->x1) && (y2 >= pbox->y1) && (x2 < pbox->x2) &&
672 (y2 < pbox->y2)) {
673 int rop;
675 for (d = 0; d < depthDst; d++) {
676 addrl = afbScanline(addrlBase, x2, y2, nlwidth);
677 addrlBase += sizeDst; /* @@@ NEXT PLANE @@@ */
679 rop = rrops[d];
680 if (dashIndex & 1)
681 rop = bgrrops[d];
683 switch (rop) {
684 case RROP_BLACK:
685 *addrl &= mfbGetrmask(x2 & PIM);
686 break;
687 case RROP_WHITE:
688 *addrl |= mfbGetmask(x2 & PIM);
689 break;
691 case RROP_INVERT:
692 *addrl ^= mfbGetmask(x2 & PIM);
693 break;
695 case RROP_NOP:
696 break;
698 } /* for (d = ...) */
699 break;
700 } else
701 pbox++;
704 #endif