Files
magic/graphics/grClip.c
T
Patrick Kurth ea03883829 Fixed unused-parameters/unused-variables warnings
Added a ARG_UNUSED macro in utils/magic.h, which
produces a simple cast to void to silence the warnings.
The reasons this is used as opposed to an attribute is
that most compilers should support this.
Besides this, the macro can be easily searched for in
the future to potentially remove (where possible) the
unused parameters.
2025-10-10 22:12:19 +02:00

1676 lines
42 KiB
C

/* grClip.c -
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*
* This file contains additional functions to manipulate a
* color display. Included here are rectangle clipping and
* drawing routines.
*/
#ifndef lint
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 $";
#endif /* not lint */
#include <stdio.h>
#include "utils/magic.h"
#include "textio/textio.h"
#include "utils/geometry.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "utils/styles.h"
#include "database/database.h"
#include "windows/windows.h"
#include "graphics/graphics.h"
#include "graphics/graphicsInt.h"
#include "utils/malloc.h"
/* Forward declaration: */
extern bool GrDisjoint();
extern void GrClipTriangle();
/* The following rectangle defines the size of the cross drawn for
* zero-size rectangles. This must be all on one line to keep
* lintpick happy!
*/
global Rect GrCrossRect = {{-GR_CROSSSIZE, -GR_CROSSSIZE}, {GR_CROSSSIZE, GR_CROSSSIZE}};
global int GrNumClipBoxes = 0; /* for benchmarking */
global int grCurDStyle;
global unsigned char GrGridMultiple = 1;
/* A rectangle that is one square of the grid */
static Rect *grGridRect;
/*
* ----------------------------------------------------------------------------
* GrSetStuff --
*
* Set up current drawing style.
*
* Results:
* None.
*
* Side effects:
* Variables are changed. If anything is drawn, it will appear in the
* specified style.
* ----------------------------------------------------------------------------
*/
/* Current state for rectangle and text drawing */
static int grCurWMask, grCurStipple;
#ifndef MAGIC_WRAPPER
static /* Used in grTkCommon.c, so don't make static */
#endif
int grCurOutline, grCurFill, grCurColor;
/* Has the device driver been informed of the above? We only inform it
* when we actually need to draw something -- this makes it harmless (in terms
* of graphics bandwidth) to call GrSetStuff extra times.
*/
bool grDriverInformed = TRUE;
void
GrSetStuff(style)
int style;
{
grCurDStyle = style;
grCurWMask = GrStyleTable[style].mask;
grCurColor = GrStyleTable[style].color;
grCurOutline = GrStyleTable[style].outline;
grCurStipple = GrStyleTable[style].stipple;
grCurFill = GrStyleTable[style].fill;
grDriverInformed = FALSE;
}
/*---------------------------------------------------------------------------
* grInformDriver:
*
* Inform the driver about the last GrSetStuff call.
*
* Results:
* None.
*
* Side Effects:
* None.
*
*----------------------------------------------------------------------------
*/
void
grInformDriver()
{
/* Now let the device drivers know */
(*grSetWMandCPtr)(grCurWMask, grCurColor);
(*grSetLineStylePtr)(grCurOutline);
(*grSetStipplePtr)(grCurStipple);
grDriverInformed = TRUE;
}
/*
* ----------------------------------------------------------------------------
* grClipAgainst --
*
* Clip a linked list of rectangles against a single rectangle. This
* may result in the list getting longer or shorter.
*
* Results:
* None.
*
* Side effects:
* The original list may change.
* ----------------------------------------------------------------------------
*/
void
grClipAgainst(startllr, clip)
LinkedRect **startllr; /* A pointer to the pointer that heads
* the list .
*/
Rect *clip; /* The rectangle to clip against */
{
extern bool grClipAddFunc(); /* forward declaration */
LinkedRect **llr, *lr;
for (llr = startllr; *llr != (LinkedRect *) NULL; /*nop*/ )
{
if ( GEO_TOUCH(&(*llr)->r_r, clip) )
{
lr = *llr;
*llr = lr->r_next;
/* this will modify the list that we are traversing! */
(void) GrDisjoint(&lr->r_r, clip, grClipAddFunc,
(ClientData) &llr);
freeMagic( (char *) lr);
}
else
llr = &((*llr)->r_next);
}
}
/* Add a box to our linked list, and advance
* our pointer into the list
*/
bool grClipAddFunc(box, cd)
Rect *box;
ClientData cd;
{
LinkedRect ***lllr, *lr;
lllr = (LinkedRect ***) cd;
lr = (LinkedRect *) mallocMagic((unsigned) (sizeof (LinkedRect)));
lr->r_r = *box;
lr->r_next = **lllr;
**lllr = lr;
*lllr = &lr->r_next;
return TRUE;
}
void
grObsBox(r)
Rect *r;
{
LinkedRect *ob;
LinkedRect *ar;
LinkedRect **areas;
ar = (LinkedRect *) mallocMagic((unsigned) (sizeof (LinkedRect)));
ar->r_r = *r;
ar->r_next = NULL;
areas = &ar;
/* clip against obscuring areas */
for (ob = grCurObscure; ob != NULL; ob = ob->r_next)
{
if ( GEO_TOUCH(r, &(ob->r_r)) )
grClipAgainst(areas, &(ob->r_r));
}
while (*areas != NULL)
{
LinkedRect *oldarea;
if (grCurFill == GR_STGRID)
(*grDrawGridPtr)(grGridRect, grCurOutline, &((*areas)->r_r));
else
(*grFillRectPtr)(&((*areas)->r_r));
oldarea = *areas;
*areas = (*areas)->r_next;
freeMagic( (char *) oldarea );
}
}
/*---------------------------------------------------------
* grClipPoints:
* This routine computes the 0, 1, or 2 intersection points
* between a line and a box.
*
* Results:
* FALSE if the line is completely outside of the box.
*
* Side Effects:
*---------------------------------------------------------
*/
bool
grClipPoints(line, box, p1, p1OK, p2, p2OK)
Rect *line; /* Actually a line from line->r_ll to
* line->r_ur. It is assumed that r_ll is to
* the left of r_ur, but we don't assume that
* r_ll is below r_ur.
*/
Rect *box; /* A box to check intersections with */
Point *p1, *p2; /* To be filled in with 0, 1, or 2 points
* that are on the border of the box as well as
* on the line.
*/
bool *p1OK, *p2OK; /* Says if the point was filled in */
{
int tmp, delx, dely;
bool delyneg;
int x1, x2, y1, y2;
bool ok1, ok2;
if (p1OK != NULL) *p1OK = FALSE;
ok1 = FALSE;
if (p2OK != NULL) *p2OK = FALSE;
ok2 = FALSE;
x1 = line->r_xbot;
x2 = line->r_xtop;
y1 = line->r_ybot;
y2 = line->r_ytop;
delx = x2-x1;
dely = y2-y1;
/* We have to be careful because of machine-dependent problems
* with rounding during division by negative numbers.
*/
if (dely<0)
{
dely = -dely;
delyneg = TRUE;
}
else
delyneg = FALSE;
/* we know that delx is nonnegative if this is a real (non-empty) line */
if (delx < 0) return FALSE;
if (x1 < box->r_xbot)
{
if (delx == 0) return FALSE;
tmp = (((box->r_xbot-x1)*dely) + (delx>>1))/delx;
if (delyneg) y1 -= tmp;
else y1 += tmp;
x1 = box->r_xbot;
}
else
if (x1 > box->r_xtop) return FALSE;
if (x2 > box->r_xtop)
{
if (delx == 0) return FALSE;
tmp = ((x2-box->r_xtop)*dely + (delx>>1))/delx;
if (delyneg) y2 += tmp;
else y2 -= tmp;
x2 = box->r_xtop;
}
else
if (x2 < box->r_xbot) return FALSE;
if (y2 > y1)
{
if (y1 < box->r_ybot)
{
x1 += (((box->r_ybot-y1)*delx) + (dely>>1))/dely;
y1 = box->r_ybot;
}
else if (y1 > box->r_ytop) return FALSE;
if (y2 > box->r_ytop)
{
x2 -= (((y2 - box->r_ytop)*delx) + (dely>>1))/dely;
y2 = box->r_ytop;
}
else if (y2 < box->r_ybot) return FALSE;
}
else
{
if (y1 > box->r_ytop)
{
if (dely == 0) return FALSE;
x1 += (((y1-box->r_ytop)*delx) + (dely>>1))/dely;
y1 = box->r_ytop;
}
else if (y1 < box->r_ybot) return FALSE;
if (y2 < box->r_ybot)
{
if (dely == 0) return FALSE;
x2 -= (((box->r_ybot-y2)*delx) + (dely>>1))/dely;
y2 = box->r_ybot;
}
else if (y2 > box->r_ytop) return FALSE;
}
if ( (x1 == box->r_xbot) || (y1 == box->r_ybot) || (y1 == box->r_ytop) )
{
if (p1 != NULL)
{
p1->p_x = x1;
p1->p_y = y1;
}
if (p1OK != NULL) *p1OK = TRUE;
ok1 = TRUE;
}
if ( (x2 == box->r_xtop) || (y2 == box->r_ybot) || (y2 == box->r_ytop) )
{
if (p2 != NULL)
{
p2->p_x = x2;
p2->p_y = y2;
}
if (p2OK != NULL) *p2OK = TRUE;
ok2 = TRUE;
}
/* is part of the line in the box? */
return ok1 || ok2 ||
((x1 >= box->r_xbot) && (x1 <= box->r_xtop) && (y1 >= box->r_ybot)
&& (y1 <= box->r_ytop));
}
#define NEWAREA(lr,x1,y1,x2,y2) {LinkedRect *tmp; \
tmp = (LinkedRect *) mallocMagic((unsigned) (sizeof (LinkedRect))); \
tmp->r_r.r_xbot = x1; tmp->r_r.r_xtop = x2; \
tmp->r_r.r_ybot = y1; tmp->r_r.r_ytop = y2; tmp->r_next = lr; lr = tmp;}
/*---------------------------------------------------------
* GrClipLine:
* GrClipLine will draw a line on the screen in the current
* style and clip stuff.
*
* Results: None.
*
* Side Effects:
* The line is drawn in the current style.
*---------------------------------------------------------
*/
void
GrClipLine(x1, y1, x2, y2)
int x1, y1, x2, y2;
{
LinkedRect **ar;
LinkedRect *ob;
LinkedRect *areas;
GR_CHECK_LOCK();
if (!grDriverInformed) grInformDriver();
/* we will pretend the the ll corner of a rectangle is the
* left endpoint of a line, and the ur corner the right endpoint
* of the line.
*/
areas = (LinkedRect *) mallocMagic((unsigned) (sizeof (LinkedRect)));
areas->r_next = NULL;
if (x1 < x2)
{
areas->r_r.r_xbot = x1;
areas->r_r.r_ybot = y1;
areas->r_r.r_xtop = x2;
areas->r_r.r_ytop = y2;
}
else
{
areas->r_r.r_xtop = x1;
areas->r_r.r_ytop = y1;
areas->r_r.r_xbot = x2;
areas->r_r.r_ybot = y2;
}
/* clip against the clip box */
for (ar = &areas; *ar != NULL; )
{
Rect *l;
Rect canonRect;
l = &((*ar)->r_r);
GeoCanonicalRect(l, &canonRect);
if (!GEO_TOUCH(&canonRect, &grCurClip))
{
/* line is totally outside of clip area */
goto deleteit;
}
else
{
/* is there some intersection with clip area? */
if (!grClipPoints(l, &grCurClip, &(l->r_ll), (bool *) NULL,
&(l->r_ur), (bool*) NULL))
{
/* no intersection */
goto deleteit;
}
/* clip against obscuring areas */
for (ob = grCurObscure; ob != NULL; ob = ob->r_next)
{
Point p1, p2;
Rect c;
bool ok1 = FALSE, ok2 = FALSE;
c = ob->r_r;
c.r_xbot--; c.r_ybot--;
c.r_xtop++; c.r_ytop++;
if (grClipPoints(l, &c, &p1, &ok1, &p2, &ok2) &&
!ok1 && !ok2)
{
/* Line is not completely outside of the box,
* nor does it intersect it.
* Therefore, line is completely obscured.
*/
goto deleteit;
}
if (ok1 &&
( ((l->r_xbot == p1.p_x) && (l->r_ybot == p1.p_y)) ||
((l->r_xtop == p1.p_x) && (l->r_ytop == p1.p_y)) ) )
{
ok1 = FALSE; /* do not split or clip at an endpoint */
}
if (ok2 &&
( ((l->r_xbot == p2.p_x) && (l->r_ybot == p2.p_y)) ||
((l->r_xtop == p2.p_x) && (l->r_ytop == p2.p_y)) ) )
{
ok2 = FALSE; /* do not split or clip at an endpoint */
}
if (ok1 ^ ok2)
{
/* one segment to deal with */
if (ok1)
l->r_ur = p1;
else
l->r_ll = p2;
}
else if (ok1 && ok2)
{
/* clip both sides */
LinkedRect *new;
new = (LinkedRect *) mallocMagic((unsigned) (sizeof (LinkedRect)));
new->r_r.r_ur = l->r_ur;
new->r_r.r_ll = p2;
new->r_next = (*ar);
l->r_ur = p1;
(*ar) = new;
}
}
}
ar = &((*ar)->r_next);
continue;
deleteit: {
LinkedRect *reclaim;
reclaim = (*ar);
*ar = reclaim->r_next;
freeMagic( (char *) reclaim);
}
} /* for ar */
/* draw the lines */
while (areas != NULL)
{
LinkedRect *oldarea;
(*grDrawLinePtr)(areas->r_r.r_xbot, areas->r_r.r_ybot,
areas->r_r.r_xtop, areas->r_r.r_ytop);
oldarea = areas;
areas = areas->r_next;
freeMagic( (char *) oldarea );
}
}
/*
*---------------------------------------------------------
* grAddSegment:
* Add a segment to a linked list of rectangles
*
* Results:
* None.
*
* Side effects:
* Allocates memory; appends LinkedRect structure to
* list "segments".
*
* Notes:
* INLINE this for speedup?
*---------------------------------------------------------
*/
void
grAddSegment(llx, lly, urx, ury, segments)
int llx, lly, urx, ury;
LinkedRect **segments;
{
LinkedRect *curseg;
curseg = (LinkedRect *)mallocMagic(sizeof(LinkedRect));
curseg->r_r.r_xbot = llx;
curseg->r_r.r_ybot = lly;
curseg->r_r.r_xtop = urx;
curseg->r_r.r_ytop = ury;
curseg->r_next = *segments;
*segments = curseg;
}
/*---------------------------------------------------------
* GrBoxOutline:
* For box outlines, works around the boundary of
* the box according to the associated tile structure,
* and returns a linked rect list defining all the
* segments which need to be drawn.
*
* Results:
* TRUE if tile is isolated (GrFastBox can be used).
* Otherwise, result is FALSE.
*
* Side Effects:
* May allocate memory for a linked rect structure,
* with pointer returned in tilesegs. If non-NULL,
* the calling function needs to free memory for the
* linked rect structure.
*
* Implementation notes:
* Standard tech files define most bordered styles as
* contact types, and most if not all contacts are
* required to be square. So we want the case of an
* isolated tile to go fast, avoiding any calls to
* allocate memory. This complicates the routine but
* keeps the routine from slowing down the layout
* rendering.
*---------------------------------------------------------
*/
bool
GrBoxOutline(tile, tilesegs)
Tile *tile;
LinkedRect **tilesegs;
{
Rect rect;
TileType ttype;
Tile *tpleft, *tpright, *tptop, *tpbot;
int edgeTop, edgeBot, edgeRight, edgeLeft;
int isolate = 0;
bool sense;
*tilesegs = NULL;
TiToRect(tile, &rect);
if (IsSplit(tile) && SplitSide(tile))
isolate |= 0x1;
else
{
ttype = TiGetLeftType(tile);
edgeBot = rect.r_ybot;
sense = TRUE;
for (tpleft = BL(tile); BOTTOM(tpleft) < rect.r_ytop; tpleft = RT(tpleft))
{
if (TiGetRightType(tpleft) != ttype)
{
if (!sense)
{
edgeBot = BOTTOM(tpleft);
if (TOP(tpleft) >= rect.r_ytop)
grAddSegment(rect.r_xbot, edgeBot, rect.r_xbot, rect.r_ytop,
tilesegs);
sense = TRUE;
}
}
else
{
if (sense)
{
edgeTop = BOTTOM(tpleft);
if (edgeTop > edgeBot)
grAddSegment(rect.r_xbot, edgeBot, rect.r_xbot, edgeTop,
tilesegs);
isolate |= 0x1;
sense = FALSE;
}
}
}
}
if (IsSplit(tile) && !SplitSide(tile))
isolate |= 0x2;
else
{
ttype = TiGetRightType(tile);
edgeTop = rect.r_ytop;
sense = TRUE;
for (tpright = TR(tile); TOP(tpright) > rect.r_ybot; tpright = LB(tpright))
{
if (TiGetLeftType(tpright) != ttype)
{
if (!sense)
{
edgeTop = TOP(tpright);
if (BOTTOM(tpright) <= rect.r_ybot)
grAddSegment(rect.r_xtop, rect.r_ybot, rect.r_xtop, edgeTop,
tilesegs);
sense = TRUE;
}
}
else
{
if (sense)
{
edgeBot = TOP(tpright);
if (edgeBot < edgeTop)
grAddSegment(rect.r_xtop, edgeBot, rect.r_xtop, edgeTop,
tilesegs);
isolate |= 0x2;
sense = FALSE;
}
}
}
}
if (IsSplit(tile) &&
(SplitSide(tile) == SplitDirection(tile)))
isolate |= 0x4;
else
{
ttype = TiGetBottomType(tile);
edgeLeft = rect.r_xbot;
sense = TRUE;
for (tpbot = LB(tile); LEFT(tpbot) < rect.r_xtop; tpbot = TR(tpbot))
{
if (TiGetTopType(tpbot) != ttype)
{
if (!sense)
{
edgeLeft = LEFT(tpbot);
if (RIGHT(tpbot) >= rect.r_xtop)
grAddSegment(edgeLeft, rect.r_ybot, rect.r_xtop, rect.r_ybot,
tilesegs);
sense = TRUE;
}
}
else
{
if (sense)
{
edgeRight = LEFT(tpbot);
if (edgeRight > edgeLeft)
grAddSegment(edgeLeft, rect.r_ybot, edgeRight, rect.r_ybot,
tilesegs);
isolate |= 0x4;
sense = FALSE;
}
}
}
}
if (IsSplit(tile) &&
(SplitSide(tile) != SplitDirection(tile)))
isolate |= 0x8;
else
{
ttype = TiGetTopType(tile);
edgeRight = rect.r_xtop;
sense = TRUE;
for (tptop = RT(tile); RIGHT(tptop) > rect.r_xbot; tptop = BL(tptop))
{
if (TiGetBottomType(tptop) != ttype)
{
if (!sense)
{
edgeRight = RIGHT(tptop);
if (LEFT(tptop) <= rect.r_xbot)
grAddSegment(rect.r_xbot, rect.r_ytop, edgeRight, rect.r_ytop,
tilesegs);
sense = TRUE;
}
}
else
{
if (sense)
{
edgeLeft = RIGHT(tptop);
if (edgeLeft < edgeRight)
grAddSegment(edgeLeft, rect.r_ytop, edgeRight, rect.r_ytop,
tilesegs);
isolate |= 0x8;
sense = FALSE;
}
}
}
}
if (isolate == 0) /* Common case */
return TRUE;
else
{
/* Need to malloc segments for isolated sides */
if (!(isolate & 0x1)) /* Left */
grAddSegment(rect.r_xbot, rect.r_ybot, rect.r_xbot, rect.r_ytop,
tilesegs);
if (!(isolate & 0x2)) /* Right */
grAddSegment(rect.r_xtop, rect.r_ybot, rect.r_xtop, rect.r_ytop,
tilesegs);
if (!(isolate & 0x4)) /* Bottom */
grAddSegment(rect.r_xbot, rect.r_ybot, rect.r_xtop, rect.r_ybot,
tilesegs);
if (!(isolate & 0x8)) /* Top */
grAddSegment(rect.r_xbot, rect.r_ytop, rect.r_xtop, rect.r_ytop,
tilesegs);
return FALSE;
}
}
/* Threshold for determining if outlines are too small to draw */
#define GR_THRESH 4
/*---------------------------------------------------------
* GrBox --
*
* GrBox draws a rectangle on the screen in the style
* set by the previous call to GrSetStuff. It will
* be clipped against the rectangles passed to GrSetStuff.
*
* Unlike GrFastBox (see below), GrBox makes no assumptions
* about how the outline will be drawn. If there is no
* outline, GrFastBox is called. The tile border is checked,
* and if the tile outline is simple, GrFastBox is called.
* Otherwise, we do a fast fill a la GrFastBox but draw the
* outline segment by segment.
*
* Results: None.
*
* Side Effects:
* The rectangle is drawn in the style specified.
* The rectangle may be clipped before being drawn.
*---------------------------------------------------------
*/
void
GrBox(MagWindow *mw, Transform *trans, Tile *tile)
{
Rect r, r2, clipr;
bool needClip, needObscure;
LinkedRect *ob, *tilesegs, *segptr;
Point polyp[5];
int np;
r.r_xbot = LEFT(tile);
r.r_ybot = BOTTOM(tile);
r.r_xtop = RIGHT(tile);
r.r_ytop = TOP(tile);
GeoTransRect(trans, &r, &r2);
if (IsSplit(tile))
WindSurfaceToScreenNoClip(mw, &r2, &r);
else
WindSurfaceToScreen(mw, &r2, &r);
GR_CHECK_LOCK();
if (!grDriverInformed) grInformDriver();
GrNumClipBoxes++;
if (!GEO_TOUCH(&r, &grCurClip)) return;
/* Do a quick check to make the (very common) special case of
* no clipping go fast.
*/
needClip = !GEO_SURROUND(&grCurClip, &r);
needObscure = FALSE;
for (ob = grCurObscure; ob != NULL; ob = ob->r_next)
needObscure |= GEO_TOUCH(&r, &(ob->r_r));
/* Nonmanhattan tiles: */
/* Expects one of the two tile types to be masked out before */
/* this procedure is called. */
if (IsSplit(tile))
{
/* Perform matrix transformations on split tiles */
TileType dinfo;
Rect fullr;
dinfo = DBTransformDiagonal(TiGetTypeExact(tile), trans);
clipr = fullr = r;
if (needClip)
GeoClip(&clipr, &grCurClip);
GrClipTriangle(&fullr, &clipr, needClip, dinfo, polyp, &np);
if ((grCurFill == GR_STSOLID) ||
(grCurFill == GR_STSTIPPLE) || (grCurFill == GR_STGRID) )
{
if (needObscure)
grObsBox(&clipr);
else if (grFillPolygonPtr)
(void) (*grFillPolygonPtr)(polyp, np);
}
}
else
{
/* do solid areas (same as GrFastBox) */
if ((grCurFill == GR_STSOLID) || (grCurFill == GR_STSTIPPLE))
{
/* We have a filled area to deal with */
clipr = r;
if (needClip)
GeoClip(&clipr, &grCurClip);
if (needObscure)
grObsBox(&clipr);
else
(void) (*grFillRectPtr)(&clipr);
}
}
/* return if outline is too small to be worth drawing */
if ((r.r_xtop - r.r_xbot < GR_THRESH)
&& (r.r_ytop - r.r_ybot < GR_THRESH)
&& (grCurFill != GR_STOUTLINE))
return;
/* do diagonal lines for contacts */
if (grCurFill == GR_STCROSS)
{
Rect rnc;
/* don't clip contact diagonals */
if (needClip || needObscure)
{
WindSurfaceToScreenNoClip(mw, &r2, &rnc);
/*
(*grDrawLinePtr)(rnc.r_xbot, rnc.r_ybot, rnc.r_xtop, rnc.r_ytop);
(*grDrawLinePtr)(rnc.r_xbot, rnc.r_ytop, rnc.r_xtop, rnc.r_ybot);
*/
if (!IsSplit(tile))
{
GrClipLine(rnc.r_xbot, rnc.r_ybot, rnc.r_xtop, rnc.r_ytop);
GrClipLine(rnc.r_xbot, rnc.r_ytop, rnc.r_xtop, rnc.r_ybot);
}
}
else
{
if (!IsSplit(tile))
{
(*grDrawLinePtr)(r.r_xbot, r.r_ybot, r.r_xtop, r.r_ytop);
(*grDrawLinePtr)(r.r_xbot, r.r_ytop, r.r_xtop, r.r_ybot);
}
}
}
/* draw outlines */
if (grCurOutline != 0)
{
if (GrBoxOutline(tile, &tilesegs))
{
/* simple box (from GrFastBox)*/
if (needClip || needObscure)
{
GrClipLine(r.r_xbot, r.r_ytop, r.r_xtop, r.r_ytop);
GrClipLine(r.r_xbot, r.r_ybot, r.r_xtop, r.r_ybot);
GrClipLine(r.r_xbot, r.r_ybot, r.r_xbot, r.r_ytop);
GrClipLine(r.r_xtop, r.r_ybot, r.r_xtop, r.r_ytop);
}
else
{
(*grDrawLinePtr)(r.r_xbot, r.r_ytop, r.r_xtop, r.r_ytop);
(*grDrawLinePtr)(r.r_xbot, r.r_ybot, r.r_xtop, r.r_ybot);
(*grDrawLinePtr)(r.r_xbot, r.r_ybot, r.r_xbot, r.r_ytop);
(*grDrawLinePtr)(r.r_xtop, r.r_ybot, r.r_xtop, r.r_ytop);
}
}
else
{
/* non-rectangular box; requires drawing segments */
for (segptr = tilesegs; segptr != NULL; segptr = segptr->r_next)
{
GeoTransRect(trans, &segptr->r_r, &r2);
WindSurfaceToScreen(mw, &r2, &r);
if (needClip || needObscure)
GrClipLine(r.r_xbot, r.r_ybot, r.r_xtop, r.r_ytop);
else
(*grDrawLinePtr)(r.r_xbot, r.r_ybot, r.r_xtop, r.r_ytop);
/* Free memory, if it was allocated for outline segments */
freeMagic(segptr);
}
/* For non-manhattan tiles, the manhattan parts of the */
/* boundary have already been drawn. The diagonal boundary */
/* is guaranteed to be continuous by definition, and it has */
/* already undergone clipping with GrClipTriangle. So just */
/* draw it, now. */
if (IsSplit(tile))
{
int cp;
for (cp = 0; cp < np - 1; cp++)
{
if ((polyp[cp].p_x != polyp[cp + 1].p_x) &&
(polyp[cp].p_y != polyp[cp + 1].p_y))
{
(*grDrawLinePtr)(polyp[cp].p_x, polyp[cp].p_y,
polyp[cp + 1].p_x, polyp[cp + 1].p_y);
break; /* only 1 diagonal line to draw */
}
}
if (cp == (np - 1))
{
if ((polyp[cp].p_x != polyp[0].p_x) &&
(polyp[cp].p_y != polyp[0].p_y))
(*grDrawLinePtr)(polyp[cp].p_x, polyp[cp].p_y,
polyp[0].p_x, polyp[0].p_y);
}
}
}
}
}
/*---------------------------------------------------------
* GrDrawFastBox:
* GrDrawFastBox will draw a rectangle on the screen in the
* style set by the previous call to GrSetStuff. It will also
* be clipped against the rectangles passed to GrSetStuff.
*
* If GrClipBox is called between GrDrawFastBox calls then GrSetStuff
* must be called to set the parameters back.
*
* Usually this is called as GrFastBox, defined as GrDrawFastBox(p, 0).
* The "scale" is only used to reduce the size of crosses drawn at
* point positions, to prevent point labels from dominating a layout
* in top-level views.
*
* Results: None.
*
* Side Effects:
* The rectangle is drawn in the style specified.
* The rectangle is clipped before being drawn.
*---------------------------------------------------------
*/
void
GrDrawFastBox(prect, scale)
Rect *prect; /* The rectangle to be drawn, given in
* screen coordinates.
*/
int scale; /* If < 0, we reduce the cross size for
* points according to the (negative) scale,
* so point labels don't dominate a top-level
* layout.
*/
{
Rect *r;
bool needClip, needObscure;
LinkedRect *ob;
GR_CHECK_LOCK();
if (!grDriverInformed) grInformDriver();
GrNumClipBoxes++;
if (grCurFill == GR_STGRID)
{
r = &grCurClip;
grGridRect = prect;
}
else
{
r = prect;
if (!GEO_TOUCH(r, &grCurClip)) return;
}
/* Do a quick check to make the (very common) special case of
* no clipping go fast.
*/
needClip = !GEO_SURROUND(&grCurClip, r);
needObscure = FALSE;
for (ob = grCurObscure; ob != NULL; ob = ob->r_next)
needObscure |= GEO_TOUCH(r, &(ob->r_r));
/* do solid areas */
if ( (grCurFill == GR_STSOLID) ||
(grCurFill == GR_STSTIPPLE) || (grCurFill == GR_STGRID) )
{
Rect clipr;
/* We have a filled area to deal with */
clipr = *r;
if (needClip)
GeoClip(&clipr, &grCurClip);
if (needObscure)
grObsBox(&clipr);
else
{
if (grCurFill == GR_STGRID)
(*grDrawGridPtr)(grGridRect, grCurOutline, &clipr);
else
(void) (*grFillRectPtr)(&clipr);
}
}
/* return if rectangle is too small to see */
if ((r->r_xtop - r->r_xbot < GR_THRESH)
&& (r->r_ytop - r->r_ybot < GR_THRESH)
&& (grCurFill != GR_STOUTLINE))
return;
/* draw outlines */
if ( (grCurOutline != 0) && (grCurFill != GR_STGRID) )
{
if ( (grCurFill == GR_STOUTLINE) && (r->r_xbot == r->r_xtop) &&
(r->r_ybot == r->r_ytop) )
{
int crossSize = GR_CROSSSIZE;
if (scale < 0)
{
crossSize += scale;
if (crossSize < 0)
goto endit;
}
/* turn the outline into a cross */
if (needClip || needObscure)
goto clipit;
else
{
bool crossClip, crossObscure;
Rect crossBox;
/* check the larger cross area for clipping */
crossBox.r_xbot = r->r_xbot - crossSize;
crossBox.r_ybot = r->r_ybot - crossSize;
crossBox.r_xtop = r->r_xtop + crossSize;
crossBox.r_ytop = r->r_ytop + crossSize;
crossClip = !GEO_SURROUND(&grCurClip, &crossBox);
crossObscure = FALSE;
for (ob = grCurObscure; ob != NULL; ob = ob->r_next)
crossObscure |= GEO_TOUCH(&crossBox, &(ob->r_r));
if (crossClip || crossObscure)
goto clipit;
else
goto noclipit;
}
clipit:
GrClipLine(r->r_xbot, r->r_ybot - crossSize,
r->r_xtop, r->r_ytop + crossSize - 1 + GrPixelCorrect);
GrClipLine(r->r_xbot - crossSize, r->r_ybot,
r->r_xtop + crossSize - 1 + GrPixelCorrect, r->r_ytop);
goto endit;
noclipit:
(*grDrawLinePtr)(r->r_xbot, r->r_ybot - crossSize,
r->r_xtop, r->r_ytop + crossSize - 1 + GrPixelCorrect);
(*grDrawLinePtr)(r->r_xbot - crossSize, r->r_ybot,
r->r_xtop + crossSize - 1 + GrPixelCorrect, r->r_ytop);
endit: ;
}
else
{
if (needClip || needObscure)
{
GrClipLine(r->r_xbot, r->r_ytop, r->r_xtop, r->r_ytop);
GrClipLine(r->r_xbot, r->r_ybot, r->r_xtop, r->r_ybot);
GrClipLine(r->r_xbot, r->r_ybot, r->r_xbot, r->r_ytop);
GrClipLine(r->r_xtop, r->r_ybot, r->r_xtop, r->r_ytop);
}
else
{
(*grDrawLinePtr)(r->r_xbot, r->r_ytop, r->r_xtop, r->r_ytop);
(*grDrawLinePtr)(r->r_xbot, r->r_ybot, r->r_xtop, r->r_ybot);
(*grDrawLinePtr)(r->r_xbot, r->r_ybot, r->r_xbot, r->r_ytop);
(*grDrawLinePtr)(r->r_xtop, r->r_ybot, r->r_xtop, r->r_ytop);
}
}
}
/* do diagonal lines for contacts */
if (grCurFill == GR_STCROSS)
{
if (needClip || needObscure)
{
GrClipLine(r->r_xbot, r->r_ybot, r->r_xtop, r->r_ytop);
GrClipLine(r->r_xbot, r->r_ytop, r->r_xtop, r->r_ybot);
}
else
{
(*grDrawLinePtr)(r->r_xbot, r->r_ybot, r->r_xtop, r->r_ytop);
(*grDrawLinePtr)(r->r_xbot, r->r_ytop, r->r_xtop, r->r_ybot);
}
}
}
/*---------------------------------------------------------
* GrClipTriangle:
* Returns an array of points representing a clipped
* triangle. These are always arranged in counter-
* clockwise order.
*
* Results:
* None.
*
* Side effects:
* Returns array of points and modifies int * np
* to hold the number of points in the array.
*---------------------------------------------------------
*/
#define xround(d) (int)(((((d % height) << 1) >= height) ? 1 : 0) + (d / height))
#define yround(d) (int)(((((d % width) << 1) >= width) ? 1 : 0) + (d / width))
void
GrClipTriangle(r, c, clipped, dinfo, points, np)
Rect *r; /* Bounding box of triangle, in screen coords */
Rect *c; /* Clipping rectangle */
bool clipped; /* Boolean, if bounding box is clipped */
TileType dinfo; /* Split side and direction information */
Point *points; /* Point array (up to 5 points) to fill */
int *np; /* Number of points in the clipped polygon */
{
if (!(dinfo & TT_SIDE))
{
points[1].p_x = r->r_xbot;
points[0].p_y = r->r_ytop;
points[2].p_y = r->r_ybot;
points[0].p_x = points[2].p_x = r->r_xtop;
}
else
{
points[1].p_x = r->r_xtop;
points[0].p_y = r->r_ybot;
points[2].p_y = r->r_ytop;
points[0].p_x = points[2].p_x = r->r_xbot;
}
if (!(dinfo & TT_DIRECTION))
{
points[1].p_y = points[0].p_y;
points[2].p_x = points[1].p_x;
}
else
{
points[0].p_x = points[1].p_x;
points[1].p_y = points[2].p_y;
}
*np = 3;
/* Clip the triangle to the clipping rectangle. Result is */
/* a 3- to 5-sided polygon, or empty. */
if (clipped)
{
dlong delx, dely;
dlong width = (dlong)(r->r_xtop - r->r_xbot);
dlong height = (dlong)(r->r_ytop - r->r_ybot);
switch(dinfo & (TT_DIAGONAL | TT_DIRECTION | TT_SIDE))
{
case TT_DIAGONAL: /* nw */
if (c->r_ytop < r->r_ytop) /* clip top */
{
delx = (dlong)(points[1].p_y - c->r_ytop) * width;
points[1].p_y = c->r_ytop;
points[0].p_y = c->r_ytop;
points[0].p_x -= xround(delx);
}
if (c->r_xbot > r->r_xbot) /* clip left */
{
dely = (dlong)(c->r_xbot - points[2].p_x) * height;
points[1].p_x = c->r_xbot;
points[2].p_x = c->r_xbot;
points[2].p_y += yround(dely);
}
if (c->r_ybot > points[2].p_y) /* clip bottom */
{
delx = (dlong)(c->r_ybot - points[2].p_y) * width;
points[2].p_y = c->r_ybot;
points[3].p_y = c->r_ybot;
points[3].p_x = points[2].p_x + xround(delx);
*np = 4;
if (c->r_xtop < points[3].p_x) /* clip right, rectangle */
{
points[3].p_x = c->r_xtop;
points[0].p_x = c->r_xtop;
}
else if (c->r_xtop < points[0].p_x) /* clip right, pentagon */
{
dely = (dlong)(points[0].p_x - c->r_xtop) * height;
points[0].p_x = c->r_xtop;
points[4].p_x = c->r_xtop;
points[4].p_y = points[0].p_y - yround(dely);
*np = 5;
}
}
else if (c->r_xtop < points[0].p_x) /* clip right, quadrangle */
{
dely = (dlong)(points[0].p_x - c->r_xtop) * height;
points[0].p_x = c->r_xtop;
points[3].p_x = c->r_xtop;
points[3].p_y = points[0].p_y - yround(dely);
*np = 4;
}
if (points[1].p_x > points[0].p_x || points[2].p_y > points[1].p_y)
*np = 0; /* clipped out of existence */
break;
case TT_DIAGONAL | TT_DIRECTION: /* sw */
if (c->r_xbot > r->r_xbot) /* clip LEFT */
{
dely = (dlong)(c->r_xbot - points[1].p_x) * height;
points[1].p_x = c->r_xbot;
points[0].p_x = c->r_xbot;
points[0].p_y -= yround(dely);
}
if (c->r_ybot > r->r_ybot) /* clip BOTTOM */
{
delx = (dlong)(c->r_ybot - points[2].p_y) * width;
points[1].p_y = c->r_ybot;
points[2].p_y = c->r_ybot;
points[2].p_x -= xround(delx);
}
if (c->r_xtop < points[2].p_x) /* clip RIGHT */
{
dely = (dlong)(points[2].p_x - c->r_xtop) * height;
points[2].p_x = c->r_xtop;
points[3].p_x = c->r_xtop;
points[3].p_y = points[1].p_y + yround(dely);
*np = 4;
if (c->r_ytop < points[3].p_y) /* clip TOP, rectangle */
{
points[3].p_y = c->r_ytop;
points[0].p_y = c->r_ytop;
}
else if (c->r_ytop < points[0].p_y) /* clip TOP, pentagon */
{
delx = (dlong)(points[0].p_y - c->r_ytop) * width;
points[0].p_y = c->r_ytop;
points[4].p_y = c->r_ytop;
points[4].p_x = points[0].p_x + xround(delx);
*np = 5;
}
}
else if (c->r_ytop < points[0].p_y) /* clip TOP, quadrangle */
{
delx = (dlong)(points[0].p_y - c->r_ytop) * width;
points[0].p_y = c->r_ytop;
points[3].p_y = c->r_ytop;
points[3].p_x = points[0].p_x + xround(delx);
*np = 4;
}
if (points[1].p_y > points[0].p_y || points[2].p_x < points[1].p_x)
*np = 0; /* clipped out of existence */
break;
case TT_DIAGONAL | TT_SIDE: /* se */
/* order: (bottom, right), (top, left) */
if (c->r_ybot > r->r_ybot) /* clip BOTTOM */
{
delx = (dlong)(c->r_ybot - points[1].p_y) * width;
points[1].p_y = c->r_ybot;
points[0].p_y = c->r_ybot;
points[0].p_x += xround(delx);
}
if (c->r_xtop < r->r_xtop) /* clip RIGHT */
{
dely = (dlong)(points[2].p_x - c->r_xtop) * height;
points[1].p_x = c->r_xtop;
points[2].p_x = c->r_xtop;
points[2].p_y -= yround(dely);
}
if (c->r_ytop < points[2].p_y) /* clip TOP */
{
delx = (dlong)(points[2].p_y - c->r_ytop) * width;
points[2].p_y = c->r_ytop;
points[3].p_y = c->r_ytop;
points[3].p_x = points[2].p_x - xround(delx);
*np = 4;
if (c->r_xbot > points[3].p_x) /* clip LEFT, rectangle */
{
points[3].p_x = c->r_xbot;
points[0].p_x = c->r_xbot;
}
else if (c->r_xbot > points[0].p_x) /* clip LEFT, pentagon */
{
dely = (dlong)(c->r_xbot - points[0].p_x) * height;
points[0].p_x = c->r_xbot;
points[4].p_x = c->r_xbot;
points[4].p_y = points[0].p_y + yround(dely);
*np = 5;
}
}
else if (c->r_xbot > points[0].p_x) /* clip LEFT, triangle */
{
dely = (dlong)(c->r_xbot - points[0].p_x) * height;
points[0].p_x = c->r_xbot;
points[3].p_x = c->r_xbot;
points[3].p_y = points[0].p_y + yround(dely);
*np = 4;
}
if (points[0].p_x > points[1].p_x || points[1].p_y > points[2].p_y)
*np = 0; /* clipped out of existence */
break;
case TT_DIAGONAL | TT_SIDE | TT_DIRECTION: /* ne */
/* order: (top, right), (bottom, left) */
if (c->r_xtop < r->r_xtop) /* clip RIGHT */
{
dely = (dlong)(points[1].p_x - c->r_xtop) * height;
points[1].p_x = c->r_xtop;
points[0].p_x = c->r_xtop;
points[0].p_y += yround(dely);
}
if (c->r_ytop < r->r_ytop) /* clip TOP */
{
delx = (dlong)(points[2].p_y - c->r_ytop) * width;
points[1].p_y = c->r_ytop;
points[2].p_y = c->r_ytop;
points[2].p_x += xround(delx);
}
if (c->r_xbot > points[2].p_x) /* clip LEFT */
{
dely = (dlong)(c->r_xbot - points[2].p_x) * height;
points[2].p_x = c->r_xbot;
points[3].p_x = c->r_xbot;
points[3].p_y = points[2].p_y - yround(dely);
*np = 4;
if (c->r_ybot >= points[3].p_y) /* clip BOTTOM, rectangle */
{
points[3].p_y = c->r_ybot;
points[0].p_y = c->r_ybot;
}
else if (c->r_ybot > points[0].p_y) /* clip BOTTOM, pentagon */
{
delx = (dlong)(c->r_ybot - points[0].p_y) * width;
points[0].p_y = c->r_ybot;
points[4].p_y = c->r_ybot;
points[4].p_x = points[0].p_x - xround(delx);
*np = 5;
}
}
else if (c->r_ybot > points[0].p_y) /* clip BOTTOM, quadrangle */
{
delx = (dlong)(c->r_ybot - points[0].p_y) * width;
points[0].p_y = c->r_ybot;
points[3].p_y = c->r_ybot;
points[3].p_x = points[0].p_x - xround(delx);
*np = 4;
}
if (points[1].p_y < points[0].p_y || points[2].p_x > points[1].p_x)
*np = 0; /* clipped out of existence */
break;
}
}
}
/*---------------------------------------------------------
* GrDrawTriangleEdge --
* Draws the diagonal line in a triangle clipped by
* grCurClip.
*
* Results:
* None.
*
* Side effects:
* Draws nonmanhattan layout geometry.
*
*---------------------------------------------------------
*/
void
GrDrawTriangleEdge(r, dinfo)
Rect *r; /* Bounding box of triangle, in screen coords */
TileType dinfo;
{
Point tpoints[5];
int tnum, i, j;
GrClipTriangle(r, &grCurClip, TRUE, dinfo, tpoints, &tnum);
for (i = 0; i < tnum; i++)
{
j = (i + 1) % tnum;
if (tpoints[i].p_x != tpoints[j].p_x &&
tpoints[i].p_y != tpoints[j].p_y)
{
GrClipLine(tpoints[i].p_x, tpoints[i].p_y,
tpoints[j].p_x, tpoints[j].p_y);
break;
}
}
}
/*---------------------------------------------------------
* GrDiagonal:
* GrDiagonal will draw a triangle on the screen in the
* style set by the previous call to GrSetStuff. It will also
* be clipped against the rectangles passed to GrSetStuff.
*
* If GrDiagonal is called between GrFastBox calls then GrSetStuff
* must be called to set the parameters back.
*
* Results:
* None.
*
* Side Effects:
* The rectangle is drawn in the style specified.
* The rectangle is clipped before being drawn.
*---------------------------------------------------------
*/
void
GrDiagonal(prect, dinfo)
Rect *prect; /* The rectangle to be drawn, given in
* screen coordinates.
*/
TileType dinfo; /* split and direction information */
{
Rect *r;
bool needClip, needObscure;
LinkedRect *ob;
int cp, np;
Rect clipr, fullr;
Point polyp[5];
GR_CHECK_LOCK();
if (!grDriverInformed) grInformDriver();
GrNumClipBoxes++;
if (grCurFill == GR_STGRID)
{
r = &grCurClip;
grGridRect = prect;
}
else
{
r = prect;
if (!GEO_TOUCH(r, &grCurClip)) return;
}
/* Do a quick check to make the (very common) special case of
* no clipping go fast.
*/
needClip = !GEO_SURROUND(&grCurClip, r);
needObscure = FALSE;
for (ob = grCurObscure; ob != NULL; ob = ob->r_next)
needObscure |= GEO_TOUCH(r, &(ob->r_r));
/* Generate points for the triangle and do clipping if necessary */
clipr = fullr = *r;
if (needClip)
GeoClip(&clipr, &grCurClip);
GrClipTriangle(&fullr, &clipr, needClip, dinfo, polyp, &np);
/* do solid areas */
if ( (grCurFill == GR_STSOLID) ||
(grCurFill == GR_STSTIPPLE) || (grCurFill == GR_STGRID) )
{
if (needObscure)
grObsBox(&clipr);
else if (grFillPolygonPtr)
(void) (*grFillPolygonPtr)(polyp, np);
}
/* return if rectangle is too small to see */
if ((r->r_xtop - r->r_xbot < GR_THRESH) &&
(r->r_ytop - r->r_ybot < GR_THRESH) && (grCurFill != GR_STOUTLINE))
return;
/* draw outlines */
if ( (grCurOutline != 0) && (grCurFill != GR_STGRID) )
{
/* TO DO: Check for boundary with shared tile type */
for (cp = 0; cp < np - 1; cp++)
(*grDrawLinePtr)(polyp[cp].p_x, polyp[cp].p_y,
polyp[cp + 1].p_x, polyp[cp + 1].p_y);
(*grDrawLinePtr)(polyp[cp].p_x, polyp[cp].p_y,
polyp[0].p_x, polyp[0].p_y);
}
}
/*---------------------------------------------------------
* GrFillPolygon --
* This routine is simply a call to the locally-defined
* grFillPolygonPtr routine.
*
*---------------------------------------------------------
*/
void
GrFillPolygon(polyp, np)
Point *polyp; /* Array of points defining polygon */
int np; /* number of points in array polyp */
{
if (grFillPolygonPtr != NULL)
{
(*grFillPolygonPtr)(polyp, np);
}
}
/*---------------------------------------------------------
* GrClipBox:
* GrClipBox will draw a rectangle on the screen in one
* of several possible styles, except that the rectangle will
* be clipped against a list of obscuring rectangles.
*
* Results: None.
*
* Side Effects:
* The rectangle is drawn in the style specified.
* The rectangle is clipped before being drawn.
*---------------------------------------------------------
*/
void
GrClipBox(prect, style)
Rect *prect; /* The rectangle to be drawn, given in
* screen coordinates.
*/
int style; /* The style to be used in drawing it. */
{
GrSetStuff(style);
GrFastBox(prect);
}
/*
* ----------------------------------------------------------------------------
* GrDisjoint --
*
* Clip a rectanglular area against a clipping box, applying the
* supplied procedure to each rectangular region in "area" which
* falls outside "clipbox". This works in pixel space, where a
* rectangle is contains its lower x- and y-coordinates AND ALSO
* its upper coordinates. This means that if the clipping box
* occupies a given pixel, the things being clipped must not occupy
* that pixel. This procedure will NOT work in tile space.
*
* The procedure should be of the form:
* bool func(box, cdarg)
* Rect * box;
* ClientData cdarg;
*
* Results:
* Return TRUE unless the supplied function returns FALSE.
*
* Side effects:
* The side effects of the invoked procedure.
* ----------------------------------------------------------------------------
*/
bool
GrDisjoint(area, clipBox, func, cdarg)
Rect * area;
Rect * clipBox;
bool (*func) ();
ClientData cdarg;
{
Rect ok, rArea;
bool result;
#define NULLBOX(R) ((R.r_xbot>R.r_xtop)||(R.r_ybot>R.r_ytop))
ASSERT((area!=(Rect *) NULL), "GrDisjoint");
if((clipBox==(Rect *) NULL)||(!GEO_TOUCH(area, clipBox)))
{
/* Since there is no overlap, all of "area" may be processed. */
result= (*func)(area, cdarg);
return(result);
}
/* Do the disjoint operation in four steps, one for each side
* of clipBox. In each step, divide the area being clipped
* into one piece that is DEFINITELY outside clipBox, and one
* piece left to check some more.
*/
/* Top edge of clipBox: */
rArea = *area;
result = TRUE;
if (clipBox->r_ytop < rArea.r_ytop)
{
ok = rArea;
ok.r_ybot = clipBox->r_ytop + 1;
rArea.r_ytop = clipBox->r_ytop;
if (!(*func)(&ok, cdarg)) result = FALSE;
}
/* Bottom edge of clipBox: */
if (clipBox->r_ybot > rArea.r_ybot)
{
ok = rArea;
ok.r_ytop = clipBox->r_ybot - 1;
rArea.r_ybot = clipBox->r_ybot;
if (!(*func)(&ok, cdarg)) result = FALSE;
}
/* Right edge of clipBox: */
if (clipBox->r_xtop < rArea.r_xtop)
{
ok = rArea;
ok.r_xbot = clipBox->r_xtop + 1;
rArea.r_xtop = clipBox->r_xtop;
if (!(*func)(&ok, cdarg)) result = FALSE;
}
/* Left edge of clipBox: */
if (clipBox->r_xbot > rArea.r_xbot)
{
ok = rArea;
ok.r_xtop = clipBox->r_xbot - 1;
rArea.r_xbot = clipBox->r_xbot;
if (!(*func)(&ok, cdarg)) result = FALSE;
}
/* Just throw away what's left of the area being clipped, since
* it overlaps the clipBox.
*/
return result;
} /*GrDisjoint*/