[GDI32]
[reactos.git] / reactos / dll / win32 / gdi32 / objects / region.c
index 519e2c7..b8d7077 100644 (file)
 #include "precomp.h"
 
+#define NDEBUG
+#include <debug.h>
+
+#define INRECT(r, x, y) \
+      ( ( ((r).right >  x)) && \
+      ( ((r).left <= x)) && \
+      ( ((r).bottom >  y)) && \
+      ( ((r).top <= y)) )
+
+#define OVERLAPPING_RGN 0
+#define INVERTED_RGN 1
+#define SAME_RGN 2
+#define DIFF_RGN 3
+/*
+ From tests, there are four results based on normalized coordinates.
+ If the rects are overlapping and normalized, it's OVERLAPPING_RGN.
+ If the rects are overlapping in anyway or same in dimension and one is inverted,
+ it's INVERTED_RGN.
+ If the rects are same in dimension or NULL, it's SAME_RGN.
+ If the rects are overlapping and not normalized or displace in different areas,
+ it's DIFF_RGN.
+ */
+INT
+FASTCALL
+ComplexityFromRects( PRECTL prc1, PRECTL prc2)
+{
+  if ( prc2->left >= prc1->left )
+  {
+     if ( ( prc1->right >= prc2->right) &&
+          ( prc1->top <= prc2->top ) &&
+          ( prc1->bottom >= prc2->bottom ) )      
+        return SAME_RGN;
+
+     if ( prc2->left > prc1->left )
+     {
+        if ( ( prc1->left >= prc2->right ) ||
+             ( prc1->right <= prc2->left ) ||
+             ( prc1->top >= prc2->bottom ) ||
+             ( prc1->bottom <= prc2->top ) )
+           return DIFF_RGN;
+     }
+  }
+
+  if ( ( prc2->right < prc1->right ) ||
+       ( prc2->top > prc1->top ) ||
+       ( prc2->bottom < prc1->bottom ) )
+  {
+     if ( ( prc1->left >= prc2->right ) ||
+          ( prc1->right <= prc2->left ) ||
+          ( prc1->top >= prc2->bottom ) ||
+          ( prc1->bottom <= prc2->top ) )
+        return DIFF_RGN;
+  }
+  else
+  {
+     return INVERTED_RGN;
+  }
+  return OVERLAPPING_RGN;
+}
+
+static
+VOID
+FASTCALL
+SortRects(PRECT pRect, INT nCount)
+{
+  INT i = 0, a = 0, b = 0, c, s;
+  RECT sRect;
+
+  if (nCount > 0)
+  {
+     i = 1; // set index point
+     c = nCount; // set inverse count
+     do
+     {
+        s = i; // set sort count
+        if ( i < nCount )
+        {
+           a = i - 1;
+           b = i;
+           do
+           {
+              if(pRect[b].top != pRect[i].bottom) break;
+              if(pRect[b].left < pRect[a].left)
+              {
+                 sRect = pRect[a];
+                 pRect[a] = pRect[b];
+                 pRect[b] = sRect;
+              }
+              ++s;
+              ++b;
+           } while ( s < nCount );
+        }
+        ++i;
+     } while ( c-- != 1 );
+  }
+}
+
+/*
+ * I thought it was okay to have this in DeleteObject but~ Speed. (jt)
+ */
+BOOL
+FASTCALL
+DeleteRegion( HRGN hRgn )
+{
+  PRGN_ATTR Rgn_Attr;
+
+  if ((GdiGetHandleUserData((HGDIOBJ) hRgn, GDI_OBJECT_TYPE_REGION, (PVOID) &Rgn_Attr)) &&
+      ( Rgn_Attr != NULL ))
+  {
+      PGDIBSOBJECT pgO;
+      
+      pgO = GdiAllocBatchCommand(NULL, GdiBCDelRgn);
+      if (pgO)
+      {
+          pgO->hgdiobj = (HGDIOBJ)hRgn;
+          return TRUE;
+      }
+  }
+  return NtGdiDeleteObjectApp((HGDIOBJ) hRgn);
+}
+
+INT
+FASTCALL
+MirrorRgnByWidth(HRGN hRgn, INT Width, HRGN *phRgn)
+{
+  INT cRgnDSize, Ret = 0;
+  PRGNDATA pRgnData;
+  
+  cRgnDSize = NtGdiGetRegionData(hRgn, 0, NULL);
+
+  if (cRgnDSize)
+  {
+     pRgnData = LocalAlloc(LMEM_FIXED, cRgnDSize * sizeof(LONG));
+     if (pRgnData)
+     {
+        if ( GetRegionData(hRgn, cRgnDSize, pRgnData) )
+        {
+           HRGN hRgnex;
+           UINT i;
+           INT SaveL = pRgnData->rdh.rcBound.left;
+           pRgnData->rdh.rcBound.left = Width - pRgnData->rdh.rcBound.right;
+           pRgnData->rdh.rcBound.right = Width - SaveL;
+           if (pRgnData->rdh.nCount > 0)
+           {
+              PRECT pRect = (PRECT)&pRgnData->Buffer;
+              for (i = 0; i < pRgnData->rdh.nCount; i++)
+              {
+                  SaveL = pRect[i].left;
+                  pRect[i].left = Width - pRect[i].right;
+                  pRect[i].right = Width - SaveL;
+              }
+           }
+           SortRects((PRECT)&pRgnData->Buffer, pRgnData->rdh.nCount);
+           hRgnex = ExtCreateRegion(NULL, cRgnDSize , pRgnData);
+           if (hRgnex)
+           {
+              if (phRgn) phRgn = (HRGN *)hRgnex;
+              else
+              {
+                 CombineRgn(hRgn, hRgnex, 0, RGN_COPY); 
+                 DeleteObject(hRgnex);
+              }
+              Ret = 1;
+           }
+        }
+        LocalFree(pRgnData);
+     }
+  }
+  return Ret;
+}
+
+INT
+WINAPI
+MirrorRgnDC(HDC hdc, HRGN hRgn, HRGN *phRgn)
+{
+  if (!GdiIsHandleValid((HGDIOBJ) hdc) ||
+      (GDI_HANDLE_GET_TYPE(hdc) != GDI_OBJECT_TYPE_DC)) return 0;
+
+  return MirrorRgnByWidth(hRgn, NtGdiGetDeviceWidth(hdc), phRgn);
+}
+
+/* FUNCTIONS *****************************************************************/
+
+/*
+ * @implemented
+ */
+INT
+WINAPI
+CombineRgn(HRGN  hDest,
+           HRGN  hSrc1,
+           HRGN  hSrc2,
+           INT  CombineMode)
+{
+  PRGN_ATTR pRgn_Attr_Dest = NULL;
+  PRGN_ATTR pRgn_Attr_Src1 = NULL;
+  PRGN_ATTR pRgn_Attr_Src2 = NULL;
+  INT Complexity;
+  BOOL Ret;
+
+  Ret = GdiGetHandleUserData((HGDIOBJ) hDest, GDI_OBJECT_TYPE_REGION, (PVOID) &pRgn_Attr_Dest);
+  Ret = GdiGetHandleUserData((HGDIOBJ) hSrc1, GDI_OBJECT_TYPE_REGION, (PVOID) &pRgn_Attr_Src1);
+
+  if ( !Ret ||
+       !pRgn_Attr_Dest ||
+       !pRgn_Attr_Src1 ||
+        pRgn_Attr_Src1->Flags > SIMPLEREGION )
+     return NtGdiCombineRgn(hDest, hSrc1, hSrc2, CombineMode);
+
+  /* Handle COPY and use only src1. */
+  if ( CombineMode == RGN_COPY )
+  {
+     switch (pRgn_Attr_Src1->Flags)
+     {
+        case NULLREGION:
+             Ret = SetRectRgn( hDest, 0, 0, 0, 0);
+             if (Ret)
+                return NULLREGION;
+             goto ERROR_Exit;
+
+        case SIMPLEREGION:
+             Ret = SetRectRgn( hDest,
+                               pRgn_Attr_Src1->Rect.left,
+                               pRgn_Attr_Src1->Rect.top,
+                               pRgn_Attr_Src1->Rect.right,
+                               pRgn_Attr_Src1->Rect.bottom );
+             if (Ret)
+                return SIMPLEREGION;
+             goto ERROR_Exit;
+
+        case COMPLEXREGION:
+        default:
+            return NtGdiCombineRgn(hDest, hSrc1, hSrc2, CombineMode);
+     }
+  }
+
+  Ret = GdiGetHandleUserData((HGDIOBJ) hSrc2, GDI_OBJECT_TYPE_REGION, (PVOID) &pRgn_Attr_Src2);
+  if ( !Ret ||
+       !pRgn_Attr_Src2 ||
+        pRgn_Attr_Src2->Flags > SIMPLEREGION )
+     return NtGdiCombineRgn(hDest, hSrc1, hSrc2, CombineMode);
+
+  /* All but AND. */
+  if ( CombineMode != RGN_AND)
+  {
+     if ( CombineMode <= RGN_AND)
+     {
+        /*
+           There might be some type of junk in the call, so go K.
+           If this becomes a problem, need to setup parameter check at the top.
+         */
+        DPRINT1("Might be junk! CombineMode %d\n",CombineMode);
+        return NtGdiCombineRgn(hDest, hSrc1, hSrc2, CombineMode);
+     }
+
+     if ( CombineMode > RGN_XOR) /* Handle DIFF. */
+     {
+        if ( CombineMode != RGN_DIFF)
+        {  /* Filter check! Well, must be junk?, so go K. */
+           DPRINT1("RGN_COPY was handled! CombineMode %d\n",CombineMode);
+           return NtGdiCombineRgn(hDest, hSrc1, hSrc2, CombineMode);
+        }
+        /* Now handle DIFF. */
+        if ( pRgn_Attr_Src1->Flags == NULLREGION )
+        {
+           if (SetRectRgn( hDest, 0, 0, 0, 0))
+              return NULLREGION;
+           goto ERROR_Exit;
+        }
+
+        if ( pRgn_Attr_Src2->Flags != NULLREGION )
+        {
+           Complexity = ComplexityFromRects( &pRgn_Attr_Src1->Rect, &pRgn_Attr_Src2->Rect);
+
+           if ( Complexity != DIFF_RGN )
+           {
+              if ( Complexity != INVERTED_RGN)
+                 /* If same or overlapping and norm just go K. */
+                 return NtGdiCombineRgn(hDest, hSrc1, hSrc2, CombineMode);
+
+              if (SetRectRgn( hDest, 0, 0, 0, 0))
+                 return NULLREGION;
+              goto ERROR_Exit;
+           }
+        }
+     }
+     else /* Handle OR or XOR. */
+     {
+        if ( pRgn_Attr_Src1->Flags == NULLREGION )
+        {
+           if ( pRgn_Attr_Src2->Flags != NULLREGION )
+           { /* Src1 null and not NULL, set from src2. */
+              Ret = SetRectRgn( hDest,
+                                pRgn_Attr_Src2->Rect.left,
+                                pRgn_Attr_Src2->Rect.top,
+                                pRgn_Attr_Src2->Rect.right,
+                                pRgn_Attr_Src2->Rect.bottom );
+              if (Ret)
+                 return SIMPLEREGION;
+              goto ERROR_Exit;
+           }
+           /* Both are NULL. */
+           if (SetRectRgn( hDest, 0, 0, 0, 0))
+              return NULLREGION;
+           goto ERROR_Exit;          
+        }
+        /* Src1 is not NULL. */
+        if ( pRgn_Attr_Src2->Flags != NULLREGION )
+        {
+           if ( CombineMode != RGN_OR ) /* Filter XOR, so go K. */
+              return NtGdiCombineRgn(hDest, hSrc1, hSrc2, CombineMode);
+
+           Complexity = ComplexityFromRects( &pRgn_Attr_Src1->Rect, &pRgn_Attr_Src2->Rect);
+           /* If inverted use Src2. */
+           if ( Complexity == INVERTED_RGN)
+           {
+              Ret = SetRectRgn( hDest,
+                                pRgn_Attr_Src2->Rect.left,
+                                pRgn_Attr_Src2->Rect.top,
+                                pRgn_Attr_Src2->Rect.right,
+                                pRgn_Attr_Src2->Rect.bottom );
+              if (Ret)
+                 return SIMPLEREGION;
+              goto ERROR_Exit;
+           }
+           /* Not NULL or overlapping or differentiated, go to K. */
+           if ( Complexity != SAME_RGN)
+              return NtGdiCombineRgn(hDest, hSrc1, hSrc2, CombineMode);
+           /* If same, just fall through. */
+        }
+     }
+     Ret = SetRectRgn( hDest,
+                       pRgn_Attr_Src1->Rect.left,
+                       pRgn_Attr_Src1->Rect.top,
+                       pRgn_Attr_Src1->Rect.right,
+                       pRgn_Attr_Src1->Rect.bottom );
+     if (Ret)
+        return SIMPLEREGION;
+     goto ERROR_Exit;
+  }
+
+  /* Handle AND.  */
+  if ( pRgn_Attr_Src1->Flags != NULLREGION &&
+       pRgn_Attr_Src2->Flags != NULLREGION )
+  {
+     Complexity = ComplexityFromRects( &pRgn_Attr_Src1->Rect, &pRgn_Attr_Src2->Rect);
+
+     if ( Complexity == DIFF_RGN ) /* Differentiated in anyway just NULL rgn. */
+     {
+        if (SetRectRgn( hDest, 0, 0, 0, 0))
+           return NULLREGION;
+        goto ERROR_Exit;
+     }
+
+     if ( Complexity != INVERTED_RGN) /* Not inverted and overlapping. */
+     {
+        if ( Complexity != SAME_RGN) /* Must be norm and overlapping. */
+           return NtGdiCombineRgn(hDest, hSrc1, hSrc2, CombineMode);
+        /* Merge from src2.  */
+        Ret = SetRectRgn( hDest,
+                          pRgn_Attr_Src2->Rect.left,
+                          pRgn_Attr_Src2->Rect.top,
+                          pRgn_Attr_Src2->Rect.right,
+                          pRgn_Attr_Src2->Rect.bottom );
+        if (Ret)
+           return SIMPLEREGION;
+        goto ERROR_Exit;
+     }
+     /* Inverted so merge from src1. */
+     Ret = SetRectRgn( hDest,
+                       pRgn_Attr_Src1->Rect.left,
+                       pRgn_Attr_Src1->Rect.top,
+                       pRgn_Attr_Src1->Rect.right,
+                       pRgn_Attr_Src1->Rect.bottom );
+     if (Ret)
+        return SIMPLEREGION;
+     goto ERROR_Exit;
+  }
+
+  /* It's all NULL! */
+  if (SetRectRgn( hDest, 0, 0, 0, 0))
+     return NULLREGION;
+
+ERROR_Exit:
+  /* Even on error the flag is set dirty and force server side to redraw. */
+  pRgn_Attr_Dest->AttrFlags |= ATTR_RGN_DIRTY;
+  return ERROR;
+}
+
+/*
+ * @implemented
+ */
+HRGN
+WINAPI
+CreateEllipticRgnIndirect(
+   const RECT *prc
+)
+{
+    /* Notes if prc is NULL it will crash on All Windows NT I checked 2000/XP/VISTA */
+    return NtGdiCreateEllipticRgn(prc->left, prc->top, prc->right, prc->bottom);
+
+}
+
+/*
+ * @implemented
+ */
+HRGN
+WINAPI
+CreatePolygonRgn( const POINT * lppt, int cPoints, int fnPolyFillMode)
+{
+    return (HRGN) NtGdiPolyPolyDraw( (HDC) fnPolyFillMode, (PPOINT) lppt, (PULONG) &cPoints, 1, GdiPolyPolyRgn);
+}
+
+/*
+ * @implemented
+ */
+HRGN
+WINAPI
+CreatePolyPolygonRgn( const POINT* lppt,
+                      const INT* lpPolyCounts,
+                      int nCount,
+                      int fnPolyFillMode)
+{
+    return (HRGN) NtGdiPolyPolyDraw(  (HDC) fnPolyFillMode, (PPOINT) lppt, (PULONG) lpPolyCounts, (ULONG) nCount, GdiPolyPolyRgn );
+}
+
+/*
+ * @implemented
+ */
+HRGN
+WINAPI
+CreateRectRgn(int x1, int y1, int x2, int y2)
+{
+  PRGN_ATTR pRgn_Attr;
+  HRGN hrgn;
+  int tmp;
+
+ /* Normalize points */
+  tmp = x1;
+  if ( x1 > x2 )
+  {
+    x1 = x2;
+    x2 = tmp;
+  }
+
+  tmp = y1;
+  if ( y1 > y2 )
+  {
+    y1 = y2;
+    y2 = tmp;
+  }
+  /* Check outside 24 bit limit for universal set. Chp 9 Areas, pg 560.*/
+  if ( x1 < -(1<<27)  ||
+       y1 < -(1<<27)  ||
+       x2 > (1<<27)-1 ||
+       y2 > (1<<27)-1 )
+  {
+     SetLastError(ERROR_INVALID_PARAMETER);
+     return NULL;
+  }
+
+  hrgn = hGetPEBHandle(hctRegionHandle, 0);
+
+  if (!hrgn)
+     hrgn = NtGdiCreateRectRgn(0, 0, 1, 1);
+
+  if (!hrgn)
+     return hrgn;
+
+  if (!GdiGetHandleUserData((HGDIOBJ) hrgn, GDI_OBJECT_TYPE_REGION, (PVOID) &pRgn_Attr))
+  {
+     DPRINT1("No Attr for Region handle!!!\n");
+     DeleteRegion(hrgn);
+     return NULL;
+  }
+
+  if (( x1 == x2) || (y1 == y2))
+  {
+     pRgn_Attr->Flags = NULLREGION;
+     pRgn_Attr->Rect.left = pRgn_Attr->Rect.top =
+     pRgn_Attr->Rect.right = pRgn_Attr->Rect.bottom = 0;
+  }
+  else
+  {
+     pRgn_Attr->Flags = SIMPLEREGION;
+     pRgn_Attr->Rect.left   = x1;
+     pRgn_Attr->Rect.top    = y1;
+     pRgn_Attr->Rect.right  = x2;
+     pRgn_Attr->Rect.bottom = y2;
+  }
+
+  pRgn_Attr->AttrFlags = (ATTR_RGN_DIRTY|ATTR_RGN_VALID);
+
+  return hrgn;
+}
+
+/*
+ * @implemented
+ */
+HRGN
+WINAPI
+CreateRectRgnIndirect(
+    const RECT *prc
+)
+{
+    /* Notes if prc is NULL it will crash on All Windows NT I checked 2000/XP/VISTA */
+    return CreateRectRgn(prc->left, prc->top, prc->right, prc->bottom);
+
+}
+
+/*
+ * @implemented
+ */
+INT
+WINAPI
+ExcludeClipRect(IN HDC hdc, IN INT xLeft, IN INT yTop, IN INT xRight, IN INT yBottom)
+{
+#if 0
+// Handle something other than a normal dc object.
+  if (GDI_HANDLE_GET_TYPE(hdc) != GDI_OBJECT_TYPE_DC)
+  {
+    if (GDI_HANDLE_GET_TYPE(hdc) == GDI_OBJECT_TYPE_METADC)
+      return MFDRV_ExcludeClipRect( hdc, xLeft, yTop, xRight, yBottom);
+    else
+    {
+      PLDC pLDC = GdiGetLDC(hdc);
+      if ( pLDC )
+      {
+         if (pLDC->iType != LDC_EMFLDC || EMFDRV_ExcludeClipRect( hdc, xLeft, yTop, xRight, yBottom))
+             return NtGdiExcludeClipRect(hdc, xLeft, yTop, xRight, yBottom);
+      }
+      else
+        SetLastError(ERROR_INVALID_HANDLE);
+      return ERROR;
+    }
+  }
+#endif
+    return NtGdiExcludeClipRect(hdc, xLeft, yTop, xRight, yBottom);
+}
+
+/*
+ * @implemented
+ */
+HRGN
+WINAPI
+ExtCreateRegion(
+       CONST XFORM *   lpXform,
+       DWORD           nCount,
+       CONST RGNDATA * lpRgnData
+       )
+{
+   if (lpRgnData)
+   {
+     if ((!lpXform) && (lpRgnData->rdh.nCount == 1))
+     {
+         PRECT pRect = (PRECT)&lpRgnData->Buffer[0];
+         return CreateRectRgn(pRect->left, pRect->top, pRect->right, pRect->bottom);
+     }
+     return NtGdiExtCreateRegion((LPXFORM) lpXform, nCount,(LPRGNDATA) lpRgnData);
+   }
+   SetLastError(ERROR_INVALID_PARAMETER);
+   return NULL;
+}
+
+/*
+ * @implemented
+ */
+INT
+WINAPI
+ExtSelectClipRgn( IN HDC hdc, IN HRGN hrgn, IN INT iMode)
+{
+  INT Ret;
+  HRGN NewRgn = NULL;
+
+#if 0
+// Handle something other than a normal dc object.
+  if (GDI_HANDLE_GET_TYPE(hdc) != GDI_OBJECT_TYPE_DC)
+  {
+    if (GDI_HANDLE_GET_TYPE(hdc) == GDI_OBJECT_TYPE_METADC)
+      return MFDRV_ExtSelectClipRgn( hdc, );
+    else
+    {
+      PLDC pLDC = GdiGetLDC(hdc);
+      if ( pLDC )
+      {
+         if (pLDC->iType != LDC_EMFLDC || EMFDRV_ExtSelectClipRgn( hdc, ))
+             return NtGdiExtSelectClipRgn(hdc, );
+      }
+      else
+        SetLastError(ERROR_INVALID_HANDLE);
+      return ERROR;
+    }
+  }
+#endif
+#if 0
+  if ( hrgn )
+  {
+     if ( GetLayout(hdc) & LAYOUT_RTL )
+     {
+        if ( MirrorRgnDC(hdc, hrgn, &NewRgn) )
+        {
+           if ( NewRgn ) hrgn = NewRgn;
+        }
+     }
+  }
+#endif
+  /* Batch handles RGN_COPY only! */
+  if (iMode == RGN_COPY)
+  {
+#if 0
+     PDC_ATTR pDc_Attr;
+     PRGN_ATTR pRgn_Attr = NULL;
+
+     /* hrgn can be NULL unless the RGN_COPY mode is specified. */
+     if (hrgn)
+        GdiGetHandleUserData((HGDIOBJ) hrgn, GDI_OBJECT_TYPE_REGION, (PVOID) &pRgn_Attr);
+
+     if ( GdiGetHandleUserData((HGDIOBJ) hdc, GDI_OBJECT_TYPE_DC, (PVOID) &pDc_Attr) &&
+          pDc_Attr )
+     {
+        PGDI_TABLE_ENTRY pEntry = GdiHandleTable + GDI_HANDLE_GET_INDEX(hdc);
+        PTEB pTeb = NtCurrentTeb();
+        
+        if ( pTeb->Win32ThreadInfo != NULL &&
+             pTeb->GdiTebBatch.HDC == hdc &&
+            !(pDc_Attr->ulDirty_ & DC_DIBSECTION) &&
+            !(pEntry->Flags & GDI_ENTRY_VALIDATE_VIS) )
+        {
+           if (!hrgn ||
+                (hrgn && pRgn_Attr && pRgn_Attr->Flags <= SIMPLEREGION) )
+           {
+              if ((pTeb->GdiTebBatch.Offset + sizeof(GDIBSEXTSELCLPRGN)) <= GDIBATCHBUFSIZE)
+              {
+                 PGDIBSEXTSELCLPRGN pgO = (PGDIBSEXTSELCLPRGN)(&pTeb->GdiTebBatch.Buffer[0] +
+                                                      pTeb->GdiTebBatch.Offset);
+                 pgO->gbHdr.Cmd = GdiBCExtSelClipRgn;
+                 pgO->gbHdr.Size = sizeof(GDIBSEXTSELCLPRGN);
+                 pgO->fnMode = iMode;
+
+                 if ( hrgn && pRgn_Attr )
+                 {
+                    Ret = pRgn_Attr->Flags;
+
+                    if ( pDc_Attr->VisRectRegion.Rect.left   >= pRgn_Attr->Rect.right  ||
+                         pDc_Attr->VisRectRegion.Rect.top    >= pRgn_Attr->Rect.bottom ||
+                         pDc_Attr->VisRectRegion.Rect.right  <= pRgn_Attr->Rect.left   ||
+                         pDc_Attr->VisRectRegion.Rect.bottom <= pRgn_Attr->Rect.top )
+                       Ret = NULLREGION;
+
+                    pgO->left   = pRgn_Attr->Rect.left;
+                    pgO->top    = pRgn_Attr->Rect.top;
+                    pgO->right  = pRgn_Attr->Rect.right;
+                    pgO->bottom = pRgn_Attr->Rect.bottom;
+                 }
+                 else
+                 {
+                    Ret = pDc_Attr->VisRectRegion.Flags;
+                    pgO->fnMode |= 0x80000000; // Set no hrgn mode.
+                 }
+                 pTeb->GdiTebBatch.Offset += sizeof(GDIBSEXTSELCLPRGN);
+                 pTeb->GdiBatchCount++;
+                 if (pTeb->GdiBatchCount >= GDI_BatchLimit) NtGdiFlush();
+                 if ( NewRgn ) DeleteObject(NewRgn);
+                 return Ret;
+              }
+           }
+        }
+     }
+#endif
+  }
+  Ret = NtGdiExtSelectClipRgn(hdc, hrgn, iMode);
+
+  if ( NewRgn ) DeleteObject(NewRgn);
+
+  return Ret;
+}
 
 /*
  * @implemented
  */
 int
-STDCALL
+WINAPI
 GetClipRgn(
         HDC     hdc,
         HRGN    hrgn
         )
 {
-       HRGN rgn = NtGdiGetClipRgn(hdc);
-       if(rgn)
-       {
-               if(NtGdiCombineRgn(hrgn, rgn, 0, RGN_COPY) != ERROR) return 1;
-               else
-                       return -1;
-       }
-       else    return 0;
+  INT Ret = NtGdiGetRandomRgn(hdc, hrgn, CLIPRGN);
+//  if (Ret)
+//  {
+//     if(GetLayout(hdc) & LAYOUT_RTL) MirrorRgnDC(hdc,(HRGN)Ret, NULL);
+//  }
+  return Ret;
 }
 
+/*
+ * @implemented
+ */
+int
+WINAPI
+GetMetaRgn(HDC hdc,
+           HRGN hrgn)
+{
+    return NtGdiGetRandomRgn(hdc, hrgn, METARGN);
+}
 
-HRGN
-WINAPI 
-CreatePolygonRgn( const POINT* Point, int Count, int Mode)
+/*
+ * @implemented
+ *
+ */
+DWORD
+WINAPI
+GetRegionData(HRGN hrgn,
+              DWORD nCount,
+              LPRGNDATA lpRgnData)
+{
+    if (!lpRgnData)
+    {
+        nCount = 0;
+    }
+
+    return NtGdiGetRegionData(hrgn,nCount,lpRgnData);
+}
+
+/*
+ * @implemented
+ *
+ */
+INT
+WINAPI
+GetRgnBox(HRGN hrgn,
+          LPRECT prcOut)
 {
-  return CreatePolyPolygonRgn(Point, (const INT*)&Count, 1, Mode);
+  PRGN_ATTR Rgn_Attr;
+
+  if (!GdiGetHandleUserData((HGDIOBJ) hrgn, GDI_OBJECT_TYPE_REGION, (PVOID) &Rgn_Attr))
+     return NtGdiGetRgnBox(hrgn, prcOut);
+
+  if (Rgn_Attr->Flags == NULLREGION)
+  {
+     prcOut->left   = 0;
+     prcOut->top    = 0;
+     prcOut->right  = 0;
+     prcOut->bottom = 0;
+  }
+  else
+  {
+     if (Rgn_Attr->Flags != SIMPLEREGION)
+        return NtGdiGetRgnBox(hrgn, prcOut);
+     /* WARNING! prcOut is never checked newbies! */
+     RtlCopyMemory( prcOut, &Rgn_Attr->Rect, sizeof(RECT));
+  }
+  return Rgn_Attr->Flags;
 }
 
+/*
+ * @implemented
+ */
+INT
+WINAPI
+IntersectClipRect(HDC hdc,
+                  int nLeftRect,
+                  int nTopRect,
+                  int nRightRect,
+                  int nBottomRect)
+{
+#if 0
+// Handle something other than a normal dc object.
+  if (GDI_HANDLE_GET_TYPE(hdc) != GDI_OBJECT_TYPE_DC)
+  {
+    if (GDI_HANDLE_GET_TYPE(hdc) == GDI_OBJECT_TYPE_METADC)
+      return MFDRV_IntersectClipRect( hdc, nLeftRect, nTopRect, nRightRect, nBottomRect);
+    else
+    {
+      PLDC pLDC = GdiGetLDC(hdc);
+      if ( pLDC )
+      {
+         if (pLDC->iType != LDC_EMFLDC || EMFDRV_IntersectClipRect( hdc, nLeftRect, nTopRect, nRightRect, nBottomRect))
+             return NtGdiIntersectClipRect(hdc, nLeftRect, nTopRect, nRightRect, nBottomRect);
+      }
+      else
+        SetLastError(ERROR_INVALID_HANDLE);
+      return ERROR;
+    }
+  }
+#endif
+    return NtGdiIntersectClipRect(hdc, nLeftRect, nTopRect, nRightRect, nBottomRect);
+}
 
-HRGN
+/*
+ * @implemented
+ */
+BOOL
 WINAPI
-CreatePolyPolygonRgn( const POINT* Point,
-                      const INT* Count,
-                      int inPolygons,
-                      int Mode)
+MirrorRgn(HWND hwnd, HRGN hrgn)
 {
-/*  return (HRGN) NtGdiPolyPolyDraw(  (HDC) Mode,
-                                 (PPOINT) Point,
-                                 (PULONG) Count,
-                                  (ULONG) inPolygons,
-                                          GdiPolyPolyRgn );
-*/
-   return (HRGN) NULL;
+  RECT Rect;
+  GetWindowRect(hwnd, &Rect);
+  return MirrorRgnByWidth(hrgn, Rect.right - Rect.left, NULL);
 }
 
+/*
+ * @implemented
+ */
+INT
+WINAPI
+OffsetClipRgn(HDC hdc,
+              int nXOffset,
+              int nYOffset)
+{
+#if 0
+// Handle something other than a normal dc object.
+  if (GDI_HANDLE_GET_TYPE(hdc) != GDI_OBJECT_TYPE_DC)
+  {
+    if (GDI_HANDLE_GET_TYPE(hdc) == GDI_OBJECT_TYPE_METADC)
+      return MFDRV_OffsetClipRgn( hdc, nXOffset, nYOffset );
+    else
+    {
+      PLDC pLDC = GdiGetLDC(hdc);
+      if ( !pLDC )
+      {
+         SetLastError(ERROR_INVALID_HANDLE);
+         return ERROR;
+      }
+      if (pLDC->iType == LDC_EMFLDC && !EMFDRV_OffsetClipRgn( hdc, nXOffset, nYOffset ))
+         return ERROR;
+      return NtGdiOffsetClipRgn( hdc,  nXOffset,  nYOffset);
+    }
+  }
+#endif
+  return NtGdiOffsetClipRgn( hdc,  nXOffset,  nYOffset);
+}
+
+/*
+ * @implemented
+ *
+ */
+INT
+WINAPI
+OffsetRgn( HRGN hrgn,
+          int nXOffset,
+          int nYOffset)
+{
+  PRGN_ATTR pRgn_Attr;
+  int nLeftRect, nTopRect, nRightRect, nBottomRect;
+
+  if (!GdiGetHandleUserData((HGDIOBJ) hrgn, GDI_OBJECT_TYPE_REGION, (PVOID) &pRgn_Attr))
+     return NtGdiOffsetRgn(hrgn,nXOffset,nYOffset);
+
+  if ( pRgn_Attr->Flags == NULLREGION)
+     return pRgn_Attr->Flags;
+
+  if ( pRgn_Attr->Flags != SIMPLEREGION)
+     return NtGdiOffsetRgn(hrgn,nXOffset,nYOffset);
+
+  nLeftRect   = pRgn_Attr->Rect.left;
+  nTopRect    = pRgn_Attr->Rect.top;
+  nRightRect  = pRgn_Attr->Rect.right;
+  nBottomRect = pRgn_Attr->Rect.bottom;
+
+  if (nLeftRect < nRightRect)
+  {
+     if (nTopRect < nBottomRect)
+     {
+        nLeftRect   = nXOffset + nLeftRect;
+        nTopRect    = nYOffset + nTopRect;
+        nRightRect  = nXOffset + nRightRect;
+        nBottomRect = nYOffset + nBottomRect;
+
+        /* Check 28 bit limit. Chp 9 Areas, pg 560. */
+        if ( nLeftRect   < -(1<<27)  ||
+             nTopRect    < -(1<<27)  ||
+             nRightRect  > (1<<27)-1 ||
+             nBottomRect > (1<<27)-1  )
+        {
+           return ERROR;
+        }
+
+        pRgn_Attr->Rect.top    = nTopRect;
+        pRgn_Attr->Rect.left   = nLeftRect;
+        pRgn_Attr->Rect.right  = nRightRect;
+        pRgn_Attr->Rect.bottom = nBottomRect;
+        pRgn_Attr->AttrFlags |= ATTR_RGN_DIRTY;
+     }
+  }
+  return pRgn_Attr->Flags;
+}
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+PtInRegion(IN HRGN hrgn,
+           int x,
+           int y)
+{
+  PRGN_ATTR pRgn_Attr;
+
+  if (!GdiGetHandleUserData((HGDIOBJ) hrgn, GDI_OBJECT_TYPE_REGION, (PVOID) &pRgn_Attr))
+     return NtGdiPtInRegion(hrgn,x,y);
+
+  if ( pRgn_Attr->Flags == NULLREGION)
+     return FALSE;
+
+  if ( pRgn_Attr->Flags != SIMPLEREGION)
+     return NtGdiPtInRegion(hrgn,x,y);
+
+  return INRECT( pRgn_Attr->Rect, x, y);
+}
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+RectInRegion(HRGN hrgn,
+             LPCRECT prcl)
+{
+  PRGN_ATTR pRgn_Attr;
+  RECTL rc;
+
+  if (!GdiGetHandleUserData((HGDIOBJ) hrgn, GDI_OBJECT_TYPE_REGION, (PVOID) &pRgn_Attr))
+     return NtGdiRectInRegion(hrgn, (LPRECT) prcl);
+
+  if ( pRgn_Attr->Flags == NULLREGION)
+     return FALSE;
+
+  if ( pRgn_Attr->Flags != SIMPLEREGION)
+     return NtGdiRectInRegion(hrgn, (LPRECT) prcl);
+
+ /* swap the coordinates to make right >= left and bottom >= top */
+ /* (region building rectangles are normalized the same way) */
+  if ( prcl->top > prcl->bottom)
+  {
+     rc.top = prcl->bottom;
+     rc.bottom = prcl->top;
+  }
+  else
+  {
+    rc.top = prcl->top;
+    rc.bottom = prcl->bottom;
+  }
+  if ( prcl->right < prcl->left)
+  {
+     rc.right = prcl->left;
+     rc.left = prcl->right;
+  }
+  else
+  {
+     rc.right = prcl->right;
+     rc.left = prcl->left;
+  }
+
+  if ( ComplexityFromRects( &pRgn_Attr->Rect, &rc) != DIFF_RGN )
+     return TRUE;
+
+  return FALSE;
+}
+
+/*
+ * @implemented
+ */
+int WINAPI
+SelectClipRgn(
+        HDC     hdc,
+        HRGN    hrgn
+)
+{
+    return ExtSelectClipRgn(hdc, hrgn, RGN_COPY);
+}
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+SetRectRgn(HRGN hrgn,
+           int nLeftRect,
+           int nTopRect,
+           int nRightRect,
+           int nBottomRect)
+{
+  PRGN_ATTR Rgn_Attr;
+
+  if (!GdiGetHandleUserData((HGDIOBJ) hrgn, GDI_OBJECT_TYPE_REGION, (PVOID) &Rgn_Attr))
+     return NtGdiSetRectRgn(hrgn, nLeftRect, nTopRect, nRightRect, nBottomRect);
+
+  if ((nLeftRect == nRightRect) || (nTopRect == nBottomRect))
+  {
+     Rgn_Attr->AttrFlags |= ATTR_RGN_DIRTY;
+     Rgn_Attr->Flags = NULLREGION;
+     Rgn_Attr->Rect.left = Rgn_Attr->Rect.top =
+     Rgn_Attr->Rect.right = Rgn_Attr->Rect.bottom = 0;
+     return TRUE;
+  }
+
+  Rgn_Attr->Rect.left   = nLeftRect;
+  Rgn_Attr->Rect.top    = nTopRect;
+  Rgn_Attr->Rect.right  = nRightRect;
+  Rgn_Attr->Rect.bottom = nBottomRect;
+
+  if(nLeftRect > nRightRect)
+  {
+     Rgn_Attr->Rect.left   = nRightRect;
+     Rgn_Attr->Rect.right  = nLeftRect;
+  }
+  if(nTopRect > nBottomRect)
+  {
+     Rgn_Attr->Rect.top    = nBottomRect;
+     Rgn_Attr->Rect.bottom = nTopRect;
+  }
+
+  Rgn_Attr->AttrFlags |= ATTR_RGN_DIRTY ;
+  Rgn_Attr->Flags = SIMPLEREGION;
+  return TRUE;
+}
+
+/*
+ * @implemented
+ */
+int
+WINAPI
+SetMetaRgn( HDC hDC )
+{
+ if (GDI_HANDLE_GET_TYPE(hDC) == GDI_OBJECT_TYPE_DC)
+    return NtGdiSetMetaRgn(hDC);
+#if 0
+ PLDC pLDC = GdiGetLDC(hDC);
+ if ( pLDC && GDI_HANDLE_GET_TYPE(hDC) != GDI_OBJECT_TYPE_METADC )
+ {
+    if (pLDC->iType == LDC_EMFLDC || EMFDRV_SetMetaRgn(hDC))
+    {
+       return NtGdiSetMetaRgn(hDC);
+    }
+    else
+       SetLastError(ERROR_INVALID_HANDLE);
+ }
+#endif
+ return ERROR;
+}