Commit in reactos/subsys/win32k/objects on MAIN
region.c+1084-1661.55 -> 1.56
ported CreatePolyPolygonRgn() and CreatePolygonRgn() from wine

reactos/subsys/win32k/objects
region.c 1.55 -> 1.56
diff -u -r1.55 -r1.56
--- region.c	18 May 2004 14:06:42 -0000	1.55
+++ region.c	18 May 2004 15:25:25 -0000	1.56
@@ -16,7 +16,104 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-/* $Id: region.c,v 1.55 2004/05/18 14:06:42 weiden Exp $ */
+
+/*
+ * GDI region objects. Shamelessly ripped out from the X11 distribution
+ * Thanks for the nice licence.
+ *
+ * Copyright 1993, 1994, 1995 Alexandre Julliard
+ * Modifications and additions: Copyright 1998 Huw Davies
+ *					  1999 Alex Korobka
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/************************************************************************
+
+Copyright (c) 1987, 1988  X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the X Consortium shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from the X Consortium.
+
+
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+			All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL 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.
+
+************************************************************************/
+/*
+ * The functions in this file implement the Region abstraction, similar to one
+ * used in the X11 sample server. A Region is simply an area, as the name
+ * implies, and is implemented as a "y-x-banded" array of rectangles. To
+ * explain: Each Region is made up of a certain number of rectangles sorted
+ * by y coordinate first, and then by x coordinate.
+ *
+ * Furthermore, the rectangles are banded such that every rectangle with a
+ * given upper-left y coordinate (y1) will have the same lower-right y
+ * coordinate (y2) and vice versa. If a rectangle has scanlines in a band, it
+ * will span the entire vertical distance of the band. This means that some
+ * areas that could be merged into a taller rectangle will be represented as
+ * several shorter rectangles to account for shorter rectangles to its left
+ * or right but within its "vertical scope".
+ *
+ * An added constraint on the rectangles is that they must cover as much
+ * horizontal area as possible. E.g. no two rectangles in a band are allowed
+ * to touch.
+ *
+ * Whenever possible, bands will be merged together to cover a greater vertical
+ * distance (and thus reduce the number of rectangles). Two bands can be merged
+ * only if the bottom of one touches the top of the other and they have
+ * rectangles in the same places (of the same width, of course). This maintains
+ * the y-x-banding that's so nice to have...
+ */
+
+/* $Id: region.c,v 1.56 2004/05/18 15:25:25 weiden Exp $ */
 #include <w32k.h>
 #include <win32k/float.h>
 
@@ -51,6 +148,247 @@
 	 (r1)->top < (r2)->bottom)
 
 /*
+ *  In scan converting polygons, we want to choose those pixels
+ *  which are inside the polygon.  Thus, we add .5 to the starting
+ *  x coordinate for both left and right edges.  Now we choose the
+ *  first pixel which is inside the pgon for the left edge and the
+ *  first pixel which is outside the pgon for the right edge.
+ *  Draw the left pixel, but not the right.
+ *
+ *  How to add .5 to the starting x coordinate:
+ *      If the edge is moving to the right, then subtract dy from the
+ *  error term from the general form of the algorithm.
+ *      If the edge is moving to the left, then add dy to the error term.
+ *
+ *  The reason for the difference between edges moving to the left
+ *  and edges moving to the right is simple:  If an edge is moving
+ *  to the right, then we want the algorithm to flip immediately.
+ *  If it is moving to the left, then we don't want it to flip until
+ *  we traverse an entire pixel.
+ */
+#define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) { \
+    int dx;      /* local storage */ \
+\
+    /* \
+     *  if the edge is horizontal, then it is ignored \
+     *  and assumed not to be processed.  Otherwise, do this stuff. \
+     */ \
+    if ((dy) != 0) { \
+        xStart = (x1); \
+        dx = (x2) - xStart; \
+        if (dx < 0) { \
+            m = dx / (dy); \
+            m1 = m - 1; \
+            incr1 = -2 * dx + 2 * (dy) * m1; \
+            incr2 = -2 * dx + 2 * (dy) * m; \
+            d = 2 * m * (dy) - 2 * dx - 2 * (dy); \
+        } else { \
+            m = dx / (dy); \
+            m1 = m + 1; \
+            incr1 = 2 * dx - 2 * (dy) * m1; \
+            incr2 = 2 * dx - 2 * (dy) * m; \
+            d = -2 * m * (dy) + 2 * dx; \
+        } \
+    } \
+}
+
+#define BRESINCRPGON(d, minval, m, m1, incr1, incr2) { \
+    if (m1 > 0) { \
+        if (d > 0) { \
+            minval += m1; \
+            d += incr1; \
+        } \
+        else { \
+            minval += m; \
+            d += incr2; \
+        } \
+    } else {\
+        if (d >= 0) { \
+            minval += m1; \
+            d += incr1; \
+        } \
+        else { \
+            minval += m; \
+            d += incr2; \
+        } \
+    } \
+}
+
+/*
+ *     This structure contains all of the information needed
+ *     to run the bresenham algorithm.
+ *     The variables may be hardcoded into the declarations
+ *     instead of using this structure to make use of
+ *     register declarations.
+ */
+typedef struct {
+    INT minor_axis;	/* minor axis        */
+    INT d;		/* decision variable */
+    INT m, m1;       	/* slope and slope+1 */
+    INT incr1, incr2;	/* error increments */
+} BRESINFO;
+
+
+#define BRESINITPGONSTRUCT(dmaj, min1, min2, bres) \
+	BRESINITPGON(dmaj, min1, min2, bres.minor_axis, bres.d, \
+                     bres.m, bres.m1, bres.incr1, bres.incr2)
+
+#define BRESINCRPGONSTRUCT(bres) \
+        BRESINCRPGON(bres.d, bres.minor_axis, bres.m, bres.m1, bres.incr1, bres.incr2)
+
+
+
+/*
+ *     These are the data structures needed to scan
+ *     convert regions.  Two different scan conversion
+ *     methods are available -- the even-odd method, and
+ *     the winding number method.
+ *     The even-odd rule states that a point is inside
+ *     the polygon if a ray drawn from that point in any
+ *     direction will pass through an odd number of
+ *     path segments.
+ *     By the winding number rule, a point is decided
+ *     to be inside the polygon if a ray drawn from that
+ *     point in any direction passes through a different
+ *     number of clockwise and counter-clockwise path
+ *     segments.
+ *
+ *     These data structures are adapted somewhat from
+ *     the algorithm in (Foley/Van Dam) for scan converting
+ *     polygons.
+ *     The basic algorithm is to start at the top (smallest y)
+ *     of the polygon, stepping down to the bottom of
+ *     the polygon by incrementing the y coordinate.  We
+ *     keep a list of edges which the current scanline crosses,
+ *     sorted by x.  This list is called the Active Edge Table (AET)
+ *     As we change the y-coordinate, we update each entry in
+ *     in the active edge table to reflect the edges new xcoord.
+ *     This list must be sorted at each scanline in case
+ *     two edges intersect.
+ *     We also keep a data structure known as the Edge Table (ET),
+ *     which keeps track of all the edges which the current
+ *     scanline has not yet reached.  The ET is basically a
+ *     list of ScanLineList structures containing a list of
+ *     edges which are entered at a given scanline.  There is one
+ *     ScanLineList per scanline at which an edge is entered.
+ *     When we enter a new edge, we move it from the ET to the AET.
+ *
+ *     From the AET, we can implement the even-odd rule as in
+ *     (Foley/Van Dam).
+ *     The winding number rule is a little trickier.  We also
+ *     keep the EdgeTableEntries in the AET linked by the
+ *     nextWETE (winding EdgeTableEntry) link.  This allows
+ *     the edges to be linked just as before for updating
+ *     purposes, but only uses the edges linked by the nextWETE
+ *     link as edges representing spans of the polygon to
+ *     drawn (as with the even-odd rule).
+ */
+
+/*
+ * for the winding number rule
+ */
+#define CLOCKWISE          1
+#define COUNTERCLOCKWISE  -1
+
+typedef struct _EdgeTableEntry {
+     INT ymax;           /* ycoord at which we exit this edge. */
+     BRESINFO bres;        /* Bresenham info to run the edge     */
+     struct _EdgeTableEntry *next;       /* next in the list     */
+     struct _EdgeTableEntry *back;       /* for insertion sort   */
+     struct _EdgeTableEntry *nextWETE;   /* for winding num rule */
+     int ClockWise;        /* flag for winding number rule       */
+} EdgeTableEntry;
+
+
+typedef struct _ScanLineList{
+     INT scanline;            /* the scanline represented */
+     EdgeTableEntry *edgelist;  /* header node              */
+     struct _ScanLineList *next;  /* next in the list       */
+} ScanLineList;
+
+
+typedef struct {
+     INT ymax;               /* ymax for the polygon     */
+     INT ymin;               /* ymin for the polygon     */
+     ScanLineList scanlines;   /* header node              */
+} EdgeTable;
+
+
+/*
+ * Here is a struct to help with storage allocation
+ * so we can allocate a big chunk at a time, and then take
+ * pieces from this heap when we need to.
+ */
+#define SLLSPERBLOCK 25
+
+typedef struct _ScanLineListBlock {
+     ScanLineList SLLs[SLLSPERBLOCK];
+     struct _ScanLineListBlock *next;
+} ScanLineListBlock;
+
+
+/*
+ *
+ *     a few macros for the inner loops of the fill code where
+ *     performance considerations don't allow a procedure call.
+ *
+ *     Evaluate the given edge at the given scanline.
+ *     If the edge has expired, then we leave it and fix up
+ *     the active edge table; otherwise, we increment the
+ *     x value to be ready for the next scanline.
+ *     The winding number rule is in effect, so we must notify
+ *     the caller when the edge has been removed so he
+ *     can reorder the Winding Active Edge Table.
+ */
+#define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) { \
+   if (pAET->ymax == y) {          /* leaving this edge */ \
+      pPrevAET->next = pAET->next; \
+      pAET = pPrevAET->next; \
+      fixWAET = 1; \
+      if (pAET) \
+         pAET->back = pPrevAET; \
+   } \
+   else { \
+      BRESINCRPGONSTRUCT(pAET->bres); \
+      pPrevAET = pAET; \
+      pAET = pAET->next; \
+   } \
+}
+
+
+/*
+ *     Evaluate the given edge at the given scanline.
+ *     If the edge has expired, then we leave it and fix up
+ *     the active edge table; otherwise, we increment the
+ *     x value to be ready for the next scanline.
+ *     The even-odd rule is in effect.
+ */
+#define EVALUATEEDGEEVENODD(pAET, pPrevAET, y) { \
+   if (pAET->ymax == y) {          /* leaving this edge */ \
+      pPrevAET->next = pAET->next; \
+      pAET = pPrevAET->next; \
+      if (pAET) \
+         pAET->back = pPrevAET; \
+   } \
+   else { \
+      BRESINCRPGONSTRUCT(pAET->bres); \
+      pPrevAET = pAET; \
+      pAET = pAET->next; \
+   } \
+}
+
+/**************************************************************************
+ *
+ *    Poly Regions
+ *
+ *************************************************************************/
+
+#define LARGE_COORDINATE  0x7fffffff /* FIXME */
+#define SMALL_COORDINATE  0x80000000
+
+
+
+/*
  *   Check to see if there is enough memory in the present region.
  */
 static inline int xmemcheck(ROSRGNDATA *reg, PRECT *rect, PRECT *firstrect ) {
@@ -1692,171 +2030,6 @@
                                  SafeRect.right - SafeRect.left, SafeRect.bottom - SafeRect.top);
 }
 
-HRGN FASTCALL
-IntCreatePolyPolgonRgn(PPOINT pt,
-                       PINT PolyCounts,
-		       INT Count,
-                       INT PolyFillMode)
-{
-  return (HRGN)0;
-}
-
-HRGN
-STDCALL
-NtGdiCreatePolygonRgn(CONST PPOINT  pt,
-                      INT  Count,
-                      INT  PolyFillMode)
-{
-   POINT *SafePoints;
-   NTSTATUS Status;
-   HRGN hRgn;
-   
-   
-   if (pt == NULL || Count == 0 ||
-       (PolyFillMode != WINDING && PolyFillMode != ALTERNATE))
-   {
-      /* Windows doesn't set a last error here */
-      return (HRGN)0;
-   }
-   
-   if (Count == 1)
-   {
-      /* can't create a region with only one point! */
-      SetLastWin32Error(ERROR_INVALID_PARAMETER);
-      return (HRGN)0;
-   }
-   
-   if (Count == 2)
-   {
-      /* Windows creates an empty region! */
-      ROSRGNDATA *rgn;
-      
-      if(!(hRgn = RGNDATA_AllocRgn(1)))
-      {
-	 return (HRGN)0;
-      }
-      if(!(rgn = RGNDATA_LockRgn(hRgn)))
-      {
-        NtGdiDeleteObject(hRgn);
-	return (HRGN)0;
-      }
-      
-      EMPTY_REGION(rgn);
-      
-      RGNDATA_UnlockRgn(hRgn);
-      return hRgn;
-   }
-   
-   if (!(SafePoints = ExAllocatePool(PagedPool, Count * sizeof(POINT))))
-   {
-      SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
-      return (HRGN)0;
-   }
-   
-   Status = MmCopyFromCaller(SafePoints, pt, Count * sizeof(POINT));
-   if (!NT_SUCCESS(Status))
-   {
-      ExFreePool(SafePoints);
-      SetLastNtError(Status);
-      return (HRGN)0;
-   }
-   
-   hRgn = IntCreatePolyPolgonRgn(SafePoints, &Count, 1, PolyFillMode);
-   
-   ExFreePool(SafePoints);
-   return hRgn;
-}
-
-HRGN
-STDCALL
-NtGdiCreatePolyPolygonRgn(CONST PPOINT  pt,
-                          CONST PINT  PolyCounts,
-                          INT  Count,
-                          INT  PolyFillMode)
-{
-   POINT *Safept;
-   INT *SafePolyCounts;
-   INT nPoints, nEmpty, nInvalid, i;
-   HRGN hRgn;
-   NTSTATUS Status;
-   
-   if (pt == NULL || PolyCounts == NULL || Count == 0 ||
-       (PolyFillMode != WINDING && PolyFillMode != ALTERNATE))
-   {
-      /* Windows doesn't set a last error here */
-      return (HRGN)0;
-   }
-   
-   if (!(SafePolyCounts = ExAllocatePool(PagedPool, Count * sizeof(INT))))
-   {
-      SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
-      return (HRGN)0;
-   }
-   
-   Status = MmCopyFromCaller(SafePolyCounts, PolyCounts, Count * sizeof(INT));
-   if (!NT_SUCCESS(Status))
-   {
-      ExFreePool(SafePolyCounts);
-      SetLastNtError(Status);
-      return (HRGN)0;
-   }
-   
-   /* validate poligons */
-   nPoints = 0;
-   nEmpty = 0;
-   nInvalid = 0;
-   for (i = 0; i < Count; i++)
-   {
-      if (SafePolyCounts[i] == 0)
-      {
-         nEmpty++;
-      }
-      if (SafePolyCounts[i] == 1)
-      {
-         nInvalid++;
-      }
-      nPoints += SafePolyCounts[i];
-   }
-   
-   if (nEmpty == Count)
-   {
-      /* if all polygon counts are zero, return without setting a last error code. */
-      ExFreePool(SafePolyCounts);
-      return (HRGN)0;
-   }
-   if (nInvalid != 0)
-   {
-     /* if at least one poly count is 1, fail */
-     ExFreePool(SafePolyCounts);
-     SetLastWin32Error(ERROR_INVALID_PARAMETER);
-     return (HRGN)0;
-   }
-   
-   /* copy points */
-   if (!(Safept = ExAllocatePool(PagedPool, nPoints * sizeof(POINT))))
-   {
-      ExFreePool(SafePolyCounts);
-      SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
-      return (HRGN)0;
-   }
-   
-   Status = MmCopyFromCaller(Safept, pt, nPoints * sizeof(POINT));
-   if (!NT_SUCCESS(Status))
-   {
-      ExFreePool(Safept);
-      ExFreePool(SafePolyCounts);
-      SetLastNtError(Status);
-      return (HRGN)0;
-   }
-   
-   /* now we're ready to calculate the region safely */
-   hRgn = IntCreatePolyPolgonRgn(Safept, SafePolyCounts, Count, PolyFillMode);
-   
-   ExFreePool(Safept);
-   ExFreePool(SafePolyCounts);
-   return hRgn;
-}
-
 HRGN STDCALL
 NtGdiCreateRectRgn(INT LeftRect, INT TopRect, INT RightRect, INT BottomRect)
 {
@@ -2463,4 +2636,749 @@
     RGNDATA_UnlockRgn( hrgn );
     return size + sizeof(RGNDATAHEADER);
 }
+
+
+/***********************************************************************
+ *     REGION_InsertEdgeInET
+ *
+ *     Insert the given edge into the edge table.
+ *     First we must find the correct bucket in the
+ *     Edge table, then find the right slot in the
+ *     bucket.  Finally, we can insert it.
+ *
+ */
+static void REGION_InsertEdgeInET(EdgeTable *ET, EdgeTableEntry *ETE,
+                INT scanline, ScanLineListBlock **SLLBlock, INT *iSLLBlock)
+
+{
+    EdgeTableEntry *start, *prev;
+    ScanLineList *pSLL, *pPrevSLL;
+    ScanLineListBlock *tmpSLLBlock;
+
+    /*
+     * find the right bucket to put the edge into
+     */
+    pPrevSLL = &ET->scanlines;
+    pSLL = pPrevSLL->next;
+    while (pSLL && (pSLL->scanline < scanline))
+    {
+        pPrevSLL = pSLL;
+        pSLL = pSLL->next;
+    }
+
+    /*
+     * reassign pSLL (pointer to ScanLineList) if necessary
+     */
+    if ((!pSLL) || (pSLL->scanline > scanline))
+    {
+        if (*iSLLBlock > SLLSPERBLOCK-1)
+        {
+            tmpSLLBlock = ExAllocatePoolWithTag( PagedPool, sizeof(ScanLineListBlock), TAG_REGION);
+	    if(!tmpSLLBlock)
+	    {
+	        DPRINT1("REGION_InsertEdgeInETL(): Can't alloc SLLB\n");
+	        /* FIXME - free resources? */
+		return;
+	    }
+            (*SLLBlock)->next = tmpSLLBlock;
+            tmpSLLBlock->next = (ScanLineListBlock *)NULL;
+            *SLLBlock = tmpSLLBlock;
+            *iSLLBlock = 0;
+        }
+        pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
+
+        pSLL->next = pPrevSLL->next;
+        pSLL->edgelist = (EdgeTableEntry *)NULL;
+        pPrevSLL->next = pSLL;
+    }
+    pSLL->scanline = scanline;
+
+    /*
+     * now insert the edge in the right bucket
+     */
+    prev = (EdgeTableEntry *)NULL;
+    start = pSLL->edgelist;
+    while (start && (start->bres.minor_axis < ETE->bres.minor_axis))
+    {
+        prev = start;
+        start = start->next;
+    }
+    ETE->next = start;
+
+    if (prev)
+        prev->next = ETE;
+    else
+        pSLL->edgelist = ETE;
+}
+
+/***********************************************************************
+ *     REGION_loadAET
+ *
+ *     This routine moves EdgeTableEntries from the
+ *     EdgeTable into the Active Edge Table,
+ *     leaving them sorted by smaller x coordinate.
+ *
+ */
+static void REGION_loadAET(EdgeTableEntry *AET, EdgeTableEntry *ETEs)
+{
+    EdgeTableEntry *pPrevAET;
+    EdgeTableEntry *tmp;
+
+    pPrevAET = AET;
+    AET = AET->next;
+    while (ETEs)
+    {
+        while (AET && (AET->bres.minor_axis < ETEs->bres.minor_axis))
+        {
+            pPrevAET = AET;
+            AET = AET->next;
+        }
+        tmp = ETEs->next;
+        ETEs->next = AET;
+        if (AET)
+            AET->back = ETEs;
+        ETEs->back = pPrevAET;
+        pPrevAET->next = ETEs;
+        pPrevAET = ETEs;
+
+        ETEs = tmp;
+    }
+}
+
+/***********************************************************************
+ *     REGION_computeWAET
+ *
+ *     This routine links the AET by the
+ *     nextWETE (winding EdgeTableEntry) link for
+ *     use by the winding number rule.  The final
+ *     Active Edge Table (AET) might look something
+ *     like:
+ *
+ *     AET
+ *     ----------  ---------   ---------
+ *     |ymax    |  |ymax    |  |ymax    |
+ *     | ...    |  |...     |  |...     |
+ *     |next    |->|next    |->|next    |->...
+ *     |nextWETE|  |nextWETE|  |nextWETE|
+ *     ---------   ---------   ^--------
+ *         |                   |       |
+ *         V------------------->       V---> ...
+ *
+ */
+static void REGION_computeWAET(EdgeTableEntry *AET)
+{
+    register EdgeTableEntry *pWETE;
+    register int inside = 1;
+    register int isInside = 0;
+
+    AET->nextWETE = (EdgeTableEntry *)NULL;
+    pWETE = AET;
+    AET = AET->next;
+    while (AET)
+    {
+        if (AET->ClockWise)
+            isInside++;
+        else
+            isInside--;
+
+        if ((!inside && !isInside) ||
+            ( inside &&  isInside))
+        {
+            pWETE->nextWETE = AET;
+            pWETE = AET;
+            inside = !inside;
+        }
+        AET = AET->next;
+    }
+    pWETE->nextWETE = (EdgeTableEntry *)NULL;
+}
+
+/***********************************************************************
+ *     REGION_InsertionSort
+ *
+ *     Just a simple insertion sort using
+ *     pointers and back pointers to sort the Active
+ *     Edge Table.
+ *
+ */
+static BOOL REGION_InsertionSort(EdgeTableEntry *AET)
+{
+    EdgeTableEntry *pETEchase;
+    EdgeTableEntry *pETEinsert;
+    EdgeTableEntry *pETEchaseBackTMP;
+    BOOL changed = FALSE;
+
+    AET = AET->next;
+    while (AET)
+    {
+        pETEinsert = AET;
+        pETEchase = AET;
+        while (pETEchase->back->bres.minor_axis > AET->bres.minor_axis)
+            pETEchase = pETEchase->back;
+
+        AET = AET->next;
+        if (pETEchase != pETEinsert)
+        {
+            pETEchaseBackTMP = pETEchase->back;
+            pETEinsert->back->next = AET;
+            if (AET)
+                AET->back = pETEinsert->back;
+            pETEinsert->next = pETEchase;
+            pETEchase->back->next = pETEinsert;
+            pETEchase->back = pETEinsert;
+            pETEinsert->back = pETEchaseBackTMP;
+            changed = TRUE;
+        }
+    }
+    return changed;
+}
+
+/***********************************************************************
+ *     REGION_FreeStorage
+ *
+ *     Clean up our act.
+ */
+static void REGION_FreeStorage(ScanLineListBlock *pSLLBlock)
+{
+    ScanLineListBlock   *tmpSLLBlock;
+
+    while (pSLLBlock)
+    {
+        tmpSLLBlock = pSLLBlock->next;
+        ExFreePool( pSLLBlock );
+        pSLLBlock = tmpSLLBlock;
+    }
+}
+
+
+/***********************************************************************
+ *     REGION_PtsToRegion
+ *
+ *     Create an array of rectangles from a list of points.
+ */
+static int REGION_PtsToRegion(int numFullPtBlocks, int iCurPtBlock,
+		       POINTBLOCK *FirstPtBlock, ROSRGNDATA *reg)
+{
+    RECT *rects;
+    POINT *pts;
+    POINTBLOCK *CurPtBlock;
+    int i;
+    RECT *extents, *temp;
+    INT numRects;
+
+    extents = &reg->rdh.rcBound;
+
+    numRects = ((numFullPtBlocks * NUMPTSTOBUFFER) + iCurPtBlock) >> 1;
+
+    if(!(temp = ExAllocatePoolWithTag(PagedPool, numRects * sizeof(RECT), TAG_REGION)))
+    {
+      return 0;
+    }
+    if(reg->Buffer != NULL)
+    {
+      RtlCopyMemory(temp, reg->Buffer, reg->rdh.nCount * sizeof(RECT));
+      if(reg->Buffer != &reg->BuiltInRect)
+        ExFreePool(reg->Buffer);
+    }
+    reg->Buffer = temp;
+    
+    reg->rdh.nCount = numRects;
+    CurPtBlock = FirstPtBlock;
+    rects = reg->Buffer - 1;
+    numRects = 0;
+    extents->left = LARGE_COORDINATE,  extents->right = SMALL_COORDINATE;
+
+    for ( ; numFullPtBlocks >= 0; numFullPtBlocks--) {
+	/* the loop uses 2 points per iteration */
+	i = NUMPTSTOBUFFER >> 1;
+	if (!numFullPtBlocks)
+	    i = iCurPtBlock >> 1;
+	for (pts = CurPtBlock->pts; i--; pts += 2) {
+	    if (pts->x == pts[1].x)
+		continue;
+	    if (numRects && pts->x == rects->left && pts->y == rects->bottom &&
+		pts[1].x == rects->right &&
+		(numRects == 1 || rects[-1].top != rects->top) &&
+		(i && pts[2].y > pts[1].y)) {
+		rects->bottom = pts[1].y + 1;
+		continue;
+	    }
+	    numRects++;
+	    rects++;
+	    rects->left = pts->x;  rects->top = pts->y;
+	    rects->right = pts[1].x;  rects->bottom = pts[1].y + 1;
+	    if (rects->left < extents->left)
+		extents->left = rects->left;
+	    if (rects->right > extents->right)
+		extents->right = rects->right;
+        }
+	CurPtBlock = CurPtBlock->next;
+    }
+
+    if (numRects) {
+	extents->top = reg->Buffer->top;
+	extents->bottom = rects->bottom;
+    } else {
+	extents->left = 0;
+	extents->top = 0;
+	extents->right = 0;
+	extents->bottom = 0;
+    }
+    reg->rdh.nCount = numRects;
+
+    return(TRUE);
+}
+
+/***********************************************************************
+ *     REGION_CreateEdgeTable
+ *
+ *     This routine creates the edge table for
+ *     scan converting polygons.
+ *     The Edge Table (ET) looks like:
+ *
+ *    EdgeTable
+ *     --------
+ *    |  ymax  |        ScanLineLists
+ *    |scanline|-->------------>-------------->...
+ *     --------   |scanline|   |scanline|
+ *                |edgelist|   |edgelist|
+ *                ---------    ---------
+ *                    |             |
+ *                    |             |
+ *                    V             V
+ *              list of ETEs   list of ETEs
+ *
+ *     where ETE is an EdgeTableEntry data structure,
+ *     and there is one ScanLineList per scanline at
+ *     which an edge is initially entered.
+ *
+ */
+static void REGION_CreateETandAET(const INT *Count, INT nbpolygons,
+            const POINT *pts, EdgeTable *ET, EdgeTableEntry *AET,
+            EdgeTableEntry *pETEs, ScanLineListBlock *pSLLBlock)
+{
+    const POINT *top, *bottom;
+    const POINT *PrevPt, *CurrPt, *EndPt;
+    INT poly, count;
+    int iSLLBlock = 0;
+    int dy;
+
+
+    /*
+     *  initialize the Active Edge Table
+     */
+    AET->next = (EdgeTableEntry *)NULL;
+    AET->back = (EdgeTableEntry *)NULL;
+    AET->nextWETE = (EdgeTableEntry *)NULL;
+    AET->bres.minor_axis = SMALL_COORDINATE;
+
+    /*
+     *  initialize the Edge Table.
+     */
+    ET->scanlines.next = (ScanLineList *)NULL;
+    ET->ymax = SMALL_COORDINATE;
+    ET->ymin = LARGE_COORDINATE;
+    pSLLBlock->next = (ScanLineListBlock *)NULL;
+
+    EndPt = pts - 1;
+    for(poly = 0; poly < nbpolygons; poly++)
+    {
+        count = Count[poly];
+        EndPt += count;
+        if(count < 2)
+	    continue;
+
+	PrevPt = EndPt;
+
+    /*
+     *  for each vertex in the array of points.
+     *  In this loop we are dealing with two vertices at
+     *  a time -- these make up one edge of the polygon.
+     */
+	while (count--)
+	{
+	    CurrPt = pts++;
+
+        /*
+         *  find out which point is above and which is below.
+         */
+	    if (PrevPt->y > CurrPt->y)
+	    {
+	        bottom = PrevPt, top = CurrPt;
+		pETEs->ClockWise = 0;
+	    }
+	    else
+	    {
+	        bottom = CurrPt, top = PrevPt;
+		pETEs->ClockWise = 1;
+	    }
+
+        /*
+         * don't add horizontal edges to the Edge table.
+         */
+	    if (bottom->y != top->y)
+	    {
+	        pETEs->ymax = bottom->y-1;
+				/* -1 so we don't get last scanline */
+
+            /*
+             *  initialize integer edge algorithm
+             */
+		dy = bottom->y - top->y;
+		BRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres);
+
+		REGION_InsertEdgeInET(ET, pETEs, top->y, &pSLLBlock,
+								&iSLLBlock);
+
+		if (PrevPt->y > ET->ymax)
+		  ET->ymax = PrevPt->y;
+		if (PrevPt->y < ET->ymin)
+		  ET->ymin = PrevPt->y;
+		pETEs++;
+	    }
+
+	    PrevPt = CurrPt;
+	}
+    }
+}
+
+HRGN FASTCALL
+IntCreatePolyPolgonRgn(POINT *Pts,
+                       INT *Count,
+		       INT nbpolygons,
+                       INT mode)
+{
+    HRGN hrgn;
+    ROSRGNDATA *region;
+    EdgeTableEntry *pAET;   /* Active Edge Table       */
+    INT y;                /* current scanline        */
+    int iPts = 0;           /* number of pts in buffer */
+    EdgeTableEntry *pWETE;  /* Winding Edge Table Entry*/
+    ScanLineList *pSLL;     /* current scanLineList    */
+    POINT *pts;           /* output buffer           */
+    EdgeTableEntry *pPrevAET;        /* ptr to previous AET     */
+    EdgeTable ET;                    /* header node for ET      */
+    EdgeTableEntry AET;              /* header node for AET     */
+    EdgeTableEntry *pETEs;           /* EdgeTableEntries pool   */
+    ScanLineListBlock SLLBlock;      /* header for scanlinelist */
+    int fixWAET = FALSE;
+    POINTBLOCK FirstPtBlock, *curPtBlock; /* PtBlock buffers    */
+    POINTBLOCK *tmpPtBlock;
+    int numFullPtBlocks = 0;
+    INT poly, total;
+
+    if(!(hrgn = RGNDATA_AllocRgn(nbpolygons)))
+        return 0;
+    if(!(region = RGNDATA_LockRgn(hrgn)))
+    {
+      NtGdiDeleteObject(hrgn);
+      return 0;
+    }
+
+    /* special case a rectangle */
+
+    if (((nbpolygons == 1) && ((*Count == 4) ||
+       ((*Count == 5) && (Pts[4].x == Pts[0].x) && (Pts[4].y == Pts[0].y)))) &&
+	(((Pts[0].y == Pts[1].y) &&
+	  (Pts[1].x == Pts[2].x) &&
+	  (Pts[2].y == Pts[3].y) &&
+	  (Pts[3].x == Pts[0].x)) ||
+	 ((Pts[0].x == Pts[1].x) &&
+	  (Pts[1].y == Pts[2].y) &&
+	  (Pts[2].x == Pts[3].x) &&
+	  (Pts[3].y == Pts[0].y))))
+    {
+        RGNDATA_UnlockRgn( hrgn );
+	NtGdiSetRectRgn( hrgn, min(Pts[0].x, Pts[2].x), min(Pts[0].y, Pts[2].y),
+		            max(Pts[0].x, Pts[2].x), max(Pts[0].y, Pts[2].y) );
+	return hrgn;
+    }
+
+    for(poly = total = 0; poly < nbpolygons; poly++)
+        total += Count[poly];
+    if (! (pETEs = ExAllocatePoolWithTag( PagedPool, sizeof(EdgeTableEntry) * total, TAG_REGION )))
+    {
+        NtGdiDeleteObject( hrgn );
+	return 0;
+    }
+    pts = FirstPtBlock.pts;
+    REGION_CreateETandAET(Count, nbpolygons, Pts, &ET, &AET, pETEs, &SLLBlock);
[truncated at 1000 lines; 279 more skipped]
CVSspam 0.2.8