https://git.reactos.org/?p=reactos.git;a=commitdiff;h=fc16259faf79e9fbb02e0…
commit fc16259faf79e9fbb02e0a852cb7ebb445d031a9
Author: James Tabor <james.tabor(a)reactos.org>
AuthorDate: Mon Sep 27 16:18:20 2021 -0500
Commit: James Tabor <james.tabor(a)reactos.org>
CommitDate: Mon Sep 27 16:18:20 2021 -0500
[GDI32] Update Wine Metafile Code
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!
---
sdk/include/psdk/wingdi.h | 1 +
win32ss/gdi/gdi32/include/gdi32p.h | 433 ++++--
win32ss/gdi/gdi32/misc/misc.c | 2 +-
win32ss/gdi/gdi32/objects/arc.c | 8 +-
win32ss/gdi/gdi32/objects/bitmap.c | 27 +-
win32ss/gdi/gdi32/objects/coord.c | 30 +-
win32ss/gdi/gdi32/objects/dc.c | 98 +-
win32ss/gdi/gdi32/objects/enhmfile.c | 35 +-
win32ss/gdi/gdi32/objects/gdiobj.c | 16 +-
win32ss/gdi/gdi32/objects/metafile.c | 37 +-
win32ss/gdi/gdi32/objects/painting.c | 32 +-
win32ss/gdi/gdi32/objects/palette.c | 5 +-
win32ss/gdi/gdi32/objects/path.c | 4 +-
win32ss/gdi/gdi32/objects/region.c | 20 +-
win32ss/gdi/gdi32/objects/text.c | 10 +-
win32ss/gdi/gdi32/wine/CMakeLists.txt | 15 +-
win32ss/gdi/gdi32/wine/emfdc.c | 2569 +++++++++++++++++++++++++++++++++
win32ss/gdi/gdi32/wine/emfdrv.c | 430 ++++++
win32ss/gdi/gdi32/wine/enhmetafile.c | 137 +-
win32ss/gdi/gdi32/wine/gdi_private.h | 132 +-
win32ss/gdi/gdi32/wine/metadc.c | 1445 ++++++++++++++++++
win32ss/gdi/gdi32/wine/metafile.c | 8 +-
win32ss/gdi/gdi32/wine/rosglue.c | 1046 ++------------
win32ss/include/ntgdihdl.h | 7 +-
win32ss/include/ntuser.h | 4 +-
25 files changed, 5198 insertions(+), 1353 deletions(-)
diff --git a/sdk/include/psdk/wingdi.h b/sdk/include/psdk/wingdi.h
index 3cbfb75069d..00a0bf8cb71 100644
--- a/sdk/include/psdk/wingdi.h
+++ b/sdk/include/psdk/wingdi.h
@@ -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
diff --git a/win32ss/gdi/gdi32/include/gdi32p.h b/win32ss/gdi/gdi32/include/gdi32p.h
index a9eb00b89ef..b5f29b7c5e6 100644
--- a/win32ss/gdi/gdi32/include/gdi32p.h
+++ b/win32ss/gdi/gdi32/include/gdi32p.h
@@ -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 */
diff --git a/win32ss/gdi/gdi32/misc/misc.c b/win32ss/gdi/gdi32/misc/misc.c
index d977d6c3080..f753e9bde0f 100644
--- a/win32ss/gdi/gdi32/misc/misc.c
+++ b/win32ss/gdi/gdi32/misc/misc.c
@@ -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)
diff --git a/win32ss/gdi/gdi32/objects/arc.c b/win32ss/gdi/gdi32/objects/arc.c
index 444b05a295b..f689b05ab4d 100644
--- a/win32ss/gdi/gdi32/objects/arc.c
+++ b/win32ss/gdi/gdi32/objects/arc.c
@@ -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,
diff --git a/win32ss/gdi/gdi32/objects/bitmap.c b/win32ss/gdi/gdi32/objects/bitmap.c
index f290b546617..438521f69e9 100644
--- a/win32ss/gdi/gdi32/objects/bitmap.c
+++ b/win32ss/gdi/gdi32/objects/bitmap.c
@@ -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);
diff --git a/win32ss/gdi/gdi32/objects/coord.c b/win32ss/gdi/gdi32/objects/coord.c
index b27711ca1e3..49c16bf93e7 100644
--- a/win32ss/gdi/gdi32/objects/coord.c
+++ b/win32ss/gdi/gdi32/objects/coord.c
@@ -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);
diff --git a/win32ss/gdi/gdi32/objects/dc.c b/win32ss/gdi/gdi32/objects/dc.c
index 91df2a90984..f929dfdd011 100644
--- a/win32ss/gdi/gdi32/objects/dc.c
+++ b/win32ss/gdi/gdi32/objects/dc.c
@@ -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);
diff --git a/win32ss/gdi/gdi32/objects/enhmfile.c b/win32ss/gdi/gdi32/objects/enhmfile.c
index a7d168dc20a..c1c58d4867d 100644
--- a/win32ss/gdi/gdi32/objects/enhmfile.c
+++ b/win32ss/gdi/gdi32/objects/enhmfile.c
@@ -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;
diff --git a/win32ss/gdi/gdi32/objects/gdiobj.c b/win32ss/gdi/gdi32/objects/gdiobj.c
index ecd5d50f5e6..96617881fc4 100644
--- a/win32ss/gdi/gdi32/objects/gdiobj.c
+++ b/win32ss/gdi/gdi32/objects/gdiobj.c
@@ -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:
diff --git a/win32ss/gdi/gdi32/objects/metafile.c b/win32ss/gdi/gdi32/objects/metafile.c
index 42bd22ec93c..f59d6ce40d6 100644
--- a/win32ss/gdi/gdi32/objects/metafile.c
+++ b/win32ss/gdi/gdi32/objects/metafile.c
@@ -17,19 +17,15 @@
*/
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
diff --git a/win32ss/gdi/gdi32/objects/painting.c b/win32ss/gdi/gdi32/objects/painting.c
index 17f64b8b384..9790111e55b 100644
--- a/win32ss/gdi/gdi32/objects/painting.c
+++ b/win32ss/gdi/gdi32/objects/painting.c
@@ -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;
diff --git a/win32ss/gdi/gdi32/objects/palette.c b/win32ss/gdi/gdi32/objects/palette.c
index 3c7afd74339..c79ca27308f 100644
--- a/win32ss/gdi/gdi32/objects/palette.c
+++ b/win32ss/gdi/gdi32/objects/palette.c
@@ -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)
{
diff --git a/win32ss/gdi/gdi32/objects/path.c b/win32ss/gdi/gdi32/objects/path.c
index 01ba886c3ae..26922f46350 100644
--- a/win32ss/gdi/gdi32/objects/path.c
+++ b/win32ss/gdi/gdi32/objects/path.c
@@ -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);
}
diff --git a/win32ss/gdi/gdi32/objects/region.c b/win32ss/gdi/gdi32/objects/region.c
index d7d2c330f73..17b500af01d 100644
--- a/win32ss/gdi/gdi32/objects/region.c
+++ b/win32ss/gdi/gdi32/objects/region.c
@@ -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);
}
diff --git a/win32ss/gdi/gdi32/objects/text.c b/win32ss/gdi/gdi32/objects/text.c
index 9a08ec56d16..799c20f5f72 100644
--- a/win32ss/gdi/gdi32/objects/text.c
+++ b/win32ss/gdi/gdi32/objects/text.c
@@ -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);
diff --git a/win32ss/gdi/gdi32/wine/CMakeLists.txt
b/win32ss/gdi/gdi32/wine/CMakeLists.txt
index 4f70a336d05..387b224e4c8 100644
--- a/win32ss/gdi/gdi32/wine/CMakeLists.txt
+++ b/win32ss/gdi/gdi32/wine/CMakeLists.txt
@@ -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
index 00000000000..b300e0efea8
--- /dev/null
+++ b/win32ss/gdi/gdi32/wine/emfdc.c
@@ -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
index 00000000000..26a13c67215
--- /dev/null
+++ b/win32ss/gdi/gdi32/wine/emfdrv.c
@@ -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;
+}
+
diff --git a/win32ss/gdi/gdi32/wine/enhmetafile.c b/win32ss/gdi/gdi32/wine/enhmetafile.c
index 07faf2a24d6..f8c0762590f 100644
--- a/win32ss/gdi/gdi32/wine/enhmetafile.c
+++ b/win32ss/gdi/gdi32/wine/enhmetafile.c
@@ -48,6 +48,16 @@
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 {
diff --git a/win32ss/gdi/gdi32/wine/gdi_private.h b/win32ss/gdi/gdi32/wine/gdi_private.h
index f3b79c462b7..de49fae2a47 100644
--- a/win32ss/gdi/gdi32/wine/gdi_private.h
+++ b/win32ss/gdi/gdi32/wine/gdi_private.h
@@ -26,7 +26,33 @@
#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
index 00000000000..c5bff94416e
--- /dev/null
+++ b/win32ss/gdi/gdi32/wine/metadc.c
@@ -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;
... 2625 lines suppressed ...