reactos/subsys/win32k/objects
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 = ®->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 != ®->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]