[Win32k]
[reactos.git] / reactos / subsystems / win32 / win32k / objects / region.c
index 77d7b4d..d0bd3ba 100644 (file)
@@ -113,7 +113,7 @@ SOFTWARE.
  * the y-x-banding that's so nice to have...
  */
 
-#include <w32k.h>
+#include <win32k.h>
 
 #define NDEBUG
 #include <debug.h>
@@ -467,7 +467,7 @@ IntDumpRegion(HRGN hRgn)
 {
     ROSRGNDATA *Data;
 
-    Data = REGION_LockRgn(hRgn);
+    Data = RGNOBJAPI_Lock(hRgn, NULL);
     if (Data == NULL)
     {
         DbgPrint("IntDumpRegion called with invalid region!\n");
@@ -482,7 +482,7 @@ IntDumpRegion(HRGN hRgn)
              Data->rdh.rcBound.bottom,
              Data->rdh.iType);
 
-    REGION_UnlockRgn(Data);
+    RGNOBJAPI_Unlock(Data);
 }
 #endif /* not NDEBUG */
 
@@ -607,42 +607,38 @@ REGION_CropAndOffsetRegion(
         else
         {
             xrect = ExAllocatePoolWithTag(PagedPool, rgnSrc->rdh.nCount * sizeof(RECT), TAG_REGION);
+                       if(!xrect)
+                               return FALSE;
             if (rgnDst->Buffer && rgnDst->Buffer != &rgnDst->rdh.rcBound)
                 ExFreePoolWithTag(rgnDst->Buffer, TAG_REGION); //free the old buffer. will be assigned to xrect below.
         }
 
-        if (xrect)
+        if (rgnDst != rgnSrc)
         {
-            ULONG i;
-
-            if (rgnDst != rgnSrc)
-            {
-                *rgnDst = *rgnSrc;
-            }
+            *rgnDst = *rgnSrc;
+        }
 
-            if (off->x || off->y)
-            {
-                for (i = 0; i < rgnDst->rdh.nCount; i++)
-                {
-                    xrect[i].left = (rgnSrc->Buffer + i)->left + off->x;
-                    xrect[i].right = (rgnSrc->Buffer + i)->right + off->x;
-                    xrect[i].top = (rgnSrc->Buffer + i)->top + off->y;
-                    xrect[i].bottom = (rgnSrc->Buffer + i)->bottom + off->y;
-                }
-                rgnDst->rdh.rcBound.left   += off->x;
-                rgnDst->rdh.rcBound.right  += off->x;
-                rgnDst->rdh.rcBound.top    += off->y;
-                rgnDst->rdh.rcBound.bottom += off->y;
-            }
-            else
+        if (off->x || off->y)
+        {
+                       ULONG i;
+            for (i = 0; i < rgnDst->rdh.nCount; i++)
             {
-                COPY_RECTS(xrect, rgnSrc->Buffer, rgnDst->rdh.nCount);
+                xrect[i].left = (rgnSrc->Buffer + i)->left + off->x;
+                xrect[i].right = (rgnSrc->Buffer + i)->right + off->x;
+                xrect[i].top = (rgnSrc->Buffer + i)->top + off->y;
+                xrect[i].bottom = (rgnSrc->Buffer + i)->bottom + off->y;
             }
-
-            rgnDst->Buffer = xrect;
+            rgnDst->rdh.rcBound.left   += off->x;
+            rgnDst->rdh.rcBound.right  += off->x;
+            rgnDst->rdh.rcBound.top    += off->y;
+            rgnDst->rdh.rcBound.bottom += off->y;
         }
         else
-            return FALSE;
+        {
+            COPY_RECTS(xrect, rgnSrc->Buffer, rgnDst->rdh.nCount);
+        }
+
+        rgnDst->Buffer = xrect;
     }
     else if ((rect->left >= rect->right) ||
              (rect->top >= rect->bottom) ||
@@ -1650,7 +1646,8 @@ REGION_SubtractO(
                 pNextRect++;
             }
             r1++;
-            left = r1->left;
+            if (r1 != r1End)
+                left = r1->left;
         }
     }
 
@@ -1739,7 +1736,7 @@ REGION_XorRegion(
     trb = REGION_AllocRgnWithHandle(srb->rdh.nCount + 1);
     if (!trb)
     {
-        REGION_UnlockRgn(tra);
+        RGNOBJAPI_Unlock(tra);
         GreDeleteObject(htra);
         return;
     }
@@ -1748,8 +1745,8 @@ REGION_XorRegion(
     REGION_SubtractRegion(tra, sra, srb);
     REGION_SubtractRegion(trb, srb, sra);
     REGION_UnionRegion(dr, tra, trb);
-    REGION_UnlockRgn(tra);
-    REGION_UnlockRgn(trb);
+    RGNOBJAPI_Unlock(tra);
+    RGNOBJAPI_Unlock(trb);
 
     GreDeleteObject(htra);
     GreDeleteObject(htrb);
@@ -1863,26 +1860,26 @@ REGION_CreateFrameRgn(
     PRECTL rc;
     ULONG i;
 
-    if (!(srcObj = REGION_LockRgn(hSrc)))
+    if (!(srcObj = RGNOBJAPI_Lock(hSrc, NULL)))
     {
         return FALSE;
     }
     if (!REGION_NOT_EMPTY(srcObj))
     {
-        REGION_UnlockRgn(srcObj);
+        RGNOBJAPI_Unlock(srcObj);
         return FALSE;
     }
-    if (!(destObj = REGION_LockRgn(hDest)))
+    if (!(destObj = RGNOBJAPI_Lock(hDest, NULL)))
     {
-        REGION_UnlockRgn(srcObj);
+        RGNOBJAPI_Unlock(srcObj);
         return FALSE;
     }
 
     EMPTY_REGION(destObj);
     if (!REGION_CopyRegion(destObj, srcObj))
     {
-        REGION_UnlockRgn(destObj);
-        REGION_UnlockRgn(srcObj);
+        RGNOBJAPI_Unlock(destObj);
+        RGNOBJAPI_Unlock(srcObj);
         return FALSE;
     }
 
@@ -1891,8 +1888,8 @@ REGION_CreateFrameRgn(
         if (!REGION_CreateSimpleFrameRgn(destObj, x, y))
         {
             EMPTY_REGION(destObj);
-            REGION_UnlockRgn(destObj);
-            REGION_UnlockRgn(srcObj);
+            RGNOBJAPI_Unlock(destObj);
+            RGNOBJAPI_Unlock(srcObj);
             return FALSE;
         }
     }
@@ -1951,8 +1948,8 @@ REGION_CreateFrameRgn(
         REGION_SubtractRegion(destObj, srcObj, destObj);
     }
 
-    REGION_UnlockRgn(destObj);
-    REGION_UnlockRgn(srcObj);
+    RGNOBJAPI_Unlock(destObj);
+    RGNOBJAPI_Unlock(srcObj);
     return TRUE;
 }
 
@@ -1986,11 +1983,11 @@ REGION_LPTODP(
         goto done;
     }
 
-    if ( !(srcObj = REGION_LockRgn(hSrc)) )
+    if ( !(srcObj = RGNOBJAPI_Lock(hSrc, NULL)) )
         goto done;
-    if ( !(destObj = REGION_LockRgn(hDest)) )
+    if ( !(destObj = RGNOBJAPI_Lock(hDest, NULL)) )
     {
-        REGION_UnlockRgn(srcObj);
+        RGNOBJAPI_Unlock(srcObj);
         goto done;
     }
     EMPTY_REGION(destObj);
@@ -2021,8 +2018,8 @@ REGION_LPTODP(
     }
     ret = TRUE;
 
-    REGION_UnlockRgn(srcObj);
-    REGION_UnlockRgn(destObj);
+    RGNOBJAPI_Unlock(srcObj);
+    RGNOBJAPI_Unlock(destObj);
 
 done:
     return ret;
@@ -2034,13 +2031,13 @@ REGION_AllocRgnWithHandle(INT nReg)
 {
     HRGN hReg;
     PROSRGNDATA pReg;
-    
+
     pReg = (PROSRGNDATA)GDIOBJ_AllocObjWithHandle(GDI_OBJECT_TYPE_REGION);
     if(!pReg)
     {
         return NULL;
     }
-    
+
     hReg = pReg->BaseObject.hHmgr;
 
     if (nReg == 0 || nReg == 1)
@@ -2054,7 +2051,7 @@ REGION_AllocRgnWithHandle(INT nReg)
         pReg->Buffer = ExAllocatePoolWithTag(PagedPool, nReg * sizeof(RECT), TAG_REGION);
         if (!pReg->Buffer)
         {
-            REGION_UnlockRgn(pReg);
+            RGNOBJAPI_Unlock(pReg);
             GDIOBJ_FreeObjByHandle(hReg, GDI_OBJECT_TYPE_REGION);
             return NULL;
         }
@@ -2068,15 +2065,158 @@ REGION_AllocRgnWithHandle(INT nReg)
     return pReg;
 }
 
+//
+// Allocate User Space Region Handle.
+//
+PROSRGNDATA
+FASTCALL
+REGION_AllocUserRgnWithHandle(INT nRgn)
+{
+    PROSRGNDATA pRgn;
+    PGDI_TABLE_ENTRY Entry;
+
+    pRgn = REGION_AllocRgnWithHandle(nRgn);
+    if (pRgn)
+    {
+       Entry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, pRgn->BaseObject.hHmgr);
+       Entry->UserData = AllocateObjectAttr();
+    }
+    return pRgn;
+}
+
+PROSRGNDATA
+FASTCALL
+RGNOBJAPI_Lock(HRGN hRgn, PRGN_ATTR *ppRgn_Attr)
+{
+  PGDI_TABLE_ENTRY Entry;
+  PRGN_ATTR pRgn_Attr;
+  PROSRGNDATA pRgn = NULL;
+
+  pRgn = REGION_LockRgn(hRgn);
+
+  if (pRgn && GDIOBJ_OwnedByCurrentProcess(hRgn))
+  {
+     Entry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, hRgn);
+     pRgn_Attr = Entry->UserData;
+
+     if ( pRgn_Attr )
+     {
+        _SEH2_TRY
+        {
+           if ( !(pRgn_Attr->AttrFlags & ATTR_CACHED) &&
+                 pRgn_Attr->AttrFlags & (ATTR_RGN_VALID|ATTR_RGN_DIRTY) )
+           {
+              switch (pRgn_Attr->Flags)
+              {
+                  case NULLREGION:
+                     EMPTY_REGION( pRgn );
+                     break;
+
+                  case SIMPLEREGION:
+                     REGION_SetRectRgn( pRgn,
+                                        pRgn_Attr->Rect.left,
+                                        pRgn_Attr->Rect.top,
+                                        pRgn_Attr->Rect.right,
+                                        pRgn_Attr->Rect.bottom );
+                     break;
+              }
+              pRgn_Attr->AttrFlags &= ~ATTR_RGN_DIRTY;
+           }
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+        }
+        _SEH2_END;
+
+        if (ppRgn_Attr)
+           *ppRgn_Attr = pRgn_Attr;
+     }
+     else
+     {
+        if (ppRgn_Attr)
+           *ppRgn_Attr = NULL;
+     }
+  }
+  return pRgn;
+}
+
+VOID
+FASTCALL
+RGNOBJAPI_Unlock(PROSRGNDATA pRgn)
+{
+  PGDI_TABLE_ENTRY Entry;
+  PRGN_ATTR pRgn_Attr;
+
+  if (pRgn && GDIOBJ_OwnedByCurrentProcess(pRgn->BaseObject.hHmgr))
+  {
+     Entry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, pRgn->BaseObject.hHmgr);
+     pRgn_Attr = Entry->UserData;
+
+     if ( pRgn_Attr )
+     {
+        _SEH2_TRY
+        {
+           if ( pRgn_Attr->AttrFlags & ATTR_RGN_VALID )
+           {
+              pRgn_Attr->Flags = REGION_Complexity( pRgn );
+              pRgn_Attr->Rect.left   = pRgn->rdh.rcBound.left;
+              pRgn_Attr->Rect.top    = pRgn->rdh.rcBound.top;
+              pRgn_Attr->Rect.right  = pRgn->rdh.rcBound.right;
+              pRgn_Attr->Rect.bottom = pRgn->rdh.rcBound.bottom;
+           }
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+        }
+        _SEH2_END;
+     }
+  }
+  REGION_UnlockRgn(pRgn);
+}
+
+/*
+  System Regions:
+    These regions do not use attribute sections and when allocated, use gdiobj
+    level functions.
+*/
+//
+// System Region Functions
+//
+PROSRGNDATA
+FASTCALL
+IntSysCreateRectpRgn(INT LeftRect, INT TopRect, INT RightRect, INT BottomRect)
+{
+  PROSRGNDATA pRgn;
+
+  pRgn = (PROSRGNDATA)GDIOBJ_AllocObjWithHandle(GDI_OBJECT_TYPE_REGION);
+  if (!pRgn)
+  {
+     return NULL;
+  }
+  pRgn->Buffer = &pRgn->rdh.rcBound;
+  REGION_SetRectRgn(pRgn, LeftRect, TopRect, RightRect, BottomRect);
+  REGION_UnlockRgn(pRgn);
+  return pRgn;
+}
+
+HRGN
+FASTCALL
+IntSysCreateRectRgn(INT LeftRect, INT TopRect, INT RightRect, INT BottomRect)
+{
+  PROSRGNDATA pRgn = IntSysCreateRectpRgn(LeftRect,TopRect,RightRect,BottomRect);
+  return (pRgn ? pRgn->BaseObject.hHmgr : NULL);
+}
+
 BOOL INTERNAL_CALL
 REGION_Cleanup(PVOID ObjectBody)
 {
     PROSRGNDATA pRgn = (PROSRGNDATA)ObjectBody;
     if (pRgn->Buffer && pRgn->Buffer != &pRgn->rdh.rcBound)
-        ExFreePool(pRgn->Buffer);
+        ExFreePoolWithTag(pRgn->Buffer, TAG_REGION);
     return TRUE;
 }
 
+// use REGION_FreeRgnByHandle(hRgn); for systems regions.
 VOID FASTCALL
 REGION_Delete(PROSRGNDATA pRgn)
 {
@@ -2084,7 +2224,6 @@ REGION_Delete(PROSRGNDATA pRgn)
   REGION_FreeRgn(pRgn);
 }
 
-
 VOID FASTCALL
 IntGdiReleaseRaoRgn(PDC pDC)
 {
@@ -2095,7 +2234,6 @@ IntGdiReleaseRaoRgn(PDC pDC)
   RECTL_vSetEmptyRect(&pDC->erclClip);
 }
 
-
 VOID FASTCALL
 IntGdiReleaseVisRgn(PDC pDC)
 {
@@ -2185,1690 +2323,1610 @@ IntGdiCombineRgn(PROSRGNDATA destRgn,
            }
            else if (src2Rgn == NULL)
            {
-               DPRINT1("IntGdiCombineRgn requires hSrc2 != NULL for combine mode %d!\n", CombineMode);
+              DPRINT1("IntGdiCombineRgn requires hSrc2 != NULL for combine mode %d!\n", CombineMode);
+              EngSetLastError(ERROR_INVALID_HANDLE);
            }
         }
      }
+     else
+     {
+        DPRINT("IntGdiCombineRgn: hSrc1 unavailable\n");
+        EngSetLastError(ERROR_INVALID_HANDLE);
+     }
   }
   else
   {
      DPRINT("IntGdiCombineRgn: hDest unavailable\n");
-     result = ERROR;
+     EngSetLastError(ERROR_INVALID_HANDLE);
   }
   return result;
 }
 
-
-// NtGdi Exported Functions
-INT
-APIENTRY
-NtGdiCombineRgn(HRGN  hDest,
-                HRGN  hSrc1,
-                HRGN  hSrc2,
-                INT  CombineMode)
+INT FASTCALL
+REGION_GetRgnBox(
+    PROSRGNDATA Rgn,
+    PRECTL pRect
+)
 {
-    INT result = ERROR;
-    PROSRGNDATA destRgn, src1Rgn, src2Rgn;
+    DWORD ret;
 
-    destRgn = REGION_LockRgn(hDest);
-    if (destRgn)
+    if (Rgn)
     {
-        src1Rgn = REGION_LockRgn(hSrc1);
-        if (src1Rgn)
-        {
-            if (CombineMode == RGN_COPY)
-            {
-                if ( !REGION_CopyRegion(destRgn, src1Rgn) )
-                    return ERROR;
-                result = REGION_Complexity(destRgn);
-            }
-            else
-            {
-                src2Rgn = REGION_LockRgn(hSrc2);
-                if (src2Rgn)
-                {
-                    switch (CombineMode)
-                    {
-                    case RGN_AND:
-                        REGION_IntersectRegion(destRgn, src1Rgn, src2Rgn);
-                        break;
-                    case RGN_OR:
-                        REGION_UnionRegion(destRgn, src1Rgn, src2Rgn);
-                        break;
-                    case RGN_XOR:
-                        REGION_XorRegion(destRgn, src1Rgn, src2Rgn);
-                        break;
-                    case RGN_DIFF:
-                        REGION_SubtractRegion(destRgn, src1Rgn, src2Rgn);
-                        break;
-                    }
-                    REGION_UnlockRgn(src2Rgn);
-                    result = REGION_Complexity(destRgn);
-                }
-                else if (hSrc2 == NULL)
-                {
-                    DPRINT1("NtGdiCombineRgn requires hSrc2 != NULL for combine mode %d!\n", CombineMode);
-                }
-            }
-
-            REGION_UnlockRgn(src1Rgn);
-        }
+        *pRect = Rgn->rdh.rcBound;
+        ret = REGION_Complexity(Rgn);
 
-        REGION_UnlockRgn(destRgn);
-    }
-    else
-    {
-        DPRINT("NtGdiCombineRgn: hDest unavailable\n");
-        result = ERROR;
+        return ret;
     }
-
-    return result;
+    return 0; //if invalid region return zero
 }
 
-HRGN
-APIENTRY
-NtGdiCreateEllipticRgn(
-    INT Left,
-    INT Top,
-    INT Right,
-    INT Bottom
+INT APIENTRY
+IntGdiGetRgnBox(
+    HRGN hRgn,
+    PRECTL pRect
 )
 {
-    return NtGdiCreateRoundRectRgn(Left, Top, Right, Bottom,
-                                   Right - Left, Bottom - Top);
-}
-
-PROSRGNDATA
-FASTCALL
-IntGdiCreateRectRgn(INT LeftRect, INT TopRect, INT RightRect, INT BottomRect)
-{
-  PROSRGNDATA pRgn;
-
-  if (!(pRgn = REGION_AllocRgnWithHandle(1))) return NULL;
-
-  REGION_SetRectRgn(pRgn, LeftRect, TopRect, RightRect, BottomRect);
-  REGION_UnlockRgn(pRgn);
-  // Return pointer with Share locks.
-  pRgn = GDIOBJ_ShareLockObj(pRgn->BaseObject.hHmgr, GDI_OBJECT_TYPE_REGION);
-
-  return pRgn;
-}
-
-
-HRGN APIENTRY
-NtGdiCreateRectRgn(INT LeftRect, INT TopRect, INT RightRect, INT BottomRect)
-{
-    PROSRGNDATA pRgn;
-    HRGN hRgn;
+    PROSRGNDATA Rgn;
+    DWORD ret;
 
-    /* Allocate region data structure with space for 1 RECTL */
-    if (!(pRgn = REGION_AllocRgnWithHandle(1)))
+    if (!(Rgn = RGNOBJAPI_Lock(hRgn, NULL)))
     {
-        SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
-        return NULL;
+        return ERROR;
     }
-    hRgn = pRgn->BaseObject.hHmgr;
 
-    REGION_SetRectRgn(pRgn, LeftRect, TopRect, RightRect, BottomRect);
-    REGION_UnlockRgn(pRgn);
+    ret = REGION_GetRgnBox(Rgn, pRect);
+    RGNOBJAPI_Unlock(Rgn);
 
-    return hRgn;
+    return ret;
 }
 
-
-HRGN
-APIENTRY
-NtGdiCreateRoundRectRgn(
-    INT left,
-    INT top,
-    INT right,
-    INT bottom,
-    INT ellipse_width,
-    INT ellipse_height
+BOOL
+FASTCALL
+IntGdiPaintRgn(
+    PDC dc,
+    HRGN hRgn
 )
 {
-    PROSRGNDATA obj;
-    HRGN hrgn;
-    int asq, bsq, d, xd, yd;
-    RECTL rect;
+    HRGN tmpVisRgn;
+    PROSRGNDATA visrgn;
+    CLIPOBJ* ClipRegion;
+    BOOL bRet = FALSE;
+    POINTL BrushOrigin;
+    SURFACE *psurf;
+    PDC_ATTR pdcattr;
 
-    /* Make the dimensions sensible */
+    if (!dc) return FALSE;
+    pdcattr = dc->pdcattr;
 
-    if (left > right)
-    {
-        INT tmp = left;
-        left = right;
-        right = tmp;
-    }
-    if (top > bottom)
+    ASSERT(!(pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY)));
+
+    if (!(tmpVisRgn = IntSysCreateRectRgn(0, 0, 0, 0))) return FALSE;
+
+    // Transform region into device co-ords
+    if (!REGION_LPTODP(dc, tmpVisRgn, hRgn) ||
+         NtGdiOffsetRgn(tmpVisRgn, dc->ptlDCOrig.x, dc->ptlDCOrig.y) == ERROR)
     {
-        INT tmp = top;
-        top = bottom;
-        bottom = tmp;
+        REGION_FreeRgnByHandle(tmpVisRgn);
+        return FALSE;
     }
 
-    ellipse_width = abs(ellipse_width);
-    ellipse_height = abs(ellipse_height);
+    NtGdiCombineRgn(tmpVisRgn, tmpVisRgn, dc->rosdc.hGCClipRgn, RGN_AND);
 
-    /* Check parameters */
+    visrgn = RGNOBJAPI_Lock(tmpVisRgn, NULL);
+    if (visrgn == NULL)
+    {
+        REGION_FreeRgnByHandle(tmpVisRgn);
+        return FALSE;
+    }
 
-    if (ellipse_width > right-left) ellipse_width = right-left;
-    if (ellipse_height > bottom-top) ellipse_height = bottom-top;
+    ClipRegion = IntEngCreateClipRegion(visrgn->rdh.nCount,
+                                        visrgn->Buffer,
+                                        &visrgn->rdh.rcBound );
+    ASSERT(ClipRegion);
 
-    /* Check if we can do a normal rectangle instead */
+    BrushOrigin.x = pdcattr->ptlBrushOrigin.x;
+    BrushOrigin.y = pdcattr->ptlBrushOrigin.y;
+    psurf = dc->dclevel.pSurface;
+    /* FIXME - Handle psurf == NULL !!!! */
 
-    if ((ellipse_width < 2) || (ellipse_height < 2))
-        return NtGdiCreateRectRgn(left, top, right, bottom);
+    bRet = IntEngPaint(&psurf->SurfObj,
+                       ClipRegion,
+                       &dc->eboFill.BrushObject,
+                       &BrushOrigin,
+                       0xFFFF);//FIXME:don't know what to put here
 
-    /* Create region */
+    RGNOBJAPI_Unlock(visrgn);
+    REGION_FreeRgnByHandle(tmpVisRgn);
 
-    d = (ellipse_height < 128) ? ((3 * ellipse_height) >> 2) : 64;
-    if (!(obj = REGION_AllocRgnWithHandle(d))) return 0;
-    hrgn = obj->BaseObject.hHmgr;
-
-    /* Ellipse algorithm, based on an article by K. Porter */
-    /* in DDJ Graphics Programming Column, 8/89 */
-
-    asq = ellipse_width * ellipse_width / 4;        /* a^2 */
-    bsq = ellipse_height * ellipse_height / 4;      /* b^2 */
-    d = bsq - asq * ellipse_height / 2 + asq / 4;   /* b^2 - a^2b + a^2/4 */
-    xd = 0;
-    yd = asq * ellipse_height;                      /* 2a^2b */
-
-    rect.left   = left + ellipse_width / 2;
-    rect.right  = right - ellipse_width / 2;
-
-    /* Loop to draw first half of quadrant */
-
-    while (xd < yd)
-    {
-        if (d > 0)  /* if nearest pixel is toward the center */
-        {
-            /* move toward center */
-            rect.top = top++;
-            rect.bottom = rect.top + 1;
-            REGION_UnionRectWithRgn(obj, &rect);
-            rect.top = --bottom;
-            rect.bottom = rect.top + 1;
-            REGION_UnionRectWithRgn(obj, &rect);
-            yd -= 2*asq;
-            d  -= yd;
-        }
-        rect.left--;        /* next horiz point */
-        rect.right++;
-        xd += 2*bsq;
-        d  += bsq + xd;
-    }
-    /* Loop to draw second half of quadrant */
-
-    d += (3 * (asq-bsq) / 2 - (xd+yd)) / 2;
-    while (yd >= 0)
-    {
-        /* next vertical point */
-        rect.top = top++;
-        rect.bottom = rect.top + 1;
-        REGION_UnionRectWithRgn(obj, &rect);
-        rect.top = --bottom;
-        rect.bottom = rect.top + 1;
-        REGION_UnionRectWithRgn(obj, &rect);
-        if (d < 0)   /* if nearest pixel is outside ellipse */
-        {
-            rect.left--;     /* move away from center */
-            rect.right++;
-            xd += 2*bsq;
-            d  += xd;
-        }
-        yd -= 2*asq;
-        d  += asq - yd;
-    }
-    /* Add the inside rectangle */
-
-    if (top <= bottom)
-    {
-        rect.top = top;
-        rect.bottom = bottom;
-        REGION_UnionRectWithRgn(obj, &rect);
-    }
-
-    REGION_UnlockRgn(obj);
-    return hrgn;
-}
+    // Fill the region
+    return bRet;
+}
 
 BOOL
-APIENTRY
-NtGdiEqualRgn(
-    HRGN  hSrcRgn1,
-    HRGN  hSrcRgn2
+FASTCALL
+REGION_RectInRegion(
+    PROSRGNDATA Rgn,
+    const RECTL *rect
 )
 {
-    PROSRGNDATA rgn1, rgn2;
-    PRECTL tRect1, tRect2;
-    ULONG i;
-    BOOL bRet = FALSE;
+    PRECTL pCurRect, pRectEnd;
+    RECT rc;
 
-    if ( !(rgn1 = REGION_LockRgn(hSrcRgn1)) )
-        return ERROR;
+    /* swap the coordinates to make right >= left and bottom >= top */
+    /* (region building rectangles are normalized the same way) */
+    if( rect->top > rect->bottom) {
+        rc.top = rect->bottom;
+        rc.bottom = rect->top;
+    } else {
+        rc.top = rect->top;
+        rc.bottom = rect->bottom;
+    }
+    if( rect->right < rect->left) {
+        rc.right = rect->left;
+        rc.left = rect->right;
+    } else {
+        rc.right = rect->right;
+        rc.left = rect->left;
+    }
 
-    if ( !(rgn2 = REGION_LockRgn(hSrcRgn2)) )
+    /* this is (just) a useful optimization */
+    if ((Rgn->rdh.nCount > 0) && EXTENTCHECK(&Rgn->rdh.rcBound, &rc))
     {
-        REGION_UnlockRgn(rgn1);
-        return ERROR;
-    }
+        for (pCurRect = Rgn->Buffer, pRectEnd = pCurRect +
+         Rgn->rdh.nCount; pCurRect < pRectEnd; pCurRect++)
+        {
+            if (pCurRect->bottom <= rc.top)
+            continue;             /* not far enough down yet */
 
-    if (rgn1->rdh.nCount != rgn2->rdh.nCount ||
-            rgn1->rdh.nCount == 0 ||
-            rgn1->rdh.rcBound.left   != rgn2->rdh.rcBound.left ||
-            rgn1->rdh.rcBound.right  != rgn2->rdh.rcBound.right ||
-            rgn1->rdh.rcBound.top    != rgn2->rdh.rcBound.top ||
-            rgn1->rdh.rcBound.bottom != rgn2->rdh.rcBound.bottom)
-        goto exit;
+            if (pCurRect->top >= rc.bottom)
+                break;                /* too far down */
 
-    tRect1 = rgn1->Buffer;
-    tRect2 = rgn2->Buffer;
+            if (pCurRect->right <= rc.left)
+                continue;              /* not far enough over yet */
 
-    if (!tRect1 || !tRect2)
-        goto exit;
+            if (pCurRect->left >= rc.right) {
+                continue;
+            }
 
-    for (i=0; i < rgn1->rdh.nCount; i++)
-    {
-        if (tRect1[i].left   != tRect2[i].left ||
-                tRect1[i].right  != tRect2[i].right ||
-                tRect1[i].top    != tRect2[i].top ||
-                tRect1[i].bottom != tRect2[i].bottom)
-            goto exit;
+            return TRUE;
+        }
     }
-    bRet = TRUE;
-
-exit:
-    REGION_UnlockRgn(rgn1);
-    REGION_UnlockRgn(rgn2);
-    return bRet;
+    return FALSE;
 }
 
-HRGN
-APIENTRY
-NtGdiExtCreateRegion(
-    OPTIONAL LPXFORM Xform,
-    DWORD Count,
-    LPRGNDATA RgnData
+VOID
+FASTCALL
+REGION_SetRectRgn(
+    PROSRGNDATA rgn,
+    INT LeftRect,
+    INT TopRect,
+    INT RightRect,
+    INT BottomRect
 )
 {
-    HRGN hRgn;
-    PROSRGNDATA Region;
-    DWORD nCount = 0;
-    DWORD iType = 0;
-    DWORD dwSize = 0;
-    NTSTATUS Status = STATUS_SUCCESS;
-    MATRIX matrix;
+    PRECTL firstRect;
 
-    DPRINT("NtGdiExtCreateRegion\n");
-    _SEH2_TRY
-    {
-        ProbeForRead(RgnData, Count, 1);
-        nCount = RgnData->rdh.nCount;
-        iType = RgnData->rdh.iType;
-        dwSize = RgnData->rdh.dwSize;
-    }
-    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    if (LeftRect > RightRect)
     {
-        Status = _SEH2_GetExceptionCode();
+        INT tmp = LeftRect;
+        LeftRect = RightRect;
+        RightRect = tmp;
     }
-    _SEH2_END;
-    if (!NT_SUCCESS(Status))
+    if (TopRect > BottomRect)
     {
-        SetLastNtError(Status);
-        return NULL;
+        INT tmp = TopRect;
+        TopRect = BottomRect;
+        BottomRect = tmp;
     }
 
-    /* Check parameters, but don't set last error here */
-    if (Count < sizeof(RGNDATAHEADER) + nCount * sizeof(RECT) ||
-        iType != RDH_RECTANGLES ||
-        dwSize != sizeof(RGNDATAHEADER))
+    if ((LeftRect != RightRect) && (TopRect != BottomRect))
     {
-        return NULL;
+        firstRect = rgn->Buffer;
+        ASSERT(firstRect);
+        firstRect->left = rgn->rdh.rcBound.left = LeftRect;
+        firstRect->top = rgn->rdh.rcBound.top = TopRect;
+        firstRect->right = rgn->rdh.rcBound.right = RightRect;
+        firstRect->bottom = rgn->rdh.rcBound.bottom = BottomRect;
+        rgn->rdh.nCount = 1;
+        rgn->rdh.iType = RDH_RECTANGLES;
     }
-
-    Region = REGION_AllocRgnWithHandle(nCount);
-
-    if (Region == NULL)
+    else
     {
-        SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
-        return FALSE;
+        EMPTY_REGION(rgn);
     }
-    hRgn = Region->BaseObject.hHmgr;
+}
 
-    _SEH2_TRY
+INT
+FASTCALL
+IntGdiOffsetRgn(
+    PROSRGNDATA rgn,
+    INT XOffset,
+    INT YOffset )
+{
+    if (XOffset || YOffset)
     {
-        if (Xform)
-        {
-            ULONG ret;
-
-            /* Init the XFORMOBJ from the Xform struct */
-            Status = STATUS_INVALID_PARAMETER;
-            ret = XFORMOBJ_iSetXform((XFORMOBJ*)&matrix, (XFORML*)Xform);
+        int nbox = rgn->rdh.nCount;
+        PRECTL pbox = rgn->Buffer;
 
-            /* Check for error, also no scale and shear allowed */
-            if (ret != DDI_ERROR && ret != GX_GENERAL)
+        if (nbox && pbox)
+        {
+            while (nbox--)
             {
-                /* Apply the coordinate transformation on the rects */
-                if (XFORMOBJ_bApplyXform((XFORMOBJ*)&matrix,
-                                         XF_LTOL,
-                                         nCount * 2,
-                                         RgnData->Buffer,
-                                         Region->Buffer))
-                {
-                    Status = STATUS_SUCCESS;
-                }
+                pbox->left += XOffset;
+                pbox->right += XOffset;
+                pbox->top += YOffset;
+                pbox->bottom += YOffset;
+                pbox++;
+            }
+            if (rgn->Buffer != &rgn->rdh.rcBound)
+            {
+                rgn->rdh.rcBound.left += XOffset;
+                rgn->rdh.rcBound.right += XOffset;
+                rgn->rdh.rcBound.top += YOffset;
+                rgn->rdh.rcBound.bottom += YOffset;
             }
         }
-        else
-        {
-            /* Copy rect coordinates */
-            RtlCopyMemory(Region->Buffer,
-                          RgnData->Buffer,
-                          nCount * sizeof(RECT));
-        }
-    }
-    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
-    {
-        Status = _SEH2_GetExceptionCode();
-    }
-    _SEH2_END;
-    if (!NT_SUCCESS(Status))
-    {
-        SetLastWin32Error(ERROR_INVALID_PARAMETER);
-        REGION_UnlockRgn(Region);
-        GreDeleteObject(hRgn);
-        return NULL;
     }
-
-    REGION_UnlockRgn(Region);
-
-    return hRgn;
+    return REGION_Complexity(rgn);
 }
 
-BOOL
-APIENTRY
-NtGdiFillRgn(
-    HDC hDC,
-    HRGN hRgn,
-    HBRUSH hBrush
+/***********************************************************************
+ *     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 FASTCALL
+REGION_InsertEdgeInET(
+    EdgeTable *ET,
+    EdgeTableEntry *ETE,
+    INT scanline,
+    ScanLineListBlock **SLLBlock,
+    INT *iSLLBlock
 )
 {
-    HBRUSH oldhBrush;
-    PROSRGNDATA rgn;
-    PRECTL r;
+    EdgeTableEntry *start, *prev;
+    ScanLineList *pSLL, *pPrevSLL;
+    ScanLineListBlock *tmpSLLBlock;
 
-    if (NULL == (rgn = REGION_LockRgn(hRgn)))
+    /*
+     * find the right bucket to put the edge into
+     */
+    pPrevSLL = &ET->scanlines;
+    pSLL = pPrevSLL->next;
+    while (pSLL && (pSLL->scanline < scanline))
     {
-        return FALSE;
+        pPrevSLL = pSLL;
+        pSLL = pSLL->next;
     }
 
-    if (NULL == (oldhBrush = NtGdiSelectBrush(hDC, hBrush)))
+    /*
+     * reassign pSLL (pointer to ScanLineList) if necessary
+     */
+    if ((!pSLL) || (pSLL->scanline > scanline))
     {
-        REGION_UnlockRgn(rgn);
-        return FALSE;
+        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;
 
-    for (r = rgn->Buffer; r < rgn->Buffer + rgn->rdh.nCount; r++)
+    /*
+     * now insert the edge in the right bucket
+     */
+    prev = (EdgeTableEntry *)NULL;
+    start = pSLL->edgelist;
+    while (start && (start->bres.minor_axis < ETE->bres.minor_axis))
     {
-        NtGdiPatBlt(hDC, r->left, r->top, r->right - r->left, r->bottom - r->top, PATCOPY);
+        prev = start;
+        start = start->next;
     }
+    ETE->next = start;
 
-    REGION_UnlockRgn(rgn);
-    NtGdiSelectBrush(hDC, oldhBrush);
-
-    return TRUE;
+    if (prev)
+        prev->next = ETE;
+    else
+        pSLL->edgelist = ETE;
 }
 
-BOOL
-APIENTRY
-NtGdiFrameRgn(
-    HDC hDC,
-    HRGN hRgn,
-    HBRUSH hBrush,
-    INT Width,
-    INT Height
+/***********************************************************************
+ *     REGION_loadAET
+ *
+ *     This routine moves EdgeTableEntries from the
+ *     EdgeTable into the Active Edge Table,
+ *     leaving them sorted by smaller x coordinate.
+ *
+ */
+static void FASTCALL
+REGION_loadAET(
+    EdgeTableEntry *AET,
+    EdgeTableEntry *ETEs
 )
 {
-    HRGN FrameRgn;
-    BOOL Ret;
+    EdgeTableEntry *pPrevAET;
+    EdgeTableEntry *tmp;
 
-    if (!(FrameRgn = NtGdiCreateRectRgn(0, 0, 0, 0)))
-    {
-        return FALSE;
-    }
-    if (!REGION_CreateFrameRgn(FrameRgn, hRgn, Width, Height))
+    pPrevAET = AET;
+    AET = AET->next;
+    while (ETEs)
     {
-        GreDeleteObject(FrameRgn);
-        return FALSE;
-    }
-
-    Ret = NtGdiFillRgn(hDC, FrameRgn, hBrush);
+        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;
 
-    GreDeleteObject(FrameRgn);
-    return Ret;
+        ETEs = tmp;
+    }
 }
 
-INT FASTCALL
-REGION_GetRgnBox(
-    PROSRGNDATA Rgn,
-    PRECTL pRect
-)
+/***********************************************************************
+ *     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 FASTCALL
+REGION_computeWAET(EdgeTableEntry *AET)
 {
-    DWORD ret;
+    register EdgeTableEntry *pWETE;
+    register int inside = 1;
+    register int isInside = 0;
 
-    if (Rgn)
+    AET->nextWETE = (EdgeTableEntry *)NULL;
+    pWETE = AET;
+    AET = AET->next;
+    while (AET)
     {
-        *pRect = Rgn->rdh.rcBound;
-        ret = REGION_Complexity(Rgn);
+        if (AET->ClockWise)
+            isInside++;
+        else
+            isInside--;
 
-        return ret;
+        if ( (!inside && !isInside) ||
+             ( inside &&  isInside) )
+        {
+            pWETE->nextWETE = AET;
+            pWETE = AET;
+            inside = !inside;
+        }
+        AET = AET->next;
     }
-    return 0; //if invalid region return zero
+    pWETE->nextWETE = (EdgeTableEntry *)NULL;
 }
 
-
-/* See wine, msdn, osr and  Feng Yuan - Windows Graphics Programming Win32 Gdi And Directdraw
-
-   1st: http://www.codeproject.com/gdi/cliprgnguide.asp is wrong!
-
-   The intersection of the clip with the meta region is not Rao it's API!
-   Go back and read 7.2 Clipping pages 418-19:
-   Rao = API & Vis:
-   1) The Rao region is the intersection of the API region and the system region,
-      named after the Microsoft engineer who initially proposed it.
-   2) The Rao region can be calculated from the API region and the system region.
-
-   API:
-      API region is the intersection of the meta region and the clipping region,
-      clearly named after the fact that it is controlled by GDI API calls.
-*/
-INT APIENTRY
-NtGdiGetRandomRgn(
-    HDC hDC,
-    HRGN hDest,
-    INT iCode
-)
+/***********************************************************************
+ *     REGION_InsertionSort
+ *
+ *     Just a simple insertion sort using
+ *     pointers and back pointers to sort the Active
+ *     Edge Table.
+ *
+ */
+static BOOL FASTCALL
+REGION_InsertionSort(EdgeTableEntry *AET)
 {
-    INT ret = 0;
-    PDC pDC;
-    HRGN hSrc = NULL;
-    POINT org;
-
-    pDC = DC_LockDc(hDC);
-    if (pDC == NULL)
-    {
-        SetLastWin32Error(ERROR_INVALID_HANDLE);
-        return -1;
-    }
-
-    switch (iCode)
-    {
-    case CLIPRGN:
-        hSrc = pDC->rosdc.hClipRgn;
-//        if (pDC->dclevel.prgnClip) hSrc = ((PROSRGNDATA)pDC->dclevel.prgnClip)->BaseObject.hHmgr;
-        break;
-    case METARGN:
-        if (pDC->dclevel.prgnMeta) hSrc = ((PROSRGNDATA)pDC->dclevel.prgnMeta)->BaseObject.hHmgr;
-        break;
-    case APIRGN:
-        hSrc = pDC->rosdc.hClipRgn;
-//        if (pDC->prgnAPI) hSrc = ((PROSRGNDATA)pDC->prgnAPI)->BaseObject.hHmgr;
-//        else if (pDC->dclevel.prgnClip) hSrc = ((PROSRGNDATA)pDC->dclevel.prgnClip)->BaseObject.hHmgr;
-//        else if (pDC->dclevel.prgnMeta) hSrc = ((PROSRGNDATA)pDC->dclevel.prgnMeta)->BaseObject.hHmgr;
-        break;
-    case SYSRGN:
-        hSrc = pDC->rosdc.hVisRgn;
-//        if (pDC->prgnVis) hSrc = ((PROSRGNDATA)pDC->prgnVis)->BaseObject.hHmgr;
-        break;
-    default:
-        hSrc = 0;
-    }
-    if (hSrc)
+    EdgeTableEntry *pETEchase;
+    EdgeTableEntry *pETEinsert;
+    EdgeTableEntry *pETEchaseBackTMP;
+    BOOL changed = FALSE;
+
+    AET = AET->next;
+    while (AET)
     {
-        if (NtGdiCombineRgn(hDest, hSrc, 0, RGN_COPY) == ERROR)
-        {
-            ret = -1;
-        }
-        else
+        pETEinsert = AET;
+        pETEchase = AET;
+        while (pETEchase->back->bres.minor_axis > AET->bres.minor_axis)
+            pETEchase = pETEchase->back;
+
+        AET = AET->next;
+        if (pETEchase != pETEinsert)
         {
-            ret = 1;
+            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;
         }
     }
-    if (iCode == SYSRGN)
-    {
-        IntGdiGetDCOrg(pDC, &org);
-        NtGdiOffsetRgn(hDest, org.x, org.y );
-    }
-
-    DC_UnlockDc(pDC);
-
-    return ret;
+    return changed;
 }
 
-INT APIENTRY
-IntGdiGetRgnBox(
-    HRGN hRgn,
-    PRECTL pRect
-)
+/***********************************************************************
+ *     REGION_FreeStorage
+ *
+ *     Clean up our act.
+ */
+static void FASTCALL
+REGION_FreeStorage(ScanLineListBlock *pSLLBlock)
 {
-    PROSRGNDATA Rgn;
-    DWORD ret;
+    ScanLineListBlock   *tmpSLLBlock;
 
-    if (!(Rgn = REGION_LockRgn(hRgn)))
+    while (pSLLBlock)
     {
-        return ERROR;
+        tmpSLLBlock = pSLLBlock->next;
+        ExFreePool(pSLLBlock);
+        pSLLBlock = tmpSLLBlock;
     }
-
-    ret = REGION_GetRgnBox(Rgn, pRect);
-    REGION_UnlockRgn(Rgn);
-
-    return ret;
 }
 
 
-INT APIENTRY
-NtGdiGetRgnBox(
-    HRGN hRgn,
-    PRECTL pRect
-)
+/***********************************************************************
+ *     REGION_PtsToRegion
+ *
+ *     Create an array of rectangles from a list of points.
+ */
+static int FASTCALL
+REGION_PtsToRegion(
+    int numFullPtBlocks,
+    int iCurPtBlock,
+    POINTBLOCK *FirstPtBlock,
+    ROSRGNDATA *reg)
 {
-    PROSRGNDATA  Rgn;
-    RECTL SafeRect;
-    DWORD ret;
-    NTSTATUS Status = STATUS_SUCCESS;
+    RECTL *rects;
+    POINT *pts;
+    POINTBLOCK *CurPtBlock;
+    int i;
+    RECTL *extents, *temp;
+    INT numRects;
 
-    if (!(Rgn = REGION_LockRgn(hRgn)))
-    {
-        return ERROR;
-    }
+    extents = &reg->rdh.rcBound;
 
-    ret = REGION_GetRgnBox(Rgn, &SafeRect);
-    REGION_UnlockRgn(Rgn);
-    if (ERROR == ret)
-    {
-        return ret;
-    }
+    numRects = ((numFullPtBlocks * NUMPTSTOBUFFER) + iCurPtBlock) >> 1;
 
-    _SEH2_TRY
-    {
-        ProbeForWrite(pRect, sizeof(RECT), 1);
-        *pRect = SafeRect;
-    }
-    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    if (!(temp = ExAllocatePoolWithTag(PagedPool, numRects * sizeof(RECT), TAG_REGION)))
     {
-        Status = _SEH2_GetExceptionCode();
+        return 0;
     }
-    _SEH2_END;
-    if (!NT_SUCCESS(Status))
+    if (reg->Buffer != NULL)
     {
-        return ERROR;
+        COPY_RECTS(temp, reg->Buffer, reg->rdh.nCount);
+        if (reg->Buffer != &reg->rdh.rcBound)
+            ExFreePoolWithTag(reg->Buffer, TAG_REGION);
     }
+    reg->Buffer = temp;
 
-    return ret;
-}
-
-BOOL
-APIENTRY
-NtGdiInvertRgn(
-    HDC hDC,
-    HRGN hRgn
-)
-{
-    PROSRGNDATA RgnData;
-    ULONG i;
-    PRECTL rc;
+    reg->rdh.nCount = numRects;
+    CurPtBlock = FirstPtBlock;
+    rects = reg->Buffer - 1;
+    numRects = 0;
+    extents->left = LARGE_COORDINATE,  extents->right = SMALL_COORDINATE;
 
-    if (!(RgnData = REGION_LockRgn(hRgn)))
+    for ( ; numFullPtBlocks >= 0; numFullPtBlocks--)
     {
-        SetLastWin32Error(ERROR_INVALID_HANDLE);
-        return FALSE;
+        /* 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;
     }
 
-    rc = RgnData->Buffer;
-    for (i = 0; i < RgnData->rdh.nCount; i++)
+    if (numRects)
     {
-
-        if (!NtGdiPatBlt(hDC, rc->left, rc->top, rc->right - rc->left, rc->bottom - rc->top, DSTINVERT))
-        {
-            REGION_UnlockRgn(RgnData);
-            return FALSE;
-        }
-        rc++;
+        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;
 
-    REGION_UnlockRgn(RgnData);
-    return TRUE;
+    return(TRUE);
 }
 
-INT
-APIENTRY
-NtGdiOffsetRgn(
-    HRGN hRgn,
-    INT XOffset,
-    INT YOffset
+/***********************************************************************
+ *     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 FASTCALL
+REGION_CreateETandAET(
+    const ULONG *Count,
+    INT nbpolygons,
+    const POINT *pts,
+    EdgeTable *ET,
+    EdgeTableEntry *AET,
+    EdgeTableEntry *pETEs,
+    ScanLineListBlock *pSLLBlock
 )
 {
-    PROSRGNDATA rgn = REGION_LockRgn(hRgn);
-    INT ret;
+    const POINT *top, *bottom;
+    const POINT *PrevPt, *CurrPt, *EndPt;
+    INT poly, count;
+    int iSLLBlock = 0;
+    int dy;
 
-    DPRINT("NtGdiOffsetRgn: hRgn %d Xoffs %d Yoffs %d rgn %x\n", hRgn, XOffset, YOffset, rgn );
 
-    if (!rgn)
-    {
-        DPRINT("NtGdiOffsetRgn: hRgn error\n");
-        return ERROR;
-    }
+    /*
+     *  initialize the Active Edge Table
+     */
+    AET->next = (EdgeTableEntry *)NULL;
+    AET->back = (EdgeTableEntry *)NULL;
+    AET->nextWETE = (EdgeTableEntry *)NULL;
+    AET->bres.minor_axis = SMALL_COORDINATE;
 
-    if (XOffset || YOffset)
+    /*
+     *  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++)
     {
-        int nbox = rgn->rdh.nCount;
-        PRECTL pbox = rgn->Buffer;
+        count = Count[poly];
+        EndPt += count;
+        if (count < 2)
+            continue;
 
-        if (nbox && pbox)
+        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--)
         {
-            while (nbox--)
+            CurrPt = pts++;
+
+            /*
+             *  find out which point is above and which is below.
+             */
+            if (PrevPt->y > CurrPt->y)
             {
-                pbox->left += XOffset;
-                pbox->right += XOffset;
-                pbox->top += YOffset;
-                pbox->bottom += YOffset;
-                pbox++;
+                bottom = PrevPt, top = CurrPt;
+                pETEs->ClockWise = 0;
             }
-            if (rgn->Buffer != &rgn->rdh.rcBound)
+            else
             {
-                rgn->rdh.rcBound.left += XOffset;
-                rgn->rdh.rcBound.right += XOffset;
-                rgn->rdh.rcBound.top += YOffset;
-                rgn->rdh.rcBound.bottom += YOffset;
+                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;
         }
     }
-    ret = REGION_Complexity(rgn);
-    REGION_UnlockRgn(rgn);
-    return ret;
 }
 
-BOOL
-FASTCALL
-IntGdiPaintRgn(
-    PDC dc,
-    HRGN hRgn
+HRGN FASTCALL
+IntCreatePolyPolygonRgn(
+    POINT *Pts,
+    PULONG Count,
+    INT nbpolygons,
+    INT mode
 )
 {
-    HRGN tmpVisRgn;
-    PROSRGNDATA visrgn;
-    CLIPOBJ* ClipRegion;
-    BOOL bRet = FALSE;
-    POINTL BrushOrigin;
-    SURFACE *psurf;
-    PDC_ATTR pdcattr;
+    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 (!dc) return FALSE;
-    pdcattr = dc->pdcattr;
+    if (mode == 0 || mode > 2) return 0;
 
-    ASSERT(!(pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY)));
+    if (!(region = REGION_AllocUserRgnWithHandle(nbpolygons)))
+        return 0;
+    hrgn = region->BaseObject.hHmgr;
 
-    if (!(tmpVisRgn = NtGdiCreateRectRgn(0, 0, 0, 0))) return FALSE;
+    /* special case a rectangle */
 
-    // Transform region into device co-ords
-    if (!REGION_LPTODP(dc, tmpVisRgn, hRgn) || 
-         NtGdiOffsetRgn(tmpVisRgn, dc->ptlDCOrig.x, dc->ptlDCOrig.y) == ERROR)
+    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))))
     {
-        GreDeleteObject(tmpVisRgn);
-        return FALSE;
+        RGNOBJAPI_Unlock(region);
+        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;
     }
 
-    NtGdiCombineRgn(tmpVisRgn, tmpVisRgn, dc->rosdc.hGCClipRgn, RGN_AND);
-
-    visrgn = REGION_LockRgn(tmpVisRgn);
-    if (visrgn == NULL)
+    for (poly = total = 0; poly < nbpolygons; poly++)
+        total += Count[poly];
+    if (! (pETEs = ExAllocatePoolWithTag(PagedPool, sizeof(EdgeTableEntry) * total, TAG_REGION)) )
     {
-        GreDeleteObject(tmpVisRgn);
-        return FALSE;
+        GreDeleteObject(hrgn);
+        return 0;
     }
+    pts = FirstPtBlock.pts;
+    REGION_CreateETandAET(Count, nbpolygons, Pts, &ET, &AET, pETEs, &SLLBlock);
+    pSLL = ET.scanlines.next;
+    curPtBlock = &FirstPtBlock;
 
-    ClipRegion = IntEngCreateClipRegion(visrgn->rdh.nCount,
-                                        visrgn->Buffer,
-                                        &visrgn->rdh.rcBound );
-    ASSERT(ClipRegion);
-
-    BrushOrigin.x = pdcattr->ptlBrushOrigin.x;
-    BrushOrigin.y = pdcattr->ptlBrushOrigin.y;
-    psurf = dc->dclevel.pSurface;
-    /* FIXME - Handle psurf == NULL !!!! */
-
-    bRet = IntEngPaint(&psurf->SurfObj,
-                       ClipRegion,
-                       &dc->eboFill.BrushObject,
-                       &BrushOrigin,
-                       0xFFFF);//FIXME:don't know what to put here
+    if (mode != WINDING)
+    {
+        /*
+         *  for each scanline
+         */
+        for (y = ET.ymin; y < ET.ymax; y++)
+        {
+            /*
+             *  Add a new edge to the active edge table when we
+             *  get to the next edge.
+             */
+            if (pSLL != NULL && y == pSLL->scanline)
+            {
+                REGION_loadAET(&AET, pSLL->edgelist);
+                pSLL = pSLL->next;
+            }
+            pPrevAET = &AET;
+            pAET = AET.next;
 
-    REGION_UnlockRgn(visrgn);
-    GreDeleteObject(tmpVisRgn);
+            /*
+             *  for each active edge
+             */
+            while (pAET)
+            {
+                pts->x = pAET->bres.minor_axis,  pts->y = y;
+                pts++, iPts++;
 
-    // Fill the region
-    return TRUE;
-}
+                /*
+                 *  send out the buffer
+                 */
+                if (iPts == NUMPTSTOBUFFER)
+                {
+                    tmpPtBlock = ExAllocatePoolWithTag(PagedPool, sizeof(POINTBLOCK), TAG_REGION);
+                    if (!tmpPtBlock)
+                    {
+                        DPRINT1("Can't alloc tPB\n");
+                        ExFreePoolWithTag(pETEs, TAG_REGION);
+                        return 0;
+                    }
+                    curPtBlock->next = tmpPtBlock;
+                    curPtBlock = tmpPtBlock;
+                    pts = curPtBlock->pts;
+                    numFullPtBlocks++;
+                    iPts = 0;
+                }
+                EVALUATEEDGEEVENODD(pAET, pPrevAET, y);
+            }
+            REGION_InsertionSort(&AET);
+        }
+    }
+    else
+    {
+        /*
+         *  for each scanline
+         */
+        for (y = ET.ymin; y < ET.ymax; y++)
+        {
+            /*
+             *  Add a new edge to the active edge table when we
+             *  get to the next edge.
+             */
+            if (pSLL != NULL && y == pSLL->scanline)
+            {
+                REGION_loadAET(&AET, pSLL->edgelist);
+                REGION_computeWAET(&AET);
+                pSLL = pSLL->next;
+            }
+            pPrevAET = &AET;
+            pAET = AET.next;
+            pWETE = pAET;
 
-BOOL
-APIENTRY
-NtGdiPtInRegion(
-    HRGN hRgn,
-    INT X,
-    INT Y
-)
-{
-    PROSRGNDATA rgn;
-    ULONG i;
-    PRECTL r;
+            /*
+             *  for each active edge
+             */
+            while (pAET)
+            {
+                /*
+                 *  add to the buffer only those edges that
+                 *  are in the Winding active edge table.
+                 */
+                if (pWETE == pAET)
+                {
+                    pts->x = pAET->bres.minor_axis,  pts->y = y;
+                    pts++, iPts++;
 
-    if (!(rgn = REGION_LockRgn(hRgn) ) )
-        return FALSE;
+                    /*
+                     *  send out the buffer
+                     */
+                    if (iPts == NUMPTSTOBUFFER)
+                    {
+                        tmpPtBlock = ExAllocatePoolWithTag(PagedPool,
+                                                           sizeof(POINTBLOCK), TAG_REGION);
+                        if (!tmpPtBlock)
+                        {
+                            DPRINT1("Can't alloc tPB\n");
+                            ExFreePoolWithTag(pETEs, TAG_REGION);
+                            GreDeleteObject(hrgn);
+                            return 0;
+                        }
+                        curPtBlock->next = tmpPtBlock;
+                        curPtBlock = tmpPtBlock;
+                        pts = curPtBlock->pts;
+                        numFullPtBlocks++;
+                        iPts = 0;
+                    }
+                    pWETE = pWETE->nextWETE;
+                }
+                EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET);
+            }
 
-    if (rgn->rdh.nCount > 0 && INRECT(rgn->rdh.rcBound, X, Y))
-    {
-        r =  rgn->Buffer;
-        for (i = 0; i < rgn->rdh.nCount; i++)
-        {
-            if (INRECT(*r, X, Y))
+            /*
+             *  recompute the winding active edge table if
+             *  we just resorted or have exited an edge.
+             */
+            if (REGION_InsertionSort(&AET) || fixWAET)
             {
-                REGION_UnlockRgn(rgn);
-                return TRUE;
+                REGION_computeWAET(&AET);
+                fixWAET = FALSE;
             }
-            r++;
         }
     }
-    REGION_UnlockRgn(rgn);
-    return FALSE;
+    REGION_FreeStorage(SLLBlock.next);
+    REGION_PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, region);
+
+    for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;)
+    {
+        tmpPtBlock = curPtBlock->next;
+        ExFreePoolWithTag(curPtBlock, TAG_REGION);
+        curPtBlock = tmpPtBlock;
+    }
+    ExFreePoolWithTag(pETEs, TAG_REGION);
+    RGNOBJAPI_Unlock(region);
+    return hrgn;
 }
 
 BOOL
 FASTCALL
-REGION_RectInRegion(
-    PROSRGNDATA Rgn,
-    const RECTL *rect
+IntRectInRegion(
+    HRGN  hRgn,
+    LPRECTL rc
 )
 {
-    PRECTL pCurRect, pRectEnd;
-    RECT rc;
+    PROSRGNDATA Rgn;
+    BOOL Ret;
 
-    /* swap the coordinates to make right >= left and bottom >= top */
-    /* (region building rectangles are normalized the same way) */
-    if( rect->top > rect->bottom) {
-        rc.top = rect->bottom;
-        rc.bottom = rect->top;
-    } else {
-        rc.top = rect->top;
-        rc.bottom = rect->bottom;
-    }
-    if( rect->right < rect->left) {
-        rc.right = rect->left;
-        rc.left = rect->right;
-    } else {
-        rc.right = rect->right;
-        rc.left = rect->left;
+    if (!(Rgn = RGNOBJAPI_Lock(hRgn, NULL)))
+    {
+        return ERROR;
     }
 
-    /* this is (just) a useful optimization */
-    if ((Rgn->rdh.nCount > 0) && EXTENTCHECK(&Rgn->rdh.rcBound, &rc))
-    {
-        for (pCurRect = Rgn->Buffer, pRectEnd = pCurRect +
-         Rgn->rdh.nCount; pCurRect < pRectEnd; pCurRect++)
-        {
-            if (pCurRect->bottom <= rc.top)
-            continue;             /* not far enough down yet */
+    Ret = REGION_RectInRegion(Rgn, rc);
+    RGNOBJAPI_Unlock(Rgn);
+    return Ret;
+}
 
-            if (pCurRect->top >= rc.bottom)
-                break;                /* too far down */
 
-            if (pCurRect->right <= rc.left)
-                continue;              /* not far enough over yet */
+//
+// NtGdi Exported Functions
+//
+INT
+APIENTRY
+NtGdiCombineRgn(HRGN  hDest,
+                HRGN  hSrc1,
+                HRGN  hSrc2,
+                INT  CombineMode)
+{
+  INT result = ERROR;
+  PROSRGNDATA destRgn, src1Rgn, src2Rgn = NULL;
 
-            if (pCurRect->left >= rc.right) {
-                continue;
-            }
+  if ( CombineMode > RGN_COPY && CombineMode < RGN_AND)
+  {
+     EngSetLastError(ERROR_INVALID_PARAMETER);
+     return ERROR;
+  }
 
-            return TRUE;
-        }
-    }
-    return FALSE;
+  destRgn = RGNOBJAPI_Lock(hDest, NULL);
+  if (!destRgn)
+  {
+     EngSetLastError(ERROR_INVALID_HANDLE);
+     return ERROR;
+  }
+
+  src1Rgn = RGNOBJAPI_Lock(hSrc1, NULL);
+  if (!src1Rgn)
+  {
+     RGNOBJAPI_Unlock(destRgn);
+     EngSetLastError(ERROR_INVALID_HANDLE);
+     return ERROR;
+  }
+
+  if (hSrc2)
+     src2Rgn = RGNOBJAPI_Lock(hSrc2, NULL);
+
+  result = IntGdiCombineRgn( destRgn, src1Rgn, src2Rgn, CombineMode);
+
+  if (src2Rgn)
+     RGNOBJAPI_Unlock(src2Rgn);
+  RGNOBJAPI_Unlock(src1Rgn);
+  RGNOBJAPI_Unlock(destRgn);
+
+  return result;
 }
 
-BOOL
+HRGN
 APIENTRY
-NtGdiRectInRegion(
-    HRGN  hRgn,
-    LPRECTL unsaferc
+NtGdiCreateEllipticRgn(
+    INT Left,
+    INT Top,
+    INT Right,
+    INT Bottom
 )
 {
-    PROSRGNDATA Rgn;
-    RECTL rc = {0};
-    BOOL Ret;
-    NTSTATUS Status = STATUS_SUCCESS;
+    return NtGdiCreateRoundRectRgn(Left, Top, Right, Bottom,
+                                   Right - Left, Bottom - Top);
+}
 
-    if (!(Rgn = REGION_LockRgn(hRgn)))
-    {
-        return ERROR;
-    }
+HRGN APIENTRY
+NtGdiCreateRectRgn(INT LeftRect, INT TopRect, INT RightRect, INT BottomRect)
+{
+    PROSRGNDATA pRgn;
+    HRGN hRgn;
 
-    _SEH2_TRY
-    {
-        ProbeForRead(unsaferc, sizeof(RECT), 1);
-        rc = *unsaferc;
-    }
-    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    /* Allocate region data structure with space for 1 RECTL */
+    if (!(pRgn = REGION_AllocUserRgnWithHandle(1)))
     {
-        Status = _SEH2_GetExceptionCode();
+        EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        return NULL;
     }
-    _SEH2_END;
+    hRgn = pRgn->BaseObject.hHmgr;
 
-    if (!NT_SUCCESS(Status))
-    {
-        REGION_UnlockRgn(Rgn);
-        SetLastNtError(Status);
-        DPRINT1("NtGdiRectInRegion: bogus rc\n");
-        return ERROR;
-    }
+    REGION_SetRectRgn(pRgn, LeftRect, TopRect, RightRect, BottomRect);
+    RGNOBJAPI_Unlock(pRgn);
 
-    Ret = REGION_RectInRegion(Rgn, &rc);
-    REGION_UnlockRgn(Rgn);
-    return Ret;
+    return hRgn;
 }
 
-VOID
-FASTCALL
-REGION_SetRectRgn(
-    PROSRGNDATA rgn,
-    INT LeftRect,
-    INT TopRect,
-    INT RightRect,
-    INT BottomRect
+HRGN
+APIENTRY
+NtGdiCreateRoundRectRgn(
+    INT left,
+    INT top,
+    INT right,
+    INT bottom,
+    INT ellipse_width,
+    INT ellipse_height
 )
 {
-    PRECTL firstRect;
+    PROSRGNDATA obj;
+    HRGN hrgn;
+    int asq, bsq, d, xd, yd;
+    RECTL rect;
 
-    if (LeftRect > RightRect)
+    /* Make the dimensions sensible */
+
+    if (left > right)
     {
-        INT tmp = LeftRect;
-        LeftRect = RightRect;
-        RightRect = tmp;
+        INT tmp = left;
+        left = right;
+        right = tmp;
     }
-    if (TopRect > BottomRect)
+    if (top > bottom)
     {
-        INT tmp = TopRect;
-        TopRect = BottomRect;
-        BottomRect = tmp;
+        INT tmp = top;
+        top = bottom;
+        bottom = tmp;
     }
 
-    if ((LeftRect != RightRect) && (TopRect != BottomRect))
-    {
-        firstRect = rgn->Buffer;
-        ASSERT(firstRect);
-        firstRect->left = rgn->rdh.rcBound.left = LeftRect;
-        firstRect->top = rgn->rdh.rcBound.top = TopRect;
-        firstRect->right = rgn->rdh.rcBound.right = RightRect;
-        firstRect->bottom = rgn->rdh.rcBound.bottom = BottomRect;
-        rgn->rdh.nCount = 1;
-        rgn->rdh.iType = RDH_RECTANGLES;
-    }
-    else
-        EMPTY_REGION(rgn);
-}
+    ellipse_width = abs(ellipse_width);
+    ellipse_height = abs(ellipse_height);
 
-BOOL
-APIENTRY
-NtGdiSetRectRgn(
-    HRGN hRgn,
-    INT LeftRect,
-    INT TopRect,
-    INT RightRect,
-    INT BottomRect
-)
-{
-    PROSRGNDATA rgn;
+    /* Check parameters */
 
-    if ( !(rgn = REGION_LockRgn(hRgn)) )
-    {
-        return 0; //per documentation
-    }
+    if (ellipse_width > right-left) ellipse_width = right-left;
+    if (ellipse_height > bottom-top) ellipse_height = bottom-top;
 
-    REGION_SetRectRgn(rgn, LeftRect, TopRect, RightRect, BottomRect);
+    /* Check if we can do a normal rectangle instead */
 
-    REGION_UnlockRgn(rgn);
-    return TRUE;
-}
+    if ((ellipse_width < 2) || (ellipse_height < 2))
+        return NtGdiCreateRectRgn(left, top, right, bottom);
 
-HRGN APIENTRY
-NtGdiUnionRectWithRgn(
-    HRGN hDest,
-    const RECTL *UnsafeRect
-)
-{
-    RECTL SafeRect = {0};
-    PROSRGNDATA Rgn;
-    NTSTATUS Status = STATUS_SUCCESS;
+    /* Create region */
 
-    if (!(Rgn = REGION_LockRgn(hDest)))
-    {
-        SetLastWin32Error(ERROR_INVALID_HANDLE);
-        return NULL;
-    }
+    d = (ellipse_height < 128) ? ((3 * ellipse_height) >> 2) : 64;
+    if (!(obj = REGION_AllocUserRgnWithHandle(d))) return 0;
+    hrgn = obj->BaseObject.hHmgr;
 
-    _SEH2_TRY
+    /* Ellipse algorithm, based on an article by K. Porter */
+    /* in DDJ Graphics Programming Column, 8/89 */
+
+    asq = ellipse_width * ellipse_width / 4;        /* a^2 */
+    bsq = ellipse_height * ellipse_height / 4;      /* b^2 */
+    d = bsq - asq * ellipse_height / 2 + asq / 4;   /* b^2 - a^2b + a^2/4 */
+    xd = 0;
+    yd = asq * ellipse_height;                      /* 2a^2b */
+
+    rect.left   = left + ellipse_width / 2;
+    rect.right  = right - ellipse_width / 2;
+
+    /* Loop to draw first half of quadrant */
+
+    while (xd < yd)
     {
-        ProbeForRead(UnsafeRect, sizeof(RECT), 1);
-        SafeRect = *UnsafeRect;
+        if (d > 0)  /* if nearest pixel is toward the center */
+        {
+            /* move toward center */
+            rect.top = top++;
+            rect.bottom = rect.top + 1;
+            REGION_UnionRectWithRgn(obj, &rect);
+            rect.top = --bottom;
+            rect.bottom = rect.top + 1;
+            REGION_UnionRectWithRgn(obj, &rect);
+            yd -= 2*asq;
+            d  -= yd;
+        }
+        rect.left--;        /* next horiz point */
+        rect.right++;
+        xd += 2*bsq;
+        d  += bsq + xd;
     }
-    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    /* Loop to draw second half of quadrant */
+
+    d += (3 * (asq-bsq) / 2 - (xd+yd)) / 2;
+    while (yd >= 0)
     {
-        Status = _SEH2_GetExceptionCode();
+        /* next vertical point */
+        rect.top = top++;
+        rect.bottom = rect.top + 1;
+        REGION_UnionRectWithRgn(obj, &rect);
+        rect.top = --bottom;
+        rect.bottom = rect.top + 1;
+        REGION_UnionRectWithRgn(obj, &rect);
+        if (d < 0)   /* if nearest pixel is outside ellipse */
+        {
+            rect.left--;     /* move away from center */
+            rect.right++;
+            xd += 2*bsq;
+            d  += xd;
+        }
+        yd -= 2*asq;
+        d  += asq - yd;
     }
-    _SEH2_END;
+    /* Add the inside rectangle */
 
-    if (! NT_SUCCESS(Status))
+    if (top <= bottom)
     {
-        REGION_UnlockRgn(Rgn);
-        SetLastNtError(Status);
-        return NULL;
+        rect.top = top;
+        rect.bottom = bottom;
+        REGION_UnionRectWithRgn(obj, &rect);
     }
 
-    REGION_UnionRectWithRgn(Rgn, &SafeRect);
-    REGION_UnlockRgn(Rgn);
-    return hDest;
+    RGNOBJAPI_Unlock(obj);
+    return hrgn;
 }
 
-/*!
- * MSDN: GetRegionData, Return Values:
- *
- * "If the function succeeds and dwCount specifies an adequate number of bytes,
- * the return value is always dwCount. If dwCount is too small or the function
- * fails, the return value is 0. If lpRgnData is NULL, the return value is the
- * required number of bytes.
- *
- * If the function fails, the return value is zero."
- */
-DWORD APIENTRY
-NtGdiGetRegionData(
-    HRGN hrgn,
-    DWORD count,
-    LPRGNDATA rgndata
+BOOL
+APIENTRY
+NtGdiEqualRgn(
+    HRGN  hSrcRgn1,
+    HRGN  hSrcRgn2
 )
 {
-    DWORD size;
-    PROSRGNDATA obj = REGION_LockRgn(hrgn);
-    NTSTATUS Status = STATUS_SUCCESS;
+    PROSRGNDATA rgn1, rgn2;
+    PRECTL tRect1, tRect2;
+    ULONG i;
+    BOOL bRet = FALSE;
 
-    if (!obj)
-        return 0;
+    if ( !(rgn1 = RGNOBJAPI_Lock(hSrcRgn1, NULL)) )
+        return ERROR;
 
-    size = obj->rdh.nCount * sizeof(RECT);
-    if (count < (size + sizeof(RGNDATAHEADER)) || rgndata == NULL)
+    if ( !(rgn2 = RGNOBJAPI_Lock(hSrcRgn2, NULL)) )
     {
-        REGION_UnlockRgn(obj);
-        if (rgndata) /* buffer is too small, signal it by return 0 */
-            return 0;
-        else         /* user requested buffer size with rgndata NULL */
-            return size + sizeof(RGNDATAHEADER);
+        RGNOBJAPI_Unlock(rgn1);
+        return ERROR;
+    }
+
+    if ( rgn1->rdh.nCount != rgn2->rdh.nCount ) goto exit;
+
+    if ( rgn1->rdh.nCount == 0 )
+    {
+       bRet = TRUE;
+       goto exit;
+    }
+
+    if ( rgn1->rdh.rcBound.left   != rgn2->rdh.rcBound.left  ||
+         rgn1->rdh.rcBound.right  != rgn2->rdh.rcBound.right ||
+         rgn1->rdh.rcBound.top    != rgn2->rdh.rcBound.top   ||
+         rgn1->rdh.rcBound.bottom != rgn2->rdh.rcBound.bottom )
+       goto exit;
+
+    tRect1 = rgn1->Buffer;
+    tRect2 = rgn2->Buffer;
+
+    if (!tRect1 || !tRect2)
+       goto exit;
+
+    for (i=0; i < rgn1->rdh.nCount; i++)
+    {
+        if ( tRect1[i].left   != tRect2[i].left  ||
+             tRect1[i].right  != tRect2[i].right ||
+             tRect1[i].top    != tRect2[i].top   ||
+             tRect1[i].bottom != tRect2[i].bottom )
+           goto exit;
     }
+    bRet = TRUE;
+
+exit:
+    RGNOBJAPI_Unlock(rgn1);
+    RGNOBJAPI_Unlock(rgn2);
+    return bRet;
+}
+
+HRGN
+APIENTRY
+NtGdiExtCreateRegion(
+    OPTIONAL LPXFORM Xform,
+    DWORD Count,
+    LPRGNDATA RgnData
+)
+{
+    HRGN hRgn;
+    PROSRGNDATA Region;
+    DWORD nCount = 0;
+    DWORD iType = 0;
+    DWORD dwSize = 0;
+    NTSTATUS Status = STATUS_SUCCESS;
+    MATRIX matrix;
+    XFORMOBJ xo;
 
+    DPRINT("NtGdiExtCreateRegion\n");
     _SEH2_TRY
     {
-        ProbeForWrite(rgndata, count, 1);
-        RtlCopyMemory(rgndata, &obj->rdh, sizeof(RGNDATAHEADER));
-        RtlCopyMemory(rgndata->Buffer, obj->Buffer, size);
+        ProbeForRead(RgnData, Count, 1);
+        nCount = RgnData->rdh.nCount;
+        iType = RgnData->rdh.iType;
+        dwSize = RgnData->rdh.dwSize;
     }
     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
     {
         Status = _SEH2_GetExceptionCode();
     }
     _SEH2_END;
-
     if (!NT_SUCCESS(Status))
     {
         SetLastNtError(Status);
-        REGION_UnlockRgn(obj);
-        return 0;
+        return NULL;
     }
 
-    REGION_UnlockRgn(obj);
-    return size + sizeof(RGNDATAHEADER);
-}
-
+    /* Check parameters, but don't set last error here */
+    if (Count < sizeof(RGNDATAHEADER) + nCount * sizeof(RECT) ||
+        iType != RDH_RECTANGLES ||
+        dwSize != sizeof(RGNDATAHEADER))
+    {
+        return NULL;
+    }
 
-/***********************************************************************
- *     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 FASTCALL
-REGION_InsertEdgeInET(
-    EdgeTable *ET,
-    EdgeTableEntry *ETE,
-    INT scanline,
-    ScanLineListBlock **SLLBlock,
-    INT *iSLLBlock
-)
-{
-    EdgeTableEntry *start, *prev;
-    ScanLineList *pSLL, *pPrevSLL;
-    ScanLineListBlock *tmpSLLBlock;
+    Region = REGION_AllocUserRgnWithHandle(nCount);
 
-    /*
-     * find the right bucket to put the edge into
-     */
-    pPrevSLL = &ET->scanlines;
-    pSLL = pPrevSLL->next;
-    while (pSLL && (pSLL->scanline < scanline))
+    if (Region == NULL)
     {
-        pPrevSLL = pSLL;
-        pSLL = pSLL->next;
+        EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        return FALSE;
     }
+    hRgn = Region->BaseObject.hHmgr;
 
-    /*
-     * reassign pSLL (pointer to ScanLineList) if necessary
-     */
-    if ((!pSLL) || (pSLL->scanline > scanline))
+    _SEH2_TRY
     {
-        if (*iSLLBlock > SLLSPERBLOCK-1)
+        if (Xform)
         {
-            tmpSLLBlock = ExAllocatePoolWithTag(PagedPool, sizeof(ScanLineListBlock), TAG_REGION);
-            if (!tmpSLLBlock)
+            ULONG ret;
+
+            /* Init the XFORMOBJ from the Xform struct */
+            Status = STATUS_INVALID_PARAMETER;
+            XFORMOBJ_vInit(&xo, &matrix);
+            ret = XFORMOBJ_iSetXform(&xo, (XFORML*)Xform);
+
+            /* Check for error, also no scale and shear allowed */
+            if (ret != DDI_ERROR && ret != GX_GENERAL)
             {
-                DPRINT1("REGION_InsertEdgeInETL(): Can't alloc SLLB\n");
-                /* FIXME - free resources? */
-                return;
+                /* Apply the coordinate transformation on the rects */
+                if (XFORMOBJ_bApplyXform(&xo,
+                                         XF_LTOL,
+                                         nCount * 2,
+                                         RgnData->Buffer,
+                                         Region->Buffer))
+                {
+                    Status = STATUS_SUCCESS;
+                }
             }
-            (*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;
+        else
+        {
+            /* Copy rect coordinates */
+            RtlCopyMemory(Region->Buffer,
+                          RgnData->Buffer,
+                          nCount * sizeof(RECT));
+        }
     }
-    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))
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
     {
-        prev = start;
-        start = start->next;
+        Status = _SEH2_GetExceptionCode();
+    }
+    _SEH2_END;
+    if (!NT_SUCCESS(Status))
+    {
+        EngSetLastError(ERROR_INVALID_PARAMETER);
+        RGNOBJAPI_Unlock(Region);
+        GreDeleteObject(hRgn);
+        return NULL;
     }
-    ETE->next = start;
 
-    if (prev)
-        prev->next = ETE;
-    else
-        pSLL->edgelist = ETE;
+    RGNOBJAPI_Unlock(Region);
+
+    return hRgn;
 }
 
-/***********************************************************************
- *     REGION_loadAET
- *
- *     This routine moves EdgeTableEntries from the
- *     EdgeTable into the Active Edge Table,
- *     leaving them sorted by smaller x coordinate.
- *
- */
-static void FASTCALL
-REGION_loadAET(
-    EdgeTableEntry *AET,
-    EdgeTableEntry *ETEs
+BOOL
+APIENTRY
+NtGdiFillRgn(
+    HDC hDC,
+    HRGN hRgn,
+    HBRUSH hBrush
 )
 {
-    EdgeTableEntry *pPrevAET;
-    EdgeTableEntry *tmp;
+    HBRUSH oldhBrush;
+    PROSRGNDATA rgn;
+    PRECTL r;
 
-    pPrevAET = AET;
-    AET = AET->next;
-    while (ETEs)
+    if (NULL == (rgn = RGNOBJAPI_Lock(hRgn, NULL)))
     {
-        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;
+        return FALSE;
+    }
 
-        ETEs = tmp;
+    if (NULL == (oldhBrush = NtGdiSelectBrush(hDC, hBrush)))
+    {
+        RGNOBJAPI_Unlock(rgn);
+        return FALSE;
+    }
+
+    for (r = rgn->Buffer; r < rgn->Buffer + rgn->rdh.nCount; r++)
+    {
+        NtGdiPatBlt(hDC, r->left, r->top, r->right - r->left, r->bottom - r->top, PATCOPY);
     }
+
+    RGNOBJAPI_Unlock(rgn);
+    NtGdiSelectBrush(hDC, oldhBrush);
+
+    return TRUE;
 }
 
-/***********************************************************************
- *     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 FASTCALL
-REGION_computeWAET(EdgeTableEntry *AET)
+BOOL
+APIENTRY
+NtGdiFrameRgn(
+    HDC hDC,
+    HRGN hRgn,
+    HBRUSH hBrush,
+    INT Width,
+    INT Height
+)
 {
-    register EdgeTableEntry *pWETE;
-    register int inside = 1;
-    register int isInside = 0;
+    HRGN FrameRgn;
+    BOOL Ret;
 
-    AET->nextWETE = (EdgeTableEntry *)NULL;
-    pWETE = AET;
-    AET = AET->next;
-    while (AET)
+    if (!(FrameRgn = IntSysCreateRectRgn(0, 0, 0, 0)))
     {
-        if (AET->ClockWise)
-            isInside++;
-        else
-            isInside--;
-
-        if ( (!inside && !isInside) ||
-             ( inside &&  isInside) )
-        {
-            pWETE->nextWETE = AET;
-            pWETE = AET;
-            inside = !inside;
-        }
-        AET = AET->next;
+        return FALSE;
     }
-    pWETE->nextWETE = (EdgeTableEntry *)NULL;
+    if (!REGION_CreateFrameRgn(FrameRgn, hRgn, Width, Height))
+    {
+        REGION_FreeRgnByHandle(FrameRgn);
+        return FALSE;
+    }
+
+    Ret = NtGdiFillRgn(hDC, FrameRgn, hBrush);
+
+    REGION_FreeRgnByHandle(FrameRgn);
+    return Ret;
 }
 
-/***********************************************************************
- *     REGION_InsertionSort
- *
- *     Just a simple insertion sort using
- *     pointers and back pointers to sort the Active
- *     Edge Table.
- *
- */
-static BOOL FASTCALL
-REGION_InsertionSort(EdgeTableEntry *AET)
+
+INT APIENTRY
+NtGdiGetRgnBox(
+    HRGN hRgn,
+    PRECTL pRect
+)
 {
-    EdgeTableEntry *pETEchase;
-    EdgeTableEntry *pETEinsert;
-    EdgeTableEntry *pETEchaseBackTMP;
-    BOOL changed = FALSE;
+    PROSRGNDATA  Rgn;
+    RECTL SafeRect;
+    DWORD ret;
+    NTSTATUS Status = STATUS_SUCCESS;
 
-    AET = AET->next;
-    while (AET)
+    if (!(Rgn = RGNOBJAPI_Lock(hRgn, NULL)))
     {
-        pETEinsert = AET;
-        pETEchase = AET;
-        while (pETEchase->back->bres.minor_axis > AET->bres.minor_axis)
-            pETEchase = pETEchase->back;
+        return ERROR;
+    }
 
-        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;
-        }
+    ret = REGION_GetRgnBox(Rgn, &SafeRect);
+    RGNOBJAPI_Unlock(Rgn);
+    if (ERROR == ret)
+    {
+        return ret;
     }
-    return changed;
+
+    _SEH2_TRY
+    {
+        ProbeForWrite(pRect, sizeof(RECT), 1);
+        *pRect = SafeRect;
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        Status = _SEH2_GetExceptionCode();
+    }
+    _SEH2_END;
+    if (!NT_SUCCESS(Status))
+    {
+        return ERROR;
+    }
+
+    return ret;
 }
 
-/***********************************************************************
- *     REGION_FreeStorage
- *
- *     Clean up our act.
- */
-static void FASTCALL
-REGION_FreeStorage(ScanLineListBlock *pSLLBlock)
+BOOL
+APIENTRY
+NtGdiInvertRgn(
+    HDC hDC,
+    HRGN hRgn
+)
 {
-    ScanLineListBlock   *tmpSLLBlock;
+    PROSRGNDATA RgnData;
+    ULONG i;
+    PRECTL rc;
 
-    while (pSLLBlock)
+    if (!(RgnData = RGNOBJAPI_Lock(hRgn, NULL)))
     {
-        tmpSLLBlock = pSLLBlock->next;
-        ExFreePool(pSLLBlock);
-        pSLLBlock = tmpSLLBlock;
+        EngSetLastError(ERROR_INVALID_HANDLE);
+        return FALSE;
     }
-}
 
+    rc = RgnData->Buffer;
+    for (i = 0; i < RgnData->rdh.nCount; i++)
+    {
 
-/***********************************************************************
- *     REGION_PtsToRegion
- *
- *     Create an array of rectangles from a list of points.
- */
-static int FASTCALL
-REGION_PtsToRegion(
-    int numFullPtBlocks,
-    int iCurPtBlock,
-    POINTBLOCK *FirstPtBlock,
-    ROSRGNDATA *reg)
-{
-    RECTL *rects;
-    POINT *pts;
-    POINTBLOCK *CurPtBlock;
-    int i;
-    RECTL *extents, *temp;
-    INT numRects;
+        if (!NtGdiPatBlt(hDC, rc->left, rc->top, rc->right - rc->left, rc->bottom - rc->top, DSTINVERT))
+        {
+            RGNOBJAPI_Unlock(RgnData);
+            return FALSE;
+        }
+        rc++;
+    }
 
-    extents = &reg->rdh.rcBound;
+    RGNOBJAPI_Unlock(RgnData);
+    return TRUE;
+}
 
-    numRects = ((numFullPtBlocks * NUMPTSTOBUFFER) + iCurPtBlock) >> 1;
+INT
+APIENTRY
+NtGdiOffsetRgn(
+    HRGN hRgn,
+    INT XOffset,
+    INT YOffset
+)
+{
+    PROSRGNDATA rgn = RGNOBJAPI_Lock(hRgn, NULL);
+    INT ret;
 
-    if (!(temp = ExAllocatePoolWithTag(PagedPool, numRects * sizeof(RECT), TAG_REGION)))
-    {
-        return 0;
-    }
-    if (reg->Buffer != NULL)
+    DPRINT("NtGdiOffsetRgn: hRgn %d Xoffs %d Yoffs %d rgn %x\n", hRgn, XOffset, YOffset, rgn );
+
+    if (!rgn)
     {
-        COPY_RECTS(temp, reg->Buffer, reg->rdh.nCount);
-        if (reg->Buffer != &reg->rdh.rcBound)
-            ExFreePoolWithTag(reg->Buffer, TAG_REGION);
+        DPRINT("NtGdiOffsetRgn: hRgn error\n");
+        return ERROR;
     }
-    reg->Buffer = temp;
 
-    reg->rdh.nCount = numRects;
-    CurPtBlock = FirstPtBlock;
-    rects = reg->Buffer - 1;
-    numRects = 0;
-    extents->left = LARGE_COORDINATE,  extents->right = SMALL_COORDINATE;
+    ret = IntGdiOffsetRgn(rgn, XOffset, YOffset);
 
-    for ( ; numFullPtBlocks >= 0; numFullPtBlocks--)
+    RGNOBJAPI_Unlock(rgn);
+    return ret;
+}
+
+BOOL
+APIENTRY
+NtGdiPtInRegion(
+    HRGN hRgn,
+    INT X,
+    INT Y
+)
+{
+    PROSRGNDATA rgn;
+    ULONG i;
+    PRECTL r;
+
+    if (!(rgn = RGNOBJAPI_Lock(hRgn, NULL) ) )
+        return FALSE;
+
+    if (rgn->rdh.nCount > 0 && INRECT(rgn->rdh.rcBound, X, Y))
     {
-        /* the loop uses 2 points per iteration */
-        i = NUMPTSTOBUFFER >> 1;
-        if (!numFullPtBlocks)
-            i = iCurPtBlock >> 1;
-        for (pts = CurPtBlock->pts; i--; pts += 2)
+        r =  rgn->Buffer;
+        for (i = 0; i < rgn->rdh.nCount; i++)
         {
-            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))
+            if (INRECT(*r, X, Y))
             {
-                rects->bottom = pts[1].y + 1;
-                continue;
+                RGNOBJAPI_Unlock(rgn);
+                return TRUE;
             }
-            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;
+            r++;
         }
-        CurPtBlock = CurPtBlock->next;
     }
+    RGNOBJAPI_Unlock(rgn);
+    return FALSE;
+}
 
-    if (numRects)
-    {
-        extents->top = reg->Buffer->top;
-        extents->bottom = rects->bottom;
-    }
-    else
-    {
-        extents->left = 0;
-        extents->top = 0;
-        extents->right = 0;
-        extents->bottom = 0;
+BOOL
+APIENTRY
+NtGdiRectInRegion(
+    HRGN  hRgn,
+    LPRECTL unsaferc
+)
+{
+    RECTL rc = {0};
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    _SEH2_TRY
+    {
+        ProbeForRead(unsaferc, sizeof(RECT), 1);
+        rc = *unsaferc;
     }
-    reg->rdh.nCount = numRects;
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        Status = _SEH2_GetExceptionCode();
+    }
+    _SEH2_END;
 
-    return(TRUE);
+    if (!NT_SUCCESS(Status))
+    {
+        SetLastNtError(Status);
+        DPRINT1("NtGdiRectInRegion: bogus rc\n");
+        return ERROR;
+    }
+
+    return IntRectInRegion(hRgn, &rc);
 }
 
-/***********************************************************************
- *     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 FASTCALL
-REGION_CreateETandAET(
-    const ULONG *Count,
-    INT nbpolygons,
-    const POINT *pts,
-    EdgeTable *ET,
-    EdgeTableEntry *AET,
-    EdgeTableEntry *pETEs,
-    ScanLineListBlock *pSLLBlock
+BOOL
+APIENTRY
+NtGdiSetRectRgn(
+    HRGN hRgn,
+    INT LeftRect,
+    INT TopRect,
+    INT RightRect,
+    INT BottomRect
 )
 {
-    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;
+    PROSRGNDATA rgn;
 
-    EndPt = pts - 1;
-    for (poly = 0; poly < nbpolygons; poly++)
+    if ( !(rgn = RGNOBJAPI_Lock(hRgn, NULL)) )
     {
-        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++;
+        return 0; //per documentation
+    }
 
-            /*
-             *  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;
-            }
+    REGION_SetRectRgn(rgn, LeftRect, TopRect, RightRect, BottomRect);
 
-            /*
-             * 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 */
+    RGNOBJAPI_Unlock(rgn);
+    return TRUE;
+}
 
-                /*
-                 *  initialize integer edge algorithm
-                 */
-                dy = bottom->y - top->y;
-                BRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres);
+HRGN APIENTRY
+NtGdiUnionRectWithRgn(
+    HRGN hDest,
+    const RECTL *UnsafeRect
+)
+{
+    RECTL SafeRect = {0};
+    PROSRGNDATA Rgn;
+    NTSTATUS Status = STATUS_SUCCESS;
 
-                REGION_InsertEdgeInET(ET, pETEs, top->y, &pSLLBlock,
-                                      &iSLLBlock);
+    if (!(Rgn = RGNOBJAPI_Lock(hDest, NULL)))
+    {
+        EngSetLastError(ERROR_INVALID_HANDLE);
+        return NULL;
+    }
 
-                if (PrevPt->y > ET->ymax)
-                    ET->ymax = PrevPt->y;
-                if (PrevPt->y < ET->ymin)
-                    ET->ymin = PrevPt->y;
-                pETEs++;
-            }
+    _SEH2_TRY
+    {
+        ProbeForRead(UnsafeRect, sizeof(RECT), 1);
+        SafeRect = *UnsafeRect;
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        Status = _SEH2_GetExceptionCode();
+    }
+    _SEH2_END;
 
-            PrevPt = CurrPt;
-        }
+    if (! NT_SUCCESS(Status))
+    {
+        RGNOBJAPI_Unlock(Rgn);
+        SetLastNtError(Status);
+        return NULL;
     }
+
+    REGION_UnionRectWithRgn(Rgn, &SafeRect);
+    RGNOBJAPI_Unlock(Rgn);
+    return hDest;
 }
 
-HRGN FASTCALL
-IntCreatePolyPolygonRgn(
-    POINT *Pts,
-    PULONG Count,
-    INT nbpolygons,
-    INT mode
+/*!
+ * MSDN: GetRegionData, Return Values:
+ *
+ * "If the function succeeds and dwCount specifies an adequate number of bytes,
+ * the return value is always dwCount. If dwCount is too small or the function
+ * fails, the return value is 0. If lpRgnData is NULL, the return value is the
+ * required number of bytes.
+ *
+ * If the function fails, the return value is zero."
+ */
+DWORD APIENTRY
+NtGdiGetRegionData(
+    HRGN hrgn,
+    DWORD count,
+    LPRGNDATA rgndata
 )
 {
-    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 (mode == 0 || mode > 2) return 0;
+    DWORD size;
+    PROSRGNDATA obj = RGNOBJAPI_Lock(hrgn, NULL);
+    NTSTATUS Status = STATUS_SUCCESS;
 
-    if (!(region = REGION_AllocRgnWithHandle(nbpolygons)))
+    if (!obj)
         return 0;
-    hrgn = region->BaseObject.hHmgr;
-
-    /* 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))))
-    {
-        REGION_UnlockRgn(region);
-        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)) )
+    size = obj->rdh.nCount * sizeof(RECT);
+    if (count < (size + sizeof(RGNDATAHEADER)) || rgndata == NULL)
     {
-        GreDeleteObject(hrgn);
-        return 0;
+        RGNOBJAPI_Unlock(obj);
+        if (rgndata) /* buffer is too small, signal it by return 0 */
+            return 0;
+        else         /* user requested buffer size with rgndata NULL */
+            return size + sizeof(RGNDATAHEADER);
     }
-    pts = FirstPtBlock.pts;
-    REGION_CreateETandAET(Count, nbpolygons, Pts, &ET, &AET, pETEs, &SLLBlock);
-    pSLL = ET.scanlines.next;
-    curPtBlock = &FirstPtBlock;
 
-    if (mode != WINDING)
+    _SEH2_TRY
     {
-        /*
-         *  for each scanline
-         */
-        for (y = ET.ymin; y < ET.ymax; y++)
-        {
-            /*
-             *  Add a new edge to the active edge table when we
-             *  get to the next edge.
-             */
-            if (pSLL != NULL && y == pSLL->scanline)
-            {
-                REGION_loadAET(&AET, pSLL->edgelist);
-                pSLL = pSLL->next;
-            }
-            pPrevAET = &AET;
-            pAET = AET.next;
-
-            /*
-             *  for each active edge
-             */
-            while (pAET)
-            {
-                pts->x = pAET->bres.minor_axis,  pts->y = y;
-                pts++, iPts++;
-
-                /*
-                 *  send out the buffer
-                 */
-                if (iPts == NUMPTSTOBUFFER)
-                {
-                    tmpPtBlock = ExAllocatePoolWithTag(PagedPool, sizeof(POINTBLOCK), TAG_REGION);
-                    if (!tmpPtBlock)
-                    {
-                        DPRINT1("Can't alloc tPB\n");
-                        ExFreePoolWithTag(pETEs, TAG_REGION);
-                        return 0;
-                    }
-                    curPtBlock->next = tmpPtBlock;
-                    curPtBlock = tmpPtBlock;
-                    pts = curPtBlock->pts;
-                    numFullPtBlocks++;
-                    iPts = 0;
-                }
-                EVALUATEEDGEEVENODD(pAET, pPrevAET, y);
-            }
-            REGION_InsertionSort(&AET);
-        }
+        ProbeForWrite(rgndata, count, 1);
+        RtlCopyMemory(rgndata, &obj->rdh, sizeof(RGNDATAHEADER));
+        RtlCopyMemory(rgndata->Buffer, obj->Buffer, size);
     }
-    else
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
     {
-        /*
-         *  for each scanline
-         */
-        for (y = ET.ymin; y < ET.ymax; y++)
-        {
-            /*
-             *  Add a new edge to the active edge table when we
-             *  get to the next edge.
-             */
-            if (pSLL != NULL && y == pSLL->scanline)
-            {
-                REGION_loadAET(&AET, pSLL->edgelist);
-                REGION_computeWAET(&AET);
-                pSLL = pSLL->next;
-            }
-            pPrevAET = &AET;
-            pAET = AET.next;
-            pWETE = pAET;
-
-            /*
-             *  for each active edge
-             */
-            while (pAET)
-            {
-                /*
-                 *  add to the buffer only those edges that
-                 *  are in the Winding active edge table.
-                 */
-                if (pWETE == pAET)
-                {
-                    pts->x = pAET->bres.minor_axis,  pts->y = y;
-                    pts++, iPts++;
-
-                    /*
-                     *  send out the buffer
-                     */
-                    if (iPts == NUMPTSTOBUFFER)
-                    {
-                        tmpPtBlock = ExAllocatePoolWithTag(PagedPool,
-                                                           sizeof(POINTBLOCK), TAG_REGION);
-                        if (!tmpPtBlock)
-                        {
-                            DPRINT1("Can't alloc tPB\n");
-                            ExFreePoolWithTag(pETEs, TAG_REGION);
-                            GreDeleteObject(hrgn);
-                            return 0;
-                        }
-                        curPtBlock->next = tmpPtBlock;
-                        curPtBlock = tmpPtBlock;
-                        pts = curPtBlock->pts;
-                        numFullPtBlocks++;
-                        iPts = 0;
-                    }
-                    pWETE = pWETE->nextWETE;
-                }
-                EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET);
-            }
-
-            /*
-             *  recompute the winding active edge table if
-             *  we just resorted or have exited an edge.
-             */
-            if (REGION_InsertionSort(&AET) || fixWAET)
-            {
-                REGION_computeWAET(&AET);
-                fixWAET = FALSE;
-            }
-        }
+        Status = _SEH2_GetExceptionCode();
     }
-    REGION_FreeStorage(SLLBlock.next);
-    REGION_PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, region);
+    _SEH2_END;
 
-    for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;)
+    if (!NT_SUCCESS(Status))
     {
-        tmpPtBlock = curPtBlock->next;
-        ExFreePoolWithTag(curPtBlock, TAG_REGION);
-        curPtBlock = tmpPtBlock;
+        SetLastNtError(Status);
+        RGNOBJAPI_Unlock(obj);
+        return 0;
     }
-    ExFreePoolWithTag(pETEs, TAG_REGION);
-    REGION_UnlockRgn(region);
-    return hrgn;
+
+    RGNOBJAPI_Unlock(obj);
+    return size + sizeof(RGNDATAHEADER);
 }
 
 /* EOF */