[WIN32K] -NtGdiGetRegionData: prgn->rdh.nRgnSize is the size of kernel mode buffer...
[reactos.git] / reactos / win32ss / gdi / ntgdi / region.c
index 8ff07c7..13fae9e 100644 (file)
@@ -405,43 +405,109 @@ typedef struct _SCANLINE_LISTBLOCK
 #define LARGE_COORDINATE  0x7fffffff /* FIXME */
 #define SMALL_COORDINATE  0x80000000
 
-/*
- *   Check to see if there is enough memory in the present region.
- */
-static __inline INT xmemcheck(PREGION reg, PRECTL *rect, PRECTL *firstrect)
+static
+BOOL
+REGION_bGrowBufferSize(
+    _Inout_ PREGION prgn,
+    _In_ UINT cRects)
 {
-    if ((reg->rdh.nCount+1) * sizeof(RECT) >= reg->rdh.nRgnSize)
+    ULONG cjNewSize;
+    PVOID pvBuffer;
+    NT_ASSERT(cRects > 0);
+
+    /* Make sure we don't overflow */
+    if (cRects > MAXULONG / sizeof(RECTL))
     {
-        PRECTL temp;
-        DWORD NewSize = 2 * reg->rdh.nRgnSize;
+        return FALSE;
+    }
 
-        if (NewSize < (reg->rdh.nCount + 1) * sizeof(RECT))
-        {
-            NewSize = (reg->rdh.nCount + 1) * sizeof(RECT);
-        }
+    /* Calculate new buffer size */
+    cjNewSize = cRects * sizeof(RECTL);
 
-        temp = ExAllocatePoolWithTag(PagedPool, NewSize, TAG_REGION);
-        if (temp == NULL)
-        {
-            return 0;
-        }
+    /* Avoid allocating too often, by duplicating the old buffer size
+       Note: we don't do an overflow check, since the old size will never
+       get that large before running out of memory. */
+    if (2 * prgn->rdh.nRgnSize > cjNewSize)
+    {
+        cjNewSize = 2 * prgn->rdh.nRgnSize;
+    }
+
+    /* Allocate the new buffer */
+    pvBuffer = ExAllocatePoolWithTag(PagedPool, cjNewSize, TAG_REGION);
+    if (pvBuffer == NULL)
+    {
+        return FALSE;
+    }
 
-        /* Copy the rectangles */
-        COPY_RECTS(temp, *firstrect, reg->rdh.nCount);
+    /* Copy the rects into the new buffer */
+    COPY_RECTS(pvBuffer, prgn->Buffer, prgn->rdh.nCount);
 
-        reg->rdh.nRgnSize = NewSize;
-        if (*firstrect != &reg->rdh.rcBound)
-        {
-            ExFreePoolWithTag(*firstrect, TAG_REGION);
-        }
+    /* Free the old buffer */
+    if (prgn->Buffer != &prgn->rdh.rcBound)
+    {
+        ExFreePoolWithTag(prgn->Buffer, TAG_REGION);
+    }
+
+    /* Set the new buffer */
+    prgn->Buffer = pvBuffer;
+    prgn->rdh.nRgnSize = cjNewSize;
 
-        *firstrect = temp;
-        *rect = (*firstrect) + reg->rdh.nCount;
+    return TRUE;
+}
+
+static __inline
+BOOL
+REGION_bEnsureBufferSize(
+    _Inout_ PREGION prgn,
+    _In_ UINT cRects)
+{
+    /* Check if the current region size is too small */
+    if (cRects > prgn->rdh.nRgnSize / sizeof(RECTL))
+    {
+        /* Allocate a new buffer */
+        return REGION_bGrowBufferSize(prgn, cRects);
     }
-    return 1;
+
+    return TRUE;
 }
 
-#define MEMCHECK(reg, rect, firstrect) xmemcheck(reg,&(rect),(PRECTL *)&(firstrect))
+FORCEINLINE
+VOID
+REGION_vAddRect(
+    _Inout_ PREGION prgn,
+    _In_ LONG left,
+    _In_ LONG top,
+    _In_ LONG right,
+    _In_ LONG bottom)
+{
+    PRECTL prcl;
+    NT_ASSERT((prgn->rdh.nCount + 1) * sizeof(RECT) <= prgn->rdh.nRgnSize);
+
+    prcl = &prgn->Buffer[prgn->rdh.nCount];
+    prcl->left = left;
+    prcl->top = top;
+    prcl->right = right;
+    prcl->bottom = bottom;
+    prgn->rdh.nCount++;
+}
+
+static __inline
+BOOL
+REGION_bAddRect(
+    _Inout_ PREGION prgn,
+    _In_ LONG left,
+    _In_ LONG top,
+    _In_ LONG right,
+    _In_ LONG bottom)
+{
+    if (!REGION_bEnsureBufferSize(prgn, prgn->rdh.nCount + 1))
+    {
+        return FALSE;
+    }
+
+    REGION_vAddRect(prgn, left, top, right, bottom);
+    return TRUE;
+}
 
 typedef VOID (FASTCALL *overlapProcp)(PREGION, PRECT, PRECT, PRECT, PRECT, INT, INT);
 typedef VOID (FASTCALL *nonOverlapProcp)(PREGION, PRECT, PRECT, INT, INT);
@@ -468,7 +534,7 @@ IntDumpRegion(HRGN hRgn)
 {
     PREGION Data;
 
-    Data = RGNOBJAPI_Lock(hRgn, NULL);
+    Data = REGION_LockRgn(hRgn);
     if (Data == NULL)
     {
         DbgPrint("IntDumpRegion called with invalid region!\n");
@@ -483,7 +549,7 @@ IntDumpRegion(HRGN hRgn)
              Data->rdh.rcBound.bottom,
              Data->rdh.iType);
 
-    RGNOBJAPI_Unlock(Data);
+    REGION_UnlockRgn(Data);
 }
 #endif /* Not NDEBUG */
 
@@ -514,7 +580,7 @@ REGION_CopyRegion(
     PREGION dst,
     PREGION src)
 {
-    /* Only copy if source and dest are equal */
+    /* Only copy if source and dest are not equal */
     if (dst != src)
     {
         /* Check if we need to increase our buffer */
@@ -597,7 +663,7 @@ REGION_SetExtents(
 
 // FIXME: This function needs review and testing
 /***********************************************************************
- *           REGION_CropAndOffsetRegion
+ *           REGION_CropRegion
  */
 INT
 FASTCALL
@@ -671,8 +737,8 @@ REGION_CropRegion(
         lpr = &rgnSrc->Buffer[i];
 
         /* Make sure the source rect is not retarded */
-        ASSERT(lpr->bottom > rect->top);
-        ASSERT(lpr->right > rect->left);
+        ASSERT(lpr->bottom > lpr->top);
+        ASSERT(lpr->right > lpr->left);
 
         /* We already checked above, this should hold true */
         ASSERT(lpr->bottom > rect->top);
@@ -683,15 +749,15 @@ REGION_CropRegion(
         {
             rpr = &rgnDst->Buffer[j];
 
-            /* Crop the rect with the intersect rect and add offset */
+            /* Crop the rect with the intersect rect */
             rpr->top = max(lpr->top, rect->top);
             rpr->bottom = min(lpr->bottom, rect->bottom);
             rpr->left = max(lpr->left, rect->left);
             rpr->right = min(lpr->right, rect->right);
 
             /* Make sure the resulting rect is not retarded */
-            ASSERT(lpr->bottom > rect->top);
-            ASSERT(lpr->right > rect->left);
+            ASSERT(rpr->bottom > rpr->top);
+            ASSERT(rpr->right > rpr->left);
 
             /* Track new bounds */
             if (rpr->left < left) left = rpr->left;
@@ -1180,10 +1246,7 @@ REGION_IntersectO(
     INT     top,
     INT     bottom)
 {
-    INT       left, right;
-    RECTL     *pNextRect;
-
-    pNextRect = pReg->Buffer + pReg->rdh.nCount;
+    INT left, right;
 
     while ((r1 != r1End) && (r2 != r2End))
     {
@@ -1197,13 +1260,10 @@ REGION_IntersectO(
          * right next to each other. Since that should never happen... */
         if (left < right)
         {
-            MEMCHECK(pReg, pNextRect, pReg->Buffer);
-            pNextRect->left = left;
-            pNextRect->top = top;
-            pNextRect->right = right;
-            pNextRect->bottom = bottom;
-            pReg->rdh.nCount += 1;
-            pNextRect++;
+            if (!REGION_bAddRect(pReg, left, top, right, bottom))
+            {
+                return;
+            }
         }
 
         /* Need to advance the pointers. Shift the one that extends
@@ -1290,23 +1350,52 @@ REGION_UnionNonO(
     INT     top,
     INT     bottom)
 {
-    RECTL *pNextRect;
+    if (r != rEnd)
+    {
+        if (!REGION_bEnsureBufferSize(pReg, pReg->rdh.nCount + (rEnd - r)))
+        {
+            return;
+        }
+
+        do
+        {
+            REGION_vAddRect(pReg, r->left, top, r->right, bottom);
+            r++;
+        }
+        while (r != rEnd);
+    }
 
-    pNextRect = pReg->Buffer + pReg->rdh.nCount;
+    return;
+}
 
-    while (r != rEnd)
+static __inline
+BOOL
+REGION_bMergeRect(
+    _Inout_ PREGION prgn,
+    _In_ LONG left,
+    _In_ LONG top,
+    _In_ LONG right,
+    _In_ LONG bottom)
+{
+    if ((prgn->rdh.nCount != 0) &&
+        (prgn->Buffer[prgn->rdh.nCount - 1].top == top) &&
+        (prgn->Buffer[prgn->rdh.nCount - 1].bottom == bottom) &&
+        (prgn->Buffer[prgn->rdh.nCount - 1].right >= left))
+    {
+        if (prgn->Buffer[prgn->rdh.nCount - 1].right < right)
+        {
+            prgn->Buffer[prgn->rdh.nCount - 1].right = right;
+        }
+    }
+    else
     {
-        MEMCHECK(pReg, pNextRect, pReg->Buffer);
-        pNextRect->left = r->left;
-        pNextRect->top = top;
-        pNextRect->right = r->right;
-        pNextRect->bottom = bottom;
-        pReg->rdh.nCount += 1;
-        pNextRect++;
-        r++;
+        if (!REGION_bAddRect(prgn, left, top, right, bottom))
+        {
+            return FALSE;
+        }
     }
 
-    return;
+    return TRUE;
 }
 
 /*!
@@ -1333,42 +1422,17 @@ REGION_UnionO (
     INT     top,
     INT     bottom)
 {
-    RECTL *pNextRect;
-
-    pNextRect = pReg->Buffer + pReg->rdh.nCount;
-
-#define MERGERECT(r) \
-    if ((pReg->rdh.nCount != 0) &&  \
-        ((pNextRect-1)->top == top) &&  \
-        ((pNextRect-1)->bottom == bottom) &&  \
-        ((pNextRect-1)->right >= r->left))  \
-    {  \
-        if ((pNextRect-1)->right < r->right)  \
-        {  \
-            (pNextRect-1)->right = r->right;  \
-        }  \
-    }  \
-    else  \
-    {  \
-        MEMCHECK(pReg, pNextRect, pReg->Buffer);  \
-        pNextRect->top = top;  \
-        pNextRect->bottom = bottom;  \
-        pNextRect->left = r->left;  \
-        pNextRect->right = r->right;  \
-        pReg->rdh.nCount += 1;  \
-        pNextRect += 1;  \
-    }  \
-    r++;
-
     while ((r1 != r1End) && (r2 != r2End))
     {
         if (r1->left < r2->left)
         {
-            MERGERECT(r1);
+            REGION_bMergeRect(pReg, r1->left, top, r1->right, bottom);
+            r1++;
         }
         else
         {
-            MERGERECT(r2);
+            REGION_bMergeRect(pReg, r2->left, top, r2->right, bottom);
+            r2++;
         }
     }
 
@@ -1376,7 +1440,8 @@ REGION_UnionO (
     {
         do
         {
-            MERGERECT(r1);
+            REGION_bMergeRect(pReg, r1->left, top, r1->right, bottom);
+            r1++;
         }
         while (r1 != r1End);
     }
@@ -1384,7 +1449,8 @@ REGION_UnionO (
     {
         while (r2 != r2End)
         {
-            MERGERECT(r2);
+            REGION_bMergeRect(pReg, r2->left, top, r2->right, bottom);
+            r2++;
         }
     }
 
@@ -1497,20 +1563,19 @@ REGION_SubtractNonO1(
     INT     top,
     INT     bottom)
 {
-    RECTL *pNextRect;
-
-    pNextRect = pReg->Buffer + pReg->rdh.nCount;
-
-    while (r != rEnd)
+    if (r != rEnd)
     {
-        MEMCHECK(pReg, pNextRect, pReg->Buffer);
-        pNextRect->left = r->left;
-        pNextRect->top = top;
-        pNextRect->right = r->right;
-        pNextRect->bottom = bottom;
-        pReg->rdh.nCount += 1;
-        pNextRect++;
-        r++;
+        if (!REGION_bEnsureBufferSize(pReg, pReg->rdh.nCount + (rEnd - r)))
+        {
+            return;
+        }
+
+        do
+        {
+            REGION_vAddRect(pReg, r->left, top, r->right, bottom);
+            r++;
+        }
+        while (r != rEnd);
     }
 
     return;
@@ -1540,11 +1605,9 @@ REGION_SubtractO(
     INT     top,
     INT     bottom)
 {
-    RECTL *pNextRect;
     INT left;
 
     left = r1->left;
-    pNextRect = pReg->Buffer + pReg->rdh.nCount;
 
     while ((r1 != r1End) && (r2 != r2End))
     {
@@ -1576,13 +1639,11 @@ REGION_SubtractO(
         {
             /* Left part of subtrahend covers part of minuend: add uncovered
              * part of minuend to region and skip to next subtrahend. */
-            MEMCHECK(pReg, pNextRect, pReg->Buffer);
-            pNextRect->left = left;
-            pNextRect->top = top;
-            pNextRect->right = r2->left;
-            pNextRect->bottom = bottom;
-            pReg->rdh.nCount += 1;
-            pNextRect++;
+            if (!REGION_bAddRect(pReg, left, top, r2->left, bottom))
+            {
+                return;
+            }
+
             left = r2->right;
             if (left >= r1->right)
             {
@@ -1602,13 +1663,10 @@ REGION_SubtractO(
             /* Minuend used up: add any remaining piece before advancing. */
             if (r1->right > left)
             {
-                MEMCHECK(pReg, pNextRect, pReg->Buffer);
-                pNextRect->left = left;
-                pNextRect->top = top;
-                pNextRect->right = r1->right;
-                pNextRect->bottom = bottom;
-                pReg->rdh.nCount += 1;
-                pNextRect++;
+                if (!REGION_bAddRect(pReg, left, top, r1->right, bottom))
+                {
+                    return;
+                }
             }
 
             r1++;
@@ -1617,21 +1675,25 @@ REGION_SubtractO(
         }
     }
 
-    /* Add remaining minuend rectangles to region. */
-    while (r1 != r1End)
+    /* Make sure the buffer is large enough for all remaining operations */
+    if (r1 != r1End)
     {
-        MEMCHECK(pReg, pNextRect, pReg->Buffer);
-        pNextRect->left = left;
-        pNextRect->top = top;
-        pNextRect->right = r1->right;
-        pNextRect->bottom = bottom;
-        pReg->rdh.nCount += 1;
-        pNextRect++;
-        r1++;
-        if (r1 != r1End)
+        if (!REGION_bEnsureBufferSize(pReg, pReg->rdh.nCount + (r1End - r1)))
+        {
+            return;
+        }
+
+        /* Add remaining minuend rectangles to region. */
+        do
         {
-            left = r1->left;
+            REGION_vAddRect(pReg, left, top, r1->right, bottom);
+            r1++;
+            if (r1 != r1End)
+            {
+                left = r1->left;
+            }
         }
+        while (r1 != r1End);
     }
 
     return;
@@ -1706,7 +1768,7 @@ REGION_XorRegion(
     trb = REGION_AllocRgnWithHandle(srb->rdh.nCount + 1);
     if (trb == NULL)
     {
-        RGNOBJAPI_Unlock(tra);
+        REGION_UnlockRgn(tra);
         GreDeleteObject(htra);
         return;
     }
@@ -1715,8 +1777,8 @@ REGION_XorRegion(
     REGION_SubtractRegion(tra, sra, srb);
     REGION_SubtractRegion(trb, srb, sra);
     REGION_UnionRegion(dr, tra, trb);
-    RGNOBJAPI_Unlock(tra);
-    RGNOBJAPI_Unlock(trb);
+    REGION_UnlockRgn(tra);
+    REGION_UnlockRgn(trb);
 
     GreDeleteObject(htra);
     GreDeleteObject(htrb);
@@ -1759,258 +1821,359 @@ REGION_SubtractRectFromRgn(
     return REGION_Complexity(prgnDest);
 }
 
+static
 BOOL
-FASTCALL
-REGION_CreateSimpleFrameRgn(
-    PREGION rgn,
-    INT x,
-    INT y)
+REGION_bMakeSimpleFrameRgn(
+    _Inout_ PREGION prgn,
+    _In_ PRECTL prclSrc,
+    _In_ INT cx,
+    _In_ INT cy)
 {
-    RECTL rc[4];
-    PRECTL prc;
+    RECTL arcl[4];
+    UINT i;
+
+    NT_ASSERT((cx >= 0) && (cy >= 0));
+    NT_ASSERT((prclSrc->bottom > prclSrc->top) &&
+              (prclSrc->right > prclSrc->left));
 
-    if ((x != 0) || (y != 0))
+    /* Start with an empty region */
+    EMPTY_REGION(prgn);
+
+    /* Check for the case where the frame covers the whole rect */
+    if (((prclSrc->bottom - prclSrc->top) <= cy * 2) ||
+        ((prclSrc->right - prclSrc->left) <= cx * 2))
     {
-        prc = rc;
+        prgn->rdh.rcBound = *prclSrc;
+        prgn->Buffer[0] = *prclSrc;
+        prgn->rdh.nCount = 1;
+        return TRUE;
+    }
 
-        if ((rgn->rdh.rcBound.bottom - rgn->rdh.rcBound.top > y * 2) &&
-            (rgn->rdh.rcBound.right - rgn->rdh.rcBound.left > x * 2))
-        {
-            if (y != 0)
-            {
-                /* Top rectangle */
-                prc->left = rgn->rdh.rcBound.left;
-                prc->top = rgn->rdh.rcBound.top;
-                prc->right = rgn->rdh.rcBound.right;
-                prc->bottom = prc->top + y;
-                prc++;
-            }
+    i = 0;
 
-            if (x != 0)
-            {
-                /* Left rectangle */
-                prc->left = rgn->rdh.rcBound.left;
-                prc->top = rgn->rdh.rcBound.top + y;
-                prc->right = prc->left + x;
-                prc->bottom = rgn->rdh.rcBound.bottom - y;
-                prc++;
-
-                /* Right rectangle */
-                prc->left = rgn->rdh.rcBound.right - x;
-                prc->top = rgn->rdh.rcBound.top + y;
-                prc->right = rgn->rdh.rcBound.right;
-                prc->bottom = rgn->rdh.rcBound.bottom - y;
-                prc++;
-            }
+    if (cy != 0)
+    {
+        /* Top rectangle */
+        arcl[i].left = prclSrc->left;
+        arcl[i].top = prclSrc->top;
+        arcl[i].right = prclSrc->right;
+        arcl[i].bottom = prclSrc->top + cy;
+        i++;
+    }
 
-            if (y != 0)
-            {
-                /* Bottom rectangle */
-                prc->left = rgn->rdh.rcBound.left;
-                prc->top = rgn->rdh.rcBound.bottom - y;
-                prc->right = rgn->rdh.rcBound.right;
-                prc->bottom = rgn->rdh.rcBound.bottom;
-                prc++;
-            }
-        }
+    if (cx != 0)
+    {
+        /* Left rectangle */
+        arcl[i].left = prclSrc->left;
+        arcl[i].top = prclSrc->top + cy;
+        arcl[i].right = prclSrc->left + cx;
+        arcl[i].bottom = prclSrc->bottom - cy;
+        i++;
 
-        if (prc != rc)
-        {
-            /* The frame results in a complex region. rcBounds remains
-               the same, though. */
-            rgn->rdh.nCount = (DWORD)(prc - rc);
-            ASSERT(rgn->rdh.nCount > 1);
-            rgn->rdh.nRgnSize = rgn->rdh.nCount * sizeof(RECT);
-            rgn->Buffer = ExAllocatePoolWithTag(PagedPool,
-                                                rgn->rdh.nRgnSize,
-                                                TAG_REGION);
-            if (rgn->Buffer == NULL)
-            {
-                rgn->rdh.nRgnSize = 0;
-                return FALSE;
-            }
+        /* Right rectangle */
+        arcl[i].left = prclSrc->right - cx;
+        arcl[i].top = prclSrc->top + cy;
+        arcl[i].right = prclSrc->right;
+        arcl[i].bottom = prclSrc->bottom - cy;
+        i++;
+    }
+
+    if (cy != 0)
+    {
+        /* Bottom rectangle */
+        arcl[i].left = prclSrc->left;
+        arcl[i].top = prclSrc->bottom - cy;
+        arcl[i].right = prclSrc->right;
+        arcl[i].bottom = prclSrc->bottom;
+        i++;
+    }
 
-            _PRAGMA_WARNING_SUPPRESS(__WARNING_MAYBE_UNINIT_VAR) // rc is initialized
-            COPY_RECTS(rgn->Buffer, rc, rgn->rdh.nCount);
+    if (i != 0)
+    {
+        /* The frame results in a complex region. rcBounds remains
+           the same, though. */
+        prgn->rdh.nCount = i;
+        NT_ASSERT(prgn->rdh.nCount > 1);
+        prgn->rdh.nRgnSize = prgn->rdh.nCount * sizeof(RECT);
+        NT_ASSERT(prgn->Buffer == &prgn->rdh.rcBound);
+        prgn->Buffer = ExAllocatePoolWithTag(PagedPool,
+                                            prgn->rdh.nRgnSize,
+                                            TAG_REGION);
+        if (prgn->Buffer == NULL)
+        {
+            prgn->rdh.nRgnSize = 0;
+            return FALSE;
         }
+
+        _PRAGMA_WARNING_SUPPRESS(__WARNING_MAYBE_UNINIT_VAR) // arcl is initialized
+        COPY_RECTS(prgn->Buffer, arcl, prgn->rdh.nCount);
     }
 
     return TRUE;
 }
 
+static
 BOOL
-FASTCALL
-REGION_CreateFrameRgn(
-    HRGN hDest,
-    HRGN hSrc,
-    INT x,
-    INT y)
-{
-    PREGION srcObj, destObj;
-    PRECTL rc;
-    ULONG i;
+REGION_bMakeFrameRegion(
+    _Inout_ PREGION prgnDest,
+    _Inout_ PREGION prgnSrc,
+    _In_ INT cx,
+    _In_ INT cy)
+{
+    /* Handle negative cx / cy */
+    cx = abs(cx);
+    cy = abs(cy);
 
-    srcObj = RGNOBJAPI_Lock(hSrc, NULL);
-    if (srcObj == NULL)
+    /* Check border size (the cast is necessary to catch cx/cy == INT_MIN!) */
+    if (((UINT)cx > MAX_COORD) || ((UINT)cy > MAX_COORD))
     {
         return FALSE;
     }
 
-    if (!REGION_NOT_EMPTY(srcObj))
+    /* Fail on empty source region */
+    if (!REGION_NOT_EMPTY(prgnSrc))
     {
-        RGNOBJAPI_Unlock(srcObj);
         return FALSE;
     }
 
-    destObj = RGNOBJAPI_Lock(hDest, NULL);
-    if (destObj == NULL)
+    /* Handle trivial case */
+    if ((cx == 0) && (cy == 0))
     {
-        RGNOBJAPI_Unlock(srcObj);
-        return FALSE;
+        EMPTY_REGION(prgnDest);
+        return TRUE;
     }
 
-    EMPTY_REGION(destObj);
-    if (!REGION_CopyRegion(destObj, srcObj))
+    /* Handle simple source region */
+    if (REGION_Complexity(prgnSrc) == SIMPLEREGION)
     {
-        RGNOBJAPI_Unlock(destObj);
-        RGNOBJAPI_Unlock(srcObj);
-        return FALSE;
+        return REGION_bMakeSimpleFrameRgn(prgnDest, &prgnSrc->rdh.rcBound, cx, cy);
     }
 
-    if (REGION_Complexity(srcObj) == SIMPLEREGION)
+    /* Check if we can move the region to create the frame region */
+    if ((prgnSrc->rdh.rcBound.left < (MIN_COORD + cx)) ||
+        (prgnSrc->rdh.rcBound.top < (MIN_COORD + cy)) ||
+        (prgnSrc->rdh.rcBound.right > (MAX_COORD - cx)) ||
+        (prgnSrc->rdh.rcBound.bottom > (MAX_COORD - cy)))
     {
-        if (!REGION_CreateSimpleFrameRgn(destObj, x, y))
-        {
-            EMPTY_REGION(destObj);
-            RGNOBJAPI_Unlock(destObj);
-            RGNOBJAPI_Unlock(srcObj);
-            return FALSE;
-        }
+        return FALSE;
     }
-    else
+
+    /* Copy the source region */
+    if (!REGION_CopyRegion(prgnDest, prgnSrc))
     {
-        /* Original region moved to right */
-        rc = srcObj->Buffer;
-        for (i = 0; i < srcObj->rdh.nCount; i++)
-        {
-            rc->left += x;
-            rc->right += x;
-            rc++;
-        }
+        return FALSE;
+    }
 
-        REGION_IntersectRegion(destObj, destObj, srcObj);
+    /* Move the source region to the bottom-right */
+    NT_VERIFY(REGION_bOffsetRgn(prgnSrc, cx, cy));
 
-        /* Original region moved to left */
-        rc = srcObj->Buffer;
-        for (i = 0; i < srcObj->rdh.nCount; i++)
-        {
-            rc->left -= 2 * x;
-            rc->right -= 2 * x;
-            rc++;
-        }
+    /* Intersect with the source region (this crops the top-left frame) */
+    REGION_IntersectRegion(prgnDest, prgnDest, prgnSrc);
 
-        REGION_IntersectRegion(destObj, destObj, srcObj);
+    /* Move the source region to the bottom-left */
+    NT_VERIFY(REGION_bOffsetRgn(prgnSrc, -2 * cx, 0));
 
-        /* Original region moved down */
-        rc = srcObj->Buffer;
-        for (i = 0; i < srcObj->rdh.nCount; i++)
-        {
-            rc->left += x;
-            rc->right += x;
-            rc->top += y;
-            rc->bottom += y;
-            rc++;
-        }
+    /* Intersect with the source region (this crops the top-right frame) */
+    REGION_IntersectRegion(prgnDest, prgnDest, prgnSrc);
 
-        REGION_IntersectRegion(destObj, destObj, srcObj);
+    /* Move the source region to the top-left */
+    NT_VERIFY(REGION_bOffsetRgn(prgnSrc, 0, -2 * cy));
 
-        /* Original region moved up */
-        rc = srcObj->Buffer;
-        for (i = 0; i < srcObj->rdh.nCount; i++)
-        {
-            rc->top -= 2 * y;
-            rc->bottom -= 2 * y;
-            rc++;
-        }
+    /* Intersect with the source region (this crops the bottom-right frame) */
+    REGION_IntersectRegion(prgnDest, prgnDest, prgnSrc);
 
-        REGION_IntersectRegion(destObj, destObj, srcObj);
+    /* Move the source region to the top-right  */
+    NT_VERIFY(REGION_bOffsetRgn(prgnSrc, 2 * cx, 0));
 
-        /* Restore the original region */
-        rc = srcObj->Buffer;
-        for (i = 0; i < srcObj->rdh.nCount; i++)
-        {
-            rc->top += y;
-            rc->bottom += y;
-            rc++;
-        }
+    /* Intersect with the source region (this crops the bottom-left frame) */
+    REGION_IntersectRegion(prgnDest, prgnDest, prgnSrc);
 
-        REGION_SubtractRegion(destObj, srcObj, destObj);
-    }
+    /* Move the source region back to the original position */
+    NT_VERIFY(REGION_bOffsetRgn(prgnSrc, -cx, cy));
+
+    /* Finally subtract the cropped region from the source */
+    REGION_SubtractRegion(prgnDest, prgnSrc, prgnDest);
 
-    RGNOBJAPI_Unlock(destObj);
-    RGNOBJAPI_Unlock(srcObj);
     return TRUE;
 }
 
+HRGN
+FASTCALL
+GreCreateFrameRgn(
+    HRGN hrgn,
+    INT cx,
+    INT cy)
+{
+    PREGION prgnFrame, prgnSrc;
+    HRGN hrgnFrame;
+
+    /* Allocate a new region */
+    prgnFrame = REGION_AllocUserRgnWithHandle(1);
+    if (prgnFrame == NULL)
+    {
+        EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        return NULL;
+    }
+
+    /* Lock the source region */
+    prgnSrc = REGION_LockRgn(hrgn);
+    if (prgnSrc == NULL)
+    {
+        REGION_Delete(prgnFrame);
+        return FALSE;
+    }
+
+    if (REGION_bMakeFrameRegion(prgnFrame, prgnSrc, cx, cy))
+    {
+        hrgnFrame = prgnFrame->BaseObject.hHmgr;
+        REGION_UnlockRgn(prgnFrame);
+    }
+    else
+    {
+        REGION_Delete(prgnFrame);
+        hrgnFrame = NULL;
+    }
+
+    REGION_UnlockRgn(prgnSrc);
+    return hrgnFrame;
+}
 
-static
 BOOL
 FASTCALL
-REGION_LPTODP(
-    _In_ PDC  dc,
-    _Inout_ PREGION RgnDest,
-    _In_ PREGION RgnSrc)
+REGION_bXformRgn(
+    _Inout_ PREGION prgn,
+    _In_ PMATRIX pmx)
 {
-    RECTL *pCurRect, *pEndRect;
-    RECTL tmpRect;
-    PDC_ATTR pdcattr;
+    XFORMOBJ xo;
+    ULONG i, j, cjSize;
+    PPOINT ppt;
+    PULONG pcPoints;
+    RECT rect;
+    BOOL bResult;
 
-    if (dc == NULL)
-        return FALSE;
-    pdcattr = dc->pdcattr;
+    /* Check for zero rectangles and return TRUE for translation only matrices */
+    if (prgn->rdh.nCount < 1)
+        return (pmx->flAccel & XFORM_UNITY) != 0;
 
-    if (pdcattr->iMapMode == MM_TEXT) // Requires only a translation
+    /* Check if this is a scaling only matrix (off-diagonal elements are 0 */
+    if (pmx->flAccel & XFORM_SCALE)
     {
-        if (IntGdiCombineRgn(RgnDest, RgnSrc, 0, RGN_COPY) == ERROR)
-            return FALSE;
+        /* Check if this is a translation only matrix */
+        if (pmx->flAccel & XFORM_UNITY)
+        {
+            /* Just offset the region */
+            return REGION_bOffsetRgn(prgn, (pmx->fxDx + 8) / 16, (pmx->fxDy + 8) / 16);
+        }
+        else
+        {
+            /* Initialize the xform object */
+            XFORMOBJ_vInit(&xo, pmx);
 
-        IntGdiOffsetRgn(RgnDest,
-                        pdcattr->ptlViewportOrg.x - pdcattr->ptlWindowOrg.x,
-                        pdcattr->ptlViewportOrg.y - pdcattr->ptlWindowOrg.y);
-        return TRUE;
-    }
+            /* Scaling can move the rects out of the coordinate space, so
+             * we first need to check whether we can apply the transformation
+             * on the bounds rect without modifying the region */
+            if (!XFORMOBJ_bApplyXform(&xo, XF_LTOL, 2, &prgn->rdh.rcBound, &rect))
+            {
+                return FALSE;
+            }
+
+            /* Apply the xform to the rects in the region */
+            if (!XFORMOBJ_bApplyXform(&xo,
+                                      XF_LTOL,
+                                      prgn->rdh.nCount * 2,
+                                      prgn->Buffer,
+                                      prgn->Buffer))
+            {
+                /* This can not happen, since we already checked the bounds! */
+                NT_ASSERT(FALSE);
+            }
+
+            /* Reset bounds */
+            RECTL_vSetEmptyRect(&prgn->rdh.rcBound);
+
+            /* Loop all rects in the region */
+            for (i = 0; i < prgn->rdh.nCount; i++)
+            {
+                /* Make sure the rect is well-ordered after the xform */
+                RECTL_vMakeWellOrdered(&prgn->Buffer[i]);
+
+                /* Update bounds */
+                RECTL_bUnionRect(&prgn->rdh.rcBound,
+                                 &prgn->rdh.rcBound,
+                                 &prgn->Buffer[i]);
+            }
 
-    EMPTY_REGION(RgnDest);
+            /* Loop all rects in the region */
+            for (i = 0; i < prgn->rdh.nCount - 1; i++)
+            {
+                for (j = i; i < prgn->rdh.nCount; i++)
+                {
+                    NT_ASSERT(prgn->Buffer[i].top < prgn->Buffer[i].bottom);
+                    NT_ASSERT(prgn->Buffer[j].top >= prgn->Buffer[i].top);
+                }
+            }
 
-    pEndRect = RgnSrc->Buffer + RgnSrc->rdh.nCount;
-    for (pCurRect = RgnSrc->Buffer; pCurRect < pEndRect; pCurRect++)
+            return TRUE;
+        }
+    }
+    else
     {
-        tmpRect = *pCurRect;
-        tmpRect.left = XLPTODP(pdcattr, tmpRect.left);
-        tmpRect.top = YLPTODP(pdcattr, tmpRect.top);
-        tmpRect.right = XLPTODP(pdcattr, tmpRect.right);
-        tmpRect.bottom = YLPTODP(pdcattr, tmpRect.bottom);
+        /* Allocate a buffer for the polygons */
+        cjSize = prgn->rdh.nCount * (4 * sizeof(POINT) + sizeof(ULONG));
+        ppt = ExAllocatePoolWithTag(PagedPool, cjSize, GDITAG_REGION);
+        if (ppt == NULL)
+        {
+            return FALSE;
+        }
 
-        if (tmpRect.left > tmpRect.right)
+        /* Fill the buffer with the rects */
+        pcPoints = (PULONG)&ppt[4 * prgn->rdh.nCount];
+        for (i = 0; i < prgn->rdh.nCount; i++)
         {
-            INT tmp = tmpRect.left;
-            tmpRect.left = tmpRect.right;
-            tmpRect.right = tmp;
+            /* Make sure the rect is within the legal range */
+            pcPoints[i] = 4;
+            ppt[4 * i + 0].x = prgn->Buffer[i].left;
+            ppt[4 * i + 0].y = prgn->Buffer[i].top;
+            ppt[4 * i + 1].x = prgn->Buffer[i].right;
+            ppt[4 * i + 1].y = prgn->Buffer[i].top;
+            ppt[4 * i + 2].x = prgn->Buffer[i].right;
+            ppt[4 * i + 2].y = prgn->Buffer[i].bottom;
+            ppt[4 * i + 3].x = prgn->Buffer[i].left;
+            ppt[4 * i + 3].y = prgn->Buffer[i].bottom;
         }
 
-        if (tmpRect.top > tmpRect.bottom)
+        /* Initialize the xform object */
+        XFORMOBJ_vInit(&xo, pmx);
+
+        /* Apply the xform to the rects in the buffer */
+        if (!XFORMOBJ_bApplyXform(&xo,
+                                  XF_LTOL,
+                                  prgn->rdh.nCount * 2,
+                                  ppt,
+                                  ppt))
         {
-            INT tmp = tmpRect.top;
-            tmpRect.top = tmpRect.bottom;
-            tmpRect.bottom = tmp;
+            /* This means, there were coordinates that would go outside of
+               the coordinate space after the transformation */
+            ExFreePoolWithTag(ppt, GDITAG_REGION);
+            return FALSE;
         }
 
-        REGION_UnionRectWithRgn(RgnDest, &tmpRect);
+        /* Now use the polygons to create a polygon region */
+        bResult = REGION_SetPolyPolygonRgn(prgn,
+                                           ppt,
+                                           pcPoints,
+                                           prgn->rdh.nCount,
+                                           WINDING);
+
+        /* Free the polygon buffer */
+        ExFreePoolWithTag(ppt, GDITAG_REGION);
+
+        return bResult;
     }
 
-    return TRUE;
 }
 
+
 PREGION
 FASTCALL
 REGION_AllocRgnWithHandle(
@@ -2028,13 +2191,6 @@ REGION_AllocRgnWithHandle(
         return NULL;
     }
 
-    if (!GDIOBJ_hInsertObject(&pReg->BaseObject, GDI_OBJ_HMGR_POWNED))
-    {
-        DPRINT1("Could not insert palette into handle table.\n");
-        GDIOBJ_vFreeObject(&pReg->BaseObject);
-        return NULL;
-    }
-
     //hReg = pReg->BaseObject.hHmgr;
 
     if ((nReg == 0) || (nReg == 1))
@@ -2062,6 +2218,19 @@ REGION_AllocRgnWithHandle(
     pReg->rdh.nRgnSize = nReg * sizeof(RECT);
     pReg->prgnattr = &pReg->rgnattr;
 
+    /* Initialize the region attribute */
+    pReg->rgnattr.AttrFlags = 0;
+    pReg->rgnattr.iComplexity = SIMPLEREGION;
+    pReg->rgnattr.Rect = pReg->rdh.rcBound;
+
+    /* Finally insert the region into the handle table */
+    if (!GDIOBJ_hInsertObject(&pReg->BaseObject, GDI_OBJ_HMGR_POWNED))
+    {
+        DPRINT1("Could not insert palette into handle table.\n");
+        GDIOBJ_vFreeObject(&pReg->BaseObject);
+        return NULL;
+    }
+
     return pReg;
 }
 
@@ -2073,6 +2242,8 @@ REGION_bAllocRgnAttr(
     PPROCESSINFO ppi;
     PRGN_ATTR prgnattr;
 
+    NT_ASSERT(prgn->prgnattr == &prgn->rgnattr);
+
     ppi = PsGetCurrentProcessWin32Process();
     ASSERT(ppi);
 
@@ -2083,6 +2254,9 @@ REGION_bAllocRgnAttr(
         return FALSE;
     }
 
+    /* Copy the current region attribute */
+    *prgnattr = prgn->rgnattr;
+
     /* Set the object attribute in the handle table */
     prgn->prgnattr = prgnattr;
     GDIOBJ_vSetObjectAttr(&prgn->BaseObject, prgnattr);
@@ -2115,105 +2289,88 @@ REGION_AllocUserRgnWithHandle(
     return prgn;
 }
 
+static
 VOID
-NTAPI
 REGION_vSyncRegion(
-    PREGION pRgn)
+    _In_ PREGION prgn)
 {
-    PRGN_ATTR pRgn_Attr = NULL;
+    PRGN_ATTR prgnattr;
+
+    NT_ASSERT(prgn != NULL);
+    NT_ASSERT(prgn->prgnattr != NULL);
+    NT_ASSERT((prgn->prgnattr == &prgn->rgnattr) ||
+              (prgn->prgnattr->AttrFlags & ATTR_RGN_VALID));
 
-    if (pRgn && pRgn->prgnattr != &pRgn->rgnattr)
+    /* Get the region attribute and check if it's dirty (modified) */
+    prgnattr = prgn->prgnattr;
+    if (prgnattr->AttrFlags & ATTR_RGN_DIRTY)
     {
-        pRgn_Attr = GDIOBJ_pvGetObjectAttr(&pRgn->BaseObject);
+        NT_ASSERT(GreGetObjectOwner(prgn->BaseObject.hHmgr) == GDI_OBJ_HMGR_POWNED);
+        NT_ASSERT(prgnattr != &prgn->rgnattr);
 
-        if ( pRgn_Attr )
+        if (prgnattr->iComplexity == NULLREGION)
         {
-            _SEH2_TRY
-            {
-                if ( !(pRgn_Attr->AttrFlags & ATTR_CACHED) )
-                {
-                    if ( pRgn_Attr->AttrFlags & (ATTR_RGN_VALID|ATTR_RGN_DIRTY) )
-                    {
-                        switch (pRgn_Attr->iComplexity)
-                        {
-                            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)
-            {
-                (VOID)0;
-            }
-            _SEH2_END;
+            EMPTY_REGION(prgn);
         }
-    }
-
-}
+        else if (prgnattr->iComplexity == SIMPLEREGION)
+        {
+            REGION_SetRectRgn(prgn,
+                              prgnattr->Rect.left,
+                              prgnattr->Rect.top,
+                              prgnattr->Rect.right,
+                              prgnattr->Rect.bottom);
+        }
+        else
+        {
+            /* Should not happen, region attribute is corrupted! */
+            DPRINT1("Region attribute is corrupted, ignoring\n");
+            NT_ASSERT(FALSE);
+        }
+    }
+
+    /* Reset the flags */
+    prgnattr->AttrFlags &= ~(ATTR_RGN_DIRTY | ATTR_RGN_VALID);
+}
 
 PREGION
 FASTCALL
-RGNOBJAPI_Lock(
-    HRGN hRgn,
-    PRGN_ATTR *ppRgn_Attr)
+REGION_LockRgn(
+    _In_ HRGN hrgn)
 {
-    PREGION pRgn;
+    PREGION prgn;
 
-    pRgn = REGION_LockRgn(hRgn);
-    if (pRgn == NULL)
+    prgn = GDIOBJ_LockObject(hrgn, GDIObjType_RGN_TYPE);
+    if (prgn == NULL)
         return NULL;
 
-    REGION_vSyncRegion(pRgn);
-
-    if (ppRgn_Attr)
-        *ppRgn_Attr = pRgn->prgnattr;
-
-    return pRgn;
+    REGION_vSyncRegion(prgn);
+    return prgn;
 }
 
 VOID
 FASTCALL
-RGNOBJAPI_Unlock(
-    PREGION pRgn)
+REGION_UnlockRgn(
+    _In_ PREGION prgn)
 {
-    PRGN_ATTR pRgn_Attr;
+    PRGN_ATTR prgnattr;
 
-    if (pRgn && GreGetObjectOwner(pRgn->BaseObject.hHmgr) == GDI_OBJ_HMGR_POWNED)
-    {
-        pRgn_Attr = GDIOBJ_pvGetObjectAttr(&pRgn->BaseObject);
+    NT_ASSERT(prgn != NULL);
+    NT_ASSERT(prgn->prgnattr != NULL);
 
-        if ( pRgn_Attr )
-        {
-            _SEH2_TRY
-            {
-                if ( pRgn_Attr->AttrFlags & ATTR_RGN_VALID )
-                {
-                    pRgn_Attr->iComplexity = 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)
-            {
-                (VOID)0;
-            }
-            _SEH2_END;
-        }
+    /* Get the region attribute and check if it's user mode */
+    prgnattr = prgn->prgnattr;
+    if (prgnattr != &prgn->rgnattr)
+    {
+        NT_ASSERT(GreGetObjectOwner(prgn->BaseObject.hHmgr) == GDI_OBJ_HMGR_POWNED);
+        prgnattr->iComplexity = REGION_Complexity(prgn);
+        prgnattr->Rect.left   = prgn->rdh.rcBound.left;
+        prgnattr->Rect.top    = prgn->rdh.rcBound.top;
+        prgnattr->Rect.right  = prgn->rdh.rcBound.right;
+        prgnattr->Rect.bottom = prgn->rdh.rcBound.bottom;
+        prgnattr->AttrFlags |= ATTR_RGN_VALID;
     }
-    REGION_UnlockRgn(pRgn);
+
+    GDIOBJ_vUnlockObject(&prgn->BaseObject);
 }
 
 /*
@@ -2234,7 +2391,7 @@ IntSysCreateRectpRgn(
 {
     PREGION prgn;
 
-    /* Allocate a region, witout a handle */
+    /* Allocate a region, without a handle */
     prgn = (PREGION)GDIOBJ_AllocateObject(GDIObjType_RGN_TYPE, sizeof(REGION), BASEFLAG_LOOKASIDE);
     if (prgn == NULL)
     {
@@ -2244,6 +2401,7 @@ IntSysCreateRectpRgn(
     /* Initialize it */
     prgn->Buffer = &prgn->rdh.rcBound;
     prgn->prgnattr = &prgn->rgnattr;
+    prgn->prgnattr->AttrFlags = ATTR_RGN_VALID;
     REGION_SetRectRgn(prgn, LeftRect, TopRect, RightRect, BottomRect);
 
     return prgn;
@@ -2275,70 +2433,6 @@ REGION_Delete(PREGION pRgn)
     GDIOBJ_vDeleteObject(&pRgn->BaseObject);
 }
 
-VOID
-FASTCALL
-IntGdiReleaseRaoRgn(PDC pDC)
-{
-    INT Index = GDI_HANDLE_GET_INDEX(pDC->BaseObject.hHmgr);
-    PGDI_TABLE_ENTRY Entry = &GdiHandleTable->Entries[Index];
-    pDC->fs |= DC_FLAG_DIRTY_RAO;
-    Entry->Flags |= GDI_ENTRY_VALIDATE_VIS;
-    RECTL_vSetEmptyRect(&pDC->erclClip);
-    REGION_Delete(pDC->prgnRao);
-    pDC->prgnRao = NULL;
-}
-
-VOID
-FASTCALL
-IntGdiReleaseVisRgn(PDC pDC)
-{
-    INT Index = GDI_HANDLE_GET_INDEX(pDC->BaseObject.hHmgr);
-    PGDI_TABLE_ENTRY Entry = &GdiHandleTable->Entries[Index];
-    pDC->fs |= DC_FLAG_DIRTY_RAO;
-    Entry->Flags |= GDI_ENTRY_VALIDATE_VIS;
-    RECTL_vSetEmptyRect(&pDC->erclClip);
-    REGION_Delete(pDC->prgnVis);
-    pDC->prgnVis = prgnDefault;
-}
-
-VOID
-FASTCALL
-IntUpdateVisRectRgn(PDC pDC, PREGION pRgn)
-{
-    INT Index = GDI_HANDLE_GET_INDEX(pDC->BaseObject.hHmgr);
-    PGDI_TABLE_ENTRY Entry = &GdiHandleTable->Entries[Index];
-    PDC_ATTR pdcattr;
-    RECTL rcl;
-
-    if (Entry->Flags & GDI_ENTRY_VALIDATE_VIS)
-    {
-        pdcattr = pDC->pdcattr;
-
-        pdcattr->VisRectRegion.iComplexity = REGION_Complexity(pRgn);
-
-        if (pRgn && pdcattr->VisRectRegion.iComplexity != NULLREGION)
-        {
-            rcl.left   = pRgn->rdh.rcBound.left;
-            rcl.top    = pRgn->rdh.rcBound.top;
-            rcl.right  = pRgn->rdh.rcBound.right;
-            rcl.bottom = pRgn->rdh.rcBound.bottom;
-
-            rcl.left   -= pDC->erclWindow.left;
-            rcl.top    -= pDC->erclWindow.top;
-            rcl.right  -= pDC->erclWindow.left;
-            rcl.bottom -= pDC->erclWindow.top;
-        }
-        else
-        {
-            RECTL_vSetEmptyRect(&rcl);
-        }
-
-        pdcattr->VisRectRegion.Rect = rcl;
-
-        Entry->Flags &= ~GDI_ENTRY_VALIDATE_VIS;
-    }
-}
-
 BOOL
 FASTCALL
 IntGdiSetRegionOwner(HRGN hRgn, DWORD OwnerMask)
@@ -2347,12 +2441,13 @@ IntGdiSetRegionOwner(HRGN hRgn, DWORD OwnerMask)
     PRGN_ATTR prgnattr;
     PPROCESSINFO ppi;
 
-    prgn = RGNOBJAPI_Lock(hRgn, &prgnattr);
+    prgn = REGION_LockRgn(hRgn);
     if (prgn == NULL)
     {
         return FALSE;
     }
 
+    prgnattr = prgn->prgnattr;
     if (prgnattr != &prgn->rgnattr)
     {
         GDIOBJ_vSetObjectAttr(&prgn->BaseObject, NULL);
@@ -2361,7 +2456,7 @@ IntGdiSetRegionOwner(HRGN hRgn, DWORD OwnerMask)
         GdiPoolFree(ppi->pPoolRgnAttr, prgnattr);
     }
 
-    RGNOBJAPI_Unlock(prgn);
+    REGION_UnlockRgn(prgn);
 
     return GreSetObjectOwner(hRgn, OwnerMask);
 }
@@ -2448,78 +2543,18 @@ IntGdiGetRgnBox(
     PREGION Rgn;
     DWORD ret;
 
-    Rgn = RGNOBJAPI_Lock(hRgn, NULL);
+    Rgn = REGION_LockRgn(hRgn);
     if (Rgn == NULL)
     {
         return ERROR;
     }
 
     ret = REGION_GetRgnBox(Rgn, pRect);
-    RGNOBJAPI_Unlock(Rgn);
+    REGION_UnlockRgn(Rgn);
 
     return ret;
 }
 
-BOOL
-FASTCALL
-IntGdiPaintRgn(
-    PDC dc,
-    PREGION Rgn)
-{
-    PREGION VisRgn;
-    XCLIPOBJ ClipRegion;
-    BOOL bRet = FALSE;
-    POINTL BrushOrigin;
-    SURFACE *psurf;
-    PDC_ATTR pdcattr;
-
-    if ((dc == NULL) || (Rgn == NULL))
-        return FALSE;
-
-    pdcattr = dc->pdcattr;
-
-    ASSERT(!(pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY)));
-
-    VisRgn = IntSysCreateRectpRgn(0, 0, 0, 0);
-    if (VisRgn == NULL)
-    {
-        return FALSE;
-    }
-
-    // Transform region into device co-ords
-    if (!REGION_LPTODP(dc, VisRgn, Rgn) ||
-        IntGdiOffsetRgn(VisRgn, dc->ptlDCOrig.x, dc->ptlDCOrig.y) == ERROR)
-    {
-        REGION_Delete(VisRgn);
-        return FALSE;
-    }
-
-    if (dc->prgnRao)
-        IntGdiCombineRgn(VisRgn, VisRgn, dc->prgnRao, RGN_AND);
-
-    IntEngInitClipObj(&ClipRegion);
-    IntEngUpdateClipRegion(&ClipRegion,
-                           VisRgn->rdh.nCount,
-                           VisRgn->Buffer,
-                           &VisRgn->rdh.rcBound );
-
-    BrushOrigin.x = pdcattr->ptlBrushOrigin.x;
-    BrushOrigin.y = pdcattr->ptlBrushOrigin.y;
-    psurf = dc->dclevel.pSurface;
-    /* FIXME: Handle psurf == NULL !!!! */
-
-    bRet = IntEngPaint(&psurf->SurfObj,
-                       &ClipRegion.ClipObj,
-                       &dc->eboFill.BrushObject,
-                       &BrushOrigin,
-                       0xFFFF); // FIXME: Don't know what to put here
-
-    REGION_Delete(VisRgn);
-    IntEngFreeClipResources(&ClipRegion);
-
-    // Fill the region
-    return bRet;
-}
 
 BOOL
 FASTCALL
@@ -2646,40 +2681,93 @@ REGION_SetRectRgn(
     }
 }
 
-INT
+BOOL
 FASTCALL
-IntGdiOffsetRgn(
-    PREGION rgn,
-    INT XOffset,
-    INT YOffset)
+REGION_bOffsetRgn(
+    _Inout_ PREGION prgn,
+    _In_ INT cx,
+    _In_ INT cy)
 {
-    if (XOffset || YOffset)
+    PRECTL prcl;
+    UINT i;
+
+    NT_ASSERT(prgn != NULL);
+
+    /* Check for trivial case */
+    if ((cx == 0) && (cy == 0))
+    {
+        return TRUE;
+    }
+
+    /* Check for empty regions, we ignore the offset values here */
+    if (prgn->rdh.nCount == 0)
     {
-        int nbox = rgn->rdh.nCount;
-        PRECTL pbox = rgn->Buffer;
+        return TRUE;
+    }
 
-        if (nbox && pbox)
+    /* Make sure the offset is within the legal range */
+    if ((cx > MAX_COORD) || (cx < MIN_COORD) ||
+        (cy > MAX_COORD) || (cy < MIN_COORD))
+    {
+        return FALSE;
+    }
+
+    /* Are we moving right? */
+    if (cx > 0)
+    {
+        /* Check if we stay inside the bounds on the right side */
+        if (prgn->rdh.rcBound.right > (MAX_COORD - cx))
         {
-            while (nbox--)
-            {
-                pbox->left += XOffset;
-                pbox->right += XOffset;
-                pbox->top += YOffset;
-                pbox->bottom += YOffset;
-                pbox++;
-            }
+            return FALSE;
+        }
+    }
+    else
+    {
+        /* Check if we stay inside the bounds on the left side */
+        if (prgn->rdh.rcBound.left < (MIN_COORD - cx))
+        {
+            return FALSE;
+        }
+    }
 
-            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;
-            }
+    /* Are we moving down? */
+    if (cy > 0)
+    {
+        /* Check if we stay inside the bounds on the right side */
+        if (prgn->rdh.rcBound.bottom > (MAX_COORD - cy))
+        {
+            return FALSE;
+        }
+    }
+    else
+    {
+        /* Check if we stay inside the bounds on the left side */
+        if (prgn->rdh.rcBound.top < (MIN_COORD - cy))
+        {
+            return FALSE;
         }
     }
 
-    return REGION_Complexity(rgn);
+    /* Loop to move the rects */
+    prcl = prgn->Buffer;
+    for (i = 0; i < prgn->rdh.nCount; i++)
+    {
+        prcl[i].left += cx;
+        prcl[i].right += cx;
+        prcl[i].top += cy;
+        prcl[i].bottom += cy;
+    }
+
+    /* Finally update the bounds rect */
+    if (prgn->Buffer != &prgn->rdh.rcBound)
+    {
+        prgn->rdh.rcBound.left += cx;
+        prgn->rdh.rcBound.right += cx;
+        prgn->rdh.rcBound.top += cy;
+        prgn->rdh.rcBound.bottom += cy;
+    }
+
+    return TRUE;
 }
 
 /***********************************************************************
@@ -3031,7 +3119,7 @@ REGION_PtsToRegion(
 }
 
 /***********************************************************************
- *     REGION_CreateEDGE_TABLE
+ *     REGION_CreateETandAET
  *
  *     This routine creates the edge table for
  *     scan converting polygons.
@@ -3072,7 +3160,7 @@ REGION_CreateETandAET(
     INT iSLLBlock = 0;
     INT dy;
 
-    /*  Initialize the Active Edge Table */
+    /* Initialize the Active Edge Table */
     AET->next = (EDGE_TABLE_ENTRY *)NULL;
     AET->back = (EDGE_TABLE_ENTRY *)NULL;
     AET->nextWETE = (EDGE_TABLE_ENTRY *)NULL;
@@ -3143,12 +3231,12 @@ REGION_CreateETandAET(
 
 BOOL
 FASTCALL
-IntSetPolyPolygonRgn(
-    POINT *Pts,
-    PULONG Count,
-    INT nbpolygons,
-    INT mode,
-    PREGION Rgn)
+REGION_SetPolyPolygonRgn(
+    _Inout_ PREGION prgn,
+    _In_ const POINT *ppt,
+    _In_ const ULONG *pcPoints,
+    _In_ ULONG cPolygons,
+    _In_ INT iMode)
 {
     EDGE_TABLE_ENTRY *pAET;               /* Active Edge Table        */
     INT y;                                /* Current scanline         */
@@ -3164,48 +3252,54 @@ IntSetPolyPolygonRgn(
     INT fixWAET = FALSE;
     POINTBLOCK FirstPtBlock, *curPtBlock; /* PtBlock buffers          */
     POINTBLOCK *tmpPtBlock;
-    INT numFullPtBlocks = 0;
-    INT poly, total;
+    UINT numFullPtBlocks = 0;
+    UINT poly, total;
 
-    if (mode == 0 || mode > 2) return 0;
+    /* Check if iMode is valid */
+    if ((iMode != ALTERNATE) && (iMode != WINDING))
+    {
+        DPRINT1("Invalid iMode: %lu\n", iMode);
+        return FALSE;
+    }
 
     /* 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_SetRectRgn(Rgn,
-                          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));
+    if (((cPolygons == 1) && ((pcPoints[0] == 4) ||
+         ((pcPoints[0] == 5) && (ppt[4].x == ppt[0].x) && (ppt[4].y == ppt[0].y)))) &&
+        (((ppt[0].y == ppt[1].y) &&
+          (ppt[1].x == ppt[2].x) &&
+          (ppt[2].y == ppt[3].y) &&
+          (ppt[3].x == ppt[0].x)) ||
+         ((ppt[0].x == ppt[1].x) &&
+          (ppt[1].y == ppt[2].y) &&
+          (ppt[2].x == ppt[3].x) &&
+          (ppt[3].y == ppt[0].y))))
+    {
+        REGION_SetRectRgn(prgn,
+                          min(ppt[0].x, ppt[2].x),
+                          min(ppt[0].y, ppt[2].y),
+                          max(ppt[0].x, ppt[2].x),
+                          max(ppt[0].y, ppt[2].y));
         return TRUE;
     }
 
-    for (poly = total = 0; poly < nbpolygons; poly++)
-        total += Count[poly];
+    for (poly = total = 0; poly < cPolygons; poly++)
+        total += pcPoints[poly];
 
     pETEs = ExAllocatePoolWithTag(PagedPool,
                                   sizeof(EDGE_TABLE_ENTRY) * total,
                                   TAG_REGION);
     if (pETEs == NULL)
     {
+        DPRINT1("Failed to allocate %lu edge entries\n", total);
         return FALSE;
     }
 
     pts = FirstPtBlock.pts;
-    REGION_CreateETandAET(Count, nbpolygons, Pts, &ET, &AET, pETEs, &SLLBlock);
+    REGION_CreateETandAET(pcPoints, cPolygons, ppt, &ET, &AET, pETEs, &SLLBlock);
     pSLL = ET.scanlines.next;
     curPtBlock = &FirstPtBlock;
 
-    if (mode != WINDING)
+    if (iMode != WINDING)
     {
         /*  For each scanline */
         for (y = ET.ymin; y < ET.ymax; y++)
@@ -3234,7 +3328,7 @@ IntSetPolyPolygonRgn(
                                                        TAG_REGION);
                     if (tmpPtBlock == NULL)
                     {
-                        DPRINT1("Can't alloc tPB\n");
+                        DPRINT1("Can't alloc tmpPtBlock\n");
                         ExFreePoolWithTag(pETEs, TAG_REGION);
                         return FALSE;
                     }
@@ -3277,8 +3371,10 @@ IntSetPolyPolygonRgn(
                  * are in the Winding active edge table. */
                 if (pWETE == pAET)
                 {
-                    pts->x = pAET->bres.minor_axis,  pts->y = y;
-                    pts++, iPts++;
+                    pts->x = pAET->bres.minor_axis;
+                    pts->y = y;
+                    pts++;
+                    iPts++;
 
                     /* Send out the buffer */
                     if (iPts == NUMPTSTOBUFFER)
@@ -3316,9 +3412,9 @@ IntSetPolyPolygonRgn(
     }
 
     REGION_FreeStorage(SLLBlock.next);
-    REGION_PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, Rgn);
+    REGION_PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, prgn);
 
-    for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;)
+    for (curPtBlock = FirstPtBlock.next; numFullPtBlocks-- > 0;)
     {
         tmpPtBlock = curPtBlock->next;
         ExFreePoolWithTag(curPtBlock, TAG_REGION);
@@ -3329,6 +3425,42 @@ IntSetPolyPolygonRgn(
     return TRUE;
 }
 
+HRGN
+NTAPI
+GreCreatePolyPolygonRgn(
+    _In_ const POINT *ppt,
+    _In_ const ULONG *pcPoints,
+    _In_ ULONG cPolygons,
+    _In_ INT iMode)
+{
+    PREGION prgn;
+    HRGN hrgn;
+
+    /* Allocate a new region */
+    prgn = REGION_AllocUserRgnWithHandle(0);
+    if (prgn == NULL)
+    {
+        EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        return NULL;
+    }
+
+    /* Call the internal function and check for success */
+    if (REGION_SetPolyPolygonRgn(prgn, ppt, pcPoints, cPolygons, iMode))
+    {
+        /* Success, get the handle and unlock the region */
+        hrgn = prgn->BaseObject.hHmgr;
+        REGION_UnlockRgn(prgn);
+    }
+    else
+    {
+        /* Failure, delete the region */
+        REGION_Delete(prgn);
+        hrgn = NULL;
+    }
+
+    return hrgn;
+}
+
 BOOL
 FASTCALL
 IntRectInRegion(
@@ -3338,14 +3470,14 @@ IntRectInRegion(
     PREGION Rgn;
     BOOL Ret;
 
-    Rgn = RGNOBJAPI_Lock(hRgn, NULL);
+    Rgn = REGION_LockRgn(hRgn);
     if (Rgn == NULL)
     {
         return ERROR;
     }
 
     Ret = REGION_RectInRegion(Rgn, rc);
-    RGNOBJAPI_Unlock(Rgn);
+    REGION_UnlockRgn(Rgn);
     return Ret;
 }
 
@@ -3376,8 +3508,9 @@ NtGdiCombineRgn(
         (hrgnSrc1 == NULL) ||
         ((iMode != RGN_COPY) && (hrgnSrc2 == NULL)))
     {
-        DPRINT1("NtGdiCombineRgn: %p, %p, %p, %d\n",
+        DPRINT1("NtGdiCombineRgn invalid parameters: %p, %p, %p, %d\n",
                 hrgnDst, hrgnSrc1, hrgnSrc2, iMode);
+        EngSetLastError(ERROR_INVALID_HANDLE);
         return ERROR;
     }
 
@@ -3387,25 +3520,25 @@ NtGdiCombineRgn(
     ahrgn[2] = iMode != RGN_COPY ? hrgnSrc2 : NULL;
     if (!GDIOBJ_bLockMultipleObjects(3, (HGDIOBJ*)ahrgn, (PVOID*)aprgn, GDIObjType_RGN_TYPE))
     {
-        DPRINT1("NtGdiCombineRgn: %p, %p, %p, %d\n",
+        DPRINT1("NtGdiCombineRgn failed to lock regions: %p, %p, %p, %d\n",
                 hrgnDst, hrgnSrc1, hrgnSrc2, iMode);
         return ERROR;
     }
 
     /* HACK: Sync usermode attributes */
     REGION_vSyncRegion(aprgn[0]);
-    REGION_vSyncRegion(aprgn[1]);
-    if (aprgn[2]) REGION_vSyncRegion(aprgn[2]);
+    if (aprgn[1] != aprgn[0])
+        REGION_vSyncRegion(aprgn[1]);
+    if ((aprgn[2] != NULL) && (aprgn[2] != aprgn[0]) && (aprgn[2] != aprgn[1]))
+        REGION_vSyncRegion(aprgn[2]);
 
     /* Call the internal function */
     iResult = IntGdiCombineRgn(aprgn[0], aprgn[1], aprgn[2], iMode);
 
-    /// FIXME: need to sync user attr back
-
-    /* Cleanup and return */
+    /* Unlock and return */
     REGION_UnlockRgn(aprgn[0]);
     REGION_UnlockRgn(aprgn[1]);
-    if (aprgn[2])
+    if (aprgn[2] != NULL)
         REGION_UnlockRgn(aprgn[2]);
 
     return iResult;
@@ -3448,7 +3581,7 @@ NtGdiCreateRectRgn(
     hRgn = pRgn->BaseObject.hHmgr;
 
     REGION_SetRectRgn(pRgn, LeftRect, TopRect, RightRect, BottomRect);
-    RGNOBJAPI_Unlock(pRgn);
+    REGION_UnlockRgn(pRgn);
 
     DPRINT("Returning %p.\n", hRgn);
 
@@ -3575,7 +3708,7 @@ NtGdiCreateRoundRectRgn(
         REGION_UnionRectWithRgn(obj, &rect);
     }
 
-    RGNOBJAPI_Unlock(obj);
+    REGION_UnlockRgn(obj);
     return hrgn;
 }
 
@@ -3585,22 +3718,47 @@ NtGdiEqualRgn(
     HRGN  hSrcRgn1,
     HRGN  hSrcRgn2)
 {
+    HRGN ahrgn[2];
+    PREGION aprgn[2];
     PREGION rgn1, rgn2;
     PRECTL tRect1, tRect2;
     ULONG i;
     BOOL bRet = FALSE;
 
-    rgn1 = RGNOBJAPI_Lock(hSrcRgn1, NULL);
-    if (rgn1 == NULL)
-        return ERROR;
+    /* Check if we got 2 regions */
+    if ((hSrcRgn1 == NULL) || (hSrcRgn2 == NULL))
+    {
+        return FALSE;
+    }
 
-    rgn2 = RGNOBJAPI_Lock(hSrcRgn2, NULL);
-    if (rgn2 == NULL)
+    /* Check if these are the same regions */
+    if (hSrcRgn1 == hSrcRgn2)
     {
-        RGNOBJAPI_Unlock(rgn1);
-        return ERROR;
+        /* Make sure this region is valid */
+        if ((GDI_HANDLE_GET_TYPE(hSrcRgn1) == GDILoObjType_LO_REGION_TYPE) &&
+            GreIsHandleValid(hSrcRgn1))
+        {
+            return TRUE;
+        }
+        return FALSE;
+    }
+
+    /* Lock both regions */
+    ahrgn[0] = hSrcRgn1;
+    ahrgn[1] = hSrcRgn2;
+    if (!GDIOBJ_bLockMultipleObjects(2, (HGDIOBJ*)ahrgn, (PVOID*)aprgn, GDIObjType_RGN_TYPE))
+    {
+        DPRINT1("NtGdiEqualRgn failed to lock regions: %p, %p\n",
+                hSrcRgn1, hSrcRgn2);
+        return FALSE;
     }
 
+    REGION_vSyncRegion(aprgn[0]);
+    REGION_vSyncRegion(aprgn[1]);
+
+    rgn1 = aprgn[0];
+    rgn2 = aprgn[1];
+
     if (rgn1->rdh.nCount != rgn2->rdh.nCount)
         goto exit;
 
@@ -3634,8 +3792,8 @@ NtGdiEqualRgn(
     bRet = TRUE;
 
 exit:
-    RGNOBJAPI_Unlock(rgn1);
-    RGNOBJAPI_Unlock(rgn2);
+    REGION_UnlockRgn(rgn1);
+    REGION_UnlockRgn(rgn2);
     return bRet;
 }
 
@@ -3735,82 +3893,16 @@ NtGdiExtCreateRegion(
     if (!NT_SUCCESS(Status))
     {
         EngSetLastError(ERROR_INVALID_PARAMETER);
-        RGNOBJAPI_Unlock(Region);
+        REGION_UnlockRgn(Region);
         GreDeleteObject(hRgn);
         return NULL;
     }
 
-    RGNOBJAPI_Unlock(Region);
+    REGION_UnlockRgn(Region);
 
     return hRgn;
 }
 
-BOOL
-APIENTRY
-NtGdiFillRgn(
-    HDC hDC,
-    HRGN hRgn,
-    HBRUSH hBrush)
-{
-    HBRUSH oldhBrush;
-    PREGION rgn;
-    PRECTL r;
-
-    rgn = RGNOBJAPI_Lock(hRgn, NULL);
-    if (rgn == NULL)
-    {
-        return FALSE;
-    }
-
-    oldhBrush = NtGdiSelectBrush(hDC, hBrush);
-    if (oldhBrush == NULL)
-    {
-        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;
-}
-
-BOOL
-APIENTRY
-NtGdiFrameRgn(
-    HDC hDC,
-    HRGN hRgn,
-    HBRUSH hBrush,
-    INT Width,
-    INT Height)
-{
-    HRGN FrameRgn;
-    BOOL Ret;
-
-    FrameRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
-    if (FrameRgn == NULL)
-    {
-        return FALSE;
-    }
-
-    if (!REGION_CreateFrameRgn(FrameRgn, hRgn, Width, Height))
-    {
-        GreDeleteObject(FrameRgn);
-        return FALSE;
-    }
-
-    Ret = NtGdiFillRgn(hDC, FrameRgn, hBrush);
-
-    GreDeleteObject(FrameRgn);
-    return Ret;
-}
-
-
 INT
 APIENTRY
 NtGdiGetRgnBox(
@@ -3822,14 +3914,14 @@ NtGdiGetRgnBox(
     DWORD ret;
     NTSTATUS Status = STATUS_SUCCESS;
 
-    Rgn = RGNOBJAPI_Lock(hRgn, NULL);
+    Rgn = REGION_LockRgn(hRgn);
     if (Rgn == NULL)
     {
         return ERROR;
     }
 
     ret = REGION_GetRgnBox(Rgn, &SafeRect);
-    RGNOBJAPI_Unlock(Rgn);
+    REGION_UnlockRgn(Rgn);
     if (ret == ERROR)
     {
         return ret;
@@ -3853,177 +3945,119 @@ NtGdiGetRgnBox(
     return ret;
 }
 
-BOOL
-APIENTRY
-NtGdiInvertRgn(
-    HDC hDC,
-    HRGN hRgn)
-{
-    PREGION RgnData;
-    ULONG i;
-    PRECTL rc;
-
-    RgnData = RGNOBJAPI_Lock(hRgn, NULL);
-    if (RgnData == NULL)
-    {
-        EngSetLastError(ERROR_INVALID_HANDLE);
-        return FALSE;
-    }
-
-    rc = RgnData->Buffer;
-    for (i = 0; i < RgnData->rdh.nCount; i++)
-    {
-
-        if (!NtGdiPatBlt(hDC, rc->left, rc->top, rc->right - rc->left, rc->bottom - rc->top, DSTINVERT))
-        {
-            RGNOBJAPI_Unlock(RgnData);
-            return FALSE;
-        }
-        rc++;
-    }
-
-    RGNOBJAPI_Unlock(RgnData);
-    return TRUE;
-}
-
 INT
 APIENTRY
 NtGdiOffsetRgn(
-    HRGN hRgn,
-    INT XOffset,
-    INT YOffset)
+    _In_ HRGN hrgn,
+    _In_ INT cx,
+    _In_ INT cy)
 {
-    PREGION rgn;
-    INT ret;
+    PREGION prgn;
+    INT iResult;
 
-    DPRINT("NtGdiOffsetRgn: hRgn %p Xoffs %d Yoffs %d rgn %p\n", hRgn, XOffset, YOffset, rgn );
+    DPRINT("NtGdiOffsetRgn: hrgn %p cx %d cy %d\n", hrgn, cx, cy);
 
-    rgn = RGNOBJAPI_Lock(hRgn, NULL);
-    if (rgn == NULL)
+    /* Lock the region */
+    prgn = REGION_LockRgn(hrgn);
+    if (prgn == NULL)
     {
-        DPRINT("NtGdiOffsetRgn: hRgn error\n");
+        DPRINT1("NtGdiOffsetRgn: failed to lock region %p\n", hrgn);
         return ERROR;
     }
 
-    ret = IntGdiOffsetRgn(rgn, XOffset, YOffset);
+    /* Call the internal function */
+    if (!REGION_bOffsetRgn(prgn, cx, cy))
+    {
+        iResult = ERROR;
+    }
+    else
+    {
+        iResult = REGION_Complexity(prgn);
+    }
 
-    RGNOBJAPI_Unlock(rgn);
-    return ret;
+    /* Unlock and return the result */
+    REGION_UnlockRgn(prgn);
+    return iResult;
 }
 
 BOOL
 APIENTRY
 NtGdiPtInRegion(
-    HRGN hRgn,
-    INT X,
-    INT Y)
+    _In_ HRGN hrgn,
+    _In_ INT x,
+    _In_ INT y)
 {
     PREGION prgn;
-    BOOL ret;
+    BOOL bResult;
 
-    prgn = RGNOBJAPI_Lock(hRgn, NULL);
+    /* Lock the region */
+    prgn = REGION_LockRgn(hrgn);
     if (prgn == NULL)
+    {
+        DPRINT1("NtGdiPtInRegion: hrgn error\n");
         return FALSE;
+    }
 
-    ret = REGION_PtInRegion(prgn, X, Y);
+    /* Call the internal function */
+    bResult = REGION_PtInRegion(prgn, x, y);
 
-    RGNOBJAPI_Unlock(prgn);
-    return ret;
+    /* Unlock and return the result */
+    REGION_UnlockRgn(prgn);
+    return bResult;
 }
 
+__kernel_entry
 BOOL
 APIENTRY
 NtGdiRectInRegion(
-    HRGN  hRgn,
-    LPRECTL unsaferc)
+    _In_ HRGN hrgn,
+    _Inout_ LPRECT prclUnsafe)
 {
-    RECTL rc = { 0 };
-    NTSTATUS Status = STATUS_SUCCESS;
+    RECTL rcTemp;
 
+    /* Probe and copy the rect */
     _SEH2_TRY
     {
-        ProbeForRead(unsaferc, sizeof(RECT), 1);
-        rc = *unsaferc;
+        ProbeForRead(prclUnsafe, sizeof(RECT), 1);
+        rcTemp = *prclUnsafe;
     }
     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
     {
-        Status = _SEH2_GetExceptionCode();
+        DPRINT1("NtGdiRectInRegion: Exception accessing the rect\n");
+        return FALSE;
     }
     _SEH2_END;
 
-    if (!NT_SUCCESS(Status))
-    {
-        SetLastNtError(Status);
-        DPRINT1("NtGdiRectInRegion: Bogus rc\n");
-        return ERROR;
-    }
-
-    return IntRectInRegion(hRgn, &rc);
+    /* Call the internal function */
+    return IntRectInRegion(hrgn, &rcTemp);
 }
 
 BOOL
 APIENTRY
 NtGdiSetRectRgn(
-    HRGN hRgn,
-    INT LeftRect,
-    INT TopRect,
-    INT RightRect,
-    INT BottomRect)
+    _In_ HRGN hrgn,
+    _In_ INT xLeft,
+    _In_ INT yTop,
+    _In_ INT xRight,
+    _In_ INT yBottom)
 {
-    PREGION rgn;
+    PREGION prgn;
 
-    rgn = RGNOBJAPI_Lock(hRgn, NULL);
-    if (rgn == NULL)
+    /* Lock the region */
+    prgn = REGION_LockRgn(hrgn);
+    if (prgn == NULL)
     {
-        return 0; // Per documentation
+        return FALSE;
     }
 
-    REGION_SetRectRgn(rgn, LeftRect, TopRect, RightRect, BottomRect);
+    /* Call the internal API */
+    REGION_SetRectRgn(prgn, xLeft, yTop, xRight, yBottom);
 
-    RGNOBJAPI_Unlock(rgn);
+    /* Unlock the region and return success */
+    REGION_UnlockRgn(prgn);
     return TRUE;
 }
 
-HRGN
-APIENTRY
-NtGdiUnionRectWithRgn(
-    HRGN hDest,
-    const RECTL *UnsafeRect)
-{
-    RECTL SafeRect = { 0 };
-    PREGION Rgn;
-    NTSTATUS Status = STATUS_SUCCESS;
-
-    Rgn = RGNOBJAPI_Lock(hDest, NULL);
-    if (Rgn == NULL)
-    {
-        EngSetLastError(ERROR_INVALID_HANDLE);
-        return NULL;
-    }
-
-    _SEH2_TRY
-    {
-        ProbeForRead(UnsafeRect, sizeof(RECT), 1);
-        SafeRect = *UnsafeRect;
-    }
-    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
-    {
-        Status = _SEH2_GetExceptionCode();
-    }
-    _SEH2_END;
-
-    if (!NT_SUCCESS(Status))
-    {
-        RGNOBJAPI_Unlock(Rgn);
-        SetLastNtError(Status);
-        return NULL;
-    }
-
-    REGION_UnionRectWithRgn(Rgn, &SafeRect);
-    RGNOBJAPI_Unlock(Rgn);
-    return hDest;
-}
-
 /*!
  * MSDN: GetRegionData, Return Values:
  *
@@ -4035,18 +4069,19 @@ NtGdiUnionRectWithRgn(
  * If the function fails, the return value is zero."
  */
 _Success_(return!=0)
+__kernel_entry
 ULONG
 APIENTRY
 NtGdiGetRegionData(
     _In_ HRGN hrgn,
     _In_ ULONG cjBuffer,
-    _Out_opt_bytecap_(cjBuffer) LPRGNDATA lpRgnData)
+    _Out_writes_bytes_to_opt_(cjBuffer, return) LPRGNDATA lpRgnData)
 {
     ULONG cjRects, cjSize;
     PREGION prgn;
 
     /* Lock the region */
-    prgn = RGNOBJAPI_Lock(hrgn, NULL);
+    prgn = REGION_LockRgn(hrgn);
     if (prgn == NULL)
     {
         EngSetLastError(ERROR_INVALID_HANDLE);
@@ -4070,6 +4105,7 @@ NtGdiGetRegionData(
                 RtlCopyMemory(lpRgnData, &prgn->rdh, sizeof(RGNDATAHEADER));
                 RtlCopyMemory(lpRgnData->Buffer, prgn->Buffer, cjRects);
                 lpRgnData->rdh.iType = RDH_RECTANGLES;
+                lpRgnData->rdh.nRgnSize = cjRects;
             }
             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
             {
@@ -4087,7 +4123,7 @@ NtGdiGetRegionData(
     }
 
     /* Unlock the region and return the size */
-    RGNOBJAPI_Unlock(prgn);
+    REGION_UnlockRgn(prgn);
     return cjSize;
 }