[GDI32] Update Wine Metafile Code
authorJames Tabor <james.tabor@reactos.org>
Mon, 27 Sep 2021 21:18:20 +0000 (16:18 -0500)
committerJames Tabor <james.tabor@reactos.org>
Mon, 27 Sep 2021 21:18:20 +0000 (16:18 -0500)
Sync/Port: Metafile code from wine.

Patches by Jacek Caban, Daniel Lehman, Zhiyi Zhang. Gabriel Ivancescu, Michael Stefaniuc, Francois Gouget, Nikolay Sivov Dmitry Timoshkov, Andrew EiKum, Piotr Caban and Alexandre Julliard.

This commit is dedicated to George Bisoc!

25 files changed:
sdk/include/psdk/wingdi.h
win32ss/gdi/gdi32/include/gdi32p.h
win32ss/gdi/gdi32/misc/misc.c
win32ss/gdi/gdi32/objects/arc.c
win32ss/gdi/gdi32/objects/bitmap.c
win32ss/gdi/gdi32/objects/coord.c
win32ss/gdi/gdi32/objects/dc.c
win32ss/gdi/gdi32/objects/enhmfile.c
win32ss/gdi/gdi32/objects/gdiobj.c
win32ss/gdi/gdi32/objects/metafile.c
win32ss/gdi/gdi32/objects/painting.c
win32ss/gdi/gdi32/objects/palette.c
win32ss/gdi/gdi32/objects/path.c
win32ss/gdi/gdi32/objects/region.c
win32ss/gdi/gdi32/objects/text.c
win32ss/gdi/gdi32/wine/CMakeLists.txt
win32ss/gdi/gdi32/wine/emfdc.c [new file with mode: 0644]
win32ss/gdi/gdi32/wine/emfdrv.c [new file with mode: 0644]
win32ss/gdi/gdi32/wine/enhmetafile.c
win32ss/gdi/gdi32/wine/gdi_private.h
win32ss/gdi/gdi32/wine/metadc.c [new file with mode: 0644]
win32ss/gdi/gdi32/wine/metafile.c
win32ss/gdi/gdi32/wine/rosglue.c
win32ss/include/ntgdihdl.h
win32ss/include/ntuser.h

index 3cbfb75..00a0bf8 100644 (file)
@@ -215,6 +215,7 @@ extern "C" {
 #define META_SETPOLYFILLMODE   0x106
 #define META_SETSTRETCHBLTMODE 0x107
 #define META_SETTEXTCHAREXTRA  0x108
+#define META_SETLAYOUT          0x149
 #define META_SETTEXTCOLOR      0x209
 #define META_SETTEXTJUSTIFICATION      0x20A
 #define META_SETWINDOWORG      0x20B
index a9eb00b..b5f29b7 100644 (file)
@@ -563,21 +563,14 @@ extern ULONG gcClientObj;
 
 VOID
 WINAPI
-METADC_DeleteObject(HGDIOBJ hobj);
+METADC_RosGlueDeleteObject(HGDIOBJ hobj);
 
 BOOL
 WINAPI
-METADC_DeleteDC(
+METADC_RosGlueDeleteDC(
     _In_ HDC hdc);
 
-INT
-WINAPI
-METADC16_Escape(
-    _In_ HDC hdc,
-    _In_ INT nEscape,
-    _In_ INT cbInput,
-    _In_ LPCSTR lpvInData,
-    _Out_ LPVOID lpvOutData);
+BOOL METADC_DeleteDC( HDC hdc );
 
 BOOL
 WINAPI
@@ -591,155 +584,323 @@ METADC_ExtTextOutW(
     UINT cchString,
     const INT *lpDx);
 
-BOOL
-WINAPI
-METADC_PatBlt(
-    _In_ HDC hdc,
-    _In_ INT xLeft,
-    _In_ INT yTop,
-    _In_ INT nWidth,
-    _In_ INT nHeight,
-    _In_ DWORD dwRop);
-
 
 /* The following METADC_* functions follow this pattern: */
-#define HANDLE_METADC0P(_RetType, _Func, dwError, hdc, ...) \
+#define HANDLE_METADC(_RetType, _Func, dwError, hdc, ...) \
     if (GDI_HANDLE_GET_TYPE(hdc) != GDILoObjType_LO_DC_TYPE) \
     { \
-        DWORD_PTR dwResult; \
-        if (METADC_Dispatch(DCFUNC_##_Func, &dwResult, (DWORD_PTR)dwError, hdc)) \
+        if (GDI_HANDLE_GET_TYPE(hdc) == GDILoObjType_LO_METADC16_TYPE) \
+        { \
+           return (_RetType)METADC_##_Func(hdc, __VA_ARGS__); \
+        } \
+        else \
         { \
-            return (_RetType)dwResult; \
+           PLDC pLDC = GdiGetLDC(hdc); \
+           _RetType _Ret = dwError; \
+           if ( !pLDC ) \
+           { \
+              SetLastError(ERROR_INVALID_HANDLE); \
+              return (_RetType)_Ret; \
+           } \
+           if ( pLDC->iType == LDC_EMFLDC && !(_Ret = (_RetType)EMFDC_##_Func(pLDC, __VA_ARGS__)) ) \
+           { \
+              return (_RetType)_Ret; \
+           } \
+           /*  Fall through to support information DC's.*/ \
         } \
     }
 
-#define HANDLE_METADC(_RetType, _Func, dwError, hdc, ...) \
+#define HANDLE_METADC16(_RetType, _Func, dwError, hdc, ...) \
     if (GDI_HANDLE_GET_TYPE(hdc) != GDILoObjType_LO_DC_TYPE) \
     { \
-        DWORD_PTR dwResult = 1; \
-        if (METADC_Dispatch(DCFUNC_##_Func, &dwResult, (DWORD_PTR)dwError, hdc, __VA_ARGS__)) \
+        if (GDI_HANDLE_GET_TYPE(hdc) == GDILoObjType_LO_METADC16_TYPE) \
         { \
-            return (_RetType)dwResult; \
+           return METADC_##_Func(hdc, __VA_ARGS__); \
         } \
     }
 
+#define HANDLE_METADC0P(_RetType, _Func, dwError, hdc, ...) \
+    if (GDI_HANDLE_GET_TYPE(hdc) != GDILoObjType_LO_DC_TYPE) \
+    { \
+       PLDC pLDC = NULL; \
+       _RetType _Ret = dwError; \
+       if (GDI_HANDLE_GET_TYPE(hdc) == GDILoObjType_LO_METADC16_TYPE) \
+       { \
+          return (_RetType)_Ret; \
+       } \
+       pLDC = GdiGetLDC(hdc); \
+       if ( !pLDC ) \
+       { \
+          SetLastError(ERROR_INVALID_HANDLE); \
+          return (_RetType)_Ret; \
+       } \
+       if ( pLDC->iType == LDC_EMFLDC && !(_Ret = (_RetType)EMFDC_##_Func(pLDC)) ) \
+       { \
+          return (_RetType)_Ret; \
+       } \
+       /*  Fall through to support information DC's.*/ \
+    }
 
-typedef enum _DCFUNC
-{
-    //DCFUNC_AbortDoc,
-    DCFUNC_AbortPath,
-    DCFUNC_AlphaBlend, // UNIMPLEMENTED
-    DCFUNC_AngleArc, // UNIMPLEMENTED
-    DCFUNC_Arc,
-    DCFUNC_ArcTo, // UNIMPLEMENTED
-    DCFUNC_BeginPath,
-    //DCFUNC_BitBlt,
-    DCFUNC_Chord,
-    DCFUNC_CloseFigure,
-    DCFUNC_Ellipse,
-    DCFUNC_EndPath,
-    DCFUNC_ExcludeClipRect,
-    DCFUNC_ExtEscape,
-    DCFUNC_ExtFloodFill,
-    DCFUNC_ExtSelectClipRgn,
-    DCFUNC_ExtTextOut,
-    DCFUNC_FillPath,
-    DCFUNC_FillRgn,
-    DCFUNC_FlattenPath,
-    DCFUNC_FrameRgn,
-    DCFUNC_GetDeviceCaps,
-    DCFUNC_GdiComment,
-    DCFUNC_GradientFill, // UNIMPLEMENTED
-    DCFUNC_IntersectClipRect,
-    DCFUNC_InvertRgn,
-    DCFUNC_LineTo,
-    DCFUNC_MaskBlt, // UNIMPLEMENTED
-    DCFUNC_ModifyWorldTransform,
-    DCFUNC_MoveTo,
-    DCFUNC_OffsetClipRgn,
-    DCFUNC_OffsetViewportOrgEx,
-    DCFUNC_OffsetWindowOrgEx,
-    DCFUNC_PathToRegion, // UNIMPLEMENTED
-    DCFUNC_PatBlt,
-    DCFUNC_Pie,
-    DCFUNC_PlgBlt, // UNIMPLEMENTED
-    DCFUNC_PolyBezier,
-    DCFUNC_PolyBezierTo,
-    DCFUNC_PolyDraw,
-    DCFUNC_Polygon,
-    DCFUNC_Polyline,
-    DCFUNC_PolylineTo,
-    DCFUNC_PolyPolygon,
-    DCFUNC_PolyPolyline,
-    DCFUNC_RealizePalette,
-    DCFUNC_Rectangle,
-    DCFUNC_RestoreDC,
-    DCFUNC_RoundRect,
-    DCFUNC_SaveDC,
-    DCFUNC_ScaleViewportExtEx,
-    DCFUNC_ScaleWindowExtEx,
-    DCFUNC_SelectBrush,
-    DCFUNC_SelectClipPath,
-    DCFUNC_SelectFont,
-    DCFUNC_SelectPalette,
-    DCFUNC_SelectPen,
-    DCFUNC_SetDCBrushColor,
-    DCFUNC_SetDCPenColor,
-    DCFUNC_SetDIBitsToDevice,
-    DCFUNC_SetBkColor,
-    DCFUNC_SetBkMode,
-    DCFUNC_SetLayout,
-    //DCFUNC_SetMapMode,
-    DCFUNC_SetPixel,
-    DCFUNC_SetPolyFillMode,
-    DCFUNC_SetROP2,
-    DCFUNC_SetStretchBltMode,
-    DCFUNC_SetTextAlign,
-    DCFUNC_SetTextCharacterExtra,
-    DCFUNC_SetTextColor,
-    DCFUNC_SetTextJustification,
-    DCFUNC_SetViewportExtEx,
-    DCFUNC_SetViewportOrgEx,
-    DCFUNC_SetWindowExtEx,
-    DCFUNC_SetWindowOrgEx,
-    DCFUNC_SetWorldTransform,
-    DCFUNC_StretchBlt,
-    DCFUNC_StrokeAndFillPath,
-    DCFUNC_StrokePath,
-    DCFUNC_TransparentBlt, // UNIMPLEMENTED
-    DCFUNC_WidenPath,
-
-} DCFUNC;
-
-BOOL
-METADC_Dispatch(
-    _In_ DCFUNC eFunction,
-    _Out_ PDWORD_PTR pdwResult,
-    _In_ DWORD_PTR dwError,
-    _In_ HDC hdc,
-    ...);
+#define HANDLE_EMETAFDC(_RetType, _Func, dwError, hdc, ...) \
+    if (GDI_HANDLE_GET_TYPE(hdc) != GDILoObjType_LO_DC_TYPE) \
+    { \
+       PLDC pLDC = NULL; \
+       _RetType _Ret = dwError; \
+       if (GDI_HANDLE_GET_TYPE(hdc) == GDILoObjType_LO_METADC16_TYPE) \
+       { \
+          return (_RetType)_Ret; \
+       } \
+       pLDC = GdiGetLDC(hdc); \
+       if ( !pLDC ) \
+       { \
+          SetLastError(ERROR_INVALID_HANDLE); \
+          return (_RetType)_Ret; \
+       } \
+       if ( pLDC->iType == LDC_EMFLDC && !(_Ret = EMFDC_##_Func(pLDC, __VA_ARGS__)) ) \
+       { \
+          return (_RetType)_Ret; \
+       } \
+       /*  Fall through to support information DC's.*/ \
+    }
 
-#define HANDLE_METADC2(_RetType, _Func, hdc, ...) \
+#define HANDLE_METADC1P(_RetType, _Func, dwError, hdc, ...) \
     if (GDI_HANDLE_GET_TYPE(hdc) != GDILoObjType_LO_DC_TYPE) \
     { \
-        _RetType result; \
-        if (METADC_##_Func(&result, hdc, __VA_ARGS__)) \
+        if (GDI_HANDLE_GET_TYPE(hdc) == GDILoObjType_LO_METADC16_TYPE) \
         { \
-            return result; \
+           return (_RetType)METADC_##_Func(hdc); \
+        } \
+        else \
+        { \
+           PLDC pLDC = GdiGetLDC(hdc); \
+           _RetType _Ret = dwError; \
+           if ( !pLDC ) \
+           { \
+              SetLastError(ERROR_INVALID_HANDLE); \
+              return (_RetType)_Ret; \
+           } \
+           if ( pLDC->iType == LDC_EMFLDC && !(_Ret = (_RetType)EMFDC_##_Func(pLDC)) ) \
+           { \
+              return (_RetType)_Ret; \
+           } \
+           /*  Fall through to support information DC's.*/ \
         } \
     }
 
-BOOL
-WINAPI
-METADC_GetAndSetDCDWord(
-    _Out_ PDWORD pdwResult,
-    _In_ HDC hdc,
-    _In_ UINT u,
-    _In_ DWORD dwIn,
-    _In_ ULONG ulMFId,
-    _In_ USHORT usMF16Id,
-    _In_ DWORD dwError);
+
+BOOL WINAPI METADC_SetD(_In_ HDC hdc,_In_ DWORD dwIn,_In_ USHORT usMF16Id);
+BOOL WINAPI EMFDC_SetD(_In_ PLDC pldc,_In_ DWORD dwIn,_In_ ULONG ulMFId);
 
 HDC WINAPI GdiConvertAndCheckDC(HDC hdc);
 
+HENHMETAFILE WINAPI SetEnhMetaFileBitsAlt( PDWORD pdw, LPWSTR FilePart, HANDLE hFile, LARGE_INTEGER li);
+
+/* meta dc files */
+extern BOOL METADC_Arc( HDC hdc, INT left, INT top, INT right, INT bottom,
+                        INT xstart, INT ystart, INT xend, INT yend ) DECLSPEC_HIDDEN;
+extern BOOL METADC_BitBlt( HDC hdc_dst, INT x_dst, INT y_dst, INT width, INT height,
+                           HDC hdc_src, INT x_src, INT y_src, DWORD rop );
+extern BOOL METADC_Chord( HDC hdc, INT left, INT top, INT right, INT bottom, INT xstart,
+                          INT ystart, INT xend, INT yend ) DECLSPEC_HIDDEN;
+extern BOOL METADC_Ellipse( HDC hdc, INT left, INT top, INT right, INT bottom ) DECLSPEC_HIDDEN;
+extern BOOL METADC_ExcludeClipRect( HDC hdc, INT left, INT top, INT right,
+                                    INT bottom ) DECLSPEC_HIDDEN;
+extern BOOL METADC_ExtEscape( HDC hdc, INT escape, INT input_size, LPCSTR input, INT output_size, LPVOID output ) DECLSPEC_HIDDEN;
+extern BOOL METADC_ExtFloodFill( HDC hdc, INT x, INT y, COLORREF color,
+                                 UINT fill_type ) DECLSPEC_HIDDEN;
+extern BOOL METADC_ExtSelectClipRgn( HDC hdc, HRGN hrgn, INT mode ) DECLSPEC_HIDDEN;
+extern BOOL METADC_ExtTextOut( HDC hdc, INT x, INT y, UINT flags, const RECT *rect,
+                               const WCHAR *str, UINT count, const INT *dx ) DECLSPEC_HIDDEN;
+extern BOOL METADC_FillRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush ) DECLSPEC_HIDDEN;
+extern BOOL METADC_FrameRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush, INT x, INT y ) DECLSPEC_HIDDEN;
+extern INT  METADC_GetDeviceCaps( HDC hdc, INT cap );
+extern BOOL METADC_IntersectClipRect( HDC hdc, INT left, INT top, INT right,
+                                      INT bottom ) DECLSPEC_HIDDEN;
+extern BOOL METADC_InvertRgn( HDC hdc, HRGN hrgn ) DECLSPEC_HIDDEN;
+extern BOOL METADC_LineTo( HDC hdc, INT x, INT y ) DECLSPEC_HIDDEN;
+extern BOOL METADC_MoveTo( HDC hdc, INT x, INT y ) DECLSPEC_HIDDEN;
+extern BOOL METADC_OffsetClipRgn( HDC hdc, INT x, INT y ) DECLSPEC_HIDDEN;
+extern BOOL METADC_OffsetViewportOrgEx( HDC hdc, INT x, INT y ) DECLSPEC_HIDDEN;
+extern BOOL METADC_OffsetWindowOrgEx( HDC hdc, INT x, INT y ) DECLSPEC_HIDDEN;
+extern BOOL METADC_PaintRgn( HDC hdc, HRGN hrgn ) DECLSPEC_HIDDEN;
+extern BOOL METADC_PatBlt( HDC hdc, INT left, INT top, INT width, INT height, DWORD rop );
+extern BOOL METADC_Pie( HDC hdc, INT left, INT top, INT right, INT bottom,
+                        INT xstart, INT ystart, INT xend, INT yend ) DECLSPEC_HIDDEN;
+extern BOOL METADC_PolyPolygon( HDC hdc, const POINT *points, const INT *counts,
+                                UINT polygons ) DECLSPEC_HIDDEN;
+extern BOOL METADC_Polygon( HDC hdc, const POINT *points, INT count ) DECLSPEC_HIDDEN;
+extern BOOL METADC_Polyline( HDC hdc, const POINT *points,INT count) DECLSPEC_HIDDEN;
+extern BOOL METADC_RealizePalette( HDC hdc ) DECLSPEC_HIDDEN;
+extern BOOL METADC_Rectangle( HDC hdc, INT left, INT top, INT right, INT bottom) DECLSPEC_HIDDEN;
+extern BOOL METADC_RestoreDC( HDC hdc, INT level ) DECLSPEC_HIDDEN;
+extern BOOL METADC_RoundRect( HDC hdc, INT left, INT top, INT right, INT bottom,
+                              INT ell_width, INT ell_height ) DECLSPEC_HIDDEN;
+extern BOOL METADC_SaveDC( HDC hdc ) DECLSPEC_HIDDEN;
+extern BOOL METADC_ScaleViewportExtEx( HDC hdc, INT x_num, INT x_denom, INT y_num,
+                                       INT y_denom ) DECLSPEC_HIDDEN;
+extern BOOL METADC_ScaleWindowExtEx( HDC hdc, INT x_num, INT x_denom, INT y_num,
+                                     INT y_denom ) DECLSPEC_HIDDEN;
+extern HGDIOBJ METADC_SelectObject( HDC hdc, HGDIOBJ obj ) DECLSPEC_HIDDEN;
+extern BOOL METADC_SelectPalette( HDC hdc, HPALETTE palette ) DECLSPEC_HIDDEN;
+extern BOOL METADC_SetBkColor( HDC hdc, COLORREF color ) DECLSPEC_HIDDEN;
+extern BOOL METADC_SetBkMode( HDC hdc, INT mode ) DECLSPEC_HIDDEN;
+extern INT  METADC_SetDIBitsToDevice( HDC hdc, INT x_dest, INT y_dest, DWORD width, DWORD height,
+                                      INT x_src, INT y_src, UINT startscan, UINT lines,
+                                      const void *bits, const BITMAPINFO *info,
+                                      UINT coloruse ) DECLSPEC_HIDDEN;
+extern BOOL METADC_SetLayout( HDC hdc, DWORD layout ) DECLSPEC_HIDDEN;
+extern BOOL METADC_SetTextCharacterExtra( HDC hdc, INT extra ) DECLSPEC_HIDDEN;
+extern BOOL METADC_SetMapMode( HDC hdc, INT mode ) DECLSPEC_HIDDEN;
+extern BOOL METADC_SetMapperFlags( HDC hdc, DWORD flags ) DECLSPEC_HIDDEN;
+extern BOOL METADC_SetPixel( HDC hdc, INT x, INT y, COLORREF color ) DECLSPEC_HIDDEN;
+extern BOOL METADC_SetPolyFillMode( HDC hdc, INT mode ) DECLSPEC_HIDDEN;
+extern BOOL METADC_SetRelAbs( HDC hdc, INT mode ) DECLSPEC_HIDDEN;
+extern BOOL METADC_SetROP2( HDC hdc, INT rop ) DECLSPEC_HIDDEN;
+extern BOOL METADC_SetStretchBltMode( HDC hdc, INT mode ) DECLSPEC_HIDDEN;
+extern BOOL METADC_SetTextAlign( HDC hdc, UINT align ) DECLSPEC_HIDDEN;
+extern BOOL METADC_SetTextColor( HDC hdc, COLORREF color ) DECLSPEC_HIDDEN;
+extern BOOL METADC_SetTextJustification( HDC hdc, INT extra, INT breaks ) DECLSPEC_HIDDEN;
+extern BOOL METADC_SetViewportExtEx( HDC hdc, INT x, INT y ) DECLSPEC_HIDDEN;
+extern BOOL METADC_SetViewportOrgEx( HDC hdc, INT x, INT y ) DECLSPEC_HIDDEN;
+extern BOOL METADC_SetWindowExtEx( HDC hdc, INT x, INT y ) DECLSPEC_HIDDEN;
+extern BOOL METADC_SetWindowOrgEx( HDC, INT x, INT y ) DECLSPEC_HIDDEN;
+extern BOOL METADC_StretchBlt( HDC hdc_dst, INT x_dst, INT y_dst, INT width_dst, INT height_dst,
+                               HDC hdc_src, INT x_src, INT y_src, INT width_src, INT height_src,
+                               DWORD rop );
+extern INT  METADC_StretchDIBits( HDC hdc, INT x_dst, INT y_dst, INT width_dst, INT height_dst,
+                                  INT x_src, INT y_src, INT width_src, INT height_src,
+                                  const void *bits, const BITMAPINFO *info, UINT coloruse,
+                                  DWORD rop ) DECLSPEC_HIDDEN;
+/* enhanced metafiles */
+extern BOOL EMFDC_AbortPath( LDC *dc_attr ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_AlphaBlend( LDC *dc_attr, INT x_dst, INT y_dst, INT width_dst, INT height_dst,
+                              HDC hdc_src, INT x_src, INT y_src, INT width_src, INT height_src,
+                              BLENDFUNCTION blend_function );
+extern BOOL EMFDC_AngleArc( LDC *dc_attr, INT x, INT y, DWORD radius, FLOAT start,
+                            FLOAT sweep ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_ArcChordPie( LDC *dc_attr, INT left, INT top, INT right,
+                               INT bottom, INT xstart, INT ystart, INT xend,
+                               INT yend, DWORD type ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_BeginPath( LDC *dc_attr ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_BitBlt( LDC *dc_attr, INT x_dst, INT y_dst, INT width, INT height,
+                          HDC hdc_src, INT x_src, INT y_src, DWORD rop );
+extern BOOL EMFDC_CloseFigure( LDC *dc_attr ) DECLSPEC_HIDDEN;
+extern void EMFDC_DeleteDC( LDC *dc_attr ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_Ellipse( LDC *dc_attr, INT left, INT top, INT right,
+                           INT bottom ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_EndPath( LDC *dc_attr ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_ExcludeClipRect( LDC *dc_attr, INT left, INT top, INT right,
+                                   INT bottom ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_ExtFloodFill( LDC *dc_attr, INT x, INT y, COLORREF color,
+                                UINT fill_type ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_ExtSelectClipRgn( LDC *dc_attr, HRGN hrgn, INT mode ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_ExtTextOut( LDC *dc_attr, INT x, INT y, UINT flags, const RECT *rect,
+                              const WCHAR *str, UINT count, const INT *dx ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_FillPath( LDC *dc_attr ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_FillRgn( LDC *dc_attr, HRGN hrgn, HBRUSH hbrush ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_FlattenPath( LDC *dc_attr ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_FrameRgn( LDC *dc_attr, HRGN hrgn, HBRUSH hbrush, INT width,
+                            INT height ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_GradientFill( LDC *dc_attr, TRIVERTEX *vert_array, ULONG nvert,
+                                void *grad_array, ULONG ngrad, ULONG mode ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_IntersectClipRect( LDC *dc_attr, INT left, INT top, INT right,
+                                     INT bottom ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_InvertRgn( LDC *dc_attr, HRGN hrgn ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_LineTo( LDC *dc_attr, INT x, INT y ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_ModifyWorldTransform( LDC *dc_attr, const XFORM *xform,
+                                        DWORD mode ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_MoveTo( LDC *dc_attr, INT x, INT y ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_OffsetClipRgn( LDC *dc_attr, INT x, INT y ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_PaintRgn( LDC *dc_attr, HRGN hrgn ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_PatBlt( LDC *dc_attr, INT left, INT top, INT width, INT height, DWORD rop );
+extern BOOL EMFDC_PolyBezier( LDC *dc_attr, const POINT *points, DWORD count ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_PolyBezierTo( LDC *dc_attr, const POINT *points, DWORD count ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_PolyDraw( LDC *dc_attr, const POINT *points, const BYTE *types,
+                            DWORD count ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_PolyPolyline( LDC *dc_attr, const POINT *points, const DWORD *counts,
+                                DWORD polys ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_PolyPolygon( LDC *dc_attr, const POINT *points, const INT *counts,
+                               UINT polys ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_Polygon( LDC *dc_attr, const POINT *points, INT count ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_Polyline( LDC *dc_attr, const POINT *points, INT count) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_PolylineTo( LDC *dc_attr, const POINT *points, INT count ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_Rectangle( LDC *dc_attr, INT left, INT top, INT right,
+                             INT bottom) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_RestoreDC( LDC *dc_attr, INT level ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_RoundRect( LDC *dc_attr, INT left, INT top, INT right, INT bottom,
+                             INT ell_width, INT ell_height ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_SaveDC( LDC *dc_attr ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_ScaleViewportExtEx( LDC *dc_attr, INT x_num, INT x_denom, INT y_num,
+                                      INT y_denom ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_ScaleWindowExtEx( LDC *dc_attr, INT x_num, INT x_denom, INT y_num,
+                                    INT y_denom ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_SelectClipPath( LDC *dc_attr, INT mode ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_SelectObject( LDC *dc_attr, HGDIOBJ obj ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_SelectPalette( LDC *dc_attr, HPALETTE palette ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_SetArcDirection( LDC *dc_attr, INT dir ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_SetBkColor( LDC *dc_attr, COLORREF color ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_SetBkMode( LDC *dc_attr, INT mode ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_SetDCBrushColor( LDC *dc_attr, COLORREF color ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_SetDCPenColor( LDC *dc_attr, COLORREF color ) DECLSPEC_HIDDEN;
+extern INT  EMFDC_SetDIBitsToDevice( LDC *dc_attr, INT x_dest, INT y_dest, DWORD width,
+                                     DWORD height, INT x_src, INT y_src, UINT startscan,
+                                     UINT lines, const void *bits, const BITMAPINFO *info,
+                                     UINT coloruse ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_SetLayout( LDC *dc_attr, DWORD layout ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_SetMapMode( LDC *dc_attr, INT mode ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_SetMapperFlags( LDC *dc_attr, DWORD flags ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_SetPixel( LDC *dc_attr, INT x, INT y, COLORREF color ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_SetPolyFillMode( LDC *dc_attr, INT mode ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_SetROP2( LDC *dc_attr, INT rop ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_SetStretchBltMode( LDC *dc_attr, INT mode ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_SetTextAlign( LDC *dc_attr, UINT align ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_SetTextColor( LDC *dc_attr, COLORREF color ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_SetTextJustification( LDC *dc_attr, INT extra, INT breaks ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_SetViewportExtEx( LDC *dc_attr, INT x, INT y ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_SetViewportOrgEx( LDC *dc_attr, INT x, INT y ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_SetWindowExtEx( LDC *dc_attr, INT x, INT y ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_SetWindowOrgEx( LDC *dc_attr, INT x, INT y ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_SetWorldTransform( LDC *dc_attr, const XFORM *xform ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_StretchBlt( LDC *dc_attr, INT x_dst, INT y_dst, INT width_dst, INT height_dst,
+                              HDC hdc_src, INT x_src, INT y_src, INT width_src, INT height_src,
+                              DWORD rop );
+extern BOOL EMFDC_StretchDIBits( LDC *dc_attr, INT x_dst, INT y_dst, INT width_dst,
+                                 INT height_dst, INT x_src, INT y_src, INT width_src,
+                                 INT height_src, const void *bits, const BITMAPINFO *info,
+                                 UINT coloruse, DWORD rop ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_StrokeAndFillPath( LDC *dc_attr ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_StrokePath( LDC *dc_attr ) DECLSPEC_HIDDEN;
+extern BOOL EMFDC_WidenPath( LDC *dc_attr ) DECLSPEC_HIDDEN;
+
+
+BOOL EMFDC_MaskBlt( LDC *dc_attr, INT xDest, INT yDest, INT cx, INT cy, HDC hdcSrc, INT xSrc, INT ySrc, HBITMAP hbmMask, INT xMask, INT yMask, DWORD dwRop);
+BOOL EMFDC_PlgBlt( LDC *dc_attr, const POINT * ppt, HDC hdcSrc, INT xSrc, INT ySrc, INT cx, INT cy, HBITMAP hbmMask, INT xMask, INT yMask);
+BOOL EMFDC_TransparentBlt( LDC *dc_attr, INT xDst, INT yDst, INT cxDst, INT cyDst, HDC hdcSrc, INT xSrc, INT ySrc, INT cxSrc, INT cySrc, UINT crTransparent);
+BOOL EMFDC_SetBrushOrg( LDC *dc_attr, INT x, INT y);
+BOOL EMFDC_SetMetaRgn( LDC *dc_attr );
+INT EMFDC_WriteNamedEscape( LDC *dc_attr, PWCHAR pDriver, INT nEscape, INT cbInput, LPCSTR lpszInData);
+INT EMFDC_WriteEscape( LDC *dc_attr, INT nEscape, INT cbInput, LPSTR lpszInData, DWORD emrType);
+
+
+FORCEINLINE BOOL EMFDC_Arc( PLDC dc_attr, INT left, INT top, INT right, INT bottom, INT xstart, INT ystart, INT xend, INT yend )
+{
+    return EMFDC_ArcChordPie( dc_attr, left, top, right, bottom, xstart, ystart, xend, yend, EMR_ARC );
+}
+
+FORCEINLINE BOOL EMFDC_ArcTo( PLDC dc_attr, INT left, INT top, INT right, INT bottom, INT xstart, INT ystart, INT xend, INT yend )
+{
+return EMFDC_ArcChordPie( dc_attr, left, top, right, bottom, xstart, ystart, xend, yend, EMR_ARCTO );
+}
+FORCEINLINE BOOL EMFDC_Chord( PLDC dc_attr, INT left, INT top, INT right, INT bottom, INT xstart, INT ystart, INT xend, INT yend )
+{
+return EMFDC_ArcChordPie( dc_attr, left, top, right, bottom, xstart, ystart, xend, yend, EMR_CHORD );
+}
+
+FORCEINLINE BOOL EMFDC_Pie( PLDC dc_attr, INT left, INT top, INT right, INT bottom, INT xstart, INT ystart, INT xend, INT yend )
+{
+return EMFDC_ArcChordPie( dc_attr, left, top, right, bottom, xstart, ystart, xend, yend, EMR_PIE );
+}
+
+BOOL WINAPI EMFDC_GdiComment( HDC hdc, UINT bytes, const BYTE *buffer );
+
 /* EOF */
index d977d6c..f753e9b 100644 (file)
@@ -66,7 +66,7 @@ Escape(
 
     if (ulObjType == GDILoObjType_LO_METADC16_TYPE)
     {
-        return METADC16_Escape(hdc, nEscape, cbInput, lpvInData, lpvOutData);
+        return METADC_ExtEscape(hdc, nEscape, cbInput, lpvInData, 0, lpvOutData);
     }
 
     switch (nEscape)
index 444b05a..f689b05 100644 (file)
@@ -54,15 +54,15 @@ AngleArc(
     _In_ FLOAT eStartAngle,
     _In_ FLOAT eSweepAngle)
 {
-    HANDLE_METADC(BOOL,
+    HANDLE_EMETAFDC(BOOL,
                   AngleArc,
                   FALSE,
                   hdc,
                   x,
                   y,
                   dwRadius,
-                  RCAST(DWORD, eStartAngle),
-                  RCAST(DWORD, eSweepAngle));
+                  eStartAngle,
+                  eSweepAngle);
 
     if ( GdiConvertAndCheckDC(hdc) == NULL ) return FALSE;
 
@@ -87,7 +87,7 @@ ArcTo(
     _In_ INT xRadial2,
     _In_ INT yRadial2)
 {
-    HANDLE_METADC(BOOL,
+    HANDLE_EMETAFDC(BOOL,
                   ArcTo,
                   FALSE,
                   hdc,
index f290b54..438521f 100644 (file)
@@ -811,7 +811,7 @@ StretchDIBits(
     BOOL Hit = FALSE;
 
     DPRINT("StretchDIBits %p : %p : %u\n", lpBits, lpBitsInfo, iUsage);
-#if 0
+
     HANDLE_METADC( int,
                    StretchDIBits,
                    0,
@@ -828,11 +828,10 @@ StretchDIBits(
                    lpBitsInfo,
                    iUsage,
                    dwRop );
-#endif
+
     if ( GdiConvertAndCheckDC(hdc) == NULL ) return 0;
 
-    pConvertedInfo = ConvertBitmapInfo(lpBitsInfo, iUsage, &ConvertedInfoSize,
-        FALSE);
+    pConvertedInfo = ConvertBitmapInfo(lpBitsInfo, iUsage, &ConvertedInfoSize, FALSE);
     if (!pConvertedInfo)
     {
         return 0;
@@ -878,10 +877,22 @@ StretchDIBits(
      (pConvertedInfo->bmiHeader.biCompression == BI_JPEG ||
      pConvertedInfo->bmiHeader.biCompression  == BI_PNG )) )*/
     {
-        LinesCopied = NtGdiStretchDIBitsInternal(hdc, XDest, YDest, nDestWidth, nDestHeight, XSrc,
-            YSrc, nSrcWidth, nSrcHeight, pvSafeBits, pConvertedInfo, (DWORD) iUsage, dwRop,
-            ConvertedInfoSize, cjBmpScanSize,
-            NULL);
+        LinesCopied = NtGdiStretchDIBitsInternal( hdc,
+                                                  XDest,
+                                                  YDest,
+                                                  nDestWidth,
+                                                  nDestHeight,
+                                                  XSrc,
+                                                  YSrc,
+                                                  nSrcWidth,
+                                                  nSrcHeight,
+                                                  pvSafeBits,
+                                                  pConvertedInfo,
+                                                  (DWORD) iUsage,
+                                                  dwRop,
+                                                  ConvertedInfoSize,
+                                                  cjBmpScanSize,
+                                                  NULL );
     }
     if (pvSafeBits)
         RtlFreeHeap(RtlGetProcessHeap(), 0, pvSafeBits);
index b27711c..49c16bf 100644 (file)
@@ -142,7 +142,7 @@ SetMapMode(
     /* Handle METADC16 here, since we don't have a DCATTR. */
     if (GDI_HANDLE_GET_TYPE(hdc) == GDILoObjType_LO_METADC16_TYPE) \
     {
-        return GetAndSetDCDWord(hdc, GdiGetSetMapMode, iMode, 0, 0, 0 );
+        return METADC_SetMapMode(hdc, iMode);
     }
 
     /* Get the DC attribute */
@@ -157,7 +157,7 @@ SetMapMode(
     if ((iMode != pdcattr->iMapMode) || (iMode == MM_ISOTROPIC))
     {
         pdcattr->ulDirty_ &= ~SLOW_WIDTHS;
-        return GetAndSetDCDWord(hdc, GdiGetSetMapMode, iMode, 0, 0, 0 );
+        return GetAndSetDCDWord(hdc, GdiGetSetMapMode, iMode, EMR_SETMAPMODE, 0, 0 );
     }
 
     return pdcattr->iMapMode;
@@ -323,11 +323,11 @@ ModifyWorldTransform(
 
     if (dwMode == MWT_SET)
     {
-       HANDLE_METADC(BOOL, SetWorldTransform, FALSE, hdc, pxform);
+       HANDLE_EMETAFDC(BOOL, SetWorldTransform, FALSE, hdc, pxform);
     }
     else
     {
-       HANDLE_METADC(BOOL, ModifyWorldTransform, FALSE, hdc, pxform, dwMode);
+       HANDLE_EMETAFDC(BOOL, ModifyWorldTransform, FALSE, hdc, pxform, dwMode);
     }
 
     /* Get the DC attribute */
@@ -470,7 +470,7 @@ SetViewportExtEx(
 {
     PDC_ATTR pdcattr;
 
-    HANDLE_METADC(BOOL, SetViewportExtEx, FALSE, hdc, nXExtent, nYExtent, lpSize);
+    HANDLE_METADC(BOOL, SetViewportExtEx, FALSE, hdc, nXExtent, nYExtent);
 
     /* Get the DC attribute */
     pdcattr = GdiGetDcAttr(hdc);
@@ -537,7 +537,7 @@ SetWindowOrgEx(
 {
     PDC_ATTR pdcattr;
 
-    HANDLE_METADC(BOOL, SetWindowOrgEx, FALSE, hdc, X, Y, lpPoint);
+    HANDLE_METADC(BOOL, SetWindowOrgEx, FALSE, hdc, X, Y);
 
     /* Get the DC attribute */
     pdcattr = GdiGetDcAttr(hdc);
@@ -589,7 +589,7 @@ SetWindowExtEx(
 {
     PDC_ATTR pdcattr;
 
-    HANDLE_METADC(BOOL, SetWindowExtEx, FALSE, hdc, nXExtent, nYExtent, lpSize);
+    HANDLE_METADC(BOOL, SetWindowExtEx, FALSE, hdc, nXExtent, nYExtent);
 
     /* Get the DC attr */
     pdcattr = GdiGetDcAttr(hdc);
@@ -660,7 +660,7 @@ SetViewportOrgEx(
 {
     PDC_ATTR pdcattr;
 
-    HANDLE_METADC(BOOL, SetViewportOrgEx, FALSE, hdc, X, Y, lpPoint);
+    HANDLE_METADC(BOOL, SetViewportOrgEx, FALSE, hdc, X, Y);
 
     /* Get the DC attribute */
     pdcattr = GdiGetDcAttr(hdc);
@@ -707,7 +707,7 @@ ScaleViewportExtEx(
     _In_ INT yDenom,
     _Out_ LPSIZE lpSize)
 {
-    HANDLE_METADC(BOOL, ScaleViewportExtEx, FALSE, hdc, xNum, xDenom, yNum, yDenom, lpSize);
+    HANDLE_METADC(BOOL, ScaleViewportExtEx, FALSE, hdc, xNum, xDenom, yNum, yDenom);
 
     if (!GdiGetDcAttr(hdc))
     {
@@ -731,7 +731,7 @@ ScaleWindowExtEx(
     _In_ INT yDenom,
     _Out_ LPSIZE lpSize)
 {
-    HANDLE_METADC(BOOL, ScaleWindowExtEx, FALSE, hdc, xNum, xDenom, yNum, yDenom, lpSize);
+    HANDLE_METADC(BOOL, ScaleWindowExtEx, FALSE, hdc, xNum, xDenom, yNum, yDenom);
 
     if (!GdiGetDcAttr(hdc))
     {
@@ -863,7 +863,7 @@ OffsetViewportOrgEx(
 {
     PDC_ATTR pdcattr;
 
-    HANDLE_METADC(BOOL, OffsetViewportOrgEx, FALSE, hdc, nXOffset, nYOffset, lpPoint);
+    HANDLE_METADC16(BOOL, OffsetViewportOrgEx, FALSE, hdc, nXOffset, nYOffset);
 
     /* Get the DC attribute */
     pdcattr = GdiGetDcAttr(hdc);
@@ -895,6 +895,9 @@ OffsetViewportOrgEx(
         pdcattr->ptlViewportOrg.x += nXOffset;
         pdcattr->ptlViewportOrg.y += nYOffset;
     }
+
+    HANDLE_EMETAFDC(BOOL, SetViewportOrgEx, FALSE, hdc, pdcattr->ptlViewportOrg.x, pdcattr->ptlViewportOrg.y);
+
     return TRUE;
 
 //    return  NtGdiOffsetViewportOrgEx(hdc, nXOffset, nYOffset, lpPoint);
@@ -914,7 +917,7 @@ OffsetWindowOrgEx(
 {
     PDC_ATTR pdcattr;
 
-    HANDLE_METADC(BOOL, OffsetWindowOrgEx, FALSE, hdc, nXOffset, nYOffset, lpPoint);
+    HANDLE_METADC16(BOOL, OffsetWindowOrgEx, FALSE, hdc, nXOffset, nYOffset);
 
     /* Get the DC attribute */
     pdcattr = GdiGetDcAttr(hdc);
@@ -946,6 +949,9 @@ OffsetWindowOrgEx(
         pdcattr->ptlWindowOrg.y += nYOffset;
         pdcattr->lWindowOrgx += nXOffset;
     }
+
+    HANDLE_EMETAFDC(BOOL, SetWindowOrgEx, FALSE, hdc, pdcattr->ptlWindowOrg.x, pdcattr->ptlWindowOrg.y);
+
     return TRUE;
 
 //    return NtGdiOffsetWindowOrgEx(hdc, nXOffset, nYOffset, lpPoint);
index 91df2a9..f929dfd 100644 (file)
@@ -281,47 +281,34 @@ BOOL
 WINAPI
 DeleteDC(HDC hdc)
 {
-    BOOL bResult = TRUE;
-    PLDC pLDC = NULL;
-    HANDLE hPrinter = NULL;
     ULONG hType = GDI_HANDLE_GET_TYPE(hdc);
 
-    pLDC = GdiGetLDC(hdc);
-
     if (hType != GDILoObjType_LO_DC_TYPE)
     {
-        return METADC_DeleteDC(hdc);
-    }
-
-    bResult = NtGdiDeleteObjectApp(hdc);
-
-    if (bResult && pLDC)
-    {
-        DPRINT1("Delete the Local DC structure\n");
-        LocalFree( pLDC );
+        return METADC_RosGlueDeleteDC(hdc);
     }
 
-    if (hPrinter)
-        fpClosePrinter(hPrinter);
+    //if ( ghICM || pdcattr->pvLIcm )
+    //    IcmDeleteLocalDC( hdc, pdcattr, NULL );
 
-    return bResult;
+    return NtGdiDeleteObjectApp(hdc);
 }
 
 
 /*
- * @unimplemented
+ * @implemented
  */
 INT
 WINAPI
 SaveDC(IN HDC hdc)
 {
-    HANDLE_METADC0P(INT, SaveDC, 0, hdc);
+    HANDLE_METADC1P(INT, SaveDC, 0, hdc);
     return NtGdiSaveDC(hdc);
 }
 
 
 /*
- * @unimplemented
+ * @implemented
  */
 BOOL
 WINAPI
@@ -381,7 +368,7 @@ SetArcDirection(
     _In_ HDC hdc,
     _In_ INT nDirection)
 {
-    return GetAndSetDCDWord(hdc, GdiGetSetArcDirection, nDirection, 0, 0, 0);
+    return GetAndSetDCDWord(hdc, GdiGetSetArcDirection, nDirection, EMR_SETARCDIRECTION, 0, 0);
 }
 
 /*
@@ -565,21 +552,43 @@ GetDeviceCaps(
     _In_ int nIndex)
 {
     PDC_ATTR pdcattr;
+    PLDC pldc;
+    ULONG hType = GDI_HANDLE_GET_TYPE(hdc);
     PDEVCAPS pDevCaps = GdiDevCaps; // Primary display device capabilities.
     DPRINT("Device CAPS1\n");
 
-    HANDLE_METADC(INT, GetDeviceCaps, 0, hdc, nIndex);
+    HANDLE_METADC16(INT, GetDeviceCaps, 0, hdc, nIndex);
 
-    /* Get the DC attribute */
-    pdcattr = GdiGetDcAttr(hdc);
-    if (pdcattr == NULL)
+    if ( hType != GDILoObjType_LO_DC_TYPE && hType != GDILoObjType_LO_METADC16_TYPE )
     {
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return 0;
+        pldc = GdiGetLDC(hdc);
+        if ( !pldc )
+        {
+            SetLastError(ERROR_INVALID_HANDLE);
+            return 0;
+        }
+        if (!(pldc->Flags & LDC_DEVCAPS) )
+        {
+            if (!NtGdiGetDeviceCapsAll(hdc, &pldc->DevCaps) )
+                SetLastError(ERROR_INVALID_PARAMETER);
+
+            pldc->Flags |= LDC_DEVCAPS;
+        }
+        pDevCaps = &pldc->DevCaps;
     }
+    else
+    {
+        /* Get the DC attribute */
+        pdcattr = GdiGetDcAttr(hdc);
+        if ( pdcattr == NULL )
+        {
+            SetLastError(ERROR_INVALID_PARAMETER);
+            return 0;
+        }
 
-    if (!(pdcattr->ulDirty_ & DC_PRIMARY_DISPLAY))
-        return NtGdiGetDeviceCaps(hdc, nIndex);
+        if (!(pdcattr->ulDirty_ & DC_PRIMARY_DISPLAY))
+            return NtGdiGetDeviceCaps(hdc, nIndex);
+    }
 
     switch (nIndex)
     {
@@ -725,7 +734,7 @@ SetRelAbs(
     HDC hdc,
     INT Mode)
 {
-    return GetAndSetDCDWord(hdc, GdiGetSetRelAbs, Mode, 0, 0, 0);
+    return GetAndSetDCDWord(hdc, GdiGetSetRelAbs, Mode, 0, META_SETRELABS, 0);
 }
 
 
@@ -743,9 +752,22 @@ GetAndSetDCDWord(
     _In_ DWORD dwError)
 {
     DWORD dwResult;
+    PLDC pldc;
 
-    /* This is a special API, handle it appropriately */
-    HANDLE_METADC2(DWORD, GetAndSetDCDWord, hdc, u, dwIn, ulMFId, usMF16Id, dwError);
+    if ( GDI_HANDLE_GET_TYPE(hdc) != GDILoObjType_LO_DC_TYPE &&
+         ulMFId != EMR_MAX + 1 )
+    {
+        if (GDI_HANDLE_GET_TYPE(hdc) == GDILoObjType_LO_METADC16_TYPE)
+        {
+            return METADC_SetD( hdc, dwIn, usMF16Id );
+        }
+        pldc = GdiGetLDC(hdc);
+        if ( pldc->iType == LDC_EMFLDC)
+        {
+            if (!EMFDC_SetD( pldc, dwIn, ulMFId ))
+                return 0;
+        }
+    }
 
     /* Call win32k to do the real work */
     if (!NtGdiGetAndSetDCDword(hdc, u, dwIn, &dwResult))
@@ -896,7 +918,7 @@ SetDCBrushColor(
     }
 
     /* We handle only enhanced meta DCs here */
-    HANDLE_METADC(COLORREF, SetDCBrushColor, CLR_INVALID, hdc, crColor);
+    HANDLE_EMETAFDC(COLORREF, SetDCBrushColor, CLR_INVALID, hdc, crColor);
 
     /* Get old color and store the new */
     crOldColor = pdcattr->ulBrushClr;
@@ -932,7 +954,7 @@ SetDCPenColor(
     }
 
     /* We handle only enhanced meta DCs here */
-    HANDLE_METADC(COLORREF, SetDCPenColor, CLR_INVALID, hdc, crColor);
+    HANDLE_EMETAFDC(COLORREF, SetDCPenColor, CLR_INVALID, hdc, crColor);
 
     /* Get old color and store the new */
     crOldColor = pdcattr->ulPenClr;
@@ -1292,7 +1314,7 @@ SelectPalette(
     HPALETTE hpal,
     BOOL bForceBackground)
 {
-    HANDLE_METADC(HPALETTE, SelectPalette, NULL, hdc, hpal, bForceBackground);
+    HANDLE_METADC(HPALETTE, SelectPalette, NULL, hdc, hpal);
 
     return NtUserSelectPalette(hdc, hpal, bForceBackground);
 }
@@ -1392,7 +1414,7 @@ GdiSelectBrush(
     PDC_ATTR pdcattr;
     HBRUSH hbrOld;
 
-    HANDLE_METADC(HBRUSH, SelectBrush, NULL, hdc, hbr);
+    HANDLE_METADC(HBRUSH, SelectObject, NULL, hdc, hbr);
 
     /* Get the DC attribute */
     pdcattr = GdiGetDcAttr(hdc);
@@ -1422,7 +1444,7 @@ GdiSelectPen(
     PDC_ATTR pdcattr;
     HPEN hpenOld;
 
-    HANDLE_METADC(HPEN, SelectPen, NULL, hdc, hpen);
+    HANDLE_METADC(HPEN, SelectObject, NULL, hdc, hpen);
 
     /* Get the DC attribute */
     pdcattr = GdiGetDcAttr(hdc);
@@ -1452,7 +1474,7 @@ GdiSelectFont(
     PDC_ATTR pdcattr;
     HFONT hfontOld;
 
-    HANDLE_METADC(HFONT, SelectFont, NULL, hdc, hfont);
+    HANDLE_METADC(HFONT, SelectObject, NULL, hdc, hfont);
 
     /* Get the DC attribute */
     pdcattr = GdiGetDcAttr(hdc);
index a7d168d..c1c58d4 100644 (file)
@@ -6,35 +6,31 @@
 /*
  * @unimplemented
  */
-DWORD
+BOOL
 WINAPI
 IsValidEnhMetaRecord(
-    DWORD      a0,
-    DWORD      a1
-)
+    PVOID pv0,
+    PVOID pv1)
 {
     UNIMPLEMENTED;
     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return 0;
-
+    return FALSE;
 }
 
 /*
  * @unimplemented
  */
-DWORD
+BOOL
 WINAPI
 IsValidEnhMetaRecordOffExt(
-    DWORD      a0,
-    DWORD      a1,
-    DWORD      a2,
-    DWORD      a3
-)
+    PVOID pv0,
+    PVOID pv1,
+    DWORD dwOffset,
+    DWORD dwExtends )
 {
     UNIMPLEMENTED;
     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return 0;
-
+    return FALSE;
 }
 
 /*
@@ -136,9 +132,7 @@ GdiComment(
     if (GDI_HANDLE_GET_TYPE(hdc) != GDILoObjType_LO_ALTDC_TYPE)
         return TRUE;
 
-    HANDLE_METADC(BOOL, GdiComment, FALSE, hdc, cbSize, lpData);
-
-    return TRUE;
+    return EMFDC_GdiComment( hdc, cbSize, lpData );
 }
 
 /*
@@ -147,10 +141,9 @@ GdiComment(
 UINT
 WINAPI
 GetEnhMetaFilePixelFormat(
-    HENHMETAFILE                       hemf,
-    UINT                               cbBuffer,
-    PIXELFORMATDESCRIPTOR      *ppfd
-)
+    HENHMETAFILE hemf,
+    UINT cbBuffer,
+    PIXELFORMATDESCRIPTOR *ppfd )
 {
     ENHMETAHEADER pemh;
 
index ecd5d50..9661788 100644 (file)
@@ -323,14 +323,15 @@ DeleteObject(HGDIOBJ hObject)
     if ((DWORD_PTR)hObject & GDI_HANDLE_STOCK_MASK)
     {
         /* Ignore the attempt to delete a stock object */
-        DPRINT("Trying to delete system object 0x%p\n", hObject);
+        DPRINT1("Trying to delete system object 0x%p\n", hObject);
         return TRUE;
     }
 
     /* If we have any METAFILE objects, we need to check them */
     if (gcClientObj > 0)
     {
-        METADC_DeleteObject(hObject);
+        DPRINT("Going Glue\n");
+        METADC_RosGlueDeleteObject(hObject);
     }
 
     /* Switch by object type */
@@ -349,16 +350,7 @@ DeleteObject(HGDIOBJ hObject)
 
         case GDILoObjType_LO_REGION_TYPE:
             return DeleteRegion(hObject);
-#if 0
-        case GDI_OBJECT_TYPE_METADC:
-            return MFDRV_DeleteObject( hObject );
-        case GDI_OBJECT_TYPE_EMF:
-        {
-            PLDC pLDC = GdiGetLDC(hObject);
-            if ( !pLDC ) return FALSE;
-            return EMFDRV_DeleteObject( hObject );
-        }
-#endif
+
         case GDILoObjType_LO_BRUSH_TYPE:
         case GDILoObjType_LO_PEN_TYPE:
         case GDILoObjType_LO_EXTPEN_TYPE:
index 42bd22e..f59d6ce 100644 (file)
  */
 BOOL
 WINAPI
-GdiIsPlayMetafileDC(HDC hDC)
+GdiIsPlayMetafileDC(HDC hdc)
 {
-#if 0
-    PLDC pLDC = GdiGetLDC(hDC);
-    if ( pLDC )
+    PDC_ATTR pdcattr = GdiGetDcAttr(hdc);
+
+    if ( pdcattr )
     {
-        if ( pLDC->Flags & LDC_PLAY_MFDC ) return TRUE;
+        return !!( pdcattr->ulDirty_ & DC_PLAYMETAFILE );
     }
     return FALSE;
-#else
-    UNIMPLEMENTED;
-    return FALSE;
-#endif
 }
 
 /*
@@ -49,17 +45,13 @@ GdiIsMetaFileDC(HDC hdc)
 
     if (ulObjType == GDILoObjType_LO_ALTDC_TYPE)
     {
-#if 0
         PLDC pLDC = GdiGetLDC(hdc);
         if ( !pLDC )
         {
             SetLastError(ERROR_INVALID_HANDLE);
             return FALSE;
         }
-        if ( pLDC->iType == LDC_EMFLDC) return TRUE;
-        return FALSE;
-#endif
-        return TRUE;
+        return !!( pLDC->iType == LDC_EMFLDC );
     }
 
     return FALSE;
@@ -70,29 +62,26 @@ GdiIsMetaFileDC(HDC hdc)
  */
 BOOL
 WINAPI
-GdiIsMetaPrintDC(HDC hDC)
+GdiIsMetaPrintDC(HDC hdc)
 {
-#if 0
-    if (GDI_HANDLE_GET_TYPE(hDC) != GDI_OBJECT_TYPE_DC)
+    ULONG hType = GDI_HANDLE_GET_TYPE(hdc);
+
+    if ( hType != GDILoObjType_LO_DC_TYPE )
     {
-        if (GDI_HANDLE_GET_TYPE(hDC) == GDI_OBJECT_TYPE_METADC)
+        if ( hType == GDILoObjType_LO_METADC16_TYPE )
             return FALSE;
         else
         {
-            PLDC pLDC = GdiGetLDC(hDC);
+            PLDC pLDC = GdiGetLDC(hdc);
             if ( !pLDC )
             {
                 SetLastError(ERROR_INVALID_HANDLE);
                 return FALSE;
             }
-            if ( pLDC->Flags & LDC_META_PRINT) return TRUE;
+            return !!( pLDC->Flags & LDC_META_PRINT );
         }
     }
     return FALSE;
-#else
-    UNIMPLEMENTED;
-    return FALSE;
-#endif
 }
 
 // NOTE: I wanna use GdiCreateLocalMetaFilePict and GdiConvertMetaFilePict
index 17f64b8..9790111 100644 (file)
@@ -29,7 +29,7 @@ MoveToEx(
 {
     PDC_ATTR pdcattr;
 
-    HANDLE_METADC(BOOL, MoveTo, FALSE, hdc, x, y, ppt);
+    HANDLE_METADC(BOOL, MoveTo, FALSE, hdc, x, y);
 
     /* Get the DC attribute */
     pdcattr = GdiGetDcAttr(hdc);
@@ -265,7 +265,7 @@ PolyBezier(
     _In_reads_(cpt) const POINT *apt,
     _In_ DWORD cpt)
 {
-    HANDLE_METADC(BOOL, PolyBezier, FALSE, hdc, apt, cpt);
+    HANDLE_EMETAFDC(BOOL, PolyBezier, FALSE, hdc, apt, cpt);
 
     if ( GdiConvertAndCheckDC(hdc) == NULL ) return FALSE;
 
@@ -283,7 +283,7 @@ PolyBezierTo(
     _In_reads_(cpt) const POINT *apt,
     _In_ DWORD cpt)
 {
-    HANDLE_METADC(BOOL, PolyBezierTo, FALSE, hdc, apt, cpt);
+    HANDLE_EMETAFDC(BOOL, PolyBezierTo, FALSE, hdc, apt, cpt);
 
     if ( GdiConvertAndCheckDC(hdc) == NULL ) return FALSE;
 
@@ -302,7 +302,7 @@ PolyDraw(
     _In_reads_(cpt) const BYTE *aj,
     _In_ INT cpt)
 {
-    HANDLE_METADC(BOOL, PolyDraw, FALSE, hdc, apt, aj, cpt);
+    HANDLE_EMETAFDC(BOOL, PolyDraw, FALSE, hdc, apt, aj, cpt);
 
     if ( GdiConvertAndCheckDC(hdc) == NULL ) return FALSE;
 
@@ -356,7 +356,7 @@ PolylineTo(
     _In_reads_(cpt) const POINT *apt,
     _In_ DWORD cpt)
 {
-    HANDLE_METADC(BOOL, PolylineTo, FALSE, hdc, apt, cpt);
+    HANDLE_EMETAFDC(BOOL, PolylineTo, FALSE, hdc, apt, cpt);
 
     if ( GdiConvertAndCheckDC(hdc) == NULL ) return FALSE;
 
@@ -397,7 +397,7 @@ PolyPolyline(
     if (GDI_HANDLE_GET_TYPE(hdc) == GDILoObjType_LO_METADC16_TYPE)
         return FALSE;
 
-    HANDLE_METADC(BOOL, PolyPolyline, FALSE, hdc, apt, asz, csz);
+    HANDLE_EMETAFDC(BOOL, PolyPolyline, FALSE, hdc, apt, asz, csz);
 
     if ( GdiConvertAndCheckDC(hdc) == NULL ) return FALSE;
 
@@ -461,9 +461,9 @@ BitBlt(
         return PatBlt(hdcDest, xDest, yDest, cx, cy, dwRop);
     }
 
-    /* For meta DCs we use StretchBlt */
+    /* For meta DCs we use StretchBlt via emfdc.c */
     HANDLE_METADC(BOOL,
-                  StretchBlt,
+                  BitBlt,
                   FALSE,
                   hdcDest,
                   xDest,
@@ -473,8 +473,6 @@ BitBlt(
                   hdcSrc,
                   xSrc,
                   ySrc,
-                  cx,
-                  cy,
                   dwRop);
 
     if ( GdiConvertAndCheckDC(hdcDest) == NULL ) return FALSE;
@@ -494,7 +492,7 @@ PatBlt(
 {
     PDC_ATTR pdcattr;
 
-    HANDLE_METADC(BOOL, PatBlt, FALSE, hdc, nXLeft, nYLeft, nWidth, nHeight, dwRop);
+    HANDLE_EMETAFDC(BOOL, PatBlt, FALSE, hdc, nXLeft, nYLeft, nWidth, nHeight, dwRop);
 
     if ( GdiConvertAndCheckDC(hdc) == NULL ) return FALSE;
 
@@ -686,7 +684,7 @@ MaskBlt(
     _In_ INT yMask,
     _In_ DWORD dwRop)
 {
-    HANDLE_METADC(BOOL,
+    HANDLE_EMETAFDC(BOOL,
                   MaskBlt,
                   FALSE,
                   hdcDest,
@@ -737,7 +735,7 @@ PlgBlt(
     _In_ INT xMask,
     _In_ INT yMask)
 {
-    HANDLE_METADC(BOOL,
+    HANDLE_EMETAFDC(BOOL,
                   PlgBlt,
                   FALSE,
                   hdcDest,
@@ -785,7 +783,7 @@ GdiAlphaBlend(
 
     if (GDI_HANDLE_GET_TYPE(hdcSrc) == GDI_OBJECT_TYPE_METADC) return FALSE;
 
-    HANDLE_METADC(BOOL,
+    HANDLE_EMETAFDC(BOOL,
                   AlphaBlend,
                   FALSE,
                   hdcDst,
@@ -835,7 +833,7 @@ GdiTransparentBlt(
     _In_ INT cySrc,
     _In_ UINT crTransparent)
 {
-    HANDLE_METADC(BOOL,
+    HANDLE_EMETAFDC(BOOL,
                   TransparentBlt,
                   FALSE,
                   hdcDst,
@@ -868,7 +866,9 @@ GdiGradientFill(
     _In_ ULONG nCount,
     _In_ ULONG ulMode)
 {
-    HANDLE_METADC(BOOL, GradientFill, FALSE, hdc, pVertex, nVertex, pMesh, nCount, ulMode);
+    if (GDI_HANDLE_GET_TYPE(hdc) == GDILoObjType_LO_METADC16_TYPE) return TRUE;
+
+    HANDLE_EMETAFDC(BOOL, GradientFill, FALSE, hdc, pVertex, nVertex, pMesh, nCount, ulMode);
 
     if ( GdiConvertAndCheckDC(hdc) == NULL ) return FALSE;
 
index 3c7afd7..c79ca27 100644 (file)
@@ -138,7 +138,10 @@ WINAPI
 RealizePalette(
     _In_ HDC hdc) /* [in] Handle of device context */
 {
-    HANDLE_METADC0P(UINT, RealizePalette, GDI_ERROR, hdc);
+    if (GDI_HANDLE_GET_TYPE(hdc) == GDILoObjType_LO_METADC16_TYPE)
+    {
+       return METADC_RealizePalette(hdc);
+    }
 
     if (GDI_HANDLE_GET_TYPE(hdc) != GDILoObjType_LO_DC_TYPE)
     {
index 01ba886..26922f4 100644 (file)
@@ -120,7 +120,7 @@ WINAPI
 PathToRegion(
     HDC        hdc)
 {
-    HANDLE_METADC0P(HRGN, PathToRegion, NULL, hdc);
+    HANDLE_METADC0P(HRGN, AbortPath, NULL, hdc);
     return NtGdiPathToRegion(hdc);
 }
 
@@ -192,6 +192,6 @@ SelectClipPath(
     HDC        hdc,
     int        iMode)
 {
-    HANDLE_METADC(BOOL, SelectClipPath, FALSE, hdc, iMode);
+    HANDLE_EMETAFDC(BOOL, SelectClipPath, FALSE, hdc, iMode);
     return NtGdiSelectClipPath(hdc, iMode);
 }
index d7d2c33..17b500a 100644 (file)
@@ -1086,20 +1086,22 @@ 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 (GDI_HANDLE_GET_TYPE(hDC) != GDILoObjType_LO_DC_TYPE)
     {
-        if (pLDC->iType == LDC_EMFLDC || EMFDRV_SetMetaRgn(hDC))
+        PLDC pLDC = GdiGetLDC(hDC);
+        if ( pLDC && GDI_HANDLE_GET_TYPE(hDC) != GDILoObjType_LO_METADC16_TYPE )
         {
-            return NtGdiSetMetaRgn(hDC);
+            if (pLDC->iType == LDC_EMFLDC && !EMFDC_SetMetaRgn( pLDC ))
+            {
+                return ERROR;
+            }
         }
         else
+        {
             SetLastError(ERROR_INVALID_HANDLE);
+            return ERROR;
+        }
     }
-#endif
-    return ERROR;
+    return NtGdiSetMetaRgn(hDC);
 }
 
index 9a08ec5..799c20f 100644 (file)
@@ -782,10 +782,7 @@ SetTextCharacterExtra(
         return 0x80000000;
     }
 
-    if (GDI_HANDLE_GET_TYPE(hdc) == GDILoObjType_LO_METADC16_TYPE)
-    {
-        HANDLE_METADC(INT, SetTextCharacterExtra, 0x80000000, hdc, nCharExtra);
-    }
+    HANDLE_METADC16(INT, SetTextCharacterExtra, 0x80000000, hdc, nCharExtra);
 
     /* Get the DC attribute */
     pdcattr = GdiGetDcAttr(hdc);
@@ -935,10 +932,7 @@ SetTextJustification(
 {
     PDC_ATTR pdcattr;
 
-    if (GDI_HANDLE_GET_TYPE(hdc) == GDILoObjType_LO_METADC16_TYPE)
-    {
-        HANDLE_METADC(BOOL, SetTextJustification, FALSE, hdc, nBreakExtra, nBreakCount);
-    }
+    HANDLE_METADC16(BOOL, SetTextJustification, FALSE, hdc, nBreakExtra, nBreakCount);
 
     /* Get the DC attribute */
     pdcattr = GdiGetDcAttr(hdc);
index 4f70a33..387b224 100644 (file)
@@ -6,20 +6,11 @@ include_directories(
     .)
 
 list(APPEND SOURCE
+    emfdc.c
+    emfdrv.c
     enhmetafile.c
+    metadc.c
     metafile.c
-    path.c
-    enhmfdrv/bitblt.c
-    enhmfdrv/dc.c
-    enhmfdrv/graphics.c
-    enhmfdrv/init.c
-    enhmfdrv/objects.c
-    mfdrv/bitblt.c
-    mfdrv/dc.c
-    mfdrv/graphics.c
-    mfdrv/init.c
-    mfdrv/objects.c
-    mfdrv/text.c
     rosglue.c)
 
 add_library(winegdi ${SOURCE})
diff --git a/win32ss/gdi/gdi32/wine/emfdc.c b/win32ss/gdi/gdi32/wine/emfdc.c
new file mode 100644 (file)
index 0000000..b300e0e
--- /dev/null
@@ -0,0 +1,2569 @@
+/*
+ * Enhanced MetaFile recording functions
+ *
+ * Copyright 1999 Huw D M Davies
+ * Copyright 2016 Alexandre Julliard
+ * Copyright 2021 Jacek Caban for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#include "config.h"
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winnls.h"
+#include "winerror.h"
+#include "gdi_private.h"
+#include "wine/wingdi16.h"
+#include "wine/debug.h"
+#ifdef __REACTOS__
+#include "wine/winternl.h"
+#else
+#include "winternl.h"
+#endif
+
+WINE_DEFAULT_DEBUG_CHANNEL(enhmetafile);
+
+struct emf
+{
+    ENHMETAHEADER  *emh;
+    WINEDC  *dc_attr;
+    UINT     handles_size, cur_handles;
+    HGDIOBJ *handles;
+    HANDLE   file;
+    HBRUSH   dc_brush;
+    HPEN     dc_pen;
+    BOOL     path;
+};
+
+#define HANDLE_LIST_INC 20
+static const RECTL empty_bounds = { 0, 0, -1, -1 };
+
+static BOOL emfdc_record( struct emf *emf, EMR *emr )
+{
+    DWORD len, size;
+    ENHMETAHEADER *emh;
+
+    TRACE( "record %d, size %d\n", emr->iType, emr->nSize );
+
+    assert( !(emr->nSize & 3) );
+
+    emf->emh->nBytes += emr->nSize;
+    emf->emh->nRecords++;
+
+    size = HeapSize( GetProcessHeap(), 0, emf->emh );
+    len = emf->emh->nBytes;
+    if (len > size)
+    {
+        size += (size / 2) + emr->nSize;
+        emh = HeapReAlloc( GetProcessHeap(), 0, emf->emh, size );
+        if (!emh) return FALSE;
+        emf->emh = emh;
+    }
+    memcpy( (char *)emf->emh + emf->emh->nBytes - emr->nSize, emr, emr->nSize );
+    return TRUE;
+}
+
+static void emfdc_update_bounds( struct emf *emf, RECTL *rect )
+{
+    RECTL *bounds = &emf->dc_attr->emf_bounds;
+    RECTL vport_rect = *rect;
+
+    LPtoDP( emf->dc_attr->hdc, (POINT *)&vport_rect, 2 );
+
+    /* The coordinate systems may be mirrored
+       (LPtoDP handles points, not rectangles) */
+    if (vport_rect.left > vport_rect.right)
+    {
+        LONG temp = vport_rect.right;
+        vport_rect.right = vport_rect.left;
+        vport_rect.left = temp;
+    }
+    if (vport_rect.top > vport_rect.bottom)
+    {
+        LONG temp = vport_rect.bottom;
+        vport_rect.bottom = vport_rect.top;
+        vport_rect.top = temp;
+    }
+
+    if (bounds->left > bounds->right)
+    {
+        /* first bounding rectangle */
+        *bounds = vport_rect;
+    }
+    else
+    {
+        bounds->left   = min(bounds->left,   vport_rect.left);
+        bounds->top    = min(bounds->top,    vport_rect.top);
+        bounds->right  = max(bounds->right,  vport_rect.right);
+        bounds->bottom = max(bounds->bottom, vport_rect.bottom);
+    }
+}
+
+static UINT get_bitmap_info( HDC *hdc, HBITMAP *bitmap, BITMAPINFO *info )
+{
+    HBITMAP blit_bitmap;
+    HDC blit_dc;
+    UINT info_size, bpp;
+    DIBSECTION dib;
+
+    if (!(info_size = GetObjectW( *bitmap, sizeof(dib), &dib ))) return 0;
+
+    if (info_size == sizeof(dib))
+    {
+        blit_dc = *hdc;
+        blit_bitmap = *bitmap;
+    }
+    else
+    {
+        unsigned char dib_info_buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
+        BITMAPINFO *dib_info = (BITMAPINFO *)dib_info_buffer;
+        BITMAP bmp = dib.dsBm;
+        HPALETTE palette;
+        void *bits;
+
+        assert( info_size == sizeof(BITMAP) );
+
+        dib_info->bmiHeader.biSize = sizeof(dib_info->bmiHeader);
+        dib_info->bmiHeader.biWidth = bmp.bmWidth;
+        dib_info->bmiHeader.biHeight = bmp.bmHeight;
+        dib_info->bmiHeader.biPlanes = 1;
+        dib_info->bmiHeader.biBitCount = bmp.bmBitsPixel;
+        dib_info->bmiHeader.biCompression = BI_RGB;
+        dib_info->bmiHeader.biSizeImage = 0;
+        dib_info->bmiHeader.biXPelsPerMeter = 0;
+        dib_info->bmiHeader.biYPelsPerMeter = 0;
+        dib_info->bmiHeader.biClrUsed = 0;
+        dib_info->bmiHeader.biClrImportant = 0;
+        switch (dib_info->bmiHeader.biBitCount)
+        {
+        case 16:
+            ((DWORD *)dib_info->bmiColors)[0] = 0xf800;
+            ((DWORD *)dib_info->bmiColors)[1] = 0x07e0;
+            ((DWORD *)dib_info->bmiColors)[2] = 0x001f;
+            break;
+        case 32:
+            ((DWORD *)dib_info->bmiColors)[0] = 0xff0000;
+            ((DWORD *)dib_info->bmiColors)[1] = 0x00ff00;
+            ((DWORD *)dib_info->bmiColors)[2] = 0x0000ff;
+            break;
+        default:
+            if (dib_info->bmiHeader.biBitCount > 8) break;
+            if (!(palette = GetCurrentObject( *hdc, OBJ_PAL ))) return FALSE;
+            if (!GetPaletteEntries( palette, 0, 256, (PALETTEENTRY *)dib_info->bmiColors ))
+                return FALSE;
+        }
+
+        if (!(blit_dc = /*NtGdi*/CreateCompatibleDC( *hdc ))) return FALSE;
+        if (!(blit_bitmap = CreateDIBSection( blit_dc, dib_info, DIB_RGB_COLORS, &bits, NULL, 0 )))
+            goto err;
+        if (!SelectObject( blit_dc, blit_bitmap )) goto err;
+        if (!BitBlt( blit_dc, 0, 0, bmp.bmWidth, bmp.bmHeight, *hdc, 0, 0, SRCCOPY ))
+            goto err;
+    }
+    if (!GetDIBits( blit_dc, blit_bitmap, 0, INT_MAX, NULL, info, DIB_RGB_COLORS ))
+        goto err;
+
+    bpp = info->bmiHeader.biBitCount;
+    if (bpp <= 8)
+        return sizeof(BITMAPINFOHEADER) + (1 << bpp) * sizeof(RGBQUAD);
+    else if (bpp == 16 || bpp == 32)
+        return sizeof(BITMAPINFOHEADER) + 3 * sizeof(RGBQUAD);
+
+    return sizeof(BITMAPINFOHEADER);
+
+err:
+    if (blit_dc && blit_dc != *hdc) DeleteDC( blit_dc );
+    if (blit_bitmap && blit_bitmap != *bitmap) DeleteObject( blit_bitmap );
+    return 0;
+}
+
+static UINT emfdc_add_handle( struct emf *emf, HGDIOBJ obj )
+{
+    UINT index;
+
+    for (index = 0; index < emf->handles_size; index++)
+        if (emf->handles[index] == 0) break;
+
+    if (index == emf->handles_size)
+    {
+        emf->handles_size += HANDLE_LIST_INC;
+        emf->handles = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
+                                    emf->handles,
+                                    emf->handles_size * sizeof(emf->handles[0]) );
+    }
+    emf->handles[index] = get_full_gdi_handle( obj );
+
+    emf->cur_handles++;
+    if (emf->cur_handles > emf->emh->nHandles)
+        emf->emh->nHandles++;
+
+    return index + 1; /* index 0 is reserved for the hmf, so we increment everything by 1 */
+}
+
+static UINT emfdc_find_object( struct emf *emf, HGDIOBJ obj )
+{
+    UINT index;
+
+    for (index = 0; index < emf->handles_size; index++)
+        if (emf->handles[index] == obj) return index + 1;
+
+    return 0;
+}
+
+void emfdc_delete_object( HDC hdc, HGDIOBJ obj )
+{
+    WINEDC *dc_attr = get_dc_ptr( hdc );
+    struct emf *emf = dc_attr->emf;
+    EMRDELETEOBJECT emr;
+    UINT index;
+
+    if(!(index = emfdc_find_object( emf, obj ))) return;
+
+    emr.emr.iType = EMR_DELETEOBJECT;
+    emr.emr.nSize = sizeof(emr);
+    emr.ihObject = index;
+
+    emfdc_record( emf, &emr.emr );
+
+    emf->handles[index - 1] = 0;
+    emf->cur_handles--;
+}
+
+static DWORD emfdc_create_brush( struct emf *emf, HBRUSH brush )
+{
+    DWORD index = 0;
+    LOGBRUSH logbrush;
+
+    if (!GetObjectA( brush, sizeof(logbrush), &logbrush )) return 0;
+
+    switch (logbrush.lbStyle) {
+    case BS_SOLID:
+    case BS_HATCHED:
+    case BS_NULL:
+        {
+            EMRCREATEBRUSHINDIRECT emr;
+            emr.emr.iType = EMR_CREATEBRUSHINDIRECT;
+            emr.emr.nSize = sizeof(emr);
+            emr.ihBrush = index = emfdc_add_handle( emf, brush );
+            emr.lb.lbStyle = logbrush.lbStyle;
+            emr.lb.lbColor = logbrush.lbColor;
+            emr.lb.lbHatch = logbrush.lbHatch;
+
+            if(!emfdc_record( emf, &emr.emr ))
+                index = 0;
+        }
+      break;
+    case BS_PATTERN:
+    case BS_DIBPATTERN:
+        {
+            EMRCREATEDIBPATTERNBRUSHPT *emr;
+            char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
+            BITMAPINFO *info = (BITMAPINFO *)buffer;
+            DWORD info_size;
+            UINT usage;
+
+            if (!get_brush_bitmap_info( brush, info, NULL, &usage )) break;
+            info_size = get_dib_info_size( info, usage );
+
+            emr = HeapAlloc( GetProcessHeap(), 0,
+                             sizeof(EMRCREATEDIBPATTERNBRUSHPT) + sizeof(DWORD) +
+                             info_size+info->bmiHeader.biSizeImage );
+            if(!emr) break;
+
+            /* FIXME: There is an extra DWORD written by native before the BMI.
+             *        Not sure what it's meant to contain.
+             */
+            emr->offBmi = sizeof( EMRCREATEDIBPATTERNBRUSHPT ) + sizeof(DWORD);
+            *(DWORD *)(emr + 1) = 0x20000000;
+
+            if (logbrush.lbStyle == BS_PATTERN && info->bmiHeader.biBitCount == 1)
+            {
+                /* Presumably to reduce the size of the written EMF, MS supports an
+                 * undocumented iUsage value of 2, indicating a mono bitmap without the
+                 * 8 byte 2 entry black/white palette. Stupidly, they could have saved
+                 * over 20 bytes more by also ignoring the BITMAPINFO fields that are
+                 * irrelevant/constant for monochrome bitmaps.
+                 * FIXME: It may be that the DIB functions themselves accept this value.
+                 */
+                emr->emr.iType = EMR_CREATEMONOBRUSH;
+                usage = DIB_PAL_MONO;
+                emr->cbBmi = sizeof( BITMAPINFOHEADER );
+            }
+            else
+            {
+                emr->emr.iType = EMR_CREATEDIBPATTERNBRUSHPT;
+                emr->cbBmi = info_size;
+            }
+            emr->ihBrush = index = emfdc_add_handle( emf, brush );
+            emr->iUsage = usage;
+            emr->offBits = emr->offBmi + emr->cbBmi;
+            emr->cbBits = info->bmiHeader.biSizeImage;
+            emr->emr.nSize = emr->offBits + emr->cbBits;
+
+            if (info->bmiHeader.biClrUsed == 1 << info->bmiHeader.biBitCount)
+                info->bmiHeader.biClrUsed = 0;
+            memcpy( (BYTE *)emr + emr->offBmi, info, emr->cbBmi );
+            get_brush_bitmap_info( brush, NULL, (char *)emr + emr->offBits, NULL );
+
+            if (!emfdc_record( emf, &emr->emr )) index = 0;
+            HeapFree( GetProcessHeap(), 0, emr );
+        }
+        break;
+
+    default:
+        FIXME("Unknown style %x\n", logbrush.lbStyle);
+        break;
+    }
+
+    return index;
+}
+
+static BOOL emfdc_select_brush( WINEDC *dc_attr, HBRUSH brush )
+{
+    struct emf *emf = dc_attr->emf;
+    EMRSELECTOBJECT emr;
+    DWORD index = 0;
+    int i;
+
+    /* If the object is a stock brush object, do not need to create it.
+     * See definitions in  wingdi.h for range of stock brushes.
+     * We do however have to handle setting the higher order bit to
+     * designate that this is a stock object.
+     */
+    for (i = WHITE_BRUSH; i <= DC_BRUSH; i++)
+    {
+        if (brush == GetStockObject(i))
+        {
+            index = i | 0x80000000;
+            break;
+        }
+    }
+
+    if (!index && !(index = emfdc_find_object( emf, brush )))
+    {
+        if (!(index = emfdc_create_brush( emf, brush ))) return 0;
+        GDI_hdc_using_object( brush, dc_attr->hdc);//, emfdc_delete_object );
+    }
+
+    emr.emr.iType = EMR_SELECTOBJECT;
+    emr.emr.nSize = sizeof(emr);
+    emr.ihObject = index;
+    return emfdc_record( emf, &emr.emr );
+}
+
+static BOOL emfdc_create_font( struct emf *emf, HFONT font )
+{
+    DWORD index = 0;
+    EMREXTCREATEFONTINDIRECTW emr;
+    int i;
+
+    if (!GetObjectW( font, sizeof(emr.elfw.elfLogFont), &emr.elfw.elfLogFont )) return FALSE;
+
+    emr.emr.iType = EMR_EXTCREATEFONTINDIRECTW;
+    emr.emr.nSize = (sizeof(emr) + 3) / 4 * 4;
+    emr.ihFont = index = emfdc_add_handle( emf, font );
+    emr.elfw.elfFullName[0] = '\0';
+    emr.elfw.elfStyle[0]    = '\0';
+    emr.elfw.elfVersion     = 0;
+    emr.elfw.elfStyleSize   = 0;
+    emr.elfw.elfMatch       = 0;
+    emr.elfw.elfReserved    = 0;
+    for (i = 0; i < ELF_VENDOR_SIZE; i++)
+        emr.elfw.elfVendorId[i] = 0;
+    emr.elfw.elfCulture                 = PAN_CULTURE_LATIN;
+    emr.elfw.elfPanose.bFamilyType      = PAN_NO_FIT;
+    emr.elfw.elfPanose.bSerifStyle      = PAN_NO_FIT;
+    emr.elfw.elfPanose.bWeight          = PAN_NO_FIT;
+    emr.elfw.elfPanose.bProportion      = PAN_NO_FIT;
+    emr.elfw.elfPanose.bContrast        = PAN_NO_FIT;
+    emr.elfw.elfPanose.bStrokeVariation = PAN_NO_FIT;
+    emr.elfw.elfPanose.bArmStyle        = PAN_NO_FIT;
+    emr.elfw.elfPanose.bLetterform      = PAN_NO_FIT;
+    emr.elfw.elfPanose.bMidline         = PAN_NO_FIT;
+    emr.elfw.elfPanose.bXHeight         = PAN_NO_FIT;
+
+    return emfdc_record( emf, &emr.emr ) ? index : 0;
+}
+
+static BOOL emfdc_select_font( WINEDC *dc_attr, HFONT font )
+{
+    struct emf *emf = dc_attr->emf;
+    EMRSELECTOBJECT emr;
+    DWORD index;
+    int i;
+
+    /* If the object is a stock font object, do not need to create it.
+     * See definitions in  wingdi.h for range of stock fonts.
+     * We do however have to handle setting the higher order bit to
+     * designate that this is a stock object.
+     */
+
+    for (i = OEM_FIXED_FONT; i <= DEFAULT_GUI_FONT; i++)
+    {
+        if (i != DEFAULT_PALETTE && font == GetStockObject(i))
+        {
+            index = i | 0x80000000;
+            goto found;
+        }
+    }
+
+    if (!(index = emfdc_find_object( emf, font )))
+    {
+        if (!(index = emfdc_create_font( emf, font ))) return FALSE;
+        GDI_hdc_using_object( font, dc_attr->hdc);//, emfdc_delete_object );
+    }
+
+ found:
+    emr.emr.iType = EMR_SELECTOBJECT;
+    emr.emr.nSize = sizeof(emr);
+    emr.ihObject = index;
+    return emfdc_record( emf, &emr.emr );
+}
+
+static DWORD emfdc_create_pen( struct emf *emf, HPEN hPen )
+{
+    EMRCREATEPEN emr;
+    DWORD index = 0;
+
+    if (!GetObjectW( hPen, sizeof(emr.lopn), &emr.lopn ))
+    {
+        /* must be an extended pen */
+        EXTLOGPEN *elp;
+        INT size = GetObjectW( hPen, 0, NULL );
+
+        if (!size) return 0;
+
+        elp = HeapAlloc( GetProcessHeap(), 0, size );
+
+        GetObjectW( hPen, size, elp );
+        /* FIXME: add support for user style pens */
+        emr.lopn.lopnStyle = elp->elpPenStyle;
+        emr.lopn.lopnWidth.x = elp->elpWidth;
+        emr.lopn.lopnWidth.y = 0;
+        emr.lopn.lopnColor = elp->elpColor;
+
+        HeapFree( GetProcessHeap(), 0, elp );
+    }
+
+    emr.emr.iType = EMR_CREATEPEN;
+    emr.emr.nSize = sizeof(emr);
+    emr.ihPen = index = emfdc_add_handle( emf, hPen );
+    return emfdc_record( emf, &emr.emr ) ? index : 0;
+}
+
+static BOOL emfdc_select_pen( WINEDC *dc_attr, HPEN pen )
+{
+    struct emf *emf = dc_attr->emf;
+    EMRSELECTOBJECT emr;
+    DWORD index = 0;
+    int i;
+
+    /* If the object is a stock pen object, do not need to create it.
+     * See definitions in  wingdi.h for range of stock pens.
+     * We do however have to handle setting the higher order bit to
+     * designate that this is a stock object.
+     */
+
+    for (i = WHITE_PEN; i <= DC_PEN; i++)
+    {
+        if (pen == GetStockObject(i))
+        {
+            index = i | 0x80000000;
+            break;
+        }
+    }
+    if (!index && !(index = emfdc_find_object( emf, pen )))
+    {
+        if (!(index = emfdc_create_pen( emf, pen ))) return FALSE;
+        GDI_hdc_using_object( pen, dc_attr->hdc);//, emfdc_delete_object );
+    }
+
+    emr.emr.iType = EMR_SELECTOBJECT;
+    emr.emr.nSize = sizeof(emr);
+    emr.ihObject = index;
+    return emfdc_record( emf, &emr.emr );
+}
+
+static DWORD emfdc_create_palette( struct emf *emf, HPALETTE hPal )
+{
+    WORD i;
+    struct {
+        EMRCREATEPALETTE hdr;
+        PALETTEENTRY entry[255];
+    } pal;
+
+    memset( &pal, 0, sizeof(pal) );
+
+    if (!GetObjectW( hPal, sizeof(pal.hdr.lgpl) + sizeof(pal.entry), &pal.hdr.lgpl ))
+        return 0;
+
+    for (i = 0; i < pal.hdr.lgpl.palNumEntries; i++)
+        pal.hdr.lgpl.palPalEntry[i].peFlags = 0;
+
+    pal.hdr.emr.iType = EMR_CREATEPALETTE;
+    pal.hdr.emr.nSize = sizeof(pal.hdr) + pal.hdr.lgpl.palNumEntries * sizeof(PALETTEENTRY);
+    pal.hdr.ihPal = emfdc_add_handle( emf, hPal );
+
+    if (!emfdc_record( emf, &pal.hdr.emr ))
+        pal.hdr.ihPal = 0;
+    return pal.hdr.ihPal;
+}
+
+BOOL EMFDC_SelectPalette( WINEDC *dc_attr, HPALETTE palette )
+{
+    struct emf *emf = dc_attr->emf;
+    EMRSELECTPALETTE emr;
+    DWORD index = 0;
+
+    if (palette == GetStockObject( DEFAULT_PALETTE ))
+    {
+        index = DEFAULT_PALETTE | 0x80000000;
+    }
+    else if (!(index = emfdc_find_object( emf, palette )))
+    {
+        if (!(index = emfdc_create_palette( emf, palette ))) return 0;
+        GDI_hdc_using_object( palette, dc_attr->hdc);//, emfdc_delete_object );
+    }
+
+    emr.emr.iType = EMR_SELECTPALETTE;
+    emr.emr.nSize = sizeof(emr);
+    emr.ihPal = index;
+    return emfdc_record( emf, &emr.emr );
+}
+
+BOOL EMFDC_SelectObject( WINEDC *dc_attr, HGDIOBJ obj )
+{
+    switch (GDI_HANDLE_GET_TYPE( obj ))
+    {
+    case GDILoObjType_LO_BRUSH_TYPE:
+        return emfdc_select_brush( dc_attr, obj );
+    case GDILoObjType_LO_FONT_TYPE:
+        return emfdc_select_font( dc_attr, obj );
+    case GDILoObjType_LO_PEN_TYPE:
+    case GDILoObjType_LO_EXTPEN_TYPE:
+        return emfdc_select_pen( dc_attr, obj );
+    default:
+        return TRUE;
+    }
+}
+
+/* determine if we can use 16-bit points to store all the input points */
+static BOOL can_use_short_points( const POINT *pts, UINT count )
+{
+    UINT i;
+
+    for (i = 0; i < count; i++)
+        if (((pts[i].x + 0x8000) & ~0xffff) || ((pts[i].y + 0x8000) & ~0xffff))
+            return FALSE;
+    return TRUE;
+}
+
+/* store points in either long or short format; return a pointer to the end of the stored data */
+static void *store_points( POINTL *dest, const POINT *pts, UINT count, BOOL short_points )
+{
+    if (short_points)
+    {
+        UINT i;
+        POINTS *dest_short = (POINTS *)dest;
+
+        for (i = 0; i < count; i++)
+        {
+            dest_short[i].x = pts[i].x;
+            dest_short[i].y = pts[i].y;
+        }
+        return dest_short + count;
+    }
+    else
+    {
+        memcpy( dest, pts, count * sizeof(*dest) );
+        return dest + count;
+    }
+}
+
+/* compute the bounds of an array of points, optionally including the current position */
+static void get_points_bounds( RECTL *bounds, const POINT *pts, UINT count, WINEDC *dc_attr )
+{
+    UINT i;
+
+    if (dc_attr)
+    {
+        POINT cur_pos;
+        GetCurrentPositionEx(dc_attr->hdc, &cur_pos); 
+        bounds->left = bounds->right = cur_pos.x;
+        bounds->top = bounds->bottom = cur_pos.y;
+    }
+    else if (count)
+    {
+        bounds->left = bounds->right = pts[0].x;
+        bounds->top = bounds->bottom = pts[0].y;
+    }
+    else *bounds = empty_bounds;
+
+    for (i = 0; i < count; i++)
+    {
+        bounds->left   = min( bounds->left, pts[i].x );
+        bounds->right  = max( bounds->right, pts[i].x );
+        bounds->top    = min( bounds->top, pts[i].y );
+        bounds->bottom = max( bounds->bottom, pts[i].y );
+    }
+}
+
+/* helper for path stroke and fill functions */
+#ifdef __REACTOS__
+static BOOL emfdrv_stroke_and_fill_path( struct emf *emf, INT type )
+{
+    EMRSTROKEANDFILLPATH emr;
+    LPPOINT Points;
+    LPBYTE Types;
+    INT nSize;
+
+    emr.emr.iType = type;
+    emr.emr.nSize = sizeof(emr);
+
+    nSize = GetPath(emf->dc_attr->hdc, NULL, NULL, 0);
+    if (nSize != -1)
+    {
+       Points = HeapAlloc( GetProcessHeap(), 0, nSize*sizeof(POINT) );
+       Types  = HeapAlloc( GetProcessHeap(), 0, nSize*sizeof(BYTE) );
+
+       GetPath(emf->dc_attr->hdc, Points, Types, nSize);
+       get_points_bounds( &emr.rclBounds, Points, nSize, 0 );
+
+       HeapFree( GetProcessHeap(), 0, Points );
+       HeapFree( GetProcessHeap(), 0, Types );
+
+       TRACE("GetBounds l %d t %d r %d b %d\n",emr.rclBounds.left, emr.rclBounds.top, emr.rclBounds.right, emr.rclBounds.bottom);
+    }
+    else emr.rclBounds = empty_bounds;
+
+    if (!emfdc_record( emf, &emr.emr )) return FALSE;
+    if (nSize == -1 ) return FALSE;
+    emfdc_update_bounds( emf, &emr.rclBounds );
+    return TRUE;
+}
+#else
+static BOOL emfdrv_stroke_and_fill_path( struct emf *emf, INT type )
+{
+    EMRSTROKEANDFILLPATH emr;
+    HRGN region;
+
+    emr.emr.iType = type;
+    emr.emr.nSize = sizeof(emr);
+    emr.rclBounds = empty_bounds;
+
+    if ((region = NtGdiPathToRegion( emf->dc_attr->hdc ))) // WTF are you doing? This removes path!!!
+    {
+        NtGdiGetRgnBox( region, (RECT *)&emr.rclBounds );
+        DeleteObject( region );
+    }
+    if (!emfdc_record( emf, &emr.emr )) return FALSE;
+    if (!region) return FALSE;
+    emfdc_update_bounds( emf, &emr.rclBounds );
+    return TRUE;
+}
+#endif
+BOOL EMFDC_MoveTo( WINEDC *dc_attr, INT x, INT y )
+{
+    struct emf *emf = dc_attr->emf;
+    EMRMOVETOEX emr;
+
+    emr.emr.iType = EMR_MOVETOEX;
+    emr.emr.nSize = sizeof(emr);
+    emr.ptl.x = x;
+    emr.ptl.y = y;
+    return emfdc_record( emf, &emr.emr );
+}
+
+BOOL EMFDC_LineTo( WINEDC *dc_attr, INT x, INT y )
+{
+    EMRLINETO emr;
+    BOOL Ret;
+
+    emr.emr.iType = EMR_LINETO;
+    emr.emr.nSize = sizeof(emr);
+    emr.ptl.x = x;
+    emr.ptl.y = y;
+    Ret = emfdc_record( dc_attr->emf, &emr.emr );
+    EMFDRV_LineTo( dc_attr, x,  y );
+    return Ret;
+}
+
+BOOL EMFDC_ArcChordPie( WINEDC *dc_attr, INT left, INT top, INT right, INT bottom,
+                        INT xstart, INT ystart, INT xend, INT yend, DWORD type )
+{
+    struct emf *emf = dc_attr->emf;
+    EMRARC emr;
+    INT temp;
+    BOOL Ret;
+
+    if (left == right || top == bottom) return FALSE;
+
+    if (left > right) { temp = left; left = right; right = temp; }
+    if (top > bottom) { temp = top; top = bottom; bottom = temp; }
+
+    if (GetGraphicsMode(dc_attr->hdc) == GM_COMPATIBLE)
+    {
+        right--;
+        bottom--;
+    }
+
+    emr.emr.iType     = type;
+    emr.emr.nSize     = sizeof(emr);
+    emr.rclBox.left   = left;
+    emr.rclBox.top    = top;
+    emr.rclBox.right  = right;
+    emr.rclBox.bottom = bottom;
+    emr.ptlStart.x    = xstart;
+    emr.ptlStart.y    = ystart;
+    emr.ptlEnd.x      = xend;
+    emr.ptlEnd.y      = yend;
+    Ret = emfdc_record( emf, &emr.emr );
+    EMFDRV_ArcChordPie( dc_attr, left, top, right, bottom, xstart, ystart, xend, yend, type );
+    return Ret;
+}
+
+BOOL EMFDC_AngleArc( WINEDC *dc_attr, INT x, INT y, DWORD radius, FLOAT start, FLOAT sweep )
+{
+    EMRANGLEARC emr;
+
+    emr.emr.iType   = EMR_ANGLEARC;
+    emr.emr.nSize   = sizeof( emr );
+    emr.ptlCenter.x = x;
+    emr.ptlCenter.y = y;
+    emr.nRadius     = radius;
+    emr.eStartAngle = start;
+    emr.eSweepAngle = sweep;
+    return emfdc_record( dc_attr->emf, &emr.emr );
+}
+
+BOOL EMFDC_Ellipse( WINEDC *dc_attr, INT left, INT top, INT right, INT bottom )
+{
+    struct emf *emf = dc_attr->emf;
+    EMRELLIPSE emr;
+    BOOL Ret;
+
+    if (left == right || top == bottom) return FALSE;
+
+    emr.emr.iType     = EMR_ELLIPSE;
+    emr.emr.nSize     = sizeof(emr);
+    emr.rclBox.left   = min( left, right );
+    emr.rclBox.top    = min( top, bottom );
+    emr.rclBox.right  = max( left, right );
+    emr.rclBox.bottom = max( top, bottom );
+    if (GetGraphicsMode(dc_attr->hdc) == GM_COMPATIBLE)
+    {
+        emr.rclBox.right--;
+        emr.rclBox.bottom--;
+    }
+    Ret = emfdc_record( emf, &emr.emr );
+    EMFDRV_Ellipse( dc_attr, left, top, right, bottom );
+    return Ret;
+}
+
+BOOL EMFDC_Rectangle( WINEDC *dc_attr, INT left, INT top, INT right, INT bottom )
+{
+    struct emf *emf = dc_attr->emf;
+    EMRRECTANGLE emr;
+    BOOL Ret;
+
+    if(left == right || top == bottom) return FALSE;
+
+    emr.emr.iType     = EMR_RECTANGLE;
+    emr.emr.nSize     = sizeof(emr);
+    emr.rclBox.left   = min( left, right );
+    emr.rclBox.top    = min( top, bottom );
+    emr.rclBox.right  = max( left, right );
+    emr.rclBox.bottom = max( top, bottom );
+    if (GetGraphicsMode(dc_attr->hdc) == GM_COMPATIBLE)
+    {
+        emr.rclBox.right--;
+        emr.rclBox.bottom--;
+    }
+    Ret = emfdc_record( emf, &emr.emr );
+    EMFDRV_Rectangle( dc_attr, left, top, right, bottom );
+    return Ret;
+}
+
+BOOL EMFDC_RoundRect( WINEDC *dc_attr, INT left, INT top, INT right,
+                      INT bottom, INT ell_width, INT ell_height )
+{
+    struct emf *emf = dc_attr->emf;
+    EMRROUNDRECT emr;
+    BOOL Ret;
+
+    if (left == right || top == bottom) return FALSE;
+
+    emr.emr.iType     = EMR_ROUNDRECT;
+    emr.emr.nSize     = sizeof(emr);
+    emr.rclBox.left   = min( left, right );
+    emr.rclBox.top    = min( top, bottom );
+    emr.rclBox.right  = max( left, right );
+    emr.rclBox.bottom = max( top, bottom );
+    emr.szlCorner.cx  = ell_width;
+    emr.szlCorner.cy  = ell_height;
+    if (GetGraphicsMode(dc_attr->hdc) == GM_COMPATIBLE)
+    {
+        emr.rclBox.right--;
+        emr.rclBox.bottom--;
+    }
+    Ret = emfdc_record( emf, &emr.emr );
+    EMFDRV_RoundRect( dc_attr, left, top, right, bottom, ell_width, ell_height );
+    return Ret;
+}
+
+BOOL EMFDC_SetPixel( WINEDC *dc_attr, INT x, INT y, COLORREF color )
+{
+    EMRSETPIXELV emr;
+    BOOL Ret;
+
+    emr.emr.iType  = EMR_SETPIXELV;
+    emr.emr.nSize  = sizeof(emr);
+    emr.ptlPixel.x = x;
+    emr.ptlPixel.y = y;
+    emr.crColor = color;
+    Ret = emfdc_record( dc_attr->emf, &emr.emr );
+    EMFDRV_SetPixel( dc_attr, x, y, color );
+    return Ret;
+}
+
+static BOOL emfdc_polylinegon( WINEDC *dc_attr, const POINT *points, INT count, DWORD type )
+{
+    struct emf *emf = dc_attr->emf;
+    EMRPOLYLINE *emr;
+    DWORD size;
+    BOOL ret, use_small_emr = can_use_short_points( points, count );
+
+    size = use_small_emr ? offsetof( EMRPOLYLINE16, apts[count] ) : offsetof( EMRPOLYLINE, aptl[count] );
+
+    emr = HeapAlloc( GetProcessHeap(), 0, size );
+    emr->emr.iType = use_small_emr ? type + EMR_POLYLINE16 - EMR_POLYLINE : type;
+    emr->emr.nSize = size;
+    emr->cptl = count;
+
+    store_points( emr->aptl, points, count, use_small_emr );
+
+    if (!emf->path)
+        get_points_bounds( &emr->rclBounds, points, count,
+                           (type == EMR_POLYBEZIERTO || type == EMR_POLYLINETO) ? dc_attr : 0 );
+    else
+        emr->rclBounds = empty_bounds;
+
+    ret = emfdc_record( emf, &emr->emr );
+    if (ret && !emf->path) emfdc_update_bounds( emf, &emr->rclBounds );
+    HeapFree( GetProcessHeap(), 0, emr );
+    return ret;
+}
+
+BOOL EMFDC_Polyline( WINEDC *dc_attr, const POINT *points, INT count )
+{
+    return emfdc_polylinegon( dc_attr, points, count, EMR_POLYLINE );
+}
+
+BOOL EMFDC_PolylineTo( WINEDC *dc_attr, const POINT *points, INT count )
+{
+    return emfdc_polylinegon( dc_attr, points, count, EMR_POLYLINETO );
+}
+
+BOOL EMFDC_Polygon( WINEDC *dc_attr, const POINT *pt, INT count )
+{
+    if(count < 2) return FALSE;
+    return emfdc_polylinegon( dc_attr, pt, count, EMR_POLYGON );
+}
+
+BOOL EMFDC_PolyBezier( WINEDC *dc_attr, const POINT *pts, DWORD count )
+{
+    return emfdc_polylinegon( dc_attr, pts, count, EMR_POLYBEZIER );
+}
+
+BOOL EMFDC_PolyBezierTo( WINEDC *dc_attr, const POINT *pts, DWORD count )
+{
+    return emfdc_polylinegon( dc_attr, pts, count, EMR_POLYBEZIERTO );
+}
+
+static BOOL emfdc_poly_polylinegon( struct emf *emf, const POINT *pt, const INT *counts,
+                                   UINT polys, DWORD type)
+{
+    EMRPOLYPOLYLINE *emr;
+    DWORD cptl = 0, poly, size;
+    BOOL ret, use_small_emr, bounds_valid = TRUE;
+
+    for(poly = 0; poly < polys; poly++) {
+        cptl += counts[poly];
+        if(counts[poly] < 2) bounds_valid = FALSE;
+    }
+    if(!cptl) bounds_valid = FALSE;
+    use_small_emr = can_use_short_points( pt, cptl );
+
+    size = FIELD_OFFSET(EMRPOLYPOLYLINE, aPolyCounts[polys]);
+    if(use_small_emr)
+        size += cptl * sizeof(POINTS);
+    else
+        size += cptl * sizeof(POINTL);
+
+    emr = HeapAlloc( GetProcessHeap(), 0, size );
+
+    emr->emr.iType = type;
+    if(use_small_emr) emr->emr.iType += EMR_POLYPOLYLINE16 - EMR_POLYPOLYLINE;
+
+    emr->emr.nSize = size;
+    if(bounds_valid && !emf->path)
+        get_points_bounds( &emr->rclBounds, pt, cptl, 0 );
+    else
+        emr->rclBounds = empty_bounds;
+    emr->nPolys = polys;
+    emr->cptl = cptl;
+
+    if(polys)
+    {
+        memcpy( emr->aPolyCounts, counts, polys * sizeof(DWORD) );
+        store_points( (POINTL *)(emr->aPolyCounts + polys), pt, cptl, use_small_emr );
+    }
+
+    ret = emfdc_record( emf, &emr->emr );
+    if(ret && !bounds_valid)
+    {
+        ret = FALSE;
+        SetLastError( ERROR_INVALID_PARAMETER );
+    }
+    if(ret && !emf->path)
+        emfdc_update_bounds( emf, &emr->rclBounds );
+    HeapFree( GetProcessHeap(), 0, emr );
+    return ret;
+}
+
+BOOL EMFDC_PolyPolyline( WINEDC *dc_attr, const POINT *pt, const DWORD *counts, DWORD polys)
+{
+    return emfdc_poly_polylinegon( dc_attr->emf, pt, (const INT *)counts, polys, EMR_POLYPOLYLINE );
+}
+
+BOOL EMFDC_PolyPolygon( WINEDC *dc_attr, const POINT *pt, const INT *counts, UINT polys )
+{
+    return emfdc_poly_polylinegon( dc_attr->emf, pt, counts, polys, EMR_POLYPOLYGON );
+}
+
+BOOL EMFDC_PolyDraw( WINEDC *dc_attr, const POINT *pts, const BYTE *types, DWORD count )
+{
+    struct emf *emf = dc_attr->emf;
+    EMRPOLYDRAW *emr;
+    BOOL ret;
+    BYTE *types_dest;
+    BOOL use_small_emr = can_use_short_points( pts, count );
+    DWORD size;
+
+    size = use_small_emr ? offsetof( EMRPOLYDRAW16, apts[count] )
+        : offsetof( EMRPOLYDRAW, aptl[count] );
+    size += (count + 3) & ~3;
+
+    if (!(emr = HeapAlloc( GetProcessHeap(), 0, size ))) return FALSE;
+
+    emr->emr.iType = use_small_emr ? EMR_POLYDRAW16 : EMR_POLYDRAW;
+    emr->emr.nSize = size;
+    emr->cptl = count;
+
+    types_dest = store_points( emr->aptl, pts, count, use_small_emr );
+    memcpy( types_dest, types, count );
+    if (count & 3) memset( types_dest + count, 0, 4 - (count & 3) );
+
+    if (!emf->path)
+        get_points_bounds( &emr->rclBounds, pts, count, 0 );
+    else
+        emr->rclBounds = empty_bounds;
+
+    ret = emfdc_record( emf, &emr->emr );
+    if (ret && !emf->path) emfdc_update_bounds( emf, &emr->rclBounds );
+    HeapFree( GetProcessHeap(), 0, emr );
+    return ret;
+}
+
+BOOL EMFDC_ExtFloodFill( WINEDC *dc_attr, INT x, INT y, COLORREF color, UINT fill_type )
+{
+    EMREXTFLOODFILL emr;
+
+    emr.emr.iType = EMR_EXTFLOODFILL;
+    emr.emr.nSize = sizeof(emr);
+    emr.ptlStart.x = x;
+    emr.ptlStart.y = y;
+    emr.crColor = color;
+    emr.iMode = fill_type;
+    return emfdc_record( dc_attr->emf, &emr.emr );
+}
+
+BOOL EMFDC_FillRgn( WINEDC *dc_attr, HRGN hrgn, HBRUSH hbrush )
+{
+    struct emf *emf = dc_attr->emf;
+    EMRFILLRGN *emr;
+    DWORD size, rgnsize, index;
+    BOOL ret;
+
+    if (!(index = emfdc_create_brush( emf, hbrush ))) return FALSE;
+
+    rgnsize = /*NtGdi*/GetRegionData( hrgn, 0, NULL );
+    size = rgnsize + offsetof(EMRFILLRGN,RgnData);
+    emr = HeapAlloc( GetProcessHeap(), 0, size );
+
+    /*NtGdi*/GetRegionData( hrgn, rgnsize, (RGNDATA *)&emr->RgnData );
+
+    emr->emr.iType = EMR_FILLRGN;
+    emr->emr.nSize = size;
+    emr->rclBounds.left   = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.left;
+    emr->rclBounds.top    = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.top;
+    emr->rclBounds.right  = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.right - 1;
+    emr->rclBounds.bottom = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.bottom - 1;
+    emr->cbRgnData = rgnsize;
+    emr->ihBrush = index;
+
+    ret = emfdc_record( emf, &emr->emr );
+    if (ret) emfdc_update_bounds( emf, &emr->rclBounds );
+    HeapFree( GetProcessHeap(), 0, emr );
+    return ret;
+}
+
+BOOL EMFDC_FrameRgn( WINEDC *dc_attr, HRGN hrgn, HBRUSH hbrush, INT width, INT height )
+{
+    struct emf *emf = dc_attr->emf;
+    EMRFRAMERGN *emr;
+    DWORD size, rgnsize, index;
+    BOOL ret;
+
+    index = emfdc_create_brush( emf, hbrush );
+    if(!index) return FALSE;
+
+    rgnsize = /*NtGdi*/GetRegionData( hrgn, 0, NULL );
+    size = rgnsize + offsetof(EMRFRAMERGN,RgnData);
+    emr = HeapAlloc( GetProcessHeap(), 0, size );
+
+    /*NtGdi*/GetRegionData( hrgn, rgnsize, (RGNDATA *)&emr->RgnData );
+
+    emr->emr.iType = EMR_FRAMERGN;
+    emr->emr.nSize = size;
+    emr->rclBounds.left   = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.left;
+    emr->rclBounds.top    = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.top;
+    emr->rclBounds.right  = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.right - 1;
+    emr->rclBounds.bottom = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.bottom - 1;
+    emr->cbRgnData = rgnsize;
+    emr->ihBrush = index;
+    emr->szlStroke.cx = width;
+    emr->szlStroke.cy = height;
+
+    ret = emfdc_record( emf, &emr->emr );
+    if (ret) emfdc_update_bounds( emf, &emr->rclBounds );
+    HeapFree( GetProcessHeap(), 0, emr );
+    return ret;
+}
+
+static BOOL emfdc_paint_invert_region( struct emf *emf, HRGN hrgn, DWORD iType )
+{
+    EMRINVERTRGN *emr;
+    DWORD size, rgnsize;
+    BOOL ret;
+
+    rgnsize = /*NtGdi*/GetRegionData( hrgn, 0, NULL );
+    size = rgnsize + offsetof(EMRINVERTRGN,RgnData);
+    emr = HeapAlloc( GetProcessHeap(), 0, size );
+
+    /*NtGdi*/GetRegionData( hrgn, rgnsize, (RGNDATA *)&emr->RgnData );
+
+    emr->emr.iType = iType;
+    emr->emr.nSize = size;
+    emr->rclBounds.left   = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.left;
+    emr->rclBounds.top    = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.top;
+    emr->rclBounds.right  = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.right - 1;
+    emr->rclBounds.bottom = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.bottom - 1;
+    emr->cbRgnData = rgnsize;
+
+    ret = emfdc_record( emf, &emr->emr );
+    if (ret) emfdc_update_bounds( emf, &emr->rclBounds );
+    HeapFree( GetProcessHeap(), 0, emr );
+    return ret;
+}
+
+BOOL EMFDC_PaintRgn( WINEDC *dc_attr, HRGN hrgn )
+{
+    return emfdc_paint_invert_region( dc_attr->emf, hrgn, EMR_PAINTRGN );
+}
+
+BOOL EMFDC_InvertRgn( WINEDC *dc_attr, HRGN hrgn )
+{
+    return emfdc_paint_invert_region( dc_attr->emf, hrgn, EMR_INVERTRGN );
+}
+
+BOOL EMFDC_ExtTextOut( WINEDC *dc_attr, INT x, INT y, UINT flags, const RECT *rect,
+                       const WCHAR *str, UINT count, const INT *dx )
+{
+    struct emf *emf = dc_attr->emf;
+    FLOAT ex_scale, ey_scale;
+    EMREXTTEXTOUTW *emr;
+    int text_height = 0;
+    int text_width = 0;
+    TEXTMETRICW tm;
+    DWORD size;
+    BOOL ret;
+
+    if (count > INT_MAX) return FALSE;
+
+    size = sizeof(*emr) + ((count+1) & ~1) * sizeof(WCHAR) + count * sizeof(INT);
+
+    TRACE( "%s %s count %d size = %d\n", debugstr_wn(str, count),
+           wine_dbgstr_rect(rect), count, size );
+    emr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
+
+    if (GetGraphicsMode(dc_attr->hdc) == GM_COMPATIBLE)
+    {
+        const INT horzSize = GetDeviceCaps( dc_attr->hdc, HORZSIZE );
+        const INT horzRes  = GetDeviceCaps( dc_attr->hdc, HORZRES );
+        const INT vertSize = GetDeviceCaps( dc_attr->hdc, VERTSIZE );
+        const INT vertRes  = GetDeviceCaps( dc_attr->hdc, VERTRES );
+        SIZE wndext, vportext;
+
+        GetViewportExtEx( dc_attr->hdc, &vportext );
+        GetWindowExtEx( dc_attr->hdc, &wndext );
+        ex_scale = 100.0 * ((FLOAT)horzSize  / (FLOAT)horzRes) /
+            ((FLOAT)wndext.cx / (FLOAT)vportext.cx);
+        ey_scale = 100.0 * ((FLOAT)vertSize  / (FLOAT)vertRes) /
+            ((FLOAT)wndext.cy / (FLOAT)vportext.cy);
+    }
+    else
+    {
+        ex_scale = 0.0;
+        ey_scale = 0.0;
+    }
+
+    emr->emr.iType = EMR_EXTTEXTOUTW;
+    emr->emr.nSize = size;
+    emr->iGraphicsMode = GetGraphicsMode(dc_attr->hdc);
+    emr->exScale = ex_scale;
+    emr->eyScale = ey_scale;
+    emr->emrtext.ptlReference.x = x;
+    emr->emrtext.ptlReference.y = y;
+    emr->emrtext.nChars = count;
+    emr->emrtext.offString = sizeof(*emr);
+    memcpy( (char*)emr + emr->emrtext.offString, str, count * sizeof(WCHAR) );
+    emr->emrtext.fOptions = flags;
+    if (!rect)
+    {
+        emr->emrtext.rcl.left = emr->emrtext.rcl.top = 0;
+        emr->emrtext.rcl.right = emr->emrtext.rcl.bottom = -1;
+    }
+    else
+    {
+        emr->emrtext.rcl.left = rect->left;
+        emr->emrtext.rcl.top = rect->top;
+        emr->emrtext.rcl.right = rect->right;
+        emr->emrtext.rcl.bottom = rect->bottom;
+    }
+
+    emr->emrtext.offDx = emr->emrtext.offString + ((count+1) & ~1) * sizeof(WCHAR);
+    if (dx)
+    {
+        UINT i;
+        SIZE str_size;
+        memcpy( (char*)emr + emr->emrtext.offDx, dx, count * sizeof(INT) );
+        for (i = 0; i < count; i++) text_width += dx[i];
+        if (GetTextExtentPoint32W( dc_attr->hdc, str, count, &str_size ))
+            text_height = str_size.cy;
+    }
+    else
+    {
+        UINT i;
+        INT *emf_dx = (INT *)((char*)emr + emr->emrtext.offDx);
+        SIZE charSize;
+        for (i = 0; i < count; i++)
+        {
+            if (GetTextExtentPoint32W( dc_attr->hdc, str + i, 1, &charSize ))
+            {
+                emf_dx[i] = charSize.cx;
+                text_width += charSize.cx;
+                text_height = max( text_height, charSize.cy );
+            }
+        }
+    }
+
+    if (emf->path)
+    {
+        emr->rclBounds.left = emr->rclBounds.top = 0;
+        emr->rclBounds.right = emr->rclBounds.bottom = -1;
+        goto no_bounds;
+    }
+
+    /* FIXME: handle font escapement */
+    switch (GetTextAlign(dc_attr->hdc) & (TA_LEFT | TA_RIGHT | TA_CENTER))
+    {
+    case TA_CENTER:
+        emr->rclBounds.left  = x - (text_width / 2) - 1;
+        emr->rclBounds.right = x + (text_width / 2) + 1;
+        break;
+
+    case TA_RIGHT:
+        emr->rclBounds.left  = x - text_width - 1;
+        emr->rclBounds.right = x;
+        break;
+
+    default: /* TA_LEFT */
+        emr->rclBounds.left  = x;
+        emr->rclBounds.right = x + text_width + 1;
+    }
+
+    switch (GetTextAlign(dc_attr->hdc) & (TA_TOP | TA_BOTTOM | TA_BASELINE))
+    {
+    case TA_BASELINE:
+        if (!GetTextMetricsW( dc_attr->hdc, &tm )) tm.tmDescent = 0;
+        /* Play safe here... it's better to have a bounding box */
+        /* that is too big than too small. */
+        emr->rclBounds.top    = y - text_height - 1;
+        emr->rclBounds.bottom = y + tm.tmDescent + 1;
+        break;
+
+    case TA_BOTTOM:
+        emr->rclBounds.top    = y - text_height - 1;
+        emr->rclBounds.bottom = y;
+        break;
+
+    default: /* TA_TOP */
+        emr->rclBounds.top    = y;
+        emr->rclBounds.bottom = y + text_height + 1;
+    }
+    emfdc_update_bounds( emf, &emr->rclBounds );
+
+no_bounds:
+    ret = emfdc_record( emf, &emr->emr );
+    HeapFree( GetProcessHeap(), 0, emr );
+    return ret;
+}
+
+BOOL EMFDC_GradientFill( WINEDC *dc_attr, TRIVERTEX *vert_array, ULONG nvert,
+                         void *grad_array, ULONG ngrad, ULONG mode )
+{
+    EMRGRADIENTFILL *emr;
+    ULONG i, pt, size, num_pts = ngrad * (mode == GRADIENT_FILL_TRIANGLE ? 3 : 2);
+    const ULONG *pts = (const ULONG *)grad_array;
+    BOOL ret;
+
+    size = FIELD_OFFSET(EMRGRADIENTFILL, Ver[nvert]) + num_pts * sizeof(pts[0]);
+
+    emr = HeapAlloc( GetProcessHeap(), 0, size );
+    if (!emr) return FALSE;
+
+    for (i = 0; i < num_pts; i++)
+    {
+        pt = pts[i];
+
+        if (i == 0)
+        {
+            emr->rclBounds.left = emr->rclBounds.right = vert_array[pt].x;
+            emr->rclBounds.top = emr->rclBounds.bottom = vert_array[pt].y;
+        }
+        else
+        {
+            if (vert_array[pt].x < emr->rclBounds.left)
+                emr->rclBounds.left = vert_array[pt].x;
+            else if (vert_array[pt].x > emr->rclBounds.right)
+                emr->rclBounds.right = vert_array[pt].x;
+            if (vert_array[pt].y < emr->rclBounds.top)
+                emr->rclBounds.top = vert_array[pt].y;
+            else if (vert_array[pt].y > emr->rclBounds.bottom)
+                emr->rclBounds.bottom = vert_array[pt].y;
+        }
+    }
+    emr->rclBounds.right--;
+    emr->rclBounds.bottom--;
+
+    emr->emr.iType = EMR_GRADIENTFILL;
+    emr->emr.nSize = size;
+    emr->nVer = nvert;
+    emr->nTri = ngrad;
+    emr->ulMode = mode;
+    memcpy( emr->Ver, vert_array, nvert * sizeof(vert_array[0]) );
+    memcpy( emr->Ver + nvert, pts, num_pts * sizeof(pts[0]) );
+
+    emfdc_update_bounds( dc_attr->emf, &emr->rclBounds );
+    ret = emfdc_record( dc_attr->emf, &emr->emr );
+    HeapFree( GetProcessHeap(), 0, emr );
+    return ret;
+}
+
+BOOL EMFDC_FillPath( WINEDC *dc_attr )
+{
+    return emfdrv_stroke_and_fill_path( dc_attr->emf, EMR_FILLPATH );
+}
+
+BOOL EMFDC_StrokeAndFillPath( WINEDC *dc_attr )
+{
+    return emfdrv_stroke_and_fill_path( dc_attr->emf, EMR_STROKEANDFILLPATH );
+}
+
+BOOL EMFDC_StrokePath( WINEDC *dc_attr )
+{
+    return emfdrv_stroke_and_fill_path( dc_attr->emf, EMR_STROKEPATH );
+}
+
+/* Generate an EMRBITBLT, EMRSTRETCHBLT or EMRALPHABLEND record depending on the type parameter */
+static BOOL emfdrv_stretchblt( struct emf *emf, INT x_dst, INT y_dst, INT width_dst, INT height_dst,
+                               HDC hdc_src, INT x_src, INT y_src, INT width_src, INT height_src,
+                               DWORD rop, DWORD type )
+{
+    BITMAPINFO src_info = {{ sizeof( src_info.bmiHeader ) }};
+    UINT bmi_size, emr_size, size;
+    HBITMAP bitmap, blit_bitmap = NULL;
+    EMRBITBLT *emr = NULL;
+    BITMAPINFO *bmi;
+    HDC blit_dc;
+    BOOL ret = FALSE;
+
+    if (hdc_src && GDI_HANDLE_GET_TYPE(hdc_src) == GDILoObjType_LO_ALTDC_TYPE)
+    {
+        WINEDC * pldc = get_dc_ptr(hdc_src);
+        
+        if (pldc->iType == LDC_EMFLDC)
+        {
+            return FALSE;
+        }
+    }
+
+    if (!(bitmap = GetCurrentObject( hdc_src, OBJ_BITMAP ))) return FALSE;
+
+    blit_dc = hdc_src;
+    blit_bitmap = bitmap;
+    if (!(bmi_size = get_bitmap_info( &blit_dc, &blit_bitmap, &src_info ))) return FALSE;
+
+    /* EMRSTRETCHBLT and EMRALPHABLEND have the same structure */
+    emr_size = type == EMR_BITBLT ? sizeof(EMRBITBLT) : sizeof(EMRSTRETCHBLT);
+    size = emr_size + bmi_size + src_info.bmiHeader.biSizeImage;
+
+    if (!(emr = HeapAlloc(GetProcessHeap(), 0, size))) goto err;
+
+    emr->emr.iType = type;
+    emr->emr.nSize = size;
+    emr->rclBounds.left = x_dst;
+    emr->rclBounds.top = y_dst;
+    emr->rclBounds.right = x_dst + width_dst - 1;
+    emr->rclBounds.bottom = y_dst + height_dst - 1;
+    emr->xDest = x_dst;
+    emr->yDest = y_dst;
+    emr->cxDest = width_dst;
+    emr->cyDest = height_dst;
+    emr->xSrc = x_src;
+    emr->ySrc = y_src;
+    if (type != EMR_BITBLT)
+    {
+        EMRSTRETCHBLT *emr_stretchblt = (EMRSTRETCHBLT *)emr;
+        emr_stretchblt->cxSrc = width_src;
+        emr_stretchblt->cySrc = height_src;
+    }
+    emr->dwRop = rop;
+    NtGdiGetTransform( hdc_src, GdiWorldSpaceToDeviceSpace, &emr->xformSrc );
+    emr->crBkColorSrc = GetBkColor( hdc_src );
+    emr->iUsageSrc = DIB_RGB_COLORS;
+    emr->offBmiSrc = emr_size;
+    emr->cbBmiSrc = bmi_size;
+    emr->offBitsSrc = emr_size + bmi_size;
+    emr->cbBitsSrc = src_info.bmiHeader.biSizeImage;
+
+    bmi = (BITMAPINFO *)((BYTE *)emr + emr->offBmiSrc);
+    bmi->bmiHeader = src_info.bmiHeader;
+    ret = GetDIBits( blit_dc, blit_bitmap, 0, src_info.bmiHeader.biHeight,
+                     (BYTE *)emr + emr->offBitsSrc, bmi, DIB_RGB_COLORS );
+
+    if (ret)
+    {
+        ret = emfdc_record( emf, (EMR *)emr );
+        if (ret) emfdc_update_bounds( emf, &emr->rclBounds );
+    }
+
+err:
+    HeapFree( GetProcessHeap(), 0, emr );
+    if (blit_bitmap != bitmap) DeleteObject( blit_bitmap );
+    if (blit_dc != hdc_src) DeleteDC( blit_dc );
+    return ret;
+}
+
+BOOL EMFDC_AlphaBlend( WINEDC *dc_attr, INT x_dst, INT y_dst, INT width_dst, INT height_dst,
+                       HDC hdc_src, INT x_src, INT y_src, INT width_src, INT height_src,
+                       BLENDFUNCTION blend_function )
+{
+    return emfdrv_stretchblt( dc_attr->emf, x_dst, y_dst, width_dst, height_dst, hdc_src,
+                              x_src, y_src, width_src, height_src, *(DWORD *)&blend_function,
+                              EMR_ALPHABLEND );
+}
+
+BOOL EMFDC_PatBlt( WINEDC *dc_attr, INT left, INT top, INT width, INT height, DWORD rop )
+{
+    struct emf *emf = dc_attr->emf;
+    EMRBITBLT emr;
+    BOOL ret;
+
+    emr.emr.iType = EMR_BITBLT;
+    emr.emr.nSize = sizeof(emr);
+    emr.rclBounds.left = left;
+    emr.rclBounds.top = top;
+    emr.rclBounds.right = left + width - 1;
+    emr.rclBounds.bottom = top + height - 1;
+    emr.xDest = left;
+    emr.yDest = top;
+    emr.cxDest = width;
+    emr.cyDest = height;
+    emr.dwRop = rop;
+    emr.xSrc = 0;
+    emr.ySrc = 0;
+    emr.xformSrc.eM11 = 1.0;
+    emr.xformSrc.eM12 = 0.0;
+    emr.xformSrc.eM21 = 0.0;
+    emr.xformSrc.eM22 = 1.0;
+    emr.xformSrc.eDx = 0.0;
+    emr.xformSrc.eDy = 0.0;
+    emr.crBkColorSrc = 0;
+    emr.iUsageSrc = 0;
+    emr.offBmiSrc = 0;
+    emr.cbBmiSrc = 0;
+    emr.offBitsSrc = 0;
+    emr.cbBitsSrc = 0;
+
+    ret = emfdc_record( emf, &emr.emr );
+    if (ret) emfdc_update_bounds( emf, &emr.rclBounds );
+    return ret;
+}
+
+static inline BOOL rop_uses_src( DWORD rop )
+{
+    return ((rop >> 2) & 0x330000) != (rop & 0x330000);
+}
+
+BOOL EMFDC_BitBlt( WINEDC *dc_attr, INT x_dst, INT y_dst, INT width, INT height,
+                   HDC hdc_src, INT x_src, INT y_src, DWORD rop )
+{
+    if (!rop_uses_src( rop )) return EMFDC_PatBlt( dc_attr, x_dst, y_dst, width, height, rop );
+    return emfdrv_stretchblt( dc_attr->emf, x_dst, y_dst, width, height,
+                              hdc_src, x_src, y_src, width, height, rop, EMR_BITBLT );
+}
+
+BOOL EMFDC_StretchBlt( WINEDC *dc_attr, INT x_dst, INT y_dst, INT width_dst, INT height_dst,
+                       HDC hdc_src, INT x_src, INT y_src, INT width_src, INT height_src,
+                       DWORD rop )
+{
+    if (!rop_uses_src( rop )) return EMFDC_PatBlt( dc_attr, x_dst, y_dst, width_dst, height_dst, rop );
+    return emfdrv_stretchblt( dc_attr->emf, x_dst, y_dst, width_dst, height_dst,
+                              hdc_src, x_src, y_src, width_src,
+                              height_src, rop, EMR_STRETCHBLT );
+}
+
+BOOL EMFDC_TransparentBlt( WINEDC *dc_attr, int x_dst, int y_dst, int width_dst, int height_dst,
+                           HDC hdc_src, int x_src, int y_src, int width_src, int height_src,
+                           UINT color )
+{
+    return emfdrv_stretchblt( dc_attr->emf, x_dst, y_dst, width_dst, height_dst,
+                              hdc_src, x_src, y_src, width_src,
+                              height_src, color, EMR_TRANSPARENTBLT );
+}
+
+BOOL EMFDC_MaskBlt( WINEDC *dc_attr, INT x_dst, INT y_dst, INT width_dst, INT height_dst,
+                    HDC hdc_src, INT x_src, INT y_src, HBITMAP mask,
+                    INT x_mask, INT y_mask, DWORD rop )
+{
+    unsigned char mask_info_buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
+    BITMAPINFO *mask_bits_info = (BITMAPINFO *)mask_info_buffer;
+    struct emf *emf = dc_attr->emf;
+    BITMAPINFO mask_info = {{ sizeof( mask_info.bmiHeader ) }};
+    BITMAPINFO src_info = {{ sizeof( src_info.bmiHeader ) }};
+    HBITMAP bitmap, blit_bitmap = NULL, mask_bitmap = NULL;
+    UINT bmi_size, size, mask_info_size = 0;
+    EMRMASKBLT *emr = NULL;
+    BITMAPINFO *bmi;
+    HDC blit_dc, mask_dc = NULL;
+    BOOL ret = FALSE;
+
+    if (!rop_uses_src( rop ))
+        return EMFDC_PatBlt( dc_attr, x_dst, y_dst, width_dst, height_dst, rop );
+
+    if (hdc_src && GDI_HANDLE_GET_TYPE(hdc_src) == GDILoObjType_LO_ALTDC_TYPE)
+    {
+        WINEDC * pldc = get_dc_ptr(hdc_src);
+        
+        if (pldc->iType == LDC_EMFLDC)
+        {
+            return FALSE;
+        }
+    }
+
+    if (!(bitmap = GetCurrentObject( hdc_src, OBJ_BITMAP ))) return FALSE;
+    blit_dc = hdc_src;
+    blit_bitmap = bitmap;
+    if (!(bmi_size = get_bitmap_info( &blit_dc, &blit_bitmap, &src_info ))) return FALSE;
+
+    if (mask)
+    {
+        mask_dc = hdc_src;
+        mask_bitmap = mask;
+        if (!(mask_info_size = get_bitmap_info( &mask_dc, &mask_bitmap, &mask_info ))) goto err;
+        if (mask_info.bmiHeader.biBitCount == 1)
+            mask_info_size = sizeof(BITMAPINFOHEADER); /* don't include colors */
+    }
+    else mask_info.bmiHeader.biSizeImage = 0;
+
+    size = sizeof(*emr) + bmi_size + src_info.bmiHeader.biSizeImage +
+        mask_info_size + mask_info.bmiHeader.biSizeImage;
+
+    if (!(emr = HeapAlloc(GetProcessHeap(), 0, size))) goto err;
+
+    emr->emr.iType = EMR_MASKBLT;
+    emr->emr.nSize = size;
+    emr->rclBounds.left = x_dst;
+    emr->rclBounds.top = y_dst;
+    emr->rclBounds.right = x_dst + width_dst - 1;
+    emr->rclBounds.bottom = y_dst + height_dst - 1;
+    emr->xDest = x_dst;
+    emr->yDest = y_dst;
+    emr->cxDest = width_dst;
+    emr->cyDest = height_dst;
+    emr->dwRop = rop;
+    emr->xSrc = x_src;
+    emr->ySrc = y_src;
+    NtGdiGetTransform( hdc_src, GdiWorldSpaceToDeviceSpace, &emr->xformSrc );
+    emr->crBkColorSrc = GetBkColor( hdc_src );
+    emr->iUsageSrc = DIB_RGB_COLORS;
+    emr->offBmiSrc = sizeof(*emr);
+    emr->cbBmiSrc = bmi_size;
+    emr->offBitsSrc = emr->offBmiSrc + bmi_size;
+    emr->cbBitsSrc = src_info.bmiHeader.biSizeImage;
+    emr->xMask = x_mask;
+    emr->yMask = y_mask;
+    emr->iUsageMask = DIB_PAL_MONO;
+    emr->offBmiMask = mask_info_size ? emr->offBitsSrc + emr->cbBitsSrc : 0;
+    emr->cbBmiMask = mask_info_size;
+    emr->offBitsMask = emr->offBmiMask + emr->cbBmiMask;
+    emr->cbBitsMask = mask_info.bmiHeader.biSizeImage;
+
+    bmi = (BITMAPINFO *)((char *)emr + emr->offBmiSrc);
+    bmi->bmiHeader = src_info.bmiHeader;
+    ret = GetDIBits( blit_dc, blit_bitmap, 0, src_info.bmiHeader.biHeight,
+                     (char *)emr + emr->offBitsSrc, bmi, DIB_RGB_COLORS );
+    if (!ret) goto err;
+
+    if (mask_info_size)
+    {
+        mask_bits_info->bmiHeader = mask_info.bmiHeader;
+        ret = GetDIBits( blit_dc, mask_bitmap, 0, mask_info.bmiHeader.biHeight,
+                         (char *)emr + emr->offBitsMask, mask_bits_info, DIB_RGB_COLORS );
+        if (ret) memcpy( (char *)emr + emr->offBmiMask, mask_bits_info, mask_info_size );
+    }
+
+    if (ret)
+    {
+        ret = emfdc_record( emf, (EMR *)emr );
+        if (ret) emfdc_update_bounds( emf, &emr->rclBounds );
+    }
+
+err:
+    HeapFree( GetProcessHeap(), 0, emr );
+    if (mask_bitmap != mask) DeleteObject( mask_bitmap );
+    if (mask_dc != hdc_src) DeleteObject( mask_dc );
+    if (blit_bitmap != bitmap) DeleteObject( blit_bitmap );
+    if (blit_dc != hdc_src) DeleteDC( blit_dc );
+    return ret;
+}
+
+BOOL EMFDC_PlgBlt( WINEDC *dc_attr, const POINT *points, HDC hdc_src, INT x_src, INT y_src,
+                   INT width, INT height, HBITMAP mask, INT x_mask, INT y_mask )
+{
+    unsigned char mask_info_buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
+    BITMAPINFO *mask_bits_info = (BITMAPINFO *)mask_info_buffer;
+    struct emf *emf = dc_attr->emf;
+    BITMAPINFO mask_info = {{ sizeof( mask_info.bmiHeader ) }};
+    BITMAPINFO src_info = {{ sizeof( src_info.bmiHeader ) }};
+    HBITMAP bitmap, blit_bitmap = NULL, mask_bitmap = NULL;
+    UINT bmi_size, size, mask_info_size = 0;
+    EMRPLGBLT *emr = NULL;
+    BITMAPINFO *bmi;
+    HDC blit_dc, mask_dc = NULL;
+    int x_min, y_min, x_max, y_max, i;
+    BOOL ret = FALSE;
+
+    if (hdc_src && GDI_HANDLE_GET_TYPE(hdc_src) == GDILoObjType_LO_ALTDC_TYPE)
+    {
+        WINEDC * pldc = get_dc_ptr(hdc_src);
+        
+        if (pldc->iType == LDC_EMFLDC)
+        {
+            return FALSE;
+        }
+    }
+
+    if (!(bitmap = GetCurrentObject( hdc_src, OBJ_BITMAP ))) return FALSE;
+
+    blit_dc = hdc_src;
+    blit_bitmap = bitmap;
+    if (!(bmi_size = get_bitmap_info( &blit_dc, &blit_bitmap, &src_info ))) return FALSE;
+
+    if (mask)
+    {
+        mask_dc = hdc_src;
+        mask_bitmap = mask;
+        if (!(mask_info_size = get_bitmap_info( &mask_dc, &mask_bitmap, &mask_info ))) goto err;
+        if (mask_info.bmiHeader.biBitCount == 1)
+            mask_info_size = sizeof(BITMAPINFOHEADER); /* don't include colors */
+    }
+    else mask_info.bmiHeader.biSizeImage = 0;
+
+    size = sizeof(*emr) + bmi_size + src_info.bmiHeader.biSizeImage +
+        mask_info_size + mask_info.bmiHeader.biSizeImage;
+
+    if (!(emr = HeapAlloc(GetProcessHeap(), 0, size))) goto err;
+
+    emr->emr.iType = EMR_PLGBLT;
+    emr->emr.nSize = size;
+
+    /* FIXME: not exactly what native does */
+    x_min = x_max = points[1].x + points[2].x - points[0].x;
+    y_min = y_max = points[1].y + points[2].y - points[0].y;
+    for (i = 0; i < ARRAYSIZE(emr->aptlDest); i++)
+    {
+        x_min = min( x_min, points[i].x );
+        y_min = min( y_min, points[i].y );
+        x_max = max( x_max, points[i].x );
+        y_max = max( y_min, points[i].y );
+    }
+    emr->rclBounds.left = x_min;
+    emr->rclBounds.top = y_min;
+    emr->rclBounds.right = x_max;
+    emr->rclBounds.bottom = y_max;
+    memcpy( emr->aptlDest, points, sizeof(emr->aptlDest) );
+    emr->xSrc = x_src;
+    emr->ySrc = y_src;
+    emr->cxSrc = width;
+    emr->cySrc = height;
+    NtGdiGetTransform( hdc_src, GdiWorldSpaceToDeviceSpace, &emr->xformSrc );
+    emr->crBkColorSrc = GetBkColor( hdc_src );
+    emr->iUsageSrc = DIB_RGB_COLORS;
+    emr->offBmiSrc = sizeof(*emr);
+    emr->cbBmiSrc = bmi_size;
+    emr->offBitsSrc = emr->offBmiSrc + bmi_size;
+    emr->cbBitsSrc = src_info.bmiHeader.biSizeImage;
+    emr->xMask = x_mask;
+    emr->yMask = y_mask;
+    emr->iUsageMask = DIB_PAL_MONO;
+    emr->offBmiMask = mask_info_size ? emr->offBitsSrc + emr->cbBitsSrc : 0;
+    emr->cbBmiMask = mask_info_size;
+    emr->offBitsMask = emr->offBmiMask + emr->cbBmiMask;
+    emr->cbBitsMask = mask_info.bmiHeader.biSizeImage;
+
+    bmi = (BITMAPINFO *)((char *)emr + emr->offBmiSrc);
+    bmi->bmiHeader = src_info.bmiHeader;
+    ret = GetDIBits( blit_dc, blit_bitmap, 0, src_info.bmiHeader.biHeight,
+                     (char *)emr + emr->offBitsSrc, bmi, DIB_RGB_COLORS );
+    if (!ret) goto err;
+
+    if (mask_info_size)
+    {
+        mask_bits_info->bmiHeader = mask_info.bmiHeader;
+        ret = GetDIBits( blit_dc, mask_bitmap, 0, mask_info.bmiHeader.biHeight,
+                         (char *)emr + emr->offBitsMask, mask_bits_info, DIB_RGB_COLORS );
+        if (ret) memcpy( (char *)emr + emr->offBmiMask, mask_bits_info, mask_info_size );
+    }
+
+    if (ret)
+    {
+        ret = emfdc_record( emf, (EMR *)emr );
+        if (ret) emfdc_update_bounds( emf, &emr->rclBounds );
+    }
+
+err:
+    HeapFree( GetProcessHeap(), 0, emr );
+    if (mask_bitmap != mask) DeleteObject( mask_bitmap );
+    if (mask_dc != hdc_src) DeleteObject( mask_dc );
+    if (blit_bitmap != bitmap) DeleteObject( blit_bitmap );
+    if (blit_dc != hdc_src) DeleteDC( blit_dc );
+    return ret;
+}
+
+BOOL EMFDC_StretchDIBits( WINEDC *dc_attr, INT x_dst, INT y_dst, INT width_dst, INT height_dst,
+                          INT x_src, INT y_src, INT width_src, INT height_src, const void *bits,
+                          const BITMAPINFO *info, UINT usage, DWORD rop )
+{
+    EMRSTRETCHDIBITS *emr;
+    BOOL ret;
+    UINT bmi_size, emr_size;
+
+    /* calculate the size of the colour table */
+    bmi_size = get_dib_info_size( info, usage );
+
+    emr_size = sizeof (EMRSTRETCHDIBITS) + bmi_size + info->bmiHeader.biSizeImage;
+    if (!(emr = HeapAlloc(GetProcessHeap(), 0, emr_size ))) return 0;
+
+    /* write a bitmap info header (with colours) to the record */
+    memcpy( &emr[1], info, bmi_size);
+
+    /* write bitmap bits to the record */
+    memcpy ( (BYTE *)&emr[1] + bmi_size, bits, info->bmiHeader.biSizeImage );
+
+    /* fill in the EMR header at the front of our piece of memory */
+    emr->emr.iType = EMR_STRETCHDIBITS;
+    emr->emr.nSize = emr_size;
+
+    emr->xDest     = x_dst;
+    emr->yDest     = y_dst;
+    emr->cxDest    = width_dst;
+    emr->cyDest    = height_dst;
+    emr->dwRop     = rop;
+    emr->xSrc      = x_src;
+    emr->ySrc      = y_src;
+
+    emr->iUsageSrc    = usage;
+    emr->offBmiSrc    = sizeof (EMRSTRETCHDIBITS);
+    emr->cbBmiSrc     = bmi_size;
+    emr->offBitsSrc   = emr->offBmiSrc + bmi_size;
+    emr->cbBitsSrc    = info->bmiHeader.biSizeImage;
+
+    emr->cxSrc = width_src;
+    emr->cySrc = height_src;
+
+    emr->rclBounds.left   = x_dst;
+    emr->rclBounds.top    = y_dst;
+    emr->rclBounds.right  = x_dst + width_dst;
+    emr->rclBounds.bottom = y_dst + height_dst;
+
+    /* save the record we just created */
+    ret = emfdc_record( dc_attr->emf, &emr->emr );
+    if (ret) emfdc_update_bounds( dc_attr->emf, &emr->rclBounds );
+    HeapFree( GetProcessHeap(), 0, emr );
+    return ret;
+}
+
+BOOL EMFDC_SetDIBitsToDevice( WINEDC *dc_attr, INT x_dst, INT y_dst, DWORD width, DWORD height,
+                              INT x_src, INT y_src, UINT startscan, UINT lines,
+                              const void *bits, const BITMAPINFO *info, UINT usage )
+{
+    EMRSETDIBITSTODEVICE *emr;
+    DWORD bmiSize = get_dib_info_size( info, usage );
+    DWORD size = sizeof(EMRSETDIBITSTODEVICE) + bmiSize + info->bmiHeader.biSizeImage;
+    BOOL ret;
+
+    if (!(emr = HeapAlloc( GetProcessHeap(), 0, size ))) return FALSE;
+
+    emr->emr.iType = EMR_SETDIBITSTODEVICE;
+    emr->emr.nSize = size;
+    emr->rclBounds.left = x_dst;
+    emr->rclBounds.top = y_dst;
+    emr->rclBounds.right = x_dst + width - 1;
+    emr->rclBounds.bottom = y_dst + height - 1;
+    emr->xDest = x_dst;
+    emr->yDest = y_dst;
+    emr->xSrc = x_src;
+    emr->ySrc = y_src;
+    emr->cxSrc = width;
+    emr->cySrc = height;
+    emr->offBmiSrc = sizeof(EMRSETDIBITSTODEVICE);
+    emr->cbBmiSrc = bmiSize;
+    emr->offBitsSrc = sizeof(EMRSETDIBITSTODEVICE) + bmiSize;
+    emr->cbBitsSrc = info->bmiHeader.biSizeImage;
+    emr->iUsageSrc = usage;
+    emr->iStartScan = startscan;
+    emr->cScans = lines;
+    memcpy( (BYTE*)emr + emr->offBmiSrc, info, bmiSize );
+    memcpy( (BYTE*)emr + emr->offBitsSrc, bits, info->bmiHeader.biSizeImage );
+
+    if ((ret = emfdc_record( dc_attr->emf, (EMR*)emr )))
+        emfdc_update_bounds( dc_attr->emf, &emr->rclBounds );
+
+    HeapFree( GetProcessHeap(), 0, emr );
+    return ret;
+}
+
+BOOL EMFDC_SetDCBrushColor( WINEDC *dc_attr, COLORREF color )
+{
+    struct emf *emf = dc_attr->emf;
+    EMRSELECTOBJECT emr;
+    DWORD index;
+
+    if (GetCurrentObject( dc_attr->hdc, OBJ_BRUSH ) != GetStockObject( DC_BRUSH )) return TRUE;
+
+    if (emf->dc_brush) DeleteObject( emf->dc_brush );
+    if (!(emf->dc_brush = CreateSolidBrush( color ))) return FALSE;
+    if (!(index = emfdc_create_brush( emf, emf->dc_brush ))) return FALSE;
+    GDI_hdc_using_object( emf->dc_brush, dc_attr->hdc);//, emfdc_delete_object );
+    emr.emr.iType = EMR_SELECTOBJECT;
+    emr.emr.nSize = sizeof(emr);
+    emr.ihObject = index;
+    return emfdc_record( emf, &emr.emr );
+}
+
+BOOL EMFDC_SetDCPenColor( WINEDC *dc_attr, COLORREF color )
+{
+    struct emf *emf = dc_attr->emf;
+    EMRSELECTOBJECT emr;
+    DWORD index;
+    LOGPEN logpen = { PS_SOLID, { 0, 0 }, color };
+
+    if (GetCurrentObject( dc_attr->hdc, OBJ_PEN ) != GetStockObject( DC_PEN )) return TRUE;
+
+    if (emf->dc_pen) DeleteObject( emf->dc_pen );
+    if (!(emf->dc_pen = CreatePenIndirect( &logpen ))) return FALSE;
+    if (!(index = emfdc_create_pen( emf, emf->dc_pen ))) return FALSE;
+    GDI_hdc_using_object( emf->dc_pen, dc_attr->hdc);//, emfdc_delete_object );
+    emr.emr.iType = EMR_SELECTOBJECT;
+    emr.emr.nSize = sizeof(emr);
+    emr.ihObject = index;
+    return emfdc_record( emf, &emr.emr );
+}
+
+BOOL EMFDC_SaveDC( WINEDC *dc_attr )
+{
+    EMRSAVEDC emr;
+
+    emr.emr.iType = EMR_SAVEDC;
+    emr.emr.nSize = sizeof(emr);
+    return emfdc_record( dc_attr->emf, &emr.emr );
+}
+#define GdiGetEMFRestorDc 5
+BOOL EMFDC_RestoreDC( WINEDC *dc_attr, INT level )
+{
+    EMRRESTOREDC emr;
+
+    /* The Restore DC function needs the save level to be set correctly.
+       Note that wine's level is 0 based, while our's is (like win) 1 based. */
+    dc_attr->save_level = GetDCDWord(dc_attr->hdc, GdiGetEMFRestorDc, 0)  - 1;
+
+    if (abs(level) > dc_attr->save_level || level == 0) return FALSE;
+
+    emr.emr.iType = EMR_RESTOREDC;
+    emr.emr.nSize = sizeof(emr);
+    if (level < 0)
+        emr.iRelative = level;
+    else
+        emr.iRelative = level - dc_attr->save_level - 1;
+    return emfdc_record( dc_attr->emf, &emr.emr );
+}
+
+BOOL EMFDC_SetTextAlign( WINEDC *dc_attr, UINT align )
+{
+    EMRSETTEXTALIGN emr;
+
+    emr.emr.iType = EMR_SETTEXTALIGN;
+    emr.emr.nSize = sizeof(emr);
+    emr.iMode = align;
+    return emfdc_record( dc_attr->emf, &emr.emr );
+}
+
+BOOL EMFDC_SetTextJustification( WINEDC *dc_attr, INT extra, INT breaks )
+{
+    EMRSETTEXTJUSTIFICATION emr;
+
+    emr.emr.iType = EMR_SETTEXTJUSTIFICATION;
+    emr.emr.nSize = sizeof(emr);
+    emr.nBreakExtra = extra;
+    emr.nBreakCount = breaks;
+    return emfdc_record( dc_attr->emf, &emr.emr );
+}
+
+BOOL EMFDC_SetBkMode( WINEDC *dc_attr, INT mode )
+{
+    EMRSETBKMODE emr;
+
+    emr.emr.iType = EMR_SETBKMODE;
+    emr.emr.nSize = sizeof(emr);
+    emr.iMode = mode;
+    return emfdc_record( dc_attr->emf, &emr.emr );
+}
+
+BOOL EMFDC_SetBkColor( WINEDC *dc_attr, COLORREF color )
+{
+    EMRSETBKCOLOR emr;
+
+    emr.emr.iType = EMR_SETBKCOLOR;
+    emr.emr.nSize = sizeof(emr);
+    emr.crColor = color;
+    return emfdc_record( dc_attr->emf, &emr.emr );
+}
+
+BOOL EMFDC_SetTextColor( WINEDC *dc_attr, COLORREF color )
+{
+    EMRSETTEXTCOLOR emr;
+
+    emr.emr.iType = EMR_SETTEXTCOLOR;
+    emr.emr.nSize = sizeof(emr);
+    emr.crColor = color;
+    return emfdc_record( dc_attr->emf, &emr.emr );
+}
+
+BOOL EMFDC_SetROP2( WINEDC *dc_attr, INT rop )
+{
+    EMRSETROP2 emr;
+
+    emr.emr.iType = EMR_SETROP2;
+    emr.emr.nSize = sizeof(emr);
+    emr.iMode = rop;
+    return emfdc_record( dc_attr->emf, &emr.emr );
+}
+
+BOOL EMFDC_SetPolyFillMode( WINEDC *dc_attr, INT mode )
+{
+    EMRSETPOLYFILLMODE emr;
+
+    emr.emr.iType = EMR_SETPOLYFILLMODE;
+    emr.emr.nSize = sizeof(emr);
+    emr.iMode = mode;
+    return emfdc_record( dc_attr->emf, &emr.emr );
+}
+
+BOOL EMFDC_SetStretchBltMode( WINEDC *dc_attr, INT mode )
+{
+    EMRSETSTRETCHBLTMODE emr;
+
+    emr.emr.iType = EMR_SETSTRETCHBLTMODE;
+    emr.emr.nSize = sizeof(emr);
+    emr.iMode = mode;
+    return emfdc_record( dc_attr->emf, &emr.emr );
+}
+
+BOOL EMFDC_SetArcDirection( WINEDC *dc_attr, INT dir )
+{
+    EMRSETARCDIRECTION emr;
+
+    emr.emr.iType = EMR_SETARCDIRECTION;
+    emr.emr.nSize = sizeof(emr);
+    emr.iArcDirection = dir;
+    return emfdc_record( dc_attr->emf, &emr.emr );
+}
+
+INT EMFDC_ExcludeClipRect( WINEDC *dc_attr, INT left, INT top, INT right, INT bottom )
+{
+    EMREXCLUDECLIPRECT emr;
+
+    emr.emr.iType      = EMR_EXCLUDECLIPRECT;
+    emr.emr.nSize      = sizeof(emr);
+    emr.rclClip.left   = left;
+    emr.rclClip.top    = top;
+    emr.rclClip.right  = right;
+    emr.rclClip.bottom = bottom;
+    return emfdc_record( dc_attr->emf, &emr.emr );
+}
+
+BOOL EMFDC_IntersectClipRect( WINEDC *dc_attr, INT left, INT top, INT right, INT bottom)
+{
+    EMRINTERSECTCLIPRECT emr;
+
+    emr.emr.iType      = EMR_INTERSECTCLIPRECT;
+    emr.emr.nSize      = sizeof(emr);
+    emr.rclClip.left   = left;
+    emr.rclClip.top    = top;
+    emr.rclClip.right  = right;
+    emr.rclClip.bottom = bottom;
+    return emfdc_record( dc_attr->emf, &emr.emr );
+}
+
+BOOL EMFDC_OffsetClipRgn( WINEDC *dc_attr, INT x, INT y )
+{
+    EMROFFSETCLIPRGN emr;
+
+    emr.emr.iType   = EMR_OFFSETCLIPRGN;
+    emr.emr.nSize   = sizeof(emr);
+    emr.ptlOffset.x = x;
+    emr.ptlOffset.y = y;
+    return emfdc_record( dc_attr->emf, &emr.emr );
+}
+
+BOOL EMFDC_ExtSelectClipRgn( WINEDC *dc_attr, HRGN hrgn, INT mode )
+{
+    EMREXTSELECTCLIPRGN *emr;
+    DWORD size, rgnsize;
+    BOOL ret;
+
+    if (!hrgn)
+    {
+        if (mode != RGN_COPY) return ERROR;
+        rgnsize = 0;
+    }
+    else rgnsize = /*NtGdi*/GetRegionData( hrgn, 0, NULL );
+
+    size = rgnsize + offsetof(EMREXTSELECTCLIPRGN,RgnData);
+    emr = HeapAlloc( GetProcessHeap(), 0, size );
+    if (rgnsize) /*NtGdi*/GetRegionData( hrgn, rgnsize, (RGNDATA *)&emr->RgnData );
+
+    emr->emr.iType = EMR_EXTSELECTCLIPRGN;
+    emr->emr.nSize = size;
+    emr->cbRgnData = rgnsize;
+    emr->iMode     = mode;
+
+    ret = emfdc_record( dc_attr->emf, &emr->emr );
+    HeapFree( GetProcessHeap(), 0, emr );
+    return ret;
+}
+
+BOOL EMFDC_SetMapMode( WINEDC *dc_attr, INT mode )
+{
+    EMRSETMAPMODE emr;
+
+    emr.emr.iType = EMR_SETMAPMODE;
+    emr.emr.nSize = sizeof(emr);
+    emr.iMode = mode;
+    return emfdc_record( dc_attr->emf, &emr.emr );
+}
+
+BOOL EMFDC_SetViewportExtEx( WINEDC *dc_attr, INT cx, INT cy )
+{
+    EMRSETVIEWPORTEXTEX emr;
+
+    emr.emr.iType = EMR_SETVIEWPORTEXTEX;
+    emr.emr.nSize = sizeof(emr);
+    emr.szlExtent.cx = cx;
+    emr.szlExtent.cy = cy;
+    return emfdc_record( dc_attr->emf, &emr.emr );
+}
+
+BOOL EMFDC_SetWindowExtEx( WINEDC *dc_attr, INT cx, INT cy )
+{
+    EMRSETWINDOWEXTEX emr;
+
+    emr.emr.iType = EMR_SETWINDOWEXTEX;
+    emr.emr.nSize = sizeof(emr);
+    emr.szlExtent.cx = cx;
+    emr.szlExtent.cy = cy;
+    return emfdc_record( dc_attr->emf, &emr.emr );
+}
+
+BOOL EMFDC_SetViewportOrgEx( WINEDC *dc_attr, INT x, INT y )
+{
+    EMRSETVIEWPORTORGEX emr;
+
+    emr.emr.iType = EMR_SETVIEWPORTORGEX;
+    emr.emr.nSize = sizeof(emr);
+    emr.ptlOrigin.x = x;
+    emr.ptlOrigin.y = y;
+    return emfdc_record( dc_attr->emf, &emr.emr );
+}
+
+BOOL EMFDC_SetWindowOrgEx( WINEDC *dc_attr, INT x, INT y )
+{
+    EMRSETWINDOWORGEX emr;
+
+    emr.emr.iType = EMR_SETWINDOWORGEX;
+    emr.emr.nSize = sizeof(emr);
+    emr.ptlOrigin.x = x;
+    emr.ptlOrigin.y = y;
+    return emfdc_record( dc_attr->emf, &emr.emr );
+}
+
+BOOL EMFDC_ScaleViewportExtEx( WINEDC *dc_attr, INT x_num, INT x_denom, INT y_num, INT y_denom )
+{
+    EMRSCALEVIEWPORTEXTEX emr;
+
+    emr.emr.iType = EMR_SCALEVIEWPORTEXTEX;
+    emr.emr.nSize = sizeof(emr);
+    emr.xNum      = x_num;
+    emr.xDenom    = x_denom;
+    emr.yNum      = y_num;
+    emr.yDenom    = y_denom;
+    return emfdc_record( dc_attr->emf, &emr.emr );
+}
+
+BOOL EMFDC_ScaleWindowExtEx( WINEDC *dc_attr, INT x_num, INT x_denom, INT y_num, INT y_denom )
+{
+    EMRSCALEWINDOWEXTEX emr;
+
+    emr.emr.iType = EMR_SCALEWINDOWEXTEX;
+    emr.emr.nSize = sizeof(emr);
+    emr.xNum      = x_num;
+    emr.xDenom    = x_denom;
+    emr.yNum      = y_num;
+    emr.yDenom    = y_denom;
+    return emfdc_record( dc_attr->emf, &emr.emr );
+}
+
+BOOL EMFDC_SetLayout( WINEDC *dc_attr, DWORD layout )
+{
+    EMRSETLAYOUT emr;
+
+    emr.emr.iType = EMR_SETLAYOUT;
+    emr.emr.nSize = sizeof(emr);
+    emr.iMode = layout;
+    return emfdc_record( dc_attr->emf, &emr.emr );
+}
+
+BOOL EMFDC_SetWorldTransform( WINEDC *dc_attr, const XFORM *xform )
+{
+    EMRSETWORLDTRANSFORM emr;
+
+    emr.emr.iType = EMR_SETWORLDTRANSFORM;
+    emr.emr.nSize = sizeof(emr);
+    emr.xform = *xform;
+    return emfdc_record( dc_attr->emf, &emr.emr );
+}
+
+BOOL EMFDC_ModifyWorldTransform( WINEDC *dc_attr, const XFORM *xform, DWORD mode )
+{
+    EMRMODIFYWORLDTRANSFORM emr;
+
+    emr.emr.iType = EMR_MODIFYWORLDTRANSFORM;
+    emr.emr.nSize = sizeof(emr);
+    if (mode == MWT_IDENTITY)
+    {
+        emr.xform.eM11 = 1.0f;
+        emr.xform.eM12 = 0.0f;
+        emr.xform.eM21 = 0.0f;
+        emr.xform.eM22 = 1.0f;
+        emr.xform.eDx = 0.0f;
+        emr.xform.eDy = 0.0f;
+    }
+    else
+    {
+        emr.xform = *xform;
+    }
+    emr.iMode = mode;
+    return emfdc_record( dc_attr->emf, &emr.emr );
+}
+
+BOOL EMFDC_SetMapperFlags( WINEDC *dc_attr, DWORD flags )
+{
+    EMRSETMAPPERFLAGS emr;
+
+    emr.emr.iType = EMR_SETMAPPERFLAGS;
+    emr.emr.nSize = sizeof(emr);
+    emr.dwFlags   = flags;
+    return emfdc_record( dc_attr->emf, &emr.emr );
+}
+
+BOOL EMFDC_AbortPath( WINEDC *dc_attr )
+{
+    struct emf *emf = dc_attr->emf;
+    EMRABORTPATH emr;
+
+    emr.emr.iType = EMR_ABORTPATH;
+    emr.emr.nSize = sizeof(emr);
+
+    emf->path = FALSE;
+    return emfdc_record( dc_attr->emf, &emr.emr );
+}
+
+BOOL EMFDC_BeginPath( WINEDC *dc_attr )
+{
+    struct emf *emf = dc_attr->emf;
+    EMRBEGINPATH emr;
+
+    emr.emr.iType = EMR_BEGINPATH;
+    emr.emr.nSize = sizeof(emr);
+    if (!emfdc_record( emf, &emr.emr )) return FALSE;
+
+    emf->path = TRUE;
+    return TRUE;
+}
+
+BOOL EMFDC_CloseFigure( WINEDC *dc_attr )
+{
+    EMRCLOSEFIGURE emr;
+
+    emr.emr.iType = EMR_CLOSEFIGURE;
+    emr.emr.nSize = sizeof(emr);
+    return emfdc_record( dc_attr->emf, &emr.emr );
+}
+
+BOOL EMFDC_EndPath( WINEDC *dc_attr )
+{
+    struct emf *emf = dc_attr->emf;
+    EMRENDPATH emr;
+
+    emf->path = FALSE;
+
+    emr.emr.iType = EMR_ENDPATH;
+    emr.emr.nSize = sizeof(emr);
+    return emfdc_record( emf, &emr.emr );
+}
+
+BOOL EMFDC_FlattenPath( WINEDC *dc_attr )
+{
+    EMRFLATTENPATH emr;
+
+    emr.emr.iType = EMR_FLATTENPATH;
+    emr.emr.nSize = sizeof(emr);
+    return emfdc_record( dc_attr->emf, &emr.emr );
+}
+
+BOOL EMFDC_SelectClipPath( WINEDC *dc_attr, INT mode )
+{
+    EMRSELECTCLIPPATH emr;
+
+    emr.emr.iType = EMR_SELECTCLIPPATH;
+    emr.emr.nSize = sizeof(emr);
+    emr.iMode = mode;
+    return emfdc_record( dc_attr->emf, &emr.emr );
+}
+
+BOOL EMFDC_WidenPath( WINEDC *dc_attr )
+{
+    EMRWIDENPATH emr;
+
+    emr.emr.iType = EMR_WIDENPATH;
+    emr.emr.nSize = sizeof(emr);
+    return emfdc_record( dc_attr->emf, &emr.emr );
+}
+
+void EMFDC_DeleteDC( WINEDC *dc_attr )
+{
+    struct emf *emf = dc_attr->emf;
+    UINT index;
+
+    HeapFree( GetProcessHeap(), 0, emf->emh );
+    for (index = 0; index < emf->handles_size; index++)
+        if (emf->handles[index])
+            GDI_hdc_not_using_object( emf->handles[index], emf->dc_attr->hdc );
+    HeapFree( GetProcessHeap(), 0, emf->handles );
+}
+
+//
+// Waiting on wine support....
+//
+
+
+//
+// ReactOS Print Support
+//
+INT
+EMFDC_WriteEscape( WINEDC *dc_attr, INT nEscape, INT cbInput, LPSTR lpszInData, DWORD emrType)
+{
+    PEMRESCAPE pemr;
+    UINT total, rounded_size;
+    INT ret;
+
+    rounded_size = (cbInput+3) & ~3;
+    total = offsetof(EMRESCAPE,Data) + rounded_size;
+
+    pemr = RtlAllocateHeap( GetProcessHeap(), 0, total );
+    if ( !pemr )
+        return 0;
+
+    RtlZeroMemory( pemr, total );
+
+    pemr->emr.iType = emrType;
+    pemr->emr.nSize = total;
+    pemr->iEsc      = nEscape;
+    pemr->cjIn      = cbInput;
+
+    RtlCopyMemory( &pemr->Data[0], lpszInData, cbInput );
+
+    ret = emfdc_record( dc_attr->emf, &pemr->emr );
+
+    RtlFreeHeap( GetProcessHeap(), 0, pemr );
+    return ret;
+}
+
+INT
+EMFDC_WriteNamedEscape( WINEDC *dc_attr, PWCHAR pDriver, INT nEscape, INT cbInput, LPCSTR lpszInData)
+{
+    PEMRNAMEDESCAPE pemr;
+    UINT sizestr, total, rounded_size;
+    INT ret;
+
+    rounded_size = (cbInput+3) & ~3;
+    total = offsetof(EMRNAMEDESCAPE,Data) + rounded_size;
+
+    total += sizestr = (wcslen(pDriver) + 1 ) * sizeof(WCHAR);
+
+    pemr = RtlAllocateHeap( GetProcessHeap(), 0, total );
+    if ( !pemr )
+        return 0;
+
+    RtlZeroMemory( pemr, total );
+
+    pemr->emr.iType = EMR_NAMEDESCAPE;
+    pemr->emr.nSize = total;
+    pemr->iEsc      = nEscape;
+    pemr->cjIn      = cbInput;
+
+    RtlCopyMemory( &pemr->Data[0], lpszInData, cbInput );
+    //
+    // WARNING :
+    //   Need to remember with wine, theses headers are relocatable.
+    RtlCopyMemory( &pemr->Data[rounded_size], pDriver, sizestr );
+
+    ret = emfdc_record( dc_attr->emf, &pemr->emr );
+
+    RtlFreeHeap( GetProcessHeap(), 0, pemr );
+    return ret;
+}
+
+BOOL
+EMFDC_SetMetaRgn( WINEDC *dc_attr )
+{
+    EMRSETMETARGN emr;
+
+    emr.emr.iType = EMR_SETMETARGN;
+    emr.emr.nSize = sizeof(emr);
+
+    return emfdc_record( dc_attr->emf, &emr.emr );
+}
+
+BOOL
+EMFDC_SetBrushOrg( WINEDC *dc_attr, INT x, INT y)
+{
+    EMRSETBRUSHORGEX emr;
+
+    emr.emr.iType = EMR_SETBRUSHORGEX;
+    emr.emr.nSize = sizeof(emr);
+    emr.ptlOrigin.x = x;
+    emr.ptlOrigin.y = y;
+
+    return emfdc_record( dc_attr->emf, &emr.emr );
+}
+
+/*******************************************************************
+ *      GdiComment   (GDI32.@)
+ */
+BOOL WINAPI EMFDC_GdiComment( HDC hdc, UINT bytes, const BYTE *buffer )
+{
+    WINEDC *dc_attr;
+    EMRGDICOMMENT *emr;
+    UINT total, rounded_size;
+    BOOL ret;
+
+    if (!(dc_attr = get_dc_ptr( hdc )) || !dc_attr->emf) return FALSE;
+
+    rounded_size = (bytes+3) & ~3;
+    total = offsetof(EMRGDICOMMENT,Data) + rounded_size;
+
+    emr = HeapAlloc(GetProcessHeap(), 0, total);
+    emr->emr.iType = EMR_GDICOMMENT;
+    emr->emr.nSize = total;
+    emr->cbData = bytes;
+    memset(&emr->Data[bytes], 0, rounded_size - bytes);
+    memcpy(&emr->Data[0], buffer, bytes);
+
+    ret = emfdc_record( dc_attr->emf, &emr->emr );
+
+    HeapFree(GetProcessHeap(), 0, emr);
+
+    return ret;
+}
+
+/**********************************************************************
+ *           CreateEnhMetaFileA   (GDI32.@)
+ */
+HDC WINAPI CreateEnhMetaFileA( HDC hdc, const char *filename, const RECT *rect,
+                               const char *description )
+{
+    WCHAR *filenameW = NULL;
+    WCHAR *descriptionW = NULL;
+    DWORD len1, len2, total;
+    HDC ret;
+
+    if (filename)
+    {
+        total = MultiByteToWideChar( CP_ACP, 0, filename, -1, NULL, 0 );
+        filenameW = HeapAlloc( GetProcessHeap(), 0, total * sizeof(WCHAR) );
+        MultiByteToWideChar( CP_ACP, 0, filename, -1, filenameW, total );
+    }
+
+    if(description)
+    {
+        len1 = strlen(description);
+        len2 = strlen(description + len1 + 1);
+        total = MultiByteToWideChar( CP_ACP, 0, description, len1 + len2 + 3, NULL, 0 );
+        descriptionW = HeapAlloc( GetProcessHeap(), 0, total * sizeof(WCHAR) );
+        MultiByteToWideChar( CP_ACP, 0, description, len1 + len2 + 3, descriptionW, total );
+    }
+
+    ret = CreateEnhMetaFileW( hdc, filenameW, rect, descriptionW );
+
+    HeapFree( GetProcessHeap(), 0, filenameW );
+    HeapFree( GetProcessHeap(), 0, descriptionW );
+    return ret;
+}
+
+/**********************************************************************
+ *           CreateEnhMetaFileW   (GDI32.@)
+ */
+HDC WINAPI CreateEnhMetaFileW( HDC hdc, const WCHAR *filename, const RECT *rect,
+                               const WCHAR *description )
+{
+    HDC ret;
+    struct emf *emf;
+    WINEDC *dc_attr;
+    HANDLE file;
+    DWORD size = 0, length = 0;
+
+    TRACE( "(%p %s %s %s)\n", hdc, debugstr_w(filename), wine_dbgstr_rect(rect),
+           debugstr_w(description) );
+
+    //if (!(ret = NtGdiCreateMetafileDC( hdc ))) return 0;
+    if(!(dc_attr = alloc_dc_ptr(OBJ_ENHMETADC)))
+    {
+       if (dc_attr->hdc) DeleteDC( dc_attr->hdc );
+       return 0;
+    }
+
+    ret = dc_attr->hdc;
+
+    if (/*!(dc_attr = get_dc_ptr( ret )) ||*/ !(emf = HeapAlloc( GetProcessHeap(), 0, sizeof(*emf) )))
+    {
+        DeleteDC( ret );
+        return 0;
+    }
+
+    emf->dc_attr = dc_attr;
+    dc_attr->emf = emf;
+
+    if (description) /* App name\0Title\0\0 */
+    {
+        length = lstrlenW( description );
+        length += lstrlenW( description + length + 1 );
+        length += 3;
+        length *= 2;
+    }
+    size = sizeof(ENHMETAHEADER) + (length + 3) / 4 * 4;
+
+    if (!(emf->emh = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size)))
+    {
+        DeleteDC( ret );
+        return 0;
+    }
+    emf->dc_attr = dc_attr;
+
+    emf->handles = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
+                              HANDLE_LIST_INC * sizeof(emf->handles[0]) );
+    emf->handles_size = HANDLE_LIST_INC;
+    emf->cur_handles = 1;
+    emf->file = 0;
+    emf->dc_brush = 0;
+    emf->dc_pen = 0;
+    emf->path = FALSE;
+
+    emf->emh->iType = EMR_HEADER;
+    emf->emh->nSize = size;
+
+    dc_attr->emf_bounds.left = dc_attr->emf_bounds.top = 0;
+    dc_attr->emf_bounds.right = dc_attr->emf_bounds.bottom = -1;
+
+    if (rect)
+    {
+        emf->emh->rclFrame.left   = rect->left;
+        emf->emh->rclFrame.top    = rect->top;
+        emf->emh->rclFrame.right  = rect->right;
+        emf->emh->rclFrame.bottom = rect->bottom;
+    }
+    else
+    {
+        /* Set this to {0,0 - -1,-1} and update it at the end */
+        emf->emh->rclFrame.left = emf->emh->rclFrame.top = 0;
+        emf->emh->rclFrame.right = emf->emh->rclFrame.bottom = -1;
+    }
+
+    emf->emh->dSignature = ENHMETA_SIGNATURE;
+    emf->emh->nVersion = 0x10000;
+    emf->emh->nBytes = emf->emh->nSize;
+    emf->emh->nRecords = 1;
+    emf->emh->nHandles = 1;
+
+    emf->emh->sReserved = 0; /* According to docs, this is reserved and must be 0 */
+    emf->emh->nDescription = length / 2;
+
+    emf->emh->offDescription = length ? sizeof(ENHMETAHEADER) : 0;
+
+    emf->emh->nPalEntries = 0; /* I guess this should start at 0 */
+
+    /* Size in pixels */
+    emf->emh->szlDevice.cx = GetDeviceCaps( ret, HORZRES );
+    emf->emh->szlDevice.cy = GetDeviceCaps( ret, VERTRES );
+
+    /* Size in millimeters */
+    emf->emh->szlMillimeters.cx = GetDeviceCaps( ret, HORZSIZE );
+    emf->emh->szlMillimeters.cy = GetDeviceCaps( ret, VERTSIZE );
+
+    /* Size in micrometers */
+    emf->emh->szlMicrometers.cx = emf->emh->szlMillimeters.cx * 1000;
+    emf->emh->szlMicrometers.cy = emf->emh->szlMillimeters.cy * 1000;
+
+    memcpy( (char *)emf->emh + sizeof(ENHMETAHEADER), description, length );
+
+    if (filename)  /* disk based metafile */
+    {
+        if ((file = CreateFileW( filename, GENERIC_WRITE | GENERIC_READ, 0,
+                                  NULL, CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE)
+        {
+            DeleteDC( ret );
+            return 0;
+        }
+        emf->file = file;
+    }
+
+    TRACE( "returning %p\n", ret );
+    return ret;
+}
+
+/******************************************************************
+ *           CloseEnhMetaFile (GDI32.@)
+ */
+HENHMETAFILE WINAPI CloseEnhMetaFile( HDC hdc )
+{
+    HENHMETAFILE hmf;
+    struct emf *emf;
+    WINEDC *dc_attr;
+    EMREOF emr;
+    HANDLE mapping = 0;
+
+    if (!(dc_attr = get_dc_ptr( hdc )) || !dc_attr->emf) return 0;
+    emf = dc_attr->emf;
+
+    if (dc_attr->save_level)
+        RestoreDC( hdc, 1 );
+
+    if (emf->dc_brush) DeleteObject( emf->dc_brush );
+    if (emf->dc_pen) DeleteObject( emf->dc_pen );
+
+    emr.emr.iType = EMR_EOF;
+    emr.emr.nSize = sizeof(emr);
+    emr.nPalEntries = 0;
+    emr.offPalEntries = FIELD_OFFSET(EMREOF, nSizeLast);
+    emr.nSizeLast = emr.emr.nSize;
+    emfdc_record( emf, &emr.emr );
+
+    emf->emh->rclBounds = dc_attr->emf_bounds;
+
+    /* Update rclFrame if not initialized in CreateEnhMetaFile */
+    if (emf->emh->rclFrame.left > emf->emh->rclFrame.right)
+    {
+        emf->emh->rclFrame.left = emf->emh->rclBounds.left *
+            emf->emh->szlMillimeters.cx * 100 / emf->emh->szlDevice.cx;
+        emf->emh->rclFrame.top = emf->emh->rclBounds.top *
+            emf->emh->szlMillimeters.cy * 100 / emf->emh->szlDevice.cy;
+        emf->emh->rclFrame.right = emf->emh->rclBounds.right *
+            emf->emh->szlMillimeters.cx * 100 / emf->emh->szlDevice.cx;
+        emf->emh->rclFrame.bottom = emf->emh->rclBounds.bottom *
+            emf->emh->szlMillimeters.cy * 100 / emf->emh->szlDevice.cy;
+    }
+
+    if (emf->file)  /* disk based metafile */
+    {
+        DWORD bytes_written;
+
+        if (!WriteFile( emf->file, emf->emh, emf->emh->nBytes, &bytes_written, NULL ))
+        {
+            CloseHandle( emf->file );
+            return 0;
+        }
+        HeapFree( GetProcessHeap(), 0, emf->emh );
+        mapping = CreateFileMappingA( emf->file, NULL, PAGE_READONLY, 0, 0, NULL );
+        TRACE( "mapping = %p\n", mapping );
+        emf->emh = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
+        TRACE( "view = %p\n", emf->emh );
+        CloseHandle( mapping );
+        CloseHandle( emf->file );
+    }
+
+    hmf = EMF_Create_HENHMETAFILE( emf->emh, emf->emh->nBytes, emf->file != 0 );
+    emf->emh = NULL;  /* So it won't be deleted */
+    DeleteDC( hdc );
+    return hmf;
+}
diff --git a/win32ss/gdi/gdi32/wine/emfdrv.c b/win32ss/gdi/gdi32/wine/emfdrv.c
new file mode 100644 (file)
index 0000000..26a13c6
--- /dev/null
@@ -0,0 +1,430 @@
+/*
+ * Enhanced MetaFile driver
+ *
+ * Copyright 1999 Huw D M Davies
+ * Copyright 2021 Jacek Caban for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+//#include "ntgdi_private.h"
+#include "wine/config.h"
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winnls.h"
+#include "winerror.h"
+#include "gdi_private.h"
+#ifdef __REACTOS__
+#include "wine/winternl.h"
+#else
+#include "winternl.h"
+#endif
+#include "wine/wingdi16.h"
+#include "wine/debug.h"
+
+#define M_PI 3.14159265358979323846
+#define M_PI_2 1.570796326794896619
+
+static void emfdrv_update_bounds( WINEDC *dc, RECTL *rect )
+{
+    RECTL *bounds = &dc->emf_bounds;
+    RECTL vport_rect = *rect;
+
+    //lp_to_dp( dc, (POINT *)&vport_rect, 2 );
+    LPtoDP(dc->hdc, (POINT *)&vport_rect, 2 );
+
+    /* The coordinate systems may be mirrored
+       (LPtoDP handles points, not rectangles) */
+    if (vport_rect.left > vport_rect.right)
+    {
+        LONG temp = vport_rect.right;
+        vport_rect.right = vport_rect.left;
+        vport_rect.left = temp;
+    }
+    if (vport_rect.top > vport_rect.bottom)
+    {
+        LONG temp = vport_rect.bottom;
+        vport_rect.bottom = vport_rect.top;
+        vport_rect.top = temp;
+    }
+
+    if (bounds->left > bounds->right)
+    {
+        /* first bounding rectangle */
+        *bounds = vport_rect;
+    }
+    else
+    {
+        bounds->left   = min( bounds->left,   vport_rect.left );
+        bounds->top    = min( bounds->top,    vport_rect.top );
+        bounds->right  = max( bounds->right,  vport_rect.right );
+        bounds->bottom = max( bounds->bottom, vport_rect.bottom );
+    }
+}
+
+BOOL EMFDRV_LineTo( WINEDC *dc, INT x, INT y )
+{
+    RECTL bounds;
+    POINT pt;
+
+    //pt = dc->attr->cur_pos;
+    GetCurrentPositionEx(dc->hdc, &pt);
+
+    bounds.left   = min( x, pt.x );
+    bounds.top    = min( y, pt.y );
+    bounds.right  = max( x, pt.x );
+    bounds.bottom = max( y, pt.y );
+    emfdrv_update_bounds( dc, &bounds );
+    return TRUE;
+}
+
+BOOL EMFDRV_RoundRect( WINEDC *dc, INT left, INT top, INT right,
+                                    INT bottom, INT ell_width, INT ell_height )
+{
+    RECTL bounds;
+
+    if (left == right || top == bottom) return FALSE;
+
+    bounds.left   = min( left, right );
+    bounds.top    = min( top, bottom );
+    bounds.right  = max( left, right );
+    bounds.bottom = max( top, bottom );
+    if (GetGraphicsMode(dc->hdc) == GM_COMPATIBLE)//dc->attr->graphics_mode == GM_COMPATIBLE)
+    {
+        bounds.right--;
+        bounds.bottom--;
+    }
+
+    emfdrv_update_bounds( dc, &bounds );
+    return TRUE;
+}
+
+BOOL EMFDRV_ArcChordPie( WINEDC *dc, INT left, INT top, INT right, INT bottom,
+                                INT xstart, INT ystart, INT xend, INT yend, DWORD type )
+{
+    INT temp, x_centre, y_centre, i;
+    double angle_start, angle_end;
+    double xinter_start, yinter_start, xinter_end, yinter_end;
+    EMRARC emr;
+    RECTL bounds;
+
+    if (left == right || top == bottom) return FALSE;
+
+    if (left > right) { temp = left; left = right; right = temp; }
+    if (top > bottom) { temp = top; top = bottom; bottom = temp; }
+
+    if (GetGraphicsMode(dc->hdc) == GM_COMPATIBLE)//dc->attr->graphics_mode == GM_COMPATIBLE)
+    {
+        right--;
+        bottom--;
+    }
+
+    emr.emr.iType     = type;
+    emr.emr.nSize     = sizeof(emr);
+    emr.rclBox.left   = left;
+    emr.rclBox.top    = top;
+    emr.rclBox.right  = right;
+    emr.rclBox.bottom = bottom;
+    emr.ptlStart.x    = xstart;
+    emr.ptlStart.y    = ystart;
+    emr.ptlEnd.x      = xend;
+    emr.ptlEnd.y      = yend;
+
+    /* Now calculate the BBox */
+    x_centre = (left + right + 1) / 2;
+    y_centre = (top + bottom + 1) / 2;
+
+    xstart -= x_centre;
+    ystart -= y_centre;
+    xend   -= x_centre;
+    yend   -= y_centre;
+
+    /* invert y co-ords to get angle anti-clockwise from x-axis */
+    angle_start = atan2( -(double)ystart, (double)xstart );
+    angle_end   = atan2( -(double)yend, (double)xend );
+
+    /* These are the intercepts of the start/end lines with the arc */
+    xinter_start = (right - left + 1)/2 * cos(angle_start) + x_centre;
+    yinter_start = -(bottom - top + 1)/2 * sin(angle_start) + y_centre;
+    xinter_end   = (right - left + 1)/2 * cos(angle_end) + x_centre;
+    yinter_end   = -(bottom - top + 1)/2 * sin(angle_end) + y_centre;
+
+    if (angle_start < 0) angle_start += 2 * M_PI;
+    if (angle_end < 0) angle_end += 2 * M_PI;
+    if (angle_end < angle_start) angle_end += 2 * M_PI;
+
+    bounds.left   = min( xinter_start, xinter_end );
+    bounds.top    = min( yinter_start, yinter_end );
+    bounds.right  = max( xinter_start, xinter_end );
+    bounds.bottom = max( yinter_start, yinter_end );
+
+    for (i = 0; i <= 8; i++)
+    {
+        if(i * M_PI / 2 < angle_start) /* loop until we're past start */
+           continue;
+       if(i * M_PI / 2 > angle_end)   /* if we're past end we're finished */
+           break;
+
+       /* the arc touches the rectangle at the start of quadrant i, so adjust
+          BBox to reflect this. */
+
+       switch(i % 4) {
+       case 0:
+           bounds.right = right;
+           break;
+       case 1:
+           bounds.top = top;
+           break;
+       case 2:
+           bounds.left = left;
+           break;
+       case 3:
+           bounds.bottom = bottom;
+           break;
+       }
+    }
+
+    /* If we're drawing a pie then make sure we include the centre */
+    if (type == EMR_PIE)
+    {
+        if (bounds.left > x_centre) bounds.left = x_centre;
+       else if (bounds.right < x_centre) bounds.right = x_centre;
+       if (bounds.top > y_centre) bounds.top = y_centre;
+       else if (bounds.bottom < y_centre) bounds.bottom = y_centre;
+    }
+    else if (type == EMR_ARCTO)
+    {
+        POINT pt;
+        //pt = dc->attr->cur_pos;
+        GetCurrentPositionEx(dc->hdc, &pt);
+        bounds.left   = min( bounds.left, pt.x );
+        bounds.top    = min( bounds.top, pt.y );
+        bounds.right  = max( bounds.right, pt.x );
+        bounds.bottom = max( bounds.bottom, pt.y );
+    }
+    emfdrv_update_bounds( dc, &bounds );
+    return TRUE;
+}
+
+BOOL EMFDRV_Arc( WINEDC *dc, INT left, INT top, INT right, INT bottom,
+                              INT xstart, INT ystart, INT xend, INT yend )
+{
+    return EMFDRV_ArcChordPie( dc, left, top, right, bottom, xstart, ystart,
+                               xend, yend, EMR_ARC );
+}
+
+BOOL EMFDRV_ArcTo( WINEDC *dc, INT left, INT top, INT right, INT bottom,
+                                INT xstart, INT ystart, INT xend, INT yend )
+{
+    return EMFDRV_ArcChordPie( dc, left, top, right, bottom, xstart, ystart,
+                               xend, yend, EMR_ARCTO );
+}
+
+BOOL EMFDRV_Pie( WINEDC *dc, INT left, INT top, INT right, INT bottom,
+                              INT xstart, INT ystart, INT xend, INT yend )
+{
+    return EMFDRV_ArcChordPie( dc, left, top, right, bottom, xstart, ystart,
+                               xend, yend, EMR_PIE );
+}
+
+BOOL EMFDRV_Chord( WINEDC *dc, INT left, INT top, INT right, INT bottom,
+                                INT xstart, INT ystart, INT xend, INT yend )
+{
+    return EMFDRV_ArcChordPie( dc, left, top, right, bottom, xstart, ystart,
+                               xend, yend, EMR_CHORD );
+}
+
+BOOL EMFDRV_Ellipse( WINEDC *dc, INT left, INT top, INT right, INT bottom )
+{
+    RECTL bounds;
+
+    if (left == right || top == bottom) return FALSE;
+
+    bounds.left   = min( left, right );
+    bounds.top    = min( top, bottom );
+    bounds.right  = max( left, right );
+    bounds.bottom = max( top, bottom );
+    if (GetGraphicsMode(dc->hdc) == GM_COMPATIBLE)//dc->attr->graphics_mode == GM_COMPATIBLE)
+    {
+        bounds.right--;
+        bounds.bottom--;
+    }
+
+    emfdrv_update_bounds( dc, &bounds );
+    return TRUE;
+}
+
+BOOL EMFDRV_Rectangle( WINEDC *dc, INT left, INT top, INT right, INT bottom )
+{
+    RECTL bounds;
+
+    if (left == right || top == bottom) return FALSE;
+
+    bounds.left   = min( left, right );
+    bounds.top    = min( top, bottom );
+    bounds.right  = max( left, right );
+    bounds.bottom = max( top, bottom );
+    if (GetGraphicsMode(dc->hdc) == GM_COMPATIBLE)//dc->attr->graphics_mode == GM_COMPATIBLE)
+    {
+        bounds.right--;
+        bounds.bottom--;
+    }
+
+    emfdrv_update_bounds( dc, &bounds );
+    return TRUE;
+}
+
+COLORREF EMFDRV_SetPixel( WINEDC *dc, INT x, INT y, COLORREF color )
+{
+    RECTL bounds;
+
+    bounds.left = bounds.right = x;
+    bounds.top = bounds.bottom = y;
+    emfdrv_update_bounds( dc, &bounds );
+    return CLR_INVALID;
+}
+
+BOOL EMFDRV_PolylineTo( WINEDC *dc, const POINT *pt, INT count )
+{
+    /* FIXME: update bounding rect */
+    return TRUE;
+}
+
+BOOL EMFDRV_PolyBezier( WINEDC *dc, const POINT *pts, DWORD count )
+{
+    /* FIXME: update bounding rect */
+    return TRUE;
+}
+
+BOOL EMFDRV_PolyBezierTo( WINEDC *dc, const POINT *pts, DWORD count )
+{
+    /* FIXME: update bounding rect */
+    return TRUE;
+}
+
+BOOL EMFDRV_PolyPolyline( WINEDC *dc, const POINT *pt,
+                                       const DWORD *counts, UINT polys )
+{
+    /* FIXME: update bounding rect */
+    return TRUE;
+}
+
+BOOL EMFDRV_PolyPolygon( WINEDC *dc, const POINT *pt,
+                                      const INT *counts, UINT polys )
+{
+    /* FIXME: update bounding rect */
+    return TRUE;
+}
+
+BOOL EMFDRV_PolyDraw( WINEDC *dc, const POINT *pts,
+                                   const BYTE *types, DWORD count )
+{
+    /* FIXME: update bounding rect */
+    return TRUE;
+}
+
+BOOL EMFDRV_FillRgn( WINEDC *dc, HRGN hrgn, HBRUSH hbrush )
+{
+    /* FIXME: update bounding rect */
+    return TRUE;
+}
+
+BOOL EMFDRV_FrameRgn( WINEDC *dc, HRGN hrgn, HBRUSH hbrush, INT width, INT height )
+{
+    /* FIXME: update bounding rect */
+    return TRUE;
+}
+
+BOOL EMFDRV_InvertRgn( WINEDC *dc, HRGN hrgn )
+{
+    /* FIXME: update bounding rect */
+    return TRUE;
+}
+
+BOOL EMFDRV_ExtTextOut( WINEDC *dc, INT x, INT y, UINT flags, const RECT *lprect,
+                                     LPCWSTR str, UINT count, const INT *lpDx )
+{
+    /* FIXME: update bounding rect */
+    return TRUE;
+}
+
+BOOL EMFDRV_GradientFill( WINEDC *dc, TRIVERTEX *vert_array, ULONG nvert,
+                                       void *grad_array, ULONG ngrad, ULONG mode )
+{
+    /* FIXME: update bounding rect */
+    return TRUE;
+}
+
+BOOL EMFDRV_FillPath( WINEDC *dc )
+{
+    /* FIXME: update bound rect */
+    return TRUE;
+}
+
+BOOL EMFDRV_StrokeAndFillPath( WINEDC *dc )
+{
+    /* FIXME: update bound rect */
+    return TRUE;
+}
+
+BOOL EMFDRV_StrokePath( WINEDC *dc )
+{
+    /* FIXME: update bound rect */
+    return TRUE;
+}
+
+BOOL EMFDRV_AlphaBlend( WINEDC *dc_dst, INT x_dst, INT y_dst, INT width_dst, INT height_dst,
+                                     HDC dc_src, INT x_src, INT y_src, INT width_src, INT height_src,
+                                     BLENDFUNCTION func )
+{
+    /* FIXME: update bound rect */
+    return TRUE;
+}
+
+BOOL EMFDRV_PatBlt( WINEDC *dc, INT left, INT top, INT width, INT height, DWORD rop )
+{
+    /* FIXME: update bound rect */
+    return TRUE;
+}
+
+INT EMFDRV_StretchDIBits( WINEDC *dc, INT x_dst, INT y_dst, INT width_dst,
+                                       INT height_dst, INT x_src, INT y_src, INT width_src,
+                                       INT height_src, const void *bits, BITMAPINFO *info,
+                                       UINT wUsage, DWORD dwRop )
+{
+    /* FIXME: Update bound rect */
+    return height_src;
+}
+
+INT EMFDRV_SetDIBitsToDevice( WINEDC *dc, INT x_dst, INT y_dst, DWORD width,
+                                           DWORD height, INT x_src, INT y_src, UINT startscan,
+                                           UINT lines, const void *bits, BITMAPINFO *info,
+                                           UINT usage )
+{
+    /* FIXME: Update bound rect */
+    return lines;
+}
+
+HBITMAP EMFDRV_SelectBitmap( WINEDC *dc, HBITMAP hbitmap )
+{
+    return 0;
+}
+
index 07faf2a..f8c0762 100644 (file)
 
 WINE_DEFAULT_DEBUG_CHANNEL(enhmetafile);
 
+
+static CRITICAL_SECTION enhmetafile_cs;
+static CRITICAL_SECTION_DEBUG critsect_debug =
+{
+    0, 0, &enhmetafile_cs,
+    { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
+      0, 0, { (DWORD_PTR)(__FILE__ ": enhmetafile_cs") }
+};
+static CRITICAL_SECTION enhmetafile_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
+
 typedef struct
 {
     ENHMETAHEADER  *emh;
@@ -246,7 +256,7 @@ static inline BOOL is_dib_monochrome( const BITMAPINFO* info )
 /****************************************************************************
  *          EMF_Create_HENHMETAFILE
  */
-HENHMETAFILE EMF_Create_HENHMETAFILE(ENHMETAHEADER *emh, BOOL on_disk )
+HENHMETAFILE EMF_Create_HENHMETAFILE(ENHMETAHEADER *emh, DWORD filesize, BOOL on_disk )
 {
     HENHMETAFILE hmf;
     ENHMETAFILEOBJ *metaObj;
@@ -263,6 +273,11 @@ HENHMETAFILE EMF_Create_HENHMETAFILE(ENHMETAHEADER *emh, BOOL on_disk )
              emh->iType, emh->dSignature);
         return 0;
     }
+    if (filesize < emh->nBytes)
+    {
+        WARN("File truncated (got %u bytes, header says %u)\n", emh->nBytes, filesize);
+        return 0;
+    }
 
     if (!(metaObj = HeapAlloc( GetProcessHeap(), 0, sizeof(*metaObj) ))) return 0;
 
@@ -279,15 +294,22 @@ HENHMETAFILE EMF_Create_HENHMETAFILE(ENHMETAHEADER *emh, BOOL on_disk )
  */
 static BOOL EMF_Delete_HENHMETAFILE( HENHMETAFILE hmf )
 {
-    ENHMETAFILEOBJ *metaObj = free_gdi_handle( hmf );
-
-    if(!metaObj) return FALSE;
+    ENHMETAFILEOBJ *metaObj;
+    BOOL Ret = FALSE;
 
-    if(metaObj->on_disk)
-        UnmapViewOfFile( metaObj->emh );
-    else
-        HeapFree( GetProcessHeap(), 0, metaObj->emh );
-    return HeapFree( GetProcessHeap(), 0, metaObj );
+    EnterCriticalSection( &enhmetafile_cs );
+    metaObj = free_gdi_handle( hmf );
+    if(metaObj)
+    {
+        if(metaObj->on_disk)
+            UnmapViewOfFile( metaObj->emh );
+        else
+            HeapFree( GetProcessHeap(), 0, metaObj->emh );
+        HeapFree( GetProcessHeap(), 0, metaObj );
+        Ret = TRUE;
+    }
+    LeaveCriticalSection( &enhmetafile_cs );
+    return Ret;
 }
 
 /******************************************************************
@@ -298,13 +320,17 @@ static BOOL EMF_Delete_HENHMETAFILE( HENHMETAFILE hmf )
 static ENHMETAHEADER *EMF_GetEnhMetaHeader( HENHMETAFILE hmf )
 {
     ENHMETAHEADER *ret = NULL;
-    ENHMETAFILEOBJ *metaObj = GDI_GetObjPtr( hmf, OBJ_ENHMETAFILE );
+    ENHMETAFILEOBJ *metaObj;
+
+    EnterCriticalSection( &enhmetafile_cs );
+    metaObj = GDI_GetObjPtr( hmf, OBJ_ENHMETAFILE );
     TRACE("hmf %p -> enhmetaObj %p\n", hmf, metaObj);
     if (metaObj)
     {
         ret = metaObj->emh;
         GDI_ReleaseObj( hmf );
     }
+    LeaveCriticalSection( &enhmetafile_cs );
     return ret;
 }
 
@@ -317,6 +343,9 @@ static HENHMETAFILE EMF_GetEnhMetaFile( HANDLE hFile )
     ENHMETAHEADER *emh;
     HANDLE hMapping;
     HENHMETAFILE hemf;
+    DWORD filesize;
+
+    filesize = GetFileSize( hFile, NULL );
 
     hMapping = CreateFileMappingA( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
     emh = MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, 0 );
@@ -324,7 +353,7 @@ static HENHMETAFILE EMF_GetEnhMetaFile( HANDLE hFile )
 
     if (!emh) return 0;
 
-    hemf = EMF_Create_HENHMETAFILE( emh, TRUE );
+    hemf = EMF_Create_HENHMETAFILE( emh, filesize, TRUE );
     if (!hemf)
         UnmapViewOfFile( emh );
     return hemf;
@@ -467,7 +496,7 @@ HENHMETAFILE WINAPI SetEnhMetaFileBits(UINT bufsize, const BYTE *buf)
     ENHMETAHEADER *emh = HeapAlloc( GetProcessHeap(), 0, bufsize );
     HENHMETAFILE hmf;
     memmove(emh, buf, bufsize);
-    hmf = EMF_Create_HENHMETAFILE( emh, FALSE );
+    hmf = EMF_Create_HENHMETAFILE( emh, bufsize, FALSE );
     if (!hmf)
         HeapFree( GetProcessHeap(), 0, emh );
     return hmf;
@@ -1127,6 +1156,31 @@ BOOL WINAPI PlayEnhMetaFileRecord(
        break;
       }
 
+    case EMR_POLYDRAW16:
+    {
+        const EMRPOLYDRAW16 *pPolyDraw16 = (const EMRPOLYDRAW16 *)mr;
+        const POINTS *ptl = pPolyDraw16->apts;
+        POINT *pts = HeapAlloc(GetProcessHeap(), 0, pPolyDraw16->cpts * sizeof(POINT));
+        DWORD i;
+
+        /* NB abTypes array doesn't start at pPolyDraw16->abTypes. It's actually
+           pPolyDraw16->apts + pPolyDraw16->cpts. */
+        const BYTE *types = (BYTE*)(pPolyDraw16->apts + pPolyDraw16->cpts);
+
+        if (!pts)
+            break;
+
+        for (i = 0; i < pPolyDraw16->cpts; ++i)
+        {
+            pts[i].x = ptl[i].x;
+            pts[i].y = ptl[i].y;
+        }
+
+        PolyDraw(hdc, pts, types, pPolyDraw16->cpts);
+        HeapFree(GetProcessHeap(), 0, pts);
+        break;
+    }
+
     case EMR_STRETCHDIBITS:
       {
        const EMRSTRETCHDIBITS *pStretchDIBits = (const EMRSTRETCHDIBITS *)mr;
@@ -2231,15 +2285,33 @@ BOOL WINAPI PlayEnhMetaFileRecord(
         break;
     }
 
-    case EMR_POLYDRAW16:
-    case EMR_GLSRECORD:
-    case EMR_GLSBOUNDEDRECORD:
     case EMR_DRAWESCAPE:
+    {
+        PEMRESCAPE pemr = (PEMRESCAPE)mr;
+        DrawEscape( hdc, pemr->iEsc, pemr->cjIn, (LPCSTR)pemr->Data );
+        break;
+    }
+
     case EMR_EXTESCAPE:
+    {
+        PEMRESCAPE pemr = (PEMRESCAPE)mr;
+        ExtEscape( hdc, pemr->iEsc, pemr->cjIn, (LPCSTR)pemr->Data, 0, NULL );
+        break;
+    }
+
+    case EMR_NAMEDESCAPE:
+    {
+        PEMRNAMEDESCAPE pemr = (PEMRNAMEDESCAPE)mr;
+        INT rounded_size = (pemr->cjIn+3) & ~3;
+        NamedEscape( hdc, (PWCHAR)&pemr->Data[rounded_size], pemr->iEsc, pemr->cjIn, (LPSTR)pemr->Data, 0, NULL );
+        break;
+    }
+
+    case EMR_GLSRECORD:
+    case EMR_GLSBOUNDEDRECORD:
     case EMR_STARTDOC:
     case EMR_SMALLTEXTOUT:
     case EMR_FORCEUFIMAPPING:
-    case EMR_NAMEDESCAPE:
     case EMR_COLORCORRECTPALETTE:
     case EMR_SETICMPROFILEA:
     case EMR_SETICMPROFILEW:
@@ -2262,7 +2334,6 @@ BOOL WINAPI PlayEnhMetaFileRecord(
   return TRUE;
 }
 
-
 /*****************************************************************************
  *
  *        EnumEnhMetaFile  (GDI32.@)
@@ -2358,13 +2429,14 @@ BOOL WINAPI EnumEnhMetaFile(
     info->state.next = NULL;
     info->save_level = 0;
     info->saved_state = NULL;
+    info->init_transform = info->state.world_transform;
 
     ht = (HANDLETABLE*) &info[1];
     ht->objectHandle[0] = hmf;
     for(i = 1; i < emh->nHandles; i++)
         ht->objectHandle[i] = NULL;
 
-    if(hdc)
+    if(hdc && !is_meta_dc( hdc ))
     {
        savedMode = SetGraphicsMode(hdc, GM_ADVANCED);
        GetWorldTransform(hdc, &savedXform);
@@ -2394,17 +2466,7 @@ BOOL WINAPI EnumEnhMetaFile(
         old_polyfill = SetPolyFillMode(hdc, ALTERNATE);
         old_stretchblt = SetStretchBltMode(hdc, BLACKONWHITE);
 
-        if ( IS_WIN9X() )
-        {
-            /* Win95 leaves the vp/win ext/org info alone */
-            info->init_transform.eM11 = 1.0;
-            info->init_transform.eM12 = 0.0;
-            info->init_transform.eM21 = 0.0;
-            info->init_transform.eM22 = 1.0;
-            info->init_transform.eDx  = 0.0;
-            info->init_transform.eDy  = 0.0;
-        }
-        else
+        if (!IS_WIN9X() )
         {
             /* WinNT combines the vp/win ext/org info into a transform */
             double xscale, yscale;
@@ -2463,6 +2525,14 @@ BOOL WINAPI EnumEnhMetaFile(
     {
        emr = (ENHMETARECORD *)((char *)emh + offset);
 
+        if (offset + 8 > emh->nBytes ||
+            offset > offset + emr->nSize ||
+            offset + emr->nSize > emh->nBytes)
+        {
+            WARN("record truncated\n");
+            break;
+        }
+
         /* In Win9x mode we update the xform if the record will produce output */
         if (hdc && IS_WIN9X() && emr_produces_output(emr->iType))
             EMF_Update_MF_Xform(hdc, info);
@@ -2472,7 +2542,7 @@ BOOL WINAPI EnumEnhMetaFile(
        offset += emr->nSize;
     }
 
-    if (hdc)
+    if (hdc && !is_meta_dc( hdc ))
     {
         SetStretchBltMode(hdc, old_stretchblt);
         SetPolyFillMode(hdc, old_polyfill);
@@ -2536,8 +2606,7 @@ BOOL WINAPI PlayEnhMetaFile(
        const RECT *lpRect /* [in] rectangle to place metafile inside */
       )
 {
-    return EnumEnhMetaFile(hdc, hmf, EMF_PlayEnhMetaFileCallback, NULL,
-                          lpRect);
+    return EnumEnhMetaFile(hdc, hmf, EMF_PlayEnhMetaFileCallback, NULL, lpRect);
 }
 
 /*****************************************************************************
@@ -2568,7 +2637,7 @@ HENHMETAFILE WINAPI CopyEnhMetaFileA(
     if (!file) {
         emrDst = HeapAlloc( GetProcessHeap(), 0, emrSrc->nBytes );
        memcpy( emrDst, emrSrc, emrSrc->nBytes );
-       hmfDst = EMF_Create_HENHMETAFILE( emrDst, FALSE );
+       hmfDst = EMF_Create_HENHMETAFILE( emrDst, emrSrc->nBytes, FALSE );
        if (!hmfDst)
                HeapFree( GetProcessHeap(), 0, emrDst );
     } else {
@@ -2610,7 +2679,7 @@ HENHMETAFILE WINAPI CopyEnhMetaFileW(
     if (!file) {
         emrDst = HeapAlloc( GetProcessHeap(), 0, emrSrc->nBytes );
        memcpy( emrDst, emrSrc, emrSrc->nBytes );
-       hmfDst = EMF_Create_HENHMETAFILE( emrDst, FALSE );
+       hmfDst = EMF_Create_HENHMETAFILE( emrDst, emrSrc->nBytes, FALSE );
        if (!hmfDst)
                HeapFree( GetProcessHeap(), 0, emrDst );
     } else {
index f3b79c4..de49fae 100644 (file)
 #include "windef.h"
 #include "winbase.h"
 #include "wingdi.h"
-#include <wine/gdi_driver.h>
+
+#define GDILoObjType_LO_DC_TYPE         0x10000
+#define GDILoObjType_LO_FONT_TYPE       0xa0000
+#define GDILoObjType_LO_BRUSH_TYPE      0x100000
+#define GDILoObjType_LO_ALTDC_TYPE      0x210000
+#define GDILoObjType_LO_PEN_TYPE        0x300000
+#define GDILoObjType_LO_EXTPEN_TYPE     0x500000
+#define GDILoObjType_LO_METAFILE16_TYPE 0x260000
+#define GDILoObjType_LO_METAFILE_TYPE   0x460000
+#define GDILoObjType_LO_METADC16_TYPE   0x660000
+
+#define GDI_HANDLE_TYPE_MASK  0x007f0000
+#define GDI_HANDLE_GET_TYPE(h)     \
+    (((ULONG_PTR)(h)) & GDI_HANDLE_TYPE_MASK)
+
+HRGN APIENTRY NtGdiPathToRegion(_In_ HDC hdc);
+HDC APIENTRY NtGdiCreateMetafileDC(_In_ HDC hdc);
+#define GdiWorldSpaceToDeviceSpace  0x204
+BOOL APIENTRY NtGdiGetTransform(_In_ HDC hdc,_In_ DWORD iXform, _Out_ LPXFORM pxf);
+/* Get/SetBounds/Rect support. */
+#define DCB_WINDOWMGR 0x8000 /* Queries the Windows bounding rectangle instead of the application's */
+BOOL WINAPI GetBoundsRectAlt(HDC hdc,LPRECT prc,UINT flags);
+BOOL WINAPI SetBoundsRectAlt(HDC hdc,LPRECT prc,UINT flags);
+
+HGDIOBJ WINAPI GdiCreateClientObj(_In_ PVOID pvObject,_In_ UINT eObjType);
+PVOID WINAPI GdiGetClientObjLink(_In_ HGDIOBJ hobj);
+PVOID WINAPI GdiDeleteClientObj(_In_ HGDIOBJ hobj);
 
 /* Metafile defines */
 #define META_EOF 0x0000
@@ -43,6 +69,15 @@ typedef struct {
     INT   nBreakCount;
 } EMRSETTEXTJUSTIFICATION, *PEMRSETTEXTJUSTIFICATION;
 
+typedef struct tagEMRESCAPE {
+        EMR emr;
+        INT iEsc;
+        INT cjIn;
+        BYTE Data[1];
+} EMRESCAPE, *PEMRESCAPE, EMRNAMEDESCAPE, *PEMRNAMEDESCAPE;
+
+INT WINAPI NamedEscape(HDC,PWCHAR,INT,INT,LPSTR,INT,LPSTR);
+
 struct gdi_obj_funcs
 {
     HGDIOBJ (*pSelectObject)( HGDIOBJ handle, HDC hdc );
@@ -56,15 +91,14 @@ struct gdi_obj_funcs
 #define LDC_LDC           0x00000001
 #define LDC_EMFLDC        0x00000002
 
+typedef struct emf *PEMF;
+
 typedef struct tagWINEDC
 {
     HDC          hdc;
     ULONG        Flags;
     INT          iType;
-    union {
-    PVOID        pvEmfDC; /* Pointer to ENHMETAFILE structure */
-    PHYSDEV      physDev; /* current top of the physdev stack */
-    };
+    PEMF         emf; /* Pointer to ENHMETAFILE structure */
     LPWSTR       pwszPort;
     ABORTPROC    pAbortProc;
     DWORD        CallBackTick;
@@ -72,21 +106,27 @@ typedef struct tagWINEDC
     PDEVMODEW    pdm;
     PVOID        pUMPDev;
     PVOID        pUMdhpdev;
+    PVOID        UFIHashTable[3];
+    ULONG        ufi[2];
+    PVOID        pvEMFSpoolData;
+    ULONG        cjSize;
+    LIST_ENTRY   leRecords;
     ULONG        DevCaps[36];
     HBRUSH       hBrush;
     HPEN         hPen;
     ////
-    struct gdi_physdev NullPhysDev;
-    LONG         refcount;         /* thread refcount */
-    INT          saveLevel;
-    HFONT        hFont;
-    HPALETTE     hPalette;
+    INT          save_level;
+    RECTL        emf_bounds;
 } WINEDC, DC;
 
-WINEDC* get_physdev_dc( PHYSDEV dev );
+static inline BOOL is_meta_dc( HDC hdc )
+{
+    return GDI_HANDLE_GET_TYPE(hdc) == GDILoObjType_LO_METADC16_TYPE;
+}
+
 
 /* brush.c */
-extern BOOL get_brush_bitmap_info( HBRUSH handle, BITMAPINFO *info, void **bits, UINT *usage ) DECLSPEC_HIDDEN;
+extern BOOL get_brush_bitmap_info( HBRUSH handle, BITMAPINFO *info, void *bits, UINT *usage ) DECLSPEC_HIDDEN;
 
 /* dc.c */
 extern DC *alloc_dc_ptr( WORD magic ) DECLSPEC_HIDDEN;
@@ -98,7 +138,7 @@ extern void release_dc_ptr( DC *dc ) DECLSPEC_HIDDEN;
 extern int bitmap_info_size( const BITMAPINFO * info, WORD coloruse ) DECLSPEC_HIDDEN;
 
 /* enhmetafile.c */
-extern HENHMETAFILE EMF_Create_HENHMETAFILE(ENHMETAHEADER *emh, BOOL on_disk ) DECLSPEC_HIDDEN;
+extern HENHMETAFILE EMF_Create_HENHMETAFILE(ENHMETAHEADER *emh, DWORD filesize, BOOL on_disk ) DECLSPEC_HIDDEN;
 
 /* gdiobj.c */
 extern HGDIOBJ alloc_gdi_handle( void *obj, WORD type, const struct gdi_obj_funcs *funcs ) DECLSPEC_HIDDEN;
@@ -117,13 +157,11 @@ extern METAHEADER *MF_CreateMetaHeaderDisk(METAHEADER *mr, LPCVOID filename, BOO
 #include <pshpack2.h>
 typedef struct
 {
-    DWORD magic;   /* WMFC */
-    WORD unk04;    /* 1 */
-    WORD unk06;    /* 0 */
-    WORD unk08;    /* 0 */
-    WORD unk0a;    /* 1 */
+    DWORD magic;        /* WMFC */
+    DWORD comment_type; /* Always 0x00000001 */
+    DWORD version;      /* Always 0x00010000 */
     WORD checksum;
-    DWORD unk0e;   /* 0 */
+    DWORD flags;        /* Always 0 */
     DWORD num_chunks;
     DWORD chunk_size;
     DWORD remaining_size;
@@ -137,28 +175,9 @@ typedef struct
 extern HPALETTE WINAPI GDISelectPalette( HDC hdc, HPALETTE hpal, WORD wBkg) DECLSPEC_HIDDEN;
 extern UINT WINAPI GDIRealizePalette( HDC hdc ) DECLSPEC_HIDDEN;
 
-#define EMR_SETLINKEDUFI        119
-
-#define GET_DC_PHYSDEV(dc,func) \
-    get_physdev_entry_point( (dc)->physDev, FIELD_OFFSET(struct gdi_dc_funcs,func))
-
-static inline PHYSDEV pop_dc_driver( DC *dc, const struct gdi_dc_funcs *funcs )
-{
-    PHYSDEV dev, *pdev = &dc->physDev;
-    while (*pdev && (*pdev)->funcs != funcs) pdev = &(*pdev)->next;
-    if (!*pdev) return NULL;
-    dev = *pdev;
-    *pdev = dev->next;
-    return dev;
-}
-
-static inline PHYSDEV find_dc_driver( DC *dc, const struct gdi_dc_funcs *funcs )
-{
-    PHYSDEV dev;
+DWORD WINAPI GetDCDWord(_In_ HDC hdc,_In_ UINT u,_In_ DWORD dwError);
 
-    for (dev = dc->physDev; dev; dev = dev->next) if (dev->funcs == funcs) return dev;
-    return NULL;
-}
+#define EMR_SETLINKEDUFI        119
 
 /* Undocumented value for DIB's iUsage: Indicates a mono DIB w/o pal entries */
 #define DIB_PAL_MONO 2
@@ -196,8 +215,6 @@ BOOL APIENTRY NtGdiGetTransform( _In_ HDC hdc, _In_ DWORD iXform, _Out_ LPXFORM
 HGDIOBJ WINAPI GdiFixUpHandle(HGDIOBJ hGdiObj);
 #define get_full_gdi_handle GdiFixUpHandle
 
-extern void push_dc_driver_ros(PHYSDEV *dev, PHYSDEV physdev, const struct gdi_dc_funcs *funcs);
-#define push_dc_driver push_dc_driver_ros
 #if 0
 BOOL WINAPI SetWorldTransformForMetafile(HDC hdc, const XFORM *pxform);
 #define SetWorldTransform SetWorldTransformForMetafile
@@ -211,5 +228,36 @@ BOOL WINAPI SetWorldTransformForMetafile(HDC hdc, const XFORM *pxform);
 #undef ASSERT
 #define ASSERT(x) if (!(x)) DbgRaiseAssertionFailure()
 
+BOOL EMFDRV_LineTo( WINEDC *dc, INT x, INT y );
+BOOL EMFDRV_RoundRect( WINEDC *dc, INT left, INT top, INT right, INT bottom, INT ell_width, INT ell_height );
+BOOL EMFDRV_ArcChordPie( WINEDC *dc, INT left, INT top, INT right, INT bottom, INT xstart, INT ystart, INT xend, INT yend, DWORD type );
+BOOL EMFDRV_Arc( WINEDC *dc, INT left, INT top, INT right, INT bottom, INT xstart, INT ystart, INT xend, INT yend );
+BOOL EMFDRV_ArcTo( WINEDC *dc, INT left, INT top, INT right, INT bottom, INT xstart, INT ystart, INT xend, INT yend );
+BOOL EMFDRV_Pie( WINEDC *dc, INT left, INT top, INT right, INT bottom, INT xstart, INT ystart, INT xend, INT yend );
+BOOL EMFDRV_Chord( WINEDC *dc, INT left, INT top, INT right, INT bottom, INT xstart, INT ystart, INT xend, INT yend );
+BOOL EMFDRV_Ellipse( WINEDC *dc, INT left, INT top, INT right, INT bottom );
+BOOL EMFDRV_Rectangle( WINEDC *dc, INT left, INT top, INT right, INT bottom );
+COLORREF EMFDRV_SetPixel( WINEDC *dc, INT x, INT y, COLORREF color );
+BOOL EMFDRV_PolylineTo( WINEDC *dc, const POINT *pt, INT count );
+BOOL EMFDRV_PolyBezier( WINEDC *dc, const POINT *pts, DWORD count );
+BOOL EMFDRV_PolyBezierTo( WINEDC *dc, const POINT *pts, DWORD count );
+BOOL EMFDRV_PolyPolyline( WINEDC *dc, const POINT *pt, const DWORD *counts, UINT polys );
+BOOL EMFDRV_PolyPolygon( WINEDC *dc, const POINT *pt, const INT *counts, UINT polys );
+BOOL EMFDRV_PolyDraw( WINEDC *dc, const POINT *pts, const BYTE *types, DWORD count );
+BOOL EMFDRV_FillRgn( WINEDC *dc, HRGN hrgn, HBRUSH hbrush );
+BOOL EMFDRV_FrameRgn( WINEDC *dc, HRGN hrgn, HBRUSH hbrush, INT width, INT height );
+BOOL EMFDRV_InvertRgn( WINEDC *dc, HRGN hrgn );
+BOOL EMFDRV_ExtTextOut( WINEDC *dc, INT x, INT y, UINT flags, const RECT *lprect,LPCWSTR str, UINT count, const INT *lpDx );
+BOOL EMFDRV_GradientFill( WINEDC *dc, TRIVERTEX *vert_array, ULONG nvert, void *grad_array, ULONG ngrad, ULONG mode );
+BOOL EMFDRV_FillPath( WINEDC *dc );
+BOOL EMFDRV_StrokeAndFillPath( WINEDC *dc );
+BOOL EMFDRV_StrokePath( WINEDC *dc );
+BOOL EMFDRV_AlphaBlend( WINEDC *dc_dst, INT x_dst, INT y_dst, INT width_dst, INT height_dst,HDC dc_src, INT x_src, INT y_src, INT width_src, INT height_src, BLENDFUNCTION func );
+BOOL EMFDRV_PatBlt( WINEDC *dc, INT left, INT top, INT width, INT height, DWORD rop );
+INT EMFDRV_StretchDIBits( WINEDC *dc, INT x_dst, INT y_dst, INT width_dst,INT height_dst, INT x_src, INT y_src, INT width_src, INT height_src, const void *bits, BITMAPINFO *info, UINT wUsage, DWORD dwRop );
+INT EMFDRV_SetDIBitsToDevice( WINEDC *dc, INT x_dst, INT y_dst, DWORD width, DWORD height, INT x_src, INT y_src, UINT startscan, UINT lines, const void *bits, BITMAPINFO *info, UINT usage );
+HBITMAP EMFDRV_SelectBitmap( WINEDC *dc, HBITMAP hbitmap );
+
+
 #endif /* __WINE_GDI_PRIVATE_H */
 
diff --git a/win32ss/gdi/gdi32/wine/metadc.c b/win32ss/gdi/gdi32/wine/metadc.c
new file mode 100644 (file)
index 0000000..c5bff94
--- /dev/null
@@ -0,0 +1,1445 @@
+/*
+ * Metafile DC functions
+ *
+ * Copyright 1999 Huw D M Davies
+ * Copyright 1993, 1994, 1996 Alexandre Julliard
+ * Copyright 2021 Jacek Caban for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "wine/config.h"
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winnls.h"
+#include "winerror.h"
+#include "gdi_private.h"
+#ifdef __REACTOS__
+#include "wine/winternl.h"
+#else
+#include "winternl.h"
+#endif
+#include "wine/wingdi16.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(metafile);
+
+struct metadc
+{
+    HDC         hdc;
+    METAHEADER *mh;           /* Pointer to metafile header */
+    UINT        handles_size, cur_handles;
+    HGDIOBJ    *handles;
+    HANDLE      hFile;          /* Handle for disk based MetaFile */
+    HPEN        pen;
+    HBRUSH      brush;
+    HFONT       font;
+};
+
+#define HANDLE_LIST_INC 20
+
+
+struct metadc *get_metadc_ptr( HDC hdc )
+{
+    struct metadc *metafile = GdiGetClientObjLink(hdc);//get_gdi_client_ptr( hdc, NTGDI_OBJ_METADC );
+    if (!metafile) SetLastError( ERROR_INVALID_HANDLE );
+    return metafile;
+}
+
+static BOOL metadc_write_record( struct metadc *metadc, METARECORD *mr, unsigned int rlen )
+{
+    DWORD len, size;
+    METAHEADER *mh;
+
+    len = metadc->mh->mtSize * sizeof(WORD) + rlen;
+    size = HeapSize( GetProcessHeap(), 0, metadc->mh );
+    if (len > size)
+    {
+        size += size / sizeof(WORD) + rlen;
+        mh = HeapReAlloc( GetProcessHeap(), 0, metadc->mh, size );
+        if (!mh) return FALSE;
+        metadc->mh = mh;
+    }
+    memcpy( (WORD *)metadc->mh + metadc->mh->mtSize, mr, rlen );
+
+    metadc->mh->mtSize += rlen / sizeof(WORD);
+    metadc->mh->mtMaxRecord = max( metadc->mh->mtMaxRecord, rlen / sizeof(WORD) );
+    return TRUE;
+}
+
+static BOOL metadc_record( HDC hdc, METARECORD *mr, DWORD rlen )
+{
+    struct metadc *metadc;
+
+    if (!(metadc = get_metadc_ptr( hdc ))) return FALSE;
+    return metadc_write_record( metadc, mr, rlen );
+}
+
+static BOOL metadc_param0( HDC hdc, short func )
+{
+    METARECORD mr;
+
+    mr.rdSize = FIELD_OFFSET(METARECORD, rdParm[0]) / sizeof(WORD);
+    mr.rdFunction = func;
+    return metadc_record( hdc, &mr, mr.rdSize * sizeof(WORD) );
+}
+
+static BOOL metadc_param1( HDC hdc, short func, short param )
+{
+    METARECORD mr;
+
+    mr.rdSize = sizeof(mr) / sizeof(WORD);
+    mr.rdFunction = func;
+    mr.rdParm[0] = param;
+    return metadc_record( hdc, &mr, mr.rdSize * sizeof(WORD) );
+}
+
+static BOOL metadc_param2( HDC hdc, short func, short param1, short param2 )
+{
+    char buffer[FIELD_OFFSET(METARECORD, rdParm[2])];
+    METARECORD *mr = (METARECORD *)&buffer;
+
+    mr->rdSize = sizeof(buffer) / sizeof(WORD);
+    mr->rdFunction = func;
+    mr->rdParm[0] = param2;
+    mr->rdParm[1] = param1;
+    return metadc_record( hdc, mr, sizeof(buffer) );
+}
+
+static BOOL metadc_param4( HDC hdc, short func, short param1, short param2,
+                           short param3, short param4 )
+{
+    char buffer[FIELD_OFFSET(METARECORD, rdParm[4])];
+    METARECORD *mr = (METARECORD *)&buffer;
+
+    mr->rdSize = sizeof(buffer) / sizeof(WORD);
+    mr->rdFunction = func;
+    mr->rdParm[0] = param4;
+    mr->rdParm[1] = param3;
+    mr->rdParm[2] = param2;
+    mr->rdParm[3] = param1;
+    return metadc_record( hdc, mr, sizeof(buffer) );
+}
+
+static BOOL metadc_param5( HDC hdc, short func, short param1, short param2,
+                           short param3, short param4, short param5 )
+{
+    char buffer[FIELD_OFFSET(METARECORD, rdParm[5])];
+    METARECORD *mr = (METARECORD *)&buffer;
+
+    mr->rdSize = sizeof(buffer) / sizeof(WORD);
+    mr->rdFunction = func;
+    mr->rdParm[0] = param5;
+    mr->rdParm[1] = param4;
+    mr->rdParm[2] = param3;
+    mr->rdParm[3] = param2;
+    mr->rdParm[4] = param1;
+    return metadc_record( hdc, mr, sizeof(buffer) );
+}
+
+static BOOL metadc_param6( HDC hdc, short func, short param1, short param2,
+                           short param3, short param4, short param5,
+                           short param6 )
+{
+    char buffer[FIELD_OFFSET(METARECORD, rdParm[6])];
+    METARECORD *mr = (METARECORD *)&buffer;
+
+    mr->rdSize = sizeof(buffer) / sizeof(WORD);
+    mr->rdFunction = func;
+    mr->rdParm[0] = param6;
+    mr->rdParm[1] = param5;
+    mr->rdParm[2] = param4;
+    mr->rdParm[3] = param3;
+    mr->rdParm[4] = param2;
+    mr->rdParm[5] = param1;
+    return metadc_record( hdc, mr, sizeof(buffer) );
+}
+
+static BOOL metadc_param8( HDC hdc, short func, short param1, short param2,
+                           short param3, short param4, short param5,
+                           short param6, short param7, short param8)
+{
+    char buffer[FIELD_OFFSET(METARECORD, rdParm[8])];
+    METARECORD *mr = (METARECORD *)&buffer;
+
+    mr->rdSize = sizeof(buffer) / sizeof(WORD);
+    mr->rdFunction = func;
+    mr->rdParm[0] = param8;
+    mr->rdParm[1] = param7;
+    mr->rdParm[2] = param6;
+    mr->rdParm[3] = param5;
+    mr->rdParm[4] = param4;
+    mr->rdParm[5] = param3;
+    mr->rdParm[6] = param2;
+    mr->rdParm[7] = param1;
+    return metadc_record( hdc, mr, sizeof(buffer) );
+}
+
+BOOL METADC_SaveDC( HDC hdc )
+{
+    return metadc_param0( hdc, META_SAVEDC );
+}
+
+BOOL METADC_RestoreDC( HDC hdc, INT level )
+{
+    return metadc_param1( hdc, META_RESTOREDC, level );
+}
+
+BOOL METADC_SetTextAlign( HDC hdc, UINT align )
+{
+    return metadc_param2( hdc, META_SETTEXTALIGN, HIWORD(align), LOWORD(align) );
+}
+
+BOOL METADC_SetBkMode( HDC hdc, INT mode )
+{
+    return metadc_param1( hdc, META_SETBKMODE, (WORD)mode );
+}
+
+BOOL METADC_SetBkColor( HDC hdc, COLORREF color )
+{
+    return metadc_param2( hdc, META_SETBKCOLOR, HIWORD(color), LOWORD(color) );
+}
+
+BOOL METADC_SetTextColor( HDC hdc, COLORREF color )
+{
+    return metadc_param2( hdc, META_SETTEXTCOLOR, HIWORD(color), LOWORD(color) );
+}
+
+BOOL METADC_SetROP2( HDC hdc, INT rop )
+{
+    return metadc_param1( hdc, META_SETROP2, (WORD)rop );
+}
+
+BOOL METADC_SetRelAbs( HDC hdc, INT mode )
+{
+    return metadc_param1( hdc, META_SETRELABS, (WORD)mode );
+}
+
+BOOL METADC_SetPolyFillMode( HDC hdc, INT mode )
+{
+    return metadc_param1( hdc, META_SETPOLYFILLMODE, mode );
+}
+
+BOOL METADC_SetStretchBltMode( HDC hdc, INT mode )
+{
+    return metadc_param1( hdc, META_SETSTRETCHBLTMODE, mode );
+}
+
+BOOL METADC_IntersectClipRect( HDC hdc, INT left, INT top, INT right, INT bottom )
+{
+    return metadc_param4( hdc, META_INTERSECTCLIPRECT, left, top, right, bottom );
+}
+
+BOOL METADC_ExcludeClipRect( HDC hdc, INT left, INT top, INT right, INT bottom )
+{
+    return metadc_param4( hdc, META_EXCLUDECLIPRECT, left, top, right, bottom );
+}
+
+BOOL METADC_OffsetClipRgn( HDC hdc, INT x, INT y )
+{
+    return metadc_param2( hdc, META_OFFSETCLIPRGN, x, y );
+}
+
+BOOL METADC_SetLayout( HDC hdc, DWORD layout )
+{
+    return metadc_param2( hdc, META_SETLAYOUT, HIWORD(layout), LOWORD(layout) );
+}
+
+BOOL METADC_SetMapMode( HDC hdc, INT mode )
+{
+    return metadc_param1( hdc, META_SETMAPMODE, mode );
+}
+
+BOOL METADC_SetViewportExtEx( HDC hdc, INT x, INT y )
+{
+    return metadc_param2( hdc, META_SETVIEWPORTEXT, x, y );
+}
+
+BOOL METADC_SetViewportOrgEx( HDC hdc, INT x, INT y )
+{
+    return metadc_param2( hdc, META_SETVIEWPORTORG, x, y );
+}
+
+BOOL METADC_SetWindowExtEx( HDC hdc, INT x, INT y )
+{
+    return metadc_param2( hdc, META_SETWINDOWEXT, x, y );
+}
+
+BOOL METADC_SetWindowOrgEx( HDC hdc, INT x, INT y )
+{
+    return metadc_param2( hdc, META_SETWINDOWORG, x, y );
+}
+
+BOOL METADC_OffsetViewportOrgEx( HDC hdc, INT x, INT y )
+{
+    return metadc_param2( hdc, META_OFFSETVIEWPORTORG, x, y );
+}
+
+BOOL METADC_OffsetWindowOrgEx( HDC hdc, INT x, INT y )
+{
+    return metadc_param2( hdc, META_OFFSETWINDOWORG, x, y );
+}
+
+BOOL METADC_ScaleViewportExtEx( HDC hdc, INT x_num, INT x_denom, INT y_num, INT y_denom )
+{
+    return metadc_param4( hdc, META_SCALEVIEWPORTEXT, x_num, x_denom, y_num, y_denom );
+}
+
+BOOL METADC_ScaleWindowExtEx( HDC hdc, INT x_num, INT x_denom, INT y_num, INT y_denom )
+{
+    return metadc_param4( hdc, META_SCALEWINDOWEXT, x_num, x_denom, y_num, y_denom );
+}
+
+BOOL METADC_SetTextJustification( HDC hdc, INT extra, INT breaks )
+{
+    return metadc_param2( hdc, META_SETTEXTJUSTIFICATION, extra, breaks );
+}
+
+BOOL METADC_SetTextCharacterExtra( HDC hdc, INT extra )
+{
+    return metadc_param1( hdc, META_SETTEXTCHAREXTRA, extra );
+}
+
+BOOL METADC_SetMapperFlags( HDC hdc, DWORD flags )
+{
+    return metadc_param2( hdc, META_SETMAPPERFLAGS, HIWORD(flags), LOWORD(flags) );
+}
+
+BOOL METADC_MoveTo( HDC hdc, INT x, INT y )
+{
+    return metadc_param2( hdc, META_MOVETO, x, y );
+}
+
+BOOL METADC_LineTo( HDC hdc, INT x, INT y )
+{
+    return metadc_param2( hdc, META_LINETO, x, y );
+}
+
+BOOL METADC_Arc( HDC hdc, INT left, INT top, INT right, INT bottom,
+                 INT xstart, INT ystart, INT xend, INT yend )
+{
+     return metadc_param8( hdc, META_ARC, left, top, right, bottom,
+                           xstart, ystart, xend, yend );
+}
+
+BOOL METADC_Pie( HDC hdc, INT left, INT top, INT right, INT bottom,
+                 INT xstart, INT ystart, INT xend, INT yend )
+{
+    return metadc_param8( hdc, META_PIE, left, top, right, bottom,
+                          xstart, ystart, xend, yend );
+}
+
+BOOL METADC_Chord( HDC hdc, INT left, INT top, INT right, INT bottom,
+                   INT xstart, INT ystart, INT xend, INT yend )
+{
+    return metadc_param8( hdc, META_CHORD, left, top, right, bottom,
+                          xstart, ystart, xend, yend );
+}
+
+BOOL METADC_Ellipse( HDC hdc, INT left, INT top, INT right, INT bottom )
+{
+    return metadc_param4( hdc, META_ELLIPSE, left, top, right, bottom );
+}
+
+BOOL METADC_Rectangle( HDC hdc, INT left, INT top, INT right, INT bottom )
+{
+    return metadc_param4( hdc, META_RECTANGLE, left, top, right, bottom );
+}
+
+BOOL METADC_RoundRect( HDC hdc, INT left, INT top, INT right,
+                       INT bottom, INT ell_width, INT ell_height )
+{
+    return metadc_param6( hdc, META_ROUNDRECT, left, top, right, bottom,
+                          ell_width, ell_height );
+}
+
+BOOL METADC_SetPixel( HDC hdc, INT x, INT y, COLORREF color )
+{
+    return metadc_param4( hdc, META_SETPIXEL, x, y, HIWORD(color), LOWORD(color) );
+}
+
+static BOOL metadc_poly( HDC hdc, short func, POINTS *pt, short count )
+{
+    BOOL ret;
+    DWORD len;
+    METARECORD *mr;
+
+    len = sizeof(METARECORD) + count * 4;
+    if (!(mr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, len )))
+        return FALSE;
+
+    mr->rdSize = len / 2;
+    mr->rdFunction = func;
+    *(mr->rdParm) = count;
+    memcpy(mr->rdParm + 1, pt, count * 4);
+    ret = metadc_record( hdc, mr, mr->rdSize * 2);
+    HeapFree( GetProcessHeap(), 0, mr);
+    return ret;
+}
+
+BOOL METADC_Polyline( HDC hdc, const POINT *pt, INT count )
+{
+    int i;
+    POINTS *pts;
+    BOOL ret;
+
+    pts = HeapAlloc( GetProcessHeap(), 0, sizeof(POINTS) * count );
+    if(!pts) return FALSE;
+    for (i=count;i--;)
+    {
+        pts[i].x = pt[i].x;
+        pts[i].y = pt[i].y;
+    }
+    ret = metadc_poly( hdc, META_POLYLINE, pts, count );
+
+    HeapFree( GetProcessHeap(), 0, pts );
+    return ret;
+}
+
+BOOL METADC_Polygon( HDC hdc, const POINT *pt, INT count )
+{
+    int i;
+    POINTS *pts;
+    BOOL ret;
+
+    pts = HeapAlloc( GetProcessHeap(), 0, sizeof(POINTS) * count );
+    if(!pts) return FALSE;
+    for (i = count; i--;)
+    {
+        pts[i].x = pt[i].x;
+        pts[i].y = pt[i].y;
+    }
+    ret = metadc_poly( hdc, META_POLYGON, pts, count );
+
+    HeapFree( GetProcessHeap(), 0, pts );
+    return ret;
+}
+
+BOOL METADC_PolyPolygon( HDC hdc, const POINT *pt, const INT *counts, UINT polygons )
+{
+    BOOL ret;
+    DWORD len;
+    METARECORD *mr;
+    unsigned int i,j;
+    POINTS *pts;
+    INT16 totalpoint16 = 0;
+    INT16 * pointcounts;
+
+    for (i = 0; i < polygons; i++)
+         totalpoint16 += counts[i];
+
+    /* allocate space for all points */
+    pts=HeapAlloc( GetProcessHeap(), 0, sizeof(POINTS) * totalpoint16 );
+    pointcounts = HeapAlloc( GetProcessHeap(), 0, sizeof(INT16) * totalpoint16 );
+
+    /* copy point counts */
+    for (i = 0; i < polygons; i++)
+          pointcounts[i] = counts[i];
+
+    /* convert all points */
+    for (j = totalpoint16; j--;)
+    {
+        pts[j].x = pt[j].x;
+        pts[j].y = pt[j].y;
+    }
+
+    len = sizeof(METARECORD) + sizeof(WORD) + polygons * sizeof(INT16) +
+        totalpoint16 * sizeof(*pts);
+
+    if (!(mr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, len )))
+    {
+         HeapFree( GetProcessHeap(), 0, pts );
+         HeapFree( GetProcessHeap(), 0, pointcounts );
+         return FALSE;
+    }
+
+    mr->rdSize = len / sizeof(WORD);
+    mr->rdFunction = META_POLYPOLYGON;
+    *mr->rdParm = polygons;
+    memcpy( mr->rdParm + 1, pointcounts, polygons * sizeof(INT16) );
+    memcpy( mr->rdParm + 1+polygons, pts , totalpoint16 * sizeof(*pts) );
+    ret = metadc_record( hdc, mr, mr->rdSize * sizeof(WORD) );
+
+    HeapFree( GetProcessHeap(), 0, pts );
+    HeapFree( GetProcessHeap(), 0, pointcounts );
+    HeapFree( GetProcessHeap(), 0, mr);
+    return ret;
+}
+
+BOOL METADC_ExtFloodFill( HDC hdc, INT x, INT y, COLORREF color, UINT fill_type )
+{
+    return metadc_param5( hdc, META_EXTFLOODFILL, x, y, HIWORD(color), LOWORD(color), fill_type );
+}
+
+static UINT metadc_add_handle( struct metadc *metadc, HGDIOBJ obj )
+{
+    UINT16 index;
+
+    for (index = 0; index < metadc->handles_size; index++)
+        if (metadc->handles[index] == 0) break;
+    if(index == metadc->handles_size)
+    {
+        metadc->handles_size += HANDLE_LIST_INC;
+        metadc->handles = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
+                                       metadc->handles,
+                                       metadc->handles_size * sizeof(metadc->handles[0]) );
+    }
+    metadc->handles[index] = get_full_gdi_handle( obj );
+
+    metadc->cur_handles++;
+    if (metadc->cur_handles > metadc->mh->mtNoObjects)
+        metadc->mh->mtNoObjects++;
+
+    return index ; /* index 0 is not reserved for metafiles */
+}
+
+static BOOL metadc_remove_handle( struct metadc *metadc, UINT index )
+{
+    BOOL ret = FALSE;
+
+    if (index < metadc->handles_size && metadc->handles[index])
+    {
+        metadc->handles[index] = 0;
+        metadc->cur_handles--;
+        ret = TRUE;
+    }
+    return ret;
+}
+
+static INT16 metadc_create_brush( struct metadc *metadc, HBRUSH brush )
+{
+    DWORD size;
+    METARECORD *mr;
+    LOGBRUSH logbrush;
+    BOOL r;
+
+    if (!GetObjectA( brush, sizeof(logbrush), &logbrush )) return -1;
+
+    switch (logbrush.lbStyle)
+    {
+    case BS_SOLID:
+    case BS_NULL:
+    case BS_HATCHED:
+        {
+            LOGBRUSH16 lb16;
+
+            lb16.lbStyle = logbrush.lbStyle;
+            lb16.lbColor = logbrush.lbColor;
+            lb16.lbHatch = logbrush.lbHatch;
+            size = sizeof(METARECORD) + sizeof(LOGBRUSH16) - sizeof(WORD);
+            mr = HeapAlloc( GetProcessHeap(), 0, size );
+            mr->rdSize = size / sizeof(WORD);
+            mr->rdFunction = META_CREATEBRUSHINDIRECT;
+            memcpy( mr->rdParm, &lb16, sizeof(LOGBRUSH16) );
+            break;
+        }
+    case BS_PATTERN:
+    case BS_DIBPATTERN:
+        {
+            char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
+            BITMAPINFO *dst_info, *src_info = (BITMAPINFO *)buffer;
+            DWORD info_size;
+            UINT usage;
+
+            if (!get_brush_bitmap_info( brush, src_info, NULL, &usage )) goto done;
+
+            info_size = get_dib_info_size( src_info, usage );
+            size = FIELD_OFFSET( METARECORD, rdParm[2] ) +
+                info_size + src_info->bmiHeader.biSizeImage;
+
+            if (!(mr = HeapAlloc( GetProcessHeap(), 0, size ))) goto done;
+            mr->rdFunction = META_DIBCREATEPATTERNBRUSH;
+            mr->rdSize = size / sizeof(WORD);
+            mr->rdParm[0] = logbrush.lbStyle;
+            mr->rdParm[1] = usage;
+            dst_info = (BITMAPINFO *)(mr->rdParm + 2);
+            get_brush_bitmap_info( brush, dst_info, (char *)dst_info + info_size, NULL );
+            if (dst_info->bmiHeader.biClrUsed == 1 << dst_info->bmiHeader.biBitCount)
+                dst_info->bmiHeader.biClrUsed = 0;
+            break;
+        }
+
+        default:
+            FIXME( "Unknown brush style %x\n", logbrush.lbStyle );
+            return 0;
+    }
+
+    r = metadc_write_record( metadc, mr, mr->rdSize * sizeof(WORD) );
+    HeapFree(GetProcessHeap(), 0, mr);
+    if (!r) return -1;
+done:
+    return metadc_add_handle( metadc, brush );
+}
+
+static INT16 metadc_create_region( struct metadc *metadc, HRGN hrgn )
+{
+    DWORD len;
+    METARECORD *mr;
+    RGNDATA *rgndata;
+    RECT *cur_rect, *end_rect;
+    WORD bands = 0, max_bounds = 0;
+    WORD *param, *start_band;
+    BOOL ret;
+
+    if (!(len = GetRegionData( hrgn, 0, NULL ))) return -1;
+    if (!(rgndata = HeapAlloc( GetProcessHeap(), 0, len )))
+    {
+        WARN( "Can't alloc rgndata buffer\n" );
+        return -1;
+    }
+    GetRegionData( hrgn, len, rgndata );
+
+    /* Overestimate of length:
+     * Assume every rect is a separate band -> 6 WORDs per rect,
+     * see MF_Play_MetaCreateRegion for format details.
+     */
+    len = sizeof(METARECORD) + 20 + rgndata->rdh.nCount * 12;
+    if (!(mr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, len )))
+    {
+        WARN( "Can't alloc METARECORD buffer\n" );
+        HeapFree( GetProcessHeap(), 0, rgndata );
+        return -1;
+    }
+
+    param = mr->rdParm + 11;
+    start_band = NULL;
+
+    end_rect = (RECT *)rgndata->Buffer + rgndata->rdh.nCount;
+    for (cur_rect = (RECT *)rgndata->Buffer; cur_rect < end_rect; cur_rect++)
+    {
+        if (start_band && cur_rect->top == start_band[1])
+        {
+            *param++ = cur_rect->left;
+            *param++ = cur_rect->right;
+        }
+        else
+        {
+            if (start_band)
+            {
+                *start_band = param - start_band - 3;
+                *param++ = *start_band;
+                if (*start_band > max_bounds)
+                    max_bounds = *start_band;
+                bands++;
+            }
+            start_band = param++;
+            *param++ = cur_rect->top;
+            *param++ = cur_rect->bottom;
+            *param++ = cur_rect->left;
+            *param++ = cur_rect->right;
+        }
+    }
+
+    if (start_band)
+    {
+        *start_band = param - start_band - 3;
+        *param++ = *start_band;
+        if (*start_band > max_bounds)
+            max_bounds = *start_band;
+        bands++;
+    }
+
+    mr->rdParm[0] = 0;
+    mr->rdParm[1] = 6;
+    mr->rdParm[2] = 0x2f6;
+    mr->rdParm[3] = 0;
+    mr->rdParm[4] = (param - &mr->rdFunction) * sizeof(WORD);
+    mr->rdParm[5] = bands;
+    mr->rdParm[6] = max_bounds;
+    mr->rdParm[7] = rgndata->rdh.rcBound.left;
+    mr->rdParm[8] = rgndata->rdh.rcBound.top;
+    mr->rdParm[9] = rgndata->rdh.rcBound.right;
+    mr->rdParm[10] = rgndata->rdh.rcBound.bottom;
+    mr->rdFunction = META_CREATEREGION;
+    mr->rdSize = param - (WORD *)mr;
+    ret = metadc_write_record( metadc, mr, mr->rdSize * 2 );
+    HeapFree( GetProcessHeap(), 0, mr );
+    HeapFree( GetProcessHeap(), 0, rgndata );
+    if (!ret)
+    {
+        WARN("MFDRV_WriteRecord failed\n");
+        return -1;
+    }
+    return metadc_add_handle( metadc, hrgn );
+}
+
+BOOL METADC_PaintRgn( HDC hdc, HRGN hrgn )
+{
+    struct metadc *metadc;
+    INT16 index;
+    if (!(metadc = get_metadc_ptr( hdc ))) return FALSE;
+    index = metadc_create_region( metadc, hrgn );
+    if(index == -1) return FALSE;
+    return metadc_param1( hdc, META_PAINTREGION, index );
+}
+
+BOOL METADC_InvertRgn( HDC hdc, HRGN hrgn )
+{
+    struct metadc *metadc;
+    INT16 index;
+    if (!(metadc = get_metadc_ptr( hdc ))) return FALSE;
+    index = metadc_create_region( metadc, hrgn );
+    if (index == -1) return FALSE;
+    return metadc_param1( hdc, META_INVERTREGION, index );
+}
+
+BOOL METADC_FillRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush )
+{
+    struct metadc *metadc;
+    INT16 rgn, brush;
+
+    if (!(metadc = get_metadc_ptr( hdc ))) return FALSE;
+
+    rgn = metadc_create_region( metadc, hrgn );
+    if (rgn == -1) return FALSE;
+    brush = metadc_create_brush( metadc, hbrush );
+    if (!brush) return FALSE;
+    return metadc_param2( hdc, META_FILLREGION, rgn, brush );
+}
+
+BOOL METADC_FrameRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush, INT x, INT y )
+{
+    struct metadc *metadc;
+    INT16 rgn, brush;
+
+    if (!(metadc = get_metadc_ptr( hdc ))) return FALSE;
+    rgn = metadc_create_region( metadc, hrgn );
+    if (rgn == -1) return FALSE;
+    brush = metadc_create_brush( metadc, hbrush );
+    if (!brush) return FALSE;
+    return metadc_param4( hdc, META_FRAMEREGION, rgn, brush, x, y );
+}
+
+BOOL METADC_PatBlt( HDC hdc, INT left, INT top, INT width, INT height, DWORD rop )
+{
+    return metadc_param6( hdc, META_PATBLT, left, top, width, height,
+                          HIWORD(rop), LOWORD(rop) );
+}
+
+static BOOL metadc_stretchblt( HDC hdc, INT x_dst, INT y_dst, INT width_dst, INT height_dst,
+                               HDC hdc_src, INT x_src, INT y_src, INT width_src, INT height_src,
+                               DWORD rop, WORD type )
+{
+    BITMAPINFO src_info = {{ sizeof( src_info.bmiHeader ) }};
+    UINT bmi_size, size, bpp;
+    int i = 0, bitmap_offset;
+    BITMAPINFO *bmi;
+    METARECORD *mr;
+    HBITMAP bitmap;
+    BOOL ret;
+
+    if (!(bitmap = GetCurrentObject( hdc_src, OBJ_BITMAP ))) return FALSE;
+    if (!GetDIBits( hdc_src, bitmap, 0, INT_MAX, NULL, &src_info, DIB_RGB_COLORS )) return FALSE;
+
+    bpp = src_info.bmiHeader.biBitCount;
+    if (bpp <= 8)
+        bmi_size = sizeof(BITMAPINFOHEADER) + (1 << bpp) * sizeof(RGBQUAD);
+    else if (bpp == 16 || bpp == 32)
+        bmi_size = sizeof(BITMAPINFOHEADER) + 3 * sizeof(RGBQUAD);
+    else
+        bmi_size = sizeof(BITMAPINFOHEADER);
+
+    bitmap_offset = type == META_DIBBITBLT ? 8 : 10;
+    size = FIELD_OFFSET( METARECORD, rdParm[bitmap_offset] ) + bmi_size +
+        src_info.bmiHeader.biSizeImage;
+    if (!(mr = HeapAlloc( GetProcessHeap(), 0, size ))) return FALSE;
+    mr->rdFunction = type;
+    bmi = (BITMAPINFO *)&mr->rdParm[bitmap_offset];
+    bmi->bmiHeader = src_info.bmiHeader;
+    TRACE( "size = %u  rop=%x\n", size, rop );
+
+    ret = GetDIBits( hdc_src, bitmap, 0, src_info.bmiHeader.biHeight, (BYTE *)bmi + bmi_size,
+                     bmi, DIB_RGB_COLORS );
+    if (ret)
+    {
+        mr->rdSize = size / sizeof(WORD);
+        mr->rdParm[i++] = LOWORD(rop);
+        mr->rdParm[i++] = HIWORD(rop);
+        if (bitmap_offset > 8)
+        {
+            mr->rdParm[i++] = height_src;
+            mr->rdParm[i++] = width_src;
+        }
+        mr->rdParm[i++] = y_src;
+        mr->rdParm[i++] = x_src;
+        mr->rdParm[i++] = height_dst;
+        mr->rdParm[i++] = width_dst;
+        mr->rdParm[i++] = y_dst;
+        mr->rdParm[i++] = x_dst;
+        ret = metadc_record( hdc, mr, size );
+    }
+
+    HeapFree( GetProcessHeap(), 0, mr);
+    return ret;
+}
+
+BOOL METADC_BitBlt( HDC hdc, INT x_dst, INT y_dst, INT width, INT height,
+                    HDC hdc_src, INT x_src, INT y_src, DWORD rop )
+{
+    return metadc_stretchblt( hdc, x_dst, y_dst, width, height,
+                              hdc_src, x_src, y_src, width, height, rop, META_DIBBITBLT );
+}
+
+BOOL METADC_StretchBlt( HDC hdc_dst, INT x_dst, INT y_dst, INT width_dst, INT height_dst,
+                        HDC hdc_src, INT x_src, INT y_src, INT width_src, INT height_src,
+                        DWORD rop )
+{
+    return metadc_stretchblt( hdc_dst, x_dst, y_dst, width_dst, height_dst,
+                              hdc_src, x_src, y_src, width_src, height_src, rop, META_DIBSTRETCHBLT );
+}
+
+INT METADC_StretchDIBits( HDC hdc, INT x_dst, INT y_dst, INT width_dst,
+                          INT height_dst, INT x_src, INT y_src, INT width_src,
+                          INT height_src, const void *bits,
+                          const BITMAPINFO *info, UINT usage, DWORD rop )
+{
+    DWORD infosize = get_dib_info_size( info, usage );
+    DWORD len = sizeof(METARECORD) + 10 * sizeof(WORD) + infosize + info->bmiHeader.biSizeImage;
+    METARECORD *mr;
+
+    if (!(mr = HeapAlloc( GetProcessHeap(), 0, len ))) return 0;
+
+    mr->rdSize = len / sizeof(WORD);
+    mr->rdFunction = META_STRETCHDIB;
+    mr->rdParm[0] = LOWORD(rop);
+    mr->rdParm[1] = HIWORD(rop);
+    mr->rdParm[2] = usage;
+    mr->rdParm[3] = height_src;
+    mr->rdParm[4] = width_src;
+    mr->rdParm[5] = y_src;
+    mr->rdParm[6] = x_src;
+    mr->rdParm[7] = height_dst;
+    mr->rdParm[8] = width_dst;
+    mr->rdParm[9] = y_dst;
+    mr->rdParm[10] = x_dst;
+    memcpy( mr->rdParm + 11, info, infosize );
+    memcpy( mr->rdParm + 11 + infosize / 2, bits, info->bmiHeader.biSizeImage );
+    metadc_record( hdc, mr, mr->rdSize * sizeof(WORD) );
+    HeapFree( GetProcessHeap(), 0, mr );
+    return height_src;
+}
+
+INT METADC_SetDIBitsToDevice( HDC hdc, INT x_dst, INT y_dst, DWORD width, DWORD height,
+                              INT x_src, INT y_src, UINT startscan, UINT lines,
+                              const void *bits, const BITMAPINFO *info, UINT coloruse )
+
+{
+    DWORD infosize = get_dib_info_size(info, coloruse);
+    DWORD len = sizeof(METARECORD) + 8 * sizeof(WORD) + infosize + info->bmiHeader.biSizeImage;
+    METARECORD *mr;
+
+    if (!(mr = HeapAlloc( GetProcessHeap(), 0, len ))) return 0;
+
+    mr->rdSize = len / sizeof(WORD);
+    mr->rdFunction = META_SETDIBTODEV;
+    mr->rdParm[0] = coloruse;
+    mr->rdParm[1] = lines;
+    mr->rdParm[2] = startscan;
+    mr->rdParm[3] = y_src;
+    mr->rdParm[4] = x_src;
+    mr->rdParm[5] = height;
+    mr->rdParm[6] = width;
+    mr->rdParm[7] = y_dst;
+    mr->rdParm[8] = x_dst;
+    memcpy( mr->rdParm + 9, info, infosize );
+    memcpy( mr->rdParm + 9 + infosize / sizeof(WORD), bits, info->bmiHeader.biSizeImage );
+    metadc_record( hdc, mr, mr->rdSize * sizeof(WORD) );
+    HeapFree( GetProcessHeap(), 0, mr );
+    return lines;
+}
+
+static BOOL metadc_text( HDC hdc, short x, short y, UINT16 flags, const RECT16 *rect,
+                         const char *str, short count, const INT16 *dx )
+{
+    BOOL ret;
+    DWORD len;
+    METARECORD *mr;
+    BOOL isrect = flags & (ETO_CLIPPED | ETO_OPAQUE);
+
+    len = sizeof(METARECORD) + (((count + 1) >> 1) * 2) + 2 * sizeof(short)
+            + sizeof(UINT16);
+    if (isrect) len += sizeof(RECT16);
+    if (dx) len += count * sizeof(INT16);
+    if (!(mr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, len ))) return FALSE;
+
+    mr->rdSize = len / sizeof(WORD);
+    mr->rdFunction = META_EXTTEXTOUT;
+    mr->rdParm[0] = y;
+    mr->rdParm[1] = x;
+    mr->rdParm[2] = count;
+    mr->rdParm[3] = flags;
+    if (isrect) memcpy( mr->rdParm + 4, rect, sizeof(RECT16) );
+    memcpy( mr->rdParm + (isrect ? 8 : 4), str, count );
+    if (dx)
+        memcpy( mr->rdParm + (isrect ? 8 : 4) + ((count + 1) >> 1), dx, count * sizeof(INT16) );
+    ret = metadc_record( hdc, mr, mr->rdSize * sizeof(WORD) );
+    HeapFree( GetProcessHeap(), 0, mr );
+    return ret;
+}
+
+BOOL METADC_ExtTextOut( HDC hdc, INT x, INT y, UINT flags, const RECT *lprect,
+                        const WCHAR *str, UINT count, const INT *dx )
+{
+    RECT16 rect16;
+    LPINT16 lpdx16 = NULL;
+    BOOL ret;
+    unsigned int i, j;
+    char *ascii;
+    DWORD len;
+    CHARSETINFO csi;
+    int charset = GetTextCharset( hdc );
+    UINT cp = CP_ACP;
+
+    if (TranslateCharsetInfo( ULongToPtr(charset), &csi, TCI_SRCCHARSET ))
+        cp = csi.ciACP;
+    else
+    {
+        switch(charset)
+        {
+        case OEM_CHARSET:
+            cp = GetOEMCP();
+            break;
+        case DEFAULT_CHARSET:
+            cp = GetACP();
+            break;
+
+        case VISCII_CHARSET:
+        case TCVN_CHARSET:
+        case KOI8_CHARSET:
+        case ISO3_CHARSET:
+        case ISO4_CHARSET:
+        case ISO10_CHARSET:
+        case CELTIC_CHARSET:
+            /* FIXME: These have no place here, but because x11drv
+               enumerates fonts with these (made up) charsets some apps
+               might use them and then the FIXME below would become
+               annoying.  Now we could pick the intended codepage for
+               each of these, but since it's broken anyway we'll just
+               use CP_ACP and hope it'll go away...
+            */
+            cp = CP_ACP;
+            break;
+
+        default:
+            FIXME("Can't find codepage for charset %d\n", charset);
+            break;
+        }
+    }
+
+
+    TRACE( "cp = %d\n", cp );
+    len = WideCharToMultiByte( cp, 0, str, count, NULL, 0, NULL, NULL );
+    ascii = HeapAlloc( GetProcessHeap(), 0, len );
+    WideCharToMultiByte( cp, 0, str, count, ascii, len, NULL, NULL );
+    TRACE( "mapped %s -> %s\n", debugstr_wn(str, count), debugstr_an(ascii, len) );
+
+
+    if (lprect)
+    {
+        rect16.left   = lprect->left;
+        rect16.top    = lprect->top;
+        rect16.right  = lprect->right;
+        rect16.bottom = lprect->bottom;
+    }
+
+    if (dx)
+    {
+        lpdx16 = HeapAlloc( GetProcessHeap(), 0, sizeof(INT16) * len );
+        for (i = j = 0; i < len; )
+            if (IsDBCSLeadByteEx( cp, ascii[i] ))
+            {
+                lpdx16[i++] = dx[j++];
+                lpdx16[i++] = 0;
+            }
+            else
+                lpdx16[i++] = dx[j++];
+    }
+
+    ret = metadc_text( hdc, x, y, flags, lprect ? &rect16 : NULL, ascii, len, lpdx16 );
+    HeapFree( GetProcessHeap(), 0, ascii );
+    HeapFree( GetProcessHeap(), 0, lpdx16 );
+    return ret;
+}
+
+BOOL METADC_ExtSelectClipRgn( HDC hdc, HRGN hrgn, INT mode )
+{
+    struct metadc *metadc;
+    INT16 rgn;
+    INT ret;
+
+    if (!(metadc = get_metadc_ptr( hdc ))) return FALSE;
+    if (mode != RGN_COPY) return ERROR;
+    if (!hrgn) return NULLREGION;
+    rgn = metadc_create_region( metadc, hrgn );
+    if(rgn == -1) return ERROR;
+    ret = metadc_param1( hdc, META_SELECTOBJECT, rgn ) ? NULLREGION : ERROR;
+    metadc_param1( hdc, META_DELETEOBJECT, rgn );
+    metadc_remove_handle( metadc, rgn );
+    return ret;
+}
+
+static INT16 metadc_find_object( struct metadc *metadc, HGDIOBJ obj )
+{
+    INT16 index;
+
+    for (index = 0; index < metadc->handles_size; index++)
+        if (metadc->handles[index] == obj) return index;
+
+    return -1;
+}
+
+void METADC_DeleteObject( HDC hdc, HGDIOBJ obj )
+{
+    struct metadc *metadc = get_metadc_ptr( hdc );
+    METARECORD mr;
+    INT16 index;
+
+    if ((index = metadc_find_object( metadc, obj )) < 0) return;
+    if (obj == metadc->pen || obj == metadc->brush || obj == metadc->font)
+    {
+        WARN( "deleting selected object %p\n", obj );
+        return;
+    }
+
+    mr.rdSize = sizeof(mr) / sizeof(WORD);
+    mr.rdFunction = META_DELETEOBJECT;
+    mr.rdParm[0] = index;
+
+    metadc_write_record( metadc, &mr, mr.rdSize * sizeof(WORD) );
+
+    metadc->handles[index] = 0;
+    metadc->cur_handles--;
+}
+
+static BOOL metadc_select_object( HDC hdc, INT16 index)
+{
+    METARECORD mr;
+
+    mr.rdSize = sizeof mr / 2;
+    mr.rdFunction = META_SELECTOBJECT;
+    mr.rdParm[0] = index;
+    return metadc_record( hdc, &mr, mr.rdSize * sizeof(WORD) );
+}
+
+static HBRUSH METADC_SelectBrush( HDC hdc, HBRUSH hbrush )
+{
+    struct metadc *metadc = get_metadc_ptr( hdc );
+    INT16 index;
+    HBRUSH ret;
+
+    index = metadc_find_object( metadc, hbrush );
+    if( index < 0 )
+    {
+        index = metadc_create_brush( metadc, hbrush );
+        if( index < 0 )
+            return 0;
+        GDI_hdc_using_object( hbrush, hdc );//, METADC_DeleteObject );
+    }
+    if (!metadc_select_object( hdc, index )) return 0;
+    ret = metadc->brush;
+    metadc->brush = hbrush;
+    return ret;
+}
+
+static UINT16 metadc_create_font( struct metadc *metadc, HFONT font, LOGFONTW *logfont )
+{
+    char buffer[sizeof(METARECORD) - 2 + sizeof(LOGFONT16)];
+    METARECORD *mr = (METARECORD *)&buffer;
+    LOGFONT16 *font16;
+    INT written;
+
+    mr->rdSize = (sizeof(METARECORD) + sizeof(LOGFONT16) - 2) / 2;
+    mr->rdFunction = META_CREATEFONTINDIRECT;
+    font16 = (LOGFONT16 *)&mr->rdParm;
+
+    font16->lfHeight         = logfont->lfHeight;
+    font16->lfWidth          = logfont->lfWidth;
+    font16->lfEscapement     = logfont->lfEscapement;
+    font16->lfOrientation    = logfont->lfOrientation;
+    font16->lfWeight         = logfont->lfWeight;
+    font16->lfItalic         = logfont->lfItalic;
+    font16->lfUnderline      = logfont->lfUnderline;
+    font16->lfStrikeOut      = logfont->lfStrikeOut;
+    font16->lfCharSet        = logfont->lfCharSet;
+    font16->lfOutPrecision   = logfont->lfOutPrecision;
+    font16->lfClipPrecision  = logfont->lfClipPrecision;
+    font16->lfQuality        = logfont->lfQuality;
+    font16->lfPitchAndFamily = logfont->lfPitchAndFamily;
+    written = WideCharToMultiByte( CP_ACP, 0, logfont->lfFaceName, -1, font16->lfFaceName,
+                                   LF_FACESIZE - 1, NULL, NULL );
+    /* Zero pad the facename buffer, so that we don't write uninitialized data to disk */
+    memset( font16->lfFaceName + written, 0, LF_FACESIZE - written );
+
+    if (!metadc_write_record( metadc, mr, mr->rdSize * 2 ))
+        return 0;
+    return metadc_add_handle( metadc, font );
+}
+
+static HFONT METADC_SelectFont( HDC hdc, HFONT hfont )
+{
+    struct metadc *metadc = get_metadc_ptr( hdc );
+    LOGFONTW font;
+    INT16 index;
+    HFONT ret;
+
+    index = metadc_find_object( metadc, hfont );
+    if (index < 0)
+    {
+        if (!GetObjectW( hfont, sizeof(font), &font ))
+            return 0;
+        index = metadc_create_font( metadc, hfont, &font );
+        if( index < 0 )
+            return 0;
+        GDI_hdc_using_object( hfont, hdc );//, METADC_DeleteObject );
+    }
+    if (!metadc_select_object( hdc, index )) return 0;
+    ret = metadc->font;
+    metadc->font = hfont;
+    return ret;
+}
+
+static UINT16 metadc_create_pen( struct metadc *metadc, HPEN pen, LOGPEN16 *logpen )
+{
+    char buffer[FIELD_OFFSET(METARECORD, rdParm[sizeof(*logpen) / sizeof(WORD)])];
+    METARECORD *mr = (METARECORD *)&buffer;
+
+    mr->rdSize = sizeof(buffer) / sizeof(WORD);
+    mr->rdFunction = META_CREATEPENINDIRECT;
+    memcpy( mr->rdParm, logpen, sizeof(*logpen) );
+    if (!metadc_write_record( metadc, mr, mr->rdSize * sizeof(WORD) )) return 0;
+    return metadc_add_handle( metadc, pen );
+}
+
+static HPEN METADC_SelectPen( HDC hdc, HPEN hpen )
+{
+    struct metadc *metadc = get_metadc_ptr( hdc );
+    LOGPEN16 logpen;
+    INT16 index;
+    HPEN ret;
+
+    index = metadc_find_object( metadc, hpen );
+    if (index < 0)
+    {
+        /* must be an extended pen */
+        INT size = GetObjectW( hpen, 0, NULL );
+
+        if (!size) return 0;
+
+        if (size == sizeof(LOGPEN))
+        {
+            LOGPEN pen;
+
+            GetObjectW( hpen, sizeof(pen), &pen );
+            logpen.lopnStyle   = pen.lopnStyle;
+            logpen.lopnWidth.x = pen.lopnWidth.x;
+            logpen.lopnWidth.y = pen.lopnWidth.y;
+            logpen.lopnColor   = pen.lopnColor;
+        }
+        else  /* must be an extended pen */
+        {
+            EXTLOGPEN *elp = HeapAlloc( GetProcessHeap(), 0, size );
+
+            GetObjectW( hpen, size, elp );
+            /* FIXME: add support for user style pens */
+            logpen.lopnStyle = elp->elpPenStyle;
+            logpen.lopnWidth.x = elp->elpWidth;
+            logpen.lopnWidth.y = 0;
+            logpen.lopnColor = elp->elpColor;
+
+            HeapFree( GetProcessHeap(), 0, elp );
+        }
+
+        index = metadc_create_pen( metadc, hpen, &logpen );
+        if( index < 0 )
+            return 0;
+        GDI_hdc_using_object( hpen, hdc );//, METADC_DeleteObject );
+    }
+
+    if (!metadc_select_object( hdc, index )) return 0;
+    ret = metadc->pen;
+    metadc->pen = hpen;
+    return ret;
+}
+
+static BOOL metadc_create_palette( struct metadc *metadc, HPALETTE palette,
+                                   LOGPALETTE *log_palette, int sizeofPalette )
+{
+    int index;
+    BOOL ret;
+    METARECORD *mr;
+
+    mr = HeapAlloc( GetProcessHeap(), 0, sizeof(METARECORD) + sizeofPalette - sizeof(WORD) );
+    if (!mr) return FALSE;
+    mr->rdSize = (sizeof(METARECORD) + sizeofPalette - sizeof(WORD)) / sizeof(WORD);
+    mr->rdFunction = META_CREATEPALETTE;
+    memcpy(&(mr->rdParm), log_palette, sizeofPalette);
+    if (!metadc_write_record( metadc, mr, mr->rdSize * sizeof(WORD) ))
+    {
+        HeapFree(GetProcessHeap(), 0, mr);
+        return FALSE;
+    }
+
+    mr->rdSize = sizeof(METARECORD) / sizeof(WORD);
+    mr->rdFunction = META_SELECTPALETTE;
+
+    if ((index = metadc_add_handle( metadc, palette )) == -1) ret = FALSE;
+    else
+    {
+        mr->rdParm[0] = index;
+        ret = metadc_write_record( metadc, mr, mr->rdSize * sizeof(WORD) );
+    }
+    HeapFree( GetProcessHeap(), 0, mr );
+    return ret;
+}
+
+BOOL METADC_SelectPalette( HDC hdc, HPALETTE palette )
+{
+    struct metadc *metadc;
+    PLOGPALETTE log_palette;
+    WORD count = 0;
+    BOOL  ret;
+    int size;
+
+    if (!(metadc = get_metadc_ptr( hdc ))) return FALSE;
+    GetObjectA( palette, sizeof(WORD), &count );
+    if (!count) return 0;
+
+    size = sizeof(LOGPALETTE) + (count - 1) * sizeof(PALETTEENTRY);
+    log_palette = HeapAlloc( GetProcessHeap(), 0, size );
+    if (!log_palette) return 0;
+
+    log_palette->palVersion = 0x300;
+    log_palette->palNumEntries = count;
+
+    GetPaletteEntries( palette, 0, count, log_palette->palPalEntry );
+
+    ret = metadc_create_palette( metadc, palette, log_palette, size );
+
+    HeapFree( GetProcessHeap(), 0, log_palette );
+    return ret;
+}
+
+BOOL METADC_RealizePalette( HDC hdc )
+{
+    return metadc_param0( hdc, META_REALIZEPALETTE );
+}
+
+HGDIOBJ METADC_SelectObject( HDC hdc, HGDIOBJ obj )
+{
+    switch (GDI_HANDLE_GET_TYPE( obj ))
+    {
+    case GDILoObjType_LO_BRUSH_TYPE:
+        return METADC_SelectBrush( hdc, obj );
+    case GDILoObjType_LO_FONT_TYPE:
+        return METADC_SelectFont( hdc, obj );
+    case GDILoObjType_LO_PEN_TYPE:
+    case GDILoObjType_LO_EXTPEN_TYPE:
+        return METADC_SelectPen( hdc, obj );
+    default:
+        SetLastError( ERROR_INVALID_FUNCTION );
+        return 0;
+    }
+}
+
+BOOL METADC_ExtEscape( HDC hdc, INT escape, INT input_size, LPCSTR input, INT output_size, LPVOID output )
+{
+    METARECORD *mr;
+    DWORD len;
+    BOOL ret;
+
+    if (output_size) return FALSE;  /* escapes that require output cannot work in metafiles */
+
+    len = sizeof(*mr) + sizeof(WORD) + ((input_size + 1) & ~1);
+    if (!(mr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, len ))) return FALSE;
+    mr->rdSize = len / sizeof(WORD);
+    mr->rdFunction = META_ESCAPE;
+    mr->rdParm[0] = escape;
+    mr->rdParm[1] = input_size;
+    memcpy( &mr->rdParm[2], input, input_size );
+    ret = metadc_record( hdc, mr, len );
+    HeapFree(GetProcessHeap(), 0, mr);
+    return ret;
+}
+
+INT METADC_GetDeviceCaps( HDC hdc, INT cap )
+{
+    if (!get_metadc_ptr( hdc )) return 0;
+
+    switch(cap)
+    {
+    case TECHNOLOGY:
+        return DT_METAFILE;
+    case TEXTCAPS:
+        return 0;
+    default:
+        TRACE(" unsupported capability %d, will return 0\n", cap );
+    }
+    return 0;
+}
+
+static void metadc_free( struct metadc *metadc )
+{
+    DWORD index;
+
+    CloseHandle( metadc->hFile );
+    HeapFree( GetProcessHeap(), 0, metadc->mh );
+    for(index = 0; index < metadc->handles_size; index++)
+        if(metadc->handles[index])
+            GDI_hdc_not_using_object( metadc->handles[index], metadc->hdc );
+    HeapFree( GetProcessHeap(), 0, metadc->handles );
+    HeapFree( GetProcessHeap(), 0, metadc );
+}
+
+BOOL METADC_DeleteDC( HDC hdc )
+{
+    struct metadc *metadc;
+
+    if (!(metadc = get_metadc_ptr( hdc ))) return FALSE;
+    if (!GdiDeleteClientObj( hdc )) return FALSE;
+    metadc_free( metadc );
+    return TRUE;
+}
+
+/**********************************************************************
+ *           CreateMetaFileW   (GDI32.@)
+ *
+ *  Create a new DC and associate it with a metafile. Pass a filename
+ *  to create a disk-based metafile, NULL to create a memory metafile.
+ */
+HDC WINAPI CreateMetaFileW( const WCHAR *filename )
+{
+    struct metadc *metadc;
+    HANDLE hdc;
+
+    TRACE( "%s\n", debugstr_w(filename) );
+
+    metadc = HeapAlloc( GetProcessHeap(), 0, sizeof(*metadc) );
+    if (!metadc)
+    {
+        return NULL;
+    }
+    if (!(metadc->mh = HeapAlloc( GetProcessHeap(), 0, sizeof(*metadc->mh) )))
+    {
+        HeapFree( GetProcessHeap(), 0, metadc );
+        return NULL;
+    }
+
+    if (!(hdc = GdiCreateClientObj( metadc, GDILoObjType_LO_METADC16_TYPE )))
+    {
+        HeapFree( GetProcessHeap(), 0, metadc );
+        return NULL;
+    }
+
+    metadc->hdc = hdc;
+
+    metadc->handles = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
+                                 HANDLE_LIST_INC * sizeof(metadc->handles[0]) );
+    metadc->handles_size = HANDLE_LIST_INC;
+    metadc->cur_handles = 0;
+
+    metadc->hFile = 0;
+
+    metadc->mh->mtHeaderSize   = sizeof(METAHEADER) / sizeof(WORD);
+    metadc->mh->mtVersion      = 0x0300;
+    metadc->mh->mtSize         = metadc->mh->mtHeaderSize;
+    metadc->mh->mtNoObjects    = 0;
+    metadc->mh->mtMaxRecord    = 0;
+    metadc->mh->mtNoParameters = 0;
+    metadc->mh->mtType         = METAFILE_MEMORY;
+
+    metadc->pen   = GetStockObject( BLACK_PEN );
+    metadc->brush = GetStockObject( WHITE_BRUSH );
+    metadc->font  = GetStockObject( DEVICE_DEFAULT_FONT );
+
+    SetVirtualResolution( hdc, 0, 0, 0, 0);
+
+    if (filename)  /* disk based metafile */
+    {
+        HANDLE file = CreateFileW( filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0 );
+        if (file == INVALID_HANDLE_VALUE)
+        {
+            HeapFree( GetProcessHeap(), 0, metadc );
+            GdiDeleteClientObj( hdc );
+            return 0;
+        }
+        metadc->hFile = file;
+    }
+
+    TRACE( "returning %p\n", hdc );
+    return hdc;
+}
+
+/**********************************************************************
+ *           CreateMetaFileA   (GDI32.@)
+ */
+HDC WINAPI CreateMetaFileA( const char *filename )
+{
+    LPWSTR filenameW;
+    DWORD len;
+    HDC hdc;
+
+    if (!filename) return CreateMetaFileW( NULL );
+
+    len = MultiByteToWideChar( CP_ACP, 0, filename, -1, NULL, 0 );
+    filenameW = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
+    MultiByteToWideChar( CP_ACP, 0, filename, -1, filenameW, len );
+
+    hdc = CreateMetaFileW( filenameW );
+
+    HeapFree( GetProcessHeap(), 0, filenameW );
+    return hdc;
+}
+
+/******************************************************************
+ *           CloseMetaFile   (GDI32.@)
+ *
+ *  Stop recording graphics operations in metafile associated with
+ *  hdc and retrieve metafile.
+ */
+HMETAFILE WINAPI CloseMetaFile( HDC hdc )
+{
+    struct metadc *metadc;
+    DWORD bytes_written;
+    HMETAFILE hmf;
+
+    TRACE( "(%p)\n", hdc );
+
+    if (!(metadc = get_metadc_ptr( hdc ))) return FALSE;
+
+    /* Construct the end of metafile record - this is documented
+     * in SDK Knowledgebase Q99334.
+     */
+    if (!metadc_param0( hdc, META_EOF )) return FALSE;
+    if (!GdiDeleteClientObj( hdc )) return FALSE;
+
+    if (metadc->hFile && !WriteFile( metadc->hFile, metadc->mh, metadc->mh->mtSize * sizeof(WORD),
+                                     &bytes_written, NULL ))
+    {
+        metadc_free( metadc );
+        return FALSE;
+    }
+
+    /* Now allocate a global handle for the metafile */
+    hmf = MF_Create_HMETAFILE( metadc->mh );
+    if (hmf) metadc->mh = NULL;  /* So it won't be deleted */
+    metadc_free( metadc );
+    return hmf;
+}
index dbd5521..70d64f9 100644 (file)
@@ -1143,12 +1143,10 @@ static BOOL add_mf_comment(HDC hdc, HENHMETAFILE emf)
     if(!chunk) goto end;
 
     chunk->magic = WMFC_MAGIC;
-    chunk->unk04 = 1;
-    chunk->unk06 = 0;
-    chunk->unk08 = 0;
-    chunk->unk0a = 1;
+    chunk->comment_type = 0x1;
+    chunk->version = 0x00010000;
     chunk->checksum = 0; /* We fixup the first chunk's checksum before returning from GetWinMetaFileBits */
-    chunk->unk0e = 0;
+    chunk->flags = 0;
     chunk->num_chunks = (size + max_chunk_size - 1) / max_chunk_size;
     chunk->chunk_size = max_chunk_size;
     chunk->remaining_size = size;
index b537b90..80d6b73 100644 (file)
@@ -6,195 +6,6 @@
 #define NDEBUG
 #include <debug.h>
 
-WINEDC *get_nulldrv_dc( PHYSDEV dev );
-
-BOOL nulldrv_BeginPath( PHYSDEV dev );
-BOOL nulldrv_EndPath( PHYSDEV dev );
-BOOL nulldrv_AbortPath( PHYSDEV dev );
-BOOL nulldrv_CloseFigure( PHYSDEV dev );
-BOOL nulldrv_SelectClipPath( PHYSDEV dev, INT mode );
-BOOL nulldrv_FillPath( PHYSDEV dev );
-BOOL nulldrv_StrokeAndFillPath( PHYSDEV dev );
-BOOL nulldrv_StrokePath( PHYSDEV dev );
-BOOL nulldrv_FlattenPath( PHYSDEV dev );
-BOOL nulldrv_WidenPath( PHYSDEV dev );
-
-static INT i = 0;
-
-static
-INT_PTR
-NULL_Unused()
-{
-    DPRINT1("NULL_Unused %d\n",i);
-    // __debugbreak();
-    return 0;
-}
-
-static INT   NULL_SaveDC(PHYSDEV dev) { return 1; }
-static BOOL  NULL_RestoreDC(PHYSDEV dev, INT level) { return TRUE; }
-static INT   NULL_SetMapMode(PHYSDEV dev, INT iMode) { return 1; }
-static HFONT NULL_SelectFont(PHYSDEV dev, HFONT hFont, UINT *aa_flags) { return NULL; }
-static BOOL  NULL_SetWindowExtEx(PHYSDEV dev, INT cx, INT cy, SIZE *size) { return TRUE; }
-static BOOL  NULL_SetViewportExtEx(PHYSDEV dev, INT cx, INT cy, SIZE *size) { return TRUE; }
-static BOOL  NULL_SetWindowOrgEx(PHYSDEV dev, INT x, INT y, POINT *pt) { return TRUE; }
-static BOOL  NULL_SetViewportOrgEx(PHYSDEV dev, INT x, INT y, POINT *pt) { return TRUE; }
-static INT   NULL_ExtSelectClipRgn(PHYSDEV dev, HRGN hrgn, INT iMode) { return 1; }
-static INT   NULL_IntersectClipRect(PHYSDEV dev, INT left, INT top, INT right, INT bottom) { return 1; }
-static INT   NULL_OffsetClipRgn(PHYSDEV dev, INT x, INT y) { return SIMPLEREGION; }
-static INT   NULL_ExcludeClipRect(PHYSDEV dev, INT left, INT top, INT right, INT bottom) { return 1; }
-static BOOL  NULL_ExtTextOutW(PHYSDEV dev, INT x, INT y, UINT fuOptions, const RECT *lprc, LPCWSTR lpString, UINT cwc, const INT *lpDx) { return TRUE; }
-static BOOL  NULL_ModifyWorldTransform( PHYSDEV dev, const XFORM* xform, DWORD mode ) { return TRUE; }
-static BOOL  NULL_SetWorldTransform( PHYSDEV dev, const XFORM* xform ) { return TRUE; }
-static BOOL  NULL_PolyPolyline(PHYSDEV dev, const POINT *pt, const DWORD *lpt, DWORD cw) { return TRUE; }
-
-static const struct gdi_dc_funcs DummyPhysDevFuncs =
-{
-    (PVOID)NULL_Unused, //INT      (*pAbortDoc)(PHYSDEV);
-    nulldrv_AbortPath,  //BOOL     (*pAbortPath)(PHYSDEV);
-    (PVOID)NULL_Unused, //BOOL     (*pAlphaBlend)(PHYSDEV,struct bitblt_coords*,PHYSDEV,struct bitblt_coords*,BLENDFUNCTION);
-    (PVOID)NULL_Unused, //BOOL     (*pAngleArc)(PHYSDEV,INT,INT,DWORD,FLOAT,FLOAT);
-    (PVOID)NULL_Unused, //BOOL     (*pArc)(PHYSDEV,INT,INT,INT,INT,INT,INT,INT,INT);
-    (PVOID)NULL_Unused, //BOOL     (*pArcTo)(PHYSDEV,INT,INT,INT,INT,INT,INT,INT,INT);
-    nulldrv_BeginPath,  //BOOL     (*pBeginPath)(PHYSDEV);
-    (PVOID)NULL_Unused, //DWORD    (*pBlendImage)(PHYSDEV,BITMAPINFO*,const struct gdi_image_bits*,struct bitblt_coords*,struct bitblt_coords*,BLENDFUNCTION);
-    (PVOID)NULL_Unused, //BOOL     (*pChord)(PHYSDEV,INT,INT,INT,INT,INT,INT,INT,INT);
-    nulldrv_CloseFigure, //BOOL     (*pCloseFigure)(PHYSDEV);
-
-    (PVOID)NULL_Unused, //BOOL     (*pCreateCompatibleDC)(PHYSDEV,PHYSDEV*);
-    (PVOID)NULL_Unused, //BOOL     (*pCreateDC)(PHYSDEV*,LPCWSTR,LPCWSTR,LPCWSTR,const DEVMODEW*);
-    (PVOID)NULL_Unused, //BOOL     (*pDeleteDC)(PHYSDEV);
-    (PVOID)NULL_Unused, //BOOL     (*pDeleteObject)(PHYSDEV,HGDIOBJ);
-    (PVOID)NULL_Unused, //DWORD    (*pDeviceCapabilities)(LPSTR,LPCSTR,LPCSTR,WORD,LPSTR,LPDEVMODEA);
-    (PVOID)NULL_Unused, //BOOL     (*pEllipse)(PHYSDEV,INT,INT,INT,INT);
-    (PVOID)NULL_Unused, //INT      (*pEndDoc)(PHYSDEV);
-    (PVOID)NULL_Unused, //INT      (*pEndPage)(PHYSDEV);
-    nulldrv_EndPath,    //BOOL     (*pEndPath)(PHYSDEV);
-    (PVOID)NULL_Unused, //BOOL     (*pEnumFonts)(PHYSDEV,LPLOGFONTW,FONTENUMPROCW,LPARAM);
-
-    (PVOID)NULL_Unused, //INT      (*pEnumICMProfiles)(PHYSDEV,ICMENUMPROCW,LPARAM);
-    NULL_ExcludeClipRect, //INT      (*pExcludeClipRect)(PHYSDEV,INT,INT,INT,INT);
-    (PVOID)NULL_Unused, //INT      (*pExtDeviceMode)(LPSTR,HWND,LPDEVMODEA,LPSTR,LPSTR,LPDEVMODEA,LPSTR,DWORD);
-    (PVOID)NULL_Unused, //INT      (*pExtEscape)(PHYSDEV,INT,INT,LPCVOID,INT,LPVOID);
-    (PVOID)NULL_Unused, //BOOL     (*pExtFloodFill)(PHYSDEV,INT,INT,COLORREF,UINT);
-    NULL_ExtSelectClipRgn, //INT      (*pExtSelectClipRgn)(PHYSDEV,HRGN,INT);
-    NULL_ExtTextOutW, //BOOL     (*pExtTextOut)(PHYSDEV,INT,INT,UINT,const RECT*,LPCWSTR,UINT,const INT*);
-    nulldrv_FillPath,   //BOOL     (*pFillPath)(PHYSDEV);
-    (PVOID)NULL_Unused, //BOOL     (*pFillRgn)(PHYSDEV,HRGN,HBRUSH);
-    nulldrv_FlattenPath, //BOOL     (*pFlattenPath)(PHYSDEV);
-
-    (PVOID)NULL_Unused, //BOOL     (*pFontIsLinked)(PHYSDEV);
-    (PVOID)NULL_Unused, //BOOL     (*pFrameRgn)(PHYSDEV,HRGN,HBRUSH,INT,INT);
-    (PVOID)NULL_Unused, //BOOL     (*pGdiComment)(PHYSDEV,UINT,const BYTE*);
-    (PVOID)NULL_Unused, //UINT     (*pGetBoundsRect)(PHYSDEV,RECT*,UINT);
-    (PVOID)NULL_Unused, //BOOL     (*pGetCharABCWidths)(PHYSDEV,UINT,UINT,LPABC);
-    (PVOID)NULL_Unused, //BOOL     (*pGetCharABCWidthsI)(PHYSDEV,UINT,UINT,WORD*,LPABC);
-    (PVOID)NULL_Unused, //BOOL     (*pGetCharWidth)(PHYSDEV,UINT,UINT,LPINT);
-    (PVOID)NULL_Unused, //BOOL     (*pGetCharWidthInfo)(PHYSDEV,void*);
-    (PVOID)NULL_Unused, //INT      (*pGetDeviceCaps)(PHYSDEV,INT);
-    (PVOID)NULL_Unused, //BOOL     (*pGetDeviceGammaRamp)(PHYSDEV,LPVOID);
-    (PVOID)NULL_Unused, //DWORD    (*pGetFontData)(PHYSDEV,DWORD,DWORD,LPVOID,DWORD);
-    (PVOID)NULL_Unused, //BOOL     (*pGetFontRealizationInfo)(PHYSDEV,void*);
-    (PVOID)NULL_Unused, //DWORD    (*pGetFontUnicodeRanges)(PHYSDEV,LPGLYPHSET);
-    (PVOID)NULL_Unused, //DWORD    (*pGetGlyphIndices)(PHYSDEV,LPCWSTR,INT,LPWORD,DWORD);
-    (PVOID)NULL_Unused, //DWORD    (*pGetGlyphOutline)(PHYSDEV,UINT,UINT,LPGLYPHMETRICS,DWORD,LPVOID,const MAT2*);
-    (PVOID)NULL_Unused, //BOOL     (*pGetICMProfile)(PHYSDEV,LPDWORD,LPWSTR);
-    (PVOID)NULL_Unused, //DWORD    (*pGetImage)(PHYSDEV,BITMAPINFO*,struct gdi_image_bits*,struct bitblt_coords*);
-    (PVOID)NULL_Unused, //DWORD    (*pGetKerningPairs)(PHYSDEV,DWORD,LPKERNINGPAIR);
-    (PVOID)NULL_Unused, //COLORREF (*pGetNearestColor)(PHYSDEV,COLORREF);
-    (PVOID)NULL_Unused, //UINT     (*pGetOutlineTextMetrics)(PHYSDEV,UINT,LPOUTLINETEXTMETRICW);
-    (PVOID)NULL_Unused, //COLORREF (*pGetPixel)(PHYSDEV,INT,INT);
-    (PVOID)NULL_Unused, //UINT     (*pGetSystemPaletteEntries)(PHYSDEV,UINT,UINT,LPPALETTEENTRY);
-    (PVOID)NULL_Unused, //UINT     (*pGetTextCharsetInfo)(PHYSDEV,LPFONTSIGNATURE,DWORD);
-    (PVOID)NULL_Unused, //BOOL     (*pGetTextExtentExPoint)(PHYSDEV,LPCWSTR,INT,LPINT);
-    (PVOID)NULL_Unused, //BOOL     (*pGetTextExtentExPointI)(PHYSDEV,const WORD*,INT,LPINT);
-    (PVOID)NULL_Unused, //INT      (*pGetTextFace)(PHYSDEV,INT,LPWSTR);
-    (PVOID)NULL_Unused, //BOOL     (*pGetTextMetrics)(PHYSDEV,TEXTMETRICW*);
-    (PVOID)NULL_Unused, //BOOL     (*pGradientFill)(PHYSDEV,TRIVERTEX*,ULONG,void*,ULONG,ULONG);
-    NULL_IntersectClipRect, //INT      (*pIntersectClipRect)(PHYSDEV,INT,INT,INT,INT);
-    (PVOID)NULL_Unused, //BOOL     (*pInvertRgn)(PHYSDEV,HRGN);
-    (PVOID)NULL_Unused, //BOOL     (*pLineTo)(PHYSDEV,INT,INT);
-    NULL_ModifyWorldTransform, //BOOL     (*pModifyWorldTransform)(PHYSDEV,const XFORM*,DWORD);
-    (PVOID)NULL_Unused, //BOOL     (*pMoveTo)(PHYSDEV,INT,INT);
-    NULL_OffsetClipRgn, //INT      (*pOffsetClipRgn)(PHYSDEV,INT,INT);
-    (PVOID)NULL_Unused, //BOOL     (*pOffsetViewportOrgEx)(PHYSDEV,INT,INT,POINT*);
-    (PVOID)NULL_Unused, //BOOL     (*pOffsetWindowOrgEx)(PHYSDEV,INT,INT,POINT*);
-    (PVOID)NULL_Unused, //BOOL     (*pPaintRgn)(PHYSDEV,HRGN);
-    (PVOID)NULL_Unused, //BOOL     (*pPatBlt)(PHYSDEV,struct bitblt_coords*,DWORD);
-    (PVOID)NULL_Unused, //BOOL     (*pPie)(PHYSDEV,INT,INT,INT,INT,INT,INT,INT,INT);
-    (PVOID)NULL_Unused, //BOOL     (*pPolyBezier)(PHYSDEV,const POINT*,DWORD);
-    (PVOID)NULL_Unused, //BOOL     (*pPolyBezierTo)(PHYSDEV,const POINT*,DWORD);
-    (PVOID)NULL_Unused, //BOOL     (*pPolyDraw)(PHYSDEV,const POINT*,const BYTE *,DWORD);
-    (PVOID)NULL_Unused, //BOOL     (*pPolyPolygon)(PHYSDEV,const POINT*,const INT*,UINT);
-    NULL_PolyPolyline, //BOOL     (*pPolyPolyline)(PHYSDEV,const POINT*,const DWORD*,DWORD);
-    (PVOID)NULL_Unused, //BOOL     (*pPolygon)(PHYSDEV,const POINT*,INT);
-    (PVOID)NULL_Unused, //BOOL     (*pPolyline)(PHYSDEV,const POINT*,INT);
-    (PVOID)NULL_Unused, //BOOL     (*pPolylineTo)(PHYSDEV,const POINT*,INT);
-    (PVOID)NULL_Unused, //DWORD    (*pPutImage)(PHYSDEV,HRGN,BITMAPINFO*,const struct gdi_image_bits*,struct bitblt_coords*,struct bitblt_coords*,DWORD);
-    (PVOID)NULL_Unused, //UINT     (*pRealizeDefaultPalette)(PHYSDEV);
-    (PVOID)NULL_Unused, //UINT     (*pRealizePalette)(PHYSDEV,HPALETTE,BOOL);
-    (PVOID)NULL_Unused, //BOOL     (*pRectangle)(PHYSDEV,INT,INT,INT,INT);
-    (PVOID)NULL_Unused, //HDC      (*pResetDC)(PHYSDEV,const DEVMODEW*);
-    NULL_RestoreDC,     //BOOL     (*pRestoreDC)(PHYSDEV,INT);
-    (PVOID)NULL_Unused, //BOOL     (*pRoundRect)(PHYSDEV,INT,INT,INT,INT,INT,INT);
-    NULL_SaveDC,        //INT      (*pSaveDC)(PHYSDEV);
-    (PVOID)NULL_Unused, //BOOL     (*pScaleViewportExtEx)(PHYSDEV,INT,INT,INT,INT,SIZE*);
-    (PVOID)NULL_Unused, //BOOL     (*pScaleWindowExtEx)(PHYSDEV,INT,INT,INT,INT,SIZE*);
-    (PVOID)NULL_Unused, //HBITMAP  (*pSelectBitmap)(PHYSDEV,HBITMAP);
-    (PVOID)NULL_Unused, //HBRUSH   (*pSelectBrush)(PHYSDEV,HBRUSH,const struct brush_pattern*);
-    nulldrv_SelectClipPath, //BOOL     (*pSelectClipPath)(PHYSDEV,INT);
-    NULL_SelectFont,    //HFONT    (*pSelectFont)(PHYSDEV,HFONT,UINT*);
-    (PVOID)NULL_Unused, //HPALETTE (*pSelectPalette)(PHYSDEV,HPALETTE,BOOL);
-    (PVOID)NULL_Unused, //HPEN     (*pSelectPen)(PHYSDEV,HPEN,const struct brush_pattern*);
-    (PVOID)NULL_Unused, //INT      (*pSetArcDirection)(PHYSDEV,INT);
-    (PVOID)NULL_Unused, //COLORREF (*pSetBkColor)(PHYSDEV,COLORREF);
-    (PVOID)NULL_Unused, //INT      (*pSetBkMode)(PHYSDEV,INT);
-    (PVOID)NULL_Unused, //UINT     (*pSetBoundsRect)(PHYSDEV,RECT*,UINT);
-    (PVOID)NULL_Unused, //COLORREF (*pSetDCBrushColor)(PHYSDEV, COLORREF);
-    (PVOID)NULL_Unused, //COLORREF (*pSetDCPenColor)(PHYSDEV, COLORREF);
-    (PVOID)NULL_Unused, //INT      (*pSetDIBitsToDevice)(PHYSDEV,INT,INT,DWORD,DWORD,INT,INT,UINT,UINT,LPCVOID,BITMAPINFO*,UINT);
-    (PVOID)NULL_Unused, //VOID     (*pSetDeviceClipping)(PHYSDEV,HRGN);
-    (PVOID)NULL_Unused, //BOOL     (*pSetDeviceGammaRamp)(PHYSDEV,LPVOID);
-    (PVOID)NULL_Unused, //DWORD    (*pSetLayout)(PHYSDEV,DWORD);
-    NULL_SetMapMode,    //INT      (*pSetMapMode)(PHYSDEV,INT);
-    (PVOID)NULL_Unused, //DWORD    (*pSetMapperFlags)(PHYSDEV,DWORD);
-    (PVOID)NULL_Unused, //COLORREF (*pSetPixel)(PHYSDEV,INT,INT,COLORREF);
-    (PVOID)NULL_Unused, //INT      (*pSetPolyFillMode)(PHYSDEV,INT);
-    (PVOID)NULL_Unused, //INT      (*pSetROP2)(PHYSDEV,INT);
-    (PVOID)NULL_Unused, //INT      (*pSetRelAbs)(PHYSDEV,INT);
-    (PVOID)NULL_Unused, //INT      (*pSetStretchBltMode)(PHYSDEV,INT);
-    (PVOID)NULL_Unused, //UINT     (*pSetTextAlign)(PHYSDEV,UINT);
-    (PVOID)NULL_Unused, //INT      (*pSetTextCharacterExtra)(PHYSDEV,INT);
-    (PVOID)NULL_Unused, //COLORREF (*pSetTextColor)(PHYSDEV,COLORREF);
-    (PVOID)NULL_Unused, //BOOL     (*pSetTextJustification)(PHYSDEV,INT,INT);
-    NULL_SetViewportExtEx, //BOOL     (*pSetViewportExtEx)(PHYSDEV,INT,INT,SIZE*);
-    NULL_SetViewportOrgEx, //BOOL     (*pSetViewportOrgEx)(PHYSDEV,INT,INT,POINT*);
-    NULL_SetWindowExtEx, //BOOL     (*pSetWindowExtEx)(PHYSDEV,INT,INT,SIZE*);
-    NULL_SetWindowOrgEx, //BOOL     (*pSetWindowOrgEx)(PHYSDEV,INT,INT,POINT*);
-    NULL_SetWorldTransform, //BOOL     (*pSetWorldTransform)(PHYSDEV,const XFORM*);
-    (PVOID)NULL_Unused, //INT      (*pStartDoc)(PHYSDEV,const DOCINFOW*);
-    (PVOID)NULL_Unused, //INT      (*pStartPage)(PHYSDEV);
-    (PVOID)NULL_Unused, //BOOL     (*pStretchBlt)(PHYSDEV,struct bitblt_coords*,PHYSDEV,struct bitblt_coords*,DWORD);
-    (PVOID)NULL_Unused, //INT      (*pStretchDIBits)(PHYSDEV,INT,INT,INT,INT,INT,INT,INT,INT,const void*,BITMAPINFO*,UINT,DWORD);
-    nulldrv_StrokeAndFillPath, //BOOL     (*pStrokeAndFillPath)(PHYSDEV);
-    nulldrv_StrokePath, //BOOL     (*pStrokePath)(PHYSDEV);
-    (PVOID)NULL_Unused, //BOOL     (*pUnrealizePalette)(HPALETTE);
-    nulldrv_WidenPath,  //BOOL     (*pWidenPath)(PHYSDEV);
-    (PVOID)NULL_Unused, //struct opengl_funcs * (*wine_get_wgl_driver)(PHYSDEV,UINT);
-    0 // UINT       priority;
-};
-
-WINEDC *get_nulldrv_dc( PHYSDEV dev )
-{
-    return CONTAINING_RECORD( dev, WINEDC, NullPhysDev );
-}
-
-WINEDC* get_physdev_dc( PHYSDEV dev )
-{
-    while (dev->funcs != &DummyPhysDevFuncs)
-        dev = dev->next;
-    return get_nulldrv_dc( dev );
-}
-
 static
 GDILOOBJTYPE
 ConvertObjectType(
@@ -304,11 +115,8 @@ alloc_dc_ptr(WORD magic)
     }
 
     ZeroMemory(pWineDc, sizeof(*pWineDc));
-    pWineDc->refcount = 1;
-    pWineDc->hFont = GetStockObject(SYSTEM_FONT);
     pWineDc->hBrush = GetStockObject(WHITE_BRUSH);
     pWineDc->hPen = GetStockObject(BLACK_PEN);
-    pWineDc->hPalette = GetStockObject(DEFAULT_PALETTE);
 
     if (magic == OBJ_ENHMETADC)
     {
@@ -326,54 +134,15 @@ alloc_dc_ptr(WORD magic)
         /* Set the Wine DC as LDC */
         GdiSetLDC(pWineDc->hdc, pWineDc);
     }
-    else if (magic == OBJ_METADC)
-    {
-        pWineDc->hdc = GdiCreateClientObj(pWineDc, GDILoObjType_LO_METADC16_TYPE);
-        if (pWineDc->hdc == NULL)
-        {
-            HeapFree(GetProcessHeap(), 0, pWineDc);
-            return NULL;
-        }
-    }
     else
     {
         // nothing else supported!
         ASSERT(FALSE);
     }
 
-    pWineDc->physDev = &pWineDc->NullPhysDev;
-    pWineDc->NullPhysDev.funcs = &DummyPhysDevFuncs;
-    pWineDc->NullPhysDev.next = NULL;
-
-    pWineDc->NullPhysDev.hdc = pWineDc->hdc;
     return pWineDc;
 }
 
-VOID
-free_dc_ptr(WINEDC* pWineDc)
-{
-    /* Invoke the DeleteDC callback to clean up the DC */
-    pWineDc->physDev->funcs->pDeleteDC(pWineDc->physDev);
-
-    /* FIXME */
-    if (GDI_HANDLE_GET_TYPE(pWineDc->hdc) == GDILoObjType_LO_ALTDC_TYPE)
-    {
-        /* Get rid of the LDC */
-        ASSERT((WINEDC*)GdiGetLDC(pWineDc->hdc) == pWineDc);
-        GdiSetLDC(pWineDc->hdc, NULL);
-
-        /* Free the DC */
-        NtGdiDeleteObjectApp(pWineDc->hdc);
-    }
-    else if (GDI_HANDLE_GET_TYPE(pWineDc->hdc) == GDILoObjType_LO_METADC16_TYPE)
-    {
-        GdiDeleteClientObj(pWineDc->hdc);
-    }
-
-    /* Free the Wine DC */
-    HeapFree(GetProcessHeap(), 0, pWineDc);
-}
-
 WINEDC*
 get_dc_ptr(HDC hdc)
 {
@@ -393,25 +162,6 @@ get_dc_ptr(HDC hdc)
     return NULL;
 }
 
-VOID
-release_dc_ptr(WINEDC* dc)
-{
-    /* We don't do any reference-counting */
-}
-
-void
-push_dc_driver_ros(
-    PHYSDEV *dev,
-    PHYSDEV physdev,
-    const struct gdi_dc_funcs *funcs)
-{
-    while ((*dev)->funcs->priority > funcs->priority) dev = &(*dev)->next;
-    physdev->funcs = funcs;
-    physdev->next = *dev;
-    physdev->hdc = CONTAINING_RECORD(dev, WINEDC, physDev)->hdc;
-    *dev = physdev;
-}
-
 VOID
 GDI_hdc_using_object(
     HGDIOBJ hobj,
@@ -473,11 +223,12 @@ BOOL
 get_brush_bitmap_info(
     HBRUSH hbr,
     PBITMAPINFO pbmi,
-    PVOID *ppvBits,
+    PVOID pvBits,
     PUINT puUsage)
 {
     HBITMAP hbmp;
     HDC hdc;
+    PVOID Bits;
 
     /* Call win32k to get the bitmap handle and color usage */
     hbmp = NtGdiGetObjectBitmapHandle(hbr, puUsage);
@@ -496,17 +247,22 @@ get_brush_bitmap_info(
     if (!GetDIBits(hdc, hbmp, 0, 0, NULL, pbmi, *puUsage))
         return FALSE;
 
-    /* Now allocate a buffer for the bits */
-    *ppvBits = HeapAlloc(GetProcessHeap(), 0, pbmi->bmiHeader.biSizeImage);
-    if (*ppvBits == NULL)
-        return FALSE;
-
-    /* Retrieve the bitmap bits */
-    if (!GetDIBits(hdc, hbmp, 0, pbmi->bmiHeader.biHeight, *ppvBits, pbmi, *puUsage))
+    if (pvBits)
     {
-        HeapFree(GetProcessHeap(), 0, *ppvBits);
-        *ppvBits = NULL;
-        return FALSE;
+        /* Now allocate a buffer for the bits */
+        Bits = HeapAlloc(GetProcessHeap(), 0, pbmi->bmiHeader.biSizeImage);
+        if (Bits == NULL)
+            return FALSE;
+
+        /* Retrieve the bitmap bits */
+        if (!GetDIBits(hdc, hbmp, 0, pbmi->bmiHeader.biHeight, Bits, pbmi, *puUsage))
+        {
+            HeapFree(GetProcessHeap(), 0, Bits);
+            return FALSE;
+        }
+
+        CopyMemory( pvBits, Bits, pbmi->bmiHeader.biSizeImage );
+
     }
 
     /* GetDIBits doesn't set biClrUsed, but wine code needs it, so we set it */
@@ -514,7 +270,6 @@ get_brush_bitmap_info(
     {
         pbmi->bmiHeader.biClrUsed =  1 << pbmi->bmiHeader.biBitCount;
     }
-
     return TRUE;
 }
 
@@ -541,34 +296,6 @@ DeleteColorSpace(
 {
     return NtGdiDeleteColorSpace(hcs);
 }
-#if 0
-BOOL
-WINAPI
-SetWorldTransformForMetafile(
-    _In_ HDC hdc,
-    _Out_ CONST XFORM *pxform)
-{
-    if (GDI_HANDLE_GET_TYPE(hdc) == GDILoObjType_LO_METADC16_TYPE)
-    {
-#if 0
-        //HANDLE_METADC(BOOL, ModifyWorldTransform, FALSE, hdc, pxform, MWT_SET);
-        /* Get the physdev */
-        physdev = GetPhysDev(hdc);
-        if (physdev == NULL)
-        {
-            DPRINT1("Failed to get physdev for meta DC %p\n", hdc);
-            return FALSE;
-        }
-
-        physdev->funcs->pSetWorldTransform(physdev, pxform);
-#endif
-        // HACK!!!
-        return TRUE;
-    }
-
-    return SetWorldTransform(hdc, pxform);
-}
-#endif
 void
 __cdecl
 _assert (
@@ -580,657 +307,52 @@ _assert (
 }
 
 /******************************************************************************/
-
-static
-VOID
-InitBitBltCoords(
-    struct bitblt_coords *coords,
-    HDC hdc,
-    int x,
-    int y,
-    int cx,
-    int cy)
-{
-    coords->log_x      = x;
-    coords->log_y      = y;
-    coords->log_width  = cx;
-    coords->log_height = cy;
-    coords->layout     = GetLayout(hdc);
-}
-
-static
-PHYSDEV
-GetPhysDev(
-    HDC hdc)
-{
-    WINEDC *pWineDc;
-
-    pWineDc = get_dc_ptr(hdc);
-    if (pWineDc == NULL)
-    {
-        return NULL;
-    }
-
-    return pWineDc->physDev;
-}
-
-static
 BOOL
-DRIVER_PatBlt(
-    _In_ PHYSDEV physdev,
-    _In_ HDC hdc,
-    _In_ INT xLeft,
-    _In_ INT yTop,
-    _In_ INT cx,
-    _In_ INT cy,
-    _In_ DWORD dwRop)
-{
-    struct bitblt_coords coords;
-
-    InitBitBltCoords(&coords, hdc, xLeft, yTop, cx, cy);
-
-    return physdev->funcs->pPatBlt(physdev, &coords, dwRop);
-}
-
-static
-BOOL
-DRIVER_StretchBlt(
-    _In_ PHYSDEV physdev,
-    _In_ HDC hdcDst,
-    _In_ INT xDst,
-    _In_ INT yDst,
-    _In_ INT cxDst,
-    _In_ INT cyDst,
-    _In_opt_ HDC hdcSrc,
-    _In_ INT xSrc,
-    _In_ INT ySrc,
-    _In_ INT cxSrc,
-    _In_ INT cySrc,
-    _In_ DWORD dwRop)
-{
-    struct bitblt_coords coordsDst, coordsSrc;
-    struct gdi_physdev physdevSrc = {0};
-
-    /* Source cannot be a metafile */
-    if (GDI_HANDLE_GET_TYPE(hdcSrc) != GDILoObjType_LO_DC_TYPE)
-        return FALSE;
-
-    /* Source physdev uses only hdc and func */
-    physdevSrc.hdc = hdcSrc;
-
-    InitBitBltCoords(&coordsDst, hdcDst, xDst, yDst, cxDst, cyDst);
-    InitBitBltCoords(&coordsSrc, hdcSrc, xSrc, ySrc, cxSrc, cySrc);
-
-    return physdev->funcs->pStretchBlt(physdev, &coordsDst, &physdevSrc, &coordsSrc, dwRop);
-}
-
-static
-BOOL
-DRIVER_RestoreDC(PHYSDEV physdev, INT level)
-{
-    WINEDC *pWineDc = get_dc_ptr(physdev->hdc);
-
-    if (GDI_HANDLE_GET_TYPE(physdev->hdc) == GDILoObjType_LO_ALTDC_TYPE)
-    {
-        /* The Restore DC function needs the save level to be set correctly.
-           Note that wine's level is 0 based, while our's is (like win) 1 based. */
-        pWineDc->saveLevel = GetDCDWord(physdev->hdc, GdiGetEMFRestorDc, 0)  - 1;
-
-        /* Fail if the level is not valid */
-        if ((abs(level) > pWineDc->saveLevel) || (level == 0))
-            return FALSE;
-    }
-
-    return physdev->funcs->pRestoreDC(physdev,level);
-}
-
-static
-HFONT
-DRIVER_SelectFont(PHYSDEV physdev, HFONT hFont, UINT *aa_flags)
-{
-    WINEDC *pWineDc = get_dc_ptr(physdev->hdc);
-    HFONT hOldFont;
-
-    if (!physdev->funcs->pSelectFont(physdev, hFont, aa_flags))
-        return 0;
-
-    hOldFont = pWineDc->hFont;
-    pWineDc->hFont = hFont;
-    return hOldFont;
-}
-
-static
-HPEN
-DRIVER_SelectPen(PHYSDEV physdev, HPEN hpen, const struct brush_pattern *pattern)
-{
-    WINEDC *pWineDc = get_dc_ptr(physdev->hdc);
-    HPEN hOldPen;
-
-    if (!physdev->funcs->pSelectPen(physdev, hpen, pattern))
-        return 0;
-
-    hOldPen = pWineDc->hPen;
-    pWineDc->hPen = hpen;
-    return hOldPen;
-}
-
-static
-HBRUSH
-DRIVER_SelectBrush(PHYSDEV physdev, HBRUSH hbrush, const struct brush_pattern *pattern)
-{
-    WINEDC *pWineDc = get_dc_ptr(physdev->hdc);
-    HBRUSH hOldBrush;
-
-    if (!physdev->funcs->pSelectBrush(physdev, hbrush, pattern))
-        return 0;
-
-    hOldBrush = pWineDc->hBrush;
-    pWineDc->hBrush = hbrush;
-    return hOldBrush;
-}
-
-static
-HRGN
-DRIVER_PathToRegion(PHYSDEV physdev)
-{
-    DPRINT1("DRIVER_PathToRegion\n");
-    return (HRGN)(ULONG_PTR)physdev->funcs->pAbortPath( physdev );
-}
-
-
-static
-DWORD_PTR
-DRIVER_Dispatch(
-    _In_ PHYSDEV physdev,
-    _In_ DCFUNC eFunction,
-    _In_ va_list argptr)
-{
-    UINT aa_flags = 0;
-
-/* Note that this is a hack that relies on some assumptions regarding the
-   Windows ABI. It relies on the fact that all vararg functions put their
-   parameters on the stack in the correct order. Additionally it relies
-   on the fact that none of the functions we handle here, pass any 64
-   bit arguments on a 32 bit architecture. */
-#define _va_arg_n(p,t,i) (*(t*)((intptr_t*)(p) + i))
-
-    switch (eFunction)
-    {
-        case DCFUNC_AbortPath:
-            return physdev->funcs->pAbortPath(physdev);
-        case DCFUNC_Arc:
-            return physdev->funcs->pArc(physdev,
-                                        _va_arg_n(argptr, INT, 0), // left
-                                        _va_arg_n(argptr, INT, 1), // top
-                                        _va_arg_n(argptr, INT, 2), // right
-                                        _va_arg_n(argptr, INT, 3), // bottom
-                                        _va_arg_n(argptr, INT, 4), // xstart
-                                        _va_arg_n(argptr, INT, 5), // ystart
-                                        _va_arg_n(argptr, INT, 6), // xend
-                                        _va_arg_n(argptr, INT, 7)); // yend
-        case DCFUNC_BeginPath:
-            return physdev->funcs->pBeginPath(physdev);
-        case DCFUNC_Chord:
-            return physdev->funcs->pChord(physdev,
-                                          _va_arg_n(argptr, INT, 0),
-                                          _va_arg_n(argptr, INT, 1),
-                                          _va_arg_n(argptr, INT, 2),
-                                          _va_arg_n(argptr, INT, 3),
-                                          _va_arg_n(argptr, INT, 4),
-                                          _va_arg_n(argptr, INT, 5),
-                                          _va_arg_n(argptr, INT, 6),
-                                          _va_arg_n(argptr, INT, 7));
-        case DCFUNC_CloseFigure:
-            return physdev->funcs->pCloseFigure(physdev);
-        case DCFUNC_Ellipse:
-            return physdev->funcs->pEllipse(physdev,
-                                            _va_arg_n(argptr, INT, 0),
-                                            _va_arg_n(argptr, INT, 1),
-                                            _va_arg_n(argptr, INT, 2),
-                                            _va_arg_n(argptr, INT, 3));
-        case DCFUNC_EndPath:
-            return physdev->funcs->pEndPath(physdev);
-        case DCFUNC_ExcludeClipRect:
-            return physdev->funcs->pExcludeClipRect(physdev,
-                                              _va_arg_n(argptr, INT, 0),
-                                              _va_arg_n(argptr, INT, 1),
-                                              _va_arg_n(argptr, INT, 2),
-                                              _va_arg_n(argptr, INT, 3));
-        case DCFUNC_ExtEscape:
-            ASSERT(physdev->funcs->pExtEscape != NULL);
-            return physdev->funcs->pExtEscape(physdev,
-                                              _va_arg_n(argptr, INT, 0),
-                                              _va_arg_n(argptr, INT, 1),
-                                              _va_arg_n(argptr, LPCVOID, 2),
-                                              _va_arg_n(argptr, INT, 3),
-                                              _va_arg_n(argptr, LPVOID, 4));
-        case DCFUNC_ExtFloodFill:
-            return physdev->funcs->pExtFloodFill(physdev,
-                                                 _va_arg_n(argptr, INT, 0),
-                                                 _va_arg_n(argptr, INT, 1),
-                                                 _va_arg_n(argptr, COLORREF, 2),
-                                                 _va_arg_n(argptr, UINT, 3));
-        case DCFUNC_ExtSelectClipRgn:
-            return physdev->funcs->pExtSelectClipRgn(physdev,
-                                                     _va_arg_n(argptr, HRGN, 0), // hrgn
-                                                     _va_arg_n(argptr, INT, 1)); // iMode
-        case DCFUNC_ExtTextOut:
-            return physdev->funcs->pExtTextOut(physdev,
-                                               _va_arg_n(argptr, INT, 0),// x
-                                               _va_arg_n(argptr, INT, 1),// y
-                                               _va_arg_n(argptr, UINT, 2),// fuOptions
-                                               _va_arg_n(argptr, const RECT *, 3),// lprc,
-                                               _va_arg_n(argptr, LPCWSTR, 4),// lpString,
-                                               _va_arg_n(argptr, UINT, 5),// cchString,
-                                               _va_arg_n(argptr, const INT *, 6));// lpDx);
-        case DCFUNC_FillPath:
-            return physdev->funcs->pFillPath(physdev);
-        case DCFUNC_FillRgn:
-            return physdev->funcs->pFillRgn(physdev,
-                                            _va_arg_n(argptr, HRGN, 0),
-                                            _va_arg_n(argptr, HBRUSH, 1));
-        case DCFUNC_FlattenPath:
-            return physdev->funcs->pFlattenPath(physdev);
-        case DCFUNC_FrameRgn:
-            return physdev->funcs->pFrameRgn(physdev,
-                                             _va_arg_n(argptr, HRGN, 0),
-                                             _va_arg_n(argptr, HBRUSH, 1),
-                                             _va_arg_n(argptr, INT, 2),
-                                             _va_arg_n(argptr, INT, 3));
-        case DCFUNC_GetDeviceCaps:
-            return physdev->funcs->pGetDeviceCaps(physdev, va_arg(argptr, INT));
-        case DCFUNC_GdiComment:
-            return physdev->funcs->pGdiComment(physdev,
-                                               _va_arg_n(argptr, UINT, 0),
-                                               _va_arg_n(argptr, const BYTE*, 1));
-        case DCFUNC_IntersectClipRect:
-            return physdev->funcs->pIntersectClipRect(physdev,
-                                                      _va_arg_n(argptr, INT, 0),
-                                                      _va_arg_n(argptr, INT, 1),
-                                                      _va_arg_n(argptr, INT, 2),
-                                                      _va_arg_n(argptr, INT, 3));
-        case DCFUNC_InvertRgn:
-            return physdev->funcs->pInvertRgn(physdev,
-                                              va_arg(argptr, HRGN));
-        case DCFUNC_LineTo:
-            return physdev->funcs->pLineTo(physdev,
-                                           _va_arg_n(argptr, INT, 0),
-                                           _va_arg_n(argptr, INT, 1));
-        case DCFUNC_ModifyWorldTransform:
-            return physdev->funcs->pModifyWorldTransform(physdev,
-                                                         _va_arg_n(argptr, const XFORM*, 0),
-                                                         _va_arg_n(argptr, DWORD, 1));
-        case DCFUNC_MoveTo:
-            return physdev->funcs->pMoveTo(physdev,
-                                           _va_arg_n(argptr, INT, 0),
-                                           _va_arg_n(argptr, INT, 1));
-        case DCFUNC_OffsetClipRgn:
-            return physdev->funcs->pOffsetClipRgn(physdev,
-                                                  _va_arg_n(argptr, INT, 0), // hrgn
-                                                  _va_arg_n(argptr, INT, 1)); // iMode
-        case DCFUNC_OffsetViewportOrgEx:
-            return physdev->funcs->pOffsetViewportOrgEx(physdev,
-                                                        _va_arg_n(argptr, INT, 0), // X
-                                                        _va_arg_n(argptr, INT, 1), // Y
-                                                        _va_arg_n(argptr, LPPOINT, 2)); // lpPoint
-        case DCFUNC_OffsetWindowOrgEx:
-            return physdev->funcs->pOffsetWindowOrgEx(physdev,
-                                                        _va_arg_n(argptr, INT, 0), // X
-                                                        _va_arg_n(argptr, INT, 1), // Y
-                                                        _va_arg_n(argptr, LPPOINT, 2)); // lpPoint
-        case DCFUNC_PatBlt:
-            return DRIVER_PatBlt(physdev,
-                                 physdev->hdc,
-                                 _va_arg_n(argptr, INT, 0),
-                                 _va_arg_n(argptr, INT, 1),
-                                 _va_arg_n(argptr, INT, 2),
-                                 _va_arg_n(argptr, INT, 3),
-                                 _va_arg_n(argptr, DWORD, 4));
-        case DCFUNC_Pie:
-            return physdev->funcs->pPie(physdev,
-                                        _va_arg_n(argptr, INT, 0),
-                                        _va_arg_n(argptr, INT, 1),
-                                        _va_arg_n(argptr, INT, 2),
-                                        _va_arg_n(argptr, INT, 3),
-                                        _va_arg_n(argptr, INT, 4),
-                                        _va_arg_n(argptr, INT, 5),
-                                        _va_arg_n(argptr, INT, 6),
-                                        _va_arg_n(argptr, INT, 7));
-        case DCFUNC_PolyBezier:
-            return physdev->funcs->pPolyBezier(physdev,
-                                               _va_arg_n(argptr, const POINT*, 0),
-                                               _va_arg_n(argptr, DWORD, 1));
-        case DCFUNC_PolyBezierTo:
-            return physdev->funcs->pPolyBezierTo(physdev,
-                                                 _va_arg_n(argptr, const POINT*, 0),
-                                                 _va_arg_n(argptr, DWORD, 1));
-        case DCFUNC_PolyDraw:
-           return physdev->funcs->pPolyDraw(physdev,
-                                             _va_arg_n(argptr, const POINT*, 0),
-                                             _va_arg_n(argptr, const BYTE*, 1),
-                                             _va_arg_n(argptr, DWORD, 2));
-        case DCFUNC_Polygon:
-            return physdev->funcs->pPolygon(physdev,
-                                            _va_arg_n(argptr, const POINT*, 0),
-                                            _va_arg_n(argptr, INT, 1));
-        case DCFUNC_Polyline:
-            return physdev->funcs->pPolyline(physdev,
-                                             _va_arg_n(argptr, const POINT*, 0),
-                                             _va_arg_n(argptr, INT, 1));
-        case DCFUNC_PolylineTo:
-            return physdev->funcs->pPolylineTo(physdev,
-                                               _va_arg_n(argptr, const POINT*, 0),
-                                               _va_arg_n(argptr, INT, 1));
-        case DCFUNC_PolyPolygon:
-            return physdev->funcs->pPolyPolygon(physdev,
-                                                _va_arg_n(argptr, const POINT*, 0),
-                                                _va_arg_n(argptr, const INT*, 1),
-                                                _va_arg_n(argptr, DWORD, 2));
-        case DCFUNC_PolyPolyline:
-            return physdev->funcs->pPolyPolyline(physdev,
-                                                 _va_arg_n(argptr, const POINT*, 0),
-                                                 _va_arg_n(argptr, const DWORD*, 1),
-                                                 _va_arg_n(argptr, DWORD, 2));
-        case DCFUNC_RealizePalette:
-            if (GDI_HANDLE_GET_TYPE(physdev->hdc) != GDILoObjType_LO_METADC16_TYPE)
-            {
-                UNIMPLEMENTED;
-                return GDI_ERROR;
-            }
-            return physdev->funcs->pRealizePalette(physdev, NULL, FALSE);
-        case DCFUNC_Rectangle:
-            return physdev->funcs->pRectangle(physdev,
-                                              _va_arg_n(argptr, INT, 0),
-                                              _va_arg_n(argptr, INT, 1),
-                                              _va_arg_n(argptr, INT, 2),
-                                              _va_arg_n(argptr, INT, 3));
-        case DCFUNC_RestoreDC:
-            return DRIVER_RestoreDC(physdev, va_arg(argptr, INT));
-        case DCFUNC_RoundRect:
-            return physdev->funcs->pRoundRect(physdev,
-                                              _va_arg_n(argptr, INT, 0),
-                                              _va_arg_n(argptr, INT, 1),
-                                              _va_arg_n(argptr, INT, 2),
-                                              _va_arg_n(argptr, INT, 3),
-                                              _va_arg_n(argptr, INT, 4),
-                                              _va_arg_n(argptr, INT, 5));
-
-        case DCFUNC_SaveDC:
-            return physdev->funcs->pSaveDC(physdev);
-        case DCFUNC_ScaleViewportExtEx:
-            return physdev->funcs->pScaleViewportExtEx(physdev,
-                                                     _va_arg_n(argptr, INT, 0), // xNum
-                                                     _va_arg_n(argptr, INT, 1), // xDenom
-                                                     _va_arg_n(argptr, INT, 2), // yNum
-                                                     _va_arg_n(argptr, INT, 3), // yDenom
-                                                     _va_arg_n(argptr, LPSIZE, 4)); // lpSize
-        case DCFUNC_ScaleWindowExtEx:
-            return physdev->funcs->pScaleWindowExtEx(physdev,
-                                                     _va_arg_n(argptr, INT, 0), // xNum
-                                                     _va_arg_n(argptr, INT, 1), // xDenom
-                                                     _va_arg_n(argptr, INT, 2), // yNum
-                                                     _va_arg_n(argptr, INT, 3), // yDenom
-                                                     _va_arg_n(argptr, LPSIZE, 4)); // lpSize
-        case DCFUNC_SelectBrush:
-            return (DWORD_PTR)DRIVER_SelectBrush(physdev, va_arg(argptr, HBRUSH), NULL);
-        case DCFUNC_SelectClipPath:
-            return physdev->funcs->pSelectClipPath(physdev, va_arg(argptr, INT));
-        case DCFUNC_SelectFont:
-            return (DWORD_PTR)DRIVER_SelectFont(physdev, va_arg(argptr, HFONT), &aa_flags);
-        case DCFUNC_SelectPalette:
-            return (DWORD_PTR)physdev->funcs->pSelectPalette(physdev,
-                                                  _va_arg_n(argptr, HPALETTE, 0),
-                                                  _va_arg_n(argptr, BOOL, 1));
-        case DCFUNC_SelectPen:
-            return (DWORD_PTR)DRIVER_SelectPen(physdev, va_arg(argptr, HPEN), NULL);
-        case DCFUNC_SetDCBrushColor:
-            return physdev->funcs->pSetDCBrushColor(physdev, va_arg(argptr, COLORREF));
-        case DCFUNC_SetDCPenColor:
-            return physdev->funcs->pSetDCPenColor(physdev, va_arg(argptr, COLORREF));
-        case DCFUNC_SetDIBitsToDevice:
-            return physdev->funcs->pSetDIBitsToDevice(physdev,
-                                                      _va_arg_n(argptr, INT, 0),
-                                                      _va_arg_n(argptr, INT, 1),
-                                                      _va_arg_n(argptr, DWORD, 2),
-                                                      _va_arg_n(argptr, DWORD, 3),
-                                                      _va_arg_n(argptr, INT, 4),
-                                                      _va_arg_n(argptr, INT, 5),
-                                                      _va_arg_n(argptr, UINT, 6),
-                                                      _va_arg_n(argptr, UINT, 7),
-                                                      _va_arg_n(argptr, LPCVOID, 8),
-                                                      _va_arg_n(argptr, BITMAPINFO*, 9),
-                                                      _va_arg_n(argptr, UINT, 10));
-        case DCFUNC_SetBkColor:
-            return physdev->funcs->pSetBkColor(physdev, va_arg(argptr, COLORREF));
-        case DCFUNC_SetBkMode:
-            return physdev->funcs->pSetBkMode(physdev, va_arg(argptr, INT));
-        case DCFUNC_SetLayout:
-            // FIXME: MF16 is UNIMPLEMENTED
-            return physdev->funcs->pSetLayout(physdev,
-                                              _va_arg_n(argptr, DWORD, 0));
-        //case DCFUNC_SetMapMode:
-        //    return physdev->funcs->pSetMapMode(physdev, va_arg(argptr, INT));
-        case DCFUNC_SetPixel:
-            return physdev->funcs->pSetPixel(physdev,
-                                             _va_arg_n(argptr, INT, 0),
-                                             _va_arg_n(argptr, INT, 1),
-                                             _va_arg_n(argptr, COLORREF, 2));
-        case DCFUNC_SetPolyFillMode:
-            return physdev->funcs->pSetPolyFillMode(physdev, va_arg(argptr, INT));
-        case DCFUNC_SetROP2:
-            return physdev->funcs->pSetROP2(physdev, va_arg(argptr, INT));
-        case DCFUNC_SetStretchBltMode:
-            return physdev->funcs->pSetStretchBltMode(physdev, va_arg(argptr, INT));
-        case DCFUNC_SetTextAlign:
-            return physdev->funcs->pSetTextAlign(physdev, va_arg(argptr, UINT));
-        case DCFUNC_SetTextCharacterExtra:
-            return physdev->funcs->pSetTextCharacterExtra(physdev, va_arg(argptr, INT));
-        case DCFUNC_SetTextColor:
-            return physdev->funcs->pSetTextColor(physdev, va_arg(argptr, COLORREF));
-        case DCFUNC_SetTextJustification:
-            return physdev->funcs->pSetTextJustification(physdev,
-                                                         _va_arg_n(argptr, INT, 0),
-                                                         _va_arg_n(argptr, INT, 1));
-        case DCFUNC_SetViewportExtEx:
-            return physdev->funcs->pSetViewportExtEx(physdev,
-                                                     _va_arg_n(argptr, INT, 0), // nXExtent
-                                                     _va_arg_n(argptr, INT, 1), // nYExtent
-                                                     _va_arg_n(argptr, LPSIZE, 2)); // lpSize
-        case DCFUNC_SetViewportOrgEx:
-            return physdev->funcs->pSetViewportOrgEx(physdev,
-                                                     _va_arg_n(argptr, INT, 0), // X
-                                                     _va_arg_n(argptr, INT, 1), // Y
-                                                     _va_arg_n(argptr, LPPOINT, 2)); // lpPoint
-        case DCFUNC_SetWindowExtEx:
-            return physdev->funcs->pSetWindowExtEx(physdev,
-                                                   _va_arg_n(argptr, INT, 0), // nXExtent
-                                                   _va_arg_n(argptr, INT, 1), // nYExtent
-                                                   _va_arg_n(argptr, LPSIZE, 2)); // lpSize
-        case DCFUNC_SetWindowOrgEx:
-            return physdev->funcs->pSetWindowOrgEx(physdev,
-                                                   _va_arg_n(argptr, INT, 0), // X
-                                                   _va_arg_n(argptr, INT, 1), // Y
-                                                   _va_arg_n(argptr, LPPOINT, 2)); // lpPoint
-
-        case DCFUNC_SetWorldTransform:
-            return physdev->funcs->pSetWorldTransform(physdev,
-                                                      va_arg(argptr, const XFORM*));
-
-        case DCFUNC_StretchBlt:
-            return DRIVER_StretchBlt(physdev,
-                                     physdev->hdc,
-                                     _va_arg_n(argptr, INT, 0),
-                                     _va_arg_n(argptr, INT, 1),
-                                     _va_arg_n(argptr, INT, 2),
-                                     _va_arg_n(argptr, INT, 3),
-                                     _va_arg_n(argptr, HDC, 4),
-                                     _va_arg_n(argptr, INT, 5),
-                                     _va_arg_n(argptr, INT, 6),
-                                     _va_arg_n(argptr, INT, 7),
-                                     _va_arg_n(argptr, INT, 8),
-                                     _va_arg_n(argptr, DWORD, 9));
-        case DCFUNC_StrokeAndFillPath:
-            return physdev->funcs->pStrokeAndFillPath(physdev);
-        case DCFUNC_StrokePath:
-            return physdev->funcs->pStrokePath(physdev);
-        case DCFUNC_WidenPath:
-            return physdev->funcs->pWidenPath(physdev);
-        case DCFUNC_AngleArc:
-            return physdev->funcs->pAngleArc(physdev,
-                                             _va_arg_n(argptr, INT, 0),
-                                             _va_arg_n(argptr, INT, 1),
-                                             _va_arg_n(argptr, DWORD, 2),
-                                             _va_arg_n(argptr, FLOAT, 3),
-                                             _va_arg_n(argptr, FLOAT, 4 ));
-        case DCFUNC_ArcTo:
-            return physdev->funcs->pArcTo(physdev,
-                                          _va_arg_n(argptr, INT, 0),
-                                          _va_arg_n(argptr, INT, 1),
-                                          _va_arg_n(argptr, INT, 2),
-                                          _va_arg_n(argptr, INT, 3),
-                                          _va_arg_n(argptr, INT, 4),
-                                          _va_arg_n(argptr, INT, 5),
-                                          _va_arg_n(argptr, INT, 6),
-                                          _va_arg_n(argptr, INT, 7));
-        case DCFUNC_GradientFill:
-            return physdev->funcs->pGradientFill(physdev,
-                                                 _va_arg_n(argptr, TRIVERTEX *, 0), 
-                                                 _va_arg_n(argptr, ULONG, 1),
-                                                 _va_arg_n(argptr, void *, 2),
-                                                 _va_arg_n(argptr, ULONG , 3),
-                                                 _va_arg_n(argptr, ULONG , 4));
-        case DCFUNC_PathToRegion:
-            return (DWORD_PTR)DRIVER_PathToRegion(physdev);
-
-        /* These are not implemented in wine */
-        case DCFUNC_AlphaBlend:
-        case DCFUNC_MaskBlt:
-        case DCFUNC_PlgBlt:
-        case DCFUNC_TransparentBlt:
-            UNIMPLEMENTED;
-            return 0;
-
-        default:
-            __debugbreak();
-            return 0;
-    }
-}
-
-BOOL
-METADC_Dispatch(
-    _In_ DCFUNC eFunction,
-    _Out_ PDWORD_PTR pdwResult,
-    _In_ DWORD_PTR dwError,
-    _In_ HDC hdc,
-    ...)
-{
-    PHYSDEV physdev;
-    va_list argptr;
-
-    /* Handle only METADC16 and ALTDC */
-    if ((GDI_HANDLE_GET_TYPE(hdc) != GDILoObjType_LO_ALTDC_TYPE) &&
-        (GDI_HANDLE_GET_TYPE(hdc) != GDILoObjType_LO_METADC16_TYPE))
-    {
-        /* Let the caller handle it */
+WINAPI
+METADC_SetD(
+     _In_ HDC hdc,
+     _In_ DWORD dwIn,
+     _In_ USHORT usMF16Id
+)
+{
+    switch(usMF16Id)
+    {
+    case META_SETMAPMODE:
+        return METADC_SetMapMode(hdc, dwIn);
+    case META_SETRELABS:
+        return METADC_SetRelAbs(hdc, dwIn);
+    default:
         return FALSE;
     }
-
-    // See if this is other than a METADATA issue.
-    if (GDI_HANDLE_GET_TYPE(hdc) == GDILoObjType_LO_ALTDC_TYPE)
-    {
-       WINEDC* pwdc = (WINEDC*)GdiGetLDC(hdc);
-       if (pwdc && pwdc->iType != LDC_EMFLDC)
-       {
-          /* Let the caller handle it */
-          return FALSE;
-       }
-    }
-
-    physdev = GetPhysDev(hdc);
-    if (physdev == NULL)
-    {
-        SetLastError(ERROR_INVALID_HANDLE);
-        *pdwResult = dwError;
-        return TRUE;
-    }
-
-    i = eFunction;
-    va_start(argptr, hdc);
-    *pdwResult = DRIVER_Dispatch(physdev, eFunction, argptr);
-    va_end(argptr);
-    i = 0;
-
-    /* Return TRUE to indicate that we want to return from the parent  */
-    return ((GDI_HANDLE_GET_TYPE(hdc) == GDILoObjType_LO_METADC16_TYPE) ||
-            (*pdwResult == dwError));
 }
 
 BOOL
 WINAPI
-METADC_GetAndSetDCDWord(
-    _Out_ DWORD* pdwResult,
-    _In_ HDC hdc,
-    _In_ UINT uFunction,
+EMFDC_SetD(
+    _In_ PLDC pldc,
     _In_ DWORD dwIn,
-    _In_ ULONG ulMFId,
-    _In_ USHORT usMF16Id,
-    _In_ DWORD dwError)
+    _In_ ULONG ulMFId)
 {
-    PHYSDEV physdev;
-
-    /* Ignore these, we let wine code handle this */
-    UNREFERENCED_PARAMETER(ulMFId);
-    UNREFERENCED_PARAMETER(usMF16Id);
-
-    physdev = GetPhysDev(hdc);
-    if (physdev == NULL)
+    switch(ulMFId)
     {
-        SetLastError(ERROR_INVALID_HANDLE);
-        *pdwResult = dwError;
-        return TRUE;
-    }
-
-    /* Check the function */
-    switch (uFunction)
-    {
-        case GdiGetSetMapMode:
-            *pdwResult = physdev->funcs->pSetMapMode(physdev, dwIn);
-            break;
-
-        case GdiGetSetArcDirection:
-            if (GDI_HANDLE_GET_TYPE(physdev->hdc) == GDILoObjType_LO_METADC16_TYPE)
-                *pdwResult = 0;
-            else
-                *pdwResult = physdev->funcs->pSetArcDirection(physdev, dwIn);
-            break;
-
-        case GdiGetSetRelAbs:
-            if (GDI_HANDLE_GET_TYPE(physdev->hdc) == GDILoObjType_LO_METADC16_TYPE)
-                *pdwResult = physdev->funcs->pSetRelAbs(physdev, dwIn);
-            else
-            {
-                UNIMPLEMENTED;
-                *pdwResult = 0;
-            }
-            break;
-
-
-        default:
-            __debugbreak();
+    case EMR_SETMAPMODE:
+        return EMFDC_SetMapMode( pldc, dwIn);
+    case EMR_SETARCDIRECTION:
+        return EMFDC_SetArcDirection( pldc, dwIn);
+    default:
+        return FALSE;
     }
-
-    /* Return TRUE to indicate that we want to return from the parent  */
-    return ((GDI_HANDLE_GET_TYPE(hdc) == GDILoObjType_LO_METADC16_TYPE) ||
-            (*pdwResult == dwError));
 }
 
+extern void METADC_DeleteObject( HDC hdc, HGDIOBJ obj );
+extern void emfdc_delete_object( HDC hdc, HGDIOBJ obj );
+
 VOID
 WINAPI
-METADC_DeleteObject(HGDIOBJ hobj)
+METADC_RosGlueDeleteObject(HGDIOBJ hobj)
 {
     GDILOOBJTYPE eObjectType;
     HDC hdc;
-    PHYSDEV physdev;
 
     /* Check for one of the types we actually handle here */
     eObjectType = GDI_HANDLE_GET_TYPE(hobj);
@@ -1248,64 +370,58 @@ METADC_DeleteObject(HGDIOBJ hobj)
     hdc = GdiRemoveClientObjLink(hobj);
     if (hdc == NULL)
     {
+        DPRINT1("the link was not found\n");
         /* The link was not found, so we are not handling this object here */
         return;
     }
 
-    /* Get the physdev */
-    physdev = GetPhysDev(hdc);
-    if (physdev == NULL)
+    if ( GDI_HANDLE_GET_TYPE(hdc) == GDILoObjType_LO_METADC16_TYPE ) METADC_DeleteObject( hdc, hobj );
+
+    if ( GDI_HANDLE_GET_TYPE(hdc) == GDILoObjType_LO_ALTDC_TYPE )
     {
-        /* This happens, when the METADC is already closed, when we delete
-           the object. Simply ignore it */
-        DPRINT1("METADC was already closed, cannot delete object. Ignoring.\n");
-        return;
+        LDC* pWineDc = GdiGetLDC(hdc);
+        if ( pWineDc )
+        {
+            emfdc_delete_object( hdc, hobj );
+        }
     }
-
-    physdev->funcs->pDeleteObject(physdev, hobj);
 }
 
 BOOL
 WINAPI
-METADC_DeleteDC(
+METADC_RosGlueDeleteDC(
     _In_ HDC hdc)
 {
-    /* Only ALTDCs are supported */
-    if (GDI_HANDLE_GET_TYPE(hdc) != GDILoObjType_LO_ALTDC_TYPE)
+    LDC* pWineDc = NULL;
+
+    if ( GDI_HANDLE_GET_TYPE(hdc) == GDILoObjType_LO_METADC16_TYPE )
     {
-        DPRINT1("Trying to delete METADC %p\n", hdc);
-        return FALSE;
+        return METADC_DeleteDC(hdc);
     }
-    // FIXME call the driver?
-    return NtGdiDeleteObjectApp(hdc);
-}
-
-INT
-WINAPI
-METADC16_Escape(
-    _In_ HDC hdc,
-    _In_ INT nEscape,
-    _In_ INT cbInput,
-    _In_ LPCSTR lpvInData,
-    _Out_ LPVOID lpvOutData)
-{
-    DWORD_PTR dwResult;
 
-    /* Do not record MFCOMMENT */
-    if (nEscape == MFCOMMENT)
+    if ( GDI_HANDLE_GET_TYPE(hdc) == GDILoObjType_LO_ALTDC_TYPE )
     {
-        // HACK required by wine code...
-        //return 1;
-    }
+        pWineDc = GdiGetLDC(hdc);
+
+        if ( pWineDc )
+        {
+            // Handle Printer LDC
+            if (pWineDc->iType != LDC_EMFLDC)
+            {
+               //return IntDeleteDC(hdc);
+            }
+
+            EMFDC_DeleteDC( pWineDc );
 
-    METADC_Dispatch(DCFUNC_ExtEscape,
-                    &dwResult,
-                    SP_ERROR,
-                    hdc,
-                    nEscape,
-                    cbInput,
-                    lpvInData,
-                    lpvOutData);
+            /* Get rid of the LDC */
+            ASSERT(GdiGetLDC(pWineDc->hDC) == pWineDc);
+            GdiSetLDC(pWineDc->hDC, NULL);
 
-    return (INT)dwResult;
+            /* Free the Wine DC */
+            HeapFree(GetProcessHeap(), 0, pWineDc);
+        }
+    }
+
+    return NtGdiDeleteObjectApp(hdc);
 }
+
index 36dc54c..c81f013 100644 (file)
@@ -294,11 +294,16 @@ typedef struct _LDC
     PDEVMODEW pdm;
     PVOID pUMPDev;        /* Ptr to User Mode Printer Device structure */
     PUMDHPDEV pUMdhpdev;  /* Ptr to Combined UMPD and DHPDEV structure */
+    PVOID UFIHashTable[3];
+    UNIVERSAL_FONT_ID ufi;
+    PVOID pvEMFSpoolData;
+    ULONG cjSize;
+    LIST_ENTRY leRecords;
     DEVCAPS DevCaps;
     HBRUSH BrushColor;
     HPEN PenColor;
     // wine data
-    DWORD dwData[7];
+    DWORD dwData[5];
 } LDC, *PLDC;
 
 typedef struct _DC_ATTR
index 482ea23..7afe690 100644 (file)
@@ -575,7 +575,7 @@ typedef struct _SBINFOEX
     SCROLLINFO ScrollInfo;
 } SBINFOEX, *PSBINFOEX;
 
-/* State Flags !Not Implemented! */
+/* State Flags !Not ALL Implemented! */
 #define WNDS_HASMENU                 0X00000001
 #define WNDS_HASVERTICALSCROOLLBAR   0X00000002
 #define WNDS_HASHORIZONTALSCROLLBAR  0X00000004
@@ -611,7 +611,7 @@ typedef struct _SBINFOEX
 
 #define WNDSACTIVEFRAME              0x00000006
 
-/* State2 Flags !Not Implemented! */
+/* State2 Flags !Not ALL Implemented! */
 #define WNDS2_WMPAINTSENT               0X00000001
 #define WNDS2_ENDPAINTINVALIDATE        0X00000002
 #define WNDS2_STARTPAINT                0X00000004