gdi32: Store a pointer to the path in the DC and make the path structure opaque.
diff --git a/dlls/gdi32/dc.c b/dlls/gdi32/dc.c
index 4eb8997..b357cee 100644
--- a/dlls/gdi32/dc.c
+++ b/dlls/gdi32/dc.c
@@ -110,6 +110,7 @@
     dc->hDevice             = 0;
     dc->hPalette            = GetStockObject( DEFAULT_PALETTE );
     dc->gdiFont             = 0;
+    dc->path                = NULL;
     dc->font_code_page      = CP_ACP;
     dc->ROPmode             = R2_COPYPEN;
     dc->polyFillMode        = ALTERNATE;
@@ -146,7 +147,6 @@
     dc->BoundsRect.top      = 0;
     dc->BoundsRect.right    = 0;
     dc->BoundsRect.bottom   = 0;
-    PATH_InitGdiPath(&dc->path);
 
     if (!(dc->hSelf = alloc_gdi_handle( &dc->header, magic, &dc_funcs )))
     {
@@ -174,7 +174,7 @@
     if (dc->hMetaRgn) DeleteObject( dc->hMetaRgn );
     if (dc->hMetaClipRgn) DeleteObject( dc->hMetaClipRgn );
     if (dc->hVisRgn) DeleteObject( dc->hVisRgn );
-    PATH_DestroyGdiPath( &dc->path );
+    if (dc->path) free_gdi_path( dc->path );
     HeapFree( GetProcessHeap(), 0, dc );
 }
 
diff --git a/dlls/gdi32/gdi_private.h b/dlls/gdi32/gdi_private.h
index 0868e14..70f2e4b 100644
--- a/dlls/gdi32/gdi_private.h
+++ b/dlls/gdi32/gdi_private.h
@@ -72,27 +72,6 @@
     struct hdc_list *hdcs;
 } GDIOBJHDR;
 
-/* It should not be necessary to access the contents of the GdiPath
- * structure directly; if you find that the exported functions don't
- * allow you to do what you want, then please place a new exported
- * function that does this job in path.c.
- */
-typedef enum tagGdiPathState
-{
-   PATH_Null,
-   PATH_Open,
-   PATH_Closed
-} GdiPathState;
-
-typedef struct gdi_path
-{
-   GdiPathState state;
-   POINT      *pPoints;
-   BYTE         *pFlags;
-   int          numEntriesUsed, numEntriesAllocated;
-   BOOL       newStroke;
-} GdiPath;
-
 typedef struct tagGdiFont GdiFont;
 
 typedef struct tagDC
@@ -137,7 +116,7 @@
     HPALETTE      hPalette;
 
     GdiFont      *gdiFont;
-    GdiPath       path;
+    struct gdi_path *path;
 
     UINT          font_code_page;
     WORD          ROPmode;
@@ -320,8 +299,7 @@
 
 /* path.c */
 
-extern void PATH_InitGdiPath(GdiPath *pPath) DECLSPEC_HIDDEN;
-extern void PATH_DestroyGdiPath(GdiPath *pPath) DECLSPEC_HIDDEN;
+extern void free_gdi_path( struct gdi_path *path ) DECLSPEC_HIDDEN;
 extern BOOL PATH_SavePath( DC *dst, DC *src ) DECLSPEC_HIDDEN;
 extern BOOL PATH_RestorePath( DC *dst, DC *src ) DECLSPEC_HIDDEN;
 
diff --git a/dlls/gdi32/path.c b/dlls/gdi32/path.c
index a8c9c89..715932c 100644
--- a/dlls/gdi32/path.c
+++ b/dlls/gdi32/path.c
@@ -81,11 +81,26 @@
    double x, y;
 } FLOAT_POINT;
 
+typedef enum
+{
+    PATH_Null,
+    PATH_Open,
+    PATH_Closed
+} GdiPathState;
+
+typedef struct gdi_path
+{
+    GdiPathState state;
+    POINT       *pPoints;
+    BYTE        *pFlags;
+    int          numEntriesUsed, numEntriesAllocated;
+    BOOL         newStroke;
+} GdiPath;
 
 struct path_physdev
 {
     struct gdi_physdev dev;
-    GdiPath           *path;
+    struct gdi_path   *path;
 };
 
 static inline struct path_physdev *get_path_physdev( PHYSDEV dev )
@@ -100,7 +115,7 @@
     HeapFree( GetProcessHeap(), 0, dev );
 }
 
-static void free_gdi_path( struct gdi_path *path )
+void free_gdi_path( struct gdi_path *path )
 {
     HeapFree( GetProcessHeap(), 0, path->pPoints );
     HeapFree( GetProcessHeap(), 0, path->pFlags );
@@ -131,6 +146,31 @@
     return path;
 }
 
+static struct gdi_path *copy_gdi_path( const struct gdi_path *src_path )
+{
+    struct gdi_path *path = HeapAlloc( GetProcessHeap(), 0, sizeof(*path) );
+
+    if (!path)
+    {
+        SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+        return NULL;
+    }
+    path->state = src_path->state;
+    path->numEntriesUsed = path->numEntriesAllocated = src_path->numEntriesUsed;
+    path->newStroke = src_path->newStroke;
+    path->pPoints = HeapAlloc( GetProcessHeap(), 0, path->numEntriesUsed * sizeof(*path->pPoints) );
+    path->pFlags = HeapAlloc( GetProcessHeap(), 0, path->numEntriesUsed * sizeof(*path->pFlags) );
+    if (!path->pPoints || !path->pFlags)
+    {
+        free_gdi_path( path );
+        SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+        return NULL;
+    }
+    memcpy( path->pPoints, src_path->pPoints, path->numEntriesUsed * sizeof(*path->pPoints) );
+    memcpy( path->pFlags, src_path->pFlags, path->numEntriesUsed * sizeof(*path->pFlags) );
+    return path;
+}
+
 /* Performs a world-to-viewport transformation on the specified point (which
  * is in floating point format).
  */
@@ -156,16 +196,6 @@
 }
 
 
-/* PATH_EmptyPath
- *
- * Removes all entries from the path and sets the path state to PATH_Null.
- */
-static void PATH_EmptyPath(GdiPath *pPath)
-{
-    pPath->state=PATH_Null;
-    pPath->numEntriesUsed=0;
-}
-
 /* PATH_ReserveEntries
  *
  * Ensures that at least "numEntries" entries (for points and flags) have
@@ -262,35 +292,6 @@
     return add_log_points( physdev, &pos, 1, PT_MOVETO ) != NULL;
 }
 
-/* PATH_AssignGdiPath
- *
- * Copies the GdiPath structure "pPathSrc" to "pPathDest". A deep copy is
- * performed, i.e. the contents of the pPoints and pFlags arrays are copied,
- * not just the pointers. Since this means that the arrays in pPathDest may
- * need to be resized, pPathDest should have been initialized using
- * PATH_InitGdiPath (in C++, this function would be an assignment operator,
- * not a copy constructor).
- * Returns TRUE if successful, else FALSE.
- */
-static BOOL PATH_AssignGdiPath(GdiPath *pPathDest, const GdiPath *pPathSrc)
-{
-   /* Make sure destination arrays are big enough */
-   if(!PATH_ReserveEntries(pPathDest, pPathSrc->numEntriesUsed))
-      return FALSE;
-
-   /* Perform the copy operation */
-   memcpy(pPathDest->pPoints, pPathSrc->pPoints,
-      sizeof(POINT)*pPathSrc->numEntriesUsed);
-   memcpy(pPathDest->pFlags, pPathSrc->pFlags,
-      sizeof(BYTE)*pPathSrc->numEntriesUsed);
-
-   pPathDest->state=pPathSrc->state;
-   pPathDest->numEntriesUsed=pPathSrc->numEntriesUsed;
-   pPathDest->newStroke=pPathSrc->newStroke;
-
-   return TRUE;
-}
-
 /* PATH_CheckCorners
  *
  * Helper function for RoundRect() and Rectangle()
@@ -622,10 +623,10 @@
 
    if(!dc) return -1;
 
-   pPath = &dc->path;
+   pPath = dc->path;
 
    /* Check that path is closed */
-   if(pPath->state!=PATH_Closed)
+   if(!pPath || pPath->state != PATH_Closed)
    {
       SetLastError(ERROR_CAN_NOT_COMPLETE);
       goto done;
@@ -669,22 +670,22 @@
  */
 HRGN WINAPI PathToRegion(HDC hdc)
 {
-   GdiPath *pPath;
    HRGN  hrgnRval = 0;
    DC *dc = get_dc_ptr( hdc );
 
    /* Get pointer to path */
    if(!dc) return 0;
 
-    pPath = &dc->path;
-
    /* Check that path is closed */
-   if(pPath->state!=PATH_Closed) SetLastError(ERROR_CAN_NOT_COMPLETE);
+   if (!dc->path || dc->path->state != PATH_Closed) SetLastError(ERROR_CAN_NOT_COMPLETE);
    else
    {
-       /* FIXME: Should we empty the path even if conversion failed? */
-       hrgnRval = PATH_PathToRegion(pPath, GetPolyFillMode(hdc));
-       if (hrgnRval) PATH_EmptyPath(pPath);
+       if ((hrgnRval = PATH_PathToRegion(dc->path, GetPolyFillMode(hdc))))
+       {
+           /* FIXME: Should we empty the path even if conversion failed? */
+           free_gdi_path( dc->path );
+           dc->path = NULL;
+       }
    }
    release_dc_ptr( dc );
    return hrgnRval;
@@ -813,7 +814,8 @@
     DC *dc = get_dc_ptr( dev->hdc );
 
     if (!dc) return FALSE;
-    PATH_EmptyPath( &dc->path );
+    free_gdi_path( dc->path );
+    dc->path = NULL;
     pop_path_driver( dc );
     release_dc_ptr( dc );
     return TRUE;
@@ -828,7 +830,7 @@
     DC *dc = get_dc_ptr( dev->hdc );
 
     if (!dc) return FALSE;
-    dc->path.state = PATH_Closed;
+    dc->path->state = PATH_Closed;
     pop_path_driver( dc );
     release_dc_ptr( dc );
     return TRUE;
@@ -846,7 +848,6 @@
 
     if (!physdev) return FALSE;
     dc = get_dc_ptr( (*dev)->hdc );
-    physdev->path = &dc->path;
     push_dc_driver( dev, &physdev->dev, &path_driver );
     release_dc_ptr( dc );
     return TRUE;
@@ -863,56 +864,36 @@
 }
 
 
-/* PATH_InitGdiPath
- *
- * Initializes the GdiPath structure.
- */
-void PATH_InitGdiPath(GdiPath *pPath)
-{
-   assert(pPath!=NULL);
-
-   pPath->state=PATH_Null;
-   pPath->pPoints=NULL;
-   pPath->pFlags=NULL;
-   pPath->numEntriesUsed=0;
-   pPath->numEntriesAllocated=0;
-}
-
-/* PATH_DestroyGdiPath
- *
- * Destroys a GdiPath structure (frees the memory in the arrays).
- */
-void PATH_DestroyGdiPath(GdiPath *pPath)
-{
-   assert(pPath!=NULL);
-
-   HeapFree( GetProcessHeap(), 0, pPath->pPoints );
-   HeapFree( GetProcessHeap(), 0, pPath->pFlags );
-}
-
 BOOL PATH_SavePath( DC *dst, DC *src )
 {
-    PATH_InitGdiPath( &dst->path );
-    return PATH_AssignGdiPath( &dst->path, &src->path );
+    if (src->path)
+    {
+        if (!(dst->path = copy_gdi_path( src->path ))) return FALSE;
+    }
+    else dst->path = NULL;
+    return TRUE;
 }
 
 BOOL PATH_RestorePath( DC *dst, DC *src )
 {
-    BOOL ret;
+    struct path_physdev *physdev;
 
-    if (src->path.state == PATH_Open && dst->path.state != PATH_Open)
+    if (src->path && src->path->state == PATH_Open)
     {
-        if (!path_driver.pCreateDC( &dst->physDev, NULL, NULL, NULL, NULL )) return FALSE;
-        ret = PATH_AssignGdiPath( &dst->path, &src->path );
-        if (!ret) pop_path_driver( dst );
+        if (!dst->path || dst->path->state != PATH_Open)
+        {
+            if (!path_driver.pCreateDC( &dst->physDev, NULL, NULL, NULL, NULL )) return FALSE;
+        }
+        physdev = get_path_physdev( dst->physDev );
+        assert( physdev->dev.funcs == &path_driver );
+        physdev->path = src->path;
     }
-    else if (src->path.state != PATH_Open && dst->path.state == PATH_Open)
-    {
-        ret = PATH_AssignGdiPath( &dst->path, &src->path );
-        if (ret) pop_path_driver( dst );
-    }
-    else ret = PATH_AssignGdiPath( &dst->path, &src->path );
-    return ret;
+    else if (dst->path && dst->path->state == PATH_Open) pop_path_driver( dst );
+
+    if (dst->path) free_gdi_path( dst->path );
+    dst->path = src->path;
+    src->path = NULL;
+    return TRUE;
 }
 
 
@@ -1797,7 +1778,7 @@
         return NULL;
     }
 
-    if (!(flat_path = PATH_FlattenPath( &dc->path ))) return NULL;
+    if (!(flat_path = PATH_FlattenPath( dc->path ))) return NULL;
 
     penWidthIn = penWidth / 2;
     penWidthOut = penWidth / 2;
@@ -2113,11 +2094,19 @@
 BOOL nulldrv_BeginPath( PHYSDEV dev )
 {
     DC *dc = get_nulldrv_dc( dev );
+    struct path_physdev *physdev;
+    struct gdi_path *path = alloc_gdi_path();
 
-    if (!path_driver.pCreateDC( &dc->physDev, NULL, NULL, NULL, NULL )) return FALSE;
-    PATH_EmptyPath(&dc->path);
-    dc->path.newStroke = TRUE;
-    dc->path.state = PATH_Open;
+    if (!path) return FALSE;
+    if (!path_driver.pCreateDC( &dc->physDev, NULL, NULL, NULL, NULL ))
+    {
+        free_gdi_path( path );
+        return FALSE;
+    }
+    physdev = get_path_physdev( dc->physDev );
+    physdev->path = path;
+    if (dc->path) free_gdi_path( dc->path );
+    dc->path = path;
     return TRUE;
 }
 
@@ -2131,7 +2120,8 @@
 {
     DC *dc = get_nulldrv_dc( dev );
 
-    PATH_EmptyPath( &dc->path );
+    if (dc->path) free_gdi_path( dc->path );
+    dc->path = NULL;
     return TRUE;
 }
 
@@ -2147,14 +2137,18 @@
     HRGN hrgn;
     DC *dc = get_nulldrv_dc( dev );
 
-    if (dc->path.state != PATH_Closed)
+    if (!dc->path || dc->path->state != PATH_Closed)
     {
         SetLastError( ERROR_CAN_NOT_COMPLETE );
         return FALSE;
     }
-    if (!(hrgn = PATH_PathToRegion( &dc->path, GetPolyFillMode(dev->hdc)))) return FALSE;
+    if (!(hrgn = PATH_PathToRegion( dc->path, GetPolyFillMode(dev->hdc)))) return FALSE;
     ret = ExtSelectClipRgn( dev->hdc, hrgn, mode ) != ERROR;
-    if (ret) PATH_EmptyPath( &dc->path );
+    if (ret)
+    {
+        free_gdi_path( dc->path );
+        dc->path = NULL;
+    }
     /* FIXME: Should this function delete the path even if it failed? */
     DeleteObject( hrgn );
     return ret;
@@ -2164,14 +2158,15 @@
 {
     DC *dc = get_nulldrv_dc( dev );
 
-    if (dc->path.state != PATH_Closed)
+    if (!dc->path || dc->path->state != PATH_Closed)
     {
         SetLastError( ERROR_CAN_NOT_COMPLETE );
         return FALSE;
     }
-    if (!PATH_FillPath( dev->hdc, &dc->path )) return FALSE;
+    if (!PATH_FillPath( dev->hdc, dc->path )) return FALSE;
     /* FIXME: Should the path be emptied even if conversion failed? */
-    PATH_EmptyPath( &dc->path );
+    free_gdi_path( dc->path );
+    dc->path = NULL;
     return TRUE;
 }
 
@@ -2179,14 +2174,15 @@
 {
     DC *dc = get_nulldrv_dc( dev );
 
-    if (dc->path.state != PATH_Closed)
+    if (!dc->path || dc->path->state != PATH_Closed)
     {
         SetLastError( ERROR_CAN_NOT_COMPLETE );
         return FALSE;
     }
-    if (!PATH_FillPath( dev->hdc, &dc->path )) return FALSE;
-    if (!PATH_StrokePath( dev->hdc, &dc->path )) return FALSE;
-    PATH_EmptyPath( &dc->path );
+    if (!PATH_FillPath( dev->hdc, dc->path )) return FALSE;
+    if (!PATH_StrokePath( dev->hdc, dc->path )) return FALSE;
+    free_gdi_path( dc->path );
+    dc->path = NULL;
     return TRUE;
 }
 
@@ -2194,13 +2190,14 @@
 {
     DC *dc = get_nulldrv_dc( dev );
 
-    if (dc->path.state != PATH_Closed)
+    if (!dc->path || dc->path->state != PATH_Closed)
     {
         SetLastError( ERROR_CAN_NOT_COMPLETE );
         return FALSE;
     }
-    if (!PATH_StrokePath( dev->hdc, &dc->path )) return FALSE;
-    PATH_EmptyPath( &dc->path );
+    if (!PATH_StrokePath( dev->hdc, dc->path )) return FALSE;
+    free_gdi_path( dc->path );
+    dc->path = NULL;
     return TRUE;
 }
 
@@ -2209,14 +2206,14 @@
     DC *dc = get_nulldrv_dc( dev );
     struct gdi_path *path;
 
-    if (dc->path.state != PATH_Closed)
+    if (!dc->path || dc->path->state != PATH_Closed)
     {
         SetLastError( ERROR_CAN_NOT_COMPLETE );
         return FALSE;
     }
-    if (!(path = PATH_FlattenPath( &dc->path ))) return FALSE;
-    PATH_AssignGdiPath( &dc->path, path );
-    free_gdi_path( path );
+    if (!(path = PATH_FlattenPath( dc->path ))) return FALSE;
+    free_gdi_path( dc->path );
+    dc->path = path;
     return TRUE;
 }
 
@@ -2225,14 +2222,14 @@
     DC *dc = get_nulldrv_dc( dev );
     struct gdi_path *path;
 
-    if (dc->path.state != PATH_Closed)
+    if (!dc->path || dc->path->state != PATH_Closed)
     {
         SetLastError( ERROR_CAN_NOT_COMPLETE );
         return FALSE;
     }
     if (!(path = PATH_WidenPath( dc ))) return FALSE;
-    PATH_AssignGdiPath( &dc->path, path );
-    free_gdi_path( path );
+    free_gdi_path( dc->path );
+    dc->path = path;
     return TRUE;
 }