mirror of
https://github.com/ctm/executor.git
synced 2024-05-29 06:41:34 +00:00
1422 lines
35 KiB
C
1422 lines
35 KiB
C
/* Copyright 1986, 1988, 1989, 1990, 1995 by Abacus Research and
|
|
* Development, Inc. All rights reserved.
|
|
*/
|
|
|
|
#if !defined (OMIT_RCSID_STRINGS)
|
|
char ROMlib_rcsid_qRegion[] =
|
|
"$Id: qRegion.c 63 2004-12-24 18:19:43Z ctm $";
|
|
#endif
|
|
|
|
/* Forward declarations in QuickDraw.h (DO NOT DELETE THIS LINE) */
|
|
|
|
#include "rsys/common.h"
|
|
|
|
#include "QuickDraw.h"
|
|
#include "MemoryMgr.h"
|
|
|
|
#include "rsys/region.h"
|
|
#include "rsys/quick.h"
|
|
#include "rsys/cquick.h"
|
|
#include "rsys/mman.h"
|
|
#include "rsys/safe_alloca.h"
|
|
|
|
#undef ALLOCABEGIN
|
|
#define ALLOCABEGIN SAFE_DECL();
|
|
#undef ALLOCA
|
|
#define ALLOCA(n) SAFE_alloca(n)
|
|
|
|
#if !defined (NDEBUG)
|
|
|
|
#define RGN_SLAM(rgn) (ROMlib_sledgehammer_rgn (rgn))
|
|
|
|
static void
|
|
ROMlib_sledgehammer_rgn (RgnHandle rgn)
|
|
{
|
|
boolean_t special_rgn_p;
|
|
int16 size;
|
|
int x, y;
|
|
int16 *ip, *start_ip;
|
|
|
|
gui_assert (rgn);
|
|
|
|
if (RGN_SMALL_P (rgn))
|
|
return;
|
|
|
|
special_rgn_p = RGN_SPECIAL_P (rgn);
|
|
size = RGN_SIZE (rgn);
|
|
|
|
#if 0
|
|
/* the line drawing code is as slimy as can be, and creates a bogo
|
|
handle that points to `alloca'ed data */
|
|
gui_assert (size <= GetHandleSize ((Handle) rgn));
|
|
#endif
|
|
|
|
start_ip = ip = RGN_DATA (rgn);
|
|
|
|
/* #### verify that `y's are increasing also */
|
|
for (y = CW (*ip++); y != RGN_STOP; y = CW (*ip++))
|
|
{
|
|
/* #### verify that there are an even numbers of `x's */
|
|
if (special_rgn_p)
|
|
{
|
|
int32 prev_x = INT32_MIN;
|
|
|
|
for (x = *ip++; x != RGN_STOP; x = *ip++)
|
|
gui_assert (x > prev_x);
|
|
}
|
|
else
|
|
{
|
|
int32 prev_x = INT32_MIN;
|
|
|
|
for (x = CW (*ip++); x != RGN_STOP; x = CW (*ip++))
|
|
gui_assert (x > prev_x);
|
|
}
|
|
}
|
|
gui_assert (ip - start_ip == (size - 10) / (int) sizeof *ip);
|
|
}
|
|
|
|
#else
|
|
|
|
#define RGN_SLAM(rgn)
|
|
|
|
#endif
|
|
|
|
P0 (PUBLIC pascal trap, RgnHandle, NewRgn)
|
|
{
|
|
RgnHandle h;
|
|
|
|
h = (RgnHandle) NewHandleClear (RGN_SMALL_SIZE);
|
|
RGN_SET_SMALL (h);
|
|
return h;
|
|
}
|
|
|
|
P0(PUBLIC pascal trap, void, OpenRgn)
|
|
{
|
|
RgnHandle rh;
|
|
|
|
rh = (RgnHandle) NewHandleClear (RGN_SMALL_SIZE + sizeof (INTEGER));
|
|
|
|
RGN_SET_SIZE_AND_SPECIAL (rh, RGN_SMALL_SIZE + sizeof (INTEGER), FALSE);
|
|
/* sentinel */
|
|
(RGN_DATA (rh))[0] = RGN_STOP_X;
|
|
|
|
PORT_REGION_SAVE_X (thePort) = (Handle) RM (rh);
|
|
HidePen();
|
|
}
|
|
|
|
static boolean_t
|
|
rgn_is_rect_p (const RgnHandle rgnh)
|
|
{
|
|
const RgnPtr rgnp = STARH (rgnh);
|
|
const INTEGER *ip;
|
|
|
|
ip = RGNP_DATA (rgnp);
|
|
return (! RGNP_SPECIAL_P (rgnp)
|
|
&& RGNP_SIZE_X (rgnp) == CWC (RGN_SMALL_SIZE + 9 * sizeof *ip)
|
|
&& ip[1] == ip[5]
|
|
&& ip[2] == ip[6]);
|
|
}
|
|
|
|
/* ROMlib_sizergn: crawl through a region and set bbox and size fields */
|
|
|
|
void
|
|
ROMlib_sizergn (RgnHandle rh, boolean_t special_p) /* INTERNAL */
|
|
{
|
|
register INTEGER *ip, i, left = RGN_STOP, right = -RGN_STOP, y;
|
|
Size rs;
|
|
|
|
ip = RGN_DATA (rh);
|
|
RGN_BBOX (rh).top = *ip;
|
|
y = INT16_MIN;
|
|
if (special_p)
|
|
{
|
|
while (*ip != RGN_STOP_X)
|
|
{
|
|
y = CW (*ip++);
|
|
while ((i = *ip++) != RGN_STOP)
|
|
{
|
|
if (i < left) /* testing every element is a waste here */
|
|
left = i;
|
|
if (i > right) /* and here. */
|
|
right = i;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while (*ip != RGN_STOP_X)
|
|
{
|
|
y = CW (*ip++);
|
|
while ((i = CW (*ip++)) != RGN_STOP)
|
|
{
|
|
if (i < left) /* testing every element is a waste here */
|
|
left = i;
|
|
if (i > right) /* and here. */
|
|
right = i;
|
|
}
|
|
}
|
|
}
|
|
if (y == INT16_MIN)
|
|
{
|
|
SetHandleSize ((Handle) rh, RGN_SMALL_SIZE);
|
|
RGN_SET_SMALL (rh);
|
|
RECT_ZERO (&RGN_BBOX (rh));
|
|
}
|
|
else
|
|
{
|
|
rs = (char *) ++ip - (char *) STARH (rh);
|
|
RGN_SET_SIZE_AND_SPECIAL (rh, rs, FALSE);
|
|
if (rgn_is_rect_p (rh))
|
|
{
|
|
SetHandleSize ((Handle) rh, RGN_SMALL_SIZE);
|
|
RGN_SET_SMALL (rh);
|
|
}
|
|
else if (rs == RGN_SMALL_SIZE + sizeof (INTEGER))
|
|
{
|
|
SetHandleSize ((Handle) rh, RGN_SMALL_SIZE);
|
|
RGN_SET_SMALL (rh);
|
|
HASSIGN_1
|
|
(rh,
|
|
rgnBBox.top, CWC (0));
|
|
left = right = y = 0;
|
|
}
|
|
else
|
|
SetHandleSize ((Handle) rh, rs);
|
|
|
|
HASSIGN_3
|
|
(rh,
|
|
rgnBBox.left, CW (left),
|
|
rgnBBox.bottom, CW (y),
|
|
rgnBBox.right, CW (right));
|
|
}
|
|
}
|
|
|
|
P2 (PUBLIC pascal trap, void, CopyRgn, RgnHandle, s, RgnHandle, d)
|
|
{
|
|
Size size;
|
|
|
|
if (s == d)
|
|
return;
|
|
size = RGN_SIZE (s);
|
|
ReallocHandle((Handle) d, size);
|
|
memcpy ((Ptr) STARH (d), (Ptr) STARH (s), size);
|
|
}
|
|
|
|
P1(PUBLIC pascal trap, void, CloseRgn, RgnHandle, rh)
|
|
{
|
|
RgnHandle rgn_save = (RgnHandle) PORT_REGION_SAVE (thePort);
|
|
|
|
if (RGN_SIZE_X (rgn_save) == CWC (RGN_SMALL_SIZE + sizeof (INTEGER))
|
|
|| rgn_is_rect_p (rgn_save))
|
|
RGN_SET_SMALL (rgn_save);
|
|
|
|
ROMlib_installhandle (PORT_REGION_SAVE (thePort), (Handle) rh);
|
|
SetHandleSize ((Handle) rh, RGN_SIZE (rh));
|
|
PORT_REGION_SAVE_X (thePort) = RM (NULL);
|
|
ShowPen ();
|
|
}
|
|
|
|
P1 (PUBLIC pascal trap, void, DisposeRgn, RgnHandle, rh)
|
|
{
|
|
DisposHandle ((Handle) rh);
|
|
}
|
|
|
|
P1 (PUBLIC pascal trap, void, SetEmptyRgn, RgnHandle, rh)
|
|
{
|
|
SetHandleSize ((Handle) rh, RGN_SMALL_SIZE);
|
|
RGN_SET_SMALL (rh);
|
|
RECT_ZERO (&RGN_BBOX (rh));
|
|
}
|
|
|
|
P5 (PUBLIC pascal trap, void, SetRectRgn, RgnHandle, rh, INTEGER, left,
|
|
INTEGER, top, INTEGER, right, INTEGER, bottom)
|
|
{
|
|
SetHandleSize ((Handle) rh, RGN_SMALL_SIZE);
|
|
SetRect (&RGN_BBOX (rh), left, top, right, bottom);
|
|
RGN_SET_SMALL (rh);
|
|
}
|
|
|
|
P2 (PUBLIC pascal trap, void, RectRgn, RgnHandle, rh, Rect *, rect)
|
|
{
|
|
Rect r;
|
|
|
|
/* suck the rect into a local before we do the `SetHandleSize ()'
|
|
because `rect' may point into an unlocked handle (that shouldn't
|
|
actually ever happen, but it is better to be safe than sorry) */
|
|
r = *rect;
|
|
SetHandleSize ((Handle) rh, RGN_SMALL_SIZE);
|
|
RGN_SET_SMALL (rh);
|
|
RGN_BBOX (rh) = r;
|
|
}
|
|
|
|
/* IM is wrong... not based on offsets */
|
|
P3 (PUBLIC pascal trap, void, OffsetRgn, RgnHandle, rh,
|
|
INTEGER, dh, INTEGER, dv)
|
|
{
|
|
if (dh || dv)
|
|
{
|
|
INTEGER *ip, *ep;
|
|
RgnPtr rp;
|
|
|
|
rp = STARH (rh);
|
|
OffsetRect (&RGNP_BBOX (rp), dh, dv);
|
|
for (ip = RGNP_DATA (rp),
|
|
ep = (INTEGER *) ((char *) ip + RGNP_SIZE (rp)) - 6;
|
|
ip < ep; ip++)
|
|
{
|
|
*ip = CW (CW (*ip) + (dv));
|
|
++ip;
|
|
do
|
|
{
|
|
*ip = CW (CW (*ip) + (dh));
|
|
++ip;
|
|
*ip = CW (CW (*ip) + (dh));
|
|
++ip;
|
|
}
|
|
while (*ip != RGN_STOP_X);
|
|
}
|
|
}
|
|
}
|
|
|
|
#define NHPAIR 1024
|
|
|
|
P2 (PUBLIC pascal trap, BOOLEAN, PtInRgn, Point, p, RgnHandle, rh)
|
|
{
|
|
if (!PtInRect (p, &RGN_BBOX (rh)))
|
|
return FALSE;
|
|
if (RGN_SMALL_P (rh))
|
|
return TRUE;
|
|
else
|
|
{
|
|
INTEGER *ipe, *op;
|
|
INTEGER *ipr;
|
|
INTEGER v, in;
|
|
/* double buffered (really [2][NHPAIR]) */
|
|
INTEGER endpoints[2 * NHPAIR];
|
|
|
|
ipr = RGN_DATA (rh);
|
|
*endpoints = RGN_STOP;
|
|
ipe = endpoints;
|
|
op = endpoints + NHPAIR;
|
|
while ((v = CW (*ipr++)) != RGN_STOP)
|
|
{
|
|
if (v > p.v)
|
|
{
|
|
in = FALSE;
|
|
for (op = ipe; *op++ <= p.h; in = !in)
|
|
;
|
|
return in;
|
|
}
|
|
while (*ipr != RGN_STOP_X || *ipe != RGN_STOP)
|
|
{
|
|
if (CW (*ipr) < *ipe)
|
|
*op++ = CW (*ipr++);
|
|
else if (*ipe < CW (*ipr))
|
|
*op++ = *ipe++;
|
|
else
|
|
{
|
|
ipr++;
|
|
ipe++;
|
|
}
|
|
}
|
|
ipr++;
|
|
ipe++;
|
|
*op = RGN_STOP;
|
|
if (op >= endpoints + NHPAIR)
|
|
{
|
|
ipe = endpoints + NHPAIR;
|
|
op = endpoints;
|
|
}
|
|
else
|
|
{
|
|
ipe = endpoints;
|
|
op = endpoints + NHPAIR;
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* NOTE: ipr points to native memory and hence has to have dereferences
|
|
* swapped. Neither mergebuf, nor freebuf have this requirement.
|
|
*/
|
|
|
|
#define merge(ipr, mergebuf, freebuf) \
|
|
{ \
|
|
INTEGER *ipe, *op; \
|
|
\
|
|
ipe = mergebuf; \
|
|
op = freebuf; \
|
|
while (*ipr != RGN_STOP_X || *ipe != RGN_STOP) \
|
|
{ \
|
|
if (CW (*ipr) < *ipe) \
|
|
*op++ = CW (*ipr++); \
|
|
else if (*ipe < CW (*ipr)) \
|
|
*op++ = *ipe++; \
|
|
else \
|
|
{ \
|
|
ipr++; \
|
|
ipe++; \
|
|
} \
|
|
} \
|
|
ipr++; \
|
|
ipe++; \
|
|
*op++ = RGN_STOP; \
|
|
*op = RGN_STOP; \
|
|
op = freebuf; \
|
|
freebuf = mergebuf; \
|
|
mergebuf = op; \
|
|
\
|
|
/* if (mergebuf[0] == mergebuf[1] && mergebuf[0] != RGN_STOP) \
|
|
printf("m[0] = %d, m[1] = %d, f[0] = %d, f[1] = %d\n", \
|
|
mergebuf[0], mergebuf[1], freebuf[0], freebuf[1]); */ \
|
|
}
|
|
|
|
#define nextline(ipr, mergebuf) \
|
|
{ \
|
|
mergebuf = ipr; \
|
|
while (*ipr++ != RGN_STOP) \
|
|
; \
|
|
}
|
|
|
|
/*
|
|
* NOTE: I *think* outputrgn has inputs in native space, but should
|
|
* output to synthetic space.
|
|
*/
|
|
|
|
#define outputrgn(vx, cur, new, out) \
|
|
{ \
|
|
INTEGER *ipe, *ipr; \
|
|
LONGINT hold; \
|
|
\
|
|
ipe = cur; \
|
|
ipr = new; \
|
|
*out++ = CW (vx); \
|
|
hold = (LONGINT) (long) out; \
|
|
while (*ipr != RGN_STOP || *ipe != RGN_STOP) \
|
|
{ \
|
|
if (*ipr < *ipe) \
|
|
*out++ = CW (*ipr++); \
|
|
else if (*ipe < *ipr) \
|
|
*out++ = CW (*ipe++); \
|
|
else \
|
|
{ \
|
|
ipr++; \
|
|
ipe++; \
|
|
} \
|
|
} \
|
|
if (hold == (LONGINT) (long) out) \
|
|
--out; \
|
|
else \
|
|
{ \
|
|
*out++ = CW (RGN_STOP); \
|
|
} \
|
|
ipe = cur; \
|
|
cur = new; \
|
|
new = ipe; \
|
|
}
|
|
|
|
#define newsource { sstart = *sp1++; sstop = *sp1++; }
|
|
#define newdest { dstart = *sp2++; dstop = *sp2++; }
|
|
#define includ(start, stop, outp) { *outp++ = start; *outp++ = stop; }
|
|
|
|
#define sect(src1, src2, outptr) \
|
|
{ \
|
|
INTEGER sstart, dstart, sstop, dstop; \
|
|
INTEGER *sp1, *sp2, *outp; \
|
|
\
|
|
sp1 = src1; \
|
|
sp2 = src2; \
|
|
outp = outptr; \
|
|
newsource \
|
|
newdest \
|
|
while (sstart != RGN_STOP && dstart != RGN_STOP) \
|
|
if (sstop <= dstart) \
|
|
newsource \
|
|
else if (dstop <= sstart) \
|
|
newdest \
|
|
else if (sstart <= dstart) { \
|
|
if (sstop < dstop) { \
|
|
includ(dstart, sstop, outp) \
|
|
dstart = sstop; \
|
|
newsource \
|
|
} else { \
|
|
includ(dstart, dstop, outp) \
|
|
sstart = dstop; \
|
|
newdest \
|
|
} \
|
|
} else { \
|
|
if (dstop < sstop) { \
|
|
includ(sstart, dstop, outp) \
|
|
sstart = dstop; \
|
|
newdest \
|
|
} else { \
|
|
includ(sstart, sstop, outp) \
|
|
dstart = sstop; \
|
|
newsource \
|
|
} \
|
|
} \
|
|
*outp = RGN_STOP; \
|
|
}
|
|
|
|
/*
|
|
* NOTE: here we're creating a "special" region that is really a set
|
|
* of start stop pairs that are in native endianness.
|
|
*/
|
|
|
|
#define sectline(src1, src2, outp, y) \
|
|
{ \
|
|
INTEGER sstart, dstart, sstop, dstop; \
|
|
INTEGER *sp1, *sp2, *outptr; \
|
|
\
|
|
sp1 = src1; \
|
|
sp2 = src2; \
|
|
newsource \
|
|
newdest \
|
|
*outp++ = CW(y); \
|
|
outptr = outp; \
|
|
while (sstart != RGN_STOP && dstart != RGN_STOP) { \
|
|
if (sstop <= dstart) \
|
|
newsource \
|
|
else if (dstop <= sstart) \
|
|
newdest \
|
|
else if (sstart <= dstart) { \
|
|
if (sstop < dstop) { \
|
|
includ(dstart, sstop, outp) \
|
|
dstart = sstop; \
|
|
newsource \
|
|
} else { \
|
|
includ(dstart, dstop, outp) \
|
|
sstart = dstop; \
|
|
newdest \
|
|
} \
|
|
} else { \
|
|
if (dstop < sstop) { \
|
|
includ(sstart, dstop, outp) \
|
|
sstart = dstop; \
|
|
newdest \
|
|
} else { \
|
|
includ(sstart, sstop, outp) \
|
|
dstart = sstop; \
|
|
newsource \
|
|
} \
|
|
} \
|
|
} \
|
|
if (wehavepairs || outp > outptr) { \
|
|
*outp++ = RGN_STOP; \
|
|
wehavepairs = TRUE; \
|
|
} else { \
|
|
outp--; \
|
|
wehavepairs = FALSE; \
|
|
} \
|
|
}
|
|
|
|
#define uunion(src1, src2, outptr) \
|
|
{ \
|
|
INTEGER sstart, dstart, sstop, dstop; \
|
|
INTEGER *sp1, *sp2, *outp; \
|
|
\
|
|
sp1 = src1; \
|
|
sp2 = src2; \
|
|
outp = outptr; \
|
|
newsource \
|
|
newdest \
|
|
while (sstart != RGN_STOP || dstart != RGN_STOP) \
|
|
if (sstart <= dstart) { \
|
|
if (sstop < dstart) { \
|
|
includ(sstart, sstop, outp) \
|
|
newsource \
|
|
} else if (sstop <= dstop) { \
|
|
dstart = sstart; \
|
|
newsource \
|
|
} else \
|
|
newdest \
|
|
} else { \
|
|
if (dstop < sstart) { \
|
|
includ(dstart, dstop, outp) \
|
|
newdest \
|
|
} else if (dstop <= sstop) { \
|
|
sstart = dstart; \
|
|
newdest \
|
|
} else \
|
|
newsource \
|
|
} \
|
|
*outp = RGN_STOP; \
|
|
}
|
|
|
|
#define diff(src1, src2, outptr) \
|
|
{ \
|
|
INTEGER sstart, dstart, sstop, dstop; \
|
|
INTEGER *sp1, *sp2, *outp; \
|
|
\
|
|
sp1 = src1; \
|
|
sp2 = src2; \
|
|
outp = outptr; \
|
|
newsource \
|
|
newdest \
|
|
while (sstart != RGN_STOP || dstart != RGN_STOP) { \
|
|
if (sstop <= dstart) { \
|
|
includ(sstart, sstop, outp) \
|
|
newsource \
|
|
} else if (dstop <= sstart) \
|
|
newdest \
|
|
else { \
|
|
if (sstart < dstart) \
|
|
includ(sstart, dstart, outp) \
|
|
if (sstop < dstop) \
|
|
newsource \
|
|
else if (sstop == dstop) { \
|
|
newsource \
|
|
newdest \
|
|
} else { \
|
|
sstart = dstop; \
|
|
newdest \
|
|
} \
|
|
} \
|
|
} \
|
|
*outp = RGN_STOP; \
|
|
}
|
|
|
|
#if !defined (NDEBUG)
|
|
A1(PRIVATE, void, assertincreasing, INTEGER *, ip)
|
|
{
|
|
LONGINT lastx = -327680;
|
|
while (*ip != RGN_STOP) {
|
|
gui_assert(lastx < *ip);
|
|
lastx = *ip++;
|
|
}
|
|
}
|
|
#endif /* NDEBUG */
|
|
|
|
A3(PRIVATE, void, sectbinop, RgnHandle, srcrgn1, RgnHandle, srcrgn2,
|
|
RgnHandle, dstrgn)
|
|
{
|
|
/* note that the buffers will not be restricted to the endpoints
|
|
that their name implies. The pointers will always point to
|
|
the buffer containing the most current set of endpoints */
|
|
|
|
INTEGER src1endpoints[NHPAIR], *src1ep = src1endpoints;
|
|
INTEGER src2endpoints[NHPAIR], *src2ep = src2endpoints;
|
|
INTEGER sectsegendpoints[NHPAIR], *sectsegep = sectsegendpoints;
|
|
INTEGER sectcurendpoints[NHPAIR], *sectcurep = sectcurendpoints;
|
|
INTEGER freeendpoints[NHPAIR], *freeep = freeendpoints;
|
|
INTEGER *ipr1, *ipr2;
|
|
INTEGER *temppoints, *tptr;
|
|
register INTEGER v1, v2, vx;
|
|
INTEGER r1[9], r2[9];
|
|
Rect *rp;
|
|
INTEGER nspecial;
|
|
RgnHandle exchrgn;
|
|
BOOLEAN wehavepairs;
|
|
ALLOCABEGIN
|
|
|
|
/*
|
|
* Some performance enhancements could be put here...
|
|
* if we are secting and the rgnBox's don't sect ... etc.
|
|
*/
|
|
if (RGN_SPECIAL_P (srcrgn1)) {
|
|
if (RGN_SPECIAL_P (srcrgn2))
|
|
nspecial = 2;
|
|
else
|
|
nspecial = 1;
|
|
} else {
|
|
if (RGN_SPECIAL_P (srcrgn2)) {
|
|
nspecial = 1;
|
|
exchrgn = srcrgn1;
|
|
srcrgn1 = srcrgn2;
|
|
srcrgn2 = exchrgn;
|
|
} else
|
|
nspecial = 0;
|
|
}
|
|
tptr = temppoints = ((INTEGER *)
|
|
ALLOCA (2 * ((RGN_SIZE (srcrgn1))
|
|
+ RGN_SIZE (srcrgn2)
|
|
+ 18 * sizeof (INTEGER))));
|
|
/* todo ... look over these */
|
|
if (RGN_SMALL_P (srcrgn1)) {
|
|
rp = &RGN_BBOX (srcrgn1);
|
|
r1[0] = rp->top;
|
|
r1[1] = rp->left;
|
|
r1[2] = rp->right != RGN_STOP_X ? rp->right : CWC(RGN_STOP - 1);
|
|
r1[3] = RGN_STOP_X;
|
|
r1[4] = rp->bottom != RGN_STOP_X ? rp->bottom : CWC(RGN_STOP - 1);
|
|
r1[5] = rp->left;
|
|
r1[6] = rp->right != RGN_STOP_X ? rp->right : CWC(RGN_STOP - 1);
|
|
r1[7] = RGN_STOP_X;
|
|
r1[8] = RGN_STOP_X;
|
|
ipr1 = r1;
|
|
} else
|
|
ipr1 = RGN_DATA (srcrgn1);
|
|
if (RGN_SMALL_P (srcrgn2)) {
|
|
rp = &RGN_BBOX (srcrgn2);
|
|
r2[0] = rp->top;
|
|
r2[1] = rp->left;
|
|
r2[2] = rp->right != RGN_STOP_X ? rp->right : CWC(RGN_STOP - 1);
|
|
r2[3] = RGN_STOP_X;
|
|
r2[4] = rp->bottom != RGN_STOP_X ? rp->bottom : CWC(RGN_STOP - 1);
|
|
r2[5] = rp->left;
|
|
r2[6] = rp->right != RGN_STOP_X ? rp->right : CWC(RGN_STOP - 1);
|
|
r2[7] = RGN_STOP_X;
|
|
r2[8] = RGN_STOP_X;
|
|
ipr2 = r2;
|
|
} else
|
|
ipr2 = RGN_DATA (srcrgn2);
|
|
*src1ep = *src2ep = *sectsegep = *sectcurep = *freeep =
|
|
*(src1ep+1) = *(src2ep+1) = RGN_STOP;
|
|
|
|
v1 = CW(*ipr1++);
|
|
v2 = CW(*ipr2++);
|
|
wehavepairs = FALSE; /* whether or not scan lines have stuff */
|
|
switch (nspecial) {
|
|
case 0:
|
|
while (v1 != RGN_STOP && v2 != RGN_STOP) {
|
|
if (v1 < v2) {
|
|
merge(ipr1, src1ep, freeep) /* no semi ... macro */
|
|
vx = v1;
|
|
v1 = CW(*ipr1++);
|
|
} else if (v2 < v1) {
|
|
merge(ipr2, src2ep, freeep)
|
|
vx = v2;
|
|
v2 = CW(*ipr2++);
|
|
} else { /* equal */
|
|
merge(ipr1, src1ep, freeep)
|
|
merge(ipr2, src2ep, freeep)
|
|
vx = v1;
|
|
v1 = CW(*ipr1++);
|
|
v2 = CW(*ipr2++);
|
|
}
|
|
sect(src1ep, src2ep, sectsegep)
|
|
outputrgn(vx, sectcurep, sectsegep, tptr);
|
|
}
|
|
break;
|
|
case 1:
|
|
vx = -32768;
|
|
while (v1 != RGN_STOP && v2 != RGN_STOP) {
|
|
if (v1 < v2) {
|
|
nextline(ipr1, src1ep) /* no semi ... macro */
|
|
vx = v1;
|
|
v1 = CW(*ipr1++);
|
|
} else if (v2 < v1) {
|
|
merge(ipr2, src2ep, freeep)
|
|
vx = v2;
|
|
v2 = CW(*ipr2++);
|
|
} else { /* equal */
|
|
nextline(ipr1, src1ep)
|
|
merge(ipr2, src2ep, freeep)
|
|
vx = v1;
|
|
v1 = CW(*ipr1++);
|
|
v2 = CW(*ipr2++);
|
|
}
|
|
#if !defined (NDEBUG)
|
|
assertincreasing(src1ep);
|
|
assertincreasing(src2ep);
|
|
#endif /* NDEBUG */
|
|
sectline(src1ep, src2ep, tptr, vx)
|
|
}
|
|
break;
|
|
case 2:
|
|
vx = -32768;
|
|
while (v1 != RGN_STOP && v2 != RGN_STOP) {
|
|
if (v1 < v2) {
|
|
nextline(ipr1, src1ep) /* no semi ... macro */
|
|
vx = v1;
|
|
v1 = CW(*ipr1++);
|
|
} else if (v2 < v1) {
|
|
nextline(ipr2, src2ep)
|
|
vx = v2;
|
|
v2 = CW(*ipr2++);
|
|
} else { /* equal */
|
|
nextline(ipr1, src1ep)
|
|
nextline(ipr2, src2ep)
|
|
vx = v1;
|
|
v1 = CW(*ipr1++);
|
|
v2 = CW(*ipr2++);
|
|
}
|
|
sectline(src1ep, src2ep, tptr, vx)
|
|
}
|
|
*tptr++ = vx;
|
|
*tptr++ = RGN_STOP;
|
|
break;
|
|
}
|
|
*tptr++ = RGN_STOP_X;
|
|
gui_assert(sizeof(INTEGER) * (tptr - temppoints) <=
|
|
2 * ((Hx(srcrgn1, rgnSize)&0x7FFF) + (Hx(srcrgn2, rgnSize) & 0x7FFF) +
|
|
18 * sizeof(INTEGER)));
|
|
|
|
{
|
|
int dst_rgn_size = (RGN_SMALL_SIZE
|
|
+ sizeof(INTEGER) * (tptr - temppoints));
|
|
RGN_SET_SIZE_AND_SPECIAL (dstrgn, dst_rgn_size, FALSE);
|
|
/* TODO fix rgnBBox here */
|
|
ReallocHandle ((Handle) dstrgn, dst_rgn_size);
|
|
}
|
|
|
|
memmove (RGN_DATA (dstrgn), temppoints,
|
|
(tptr - temppoints) * sizeof *temppoints);
|
|
ROMlib_sizergn (dstrgn, nspecial > 0); /* could do this while copying... */
|
|
if (nspecial > 0)
|
|
RGN_SET_SPECIAL (dstrgn, TRUE);
|
|
ASSERT_SAFE (temppoints);
|
|
ALLOCAEND
|
|
}
|
|
|
|
typedef enum { sectop, unionop, diffop } optype;
|
|
|
|
A4(PRIVATE, void, binop, optype, op, RgnHandle, srcrgn1, RgnHandle, srcrgn2,
|
|
RgnHandle, dstrgn)
|
|
{
|
|
/* note that the buffers will not be restricted to the endpoints
|
|
that their name implies. The pointers will always point to
|
|
the buffer containing the most current set of endpoints */
|
|
|
|
INTEGER src1endpoints[NHPAIR], *src1ep = src1endpoints;
|
|
INTEGER src2endpoints[NHPAIR], *src2ep = src2endpoints;
|
|
INTEGER sectsegendpoints[NHPAIR], *sectsegep = sectsegendpoints;
|
|
INTEGER sectcurendpoints[NHPAIR], *sectcurep = sectcurendpoints;
|
|
INTEGER freeendpoints[NHPAIR], *freeep = freeendpoints;
|
|
INTEGER *ipr1, *ipr2;
|
|
INTEGER *temppoints, *tptr;
|
|
register INTEGER v1, v2, vx;
|
|
INTEGER r1[9], r2[9];
|
|
Rect *rp;
|
|
ALLOCABEGIN
|
|
|
|
/*
|
|
* Some performance enhancements could be put here...
|
|
* if we are secting and the rgnBox's don't sect ... etc.
|
|
*/
|
|
tptr = temppoints = (INTEGER *) ALLOCA((Size)2 * (Hx(srcrgn1, rgnSize) +
|
|
Hx(srcrgn2, rgnSize) + 18 * sizeof(INTEGER)));
|
|
/* todo ... look over these */
|
|
if (RGN_SMALL_P (srcrgn1)) {
|
|
rp = &(RGN_BBOX (srcrgn1));
|
|
r1[0] = rp->top;
|
|
r1[1] = rp->left;
|
|
r1[2] = rp->right != RGN_STOP_X ? rp->right : CW(RGN_STOP - 1);
|
|
r1[3] = RGN_STOP_X;
|
|
r1[4] = rp->bottom != RGN_STOP_X ? rp->bottom : CW(RGN_STOP - 1);
|
|
r1[5] = rp->left;
|
|
r1[6] = rp->right != RGN_STOP_X ? rp->right : CW(RGN_STOP - 1);
|
|
r1[7] = RGN_STOP_X;
|
|
r1[8] = RGN_STOP_X;
|
|
ipr1 = r1;
|
|
} else
|
|
ipr1 = RGN_DATA (srcrgn1);
|
|
if (RGN_SMALL_P (srcrgn2)) {
|
|
rp = &(RGN_BBOX (srcrgn2));
|
|
r2[0] = rp->top;
|
|
r2[1] = rp->left;
|
|
r2[2] = rp->right != RGN_STOP ? rp->right : CW(RGN_STOP - 1);
|
|
r2[3] = RGN_STOP_X;
|
|
r2[4] = rp->bottom != RGN_STOP ? rp->bottom : CW(RGN_STOP - 1);
|
|
r2[5] = rp->left;
|
|
r2[6] = rp->right != RGN_STOP ? rp->right : CW(RGN_STOP - 1);
|
|
r2[7] = RGN_STOP_X;
|
|
r2[8] = RGN_STOP_X;
|
|
ipr2 = r2;
|
|
} else
|
|
ipr2 = RGN_DATA (srcrgn2);
|
|
*src1ep = *src2ep = *sectsegep = *sectcurep = *freeep =
|
|
*(src1ep+1) = *(src2ep+1) = RGN_STOP;
|
|
|
|
v1 = CW(*ipr1++);
|
|
v2 = CW(*ipr2++);
|
|
while (v1 != RGN_STOP || v2 != RGN_STOP) {
|
|
if (v1 < v2) {
|
|
merge(ipr1, src1ep, freeep) /* no semi ... macro */
|
|
vx = v1;
|
|
v1 = CW(*ipr1++);
|
|
} else if (v2 < v1) {
|
|
merge(ipr2, src2ep, freeep)
|
|
vx = v2;
|
|
v2 = CW(*ipr2++);
|
|
} else { /* equal */
|
|
merge(ipr1, src1ep, freeep)
|
|
merge(ipr2, src2ep, freeep)
|
|
vx = v1;
|
|
v1 = CW(*ipr1++);
|
|
v2 = CW(*ipr2++);
|
|
}
|
|
switch (op) {
|
|
case sectop:
|
|
sect(src1ep, src2ep, sectsegep)
|
|
break;
|
|
case diffop:
|
|
diff(src1ep, src2ep, sectsegep)
|
|
break;
|
|
case unionop:
|
|
uunion(src1ep, src2ep, sectsegep)
|
|
break;
|
|
}
|
|
outputrgn(vx, sectcurep, sectsegep, tptr);
|
|
}
|
|
*tptr++ = RGN_STOP_X;
|
|
gui_assert(sizeof(INTEGER) * (tptr - temppoints) <=
|
|
2 * (Hx(srcrgn1, rgnSize) + Hx(srcrgn2, rgnSize) + 18 * sizeof(INTEGER)));
|
|
HxX(dstrgn, rgnSize) = CW(RGN_SMALL_SIZE + sizeof(INTEGER) * (tptr - temppoints));
|
|
/* TODO fix rgnBBox here */
|
|
ReallocHandle((Handle) dstrgn,
|
|
RGN_SMALL_SIZE + sizeof(INTEGER) * (tptr - temppoints));
|
|
{ register INTEGER *ip, *op;
|
|
ip = temppoints;
|
|
op = (INTEGER *) STARH(dstrgn) + 5;
|
|
while (ip != tptr)
|
|
*op++ = *ip++;
|
|
ROMlib_sizergn(dstrgn, FALSE); /* could do this while copying... */
|
|
}
|
|
ASSERT_SAFE (temppoints);
|
|
ALLOCAEND
|
|
}
|
|
|
|
|
|
void
|
|
nonspecial_rgn_to_special_rgn (const INTEGER *src, INTEGER *dst)
|
|
{
|
|
static const INTEGER empty_row[2] = { 0, RGN_STOP };
|
|
const INTEGER *prev;
|
|
|
|
/* Each scanline gets XOR'd with the previous one. We proceed until we
|
|
* hit a RGN_STOP_X y value.
|
|
*/
|
|
for (prev = empty_row; (dst[0] = src[0]) != RGN_STOP_X; )
|
|
{
|
|
int srcx, prevx;
|
|
INTEGER *next_prev;
|
|
|
|
/* Fetch the first X on this new scanline. */
|
|
srcx = CW (src[1]);
|
|
if (srcx == RGN_STOP)
|
|
{
|
|
/* The row with which to XOR is empty, so just extend the
|
|
* current row.
|
|
*/
|
|
src += 2;
|
|
continue;
|
|
}
|
|
|
|
next_prev = dst;
|
|
|
|
/* Fetch the first X on the previous scanline. If the previous
|
|
* scanline was empty, then XORing just gives us the scanline
|
|
* from src.
|
|
*/
|
|
prevx = prev[1];
|
|
if (prevx == RGN_STOP)
|
|
{
|
|
for (; (dst[1] = CW (src[1])) != RGN_STOP; src += 2, dst += 2)
|
|
dst[2] = CW (src[2]);
|
|
src += 2;
|
|
dst += 2;
|
|
prev = next_prev;
|
|
continue;
|
|
}
|
|
|
|
/* Neither scanline is empty. This is the tricky case. Since
|
|
* we are XORing two scanlines of start/stop X pairs, we just
|
|
* merge the two lists of X coordinates into one sorted array.
|
|
* If you draw two scanlines, one above the other, you'll see
|
|
* that all of the X coordinates just "drop down" to the
|
|
* resulting scanline. The only exception is when both
|
|
* scanlines have the same X value; in that case, it
|
|
* "disappears".
|
|
*/
|
|
src += 2;
|
|
prev += 2;
|
|
dst++;
|
|
|
|
while (1)
|
|
{
|
|
if (srcx < prevx)
|
|
{
|
|
*dst++ = srcx;
|
|
srcx = CW (*src++);
|
|
if (srcx == RGN_STOP)
|
|
goto read_prev_only;
|
|
}
|
|
else if (srcx > prevx)
|
|
{
|
|
*dst++ = prevx;
|
|
prevx = *prev++;
|
|
if (prevx == RGN_STOP)
|
|
goto read_src_only;
|
|
}
|
|
else /* srcx == prevx */
|
|
{
|
|
srcx = CW (*src++);
|
|
prevx = *prev++;
|
|
if (srcx == RGN_STOP)
|
|
goto read_prev_only;
|
|
if (prevx == RGN_STOP)
|
|
goto read_src_only;
|
|
}
|
|
}
|
|
|
|
/* We've run out of data from "src", so just copy the rest of the
|
|
* prev scanline.
|
|
*/
|
|
read_prev_only:
|
|
while (prevx != RGN_STOP)
|
|
{
|
|
*dst++ = prevx;
|
|
prevx = *prev++;
|
|
}
|
|
goto do_next;
|
|
|
|
/* We've run out of data from "prev", so just copy the rest of the
|
|
* src scanline.
|
|
*/
|
|
read_src_only:
|
|
while (srcx != RGN_STOP)
|
|
{
|
|
*dst++ = srcx;
|
|
srcx = CW (*src++);
|
|
}
|
|
|
|
do_next:
|
|
*dst++ = RGN_STOP;
|
|
prev = next_prev;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Here's how the little bugger works:
|
|
* Three macros are needed to be defined so that some boilerplate
|
|
* can expand into rhtopandinseth and inseth
|
|
* the pairs will always be kept as (y, x) so there need to be
|
|
* two different NEXTPAIR routines and comparison routines...
|
|
*/
|
|
|
|
static INTEGER npairs;
|
|
|
|
#define DECL void rhtopandinseth(RgnHandle rh, INTEGER *p, register INTEGER dh)
|
|
|
|
#define STATEDECL SignedByte state;
|
|
#define SETIO ip = &HxX(rh, rgnSize) + 5; op = p; y = CW(*ip++); npairs = 0; \
|
|
state = HGetState((Handle) rh); \
|
|
HLock((Handle) rh)
|
|
#define NEXTPAIR (x = CW(*ip++)) == RGN_STOP ? (y = CW(*ip++), 0) : 1
|
|
#define INCLXY(x, y) *op++ = y, *op++ = x, npairs++
|
|
#define UNSETIO HSetState((Handle) rh, state); INCLXY(RGN_STOP, RGN_STOP)
|
|
|
|
#include "hintemplate.h"
|
|
|
|
#define DECL void hinset(INTEGER *p, INTEGER dh)
|
|
|
|
#define STATEDECL
|
|
#define SETIO ip = p; op = p; y = *(ip+1); npairs = 0
|
|
#define NEXTPAIR y == *(ip+1) ? (x = *ip++, ip++, 1) : (y = *(ip+1), 0)
|
|
#define INCLXY(x, y) *op++ = x, *op++ = y, npairs++
|
|
#define UNSETIO
|
|
|
|
#include "hintemplate.h"
|
|
|
|
A2(PRIVATE, LONGINT, comparex, char *, cp1, char *, cp2)
|
|
{
|
|
register INTEGER *p1, *p2;
|
|
LONGINT retval;
|
|
|
|
p1 = (INTEGER *) cp1 + 1;
|
|
p2 = (INTEGER *) cp2 + 1;
|
|
if (*p1 < *p2)
|
|
retval = -1;
|
|
else if (*p1 > *p2)
|
|
retval = 1;
|
|
else {
|
|
p1--;
|
|
p2--;
|
|
if (*p1 < *p2)
|
|
retval = -1;
|
|
else if (*p1 > *p2)
|
|
retval = 1;
|
|
else
|
|
retval = 0;
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
A2(PRIVATE, LONGINT, comparey, char *, cp1, char *, cp2)
|
|
{
|
|
register INTEGER *p1, *p2;
|
|
LONGINT retval;
|
|
|
|
p1 = (INTEGER *) cp1;
|
|
p2 = (INTEGER *) cp2;
|
|
if (*p1 < *p2)
|
|
retval = -1;
|
|
else if (*p1 > *p2)
|
|
retval = 1;
|
|
else {
|
|
p1++;
|
|
p2++;
|
|
if (*p1 < *p2)
|
|
retval = -1;
|
|
else if (*p1 > *p2)
|
|
retval = 1;
|
|
else
|
|
retval = 0;
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
/*
|
|
* BEWARE: ptorh can trash memory... regions can grow by being inset (honest)
|
|
*/
|
|
|
|
A2(PRIVATE, void, ptorh, INTEGER *, p, RgnHandle, rh)
|
|
{
|
|
INTEGER y, oy, *op;
|
|
|
|
op = RGN_DATA (rh);
|
|
if (npairs) { /* decrement one 'cause of the 32767 sentinel */
|
|
*op++ = CW(oy = *p);
|
|
for (;npairs; npairs -= 2) {
|
|
if ((y = *p++) != oy) {
|
|
*op++ = RGN_STOP_X;
|
|
*op++ = CW(y);
|
|
oy = y;
|
|
}
|
|
*op++ = CW(*p++);
|
|
++p; /* if Cx((*ip)++ != oy) error! */
|
|
*op++ = CW(*p++);
|
|
}
|
|
}
|
|
*op++ = RGN_STOP_X; /* need one or two? */
|
|
*op++ = RGN_STOP_X; /* need one or two? */
|
|
}
|
|
|
|
P3(PUBLIC pascal trap, void, InsetRgn, RgnHandle, rh, INTEGER, dh, INTEGER, dv)
|
|
{
|
|
Handle h;
|
|
INTEGER *p;
|
|
Rect *rp;
|
|
register Size newsize;;
|
|
|
|
if (RGN_SMALL_P (rh)) {
|
|
InsetRect(&RGN_BBOX (rh), dh, dv);
|
|
#define INSANEBUTNECESSARY
|
|
#if defined (INSANEBUTNECESSARY)
|
|
rp = &RGN_BBOX (rh);
|
|
if (CW(rp->top) >= CW(rp->bottom) || CW(rp->left) >= CW(rp->right))
|
|
RECT_ZERO (rp);
|
|
#endif /* INSANEBUTNECESSARY */
|
|
} else {
|
|
newsize = 4 * RGN_SIZE (rh);
|
|
h = NewHandle(newsize);
|
|
HLock(h);
|
|
p = (INTEGER *) STARH(h);
|
|
rhtopandinseth(rh, p, dh); /* must be combined for efficiency */
|
|
gui_assert(npairs * (int) sizeof(INTEGER) * 2 <= newsize);
|
|
qsort((char *) p, npairs, sizeof(INTEGER) * 2, (void *) comparex);
|
|
hinset(p, dv);
|
|
qsort((char *) p, npairs, sizeof(INTEGER) * 2, (void *) comparey);
|
|
ReallocHandle((Handle) rh, newsize);
|
|
ptorh(p, rh);
|
|
ROMlib_sizergn(rh, FALSE);
|
|
gui_assert(Hx(rh, rgnSize) <= newsize);
|
|
HUnlock(h);
|
|
DisposHandle(h);
|
|
}
|
|
}
|
|
|
|
static boolean_t
|
|
justone (const Rect *rp, RgnHandle rgn, RgnHandle dest)
|
|
{
|
|
const Rect *rp2 = &RGN_BBOX (rgn);
|
|
|
|
if ( CW (rp->left) <= CW (rp2->left)
|
|
&& CW (rp->top) <= CW (rp2->top)
|
|
&& CW (rp->right) >= CW (rp2->right)
|
|
&& CW (rp->bottom) >= CW (rp2->bottom))
|
|
{
|
|
CopyRgn (rgn, dest);
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
P3(PUBLIC pascal trap, void, SectRgn, RgnHandle, s1, RgnHandle, s2,
|
|
RgnHandle, dest)
|
|
{
|
|
Rect dummy;
|
|
const Region *rp1, *rp2;
|
|
|
|
RGN_SLAM (s1);
|
|
RGN_SLAM (s2);
|
|
|
|
rp1 = STARH (s1);
|
|
rp2 = STARH (s2);
|
|
|
|
if (RGNP_SMALL_P (rp1))
|
|
{
|
|
if (RGNP_SMALL_P (rp2))
|
|
{
|
|
SectRect (&RGNP_BBOX (rp1), &RGNP_BBOX (rp2), &RGN_BBOX (dest));
|
|
/* #### should this set the handle size of `dest' */
|
|
RGN_SET_SMALL (dest);
|
|
return;
|
|
}
|
|
else
|
|
if (justone (&RGNP_BBOX (rp1), s2, dest))
|
|
return;
|
|
}
|
|
else if (RGNP_SMALL_P (rp2))
|
|
if (justone(&RGNP_BBOX (rp2), s1, dest))
|
|
return;
|
|
if (SectRect (&RGNP_BBOX (rp1), &RGNP_BBOX (rp2), &dummy))
|
|
sectbinop (s1, s2, dest);
|
|
else
|
|
SetEmptyRgn (dest);
|
|
}
|
|
|
|
P3(PUBLIC pascal trap, void, UnionRgn, RgnHandle, s1, RgnHandle, s2,
|
|
RgnHandle, dest)
|
|
{
|
|
if (EmptyRgn(s1))
|
|
CopyRgn(s2, dest);
|
|
else if (EmptyRgn(s2))
|
|
CopyRgn(s1, dest);
|
|
else
|
|
binop(unionop, s1, s2, dest);
|
|
}
|
|
|
|
P3(PUBLIC pascal trap, void, DiffRgn, RgnHandle, s1, RgnHandle, s2,
|
|
RgnHandle, dest)
|
|
{
|
|
if (EmptyRgn(s1) || EmptyRgn(s2))
|
|
CopyRgn(s1, dest);
|
|
else
|
|
binop(diffop, s1, s2, dest);
|
|
}
|
|
|
|
P3(PUBLIC pascal trap, void, XorRgn, RgnHandle, s1, RgnHandle, s2,
|
|
RgnHandle, dest)
|
|
{
|
|
INTEGER y1, y2, x1, x2;
|
|
INTEGER *ip1, *ip2, *op;
|
|
INTEGER left, right, bottom;
|
|
INTEGER cnt;
|
|
RgnHandle finalrestingplace;
|
|
HIDDEN_RgnPtr temp2, temp3;
|
|
ALLOCABEGIN
|
|
|
|
/* the +36 below is necessary because small regions have size of 10
|
|
yet they actually have an additional implied 18 bytes associated
|
|
with them */
|
|
|
|
if (s1 == dest || s2 == dest) {
|
|
finalrestingplace = dest;
|
|
dest = (RgnHandle) NewHandle((Size) Hx(s1, rgnSize) +
|
|
Hx(s2, rgnSize) + 36);
|
|
} else {
|
|
finalrestingplace = 0;
|
|
ReallocHandle((Handle) dest, Hx(s1, rgnSize) + Hx(s2, rgnSize) + 36);
|
|
}
|
|
|
|
if (RGN_SMALL_P (s1)) {
|
|
temp2.p = (RgnPtr) ALLOCA( RGN_SMALL_SIZE + 9 * sizeof(INTEGER) );
|
|
#if 0
|
|
BlockMove(CL(*(Ptr *) s1), (Ptr) temp2.p, RGN_SMALL_SIZE);
|
|
#else
|
|
memcpy((Ptr) temp2.p, MR(*(Ptr *) s1), RGN_SMALL_SIZE);
|
|
#endif
|
|
op = (INTEGER *) ((char *)temp2.p + RGN_SMALL_SIZE);
|
|
*op++ = HxX(s1, rgnBBox.top);
|
|
*op++ = HxX(s1, rgnBBox.left);
|
|
*op++ = HxX(s1, rgnBBox.right);
|
|
*op++ = RGN_STOP_X;
|
|
*op++ = HxX(s1, rgnBBox.bottom);
|
|
*op++ = HxX(s1, rgnBBox.left);
|
|
*op++ = HxX(s1, rgnBBox.right);
|
|
*op++ = RGN_STOP_X;
|
|
*op++ = RGN_STOP_X;
|
|
ASSERT_SAFE (temp2.p);
|
|
temp2.p = RM(temp2.p);
|
|
s1 = &temp2;
|
|
}
|
|
|
|
if (RGN_SMALL_P (s2)) {
|
|
temp3.p = (RgnPtr) ALLOCA (RGN_SMALL_SIZE + 9 * sizeof (INTEGER));
|
|
#if 0
|
|
BlockMove(CL(*(Ptr *) s2), (Ptr) temp3.p, RGN_SMALL_SIZE);
|
|
#else
|
|
memcpy((Ptr) temp3.p, STARH (s2), RGN_SMALL_SIZE);
|
|
#endif
|
|
op = (INTEGER *) ((char *)temp3.p + RGN_SMALL_SIZE);
|
|
*op++ = HxX(s2, rgnBBox.top);
|
|
*op++ = HxX(s2, rgnBBox.left);
|
|
*op++ = HxX(s2, rgnBBox.right);
|
|
*op++ = RGN_STOP_X;
|
|
*op++ = HxX(s2, rgnBBox.bottom);
|
|
*op++ = HxX(s2, rgnBBox.left);
|
|
*op++ = HxX(s2, rgnBBox.right);
|
|
*op++ = RGN_STOP_X;
|
|
*op++ = RGN_STOP_X;
|
|
ASSERT_SAFE (temp3.p);
|
|
temp3.p = RM(temp3.p);
|
|
s2 = &temp3;
|
|
}
|
|
|
|
ip1 = RGN_DATA (s1);
|
|
ip2 = RGN_DATA (s2);
|
|
op = RGN_DATA (dest);
|
|
left = RGN_STOP; right = -32768;
|
|
bottom = -32768;
|
|
for (y1 = CW(*ip1++), y2 = CW(*ip2++); y1 != RGN_STOP || y2 != RGN_STOP;) {
|
|
if (y1 < y2) {
|
|
bottom = y1;
|
|
*op++ = CW(y1);
|
|
while ((*op++ = *ip1++) != RGN_STOP_X) {
|
|
x1 = CW(op[-1]);
|
|
if (x1 < left)
|
|
left = x1;
|
|
if (x1 > right)
|
|
right = x1;
|
|
}
|
|
y1 = CW(*ip1++);
|
|
} else if (y2 < y1) {
|
|
bottom = y2;
|
|
*op++ = CW(y2);
|
|
while ((*op++ = *ip2++) != RGN_STOP_X) {
|
|
x2 = CW(op[-1]);
|
|
if (x2 < left)
|
|
left = x2;
|
|
if (x2 > right)
|
|
right = x2;
|
|
}
|
|
y2 = CW(*ip2++);
|
|
} else {
|
|
cnt = 0;
|
|
for (x1 = CW(*ip1++), x2 = CW(*ip2++);
|
|
x1 != RGN_STOP || x2 != RGN_STOP;) {
|
|
if (x1 < x2) {
|
|
if (!cnt) {
|
|
bottom = y1;
|
|
*op++ = CW(y1);
|
|
if (x1 < left)
|
|
left = x1;
|
|
} else if (x1 > right)
|
|
right = x1;
|
|
*op++ = CW(x1);
|
|
cnt++;
|
|
x1 = CW(*ip1++);
|
|
} else if (x2 < x1) {
|
|
if (!cnt) {
|
|
bottom = y1;
|
|
*op++ = CW(y1);
|
|
if (x2 < left)
|
|
left = x2;
|
|
} else if (x2 > right)
|
|
right = x2;
|
|
*op++ = CW(x2);
|
|
cnt++;
|
|
x2 = CW(*ip2++);
|
|
} else {
|
|
x1 = CW(*ip1++);
|
|
x2 = CW(*ip2++);
|
|
}
|
|
}
|
|
if (cnt)
|
|
*op++ = RGN_STOP_X;
|
|
y1 = CW(*ip1++);
|
|
y2 = CW(*ip2++);
|
|
}
|
|
}
|
|
*op++ = RGN_STOP_X;
|
|
HASSIGN_5 (dest,
|
|
rgnBBox.top, *RGN_DATA (dest),
|
|
rgnBBox.left, CW (left),
|
|
rgnBBox.bottom, CW (bottom),
|
|
rgnBBox.right, CW (right),
|
|
rgnSize, CW ((char *) op - (char *) STARH (dest)));
|
|
if (rgn_is_rect_p (dest))
|
|
RGN_SET_SMALL (dest);
|
|
if (finalrestingplace) {
|
|
ROMlib_installhandle((Handle) dest, (Handle) finalrestingplace);
|
|
SetHandleSize((Handle) finalrestingplace,
|
|
RGN_SIZE (finalrestingplace));
|
|
} else
|
|
SetHandleSize((Handle) dest, RGN_SIZE (dest));
|
|
ALLOCAEND
|
|
}
|
|
|
|
P2(PUBLIC pascal trap, BOOLEAN, RectInRgn, Rect *, rp, /* IMIV-23 */
|
|
RgnHandle, rh)
|
|
{
|
|
RgnHandle newrh;
|
|
BOOLEAN retval;
|
|
|
|
newrh = NewRgn();
|
|
RectRgn(newrh, rp);
|
|
SectRgn(newrh, rh, newrh);
|
|
retval = !EmptyRgn(newrh);
|
|
DisposeRgn(newrh);
|
|
return retval;
|
|
}
|
|
|
|
P2(PUBLIC pascal trap, BOOLEAN, EqualRgn, RgnHandle, r1, RgnHandle, r2)
|
|
{
|
|
/* Since the first field of the region is the size, this
|
|
* will return FALSE if the sizes differ, too.
|
|
*/
|
|
return !memcmp (STARH (r1), STARH (r2), RGN_SIZE (r1));
|
|
}
|
|
|
|
P1(PUBLIC pascal trap, BOOLEAN, EmptyRgn, RgnHandle, rh)
|
|
{
|
|
#warning What does a mac do with a NULL HANDLE here?
|
|
BOOLEAN retval;
|
|
|
|
retval = rh ? EmptyRect (&RGN_BBOX (rh)) : TRUE;
|
|
return retval;
|
|
}
|
|
|
|
#if !defined (NDEBUG)
|
|
A1(PUBLIC, void, ROMlib_printrgn, RgnHandle, h)
|
|
{
|
|
INTEGER *ip, x, y;
|
|
INTEGER special, size, newsize;
|
|
|
|
size = Hx (h, rgnSize);
|
|
special = size & 0x8000;
|
|
size &= ~0x8000;
|
|
if (special)
|
|
printf ("SPECIAL, ");
|
|
printf ("size = %ld, l = %ld, t = %ld, r = %ld, b = %ld\n",
|
|
(long) size, (long) Hx (h, rgnBBox.left),
|
|
(long) Hx (h, rgnBBox.top),
|
|
(long) Hx (h, rgnBBox.right), (long) Hx (h, rgnBBox.bottom));
|
|
|
|
LOCK_HANDLE_EXCURSION_1
|
|
(h,
|
|
{
|
|
if (!RGN_SMALL_P (h))
|
|
{
|
|
ip = RGN_DATA (h);
|
|
while ((y = CW (*ip++)) != RGN_STOP)
|
|
{
|
|
printf ("%ld:", (long) y);
|
|
if (special)
|
|
{
|
|
while ((x = *ip++) != RGN_STOP)
|
|
printf (" %ld", (long) x);
|
|
}
|
|
else
|
|
{
|
|
while ((x = CW (*ip++)) != RGN_STOP)
|
|
printf (" %ld", (long) x);
|
|
}
|
|
printf (" 32767\n");
|
|
}
|
|
printf ("32767\n");
|
|
newsize = ((char *) ip - (char *) STARH (h));
|
|
if (newsize != size)
|
|
printf ("WARNING: computed size = %d\n", newsize);
|
|
}
|
|
});
|
|
}
|
|
|
|
#endif /* NDEBUG */
|