Added support for the DC meta region.

diff --git a/dlls/gdi/clipping.c b/dlls/gdi/clipping.c
index 0b98b46..0f69be7 100644
--- a/dlls/gdi/clipping.c
+++ b/dlls/gdi/clipping.c
@@ -33,12 +33,27 @@
 
 
 /***********************************************************************
+ *           get_clip_region
+ *
+ * Return the total clip region (if any).
+ */
+static inline HRGN get_clip_region( DC * dc )
+{
+    if (dc->hMetaClipRgn) return dc->hMetaClipRgn;
+    if (dc->hMetaRgn) return dc->hMetaRgn;
+    return dc->hClipRgn;
+}
+
+
+/***********************************************************************
  *           CLIPPING_UpdateGCRegion
  *
  * Update the GC clip region when the ClipRgn or VisRgn have changed.
  */
 void CLIPPING_UpdateGCRegion( DC * dc )
 {
+    HRGN clip_rgn;
+
     if (!dc->hVisRgn)
     {
         ERR("hVisRgn is zero. Please report this.\n" );
@@ -47,12 +62,26 @@
 
     if (dc->flags & DC_DIRTY) ERR( "DC is dirty. Please report this.\n" );
 
+    /* update the intersection of meta and clip regions */
+    if (dc->hMetaRgn && dc->hClipRgn)
+    {
+        if (!dc->hMetaClipRgn) dc->hMetaClipRgn = CreateRectRgn( 0, 0, 0, 0 );
+        CombineRgn( dc->hMetaClipRgn, dc->hClipRgn, dc->hMetaRgn, RGN_AND );
+        clip_rgn = dc->hMetaClipRgn;
+    }
+    else  /* only one is set, no need for an intersection */
+    {
+        if (dc->hMetaClipRgn) DeleteObject( dc->hMetaClipRgn );
+        dc->hMetaClipRgn = 0;
+        clip_rgn = dc->hMetaRgn ? dc->hMetaRgn : dc->hClipRgn;
+    }
+
     if (dc->funcs->pSetDeviceClipping)
-        dc->funcs->pSetDeviceClipping( dc->physDev, dc->hVisRgn, dc->hClipRgn );
+        dc->funcs->pSetDeviceClipping( dc->physDev, dc->hVisRgn, clip_rgn );
 }
 
 /***********************************************************************
- *           create_default_clip_rgn
+ *           create_default_clip_region
  *
  * Create a default clipping region when none already exists.
  */
@@ -346,6 +375,7 @@
 {
     POINT pt;
     BOOL ret;
+    HRGN clip;
     DC *dc = DC_GetDCUpdate( hdc );
 
     TRACE("%p %d,%d\n", hdc, x, y );
@@ -355,7 +385,7 @@
     pt.y = y;
     LPtoDP( hdc, &pt, 1 );
     ret = PtInRegion( dc->hVisRgn, pt.x, pt.y );
-    if (ret && dc->hClipRgn) ret = PtInRegion( dc->hClipRgn, pt.x, pt.y );
+    if (ret && (clip = get_clip_region(dc))) ret = PtInRegion( clip, pt.x, pt.y );
     GDI_ReleaseObj( hdc );
     return ret;
 }
@@ -368,6 +398,7 @@
 {
     RECT tmpRect;
     BOOL ret;
+    HRGN clip;
     DC *dc = DC_GetDCUpdate( hdc );
     if (!dc) return FALSE;
     TRACE("%p %ld,%ldx%ld,%ld\n", hdc, rect->left, rect->top, rect->right, rect->bottom );
@@ -375,10 +406,10 @@
     tmpRect = *rect;
     LPtoDP( hdc, (POINT *)&tmpRect, 2 );
 
-    if (dc->hClipRgn)
+    if ((clip = get_clip_region(dc)))
     {
         HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
-        CombineRgn( hrgn, dc->hVisRgn, dc->hClipRgn, RGN_AND );
+        CombineRgn( hrgn, dc->hVisRgn, clip, RGN_AND );
         ret = RectInRegion( hrgn, &tmpRect );
         DeleteObject( hrgn );
     }
@@ -394,12 +425,13 @@
 INT WINAPI GetClipBox( HDC hdc, LPRECT rect )
 {
     INT ret;
+    HRGN clip;
     DC *dc = DC_GetDCUpdate( hdc );
     if (!dc) return ERROR;
-    if (dc->hClipRgn)
+    if ((clip = get_clip_region(dc)))
     {
         HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
-        CombineRgn( hrgn, dc->hVisRgn, dc->hClipRgn, RGN_AND );
+        CombineRgn( hrgn, dc->hVisRgn, clip, RGN_AND );
         ret = GetRgnBox( hrgn, rect );
         DeleteObject( hrgn );
     }
@@ -429,6 +461,25 @@
     return ret;
 }
 
+
+/***********************************************************************
+ *           GetMetaRgn    (GDI32.@)
+ */
+INT WINAPI GetMetaRgn( HDC hdc, HRGN hRgn )
+{
+    INT ret = 0;
+    DC * dc = DC_GetDCPtr( hdc );
+
+    if (dc)
+    {
+        if (dc->hMetaRgn && CombineRgn( hRgn, dc->hMetaRgn, 0, RGN_COPY ) != ERROR)
+            ret = 1;
+        GDI_ReleaseObj( hdc );
+    }
+    return ret;
+}
+
+
 /***********************************************************************
  *           SaveVisRgn   (GDI.129)
  */
@@ -500,50 +551,41 @@
  */
 INT WINAPI GetRandomRgn(HDC hDC, HRGN hRgn, INT iCode)
 {
+    HRGN rgn;
+    DC *dc = DC_GetDCPtr( hDC );
+
+    if (!dc) return -1;
+
     switch (iCode)
     {
+    case 1:
+        rgn = dc->hClipRgn;
+        break;
+    case 2:
+        rgn = dc->hMetaRgn;
+        break;
+    case 3:
+        rgn = dc->hMetaClipRgn;
+        break;
     case SYSRGN: /* == 4 */
-	{
-	    DC *dc = DC_GetDCPtr (hDC);
-	    if (!dc) return -1;
-
-	    CombineRgn (hRgn, dc->hVisRgn, 0, RGN_COPY);
-            GDI_ReleaseObj( hDC );
-	    /*
-	     *     On Windows NT/2000,
-	     *           the region returned is in screen coordinates.
-	     *     On Windows 95/98,
-	     *           the region returned is in window coordinates
-	     */
-            if (!(GetVersion() & 0x80000000))
-            {
-                POINT org;
-                GetDCOrgEx(hDC, &org);
-                OffsetRgn(hRgn, org.x, org.y);
-            }
-	    return 1;
-	}
-
-    case 1: /* clip region */
-            return GetClipRgn (hDC, hRgn);
-
+        rgn = dc->hVisRgn;
+        break;
     default:
-        WARN("Unknown iCode %d\n", iCode);
+        WARN("Unknown code %d\n", iCode);
+        GDI_ReleaseObj( hDC );
         return -1;
     }
+    if (rgn) CombineRgn( hRgn, rgn, 0, RGN_COPY );
+    GDI_ReleaseObj( hDC );
 
-    return -1;
-}
-
-
-/***********************************************************************
- *           GetMetaRgn    (GDI32.@)
- */
-INT WINAPI GetMetaRgn( HDC hdc, HRGN hRgn )
-{
-    FIXME( "stub\n" );
-
-    return 0;
+    /* On Windows NT/2000, the region returned is in screen coordinates */
+    if (!(GetVersion() & 0x80000000))
+    {
+        POINT org;
+        GetDCOrgEx( hDC, &org );
+        OffsetRgn( hRgn, org.x, org.y );
+    }
+    return (rgn != 0);
 }
 
 
@@ -552,7 +594,31 @@
  */
 INT WINAPI SetMetaRgn( HDC hdc )
 {
-    FIXME( "stub\n" );
+    INT ret;
+    RECT dummy;
+    DC *dc = DC_GetDCPtr( hdc );
 
-    return ERROR;
+    if (!dc) return ERROR;
+
+    if (dc->hMetaClipRgn)
+    {
+        /* the intersection becomes the new meta region */
+        DeleteObject( dc->hMetaRgn );
+        DeleteObject( dc->hClipRgn );
+        dc->hMetaRgn = dc->hMetaClipRgn;
+        dc->hClipRgn = 0;
+        dc->hMetaClipRgn = 0;
+    }
+    else if (dc->hClipRgn)
+    {
+        dc->hMetaRgn = dc->hClipRgn;
+        dc->hClipRgn = 0;
+    }
+    /* else nothing to do */
+
+    /* Note: no need to call CLIPPING_UpdateGCRegion, the overall clip region hasn't changed */
+
+    ret = GetRgnBox( dc->hMetaRgn, &dummy );
+    GDI_ReleaseObj( hdc );
+    return ret;
 }
diff --git a/dlls/gdi/dc.c b/dlls/gdi/dc.c
index 90b84f4..077ec53 100644
--- a/dlls/gdi/dc.c
+++ b/dlls/gdi/dc.c
@@ -80,6 +80,8 @@
     dc->flags               = 0;
     dc->layout              = 0;
     dc->hClipRgn            = 0;
+    dc->hMetaRgn            = 0;
+    dc->hMetaClipRgn        = 0;
     dc->hVisRgn             = 0;
     dc->hPen                = GetStockObject( BLACK_PEN );
     dc->hBrush              = GetStockObject( WHITE_BRUSH );
@@ -347,14 +349,21 @@
 
     /* Get/SetDCState() don't change hVisRgn field ("Undoc. Windows" p.559). */
 
-    newdc->hVisRgn = 0;
+    newdc->hVisRgn      = 0;
+    newdc->hClipRgn     = 0;
+    newdc->hMetaRgn     = 0;
+    newdc->hMetaClipRgn = 0;
     if (dc->hClipRgn)
     {
-	newdc->hClipRgn = CreateRectRgn( 0, 0, 0, 0 );
-	CombineRgn( newdc->hClipRgn, dc->hClipRgn, 0, RGN_COPY );
+        newdc->hClipRgn = CreateRectRgn( 0, 0, 0, 0 );
+        CombineRgn( newdc->hClipRgn, dc->hClipRgn, 0, RGN_COPY );
     }
-    else
-	newdc->hClipRgn = 0;
+    if (dc->hMetaRgn)
+    {
+        newdc->hMetaRgn = CreateRectRgn( 0, 0, 0, 0 );
+        CombineRgn( newdc->hMetaRgn, dc->hMetaRgn, 0, RGN_COPY );
+    }
+    /* don't bother recomputing hMetaClipRgn, we'll do that in SetDCState */
 
     if(dc->gdiFont) {
 	newdc->gdiFont = dc->gdiFont;
@@ -436,6 +445,16 @@
         if (dc->hClipRgn) DeleteObject( dc->hClipRgn );
         dc->hClipRgn = 0;
     }
+    if (dcs->hMetaRgn)
+    {
+        if (!dc->hMetaRgn) dc->hMetaRgn = CreateRectRgn( 0, 0, 0, 0 );
+        CombineRgn( dc->hMetaRgn, dcs->hMetaRgn, 0, RGN_COPY );
+    }
+    else
+    {
+        if (dc->hMetaRgn) DeleteObject( dc->hMetaRgn );
+        dc->hMetaRgn = 0;
+    }
     CLIPPING_UpdateGCRegion( dc );
 
     SelectObject( hdc, dcs->hBitmap );
@@ -777,6 +796,8 @@
         dc->saved_dc = dcs->saved_dc;
         dc->saveLevel--;
         if (dcs->hClipRgn) DeleteObject( dcs->hClipRgn );
+        if (dcs->hMetaRgn) DeleteObject( dcs->hMetaRgn );
+        if (dcs->hMetaClipRgn) DeleteObject( dcs->hMetaClipRgn );
         if (dcs->hVisRgn) DeleteObject( dcs->hVisRgn );
         PATH_DestroyGdiPath(&dcs->path);
         GDI_FreeObject( hdcs, dcs );
@@ -801,6 +822,8 @@
         dc->saved_visrgn = next;
     }
     if (dc->hClipRgn) DeleteObject( dc->hClipRgn );
+    if (dc->hMetaRgn) DeleteObject( dc->hMetaRgn );
+    if (dc->hMetaClipRgn) DeleteObject( dc->hMetaClipRgn );
     if (dc->hVisRgn) DeleteObject( dc->hVisRgn );
     PATH_DestroyGdiPath(&dc->path);
 
diff --git a/dlls/gdi/gdi_private.h b/dlls/gdi/gdi_private.h
index a7717bc..fc71da3 100644
--- a/dlls/gdi/gdi_private.h
+++ b/dlls/gdi/gdi_private.h
@@ -229,8 +229,10 @@
 
     int           flags;
     DWORD         layout;
-    HRGN          hClipRgn;     /* Clip region (may be 0) */
-    HRGN          hVisRgn;      /* Visible region (must never be 0) */
+    HRGN          hClipRgn;      /* Clip region (may be 0) */
+    HRGN          hMetaRgn;      /* Meta region (may be 0) */
+    HRGN          hMetaClipRgn;  /* Intersection of meta and clip regions (may be 0) */
+    HRGN          hVisRgn;       /* Visible region (must never be 0) */
     HPEN          hPen;
     HBRUSH        hBrush;
     HFONT         hFont;