]> git.sesse.net Git - rdpsrv/blobdiff - Xserver/lib/font/Type1/regions.c
Removed Xserver/ directory, it does nothing useful ATM.
[rdpsrv] / Xserver / lib / font / Type1 / regions.c
diff --git a/Xserver/lib/font/Type1/regions.c b/Xserver/lib/font/Type1/regions.c
deleted file mode 100644 (file)
index c9b0038..0000000
+++ /dev/null
@@ -1,1746 +0,0 @@
-/* $XConsortium: regions.c,v 1.6 94/02/06 16:22:21 gildea Exp $ */
-/* $XFree86: xc/lib/font/Type1/regions.c,v 3.0 1996/08/25 13:58:26 dawes Exp $ */
-/* Copyright International Business Machines, Corp. 1991
- * All Rights Reserved
- * Copyright Lexmark International, Inc. 1991
- * All Rights Reserved
- *
- * License 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 and that
- * both that copyright notice and this permission notice appear in
- * supporting documentation, and that the name of IBM or Lexmark not be
- * used in advertising or publicity pertaining to distribution of the
- * software without specific, written prior permission.
- *
- * IBM AND LEXMARK PROVIDE THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES OF
- * ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO ANY
- * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
- * AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.  THE ENTIRE RISK AS TO THE
- * QUALITY AND PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
- * OR MAINTAIN, BELONGS TO THE LICENSEE.  SHOULD ANY PORTION OF THE
- * SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM OR LEXMARK) ASSUMES THE
- * ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION.  IN NO EVENT SHALL
- * IBM OR LEXMARK BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
- * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
- * THIS SOFTWARE.
- */
- /* REGIONS  CWEB         V0023 LOTS                                 */
-/*
-:h1 id=regions.REGIONS Module - Regions Operator Handler
-This module is responsible for creating and manipulating regions.
-&author. Jeffrey B. Lotspiech (lotspiech@almaden.ibm.com)
-:h3.Include Files
-The included files are:
-*/
-#include  "objects.h"
-#include  "spaces.h"
-#include  "regions.h"
-#include  "paths.h"
-#include  "curves.h"
-#include  "lines.h"
-#include  "pictures.h"
-#include  "fonts.h"
-#include  "hints.h"
-#include  "strokes.h"      /* to pick up 'DoStroke'                        */
-static Unwind();
-static void newfilledge();
-static struct edgelist *splitedge();
-static void vertjoin();
-static int touches();
-static int crosses();
-static void edgemin();
-static void edgemax();
-static discard();
-static edgecheck();
-static struct edgelist *NewEdge();
-static struct edgelist *swathxsort();  /* 'SortSwath' function               */
-/*
-:h3.Functions Provided to the TYPE1IMAGER User
-This module provides the following TYPE1IMAGER entry points:
-*/
-/*SHARED LINE(S) ORIGINATED HERE*/
-/*
-:h3.Functions Provided to Other Modules
-This module provides the following entry points to other modules:
-*/
-/*SHARED LINE(S) ORIGINATED HERE*/
-/*
-:h3.Macros Provided to Other Modules
-:h4.GOING_TO() - Macro Predicate Needed for Changing Direction, Etc.
-The actual generation of run end lists (edge boundaries) is left
-to the low level rasterizing modules, LINES and CURVES.  There
-are some global region-type
-questions that occur when doing a low-level
-rasterization:
-:ol.
-:li.Did we just change direction in Y and therefore need to start
-a new edge?
-:li.Did we run out of allocated edge space?
-:li.Do the minimum or maximum X values for the current edge need
-updating?
-:eol.
-In general the REGIONS is not smart enough to answer those questions
-itself.  (For example, determining if and when a curve changes direction
-may need detailed curve knowledge.)  Yet, this must be done efficiently.
-We provide a macro "GOING_TO" where the invoker tells us where it is
-heading for (x2,y2), plus where it is now (x1,y1), plus the current
-region under construction, and the macro answers the questions above.
-*/
-/*SHARED LINE(S) ORIGINATED HERE*/
-/*
-:h2.Data Structures Used to Represent Regions
-:h3.The "region" Structure
-The region structure is an anchor for a linked list of "edgelist"
-structures (see :hdref refid=edgelist..).  It also summarizes the
-information in the edgelist structures (for example, the bounding
-box of the region).  And, it contains scratch areas used during
-the creation of a region.
-*/
-/*SHARED LINE(S) ORIGINATED HERE*/
-/*
-The ISOPTIMIZED flag tells us if we've put a permanent region in
-'optimal' form.
-*/
-#define   ISOPTIMIZED(flag)    ((flag)&0x10)
-/*
-The ISRECTANGULAR flag tells us if a region is a rectangle.  We don't
-always notice rectangles--if this flag is set, the region definitely
-is a rectangle, but some rectangular regions will not have the flag
-set.  The flag is used to optimize some paths.
-*/
-/*SHARED LINE(S) ORIGINATED HERE*/
-/*
-:h4."INFINITY" - A Constant Region Structure of Infinite Extent
-Infinity is the complement of a null area:
-Note - removed the refcount = 1 init, replaced with references = 2 3-26-91 PNM
-*/
-static struct region infinity = { REGIONTYPE,
-                           ISCOMPLEMENT(ON)+ISINFINITE(ON)+ISPERMANENT(ON)+ISIMMORTAL(ON), 2,
-                           0, 0, 0, 0,
-                           0, 0, 0, 0,
-                           NULL, NULL,
-                           0, 0, 0, 0, 0, NULL, NULL,
-                           NULL, 0, NULL, NULL };
-struct region *INFINITY = &infinity;
-/*
-:h4."EmptyRegion" - A Region Structure with Zero Area
-This structure is used to initialize the region to be built in
-Interior():
-Note - replaced refcount = 1 init with references = 2 3-26-91 PNM
-*/
-/*SHARED LINE(S) ORIGINATED HERE*/
-struct region EmptyRegion = { REGIONTYPE,
-                           ISPERMANENT(ON)+ISIMMORTAL(ON), 2,
-                           0, 0, 0, 0,
-                           MAXPEL, MAXPEL, MINPEL, MINPEL,
-                           NULL, NULL,
-                           0, 0, 0, 0, 0, NULL, NULL,
-                           NULL, 0, NULL, NULL };
-/*
-:h3 id=edgelist.The "edgelist" Structure
-Regions are represented by a linked list of 'edgelist' structures.
-When a region is complete, the structures are paired, one for the
-left and one for the right edge.  While a region is being built,
-this rule may be violated temporarily.
-An 'edgelist' structure contains the X values for a given span
-of Y values.  The (X,Y) pairs define an edge.  We use the crack
-and edge coordinate system, so that integer values of X and Y
-go between pels.  The edge is defined between the minimum Y and
-maximum Y.
-The linked list is kept sorted from top to bottom, that is, in
-increasing y.  Also, if 'e1' is an edgelist structure and 'e2' is the
-next one in the list, they must have exactly the same ymin,ymax values
-or be totally disjoint.  These two requirements mean that if e2's ymin
-is less than e1's ymax, it must be exactly equal to e1's ymin.  A
-sublist of structures with identical ymin and ymax values is called a
-'swath'.
-In addition, edgelist structures are separately linked together based
-on what subpath originally created them; each subpath is kept as a
-separate circular linked list.  This information is ignored unless
-continuity checking is invoked.  See :hdref refid=subpath. for a
-complete description of this.
-*/
-/*SHARED LINE(S) ORIGINATED HERE*/
-/*
-The "edgelist" structure follows the convention of TYPE1IMAGER user
-objects, having a type field and a flag field as the first two
-elements.  However, the user never sees "edgelist" structures
-directly; he is given handles to "region" structures only.
-By having a type field, we can use the "copy" feature of Allocate()
-to duplicate edge lists quickly.
-We also define two flag bits for this structure.  The ISDOWN bit is set
-if the edge is going in the direction of increasing Y. The ISAMBIGUOUS
-bit is set if the edge is identical to its neighbor (edge->link); such
-edges may be "left" when they should be "right", or vice versa,
-unnecessarily confusing the continuity checking logic.  The FixSubPaths()
-routine in HINTS will swap ambiguous edges if that avoids crossing edges;
-see :hdref refid=fixsubp..
-*/
-/*SHARED LINE(S) ORIGINATED HERE*/
-/*
-:h3.KillRegion() - Destroys a Region
-KillRegion nominally just decrements the reference count to that region.
-If the reference count becomes 0, all memory associated with it is
-freed.  We just follow the linked list, freeing as we go, then kill any
-associated (thresholded) picture.
-Note - added conditional return based on references 3-26-91 PNM
-*/
-void KillRegion(area)
-        register struct region *area;  /* area to free                       */
-{
-        register struct edgelist *p;  /* loop variable                       */
-        register struct edgelist *next;  /* loop variable                    */
-        if (area->references < 0)
-               abort("KillRegion:  negative reference count");
-        if ( (--(area->references) > 1) ||
-           ( (area->references == 1) && !ISPERMANENT(area->flag) ) )
-            return;
-        for (p=area->anchor; p != NULL; p=next) {
-               next = p->link;
-               Free(p);
-        }
-        if (area->thresholded != NULL)
-                 KillPicture(area->thresholded);
-        Free(area);
-}
-/*
-:h3.CopyRegion() - Makes a Copy of a Region
-*/
-struct region *CopyRegion(area)
-        register struct region *area;  /* region to duplicate                */
-{
-        register struct region *r;  /* output region built here              */
-        register struct edgelist *last;  /* loop variable                    */
-        register struct edgelist *p,*newp;  /* loop variables                */
-        r = (struct region *)Allocate(sizeof(struct region), area, 0);
-        r->anchor = NULL;
-        for (p=area->anchor; VALIDEDGE(p); p=p->link) {
-               newp = NewEdge(p->xmin, p->xmax, p->ymin, p->ymax, p->xvalues, ISDOWN(p->flag));
-               if (r->anchor == NULL)
-                       r->anchor = last = newp;
-               else
-                       last->link = newp;
-               last = newp;
-        }
-        if (area->thresholded != NULL)
-    /* replaced DupPicture with Dup() 3-26-91 PNM */
-               r->thresholded = (struct picture *)Dup(area->thresholded);
-        return(r);
-}
-/*
-:h4.NewEdge() - Allocates and Returns a New "edgelist" Structure
-We allocate space for the X values contiguously with the 'edgelist'
-structure that locates them.  That way, we only have to free the
-edgelist structure to free all memory associated with it.  Damn
-clever, huh?
-*/
-static struct edgelist *NewEdge(xmin, xmax, ymin, ymax, xvalues, isdown)
-       pel xmin,xmax;        /* X extent of edge                             */
-       pel ymin,ymax;        /* Y extent of edge                             */
-       pel *xvalues;         /* list of X values for entire edge             */
-       int isdown;           /* flag:  TRUE means edge progresses downward   */
-{
-       static struct edgelist template = {
-                 EDGETYPE, 0, 1, NULL, NULL,
-                 0, 0, 0, 0, NULL };
-       register struct edgelist *r;  /* returned structure                   */
-       register int iy;      /* ymin adjusted for 'long' alignment purposes  */
-       IfTrace2((RegionDebug),"....new edge: ymin=%d, ymax=%d ",
-                                              (long)ymin, (long) ymax);
-       if (ymin >= ymax)
-               abort("newedge: height not positive");
-/*
-We are going to copy the xvalues into a newly allocated area.  It
-helps performance if the values are all "long" aligned.  We can test
-if the xvalues are long aligned by ANDing the address with the
-(sizeof(long) - 1)--if non zero, the xvalues are not aligned well.  We
-set 'iy' to the ymin value that would give us good alignment:
-*/
-       iy = ymin - (((unsigned long)xvalues) & (sizeof(long)-1)) / sizeof(pel);
-       r = (struct edgelist *)Allocate(sizeof(struct edgelist), &template,
-                             (ymax - iy) * sizeof(pel));
-       if (isdown) r->flag = ISDOWN(ON);
-       r->xmin = xmin;
-       r->xmax = xmax;
-       r->ymin = ymin;
-       r->ymax = ymax;
-       r->xvalues = (pel *) FOLLOWING(r);
-       if (ymin != iy) {
-               r->xvalues += ymin - iy;
-               xvalues -= ymin - iy;
-       }
-/*
-We must round up (ymax - iy) so we get the ceiling of the number of
-longs.  The destination must be able to hold these extra bytes because
-Allocate() makes everything it allocates be in multiples of longs.
-*/
-       LONGCOPY(&r[1], xvalues, (ymax - iy) * sizeof(pel) + sizeof(long) - 1);
-       IfTrace1((RegionDebug),"result=%x\n", r);
-       return(r);
-}
-/*
-:h2.Building Regions
-:h3.Interior() - Iterate Through a Path, Building a Region
-This routine is the workhorse driver routine that iterates through a
-path, calling the appropriate stepping routines to actually produce the
-run end "edgelist" structures.
-:ol.
-:li."Interior" calls StepLine or StepConic or StepBezier as appropriate
-to produce run ends.
-:li.Occasionally these routines will notice a change in Y direction
-and will call ChangeDirection (through the GOING_TO macro); this is
-a call back to the REGIONS module.
-:li.ChangeDirection will call whatever function is in the region
-structure; for Interior, this function is 'newfilledge'.
-:li.Newfilledge will call NewEdge to create a new edgelist structure,
-then, call SortSwath to sort it onto the linked list being built at
-the region "anchor".
-:eol.
-By making the function called by ChangeDirection be a parameter of the
-region, we allow the same ChangeDirection logic to be used by stroking.
-*/
-/*SHARED LINE(S) ORIGINATED HERE*/
-struct region *Interior(p, fillrule)
-       register struct segment *p;    /* take interior of this path          */
-       register int fillrule;         /* rule to follow if path crosses itself */
-{
-       register fractpel x,y;  /* keeps ending point of path segment         */
-       fractpel lastx,lasty; /* previous x,y from path segment before        */
-       register struct region *R;  /* region I will build                    */
-       register struct segment *nextP; /* next segment of path */
-       struct fractpoint hint; /* accumulated hint value */
-       char tempflag;        /* flag; is path temporary?                     */
-       char Cflag;           /* flag; should we apply continuity?            */
-       IfTrace2((MustTraceCalls),".  INTERIOR(%z, %d)\n", p, (long) fillrule);
-       if (p == NULL)
-               return(NULL);
-/*
-Establish the 'Cflag' continuity flag based on user's fill rule and
-our own 'Continuity' pragmatic (0: never do continuity, 1: do what
-user asked, >1: do it regardless).
-*/
-       if (fillrule > 0) {
-               Cflag = Continuity > 0;
-               fillrule -= CONTINUITY;
-       }
-       else
-               Cflag = Continuity > 1;
-       ARGCHECK((fillrule != WINDINGRULE && fillrule != EVENODDRULE),
-                       "Interior: bad fill rule", NULL, NULL, (1,p), struct region *);
-       if (p->type == TEXTTYPE)
-/*             if (fillrule != EVENODDRULE)
-               else */
-                       return((struct region *)UniquePath(p));
-       if (p->type == STROKEPATHTYPE)
-               if (fillrule == WINDINGRULE)
-                       return((struct region *)DoStroke(p));
-               else
-                       p = CoercePath(p);
-       R = (struct region *)Allocate(sizeof(struct region), &EmptyRegion, 0);
-       ARGCHECK(!ISPATHANCHOR(p), "Interior:  bad path", p, R, (0), struct region *);
-       ARGCHECK((p->type != MOVETYPE), "Interior:  path not closed", p, R, (0), struct region *);
-/* changed definition from !ISPERMANENT to references <= 1 3-26-91 PNM */
-       tempflag =  (p->references <= 1); /* only first segment in path is so marked */
-       if (!ISPERMANENT(p->flag)) p->references -= 1;
-       R->newedgefcn = newfilledge;
-/*
-Believe it or not, "R" is now completely initialized.  We are counting
-on the copy of template to get other fields the way we want them,
-namely
-:ol.
-:li.anchor = NULL
-:li.xmin, ymin, xmax, ymax, to minimum and maximum values respectively.
-:eol.
-Anchor = NULL is very
-important to ChangeDirection.
-See :hdref refid=CD..
-To minimize problems of "wrapping" in our pel arithmetic, we keep an
-origin of the region which is the first move.  Hopefully, that keeps
-numbers within plus or minus 32K pels.
-*/
-       R->origin.x = 0/*TOFRACTPEL(NEARESTPEL(p->dest.x))*/;
-       R->origin.y = 0/*TOFRACTPEL(NEARESTPEL(p->dest.y))*/;
-       lastx = - R->origin.x;
-       lasty = - R->origin.y;
-/*
-ChangeDirection initializes other important fields in R, such as
-lastdy, edge, edgeYstop, edgexmin, and edgexmax.  The first segment
-is a MOVETYPE, so it will be called first.
-*/
-/*
-The hints data structure must be initialized once for each path.
-*/
-       if (ProcessHints)
-               InitHints(); /* initialize hint data structure */
-       while (p != NULL)  {
-               x = lastx + p->dest.x;
-               y = lasty + p->dest.y;
-               IfTrace2((HintDebug > 0),"Ending point = (%p,%p)\n", x, y);
-               nextP = p->link;
-/*
-Here we start the hints processing by initializing the hint value to
-zero.  If ProcessHints is FALSE, the value will remain zero.
-Otherwise, hint accumulates the computed hint values.
-*/
-               hint.x = hint.y = 0;
-/*
-If we are processing hints, and this is a MOVE segment (other than
-the first on the path), we need to close (reverse) any open hints.
-*/
-               if (ProcessHints)
-                       if ((p->type == MOVETYPE) && (p->last == NULL)) {
-                               CloseHints(&hint);
-                               IfTrace2((HintDebug>0),"Closed point= (%p,%p)\n",
-                                               x+hint.x, y+hint.y);
-                       }
-/*
-Next we run through all the hint segments (if any) attached to this
-segment.  If ProcessHints is TRUE, we will accumulate computed hint
-values.  In either case, nextP will be advanced to the first non-HINT
-segment (or NULL), and each hint segment will be freed if necessary.
-*/
-               while ((nextP != NULL) && (nextP->type == HINTTYPE))  {
-                       if (ProcessHints)
-                               ProcessHint(nextP, x + hint.x, y + hint.y, &hint);
-                       {
-                               register struct segment *saveP = nextP;
-                               nextP = nextP->link;
-                               if (tempflag)
-                                       Free(saveP);
-                       }
-               }
-/*
-We now apply the full hint value to the ending point of the path segment.
-*/
-               x += hint.x;
-               y += hint.y;
-               IfTrace2((HintDebug>0),"Hinted ending point = (%p,%p)\n", x, y);
-               switch(p->type) {
-                   case LINETYPE:
-                       StepLine(R, lastx, lasty, x, y);
-                       break;
-                   case CONICTYPE:
-                   {
-/*
-For a conic curve, we apply half the hint value to the conic midpoint.
-*/
-                   }
-                       break;
-                   case BEZIERTYPE:
-                   {
-                       register struct beziersegment *bp = (struct beziersegment *) p;
-/*
-For a Bezier curve, we apply the full hint value to the Bezier C point.
-*/
-                       StepBezier(R, lastx, lasty,
-                                 lastx + bp->B.x, lasty + bp->B.y,
-                                 lastx + bp->C.x + hint.x,
-                                 lasty + bp->C.y + hint.y,
-                                 x, y);
-                   }
-                       break;
-                   case MOVETYPE:
-/*
-At this point we have encountered a MOVE segment.  This breaks the
-path, making it disjoint.
-*/
-                       if (p->last == NULL) /* i.e., not first in path */
-                               ChangeDirection(CD_LAST, R, lastx, lasty, (fractpel) 0);
-                       ChangeDirection(CD_FIRST, R, x, y, (fractpel) 0);
-/*
-We'll just double check for closure here.  We forgive an appended
-MOVETYPE at the end of the path, if it isn't closed:
-*/
-                       if (!ISCLOSED(p->flag) && p->link != NULL)
-                               return((struct region *)ArgErr("Fill: sub-path not closed", p, NULL));
-                       break;
-                   default:
-                       abort("Interior: path type error");
-               }
-/*
-We're done with this segment.  Advance to the next path segment in
-the list, freeing this one if necessary:
-*/
-               lastx = x;  lasty = y;
-               if (tempflag)
-                       Free(p);
-               p = nextP;
-       }
-       ChangeDirection(CD_LAST, R, lastx, lasty, (fractpel) 0);
-       R->ending.x = lastx;
-       R->ending.y = lasty;
-/*
-Finally, clean up the region's based on the user's 'fillrule' request:
-*/
-       if (Cflag)
-             ApplyContinuity(R);
-       if (fillrule == WINDINGRULE)
-             Unwind(R->anchor);
-       return(R);
-}
-/*
-:h4.Unwind() - Discards Edges That Fail the Winding Rule Test
-The winding rule says that upward going edges should be paired with
-downward going edges only, and vice versa.  So, if two upward edges
-or two downward edges are nominally left/right pairs, Unwind() should
-discard the second one.  Everything should balance; we should discard
-an even number of edges; of course, we abort if we don't.
-*/
-static Unwind(area)
-       register struct edgelist *area;  /* input area modified in place      */
-{
-       register struct edgelist *last,*next;  /* struct before and after current one */
-       register int y;       /* ymin of current swath                        */
-       register int count,newcount;  /* winding count registers              */
-       IfTrace1((RegionDebug>0),"...Unwind(%z)\n", area);
-       while (VALIDEDGE(area)) {
-               count = 0;
-               y = area->ymin;
-               do {
-                       next = area->link;
-                       if (ISDOWN(area->flag))
-                               newcount = count + 1;
-                       else
-                               newcount = count - 1;
-                       if (count == 0 || newcount == 0)
-                               last = area;
-                       else
-                               discard(last, next);
-                       count = newcount;
-                       area = next;
-               } while (area != NULL && area->ymin == y);
-               if (count != 0)
-                       abort("Unwind:  uneven edges");
-       }
-}
-/*
-:h3."workedge" Array
-This is a statically allocated array where edges are built
-before being copied into more permanent storage by NewEdge().
-*/
-#ifndef   MAXEDGE
-#define   MAXEDGE     1000
-#endif
-static pel workedge[MAXEDGE];
-static pel *currentworkarea = workedge;
-static pel currentsize = MAXEDGE;
-/*
-:h3 id=cd.ChangeDirection() - Called When Y Direction Changes
-The rasterizing routines call this entry point when they detect
-a change in Y.  We then build the current edge and sort it into
-emerging edgelist at 'anchor' by calling whatever "newedgefcn"
-is appropriate.
-*/
-void ChangeDirection(type, R, x, y, dy)
-       int type;             /* CD_FIRST, CD_CONTINUE, or CD_LAST            */
-       register struct region *R;  /* region in which we are changing direction */
-       fractpel x,y;         /* current beginning x,y                        */
-       fractpel dy;          /* direction and magnitude of change in y       */
-{
-       register fractpel ymin,ymax;  /* minimum and maximum Y since last call */
-       register fractpel x_at_ymin,x_at_ymax;  /* their respective X's       */
-       register pel iy;      /* nearest integer pel to 'y'                   */
-       register pel idy;     /* nearest integer pel to 'dy'                  */
-       register int ydiff;   /* allowed Y difference in 'currentworkarea'    */
-       IfTrace4((RegionDebug>0),"Change Y direction (%d) from (%p,%p), dy=%p\n",
-                                         (long) type, x, y, dy);
-       if (type != CD_FIRST) {
-               if (R->lastdy > 0) {
-                       ymin = R->firsty;
-                       x_at_ymin = R->firstx;
-                       ymax = y;
-                       x_at_ymax = x;
-               }
-               else {
-                       ymin = y;
-                       x_at_ymin = x;
-                       ymax = R->firsty;
-                       x_at_ymax = R->firstx;
-               }
-               if (ymax < ymin)
-                       abort("negative sized edge?");
-               (*R->newedgefcn)(R, R->edgexmin, R->edgexmax, ymin, ymax,
-                                   R->lastdy > 0, x_at_ymin, x_at_ymax);
-       }
-       R->firsty = y;
-       R->firstx = x;
-       R->lastdy = dy;
-       iy = NEARESTPEL(y);
-       idy = NEARESTPEL(dy);
-       if (currentworkarea != workedge && idy < MAXEDGE && idy > -MAXEDGE) {
-               NonObjectFree(currentworkarea);
-               currentworkarea = workedge;
-               currentsize = MAXEDGE;
-       }
-       ydiff = currentsize - 1;
-       if (dy > 0) {
-               R->edge = &currentworkarea[-iy];
-               R->edgeYstop = TOFRACTPEL(ydiff + iy) + FPHALF;
-       }
-       else {
-               R->edge = &currentworkarea[ydiff - iy];
-               R->edgeYstop = TOFRACTPEL(iy - ydiff) - FPHALF;
-       }
-       R->edgexmax = R->edgexmin = x;
-/*
-If this is the end of a subpath, we complete the subpath circular
-chain:
-*/
-       if (type == CD_LAST && R->lastedge != NULL) {
-               register struct edgelist *e = R->firstedge;
-               while (e->subpath != NULL)
-                       e = e->subpath;
-               e->subpath = R->lastedge;
-               R->lastedge = R->firstedge = NULL;
-       }
-}
-/*
-:h3 id=newfill.newfilledge() - Called When We Have a New Edge While Filling
-This is the prototypical "newedge" function passed to "Rasterize" and
-stored in "newedgefcn" in the region being built.
-If the edge is non-null, we sort it onto the list of edges we are
-building at "anchor".
-This function also has to keep the bounding box of the region
-up to date.
-*/
-static void newfilledge(R, xmin, xmax, ymin, ymax, isdown)
-       register struct region *R;  /* region being built                     */
-       fractpel xmin,xmax;   /* X range of this edge                         */
-       fractpel ymin,ymax;   /* Y range of this edge                         */
-       int isdown;           /* flag:  TRUE means edge goes down, else up    */
-{
-       register pel pelxmin,pelymin,pelxmax,pelymax;  /* pel versions of bounds */
-       register struct edgelist *edge;  /* newly created edge                */
-       pelymin = NEARESTPEL(ymin);
-       pelymax = NEARESTPEL(ymax);
-       if (pelymin == pelymax)
-               return;
-       pelxmin = NEARESTPEL(xmin);
-       pelxmax = NEARESTPEL(xmax);
-       if (pelxmin < R->xmin)  R->xmin = pelxmin;
-       if (pelxmax > R->xmax)  R->xmax = pelxmax;
-       if (pelymin < R->ymin)  R->ymin = pelymin;
-       if (pelymax > R->ymax)  R->ymax = pelymax;
-       edge = NewEdge(pelxmin, pelxmax, pelymin, pelymax, &R->edge[pelymin], isdown);
-       edge->subpath = R->lastedge;
-       R->lastedge = edge;
-       if (R->firstedge == NULL)
-               R->firstedge = edge;
-       R->anchor = SortSwath(R->anchor, edge, swathxsort);
-}
-/*
-:h2.Sorting Edges
-:h3.SortSwath() - Vertically Sort an Edge into a Region
-This routine sorts an edge or a pair of edges into a growing region,
-so that the region maintains its top-to-bottom, left-to-right form.
-The rules for sorting horizontally may vary depending on what you
-are doing, but the rules for vertical sorting are always the same.
-This routine is passed an argument that is a function that will
-perform the horizontal sort on demand (for example, swathxsort() or
-SwathUnion()).
-This is a recursive routine.  A new edge (or edge pair) may overlap
-the list I am building in strange and wonderful ways.  Edges may
-cross.  When this happens, my strategy is to split the incoming edge
-(or the growing list) in two at that point, execute the actual sort on
-the top part of the split, and recursively call myself to figure out
-exactly where the bottom part belongs.
-*/
-#define   TOP(e)      ((e)->ymin)  /* the top of an edge (for readability    */
-#define   BOTTOM(e)   ((e)->ymax)  /* the bottom of an edge (for readability */
-struct edgelist *SortSwath(anchor, edge, swathfcn)
-       struct edgelist *anchor;  /* list being built                         */
-       register struct edgelist *edge;  /* incoming edge or pair of edges    */
-       struct edgelist *(*swathfcn)();  /* horizontal sorter                 */
-{
-       register struct edgelist *before,*after;
-       struct edgelist base;
-       if (RegionDebug > 0) {
-               if (RegionDebug > 2)  {
-                       IfTrace3(TRUE,"SortSwath(anchor=%z, edge=%z, fcn=%x)\n",
-                            anchor, edge, swathfcn);
-               }
-               else  {
-                       IfTrace3(TRUE,"SortSwath(anchor=%x, edge=%x, fcn=%x)\n",
-                            anchor, edge, swathfcn);
-               }
-       }
-       if (anchor == NULL)
-               return(edge);
-       before = &base;
-       before->ymin = before->ymax = MINPEL;
-       before->link = after = anchor;
-/*
-If the incoming edge is above the current list, we connect the current
-list to the bottom of the incoming edge.  One slight complication is
-if the incoming edge overlaps into the current list.  Then, we
-first split the incoming edge in two at the point of overlap and recursively
-call ourselves to sort the bottom of the split into the current list:
-*/
-       if (TOP(edge) < TOP(after)) {
-               if (BOTTOM(edge) > TOP(after)) {
-                       after = SortSwath(after, splitedge(edge, TOP(after)), swathfcn);
-               }
-               vertjoin(edge, after);
-               return(edge);
-       }
-/*
-At this point the top of edge is not higher than the top of the list,
-which we keep in 'after'.  We move the 'after' point down the list,
-until the top of the edge occurs in the swath beginning with 'after'.
-If the bottom of 'after' is below the bottom of the edge, we have to
-split the 'after' swath into two parts, at the bottom of the edge.
-If the bottom of 'after' is above the bottom of the swath,
-*/
-       while (VALIDEDGE(after)) {
-               if (TOP(after) == TOP(edge)) {
-                       if (BOTTOM(after) > BOTTOM(edge))
-                               vertjoin(after, splitedge(after, BOTTOM(edge)));
-                       else if (BOTTOM(after) < BOTTOM(edge)) {
-                               after = SortSwath(after,
-                                     splitedge(edge, BOTTOM(after)), swathfcn);
-                       }
-                       break;
-               }
-               else if (TOP(after) > TOP(edge)) {
-                       IfTrace0((BOTTOM(edge) < TOP(after) && RegionDebug > 0),
-                                                "SortSwath:  disjoint edges\n");
-                       if (BOTTOM(edge) > TOP(after)) {
-                               after = SortSwath(after,
-                                         splitedge(edge, TOP(after)), swathfcn);
-                       }
-                       break;
-               }
-               else if (BOTTOM(after) > TOP(edge))
-                       vertjoin(after, splitedge(after, TOP(edge)));
-               before = after;
-               after = after->link;
-       }
-/*
-At this point 'edge' exactly corresponds in height to the current
-swath pointed to by 'after'.
-*/
-       if (after != NULL && TOP(after) == TOP(edge)) {
-               before = (*swathfcn)(before, edge);
-               after = before->link;
-       }
-/*
-At this point 'after' contains all the edges after 'edge', and 'before'
-contains all the edges before.  Whew!  A simple matter now of adding
-'edge' to the linked list in its rightful place:
-*/
-       before->link = edge;
-       if (RegionDebug > 1) {
-               IfTrace3(TRUE,"SortSwath:  in between %x and %x are %x",
-                                                before, after, edge);
-               while (edge->link != NULL) {
-                       edge = edge->link;
-                       IfTrace1(TRUE," and %x", edge);
-               }
-               IfTrace0(TRUE,"\n");
-       }
-       else
-               for (; edge->link != NULL; edge = edge->link) { ; }
-       edge->link = after;
-       return(base.link);
-}
-/*
-:h3.splitedge() - Split an Edge or Swath in Two at a Given Y Value
-This function returns the edge or swath beginning at the Y value, and
-is guaranteed not to change the address of the old swath while splitting
-it.
-*/
-static struct edgelist *splitedge(list, y)
-       struct edgelist *list;  /* area to split                              */
-       register pel y;       /* Y value to split list at                     */
-{
-       register struct edgelist *new;  /* anchor for newly built list        */
-       register struct edgelist *last;  /* end of newly built list           */
-       register struct edgelist *r;  /* temp pointer to new structure        */
-       register struct edgelist *lastlist;  /* temp pointer to last 'list' value */
-       IfTrace2((RegionDebug > 1),"splitedge of %x at %d ", list, (long) y);
-       lastlist = new = NULL;
-       while (list != NULL) {
-               if (y < list->ymin)
-                       break;
-               if (y >= list->ymax)
-                       abort("splitedge: above top of list");
-               if (y == list->ymin)
-                       abort("splitedge: would be null");
-               r = (struct edgelist *)Allocate(sizeof(struct edgelist), list, 0);
-/*
-At this point 'r' points to a copy of the single structure at 'list'.
-We will make 'r' be the new split 'edgelist'--the lower half.
-We don't bother to correct 'xmin' and 'xmax', we'll take the
-the pessimistic answer that results from using the old values.
-*/
-               r->ymin = y;
-               r->xvalues = list->xvalues + (y - list->ymin);
-/*
-Note that we do not need to allocate new memory for the X values,
-they can remain with the old "edgelist" structure.  We do have to
-update that old structure so it is not as high:
-*/
-               list->ymax = y;
-/*
-Insert 'r' in the subpath chain:
-*/
-               r->subpath = list->subpath;
-               list->subpath = r;
-/*
-Now attach 'r' to the list we are building at 'new', and advance
-'list' to point to the next element in the old list:
-*/
-               if (new == NULL)
-                       new = r;
-               else
-                       last->link = r;
-               last = r;
-               lastlist = list;
-               list = list->link;
-       }
-/*
-At this point we have a new list built at 'new'.  We break the old
-list at 'lastlist', and add the broken off part to the end of 'new'.
-Then, we return the caller a pointer to 'new':
-*/
-       if (new == NULL)
-               abort("null splitedge");
-       lastlist->link = NULL;
-       last->link = list;
-       IfTrace1((RegionDebug > 1),"yields %x\n", new);
-       return(new);
-}
-/*
-:h3.vertjoin() - Join Two Disjoint Edge Lists Vertically
-The two edges must be disjoint vertically.
-*/
-static void vertjoin(top, bottom)
-       register struct edgelist *top;  /* uppermost region                   */
-       register struct edgelist *bottom;  /* bottommost region               */
-{
-       if (BOTTOM(top) > TOP(bottom))
-               abort("vertjoin not disjoint");
-       for (; top->link != NULL; top=top->link) { ; }
-       top->link = bottom;
-       return;
-}
-/*
-:h3.swathxsort() - Sorting by X Values
-We need to sort 'edge' into its rightful
-place in the swath by X value, taking care that we do not accidentally
-advance to the next swath while searching for the correct X value.  Like
-all swath functions, this function returns a pointer to the edge
-BEFORE the given edge in the sort.
-*/
-static struct edgelist *swathxsort(before0, edge)
-       register struct edgelist *before0;  /* edge before this swath         */
-       register struct edgelist *edge;  /* input edge                        */
-{
-       register struct edgelist *before;
-       register struct edgelist *after;
-       register pel y;
-       before = before0;
-       after = before->link;
-       while (after != NULL && TOP(after) == TOP(edge)) {
-               register pel *x1,*x2;
-               y = TOP(edge);
-               x1 = after->xvalues;
-               x2 = edge->xvalues;
-               while (y < BOTTOM(edge) && *x1 == *x2) {
-                       x1++; x2++; y++;
-               }
-               if (y >= BOTTOM(edge)) {
-                       edge->flag |= ISAMBIGUOUS(ON);
-                       after->flag |= ISAMBIGUOUS(ON);
-                       break;
-               }
-               if (*x1 >= *x2)
-                       break;
-               before = after;
-               after = after->link;
-       }
-/*
-At this point, 'edge' is between 'before' and 'after'.  If 'edge' didn't
-cross either of those other edges, we would be done.  We check for
-crossing.  If it does cross, we split the problem up by calling SortSwath
-recursively with the part of the edge that is below the crossing point:
-*/
-{
-       register int h0,h;    /* height of edge--number of scans              */
-       h0 = h = BOTTOM(edge) - y;
-       y -= TOP(edge);
-       if (h0 <= 0) {
-               IfTrace0((RegionDebug>0),"swathxsort: exactly equal edges\n");
-               return(before);
-       }
-       if (TOP(before) == TOP(edge))
-               h -= crosses(h, &before->xvalues[y], &edge->xvalues[y]);
-       if (after != NULL && TOP(after) == TOP(edge))
-               h -= crosses(h, &edge->xvalues[y], &after->xvalues[y]);
-       if (h < h0) {
-               SortSwath(before0->link,
-                         splitedge(edge, TOP(edge) + y + h),
-                         swathxsort);
-       }
-}
-       return(before);
-}
-/*
-:h3.SwathUnion() - Union Two Edges by X Value
-We have a left and right edge that must be unioned into a growing
-swath.  If they are totally disjoint, they are just added in.  The
-fun comes in they overlap the existing edges.  Then some edges
-will disappear.
-*/
-struct edgelist *SwathUnion(before0, edge)
-       register struct edgelist *before0;  /* edge before the swath          */
-       register struct edgelist *edge;  /* list of two edges to be unioned   */
-{
-       register int h;       /* saves height of edge                         */
-       register struct edgelist *rightedge;  /* saves right edge of 'edge'   */
-       register struct edgelist *before,*after;  /* edge before and after    */
-       int h0;               /* saves initial height                         */
-       IfTrace2((RegionDebug > 1),"SwathUnion entered, before=%x, edge=%x\n",
-                      before0, edge);
-       h0 = h = edge->ymax - edge->ymin;
-       if (h <= 0)
-               abort("SwathUnion:  0 height swath?");
-       before = before0;
-       after = before->link;
-       while (after != NULL && TOP(after) == TOP(edge)) {
-               register struct edgelist *right;
-               right = after->link;
-               if (right->xvalues[0] >= edge->xvalues[0])
-                       break;
-               before = right;
-               after = before->link;
-       }
-/*
-This is the picture at this point.  'L' indicates a left hand edge,
-'R' indicates the right hand edge.
-'<--->' indicates the degree of uncertainty as to its placement
-relative to other edges:
-:xmp atomic.
-   before           after
-     R            <---L---->  R             L   R    L   R
-              <---L--->  <------R-------------------------->
-                 edge
-:exmp.
-In case the left of 'edge' touches 'before', we need to reduce
-the height by that amount.
-*/
-       if (TOP(before) == TOP(edge))
-               h -= touches(h, before->xvalues, edge->xvalues);
-       rightedge = edge->link;
-       if (after == NULL || TOP(after) != TOP(edge) ||
-                   after->xvalues[0] > rightedge->xvalues[0]) {
-              IfTrace2((RegionDebug > 1),
-                       "SwathUnion starts disjoint: before=%x after=%x\n",
-                                     before, after);
-/*
-On this side of the the above 'if', the new edge is disjoint from the
-existing edges in the swath.  This is the picture:
-:xmp atomic.
-   before           after
-     R                L    R     L   R    L   R
-              L    R
-             edge
-:exmp.
-We will verify it remains disjoint for the entire height.  If the
-situation changes somewhere down the edge, we split the edge at that
-point and recursively call ourselves (through 'SortSwath') to figure
-out the new situation:
-*/
-               if (after != NULL && TOP(after) == TOP(edge))
-                       h -= touches(h, rightedge->xvalues, after->xvalues);
-               if (h < h0)
-                       SortSwath(before0->link, splitedge(edge, edge->ymin + h), t1_SwathUnion);
-               /* go to "return" this edge pair; it is totally disjoint */
-       }
-       else {
-/*
-At this point, at the 'else', we know that the
-new edge overlaps one or more pairs in the existing swath.  Here is
-a picture of our knowledge and uncertainties:
-:xmp atomic.
-   before       after
-     R            L        R     L   R    L   R
-            <---L--->   <---R------------------->
-               edge
-:exmp.
-We need to move 'after' along until it is to the right of the
-right of 'edge'.  ('After' should always point to a left edge of a pair:)
-*/
-               register struct edgelist *left;  /* variable to keep left edge in */
-               do {
-                        left = after;
-                        after = (after->link)->link;
-               } while  (after != NULL && TOP(after) == TOP(edge)
-                               && after->xvalues[0] <= rightedge->xvalues[0]);
-/*
-At this point this is the picture:
-:xmp atomic.
-   before                 left        after
-     R            L    R   L      R     L   R
-            <---L--->        <---R--->
-               edge
-:exmp.
-We need to verify that the situation stays like this all the way
-down the edge.  Again, if the
-situation changes somewhere down the edge, we split the edge at that
-point and recursively call ourselves (through 'SortSwath') to figure
-out the new situation:
-*/
-               h -= crosses(h, left->xvalues, rightedge->xvalues);
-               h -= crosses(h, edge->xvalues, ((before->link)->link)->xvalues);
-               if (after != NULL && TOP(after) == TOP(edge))
-                       h -= touches(h, rightedge->xvalues, after->xvalues);
-               IfTrace3((RegionDebug > 1),
-                      "SwathUnion is overlapped until %d: before=%x after=%x\n",
-                                          (long) TOP(edge) + h, before, after);
-/*
-OK, if we touched either of our neighbors we need to split at that point
-and recursively sort the split edge onto the list.  One tricky part
-is that when we recursively sort, 'after' will change if it was not
-in our current swath:
-*/
-               if (h < h0) {
-                       SortSwath(before0->link,
-                                 splitedge(edge, edge->ymin + h),
-                                 t1_SwathUnion);
-                       if (after == NULL || TOP(after) != TOP(edge))
-                                 for (after = before0->link;
-                                      TOP(after) == TOP(edge);
-                                      after = after->link) { ; }
-               }
-/*
-Now we need to augment 'edge' by the left and right of the overlapped
-swath, and to discard all edges between before and after, because they
-were overlapped and have been combined with the new incoming 'edge':
-*/
-               edge->xmin = MIN(edge->xmin, (before->link)->xmin);
-               edge->xmax = MIN(edge->xmax, (before->link)->xmax);
-               edgemin(h, edge->xvalues, (before->link)->xvalues);
-               rightedge->xmin = MAX(rightedge->xmin, (left->link)->xmin);
-               rightedge->xmax = MAX(rightedge->xmax, (left->link)->xmax);
-               edgemax(h, rightedge->xvalues, (left->link)->xvalues);
-               discard(before, after);
-       }
-       return(before);
-}
-/*
-:h3.swathrightmost() - Simply Sorts New Edge to Rightmost of Swath
-Like all swath functions, this function returns a pointer to the edge
-BEFORE the given edge in the sort.
-*/
-static struct edgelist *swathrightmost(before, edge)
-       register struct edgelist *before;  /* edge before this swath         */
-       register struct edgelist *edge;  /* input edge                        */
-{
-       register struct edgelist *after;
-       after = before->link;
-       while (after != NULL && TOP(after) == TOP(edge)) {
-               before = after;
-               after = after->link;
-       }
-       return(before);
-}
-/*
-:h3.touches() - Returns the Remaining Height When Two Edges Touch
-So, it will return 0 if they never touch.  Allows incredibly(?) mnemonic
-if (touches(...)) construct.
-*/
-static int touches(h, left, right)
-       register int h;
-       register pel *left,*right;
-{
-       for (; h > 0; h--)
-               if (*left++ >= *right++)
-                       break;
-       return(h);
-}
-/*
-:h3.crosses() - Returns the Remaining Height When Two Edges Cross
-So, it will return 0 if they never cross.
-*/
-static int crosses(h, left, right)
-       register int h;
-       register pel *left,*right;
-{
-       for (; h > 0; h--)
-               if (*left++ > *right++)
-                       break;
-       return(h);
-}
-/*
-:h3.cedgemin() - Stores the Mininum of an Edge and an X Value
-*/
-static void cedgemin(h, e1, x)
-       register int h;
-       register pel *e1;
-       register pel x;
-{
-       for (; --h >= 0; e1++)
-               if (*e1 > x)
-                       *e1 = x;
-}
-/*
-:h3.cedgemax() - Stores the Maximum of an Edge and an X Value
-*/
-static void cedgemax(h, e1, x)
-       register int h;
-       register pel *e1;
-       register pel x;
-{
-       for (; --h >= 0; e1++)
-               if (*e1 < x)
-                       *e1 = x;
-}
-/*
-:h3.edgemin() - Stores the Mininum of Two Edges in First Edge
-*/
-static void edgemin(h, e1, e2)
-       register int h;
-       register pel *e1,*e2;
-{
-       for (; --h >= 0; e1++,e2++)
-               if (*e1 > *e2)
-                       *e1 = *e2;
-}
-/*
-:h3.edgemax() - Stores the Maximum of Two Edges in First Edge
-*/
-static void edgemax(h, e1, e2)
-       register int h;
-       register pel *e1,*e2;
-{
-       for (; --h >= 0; e1++,e2++)
-               if (*e1 < *e2)
-                       *e1 = *e2;
-}
-/*
-:h3 id=discard.discard() - Discard All Edges Between Two Edges
-At first glance it would seem that we could discard an edgelist
-structure merely by unlinking it from the list and freeing it.  You are
-wrong, region-breath!  For performance, the X values associated with an
-edge are allocated contiguously with it.  So, we free the X values when
-we free a structure.  However, once an edge has been split, we are no
-longer sure which control block actually is part of the memory block
-that contains the edges.  Rather than trying to decide, we play it safe
-and never free part of a region.
-So, to mark a 'edgelist' structure as discarded, we move it to the end
-of the list and set ymin=ymax.
-*/
-static discard(left, right)
-       register struct edgelist *left,*right;  /* all edges between here exclusive */
-                                       /* should be discarded */
-{
-       register struct edgelist *beg,*end,*p;
-       IfTrace2((RegionDebug > 0),"discard:  l=%x, r=%x\n", left, right);
-       beg = left->link;
-       if (beg == right)
-               return;
-       for (p = beg; p != right; p = p->link) {
-               if (p->link == NULL && right != NULL)
-                       abort("discard():  ran off end");
-               IfTrace1((RegionDebug > 0),"discarding %x\n", p);
-               p->ymin = p->ymax = 32767;
-               end = p;
-       }
-       /*
-       * now put the chain beg/end at the end of right, if it is not
-       * already there:
-       */
-       if (right != NULL) {
-               left->link = right;
-               while (right->link != NULL)
-                       right = right->link;
-               right->link = beg;
-       }
-       end->link = NULL;
-}
-/*
-:h2.Changing the Representation of Regions
-For convenience and/or performance, we sometimes like to change the way
-regions are represented.  This does not change the object itself, just
-the representation, so these transformations can be made on a permanent
-region.
-*/
-void MoveEdges(R, dx, dy)
-       register struct region *R; /* region to modify                        */
-       register fractpel dx,dy;  /* delta X and Y to move edge list by       */
-{
-       register struct edgelist *edge;  /* for looping through edges         */
-       R->origin.x += dx;
-       R->origin.y += dy;
-       R->ending.x += dx;
-       R->ending.y += dy;
-       if (R->thresholded != NULL) {
-               R->thresholded->origin.x -= dx;
-               R->thresholded->origin.y -= dy;
-       }
-/*
-From now on we will deal with dx and dy as integer pel values:
-*/
-       dx = NEARESTPEL(dx);
-       dy = NEARESTPEL(dy);
-       if (dx == 0 && dy == 0)
-               return;
-       R->xmin += dx;
-       R->xmax += dx;
-       R->ymin += dy;
-       R->ymax += dy;
-       for (edge = R->anchor; VALIDEDGE(edge); edge = edge->link) {
-               edge->ymin += dy;
-               edge->ymax += dy;
-               if (dx != 0) {
-                       register int h;  /* loop index; height of edge        */
-                       register pel *Xp;  /* loop pointer to X values        */
-                       edge->xmin += dx;
-                       edge->xmax += dx;
-                       for (Xp = edge->xvalues, h = edge->ymax - edge->ymin;
-                                     --h >= 0; )
-                               *Xp++ += dx;
-               }
-       }
-}
-/*
-:h3.UnJumble() - Sort a Region Top to Bottom
-It is an open question whether it pays in general to do this.
-*/
-void UnJumble(region)
-       struct region *region;  /* region to sort                             */
-{
-       register struct edgelist *anchor;  /* new lists built here            */
-       register struct edgelist *edge;  /* edge pointer for loop             */
-       register struct edgelist *next;  /* ditto                             */
-       anchor = NULL;
-       for (edge=region->anchor; VALIDEDGE(edge); edge=next) {
-               if (edge->link == NULL)
-                       abort("UnJumble:  unpaired edge?");
-               next = edge->link->link;
-               edge->link->link = NULL;
-               anchor = SortSwath(anchor, edge, t1_SwathUnion);
-       }
-       if (edge != NULL)
-               vertjoin(anchor, edge);
-       region->anchor = anchor;
-       region->flag &= ~ISJUMBLED(ON);
-}
-/*
-*/
-static OptimizeRegion(R)
-       struct region *R;     /* region to optimize                           */
-{
-       register pel *xP;     /* pel pointer for inner loop                   */
-       register int x;       /* holds X value                                */
-       register int xmin,xmax;  /* holds X range                             */
-       register int h;       /* loop counter                                 */
-       register struct edgelist *e;  /* edgelist pointer for loop            */
-       R->flag |= ISRECTANGULAR(ON);
-       for (e = R->anchor; VALIDEDGE(e); e=e->link) {
-               xmin = MAXPEL;
-               xmax = MINPEL;
-               for (h = e->ymax - e->ymin, xP = e->xvalues; --h >= 0;) {
-                         x = *xP++;
-                         if (x < xmin)  xmin = x;
-                         if (x > xmax)  xmax = x;
-               }
-               if (xmin != xmax || (xmin != R->xmin && xmax != R->xmax))
-                       R->flag &= ~ISRECTANGULAR(ON);
-               if (xmin < e->xmin || xmax > e->xmax)
-                       abort("Tighten: existing edge bound was bad");
-               if (xmin < R->xmin || xmax > R->xmax)
-                       abort("Tighten: existing region bound was bad");
-               e->xmin = xmin;
-               e->xmax = xmax;
-       }
-       R->flag |= ISOPTIMIZED(ON);
-}
-/*
-:h2.Miscelaneous Routines
-:h3.MoreWorkArea() - Allocate New Space for "edge"
-Our strategy is to temporarily allocate an array to hold this
-unexpectedly large edge.  ChangeDirection frees this array any time
-it gets a shorter 'dy'.
-*/
-/*ARGSUSED*/
-void MoreWorkArea(R, x1, y1, x2, y2)
-       struct region *R;     /* region we are generating                     */
-       fractpel x1,y1;       /* starting point of line                       */
-       fractpel x2,y2;       /* ending point of line                         */
-{
-       register int idy;     /* integer dy of line                           */
-       idy = NEARESTPEL(y1) - NEARESTPEL(y2);
-       if (idy < 0)  idy = - idy;
-       /*
-       * we must add one to the delta for the number of run ends we
-       * need to store:
-       */
-       if (++idy > currentsize) {
-               IfTrace1((RegionDebug > 0),"Allocating edge of %d pels\n", idy);
-               if (currentworkarea != workedge)
-                       NonObjectFree(currentworkarea);
-               currentworkarea = (pel *)Allocate(0, NULL, idy * sizeof(pel));
-               currentsize = idy;
-       }
-       ChangeDirection(CD_CONTINUE, R, x1, y1, y2 - y1);
-}
-/*
-:h3.BoxClip() - Clip a Region to a Rectangle
-BoxClip also duplicates the region if it is permanent.  Note the
-clipping box is specified in REGION coordinates, that is, in
-coordinates relative to the region (0,0) point
-*/
-struct region *BoxClip(R, xmin, ymin, xmax, ymax)
-       register struct region *R;  /* region to clip                         */
-       register pel xmin,ymin;  /* upper left hand corner of rectangle       */
-       register pel xmax,ymax;  /* lower right hand corner                   */
-{
-       struct edgelist anchor;  /* pretend edgelist to facilitate discards   */
-       register struct edgelist *e,*laste;
-       IfTrace1((OffPageDebug),"BoxClip of %z:\n", R);
-       R = UniqueRegion(R);
-       if (xmin > R->xmin) {
-               IfTrace2((OffPageDebug),"BoxClip:  left clip old %d new %d\n",
-                                            (long) R->xmin, (long) xmin);
-               R->xmin = xmin;
-       }
-       if (xmax < R->xmax) {
-               IfTrace2((OffPageDebug),"BoxClip:  right clip old %d new %d\n",
-                                            (long) R->xmax, (long) xmax);
-               R->xmax = xmax;
-       }
-       if (ymin > R->ymin) {
-               IfTrace2((OffPageDebug),"BoxClip:  top clip old %d new %d\n",
-                                            (long) R->ymin, (long) ymin);
-               R->ymin = ymin;
-       }
-       if (ymax < R->ymax) {
-               IfTrace2((OffPageDebug),"BoxClip:  bottom clip old %d new %d\n",
-                                            (long) R->ymax, (long) ymax);
-               R->ymax = ymax;
-       }
-       laste = &anchor;
-       anchor.link = R->anchor;
-       for (e = R->anchor; VALIDEDGE(e); e = e->link) {
-               if (TOP(e) < ymin) {
-                       e->xvalues += ymin - e->ymin;
-                       e->ymin = ymin;
-               }
-               if (BOTTOM(e) > ymax)
-                       e->ymax = ymax;
-               if (TOP(e) >= BOTTOM(e)) {
-                       discard(laste, e->link->link);
-                       e = laste;
-                       continue;
-               }
-               if (e->xmin < xmin) {
-                       cedgemax(BOTTOM(e) - TOP(e), e->xvalues, xmin);
-                       e->xmin = xmin;
-                       e->xmax = MAX(e->xmax, xmin);
-               }
-               if (e->xmax > xmax) {
-                       cedgemin(BOTTOM(e) - TOP(e), e->xvalues, xmax);
-                       e->xmin = MIN(e->xmin, xmax);
-                       e->xmax = xmax;
-               }
-               laste = e;
-       }
-       R->anchor = anchor.link;
-       return(R);
-}
-#ifdef notdef
-/*
-:h3.CoerceRegion() - Force a TextPath Structure to Become a Region
-We also save the newly created region in the textpath structure, if the
-structure was permanent.  Then we don't have to do this again.  Why not
-save it all the time?  Well, we certainly could, but I suspect it
-wouldn't pay.  We would have to make this region permanent (because we
-couldn't have it be consumed) and this would probably require
-unnecessary CopyRegions in most cases.
-*/
-struct region *CoerceRegion(tp)
-       register struct textpath *tp;  /* input TEXTTYPE                     */
-{
-       struct segment *path; /* temporary character path                     */
-       struct region *R;     /* returned region                              */
-       R = Interior(path, EVENODDRULE);
-       return(R);
-}
-#endif
-/*
-:h3.RegionBounds() - Returns Bounding Box of a Region
-*/
-struct segment *RegionBounds(R)
-       register struct region *R;
-{
-       extern struct XYspace *IDENTITY;
-       register struct segment *path;  /* returned path                      */
-       path = BoxPath(IDENTITY, R->ymax - R->ymin, R->xmax - R->xmin);
-       path = Join(PathSegment(MOVETYPE, R->origin.x + TOFRACTPEL(R->xmin),
-                                         R->origin.y + TOFRACTPEL(R->ymin) ),
-                   path);
-       return(path);
-}
-/*
-:h2.Formatting/Dump Routines for Debug
-:h3.DumpArea() - Display a Region
-*/
-void DumpArea(area)
-       register struct region *area;
-{
-       IfTrace1(TRUE,"Dumping area %x,", area);
-       IfTrace4(TRUE," X %d:%d Y %d:%d;", (long) area->xmin,
-                      (long) area->xmax, (long) area->ymin,(long) area->ymax);
-       IfTrace4(TRUE," origin=(%p,%p), ending=(%p,%p)\n",
-               area->origin.x, area->origin.y, area->ending.x, area->ending.y);
-       DumpEdges(area->anchor);
-}
-#define  INSWATH(p, y0, y1)  (p != NULL && p->ymin == y0 && p->ymax == y1)
-/*
-:h3.DumpEdges() - Display Run End Lists (Edge Lists)
-*/
-static pel RegionDebugYMin = MINPEL;
-static pel RegionDebugYMax = MAXPEL;
-void DumpEdges(edges)
-       register struct edgelist *edges;
-{
-       register struct edgelist *p,*p2;
-       register pel ymin = MINPEL;
-       register pel ymax = MINPEL;
-       register int y;
-       if (edges == NULL) {
-               IfTrace0(TRUE,"    NULL area.\n");
-               return;
-       }
-       if (RegionDebug <= 1) {
-               for (p=edges; p != NULL; p = p->link) {
-                       edgecheck(p, ymin, ymax);
-                       ymin = p->ymin;  ymax = p->ymax;
-                       IfTrace3(TRUE,". at %x type=%d flag=%x",
-                                        p, (long) p->type,(long) p->flag);
-                       IfTrace4(TRUE," bounding box HxW is %dx%d at (%d,%d)\n",
-                               (long) ymax - ymin, (long) p->xmax - p->xmin,
-                               (long) p->xmin, (long) ymin);
-               }
-       }
-       else {
-               for (p2=edges; p2 != NULL; ) {
-                       edgecheck(p2, ymin, ymax);
-                       ymin = p2->ymin;
-                       ymax = p2->ymax;
-                       if (RegionDebug > 3 || (ymax > RegionDebugYMin
-                                   && ymin < RegionDebugYMax)) {
-                               IfTrace2 (TRUE,". Swath from %d to %d:\n",
-                                                              ymin, ymax);
-                               for (p=p2; INSWATH(p,ymin,ymax); p = p->link) {
-                                       IfTrace4(TRUE,". . at %x[%x] range %d:%d, ",
-                                                 p, (long) p->flag,
-                                                 (long) p->xmin, (long)p->xmax);
-                                       IfTrace1(TRUE, "subpath=%x,\n", p->subpath);
-                               }
-                       }
-                       for (y=MAX(ymin,RegionDebugYMin); y < MIN(ymax, RegionDebugYMax); y++) {
-                               IfTrace1(TRUE,". . . Y[%5d] ", (long) y);
-                               for (p=p2; INSWATH(p,ymin,ymax); p = p->link)
-                                       IfTrace1(TRUE,"%5d ",
-                                                (long) p->xvalues[y - ymin]);
-                               IfTrace0(TRUE,"\n");
-                       }
-                       while (INSWATH(p2, ymin, ymax))
-                               p2 = p2->link;
-               }
-       }
-}
-/*
-:h3.edgecheck() - For Debug, Verify that an Edge Obeys the Rules
-*/
-/*ARGSUSED*/
-static edgecheck(edge, oldmin, oldmax)
-       struct edgelist *edge;
-       int oldmin,oldmax;
-{
-       if (edge->type != EDGETYPE)
-               abort("EDGE ERROR: non EDGETYPE in list");
-/*
-The following check is not valid if the region is jumbled so I took it
-out:
-*/
-/*     if (edge->ymin < oldmax && edge->ymin != oldmin)
-               abort("EDGE ERROR: overlapping swaths"); */
-}