gdiplus: Implement GdipBeginContainer2 and GdipEndContainer.
diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c
index 3525743..b81a984 100644
--- a/dlls/gdiplus/graphics.c
+++ b/dlls/gdiplus/graphics.c
@@ -38,6 +38,7 @@
 #include "gdiplus.h"
 #include "gdiplus_private.h"
 #include "wine/debug.h"
+#include "wine/list.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
 
@@ -941,6 +942,104 @@
     return result;
 }
 
+typedef struct _GraphicsContainerItem {
+    struct list entry;
+    GraphicsContainer contid;
+
+    SmoothingMode smoothing;
+    CompositingQuality compqual;
+    InterpolationMode interpolation;
+    CompositingMode compmode;
+    TextRenderingHint texthint;
+    REAL scale;
+    GpUnit unit;
+    PixelOffsetMode pixeloffset;
+    UINT textcontrast;
+    GpMatrix* worldtrans;
+    GpRegion* clip;
+} GraphicsContainerItem;
+
+static GpStatus init_container(GraphicsContainerItem** container,
+        GDIPCONST GpGraphics* graphics){
+    GpStatus sts;
+
+    *container = GdipAlloc(sizeof(GraphicsContainerItem));
+    if(!(*container))
+        return OutOfMemory;
+
+    (*container)->contid = graphics->contid + 1;
+
+    (*container)->smoothing = graphics->smoothing;
+    (*container)->compqual = graphics->compqual;
+    (*container)->interpolation = graphics->interpolation;
+    (*container)->compmode = graphics->compmode;
+    (*container)->texthint = graphics->texthint;
+    (*container)->scale = graphics->scale;
+    (*container)->unit = graphics->unit;
+    (*container)->textcontrast = graphics->textcontrast;
+    (*container)->pixeloffset = graphics->pixeloffset;
+
+    sts = GdipCloneMatrix(graphics->worldtrans, &(*container)->worldtrans);
+    if(sts != Ok){
+        GdipFree(*container);
+        *container = NULL;
+        return sts;
+    }
+
+    sts = GdipCloneRegion(graphics->clip, &(*container)->clip);
+    if(sts != Ok){
+        GdipDeleteMatrix((*container)->worldtrans);
+        GdipFree(*container);
+        *container = NULL;
+        return sts;
+    }
+
+    return Ok;
+}
+
+static void delete_container(GraphicsContainerItem* container){
+    GdipDeleteMatrix(container->worldtrans);
+    GdipDeleteRegion(container->clip);
+    GdipFree(container);
+}
+
+static GpStatus restore_container(GpGraphics* graphics,
+        GDIPCONST GraphicsContainerItem* container){
+    GpStatus sts;
+    GpMatrix *newTrans;
+    GpRegion *newClip;
+
+    sts = GdipCloneMatrix(container->worldtrans, &newTrans);
+    if(sts != Ok)
+        return sts;
+
+    sts = GdipCloneRegion(container->clip, &newClip);
+    if(sts != Ok){
+        GdipDeleteMatrix(newTrans);
+        return sts;
+    }
+
+    GdipDeleteMatrix(graphics->worldtrans);
+    graphics->worldtrans = newTrans;
+
+    GdipDeleteRegion(graphics->clip);
+    graphics->clip = newClip;
+
+    graphics->contid = container->contid - 1;
+
+    graphics->smoothing = container->smoothing;
+    graphics->compqual = container->compqual;
+    graphics->interpolation = container->interpolation;
+    graphics->compmode = container->compmode;
+    graphics->texthint = container->texthint;
+    graphics->scale = container->scale;
+    graphics->unit = container->unit;
+    graphics->textcontrast = container->textcontrast;
+    graphics->pixeloffset = container->pixeloffset;
+
+    return Ok;
+}
+
 GpStatus WINGDIPAPI GdipCreateFromHDC(HDC hdc, GpGraphics **graphics)
 {
     TRACE("(%p, %p)\n", hdc, graphics);
@@ -991,6 +1090,8 @@
     (*graphics)->scale = 1.0;
     (*graphics)->busy = FALSE;
     (*graphics)->textcontrast = 4;
+    list_init(&(*graphics)->containers);
+    (*graphics)->contid = 0;
 
     return Ok;
 }
@@ -1155,6 +1256,7 @@
 
 GpStatus WINGDIPAPI GdipDeleteGraphics(GpGraphics *graphics)
 {
+    GraphicsContainerItem *cont, *next;
     TRACE("(%p)\n", graphics);
 
     if(!graphics) return InvalidParameter;
@@ -1163,6 +1265,11 @@
     if(graphics->owndc)
         ReleaseDC(graphics->hwnd, graphics->hdc);
 
+    LIST_FOR_EACH_ENTRY_SAFE(cont, next, &graphics->containers, GraphicsContainerItem, entry){
+        list_remove(&cont->entry);
+        delete_container(cont);
+    }
+
     GdipDeleteRegion(graphics->clip);
     GdipDeleteMatrix(graphics->worldtrans);
     GdipFree(graphics);
@@ -3254,14 +3361,24 @@
     return Ok;
 }
 
-GpStatus WINGDIPAPI GdipBeginContainer2(GpGraphics *graphics, GraphicsContainer *state)
+GpStatus WINGDIPAPI GdipBeginContainer2(GpGraphics *graphics,
+        GraphicsContainer *state)
 {
-    FIXME("(%p, %p)\n", graphics, state);
+    GraphicsContainerItem *container;
+    GpStatus sts;
+
+    TRACE("(%p, %p)\n", graphics, state);
 
     if(!graphics || !state)
         return InvalidParameter;
 
-    *state = 0xdeadbeef;
+    sts = init_container(&container, graphics);
+    if(sts != Ok)
+        return sts;
+
+    list_add_head(&graphics->containers, &container->entry);
+    *state = graphics->contid = container->contid;
+
     return Ok;
 }
 
@@ -3285,12 +3402,36 @@
 
 GpStatus WINGDIPAPI GdipEndContainer(GpGraphics *graphics, GraphicsState state)
 {
-    FIXME("(%p, 0x%x)\n", graphics, state);
+    GpStatus sts;
+    GraphicsContainerItem *container, *container2;
 
-    if(!graphics || !state)
+    TRACE("(%p, %x)\n", graphics, state);
+
+    if(!graphics)
         return InvalidParameter;
 
-    return Ok;
+    LIST_FOR_EACH_ENTRY(container, &graphics->containers, GraphicsContainerItem, entry){
+        if(container->contid == state)
+            break;
+    }
+
+    /* did not find a matching container */
+    if(&container->entry == &graphics->containers)
+        return Ok;
+
+    /* remove all of the containers on top of the found container */
+    LIST_FOR_EACH_ENTRY_SAFE(container, container2, &graphics->containers, GraphicsContainerItem, entry){
+        if(container->contid == state)
+            break;
+        list_remove(&container->entry);
+        delete_container(container);
+    }
+
+    list_remove(&container->entry);
+    sts = restore_container(graphics, container);
+    delete_container(container);
+
+    return sts;
 }
 
 GpStatus WINGDIPAPI GdipScaleWorldTransform(GpGraphics *graphics, REAL sx,