1 /* grClip.c -
2  *
3  *     *********************************************************************
4  *     * Copyright (C) 1985, 1990 Regents of the University of California. *
5  *     * Permission to use, copy, modify, and distribute this              *
6  *     * software and its documentation for any purpose and without        *
7  *     * fee is hereby granted, provided that the above copyright          *
8  *     * notice appear in all copies.  The University of California        *
9  *     * makes no representations about the suitability of this            *
10  *     * software for any purpose.  It is provided "as is" without         *
11  *     * express or implied warranty.  Export of this software outside     *
12  *     * of the United States of America may require an export license.    *
13  *     *********************************************************************
14  *
15  * This file contains additional functions to manipulate a
16  * color display.  Included here are rectangle clipping and
17  * drawing routines.
18  */
19 
20 
21 #ifndef lint
22 static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/graphics/grClip.c,v 1.4 2010/06/24 12:37:18 tim Exp $";
23 #endif  /* not lint */
24 
25 #include <stdio.h>
26 
27 #include "utils/magic.h"
28 #include "textio/textio.h"
29 #include "utils/geometry.h"
30 #include "tiles/tile.h"
31 #include "utils/hash.h"
32 #include "utils/styles.h"
33 #include "database/database.h"
34 #include "windows/windows.h"
35 #include "graphics/graphics.h"
36 #include "graphics/graphicsInt.h"
37 #include "utils/malloc.h"
38 
39 /* Forward declaration: */
40 
41 extern bool GrDisjoint();
42 extern void GrClipTriangle();
43 
44 /* The following rectangle defines the size of the cross drawn for
45  * zero-size rectangles.  This must be all on one line to keep
46  * lintpick happy!
47  */
48 
49 global Rect GrCrossRect = {-GR_CROSSSIZE, -GR_CROSSSIZE, GR_CROSSSIZE, GR_CROSSSIZE};
50 global int GrNumClipBoxes = 0;	/* for benchmarking */
51 global int grCurDStyle;
52 global unsigned char GrGridMultiple = 1;
53 
54 /* A rectangle that is one square of the grid */
55 static Rect *grGridRect;
56 
57 /*
58  * ----------------------------------------------------------------------------
59  * GrSetStuff --
60  *
61  *	Set up current drawing style.
62  *
63  * Results:
64  *	None.
65  *
66  * Side effects:
67  *	Variables are changed.  If anything is drawn, it will appear in the
68  *	specified style.
69  * ----------------------------------------------------------------------------
70  */
71 
72 /* Current state for rectangle and text drawing */
73 static int grCurWMask, grCurStipple;
74 #ifndef MAGIC_WRAPPER
75 static 				/* Used in grTkCommon.c, so don't make static */
76 #endif
77 int grCurOutline, grCurFill, grCurColor;
78 
79 /* Has the device driver been informed of the above?  We only inform it
80  * when we actually need to draw something -- this makes it harmless (in terms
81  * of graphics bandwidth) to call GrSetStuff extra times.
82  */
83 bool grDriverInformed = TRUE;
84 
85 void
GrSetStuff(style)86 GrSetStuff(style)
87     int style;
88 {
89     grCurDStyle = style;
90     grCurWMask = GrStyleTable[style].mask;
91     grCurColor = GrStyleTable[style].color;
92     grCurOutline = GrStyleTable[style].outline;
93     grCurStipple = GrStyleTable[style].stipple;
94     grCurFill = GrStyleTable[style].fill;
95     grDriverInformed = FALSE;
96 }
97 
98 /*---------------------------------------------------------------------------
99  * grInformDriver:
100  *
101  *	Inform the driver about the last GrSetStuff call.
102  *
103  * Results:
104  *	None.
105  *
106  * Side Effects:
107  *	None.
108  *
109  *----------------------------------------------------------------------------
110  */
111 
112 void
grInformDriver()113 grInformDriver()
114 {
115     /* Now let the device drivers know */
116     (*grSetWMandCPtr)(grCurWMask, grCurColor);
117     (*grSetLineStylePtr)(grCurOutline);
118     (*grSetStipplePtr)(grCurStipple);
119     grDriverInformed = TRUE;
120 }
121 
122 
123 /*
124  * ----------------------------------------------------------------------------
125  * grClipAgainst --
126  *
127  *	Clip a linked list of rectangles against a single rectangle.  This
128  *	may result in the list getting longer or shorter.
129  *
130  * Results:
131  *	None.
132  *
133  * Side effects:
134  *	The original list may change.
135  * ----------------------------------------------------------------------------
136  */
137 
138 void
grClipAgainst(startllr,clip)139 grClipAgainst(startllr, clip)
140     LinkedRect **startllr;	/* A pointer to the pointer that heads
141 				 * the list .
142 				 */
143     Rect *clip;		  	/* The rectangle to clip against */
144 {
145     extern bool grClipAddFunc();	/* forward declaration */
146     LinkedRect **llr, *lr;
147 
148     for (llr = startllr; *llr != (LinkedRect *) NULL; /*nop*/ )
149     {
150 	if ( GEO_TOUCH(&(*llr)->r_r, clip) )
151 	{
152 	    lr = *llr;
153 	    *llr = lr->r_next;
154 	    /* this will modify the list that we are traversing! */
155 	    (void) GrDisjoint(&lr->r_r, clip, grClipAddFunc,
156 		    (ClientData) &llr);
157 	    freeMagic( (char *) lr);
158 	}
159 	else
160 	    llr = &((*llr)->r_next);
161     }
162 }
163 
164 
165 /* Add a box to our linked list, and advance
166  * our pointer into the list
167  */
168 
grClipAddFunc(box,cd)169 bool grClipAddFunc(box, cd)
170     Rect *box;
171     ClientData cd;
172 {
173     LinkedRect ***lllr, *lr;
174 
175     lllr = (LinkedRect ***) cd;
176 
177     lr = (LinkedRect *) mallocMagic((unsigned) (sizeof (LinkedRect)));
178     lr->r_r = *box;
179     lr->r_next = **lllr;
180     **lllr = lr;
181     *lllr = &lr->r_next;
182 
183     return TRUE;
184 }
185 
186 
187 void
grObsBox(r)188 grObsBox(r)
189     Rect *r;
190 {
191     LinkedRect *ob;
192     LinkedRect *ar;
193     LinkedRect **areas;
194 
195     ar = (LinkedRect *) mallocMagic((unsigned) (sizeof (LinkedRect)));
196     ar->r_r = *r;
197     ar->r_next = NULL;
198     areas = &ar;
199 
200     /* clip against obscuring areas */
201     for (ob = grCurObscure; ob != NULL; ob = ob->r_next)
202     {
203 	if ( GEO_TOUCH(r, &(ob->r_r)) )
204 	    grClipAgainst(areas, &(ob->r_r));
205     }
206 
207     while (*areas != NULL)
208     {
209 	LinkedRect *oldarea;
210 	if (grCurFill == GR_STGRID)
211 	    (*grDrawGridPtr)(grGridRect, grCurOutline, &((*areas)->r_r));
212 	else
213 	    (*grFillRectPtr)(&((*areas)->r_r));
214 	oldarea = *areas;
215 	*areas = (*areas)->r_next;
216 	freeMagic( (char *) oldarea );
217     }
218 }
219 
220 
221 /*---------------------------------------------------------
222  * grClipPoints:
223  *	This routine computes the 0, 1, or 2 intersection points
224  *	between a line and a box.
225  *
226  * Results:
227  *	FALSE if the line is completely outside of the box.
228  *
229  * Side Effects:
230  *---------------------------------------------------------
231  */
232 
233 bool
grClipPoints(line,box,p1,p1OK,p2,p2OK)234 grClipPoints(line, box, p1, p1OK, p2, p2OK)
235     Rect *line;		/* Actually a line from line->r_ll to
236 			 * line->r_ur.  It is assumed that r_ll is to
237 			 * the left of r_ur, but we don't assume that
238 			 * r_ll is below r_ur.
239 			 */
240     Rect *box;		/* A box to check intersections with */
241     Point *p1, *p2;	/* To be filled in with 0, 1, or 2 points
242 			 * that are on the border of the box as well as
243 			 * on the line.
244 			 */
245     bool *p1OK, *p2OK;	/* Says if the point was filled in */
246 {
247     int tmp, delx, dely;
248     bool delyneg;
249     int x1, x2, y1, y2;
250     bool ok1, ok2;
251 
252     if (p1OK != NULL) *p1OK = FALSE;
253     ok1 = FALSE;
254     if (p2OK != NULL) *p2OK = FALSE;
255     ok2 = FALSE;
256 
257     x1 = line->r_xbot;
258     x2 = line->r_xtop;
259     y1 = line->r_ybot;
260     y2 = line->r_ytop;
261 
262     delx = x2-x1;
263     dely = y2-y1;
264 
265     /* We have to be careful because of machine-dependent problems
266      * with rounding during division by negative numbers.
267      */
268 
269     if (dely<0)
270     {
271 	dely = -dely;
272 	delyneg = TRUE;
273     }
274     else
275 	delyneg = FALSE;
276     /* we know that delx is nonnegative if this is a real (non-empty) line */
277     if (delx < 0) return FALSE;
278 
279     if (x1 < box->r_xbot)
280     {
281 	if (delx == 0) return FALSE;
282 	tmp = (((box->r_xbot-x1)*dely) + (delx>>1))/delx;
283 	if (delyneg) y1 -= tmp;
284 	else y1 += tmp;
285 	x1 = box->r_xbot;
286     }
287     else
288 	if (x1 > box->r_xtop) return FALSE;
289 
290     if (x2 > box->r_xtop)
291     {
292 	if (delx == 0) return FALSE;
293 	tmp = ((x2-box->r_xtop)*dely + (delx>>1))/delx;
294 	if (delyneg) y2 += tmp;
295 	else y2 -= tmp;
296 	x2 = box->r_xtop;
297     }
298     else
299 	if (x2 < box->r_xbot) return FALSE;
300 
301     if (y2 > y1)
302     {
303 	if (y1 < box->r_ybot)
304 	{
305 	    x1 += (((box->r_ybot-y1)*delx) + (dely>>1))/dely;
306 	    y1 = box->r_ybot;
307 	}
308 	else if (y1 > box->r_ytop) return FALSE;
309 	if (y2 > box->r_ytop)
310 	{
311 	    x2 -= (((y2 - box->r_ytop)*delx) + (dely>>1))/dely;
312 	    y2 = box->r_ytop;
313 	}
314 	else if (y2 < box->r_ybot) return FALSE;
315     }
316     else
317     {
318 	if (y1 > box->r_ytop)
319 	{
320 	    if (dely == 0) return FALSE;
321 	    x1 += (((y1-box->r_ytop)*delx) + (dely>>1))/dely;
322 	    y1 = box->r_ytop;
323 	}
324 	else if (y1 < box->r_ybot) return FALSE;
325 	if (y2 < box->r_ybot)
326 	{
327 	    if (dely == 0) return FALSE;
328 	    x2 -= (((box->r_ybot-y2)*delx) + (dely>>1))/dely;
329 	    y2 = box->r_ybot;
330 	}
331 	else if (y2 > box->r_ytop) return FALSE;
332     }
333 
334     if ( (x1 == box->r_xbot) || (y1 == box->r_ybot) || (y1 == box->r_ytop) )
335     {
336 	if (p1 != NULL)
337 	{
338 	    p1->p_x = x1;
339 	    p1->p_y = y1;
340 	}
341 	if (p1OK != NULL) *p1OK = TRUE;
342 	ok1 = TRUE;
343     }
344     if ( (x2 == box->r_xtop) || (y2 == box->r_ybot) || (y2 == box->r_ytop) )
345     {
346 	if (p2 != NULL)
347 	{
348 	    p2->p_x = x2;
349 	    p2->p_y = y2;
350 	}
351 	if (p2OK != NULL) *p2OK = TRUE;
352 	ok2 = TRUE;
353     }
354     /* is part of the line in the box? */
355     return ok1 || ok2 ||
356 	    ((x1 >= box->r_xbot) && (x1 <= box->r_xtop) && (y1 >= box->r_ybot)
357 	    && (y1 <= box->r_ytop));
358 }
359 
360 
361 #define NEWAREA(lr,x1,y1,x2,y2)	{LinkedRect *tmp; \
362     tmp = (LinkedRect *) mallocMagic((unsigned) (sizeof (LinkedRect))); \
363     tmp->r_r.r_xbot = x1; tmp->r_r.r_xtop = x2; \
364     tmp->r_r.r_ybot = y1; tmp->r_r.r_ytop = y2; tmp->r_next = lr; lr = tmp;}
365 
366 /*---------------------------------------------------------
367  * GrClipLine:
368  *	GrClipLine will draw a line on the screen in the current
369  *	style and clip stuff.
370  *
371  * Results:	None.
372  *
373  * Side Effects:
374  *	The line is drawn in the current style.
375  *---------------------------------------------------------
376  */
377 
378 void
GrClipLine(x1,y1,x2,y2)379 GrClipLine(x1, y1, x2, y2)
380     int x1, y1, x2, y2;
381 {
382     LinkedRect **ar;
383     LinkedRect *ob;
384     LinkedRect *areas;
385 
386     GR_CHECK_LOCK();
387     if (!grDriverInformed) grInformDriver();
388 
389     /* we will pretend the the ll corner of a rectangle is the
390      * left endpoint of a line, and the ur corner the right endpoint
391      * of the line.
392      */
393     areas = (LinkedRect *) mallocMagic((unsigned) (sizeof (LinkedRect)));
394     areas->r_next = NULL;
395     if (x1 < x2)
396     {
397 	areas->r_r.r_xbot = x1;
398 	areas->r_r.r_ybot = y1;
399 	areas->r_r.r_xtop = x2;
400 	areas->r_r.r_ytop = y2;
401     }
402     else
403     {
404 	areas->r_r.r_xtop = x1;
405 	areas->r_r.r_ytop = y1;
406 	areas->r_r.r_xbot = x2;
407 	areas->r_r.r_ybot = y2;
408     }
409 
410     /* clip against the clip box */
411     for (ar = &areas; *ar != NULL; )
412     {
413 	Rect *l;
414 	Rect canonRect;
415 	l = &((*ar)->r_r);
416 	GeoCanonicalRect(l, &canonRect);
417 	if (!GEO_TOUCH(&canonRect, &grCurClip))
418 	{
419 	    /* line is totally outside of clip area */
420 	    goto deleteit;
421 	}
422 	else
423 	{
424 	    /* is there some intersection with clip area? */
425 	    if (!grClipPoints(l, &grCurClip, &(l->r_ll), (bool *) NULL,
426 		    &(l->r_ur), (bool*) NULL))
427 	    {
428 		/* no intersection */
429 		goto deleteit;
430 	    }
431 
432 	    /* clip against obscuring areas */
433 	    for (ob = grCurObscure; ob != NULL; ob = ob->r_next)
434 	    {
435 		Point p1, p2;
436 		Rect c;
437 		bool ok1, ok2;
438 		c = ob->r_r;
439 		c.r_xbot--;  c.r_ybot--;
440 		c.r_xtop++;  c.r_ytop++;
441 		if (grClipPoints(l, &c, &p1, &ok1, &p2, &ok2) &&
442 			!ok1 && !ok2)
443 		{
444 		    /* Line is not completely outside of the box,
445 		     * nor does it intersect it.
446 		     * Therefore, line is completely obscured.
447 		     */
448 		     goto deleteit;
449 		}
450 
451 		if (ok1 &&
452 		   ( ((l->r_xbot == p1.p_x) && (l->r_ybot == p1.p_y)) ||
453 		     ((l->r_xtop == p1.p_x) && (l->r_ytop == p1.p_y)) ) )
454 		{
455 		    ok1 = FALSE;  /* do not split or clip at an endpoint */
456 		}
457 		if (ok2 &&
458 		   ( ((l->r_xbot == p2.p_x) && (l->r_ybot == p2.p_y)) ||
459 		     ((l->r_xtop == p2.p_x) && (l->r_ytop == p2.p_y)) ) )
460 		{
461 		    ok2 = FALSE;  /* do not split or clip at an endpoint */
462 		}
463 
464 		if (ok1 ^ ok2)
465 		{
466 		    /* one segment to deal with */
467 		    if (ok1)
468 			l->r_ur = p1;
469 		    else
470 			l->r_ll = p2;
471 		}
472 		else if (ok1 && ok2)
473 		{
474 		    /* clip both sides */
475 		    LinkedRect *new;
476 		    new = (LinkedRect *) mallocMagic((unsigned) (sizeof (LinkedRect)));
477 		    new->r_r.r_ur = l->r_ur;
478 		    new->r_r.r_ll = p2;
479 		    new->r_next = (*ar);
480 		    l->r_ur = p1;
481 		    (*ar) = new;
482 		}
483 	    }
484 
485 	}
486 
487 	ar = &((*ar)->r_next);
488 	continue;
489 
490 deleteit: {
491 	    LinkedRect *reclaim;
492 	    reclaim = (*ar);
493 	    *ar = reclaim->r_next;
494 	    freeMagic( (char *) reclaim);
495 	}
496 
497     } /* for ar */
498 
499 
500     /* draw the lines */
501     while (areas != NULL)
502     {
503 	LinkedRect *oldarea;
504 	(*grDrawLinePtr)(areas->r_r.r_xbot, areas->r_r.r_ybot,
505 		areas->r_r.r_xtop, areas->r_r.r_ytop);
506 	oldarea = areas;
507 	areas = areas->r_next;
508 	freeMagic( (char *) oldarea );
509     }
510 }
511 
512 /*
513  *---------------------------------------------------------
514  * grAddSegment:
515  *	Add a segment to a linked list of rectangles
516  *
517  * Results:
518  *	None.
519  *
520  * Side effects:
521  *	Allocates memory;  appends LinkedRect structure to
522  *	list "segments".
523  *
524  * Notes:
525  *	INLINE this for speedup?
526  *---------------------------------------------------------
527  */
528 
529 void
grAddSegment(llx,lly,urx,ury,segments)530 grAddSegment(llx, lly, urx, ury, segments)
531     int llx, lly, urx, ury;
532     LinkedRect **segments;
533 {
534     LinkedRect *curseg;
535 
536     curseg = (LinkedRect *)mallocMagic(sizeof(LinkedRect));
537     curseg->r_r.r_xbot = llx;
538     curseg->r_r.r_ybot = lly;
539     curseg->r_r.r_xtop = urx;
540     curseg->r_r.r_ytop = ury;
541     curseg->r_next = *segments;
542     *segments = curseg;
543 }
544 
545 /*---------------------------------------------------------
546  * GrBoxOutline:
547  *	For box outlines, works around the boundary of
548  *	the box according to the associated tile structure,
549  *	and returns a linked rect list defining all the
550  *	segments which need to be drawn.
551  *
552  * Results:
553  *	TRUE if tile is isolated (GrFastBox can be used).
554  *	Otherwise, result is FALSE.
555  *
556  * Side Effects:
557  *	May allocate memory for a linked rect structure,
558  *	with pointer returned in tilesegs.  If non-NULL,
559  *	the calling function needs to free memory for the
560  *	linked rect structure.
561  *
562  * Implementation notes:
563  *	Standard tech files define most bordered styles as
564  *	contact types, and most if not all contacts are
565  *	required to be square.  So we want the case of an
566  *	isolated tile to go fast, avoiding any calls to
567  *	allocate memory.  This complicates the routine but
568  *	keeps the routine from slowing down the layout
569  *	rendering.
570  *---------------------------------------------------------
571  */
572 
573 bool
GrBoxOutline(tile,tilesegs)574 GrBoxOutline(tile, tilesegs)
575     Tile *tile;
576     LinkedRect **tilesegs;
577 {
578     Rect rect;
579     TileType ttype;
580     LinkedRect *curseg;
581     Tile *tpleft, *tpright, *tptop, *tpbot;
582     int edgeTop, edgeBot, edgeRight, edgeLeft;
583     int isolate = 0;
584     bool sense;
585 
586     *tilesegs = NULL;
587     TiToRect(tile, &rect);
588 
589     if (IsSplit(tile) && SplitSide(tile))
590 	isolate |= 0x1;
591     else
592     {
593 	ttype = TiGetLeftType(tile);
594 	edgeBot = rect.r_ybot;
595 	sense = TRUE;
596 	for (tpleft = BL(tile); BOTTOM(tpleft) < rect.r_ytop; tpleft = RT(tpleft))
597 	{
598 	    if (TiGetRightType(tpleft) != ttype)
599 	    {
600 		if (!sense)
601 		{
602 		    edgeBot = BOTTOM(tpleft);
603 		    if (TOP(tpleft) >= rect.r_ytop)
604 			grAddSegment(rect.r_xbot, edgeBot, rect.r_xbot, rect.r_ytop,
605 					tilesegs);
606 		    sense = TRUE;
607 		}
608 	    }
609 	    else
610 	    {
611 		if (sense)
612 		{
613 		    edgeTop = BOTTOM(tpleft);
614 		    if (edgeTop > edgeBot)
615 			grAddSegment(rect.r_xbot, edgeBot, rect.r_xbot, edgeTop,
616 				tilesegs);
617 		    isolate |= 0x1;
618 		    sense = FALSE;
619 		}
620 	    }
621 	}
622     }
623     if (IsSplit(tile) && !SplitSide(tile))
624 	isolate |= 0x2;
625     else
626     {
627 	ttype = TiGetRightType(tile);
628 	edgeTop = rect.r_ytop;
629 	sense = TRUE;
630 	for (tpright = TR(tile); TOP(tpright) > rect.r_ybot; tpright = LB(tpright))
631 	{
632 	    if (TiGetLeftType(tpright) != ttype)
633 	    {
634 		if (!sense)
635 		{
636 		    edgeTop = TOP(tpright);
637 		    if (BOTTOM(tpright) <= rect.r_ybot)
638 			grAddSegment(rect.r_xtop, rect.r_ybot, rect.r_xtop, edgeTop,
639 					tilesegs);
640 		    sense = TRUE;
641 		}
642 	    }
643 	    else
644 	    {
645 		if (sense)
646 		{
647 		    edgeBot = TOP(tpright);
648 		    if (edgeBot < edgeTop)
649 			grAddSegment(rect.r_xtop, edgeBot, rect.r_xtop, edgeTop,
650 					tilesegs);
651 		    isolate |= 0x2;
652 		    sense = FALSE;
653 		}
654 	    }
655 	}
656     }
657 
658     if (IsSplit(tile) &&
659 		(SplitSide(tile) == SplitDirection(tile)))
660 	isolate |= 0x4;
661     else
662     {
663 	ttype = TiGetBottomType(tile);
664 	edgeLeft = rect.r_xbot;
665 	sense = TRUE;
666 	for (tpbot = LB(tile); LEFT(tpbot) < rect.r_xtop; tpbot = TR(tpbot))
667 	{
668 	    if (TiGetTopType(tpbot) != ttype)
669 	    {
670 		if (!sense)
671 		{
672 		    edgeLeft = LEFT(tpbot);
673 		    if (RIGHT(tpbot) >= rect.r_xtop)
674 			grAddSegment(edgeLeft, rect.r_ybot, rect.r_xtop, rect.r_ybot,
675 					tilesegs);
676 		    sense = TRUE;
677 		}
678 	    }
679 	    else
680 	    {
681 		if (sense)
682 		{
683 		    edgeRight = LEFT(tpbot);
684 		    if (edgeRight > edgeLeft)
685 			grAddSegment(edgeLeft, rect.r_ybot, edgeRight, rect.r_ybot,
686 					tilesegs);
687 		    isolate |= 0x4;
688 		    sense = FALSE;
689 		}
690 	    }
691 	}
692     }
693 
694     if (IsSplit(tile) &&
695 		(SplitSide(tile) != SplitDirection(tile)))
696 	isolate |= 0x8;
697     else
698     {
699 	ttype = TiGetTopType(tile);
700 	edgeRight = rect.r_xtop;
701 	sense = TRUE;
702 	for (tptop = RT(tile); RIGHT(tptop) > rect.r_xbot; tptop = BL(tptop))
703 	{
704 	    if (TiGetBottomType(tptop) != ttype)
705 	    {
706 		if (!sense)
707 		{
708 		    edgeRight = RIGHT(tptop);
709 		    if (LEFT(tptop) <= rect.r_xbot)
710 			grAddSegment(rect.r_xbot, rect.r_ytop, edgeRight, rect.r_ytop,
711 					tilesegs);
712 		    sense = TRUE;
713 		}
714 	    }
715 	    else
716 	    {
717 		if (sense)
718 		{
719 		    edgeLeft = RIGHT(tptop);
720 		    if (edgeLeft < edgeRight)
721 			grAddSegment(edgeLeft, rect.r_ytop, edgeRight, rect.r_ytop,
722 					tilesegs);
723 		    isolate |= 0x8;
724 		    sense = FALSE;
725 		}
726 	    }
727 	}
728     }
729 
730     if (isolate == 0)	/* Common case */
731 	return TRUE;
732     else
733     {
734 	/* Need to malloc segments for isolated sides */
735 	if (!(isolate & 0x1))	/* Left */
736 	    grAddSegment(rect.r_xbot, rect.r_ybot, rect.r_xbot, rect.r_ytop,
737 			tilesegs);
738 	if (!(isolate & 0x2))	/* Right */
739 	    grAddSegment(rect.r_xtop, rect.r_ybot, rect.r_xtop, rect.r_ytop,
740 			tilesegs);
741 	if (!(isolate & 0x4))	/* Bottom */
742 	    grAddSegment(rect.r_xbot, rect.r_ybot, rect.r_xtop, rect.r_ybot,
743 			tilesegs);
744 	if (!(isolate & 0x8))	/* Top */
745 	    grAddSegment(rect.r_xbot, rect.r_ytop, rect.r_xtop, rect.r_ytop,
746 			tilesegs);
747 	return FALSE;
748     }
749 }
750 
751 /* Threshold for determining if outlines are too small to draw */
752 #define GR_THRESH	4
753 
754 /*---------------------------------------------------------
755  * GrBox --
756  *
757  *	GrBox draws a rectangle on the screen in the style
758  *	set by the previous call to GrSetStuff.   It will
759  *	be clipped against the rectangles passed to GrSetStuff.
760  *
761  *	Unlike GrFastBox (see below), GrBox makes no assumptions
762  *	about how the outline will be drawn.  If there is no
763  *	outline, GrFastBox is called.  The tile border is checked,
764  *	and if the tile outline is simple, GrFastBox is called.
765  *	Otherwise, we do a fast fill a la GrFastBox but draw the
766  *	outline segment by segment.
767  *
768  * Results:	None.
769  *
770  * Side Effects:
771  *	The rectangle is drawn in the style specified.
772  *	The rectangle may be clipped before being drawn.
773  *---------------------------------------------------------
774  */
775 void
GrBox(MagWindow * mw,Transform * trans,Tile * tile)776 GrBox(MagWindow *mw, Transform *trans, Tile *tile)
777 {
778     Rect r, r2, clipr;
779     bool needClip, needObscure, simpleBox;
780     LinkedRect *ob, *tilesegs, *segptr;
781     Point polyp[5];
782     int np;
783 
784     r.r_xbot = LEFT(tile);
785     r.r_ybot = BOTTOM(tile);
786     r.r_xtop = RIGHT(tile);
787     r.r_ytop = TOP(tile);
788 
789     GeoTransRect(trans, &r, &r2);
790     if (IsSplit(tile))
791 	WindSurfaceToScreenNoClip(mw, &r2, &r);
792     else
793 	WindSurfaceToScreen(mw, &r2, &r);
794 
795     GR_CHECK_LOCK();
796     if (!grDriverInformed) grInformDriver();
797     GrNumClipBoxes++;
798 
799     if (!GEO_TOUCH(&r, &grCurClip)) return;
800 
801     /* Do a quick check to make the (very common) special case of
802      * no clipping go fast.
803      */
804     needClip = !GEO_SURROUND(&grCurClip, &r);
805     needObscure = FALSE;
806     for (ob = grCurObscure; ob != NULL; ob = ob->r_next)
807 	needObscure |= GEO_TOUCH(&r, &(ob->r_r));
808 
809     /* Nonmanhattan tiles: */
810     /* Expects one of the two tile types to be masked out before */
811     /* this procedure is called.                                 */
812 
813     if (IsSplit(tile))
814     {
815 	/* Perform matrix transformations on split tiles */
816 	TileType dinfo;
817 	Rect fullr;
818 
819 	dinfo = DBTransformDiagonal(TiGetTypeExact(tile), trans);
820 	clipr = fullr = r;
821 
822 	if (needClip)
823 	    GeoClip(&clipr, &grCurClip);
824 
825 	GrClipTriangle(&fullr, &clipr, needClip, dinfo, polyp, &np);
826 
827 	if ((grCurFill == GR_STSOLID) ||
828 	(grCurFill == GR_STSTIPPLE) || (grCurFill == GR_STGRID) )
829 	{
830 	    if (needObscure)
831 		grObsBox(&clipr);
832 	    else if (grFillPolygonPtr)
833 		(void) (*grFillPolygonPtr)(polyp, np);
834 	}
835     }
836     else
837     {
838 
839 	/* do solid areas (same as GrFastBox) */
840 
841 	if ((grCurFill == GR_STSOLID) || (grCurFill == GR_STSTIPPLE))
842 	{
843 	    /* We have a filled area to deal with */
844 	    clipr = r;
845 	    if (needClip)
846 		GeoClip(&clipr, &grCurClip);
847 	    if (needObscure)
848 		grObsBox(&clipr);
849 	    else
850 		(void) (*grFillRectPtr)(&clipr);
851 	}
852     }
853 
854     /* return if outline is too small to be worth drawing */
855 
856     if ((r.r_xtop - r.r_xbot < GR_THRESH)
857 		&& (r.r_ytop - r.r_ybot < GR_THRESH)
858 		&& (grCurFill != GR_STOUTLINE))
859 	return;
860 
861     /* do diagonal lines for contacts */
862 
863     if (grCurFill == GR_STCROSS)
864     {
865 	Rect rnc;
866 	/* don't clip contact diagonals */
867 	if (needClip || needObscure)
868 	{
869 	    WindSurfaceToScreenNoClip(mw, &r2, &rnc);
870 /*
871 	    (*grDrawLinePtr)(rnc.r_xbot, rnc.r_ybot, rnc.r_xtop, rnc.r_ytop);
872 	    (*grDrawLinePtr)(rnc.r_xbot, rnc.r_ytop, rnc.r_xtop, rnc.r_ybot);
873 */
874 	    if (!IsSplit(tile))
875 	    {
876 		GrClipLine(rnc.r_xbot, rnc.r_ybot, rnc.r_xtop, rnc.r_ytop);
877 		GrClipLine(rnc.r_xbot, rnc.r_ytop, rnc.r_xtop, rnc.r_ybot);
878 	    }
879 	}
880 	else
881 	{
882 	    if (!IsSplit(tile))
883 	    {
884 		(*grDrawLinePtr)(r.r_xbot, r.r_ybot, r.r_xtop, r.r_ytop);
885 		(*grDrawLinePtr)(r.r_xbot, r.r_ytop, r.r_xtop, r.r_ybot);
886 	    }
887 	}
888     }
889 
890     /* draw outlines */
891 
892     if (grCurOutline != 0)
893     {
894 	if (GrBoxOutline(tile, &tilesegs))
895 	{
896 	    /* simple box (from GrFastBox)*/
897 
898 	    if (needClip || needObscure)
899 	    {
900 		GrClipLine(r.r_xbot, r.r_ytop, r.r_xtop, r.r_ytop);
901 		GrClipLine(r.r_xbot, r.r_ybot, r.r_xtop, r.r_ybot);
902 		GrClipLine(r.r_xbot, r.r_ybot, r.r_xbot, r.r_ytop);
903 		GrClipLine(r.r_xtop, r.r_ybot, r.r_xtop, r.r_ytop);
904 	    }
905 	    else
906 	    {
907 		(*grDrawLinePtr)(r.r_xbot, r.r_ytop, r.r_xtop, r.r_ytop);
908 		(*grDrawLinePtr)(r.r_xbot, r.r_ybot, r.r_xtop, r.r_ybot);
909 		(*grDrawLinePtr)(r.r_xbot, r.r_ybot, r.r_xbot, r.r_ytop);
910 		(*grDrawLinePtr)(r.r_xtop, r.r_ybot, r.r_xtop, r.r_ytop);
911 	    }
912 	}
913 	else
914 	{
915 	    /* non-rectangular box; requires drawing segments */
916 	    for (segptr = tilesegs; segptr != NULL; segptr = segptr->r_next)
917 	    {
918 		GeoTransRect(trans, &segptr->r_r, &r2);
919 		WindSurfaceToScreen(mw, &r2, &r);
920 
921 		if (needClip || needObscure)
922 		    GrClipLine(r.r_xbot, r.r_ybot, r.r_xtop, r.r_ytop);
923 		else
924 		    (*grDrawLinePtr)(r.r_xbot, r.r_ybot, r.r_xtop, r.r_ytop);
925 
926 		/* Free memory, if it was allocated for outline segments */
927 		freeMagic(segptr);
928 	    }
929 
930 	    /* For non-manhattan tiles, the manhattan parts of the	*/
931 	    /* boundary have already been drawn.  The diagonal boundary */
932 	    /* is guaranteed to be continuous by definition, and it has	*/
933 	    /* already undergone clipping with GrClipTriangle.  So just	*/
934 	    /* draw it, now.						*/
935 
936 	    if (IsSplit(tile))
937 	    {
938 		int cp;
939 		for (cp = 0; cp < np - 1; cp++)
940 		{
941 		    if ((polyp[cp].p_x != polyp[cp + 1].p_x) &&
942 				(polyp[cp].p_y != polyp[cp + 1].p_y))
943 		    {
944 			(*grDrawLinePtr)(polyp[cp].p_x, polyp[cp].p_y,
945 				polyp[cp + 1].p_x, polyp[cp + 1].p_y);
946 			break;	/* only 1 diagonal line to draw */
947 		    }
948 		}
949 		if (cp == (np - 1))
950 		{
951 		    if ((polyp[cp].p_x != polyp[0].p_x) &&
952 				(polyp[cp].p_y != polyp[0].p_y))
953 			(*grDrawLinePtr)(polyp[cp].p_x, polyp[cp].p_y,
954 				polyp[0].p_x, polyp[0].p_y);
955 		}
956 	    }
957 	}
958     }
959 }
960 
961 /*---------------------------------------------------------
962  * GrDrawFastBox:
963  *	GrDrawFastBox will draw a rectangle on the screen in the
964  *	style set by the previous call to GrSetStuff.  It will also
965  *	be clipped against the rectangles passed to GrSetStuff.
966  *
967  *	If GrClipBox is called between GrDrawFastBox calls then GrSetStuff
968  *	must be called to set the parameters back.
969  *
970  *	Usually this is called as GrFastBox, defined as GrDrawFastBox(p, 0).
971  *	The "scale" is only used to reduce the size of crosses drawn at
972  *	point positions, to prevent point labels from dominating a layout
973  *	in top-level views.
974  *
975  * Results:	None.
976  *
977  * Side Effects:
978  *	The rectangle is drawn in the style specified.
979  *	The rectangle is clipped before being drawn.
980  *---------------------------------------------------------
981  */
982 
983 void
GrDrawFastBox(prect,scale)984 GrDrawFastBox(prect, scale)
985     Rect *prect;	/* The rectangle to be drawn, given in
986 			 * screen coordinates.
987 			 */
988     int scale;		/* If < 0, we reduce the cross size for
989 			 * points according to the (negative) scale,
990 			 * so point labels don't dominate a top-level
991 			 * layout.
992 			 */
993 {
994     Rect *r;
995     bool needClip, needObscure;
996     LinkedRect *ob;
997 
998     GR_CHECK_LOCK();
999     if (!grDriverInformed) grInformDriver();
1000     GrNumClipBoxes++;
1001     if (grCurFill == GR_STGRID)
1002     {
1003 	r = &grCurClip;
1004 	grGridRect = prect;
1005     }
1006     else
1007     {
1008 	r = prect;
1009 	if (!GEO_TOUCH(r, &grCurClip)) return;
1010     }
1011 
1012     /* Do a quick check to make the (very common) special case of
1013      * no clipping go fast.
1014      */
1015     needClip = !GEO_SURROUND(&grCurClip, r);
1016     needObscure = FALSE;
1017     for (ob = grCurObscure; ob != NULL; ob = ob->r_next)
1018 	needObscure |= GEO_TOUCH(r, &(ob->r_r));
1019 
1020     /* do solid areas */
1021     if ( (grCurFill == GR_STSOLID) ||
1022 	(grCurFill == GR_STSTIPPLE) || (grCurFill == GR_STGRID) )
1023     {
1024 	Rect clipr;
1025 	/* We have a filled area to deal with */
1026 	clipr = *r;
1027 	if (needClip)
1028 	    GeoClip(&clipr, &grCurClip);
1029 	if (needObscure)
1030 	    grObsBox(&clipr);
1031 	else
1032 	{
1033 	    if (grCurFill == GR_STGRID)
1034 		(*grDrawGridPtr)(grGridRect, grCurOutline, &clipr);
1035 	    else
1036 		(void) (*grFillRectPtr)(&clipr);
1037 	}
1038     }
1039 
1040     /* return if rectangle is too small to see */
1041     if ((r->r_xtop - r->r_xbot < GR_THRESH)
1042 		&& (r->r_ytop - r->r_ybot < GR_THRESH)
1043 		&& (grCurFill != GR_STOUTLINE))
1044 	return;
1045 
1046     /* draw outlines */
1047 
1048     if ( (grCurOutline != 0) && (grCurFill != GR_STGRID) )
1049     {
1050 	if ( (grCurFill == GR_STOUTLINE) && (r->r_xbot == r->r_xtop) &&
1051 		(r->r_ybot == r->r_ytop) )
1052 	{
1053 	    int crossSize = GR_CROSSSIZE;
1054 
1055 	    if (scale < 0)
1056 	    {
1057 		crossSize += scale;
1058 		if (crossSize < 0)
1059 		    goto endit;
1060 	    }
1061 
1062 	    /* turn the outline into a cross */
1063 	    if (needClip || needObscure)
1064 		goto clipit;
1065 	    else
1066 	    {
1067 		bool crossClip, crossObscure;
1068 		Rect crossBox;
1069 
1070 		/* check the larger cross area for clipping */
1071 		crossBox.r_xbot = r->r_xbot - crossSize;
1072 		crossBox.r_ybot = r->r_ybot - crossSize;
1073 		crossBox.r_xtop = r->r_xtop + crossSize;
1074 		crossBox.r_ytop = r->r_ytop + crossSize;
1075 
1076 		crossClip = !GEO_SURROUND(&grCurClip, &crossBox);
1077 		crossObscure = FALSE;
1078 		for (ob = grCurObscure; ob != NULL; ob = ob->r_next)
1079 		    crossObscure |= GEO_TOUCH(&crossBox, &(ob->r_r));
1080 
1081 		if (crossClip || crossObscure)
1082 		    goto clipit;
1083 		else
1084 		    goto noclipit;
1085 	    }
1086 
1087 	    clipit:
1088 		GrClipLine(r->r_xbot, r->r_ybot - crossSize,
1089 		    r->r_xtop, r->r_ytop + crossSize - 1 + GrPixelCorrect);
1090 		GrClipLine(r->r_xbot - crossSize, r->r_ybot,
1091 		    r->r_xtop + crossSize - 1 + GrPixelCorrect, r->r_ytop);
1092 		goto endit;
1093 
1094 	    noclipit:
1095 		(*grDrawLinePtr)(r->r_xbot, r->r_ybot - crossSize,
1096 		    r->r_xtop, r->r_ytop + crossSize - 1 + GrPixelCorrect);
1097 		(*grDrawLinePtr)(r->r_xbot - crossSize, r->r_ybot,
1098 		    r->r_xtop + crossSize - 1 + GrPixelCorrect, r->r_ytop);
1099 
1100 	    endit:  ;
1101 	}
1102 	else
1103 	{
1104 	    if (needClip || needObscure)
1105 	    {
1106 		GrClipLine(r->r_xbot, r->r_ytop, r->r_xtop, r->r_ytop);
1107 		GrClipLine(r->r_xbot, r->r_ybot, r->r_xtop, r->r_ybot);
1108 		GrClipLine(r->r_xbot, r->r_ybot, r->r_xbot, r->r_ytop);
1109 		GrClipLine(r->r_xtop, r->r_ybot, r->r_xtop, r->r_ytop);
1110 	    }
1111 	    else
1112 	    {
1113 		(*grDrawLinePtr)(r->r_xbot, r->r_ytop, r->r_xtop, r->r_ytop);
1114 		(*grDrawLinePtr)(r->r_xbot, r->r_ybot, r->r_xtop, r->r_ybot);
1115 		(*grDrawLinePtr)(r->r_xbot, r->r_ybot, r->r_xbot, r->r_ytop);
1116 		(*grDrawLinePtr)(r->r_xtop, r->r_ybot, r->r_xtop, r->r_ytop);
1117 	    }
1118 	}
1119     }
1120 
1121     /* do diagonal lines for contacts */
1122     if (grCurFill == GR_STCROSS)
1123     {
1124 	if (needClip || needObscure)
1125 	{
1126 	    GrClipLine(r->r_xbot, r->r_ybot, r->r_xtop, r->r_ytop);
1127 	    GrClipLine(r->r_xbot, r->r_ytop, r->r_xtop, r->r_ybot);
1128 	}
1129 	else
1130 	{
1131 	    (*grDrawLinePtr)(r->r_xbot, r->r_ybot, r->r_xtop, r->r_ytop);
1132 	    (*grDrawLinePtr)(r->r_xbot, r->r_ytop, r->r_xtop, r->r_ybot);
1133 	}
1134     }
1135 }
1136 
1137 /*---------------------------------------------------------
1138  * GrClipTriangle:
1139  *	Returns an array of points representing a clipped
1140  *	triangle.  These are always arranged in counter-
1141  *	clockwise order.
1142  *
1143  * Results:
1144  *	None.
1145  *
1146  * Side effects:
1147  *	Returns array of points and modifies int * np
1148  *	to hold the number of points in the array.
1149  *---------------------------------------------------------
1150  */
1151 
1152 #define xround(d) (int)(((((d % height) << 1) >= height) ? 1 : 0) + (d / height))
1153 #define yround(d) (int)(((((d % width) << 1) >= width) ? 1 : 0) + (d / width))
1154 
1155 void
GrClipTriangle(r,c,clipped,dinfo,points,np)1156 GrClipTriangle(r, c, clipped, dinfo, points, np)
1157     Rect *r;   /* Bounding box of triangle, in screen coords	*/
1158     Rect *c;		/* Clipping rectangle 				*/
1159     bool clipped;	/* Boolean, if bounding box is clipped		*/
1160     TileType dinfo;	/* Split side and direction information		*/
1161     Point *points;	/* Point array (up to 5 points) to fill		*/
1162     int *np;		/* Number of points in the clipped polygon	*/
1163 {
1164     if (!(dinfo & TT_SIDE))
1165     {
1166 	points[1].p_x = r->r_xbot;
1167 	points[0].p_y = r->r_ytop;
1168 	points[2].p_y = r->r_ybot;
1169 	points[0].p_x = points[2].p_x = r->r_xtop;
1170     }
1171     else
1172     {
1173 	points[1].p_x = r->r_xtop;
1174 	points[0].p_y = r->r_ybot;
1175 	points[2].p_y = r->r_ytop;
1176 	points[0].p_x = points[2].p_x = r->r_xbot;
1177     }
1178 
1179     if (!(dinfo & TT_DIRECTION))
1180     {
1181 	points[1].p_y = points[0].p_y;
1182 	points[2].p_x = points[1].p_x;
1183     }
1184     else
1185     {
1186 	points[0].p_x = points[1].p_x;
1187 	points[1].p_y = points[2].p_y;
1188     }
1189 
1190     *np = 3;
1191 
1192     /* Clip the triangle to the clipping rectangle.  Result is	*/
1193     /* a 3- to 5-sided polygon, or empty.			*/
1194 
1195     if (clipped)
1196     {
1197         dlong delx, dely;
1198         dlong width = (dlong)(r->r_xtop - r->r_xbot);
1199 	dlong height = (dlong)(r->r_ytop - r->r_ybot);
1200 
1201 	switch(dinfo & (TT_DIAGONAL | TT_DIRECTION | TT_SIDE))
1202 	{
1203 	    case TT_DIAGONAL:	/* nw */
1204 		if (c->r_ytop < r->r_ytop)	/* clip top */
1205 		{
1206 		    delx = (dlong)(points[1].p_y - c->r_ytop) * width;
1207 		    points[1].p_y = c->r_ytop;
1208 		    points[0].p_y = c->r_ytop;
1209 		    points[0].p_x -= xround(delx);
1210 		}
1211 		if (c->r_xbot > r->r_xbot)	/* clip left */
1212 		{
1213 		    dely = (dlong)(c->r_xbot - points[2].p_x) * height;
1214 		    points[1].p_x = c->r_xbot;
1215 		    points[2].p_x = c->r_xbot;
1216 		    points[2].p_y += yround(dely);
1217 		}
1218 		if (c->r_ybot > points[2].p_y)	/* clip bottom */
1219 		{
1220 		    delx = (dlong)(c->r_ybot - points[2].p_y) * width;
1221 		    points[2].p_y = c->r_ybot;
1222 		    points[3].p_y = c->r_ybot;
1223 		    points[3].p_x = points[2].p_x + xround(delx);
1224 		    *np = 4;
1225 
1226 		    if (c->r_xtop < points[3].p_x)  /* clip right, rectangle */
1227 		    {
1228 			points[3].p_x = c->r_xtop;
1229 			points[0].p_x = c->r_xtop;
1230 		    }
1231 		    else if (c->r_xtop < points[0].p_x) /* clip right, pentagon */
1232 		    {
1233 			dely = (dlong)(points[0].p_x - c->r_xtop) * height;
1234 			points[0].p_x = c->r_xtop;
1235 			points[4].p_x = c->r_xtop;
1236 			points[4].p_y = points[0].p_y - yround(dely);
1237 		        *np = 5;
1238 		    }
1239 		}
1240 		else if (c->r_xtop < points[0].p_x) /* clip right, quadrangle */
1241 		{
1242 		    dely = (dlong)(points[0].p_x - c->r_xtop) * height;
1243 		    points[0].p_x = c->r_xtop;
1244 		    points[3].p_x = c->r_xtop;
1245 		    points[3].p_y = points[0].p_y - yround(dely);
1246 		    *np = 4;
1247 		}
1248 		if (points[1].p_x > points[0].p_x || points[2].p_y > points[1].p_y)
1249 		    *np = 0;	/* clipped out of existence */
1250 		break;
1251 
1252 	    case TT_DIAGONAL | TT_DIRECTION:	/* sw */
1253 		if (c->r_xbot > r->r_xbot)	/* clip LEFT */
1254 		{
1255 		    dely = (dlong)(c->r_xbot - points[1].p_x) * height;
1256 		    points[1].p_x = c->r_xbot;
1257 		    points[0].p_x = c->r_xbot;
1258 		    points[0].p_y -= yround(dely);
1259 		}
1260 		if (c->r_ybot > r->r_ybot)	/* clip BOTTOM */
1261 		{
1262 		    delx = (dlong)(c->r_ybot - points[2].p_y) * width;
1263 		    points[1].p_y = c->r_ybot;
1264 		    points[2].p_y = c->r_ybot;
1265 		    points[2].p_x -= xround(delx);
1266 		}
1267 		if (c->r_xtop < points[2].p_x)	/* clip RIGHT */
1268 		{
1269 		    dely = (dlong)(points[2].p_x - c->r_xtop) * height;
1270 		    points[2].p_x = c->r_xtop;
1271 		    points[3].p_x = c->r_xtop;
1272 		    points[3].p_y = points[1].p_y + yround(dely);
1273 		    *np = 4;
1274 
1275 		    if (c->r_ytop < points[3].p_y)  /* clip TOP, rectangle */
1276 		    {
1277 			points[3].p_y = c->r_ytop;
1278 			points[0].p_y = c->r_ytop;
1279 		    }
1280 		    else if (c->r_ytop < points[0].p_y) /* clip TOP, pentagon */
1281 		    {
1282 			delx = (dlong)(points[0].p_y - c->r_ytop) * width;
1283 			points[0].p_y = c->r_ytop;
1284 			points[4].p_y = c->r_ytop;
1285 			points[4].p_x = points[0].p_x + xround(delx);
1286 		        *np = 5;
1287 		    }
1288 		}
1289 		else if (c->r_ytop < points[0].p_y) /* clip TOP, quadrangle */
1290 		{
1291 		    delx = (dlong)(points[0].p_y - c->r_ytop) * width;
1292 		    points[0].p_y = c->r_ytop;
1293 		    points[3].p_y = c->r_ytop;
1294 		    points[3].p_x = points[0].p_x + xround(delx);
1295 		    *np = 4;
1296 		}
1297 		if (points[1].p_y > points[0].p_y || points[2].p_x < points[1].p_x)
1298 		    *np = 0;	/* clipped out of existence */
1299 		break;
1300 
1301 	    case TT_DIAGONAL | TT_SIDE:	/* se */
1302 		/* order: (bottom, right), (top, left) */
1303 		if (c->r_ybot > r->r_ybot)	/* clip BOTTOM */
1304 		{
1305 		    delx = (dlong)(c->r_ybot - points[1].p_y) * width;
1306 		    points[1].p_y = c->r_ybot;
1307 		    points[0].p_y = c->r_ybot;
1308 		    points[0].p_x += xround(delx);
1309 		}
1310 		if (c->r_xtop < r->r_xtop)	/* clip RIGHT */
1311 		{
1312 		    dely = (dlong)(points[2].p_x - c->r_xtop) * height;
1313 		    points[1].p_x = c->r_xtop;
1314 		    points[2].p_x = c->r_xtop;
1315 		    points[2].p_y -= yround(dely);
1316 		}
1317 		if (c->r_ytop < points[2].p_y)	/* clip TOP */
1318 		{
1319 		    delx = (dlong)(points[2].p_y - c->r_ytop) * width;
1320 		    points[2].p_y = c->r_ytop;
1321 		    points[3].p_y = c->r_ytop;
1322 		    points[3].p_x = points[2].p_x - xround(delx);
1323 		    *np = 4;
1324 
1325 		    if (c->r_xbot > points[3].p_x)  /* clip LEFT, rectangle */
1326 		    {
1327 			points[3].p_x = c->r_xbot;
1328 			points[0].p_x = c->r_xbot;
1329 		    }
1330 		    else if (c->r_xbot > points[0].p_x) /* clip LEFT, pentagon */
1331 		    {
1332 			dely = (dlong)(c->r_xbot - points[0].p_x) * height;
1333 			points[0].p_x = c->r_xbot;
1334 			points[4].p_x = c->r_xbot;
1335 			points[4].p_y = points[0].p_y + yround(dely);
1336 		        *np = 5;
1337 		    }
1338 		}
1339 		else if (c->r_xbot > points[0].p_x) /* clip LEFT, triangle */
1340 		{
1341 		    dely = (dlong)(c->r_xbot - points[0].p_x) * height;
1342 		    points[0].p_x = c->r_xbot;
1343 		    points[3].p_x = c->r_xbot;
1344 		    points[3].p_y = points[0].p_y + yround(dely);
1345 		    *np = 4;
1346 		}
1347 		if (points[0].p_x > points[1].p_x || points[1].p_y > points[2].p_y)
1348 		    *np = 0;	/* clipped out of existence */
1349 		break;
1350 
1351 	    case TT_DIAGONAL | TT_SIDE | TT_DIRECTION:	/* ne */
1352 		/* order: (top, right), (bottom, left) */
1353 		if (c->r_xtop < r->r_xtop)	/* clip RIGHT */
1354 		{
1355 		    dely = (dlong)(points[1].p_x - c->r_xtop) * height;
1356 		    points[1].p_x = c->r_xtop;
1357 		    points[0].p_x = c->r_xtop;
1358 		    points[0].p_y += yround(dely);
1359 		}
1360 		if (c->r_ytop < r->r_ytop)	/* clip TOP */
1361 		{
1362 		    delx = (dlong)(points[2].p_y - c->r_ytop) * width;
1363 		    points[1].p_y = c->r_ytop;
1364 		    points[2].p_y = c->r_ytop;
1365 		    points[2].p_x += xround(delx);
1366 		}
1367 		if (c->r_xbot > points[2].p_x)	/* clip LEFT */
1368 		{
1369 		    dely = (dlong)(c->r_xbot - points[2].p_x) * height;
1370 		    points[2].p_x = c->r_xbot;
1371 		    points[3].p_x = c->r_xbot;
1372 		    points[3].p_y = points[2].p_y - yround(dely);
1373 		    *np = 4;
1374 
1375 		    if (c->r_ybot >= points[3].p_y)  /* clip BOTTOM, rectangle */
1376 		    {
1377 			points[3].p_y = c->r_ybot;
1378 			points[0].p_y = c->r_ybot;
1379 		    }
1380 		    else if (c->r_ybot > points[0].p_y) /* clip BOTTOM, pentagon */
1381 		    {
1382 			delx = (dlong)(c->r_ybot - points[0].p_y) * width;
1383 			points[0].p_y = c->r_ybot;
1384 			points[4].p_y = c->r_ybot;
1385 			points[4].p_x = points[0].p_x - xround(delx);
1386 		        *np = 5;
1387 		    }
1388 		}
1389 		else if (c->r_ybot > points[0].p_y) /* clip BOTTOM, quadrangle */
1390 		{
1391 		    delx = (dlong)(c->r_ybot - points[0].p_y) * width;
1392 		    points[0].p_y = c->r_ybot;
1393 		    points[3].p_y = c->r_ybot;
1394 		    points[3].p_x = points[0].p_x - xround(delx);
1395 		    *np = 4;
1396 		}
1397 		if (points[1].p_y < points[0].p_y || points[2].p_x > points[1].p_x)
1398 		    *np = 0;	/* clipped out of existence */
1399 		break;
1400 	}
1401     }
1402 }
1403 
1404 /*---------------------------------------------------------
1405  * GrDrawTriangleEdge --
1406  *	Draws the diagonal line in a triangle clipped by
1407  *	grCurClip.
1408  *
1409  * Results:
1410  *	None.
1411  *
1412  * Side effects:
1413  *	Draws nonmanhattan layout geometry.
1414  *
1415  *---------------------------------------------------------
1416  */
1417 
1418 void
GrDrawTriangleEdge(r,dinfo)1419 GrDrawTriangleEdge(r, dinfo)
1420     Rect *r;   /* Bounding box of triangle, in screen coords	*/
1421     TileType dinfo;
1422 {
1423     Point tpoints[5];
1424     int tnum, i, j;
1425 
1426     GrClipTriangle(r, &grCurClip, TRUE, dinfo, tpoints, &tnum);
1427 
1428     for (i = 0; i < tnum; i++)
1429     {
1430 	j = (i + 1) % tnum;
1431 	if (tpoints[i].p_x != tpoints[j].p_x &&
1432 		tpoints[i].p_y != tpoints[j].p_y)
1433 	{
1434 	    GrClipLine(tpoints[i].p_x, tpoints[i].p_y,
1435 			tpoints[j].p_x, tpoints[j].p_y);
1436 	    break;
1437 	}
1438     }
1439 }
1440 
1441 /*---------------------------------------------------------
1442  * GrDiagonal:
1443  *	GrDiagonal will draw a triangle on the screen in the
1444  *	style set by the previous call to GrSetStuff.  It will also
1445  *	be clipped against the rectangles passed to GrSetStuff.
1446  *
1447  *	If GrDiagonal is called between GrFastBox calls then GrSetStuff
1448  *	must be called to set the parameters back.
1449  *
1450  * Results:
1451  *	None.
1452  *
1453  * Side Effects:
1454  *	The rectangle is drawn in the style specified.
1455  *	The rectangle is clipped before being drawn.
1456  *---------------------------------------------------------
1457  */
1458 
1459 void
GrDiagonal(prect,dinfo)1460 GrDiagonal(prect, dinfo)
1461     Rect *prect;	/* The rectangle to be drawn, given in
1462 				 * screen coordinates.
1463 			         */
1464     TileType dinfo;	/* split and direction information */
1465 {
1466     Rect *r;
1467     bool needClip, needObscure;
1468     LinkedRect *ob;
1469     int cp, np;
1470     Rect clipr, fullr;
1471     Point polyp[5];
1472 
1473     GR_CHECK_LOCK();
1474     if (!grDriverInformed) grInformDriver();
1475     GrNumClipBoxes++;
1476     if (grCurFill == GR_STGRID)
1477     {
1478 	r = &grCurClip;
1479 	grGridRect = prect;
1480     }
1481     else
1482     {
1483 	r = prect;
1484 	if (!GEO_TOUCH(r, &grCurClip)) return;
1485     }
1486 
1487     /* Do a quick check to make the (very common) special case of
1488      * no clipping go fast.
1489      */
1490     needClip = !GEO_SURROUND(&grCurClip, r);
1491     needObscure = FALSE;
1492     for (ob = grCurObscure; ob != NULL; ob = ob->r_next)
1493 	needObscure |= GEO_TOUCH(r, &(ob->r_r));
1494 
1495     /* Generate points for the triangle and do clipping if necessary */
1496 
1497     clipr = fullr = *r;
1498     if (needClip)
1499 	GeoClip(&clipr, &grCurClip);
1500 
1501     GrClipTriangle(&fullr, &clipr, needClip, dinfo, polyp, &np);
1502 
1503     /* do solid areas */
1504     if ( (grCurFill == GR_STSOLID) ||
1505 	(grCurFill == GR_STSTIPPLE) || (grCurFill == GR_STGRID) )
1506     {
1507 	if (needObscure)
1508 	    grObsBox(&clipr);
1509 	else if (grFillPolygonPtr)
1510 	    (void) (*grFillPolygonPtr)(polyp, np);
1511     }
1512 
1513     /* return if rectangle is too small to see */
1514 
1515     if ((r->r_xtop - r->r_xbot < GR_THRESH) &&
1516 	    (r->r_ytop - r->r_ybot < GR_THRESH) && (grCurFill != GR_STOUTLINE))
1517 	return;
1518 
1519     /* draw outlines */
1520     if ( (grCurOutline != 0) && (grCurFill != GR_STGRID) )
1521     {
1522 	/* TO DO: Check for boundary with shared tile type */
1523 	for (cp = 0; cp < np - 1; cp++)
1524 	    (*grDrawLinePtr)(polyp[cp].p_x, polyp[cp].p_y,
1525 			polyp[cp + 1].p_x, polyp[cp + 1].p_y);
1526 
1527 	(*grDrawLinePtr)(polyp[cp].p_x, polyp[cp].p_y,
1528 			polyp[0].p_x, polyp[0].p_y);
1529     }
1530 }
1531 
1532 /*---------------------------------------------------------
1533  * GrFillPolygon --
1534  *	This routine is simply a call to the locally-defined
1535  *	grFillPolygonPtr routine.
1536  *
1537  *---------------------------------------------------------
1538  */
1539 
1540 void
GrFillPolygon(polyp,np)1541 GrFillPolygon(polyp, np)
1542     Point *polyp;		/* Array of points defining polygon */
1543     int np;			/* number of points in array polyp  */
1544 {
1545     if (grFillPolygonPtr != NULL)
1546     {
1547 	(*grFillPolygonPtr)(polyp, np);
1548     }
1549 }
1550 
1551 
1552 /*---------------------------------------------------------
1553  * GrClipBox:
1554  *	GrClipBox will draw a rectangle on the screen in one
1555  *	of several possible styles, except that the rectangle will
1556  *	be clipped against a list of obscuring rectangles.
1557  *
1558  * Results:	None.
1559  *
1560  * Side Effects:
1561  *	The rectangle is drawn in the style specified.
1562  *	The rectangle is clipped before being drawn.
1563  *---------------------------------------------------------
1564  */
1565 
1566 void
GrClipBox(prect,style)1567 GrClipBox(prect, style)
1568     Rect *prect;		/* The rectangle to be drawn, given in
1569 				 * screen coordinates.
1570 			         */
1571     int style;			/* The style to be used in drawing it. */
1572 {
1573     GrSetStuff(style);
1574     GrFastBox(prect);
1575 }
1576 
1577 
1578 /*
1579  * ----------------------------------------------------------------------------
1580  *	GrDisjoint --
1581  *
1582  * 	Clip a rectanglular area against a clipping box, applying the
1583  *	supplied procedure to each rectangular region in "area" which
1584  *	falls outside "clipbox".  This works in pixel space, where a
1585  *	rectangle is contains its lower x- and y-coordinates AND ALSO
1586  *	its upper coordinates.  This means that if the clipping box
1587  *	occupies a given pixel, the things being clipped must not occupy
1588  *	that pixel.  This procedure will NOT work in tile space.
1589  *
1590  *	The procedure should be of the form:
1591  *		bool func(box, cdarg)
1592  *			Rect	   * box;
1593  *			ClientData   cdarg;
1594  *
1595  * Results:
1596  *	Return TRUE unless the supplied function returns FALSE.
1597  *
1598  * Side effects:
1599  *	The side effects of the invoked procedure.
1600  * ----------------------------------------------------------------------------
1601  */
1602 bool
GrDisjoint(area,clipBox,func,cdarg)1603 GrDisjoint(area, clipBox, func, cdarg)
1604     Rect	* area;
1605     Rect	* clipBox;
1606     bool 	(*func) ();
1607     ClientData	  cdarg;
1608 {
1609     Rect 	  ok, rArea;
1610     bool	  result;
1611 
1612 #define NULLBOX(R) ((R.r_xbot>R.r_xtop)||(R.r_ybot>R.r_ytop))
1613 
1614     ASSERT((area!=(Rect *) NULL), "GrDisjoint");
1615     if((clipBox==(Rect *) NULL)||(!GEO_TOUCH(area, clipBox)))
1616     {
1617     /* Since there is no overlap, all of "area" may be processed. */
1618 
1619 	result= (*func)(area, cdarg);
1620 	return(result);
1621     }
1622 
1623     /* Do the disjoint operation in four steps, one for each side
1624      * of clipBox.  In each step, divide the area being clipped
1625      * into one piece that is DEFINITELY outside clipBox, and one
1626      * piece left to check some more.
1627      */
1628 
1629     /* Top edge of clipBox: */
1630 
1631     rArea = *area;
1632     result = TRUE;
1633     if (clipBox->r_ytop < rArea.r_ytop)
1634     {
1635 	ok = rArea;
1636 	ok.r_ybot = clipBox->r_ytop + 1;
1637 	rArea.r_ytop = clipBox->r_ytop;
1638 	if (!(*func)(&ok, cdarg)) result = FALSE;
1639     }
1640 
1641     /* Bottom edge of clipBox: */
1642 
1643     if (clipBox->r_ybot > rArea.r_ybot)
1644     {
1645 	ok = rArea;
1646 	ok.r_ytop = clipBox->r_ybot - 1;
1647 	rArea.r_ybot = clipBox->r_ybot;
1648 	if (!(*func)(&ok, cdarg)) result = FALSE;
1649     }
1650 
1651     /* Right edge of clipBox: */
1652 
1653     if (clipBox->r_xtop < rArea.r_xtop)
1654     {
1655 	ok = rArea;
1656 	ok.r_xbot = clipBox->r_xtop + 1;
1657 	rArea.r_xtop = clipBox->r_xtop;
1658 	if (!(*func)(&ok, cdarg)) result = FALSE;
1659     }
1660 
1661     /* Left edge of clipBox: */
1662 
1663     if (clipBox->r_xbot > rArea.r_xbot)
1664     {
1665 	ok = rArea;
1666 	ok.r_xtop = clipBox->r_xbot - 1;
1667 	rArea.r_xbot = clipBox->r_xbot;
1668 	if (!(*func)(&ok, cdarg)) result = FALSE;
1669     }
1670 
1671     /* Just throw away what's left of the area being clipped, since
1672      * it overlaps the clipBox.
1673      */
1674 
1675     return result;
1676 } /*GrDisjoint*/
1677