diff --git a/reactos/config.rbuild b/reactos/config.rbuild
index 0f259c47349..c10cb253653 100644
--- a/reactos/config.rbuild
+++ b/reactos/config.rbuild
@@ -67,6 +67,6 @@
enable this (except they/you purchased a license from the patent owner).
This settings is disabled (0) by default.
-->
-
+
diff --git a/reactos/include/psdk/wingdi.h b/reactos/include/psdk/wingdi.h
index 823b0c69f1e..0375635fdd8 100644
--- a/reactos/include/psdk/wingdi.h
+++ b/reactos/include/psdk/wingdi.h
@@ -614,6 +614,7 @@ extern "C" {
#define OBJ_METADC 4
#define OBJ_ENHMETAFILE 13
#define OBJ_ENHMETADC 12
+#define OBJ_COLORSPACE 14
#define DRIVERVERSION 0
#define TECHNOLOGY 2
#define DT_PLOTTER 0
@@ -933,6 +934,8 @@ extern "C" {
#define SP_NOTREPORTED 0x4000
#define PR_JOBSTATUS 0
#define ASPECT_FILTERING 1
+#define GS_8BIT_INDICES 0x00000001
+#define GGI_MARK_NONEXISTING_GLYPHS 0X0001
#define BS_SOLID 0
#define BS_NULL 1
#define BS_HOLLOW 1
@@ -1184,6 +1187,9 @@ extern "C" {
#define CS_DISABLE 0x00000002
#define CS_DELETE_TRANSFORM 0x00000003
#endif
+
+
+
#if (WINVER > 0x500)
#define GRADIENT_FILL_RECT_H 0x00
#define GRADIENT_FILL_RECT_V 0x01
@@ -1336,7 +1342,7 @@ typedef struct {
typedef struct tagFONTSIGNATURE {
DWORD fsUsb[4];
DWORD fsCsb[2];
-} FONTSIGNATURE,*LPFONTSIGNATURE;
+} FONTSIGNATURE, *PFONTSIGNATURE,*LPFONTSIGNATURE;
typedef struct {
UINT ciCharset;
UINT ciACP;
@@ -1483,6 +1489,15 @@ typedef struct tagEMR {
DWORD iType;
DWORD nSize;
} EMR,*PEMR;
+
+#if(WINVER >= 0x0400)
+typedef struct tagEMRGLSRECORD
+{
+ EMR emr;
+ DWORD cbData;
+ BYTE Data[1];
+} EMRGLSRECORD, *PEMRGLSRECORD;
+#endif
typedef struct tagEMRANGLEARC {
EMR emr;
POINTL ptlCenter;
@@ -1757,6 +1772,15 @@ typedef struct tagEMRFORMAT {
DWORD cbData;
DWORD offData;
} EMRFORMAT;
+
+
+typedef struct tagEMRSETCOLORSPACE
+{
+ EMR emr;
+ DWORD ihCS;
+} EMRSETCOLORSPACE, *PEMRSETCOLORSPACE, EMRSELECTCOLORSPACE, *PEMRSELECTCOLORSPACE,
+ EMRDELETECOLORSPACE, *PEMRDELETECOLORSPACE;
+
typedef struct tagEMRFRAMERGN {
EMR emr;
RECTL rclBounds;
@@ -1909,10 +1933,8 @@ typedef struct tagEMRSCALEVIEWPORTEXTEX {
LONG yNum;
LONG yDenom;
} EMRSCALEVIEWPORTEXTEX,*PEMRSCALEVIEWPORTEXTEX,EMRSCALEWINDOWEXTEX,*PEMRSCALEWINDOWEXTEX;
-typedef struct tagEMRSELECTCOLORSPACE {
- EMR emr;
- DWORD ihCS;
-} EMRSELECTCOLORSPACE,*PEMRSELECTCOLORSPACE,EMRDELETECOLORSPACE,*PEMRDELETECOLORSPACE;
+
+
typedef struct tagEMRSELECTOBJECT {
EMR emr;
DWORD ihObject;
@@ -2026,7 +2048,14 @@ typedef struct tagABORTPATH {
typedef struct tagEMRSELECTCLIPPATH {
EMR emr;
DWORD iMode;
-} EMRSELECTCLIPPATH,*PEMRSELECTCLIPPATH,EMRSETBKMODE,*PEMRSETBKMODE,EMRSETMAPMODE,*PEMRSETMAPMODE,EMRSETPOLYFILLMODE,*PEMRSETPOLYFILLMODE,EMRSETROP2,*PEMRSETROP2,EMRSETSTRETCHBLTMODE,*PEMRSETSTRETCHBLTMODE,EMRSETTEXTALIGN,*PEMRSETTEXTALIGN,EMRENABLEICM,*PEMRENABLEICM;
+} EMRSELECTCLIPPATH,*PEMRSELECTCLIPPATH, EMRSETBKMODE,*PEMRSETBKMODE, EMRSETMAPMODE, *PEMRSETMAPMODE,
+ EMRSETPOLYFILLMODE, *PEMRSETPOLYFILLMODE, EMRSETROP2, *PEMRSETROP2, EMRSETSTRETCHBLTMODE, *PEMRSETSTRETCHBLTMODE,
+ EMRSETICMMODE, *PEMRSETICMMODE, EMRSETTEXTALIGN,
+#if(WINVER >= 0x0500)
+ EMRSETLAYOUT, *PEMRSETLAYOUT,
+#endif
+ *PEMRSETTEXTALIGN;
+
#include "pshpack2.h"
typedef struct tagMETAHEADER {
WORD mtType;
@@ -2062,7 +2091,7 @@ typedef struct tagENHMETAHEADER {
#if (WINVER >= 0x0500)
SIZEL szlMicrometers;
#endif
-} ENHMETAHEADER,*LPENHMETAHEADER;
+} ENHMETAHEADER,*PENHMETAHEADER,*LPENHMETAHEADER;
typedef struct tagMETARECORD {
DWORD rdSize;
WORD rdFunction;
@@ -2075,7 +2104,7 @@ typedef struct tagENHMETARECORD {
} ENHMETARECORD,*LPENHMETARECORD;
typedef struct tagHANDLETABLE {
HGDIOBJ objectHandle[1];
-} HANDLETABLE,*LPHANDLETABLE;
+} HANDLETABLE,*PHANDLETABLE, *LPHANDLETABLE;
typedef struct tagTEXTMETRICA {
LONG tmHeight;
LONG tmAscent;
@@ -2120,6 +2149,7 @@ typedef struct tagTEXTMETRICW {
BYTE tmPitchAndFamily;
BYTE tmCharSet;
} TEXTMETRICW,*PTEXTMETRICW,*LPTEXTMETRICW;
+
typedef struct _RGNDATAHEADER {
DWORD dwSize;
DWORD iType;
@@ -2311,6 +2341,13 @@ typedef struct tagPIXELFORMATDESCRIPTOR {
DWORD dwVisibleMask;
DWORD dwDamageMask;
} PIXELFORMATDESCRIPTOR,*PPIXELFORMATDESCRIPTOR,*LPPIXELFORMATDESCRIPTOR;
+
+typedef struct tagEMRPIXELFORMAT
+{
+ EMR emr;
+ PIXELFORMATDESCRIPTOR pfd;
+} EMRPIXELFORMAT, *PEMRPIXELFORMAT;
+
typedef struct tagMETAFILEPICT {
LONG mm;
LONG xExt;
@@ -2522,6 +2559,8 @@ typedef struct _DISPLAY_DEVICEW {
WCHAR DeviceKey[128];
} DISPLAY_DEVICEW, *PDISPLAY_DEVICEW, *LPDISPLAY_DEVICEW;
+
+
typedef BOOL (CALLBACK *ABORTPROC)(HDC,int);
typedef int (CALLBACK *MFENUMPROC)(HDC,HANDLETABLE*,METARECORD*,int,LPARAM);
typedef int (CALLBACK *ENHMFENUMPROC)(HDC,HANDLETABLE*,ENHMETARECORD*,int,LPARAM);
diff --git a/reactos/regtests/winetests/gdi/.gitignore b/reactos/regtests/winetests/gdi/.gitignore
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/reactos/regtests/winetests/gdi32/bitmap.c b/reactos/regtests/winetests/gdi32/bitmap.c
index dbbb81b8068..62a57ebf2da 100755
--- a/reactos/regtests/winetests/gdi32/bitmap.c
+++ b/reactos/regtests/winetests/gdi32/bitmap.c
@@ -2,6 +2,7 @@
* Unit test suite for bitmaps
*
* Copyright 2004 Huw Davies
+ * Copyright 2006 Dmitry Timoshkov
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -15,11 +16,12 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include
#include
+#include
#include "windef.h"
#include "winbase.h"
@@ -31,11 +33,88 @@
static BOOL is_win9x;
+static INT BITMAP_GetWidthBytes( INT bmWidth, INT bpp )
+{
+ switch(bpp)
+ {
+ case 1:
+ return 2 * ((bmWidth+15) >> 4);
+
+ case 24:
+ bmWidth *= 3; /* fall through */
+ case 8:
+ return bmWidth + (bmWidth & 1);
+
+ case 32:
+ return bmWidth * 4;
+
+ case 16:
+ case 15:
+ return bmWidth * 2;
+
+ case 4:
+ return 2 * ((bmWidth+3) >> 2);
+
+ default:
+ trace("Unknown depth %d, please report.\n", bpp );
+ assert(0);
+ }
+ return -1;
+}
+
+static void test_bitmap_info(HBITMAP hbm, INT expected_depth, const BITMAPINFOHEADER *bmih)
+{
+ BITMAP bm;
+ INT ret, width_bytes;
+ char buf[512], buf_cmp[512];
+
+ ret = GetObject(hbm, sizeof(bm), &bm);
+ ok(ret == sizeof(bm), "GetObject returned %d\n", ret);
+
+ ok(bm.bmType == 0, "wrong bm.bmType %d\n", bm.bmType);
+ ok(bm.bmWidth == bmih->biWidth, "wrong bm.bmWidth %d\n", bm.bmWidth);
+ ok(bm.bmHeight == bmih->biHeight, "wrong bm.bmHeight %d\n", bm.bmHeight);
+ width_bytes = BITMAP_GetWidthBytes(bm.bmWidth, bm.bmBitsPixel);
+ ok(bm.bmWidthBytes == width_bytes, "wrong bm.bmWidthBytes %d != %d\n", bm.bmWidthBytes, width_bytes);
+ ok(bm.bmPlanes == bmih->biPlanes, "wrong bm.bmPlanes %d\n", bm.bmPlanes);
+ ok(bm.bmBitsPixel == expected_depth, "wrong bm.bmBitsPixel %d != %d\n", bm.bmBitsPixel, expected_depth);
+ ok(bm.bmBits == NULL, "wrong bm.bmBits %p\n", bm.bmBits);
+
+ assert(sizeof(buf) >= bm.bmWidthBytes * bm.bmHeight);
+ assert(sizeof(buf) == sizeof(buf_cmp));
+
+ ret = GetBitmapBits(hbm, 0, NULL);
+ ok(ret == bm.bmWidthBytes * bm.bmHeight, "%d != %d\n", ret, bm.bmWidthBytes * bm.bmHeight);
+
+ memset(buf_cmp, 0xAA, sizeof(buf_cmp));
+ memset(buf_cmp, 0, bm.bmWidthBytes * bm.bmHeight);
+
+ memset(buf, 0xAA, sizeof(buf));
+ ret = GetBitmapBits(hbm, sizeof(buf), buf);
+ ok(ret == bm.bmWidthBytes * bm.bmHeight, "%d != %d\n", ret, bm.bmWidthBytes * bm.bmHeight);
+ ok(!memcmp(buf, buf_cmp, sizeof(buf)), "buffers do not match\n");
+
+ /* test various buffer sizes for GetObject */
+ ret = GetObject(hbm, 0, NULL);
+ ok(ret == sizeof(bm), "wrong size %d\n", ret);
+
+ ret = GetObject(hbm, sizeof(bm) * 2, &bm);
+ ok(ret == sizeof(bm), "wrong size %d\n", ret);
+
+ ret = GetObject(hbm, sizeof(bm) / 2, &bm);
+ ok(ret == 0, "%d != 0\n", ret);
+
+ ret = GetObject(hbm, 0, &bm);
+ ok(ret == 0, "%d != 0\n", ret);
+
+ ret = GetObject(hbm, 1, &bm);
+ ok(ret == 0, "%d != 0\n", ret);
+}
+
static void test_createdibitmap(void)
{
HDC hdc, hdcmem;
BITMAPINFOHEADER bmih;
- BITMAP bm;
HBITMAP hbm, hbm_colour, hbm_old;
INT screen_depth;
@@ -56,27 +135,21 @@ static void test_createdibitmap(void)
/* First try 32 bits */
hbm = CreateDIBitmap(hdc, &bmih, 0, NULL, NULL, 0);
ok(hbm != NULL, "CreateDIBitmap failed\n");
- ok(GetObject(hbm, sizeof(bm), &bm), "GetObject failed\n");
-
- ok(bm.bmBitsPixel == screen_depth, "CreateDIBitmap created bitmap of incorrect depth %d != %d\n", bm.bmBitsPixel, screen_depth);
+ test_bitmap_info(hbm, screen_depth, &bmih);
DeleteObject(hbm);
/* Then 16 */
bmih.biBitCount = 16;
hbm = CreateDIBitmap(hdc, &bmih, 0, NULL, NULL, 0);
ok(hbm != NULL, "CreateDIBitmap failed\n");
- ok(GetObject(hbm, sizeof(bm), &bm), "GetObject failed\n");
-
- ok(bm.bmBitsPixel == screen_depth, "CreateDIBitmap created bitmap of incorrect depth %d != %d\n", bm.bmBitsPixel, screen_depth);
+ test_bitmap_info(hbm, screen_depth, &bmih);
DeleteObject(hbm);
/* Then 1 */
bmih.biBitCount = 1;
hbm = CreateDIBitmap(hdc, &bmih, 0, NULL, NULL, 0);
ok(hbm != NULL, "CreateDIBitmap failed\n");
- ok(GetObject(hbm, sizeof(bm), &bm), "GetObject failed\n");
-
- ok(bm.bmBitsPixel == screen_depth, "CreateDIBitmap created bitmap of incorrect depth %d != %d\n", bm.bmBitsPixel, screen_depth);
+ test_bitmap_info(hbm, screen_depth, &bmih);
DeleteObject(hbm);
/* Now with a monochrome dc we expect a monochrome bitmap */
@@ -86,27 +159,21 @@ static void test_createdibitmap(void)
bmih.biBitCount = 32;
hbm = CreateDIBitmap(hdcmem, &bmih, 0, NULL, NULL, 0);
ok(hbm != NULL, "CreateDIBitmap failed\n");
- ok(GetObject(hbm, sizeof(bm), &bm), "GetObject failed\n");
-
- ok(bm.bmBitsPixel == 1, "CreateDIBitmap created bitmap of incorrect depth %d != %d\n", bm.bmBitsPixel, 1);
+ test_bitmap_info(hbm, 1, &bmih);
DeleteObject(hbm);
/* Then 16 */
bmih.biBitCount = 16;
hbm = CreateDIBitmap(hdcmem, &bmih, 0, NULL, NULL, 0);
ok(hbm != NULL, "CreateDIBitmap failed\n");
- ok(GetObject(hbm, sizeof(bm), &bm), "GetObject failed\n");
-
- ok(bm.bmBitsPixel == 1, "CreateDIBitmap created bitmap of incorrect depth %d != %d\n", bm.bmBitsPixel, 1);
+ test_bitmap_info(hbm, 1, &bmih);
DeleteObject(hbm);
/* Then 1 */
bmih.biBitCount = 1;
hbm = CreateDIBitmap(hdcmem, &bmih, 0, NULL, NULL, 0);
ok(hbm != NULL, "CreateDIBitmap failed\n");
- ok(GetObject(hbm, sizeof(bm), &bm), "GetObject failed\n");
-
- ok(bm.bmBitsPixel == 1, "CreateDIBitmap created bitmap of incorrect depth %d != %d\n", bm.bmBitsPixel, 1);
+ test_bitmap_info(hbm, 1, &bmih);
DeleteObject(hbm);
/* Now select a polychrome bitmap into the dc and we expect
@@ -118,27 +185,21 @@ static void test_createdibitmap(void)
bmih.biBitCount = 32;
hbm = CreateDIBitmap(hdcmem, &bmih, 0, NULL, NULL, 0);
ok(hbm != NULL, "CreateDIBitmap failed\n");
- ok(GetObject(hbm, sizeof(bm), &bm), "GetObject failed\n");
-
- ok(bm.bmBitsPixel == screen_depth, "CreateDIBitmap created bitmap of incorrect depth %d != %d\n", bm.bmBitsPixel, screen_depth);
+ test_bitmap_info(hbm, screen_depth, &bmih);
DeleteObject(hbm);
/* Then 16 */
bmih.biBitCount = 16;
hbm = CreateDIBitmap(hdcmem, &bmih, 0, NULL, NULL, 0);
ok(hbm != NULL, "CreateDIBitmap failed\n");
- ok(GetObject(hbm, sizeof(bm), &bm), "GetObject failed\n");
-
- ok(bm.bmBitsPixel == screen_depth, "CreateDIBitmap created bitmap of incorrect depth %d != %d\n", bm.bmBitsPixel, screen_depth);
+ test_bitmap_info(hbm, screen_depth, &bmih);
DeleteObject(hbm);
/* Then 1 */
bmih.biBitCount = 1;
hbm = CreateDIBitmap(hdcmem, &bmih, 0, NULL, NULL, 0);
ok(hbm != NULL, "CreateDIBitmap failed\n");
- ok(GetObject(hbm, sizeof(bm), &bm), "GetObject failed\n");
-
- ok(bm.bmBitsPixel == screen_depth, "CreateDIBitmap created bitmap of incorrect depth %d != %d\n", bm.bmBitsPixel, screen_depth);
+ test_bitmap_info(hbm, screen_depth, &bmih);
DeleteObject(hbm);
SelectObject(hdcmem, hbm_old);
@@ -150,15 +211,124 @@ static void test_createdibitmap(void)
bmih.biBitCount = 32;
hbm = CreateDIBitmap(0, &bmih, 0, NULL, NULL, 0);
ok(hbm != NULL, "CreateDIBitmap failed\n");
- ok(GetObject(hbm, sizeof(bm), &bm), "GetObject failed\n");
-
- ok(bm.bmBitsPixel == 1, "CreateDIBitmap created bitmap of incorrect depth %d != %d\n", bm.bmBitsPixel, 1);
+ test_bitmap_info(hbm, 1, &bmih);
DeleteObject(hbm);
}
ReleaseDC(0, hdc);
}
+static INT DIB_GetWidthBytes( int width, int bpp )
+{
+ int words;
+
+ switch (bpp)
+ {
+ case 1: words = (width + 31) / 32; break;
+ case 4: words = (width + 7) / 8; break;
+ case 8: words = (width + 3) / 4; break;
+ case 15:
+ case 16: words = (width + 1) / 2; break;
+ case 24: words = (width * 3 + 3)/4; break;
+ case 32: words = width; break;
+
+ default:
+ words=0;
+ trace("Unknown depth %d, please report.\n", bpp );
+ assert(0);
+ break;
+ }
+ return 4 * words;
+}
+
+static void test_dib_info(HBITMAP hbm, const void *bits, const BITMAPINFOHEADER *bmih)
+{
+ BITMAP bm;
+ DIBSECTION ds;
+ INT ret, width_bytes;
+ BYTE *buf;
+
+ ret = GetObject(hbm, sizeof(bm), &bm);
+ ok(ret == sizeof(bm), "GetObject returned %d\n", ret);
+
+ ok(bm.bmType == 0, "wrong bm.bmType %d\n", bm.bmType);
+ ok(bm.bmWidth == bmih->biWidth, "wrong bm.bmWidth %d\n", bm.bmWidth);
+ ok(bm.bmHeight == bmih->biHeight, "wrong bm.bmHeight %d\n", bm.bmHeight);
+ width_bytes = DIB_GetWidthBytes(bm.bmWidth, bm.bmBitsPixel);
+ ok(bm.bmWidthBytes == width_bytes, "wrong bm.bmWidthBytes %d != %d\n", bm.bmWidthBytes, width_bytes);
+ ok(bm.bmPlanes == bmih->biPlanes, "wrong bm.bmPlanes %d\n", bm.bmPlanes);
+ ok(bm.bmBitsPixel == bmih->biBitCount, "bm.bmBitsPixel %d != %d\n", bm.bmBitsPixel, bmih->biBitCount);
+ ok(bm.bmBits == bits, "wrong bm.bmBits %p != %p\n", bm.bmBits, bits);
+
+ buf = HeapAlloc(GetProcessHeap(), 0, bm.bmWidthBytes * bm.bmHeight + 4096);
+
+ width_bytes = BITMAP_GetWidthBytes(bm.bmWidth, bm.bmBitsPixel);
+
+ /* GetBitmapBits returns not 32-bit aligned data */
+ ret = GetBitmapBits(hbm, 0, NULL);
+ ok(ret == width_bytes * bm.bmHeight, "%d != %d\n", ret, width_bytes * bm.bmHeight);
+
+ memset(buf, 0xAA, bm.bmWidthBytes * bm.bmHeight + 4096);
+ ret = GetBitmapBits(hbm, bm.bmWidthBytes * bm.bmHeight + 4096, buf);
+ ok(ret == width_bytes * bm.bmHeight, "%d != %d\n", ret, width_bytes * bm.bmHeight);
+
+ HeapFree(GetProcessHeap(), 0, buf);
+
+ /* test various buffer sizes for GetObject */
+ memset(&ds, 0xAA, sizeof(ds));
+ ret = GetObject(hbm, sizeof(bm) * 2, &bm);
+ ok(ret == sizeof(bm), "wrong size %d\n", ret);
+ ok(bm.bmWidth == bmih->biWidth, "wrong bm.bmWidth %d\n", bm.bmWidth);
+ ok(bm.bmHeight == bmih->biHeight, "wrong bm.bmHeight %d\n", bm.bmHeight);
+ ok(bm.bmBits == bits, "wrong bm.bmBits %p != %p\n", bm.bmBits, bits);
+
+ ret = GetObject(hbm, sizeof(bm) / 2, &bm);
+ ok(ret == 0, "%d != 0\n", ret);
+
+ ret = GetObject(hbm, 0, &bm);
+ ok(ret == 0, "%d != 0\n", ret);
+
+ ret = GetObject(hbm, 1, &bm);
+ ok(ret == 0, "%d != 0\n", ret);
+
+ /* test various buffer sizes for GetObject */
+ ret = GetObject(hbm, 0, NULL);
+ ok(ret == sizeof(bm), "wrong size %d\n", ret);
+
+ memset(&ds, 0xAA, sizeof(ds));
+ ret = GetObject(hbm, sizeof(ds) * 2, &ds);
+ ok(ret == sizeof(ds), "wrong size %d\n", ret);
+
+ ok(ds.dsBm.bmBits == bits, "wrong bm.bmBits %p != %p\n", ds.dsBm.bmBits, bits);
+ ok(ds.dsBmih.biSizeImage == ds.dsBm.bmWidthBytes * ds.dsBm.bmHeight, "%lu != %u\n",
+ ds.dsBmih.biSizeImage, ds.dsBm.bmWidthBytes * ds.dsBm.bmHeight);
+ ok(bmih->biSizeImage == 0, "%lu != 0\n", bmih->biSizeImage);
+ ds.dsBmih.biSizeImage = 0;
+
+ ok(ds.dsBmih.biSize == bmih->biSize, "%lu != %lu\n", ds.dsBmih.biSize, bmih->biSize);
+ ok(ds.dsBmih.biWidth == bmih->biWidth, "%lu != %lu\n", ds.dsBmih.biWidth, bmih->biWidth);
+ ok(ds.dsBmih.biHeight == bmih->biHeight, "%lu != %lu\n", ds.dsBmih.biHeight, bmih->biHeight);
+ ok(ds.dsBmih.biPlanes == bmih->biPlanes, "%u != %u\n", ds.dsBmih.biPlanes, bmih->biPlanes);
+ ok(ds.dsBmih.biBitCount == bmih->biBitCount, "%u != %u\n", ds.dsBmih.biBitCount, bmih->biBitCount);
+ ok(ds.dsBmih.biCompression == bmih->biCompression, "%lu != %lu\n", ds.dsBmih.biCompression, bmih->biCompression);
+ ok(ds.dsBmih.biSizeImage == bmih->biSizeImage, "%lu != %lu\n", ds.dsBmih.biSizeImage, bmih->biSizeImage);
+ ok(ds.dsBmih.biXPelsPerMeter == bmih->biXPelsPerMeter, "%lu != %lu\n", ds.dsBmih.biXPelsPerMeter, bmih->biXPelsPerMeter);
+ ok(ds.dsBmih.biYPelsPerMeter == bmih->biYPelsPerMeter, "%lu != %lu\n", ds.dsBmih.biYPelsPerMeter, bmih->biYPelsPerMeter);
+
+ memset(&ds, 0xAA, sizeof(ds));
+ ret = GetObject(hbm, sizeof(ds) - 4, &ds);
+ ok(ret == sizeof(ds.dsBm), "wrong size %d\n", ret);
+ ok(ds.dsBm.bmWidth == bmih->biWidth, "%lu != %lu\n", ds.dsBmih.biWidth, bmih->biWidth);
+ ok(ds.dsBm.bmHeight == bmih->biHeight, "%lu != %lu\n", ds.dsBmih.biHeight, bmih->biHeight);
+ ok(ds.dsBm.bmBits == bits, "%p != %p\n", ds.dsBm.bmBits, bits);
+
+ ret = GetObject(hbm, 0, &ds);
+ ok(ret == 0, "%d != 0\n", ret);
+
+ ret = GetObject(hbm, 1, &ds);
+ ok(ret == 0, "%d != 0\n", ret);
+}
+
#define test_color_todo(got, exp, txt, todo) \
if (!todo && got != exp && screen_depth < 24) { \
todo_wine ok(0, #txt " failed at %d-bit screen depth: got 0x%06x expected 0x%06x - skipping DIB tests\n", \
@@ -194,12 +364,73 @@ static void test_dibsections(void)
WORD *index;
DWORD *bits32;
HPALETTE hpal, oldpal;
+ DIBSECTION dibsec;
COLORREF c0, c1;
int i;
int screen_depth;
+ MEMORY_BASIC_INFORMATION info;
hdc = GetDC(0);
screen_depth = GetDeviceCaps(hdc, BITSPIXEL) * GetDeviceCaps(hdc, PLANES);
+
+ memset(pbmi, 0, sizeof(bmibuf));
+ pbmi->bmiHeader.biSize = sizeof(pbmi->bmiHeader);
+ pbmi->bmiHeader.biHeight = 100;
+ pbmi->bmiHeader.biWidth = 512;
+ pbmi->bmiHeader.biBitCount = 24;
+ pbmi->bmiHeader.biPlanes = 1;
+ pbmi->bmiHeader.biCompression = BI_RGB;
+
+ SetLastError(0xdeadbeef);
+ hdib = CreateDIBSection(hdc, pbmi, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
+ ok(hdib != NULL, "CreateDIBSection error %ld\n", GetLastError());
+ ok(GetObject(hdib, sizeof(DIBSECTION), &dibsec) != 0, "GetObject failed for DIBSection\n");
+ ok(dibsec.dsBm.bmBits == bits, "dibsec.dsBits %p != bits %p\n", dibsec.dsBm.bmBits, bits);
+
+ /* test the DIB memory */
+ ok(VirtualQuery(bits, &info, sizeof(info)) == sizeof(info),
+ "VirtualQuery failed\n");
+ ok(info.BaseAddress == bits, "%p != %p\n", info.BaseAddress, bits);
+ ok(info.AllocationBase == bits, "%p != %p\n", info.AllocationBase, bits);
+ ok(info.AllocationProtect == PAGE_READWRITE, "%lx != PAGE_READWRITE\n", info.AllocationProtect);
+ ok(info.RegionSize == 0x26000, "0x%lx != 0x26000\n", info.RegionSize);
+ ok(info.State == MEM_COMMIT, "%lx != MEM_COMMIT\n", info.State);
+ ok(info.Protect == PAGE_READWRITE, "%lx != PAGE_READWRITE\n", info.Protect);
+ ok(info.Type == MEM_PRIVATE, "%lx != MEM_PRIVATE\n", info.Type);
+
+ test_dib_info(hdib, bits, &pbmi->bmiHeader);
+ DeleteObject(hdib);
+
+ pbmi->bmiHeader.biBitCount = 8;
+ pbmi->bmiHeader.biCompression = BI_RLE8;
+ SetLastError(0xdeadbeef);
+ hdib = CreateDIBSection(hdc, pbmi, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
+ ok(hdib == NULL, "CreateDIBSection should fail when asked to create a compressed DIB section\n");
+ ok(GetLastError() == 0xdeadbeef, "wrong error %ld\n", GetLastError());
+
+ pbmi->bmiHeader.biBitCount = 16;
+ pbmi->bmiHeader.biCompression = BI_BITFIELDS;
+ ((PDWORD)pbmi->bmiColors)[0] = 0xf800;
+ ((PDWORD)pbmi->bmiColors)[1] = 0x07e0;
+ ((PDWORD)pbmi->bmiColors)[2] = 0x001f;
+ SetLastError(0xdeadbeef);
+ hdib = CreateDIBSection(hdc, pbmi, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
+ ok(hdib != NULL, "CreateDIBSection error %ld\n", GetLastError());
+
+ /* test the DIB memory */
+ ok(VirtualQuery(bits, &info, sizeof(info)) == sizeof(info),
+ "VirtualQuery failed\n");
+ ok(info.BaseAddress == bits, "%p != %p\n", info.BaseAddress, bits);
+ ok(info.AllocationBase == bits, "%p != %p\n", info.AllocationBase, bits);
+ ok(info.AllocationProtect == PAGE_READWRITE, "%lx != PAGE_READWRITE\n", info.AllocationProtect);
+ ok(info.RegionSize == 0x19000, "0x%lx != 0x19000\n", info.RegionSize);
+ ok(info.State == MEM_COMMIT, "%lx != MEM_COMMIT\n", info.State);
+ ok(info.Protect == PAGE_READWRITE, "%lx != PAGE_READWRITE\n", info.Protect);
+ ok(info.Type == MEM_PRIVATE, "%lx != MEM_PRIVATE\n", info.Type);
+
+ test_dib_info(hdib, bits, &pbmi->bmiHeader);
+ DeleteObject(hdib);
+
memset(pbmi, 0, sizeof(bmibuf));
pbmi->bmiHeader.biSize = sizeof(pbmi->bmiHeader);
pbmi->bmiHeader.biHeight = 16;
@@ -216,6 +447,9 @@ static void test_dibsections(void)
hdib = CreateDIBSection(hdc, pbmi, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
ok(hdib != NULL, "CreateDIBSection failed\n");
+ ok(GetObject(hdib, sizeof(DIBSECTION), &dibsec) != 0, "GetObject failed for DIBSection\n");
+ ok(dibsec.dsBmih.biClrUsed == 2,
+ "created DIBSection: wrong biClrUsed field: %lu, should be: %u\n", dibsec.dsBmih.biClrUsed, 2);
/* Test if the old BITMAPCOREINFO structure is supported */
@@ -280,6 +514,45 @@ static void test_dibsections(void)
SelectObject(hdcmem, oldbm);
DeleteObject(hdib);
+ pbmi->bmiColors[0].rgbRed = 0xff;
+ pbmi->bmiColors[0].rgbGreen = 0xff;
+ pbmi->bmiColors[0].rgbBlue = 0xff;
+ pbmi->bmiColors[1].rgbRed = 0;
+ pbmi->bmiColors[1].rgbGreen = 0;
+ pbmi->bmiColors[1].rgbBlue = 0;
+
+ hdib = CreateDIBSection(hdc, pbmi, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
+ ok(hdib != NULL, "CreateDIBSection failed\n");
+
+ test_dib_info(hdib, bits, &pbmi->bmiHeader);
+
+ oldbm = SelectObject(hdcmem, hdib);
+
+ ret = GetDIBColorTable(hdcmem, 0, 2, rgb);
+ ok(ret == 2, "GetDIBColorTable returned %d\n", ret);
+ ok(!memcmp(rgb, pbmi->bmiColors, 2 * sizeof(RGBQUAD)),
+ "GetDIBColorTable returns table 0: r%02x g%02x b%02x res%02x 1: r%02x g%02x b%02x res%02x\n",
+ rgb[0].rgbRed, rgb[0].rgbGreen, rgb[0].rgbBlue, rgb[0].rgbReserved,
+ rgb[1].rgbRed, rgb[1].rgbGreen, rgb[1].rgbBlue, rgb[1].rgbReserved);
+
+ SelectObject(hdcmem, oldbm);
+ test_dib_info(hdib, bits, &pbmi->bmiHeader);
+ DeleteObject(hdib);
+
+ pbmi->bmiHeader.biBitCount = 4;
+ for (i = 0; i < 16; i++) {
+ pbmi->bmiColors[i].rgbRed = i;
+ pbmi->bmiColors[i].rgbGreen = 16-i;
+ pbmi->bmiColors[i].rgbBlue = 0;
+ }
+ hdib = CreateDIBSection(hdcmem, pbmi, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
+ ok(hdib != NULL, "CreateDIBSection failed\n");
+ ok(GetObject(hdib, sizeof(DIBSECTION), &dibsec) != 0, "GetObject failed for DIB Section\n");
+ ok(dibsec.dsBmih.biClrUsed == 16,
+ "created DIBSection: wrong biClrUsed field: %lu, should be: %u\n", dibsec.dsBmih.biClrUsed, 16);
+ test_dib_info(hdib, bits, &pbmi->bmiHeader);
+ DeleteObject(hdib);
+
pbmi->bmiHeader.biBitCount = 8;
for (i = 0; i < 128; i++) {
@@ -292,6 +565,10 @@ static void test_dibsections(void)
}
hdib = CreateDIBSection(hdcmem, pbmi, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
ok(hdib != NULL, "CreateDIBSection failed\n");
+ ok(GetObject(hdib, sizeof(DIBSECTION), &dibsec) != 0, "GetObject failed for DIB Section\n");
+ ok(dibsec.dsBmih.biClrUsed == 256,
+ "created DIBSection: wrong biClrUsed field: %lu, should be: %u\n", dibsec.dsBmih.biClrUsed, 256);
+
oldbm = SelectObject(hdcmem, hdib);
for (i = 0; i < 256; i++) {
@@ -302,6 +579,7 @@ static void test_dibsections(void)
}
SelectObject(hdcmem, oldbm);
+ test_dib_info(hdib, bits, &pbmi->bmiHeader);
DeleteObject(hdib);
pbmi->bmiHeader.biBitCount = 1;
@@ -322,6 +600,9 @@ static void test_dibsections(void)
oldpal = SelectPalette(hdc, hpal, TRUE);
hdib = CreateDIBSection(hdc, pbmi, DIB_PAL_COLORS, (void**)&bits, NULL, 0);
ok(hdib != NULL, "CreateDIBSection failed\n");
+ ok(GetObject(hdib, sizeof(DIBSECTION), &dibsec) != 0, "GetObject failed for DIB Section\n");
+ ok(dibsec.dsBmih.biClrUsed == 2,
+ "created DIBSection: wrong biClrUsed field: %lu, should be: %u\n", dibsec.dsBmih.biClrUsed, 2);
/* The colour table has already been grabbed from the dc, so we select back the
old palette */
@@ -362,6 +643,7 @@ static void test_dibsections(void)
bits[0] = bits[1] = 0xff;
bits[13 * 4] = bits[13*4 + 1] = 0xff;
+ test_dib_info(hdib, bits, &pbmi->bmiHeader);
pbmi->bmiHeader.biBitCount = 32;
@@ -376,6 +658,7 @@ static void test_dibsections(void)
ok(bits32[17] == 0xff00ff, "bottom but one, left pixel is %08lx\n", bits32[17]);
SelectObject(hdcmem2, oldbm2);
+ test_dib_info(hdib2, bits32, &pbmi->bmiHeader);
DeleteObject(hdib2);
SelectObject(hdcmem, oldbm);
@@ -409,6 +692,11 @@ static void test_dibsections(void)
oldpal = SelectPalette(hdc, hpal, TRUE);
hdib = CreateDIBSection(hdc, pbmi, DIB_PAL_COLORS, (void**)&bits, NULL, 0);
ok(hdib != NULL, "CreateDIBSection failed\n");
+ ok(GetObject(hdib, sizeof(DIBSECTION), &dibsec) != 0, "GetObject failed for DIB Section\n");
+ ok(dibsec.dsBmih.biClrUsed == 256,
+ "created DIBSection: wrong biClrUsed field: %lu, should be: %u\n", dibsec.dsBmih.biClrUsed, 256);
+
+ test_dib_info(hdib, bits, &pbmi->bmiHeader);
SelectPalette(hdc, oldpal, TRUE);
oldbm = SelectObject(hdcmem, hdib);
@@ -443,17 +731,534 @@ static void test_dibsections(void)
ReleaseDC(0, hdc);
}
+void test_mono_dibsection(void)
+{
+ HDC hdc, memdc;
+ HBITMAP old_bm, mono_ds;
+ char bmibuf[sizeof(BITMAPINFO) + 256 * sizeof(RGBQUAD)];
+ BITMAPINFO *pbmi = (BITMAPINFO *)bmibuf;
+ BYTE bits[10 * 4];
+ BYTE *ds_bits;
+ int num;
+
+ hdc = GetDC(0);
+
+ memdc = CreateCompatibleDC(hdc);
+
+ memset(pbmi, 0, sizeof(bmibuf));
+ pbmi->bmiHeader.biSize = sizeof(pbmi->bmiHeader);
+ pbmi->bmiHeader.biHeight = 10;
+ pbmi->bmiHeader.biWidth = 10;
+ pbmi->bmiHeader.biBitCount = 1;
+ pbmi->bmiHeader.biPlanes = 1;
+ pbmi->bmiHeader.biCompression = BI_RGB;
+ pbmi->bmiColors[0].rgbRed = 0xff;
+ pbmi->bmiColors[0].rgbGreen = 0xff;
+ pbmi->bmiColors[0].rgbBlue = 0xff;
+ pbmi->bmiColors[1].rgbRed = 0x0;
+ pbmi->bmiColors[1].rgbGreen = 0x0;
+ pbmi->bmiColors[1].rgbBlue = 0x0;
+
+ /*
+ * First dib section is 'inverted' ie color[0] is white, color[1] is black
+ */
+
+ mono_ds = CreateDIBSection(hdc, pbmi, DIB_RGB_COLORS, (void**)&ds_bits, NULL, 0);
+ ok(mono_ds != NULL, "CreateDIBSection rets NULL\n");
+ old_bm = SelectObject(memdc, mono_ds);
+
+ /* black border, white interior */
+ Rectangle(memdc, 0, 0, 10, 10);
+ ok(ds_bits[0] == 0xff, "out_bits %02x\n", ds_bits[0]);
+ ok(ds_bits[4] == 0x80, "out_bits %02x\n", ds_bits[4]);
+
+ /* SetDIBitsToDevice with an inverted bmi -> inverted dib section */
+
+ memset(bits, 0, sizeof(bits));
+ bits[0] = 0xaa;
+
+ SetDIBitsToDevice(memdc, 0, 0, 10, 10, 0, 0, 0, 10, bits, pbmi, DIB_RGB_COLORS);
+ ok(ds_bits[0] == 0xaa, "out_bits %02x\n", ds_bits[0]);
+
+ /* SetDIBitsToDevice with a normal bmi -> inverted dib section */
+
+ pbmi->bmiColors[0].rgbRed = 0x0;
+ pbmi->bmiColors[0].rgbGreen = 0x0;
+ pbmi->bmiColors[0].rgbBlue = 0x0;
+ pbmi->bmiColors[1].rgbRed = 0xff;
+ pbmi->bmiColors[1].rgbGreen = 0xff;
+ pbmi->bmiColors[1].rgbBlue = 0xff;
+
+ SetDIBitsToDevice(memdc, 0, 0, 10, 10, 0, 0, 0, 10, bits, pbmi, DIB_RGB_COLORS);
+ ok(ds_bits[0] == 0x55, "out_bits %02x\n", ds_bits[0]);
+
+ SelectObject(memdc, old_bm);
+ DeleteObject(mono_ds);
+
+ /*
+ * Next dib section is 'normal' ie color[0] is black, color[1] is white
+ */
+
+ pbmi->bmiColors[0].rgbRed = 0x0;
+ pbmi->bmiColors[0].rgbGreen = 0x0;
+ pbmi->bmiColors[0].rgbBlue = 0x0;
+ pbmi->bmiColors[1].rgbRed = 0xff;
+ pbmi->bmiColors[1].rgbGreen = 0xff;
+ pbmi->bmiColors[1].rgbBlue = 0xff;
+
+ mono_ds = CreateDIBSection(hdc, pbmi, DIB_RGB_COLORS, (void**)&ds_bits, NULL, 0);
+ ok(mono_ds != NULL, "CreateDIBSection rets NULL\n");
+ old_bm = SelectObject(memdc, mono_ds);
+
+ /* black border, white interior */
+ Rectangle(memdc, 0, 0, 10, 10);
+ ok(ds_bits[0] == 0x00, "out_bits %02x\n", ds_bits[0]);
+ ok(ds_bits[4] == 0x7f, "out_bits %02x\n", ds_bits[4]);
+
+ /* SetDIBitsToDevice with a normal bmi -> normal dib section */
+
+ SetDIBitsToDevice(memdc, 0, 0, 10, 10, 0, 0, 0, 10, bits, pbmi, DIB_RGB_COLORS);
+ ok(ds_bits[0] == 0xaa, "out_bits %02x\n", ds_bits[0]);
+
+ /* SetDIBitsToDevice with a inverted bmi -> normal dib section */
+
+ pbmi->bmiColors[0].rgbRed = 0xff;
+ pbmi->bmiColors[0].rgbGreen = 0xff;
+ pbmi->bmiColors[0].rgbBlue = 0xff;
+ pbmi->bmiColors[1].rgbRed = 0x0;
+ pbmi->bmiColors[1].rgbGreen = 0x0;
+ pbmi->bmiColors[1].rgbBlue = 0x0;
+
+ SetDIBitsToDevice(memdc, 0, 0, 10, 10, 0, 0, 0, 10, bits, pbmi, DIB_RGB_COLORS);
+ ok(ds_bits[0] == 0x55, "out_bits %02x\n", ds_bits[0]);
+
+ /*
+ * Take that 'normal' dibsection and change its colour table to an 'inverted' one
+ */
+
+ pbmi->bmiColors[0].rgbRed = 0xff;
+ pbmi->bmiColors[0].rgbGreen = 0xff;
+ pbmi->bmiColors[0].rgbBlue = 0xff;
+ pbmi->bmiColors[1].rgbRed = 0x0;
+ pbmi->bmiColors[1].rgbGreen = 0x0;
+ pbmi->bmiColors[1].rgbBlue = 0x0;
+ num = SetDIBColorTable(memdc, 0, 2, pbmi->bmiColors);
+ ok(num == 2, "num = %d\n", num);
+
+ /* black border, white interior */
+ Rectangle(memdc, 0, 0, 10, 10);
+todo_wine {
+ ok(ds_bits[0] == 0xff, "out_bits %02x\n", ds_bits[0]);
+ ok(ds_bits[4] == 0x80, "out_bits %02x\n", ds_bits[4]);
+ }
+ /* SetDIBitsToDevice with an inverted bmi -> inverted dib section */
+
+ memset(bits, 0, sizeof(bits));
+ bits[0] = 0xaa;
+
+ SetDIBitsToDevice(memdc, 0, 0, 10, 10, 0, 0, 0, 10, bits, pbmi, DIB_RGB_COLORS);
+ ok(ds_bits[0] == 0xaa, "out_bits %02x\n", ds_bits[0]);
+
+ /* SetDIBitsToDevice with a normal bmi -> inverted dib section */
+
+ pbmi->bmiColors[0].rgbRed = 0x0;
+ pbmi->bmiColors[0].rgbGreen = 0x0;
+ pbmi->bmiColors[0].rgbBlue = 0x0;
+ pbmi->bmiColors[1].rgbRed = 0xff;
+ pbmi->bmiColors[1].rgbGreen = 0xff;
+ pbmi->bmiColors[1].rgbBlue = 0xff;
+
+ SetDIBitsToDevice(memdc, 0, 0, 10, 10, 0, 0, 0, 10, bits, pbmi, DIB_RGB_COLORS);
+ ok(ds_bits[0] == 0x55, "out_bits %02x\n", ds_bits[0]);
+
+ SelectObject(memdc, old_bm);
+ DeleteObject(mono_ds);
+
+ /*
+ * Now a dib section with a strange colour map just for fun. This behaves just like an inverted one.
+ */
+
+ pbmi->bmiColors[0].rgbRed = 0xff;
+ pbmi->bmiColors[0].rgbGreen = 0x0;
+ pbmi->bmiColors[0].rgbBlue = 0x0;
+ pbmi->bmiColors[1].rgbRed = 0xfe;
+ pbmi->bmiColors[1].rgbGreen = 0x0;
+ pbmi->bmiColors[1].rgbBlue = 0x0;
+
+ mono_ds = CreateDIBSection(hdc, pbmi, DIB_RGB_COLORS, (void**)&ds_bits, NULL, 0);
+ ok(mono_ds != NULL, "CreateDIBSection rets NULL\n");
+ old_bm = SelectObject(memdc, mono_ds);
+
+ /* black border, white interior */
+ Rectangle(memdc, 0, 0, 10, 10);
+ ok(ds_bits[0] == 0xff, "out_bits %02x\n", ds_bits[0]);
+ ok(ds_bits[4] == 0x80, "out_bits %02x\n", ds_bits[4]);
+
+ /* SetDIBitsToDevice with a normal bmi -> inverted dib section */
+
+ pbmi->bmiColors[0].rgbRed = 0x0;
+ pbmi->bmiColors[0].rgbGreen = 0x0;
+ pbmi->bmiColors[0].rgbBlue = 0x0;
+ pbmi->bmiColors[1].rgbRed = 0xff;
+ pbmi->bmiColors[1].rgbGreen = 0xff;
+ pbmi->bmiColors[1].rgbBlue = 0xff;
+
+ SetDIBitsToDevice(memdc, 0, 0, 10, 10, 0, 0, 0, 10, bits, pbmi, DIB_RGB_COLORS);
+ ok(ds_bits[0] == 0x55, "out_bits %02x\n", ds_bits[0]);
+
+ /* SetDIBitsToDevice with a inverted bmi -> inverted dib section */
+
+ pbmi->bmiColors[0].rgbRed = 0xff;
+ pbmi->bmiColors[0].rgbGreen = 0xff;
+ pbmi->bmiColors[0].rgbBlue = 0xff;
+ pbmi->bmiColors[1].rgbRed = 0x0;
+ pbmi->bmiColors[1].rgbGreen = 0x0;
+ pbmi->bmiColors[1].rgbBlue = 0x0;
+
+ SetDIBitsToDevice(memdc, 0, 0, 10, 10, 0, 0, 0, 10, bits, pbmi, DIB_RGB_COLORS);
+ ok(ds_bits[0] == 0xaa, "out_bits %02x\n", ds_bits[0]);
+
+ SelectObject(memdc, old_bm);
+ DeleteObject(mono_ds);
+
+ DeleteDC(memdc);
+ ReleaseDC(0, hdc);
+}
+
+static void test_bitmap(void)
+{
+ char buf[256], buf_cmp[256];
+ HBITMAP hbmp, hbmp_old;
+ HDC hdc;
+ BITMAP bm;
+ INT ret;
+
+ hdc = CreateCompatibleDC(0);
+ assert(hdc != 0);
+
+ hbmp = CreateBitmap(15, 15, 1, 1, NULL);
+ assert(hbmp != NULL);
+
+ ret = GetObject(hbmp, sizeof(bm), &bm);
+ ok(ret == sizeof(bm), "wrong size %d\n", ret);
+
+ ok(bm.bmType == 0, "wrong bm.bmType %d\n", bm.bmType);
+ ok(bm.bmWidth == 15, "wrong bm.bmWidth %d\n", bm.bmWidth);
+ ok(bm.bmHeight == 15, "wrong bm.bmHeight %d\n", bm.bmHeight);
+ ok(bm.bmWidthBytes == 2, "wrong bm.bmWidthBytes %d\n", bm.bmWidthBytes);
+ ok(bm.bmPlanes == 1, "wrong bm.bmPlanes %d\n", bm.bmPlanes);
+ ok(bm.bmBitsPixel == 1, "wrong bm.bmBitsPixel %d\n", bm.bmBitsPixel);
+ ok(bm.bmBits == NULL, "wrong bm.bmBits %p\n", bm.bmBits);
+
+ assert(sizeof(buf) >= bm.bmWidthBytes * bm.bmHeight);
+ assert(sizeof(buf) == sizeof(buf_cmp));
+
+ ret = GetBitmapBits(hbmp, 0, NULL);
+ ok(ret == bm.bmWidthBytes * bm.bmHeight, "%d != %d\n", ret, bm.bmWidthBytes * bm.bmHeight);
+
+ memset(buf_cmp, 0xAA, sizeof(buf_cmp));
+ memset(buf_cmp, 0, bm.bmWidthBytes * bm.bmHeight);
+
+ memset(buf, 0xAA, sizeof(buf));
+ ret = GetBitmapBits(hbmp, sizeof(buf), buf);
+ ok(ret == bm.bmWidthBytes * bm.bmHeight, "%d != %d\n", ret, bm.bmWidthBytes * bm.bmHeight);
+ ok(!memcmp(buf, buf_cmp, sizeof(buf)), "buffers do not match\n");
+
+ hbmp_old = SelectObject(hdc, hbmp);
+
+ ret = GetObject(hbmp, sizeof(bm), &bm);
+ ok(ret == sizeof(bm), "wrong size %d\n", ret);
+
+ ok(bm.bmType == 0, "wrong bm.bmType %d\n", bm.bmType);
+ ok(bm.bmWidth == 15, "wrong bm.bmWidth %d\n", bm.bmWidth);
+ ok(bm.bmHeight == 15, "wrong bm.bmHeight %d\n", bm.bmHeight);
+ ok(bm.bmWidthBytes == 2, "wrong bm.bmWidthBytes %d\n", bm.bmWidthBytes);
+ ok(bm.bmPlanes == 1, "wrong bm.bmPlanes %d\n", bm.bmPlanes);
+ ok(bm.bmBitsPixel == 1, "wrong bm.bmBitsPixel %d\n", bm.bmBitsPixel);
+ ok(bm.bmBits == NULL, "wrong bm.bmBits %p\n", bm.bmBits);
+
+ memset(buf, 0xAA, sizeof(buf));
+ ret = GetBitmapBits(hbmp, sizeof(buf), buf);
+ ok(ret == bm.bmWidthBytes * bm.bmHeight, "%d != %d\n", ret, bm.bmWidthBytes * bm.bmHeight);
+ ok(!memcmp(buf, buf_cmp, sizeof(buf)), "buffers do not match\n");
+
+ hbmp_old = SelectObject(hdc, hbmp_old);
+ ok(hbmp_old == hbmp, "wrong old bitmap %p\n", hbmp_old);
+
+ /* test various buffer sizes for GetObject */
+ ret = GetObject(hbmp, sizeof(bm) * 2, &bm);
+ ok(ret == sizeof(bm), "wrong size %d\n", ret);
+
+ ret = GetObject(hbmp, sizeof(bm) / 2, &bm);
+ ok(ret == 0, "%d != 0\n", ret);
+
+ ret = GetObject(hbmp, 0, &bm);
+ ok(ret == 0, "%d != 0\n", ret);
+
+ ret = GetObject(hbmp, 1, &bm);
+ ok(ret == 0, "%d != 0\n", ret);
+
+ DeleteObject(hbmp);
+ DeleteDC(hdc);
+}
+
+static void test_bmBits(void)
+{
+ BYTE bits[4];
+ HBITMAP hbmp;
+ BITMAP bmp;
+
+ memset(bits, 0, sizeof(bits));
+ hbmp = CreateBitmap(2, 2, 1, 4, bits);
+ ok(hbmp != NULL, "CreateBitmap failed\n");
+
+ memset(&bmp, 0xFF, sizeof(bmp));
+ ok(GetObject(hbmp, sizeof(bmp), &bmp) == sizeof(bmp),
+ "GetObject failed or returned a wrong structure size\n");
+ ok(!bmp.bmBits, "bmBits must be NULL for device-dependent bitmaps\n");
+
+ DeleteObject(hbmp);
+}
+
+static void test_GetDIBits_selected_DIB(UINT bpp)
+{
+ HBITMAP dib;
+ BITMAPINFO * info;
+ BITMAPINFO * info2;
+ void * bits;
+ void * bits2;
+ UINT dib_size;
+ HDC dib_dc, dc;
+ HBITMAP old_bmp;
+ BOOL equalContents;
+ UINT i;
+ int res;
+
+ /* Create a DIB section with a color table */
+
+ info = (BITMAPINFO *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + (1 << bpp) * sizeof(RGBQUAD));
+ info2 = (BITMAPINFO *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + (1 << bpp) * sizeof(RGBQUAD));
+ assert(info);
+ assert(info2);
+
+ info->bmiHeader.biSize = sizeof(info->bmiHeader);
+
+ /* Choose width and height such that the row length (in bytes)
+ is a multiple of 4 (makes things easier) */
+ info->bmiHeader.biWidth = 32;
+ info->bmiHeader.biHeight = 32;
+ info->bmiHeader.biPlanes = 1;
+ info->bmiHeader.biBitCount = bpp;
+ info->bmiHeader.biCompression = BI_RGB;
+
+ for (i=0; i < (1 << bpp); i++)
+ {
+ BYTE c = i * (1 << (8 - bpp));
+ info->bmiColors[i].rgbRed = c;
+ info->bmiColors[i].rgbGreen = c;
+ info->bmiColors[i].rgbBlue = c;
+ info->bmiColors[i].rgbReserved = 0;
+ }
+
+ dib = CreateDIBSection(NULL, info, DIB_RGB_COLORS, &bits, NULL, 0);
+ assert(dib);
+ dib_size = bpp * (info->bmiHeader.biWidth * info->bmiHeader.biHeight) / 8;
+
+ /* Set the bits of the DIB section */
+ for (i=0; i < dib_size; i++)
+ {
+ ((BYTE *)bits)[i] = i % 256;
+ }
+
+ /* Select the DIB into a DC */
+ dib_dc = CreateCompatibleDC(NULL);
+ old_bmp = (HBITMAP) SelectObject(dib_dc, dib);
+ dc = CreateCompatibleDC(NULL);
+ bits2 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dib_size);
+ assert(bits2);
+
+ /* Copy the DIB attributes but not the color table */
+ memcpy(info2, info, sizeof(BITMAPINFOHEADER));
+
+ res = GetDIBits(dc, dib, 0, info->bmiHeader.biHeight, bits2, info2, DIB_RGB_COLORS);
+ ok(res, "GetDIBits failed\n");
+
+ /* Compare the color table and the bits */
+ equalContents = TRUE;
+ for (i=0; i < (1 << bpp); i++)
+ {
+ if ((info->bmiColors[i].rgbRed != info2->bmiColors[i].rgbRed)
+ || (info->bmiColors[i].rgbGreen != info2->bmiColors[i].rgbGreen)
+ || (info->bmiColors[i].rgbBlue != info2->bmiColors[i].rgbBlue)
+ || (info->bmiColors[i].rgbReserved != info2->bmiColors[i].rgbReserved))
+ {
+ equalContents = FALSE;
+ break;
+ }
+ }
+ todo_wine
+ {
+ ok(equalContents, "GetDIBits with DIB selected in DC: Invalid DIB color table\n");
+ }
+
+ equalContents = TRUE;
+ for (i=0; i < dib_size / sizeof(DWORD); i++)
+ {
+ if (((DWORD *)bits)[i] != ((DWORD *)bits2)[i])
+ {
+ equalContents = FALSE;
+ break;
+ }
+ }
+ todo_wine
+ {
+ ok(equalContents, "GetDIBits with DIB selected in DC: Invalid DIB bits\n");
+ }
+
+ HeapFree(GetProcessHeap(), 0, bits2);
+ DeleteDC(dc);
+
+ SelectObject(dib_dc, old_bmp);
+ DeleteDC(dib_dc);
+ DeleteObject(dib);
+
+ HeapFree(GetProcessHeap(), 0, info2);
+ HeapFree(GetProcessHeap(), 0, info);
+}
+
+static void test_GetDIBits_selected_DDB(BOOL monochrome)
+{
+ HBITMAP ddb;
+ BITMAPINFO * info;
+ BITMAPINFO * info2;
+ void * bits;
+ void * bits2;
+ HDC ddb_dc, dc;
+ HBITMAP old_bmp;
+ BOOL equalContents;
+ UINT width, height;
+ UINT bpp;
+ UINT i, j;
+ int res;
+
+ width = height = 16;
+
+ /* Create a DDB (device-dependent bitmap) */
+ if (monochrome)
+ {
+ bpp = 1;
+ ddb = CreateBitmap(width, height, 1, 1, NULL);
+ }
+ else
+ {
+ HDC screen_dc = GetDC(NULL);
+ bpp = GetDeviceCaps(screen_dc, BITSPIXEL) * GetDeviceCaps(screen_dc, PLANES);
+ ddb = CreateCompatibleBitmap(screen_dc, width, height);
+ ReleaseDC(NULL, screen_dc);
+ }
+
+ /* Set the pixels */
+ ddb_dc = CreateCompatibleDC(NULL);
+ old_bmp = (HBITMAP) SelectObject(ddb_dc, ddb);
+ for (i = 0; i < width; i++)
+ {
+ for (j=0; j < height; j++)
+ {
+ BYTE c = (i * width + j) % 256;
+ SetPixelV(ddb_dc, i, j, RGB(c, c, c));
+ }
+ }
+ SelectObject(ddb_dc, old_bmp);
+
+ info = (BITMAPINFO *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
+ info2 = (BITMAPINFO *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
+ assert(info);
+ assert(info2);
+
+ info->bmiHeader.biSize = sizeof(info->bmiHeader);
+ info->bmiHeader.biWidth = width;
+ info->bmiHeader.biHeight = height;
+ info->bmiHeader.biPlanes = 1;
+ info->bmiHeader.biBitCount = bpp;
+ info->bmiHeader.biCompression = BI_RGB;
+
+ dc = CreateCompatibleDC(NULL);
+
+ /* Fill in biSizeImage */
+ GetDIBits(dc, ddb, 0, height, NULL, info, DIB_RGB_COLORS);
+ ok(info->bmiHeader.biSizeImage != 0, "GetDIBits failed to get the DIB attributes\n");
+
+ bits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, info->bmiHeader.biSizeImage);
+ bits2 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, info->bmiHeader.biSizeImage);
+ assert(bits);
+ assert(bits2);
+
+ /* Get the bits */
+ res = GetDIBits(dc, ddb, 0, height, bits, info, DIB_RGB_COLORS);
+ ok(res, "GetDIBits failed\n");
+
+ /* Copy the DIB attributes but not the color table */
+ memcpy(info2, info, sizeof(BITMAPINFOHEADER));
+
+ /* Select the DDB into another DC */
+ old_bmp = (HBITMAP) SelectObject(ddb_dc, ddb);
+
+ /* Get the bits */
+ res = GetDIBits(dc, ddb, 0, height, bits2, info2, DIB_RGB_COLORS);
+ ok(res, "GetDIBits failed\n");
+
+ /* Compare the color table and the bits */
+ if (bpp <= 8)
+ {
+ equalContents = TRUE;
+ for (i=0; i < (1 << bpp); i++)
+ {
+ if ((info->bmiColors[i].rgbRed != info2->bmiColors[i].rgbRed)
+ || (info->bmiColors[i].rgbGreen != info2->bmiColors[i].rgbGreen)
+ || (info->bmiColors[i].rgbBlue != info2->bmiColors[i].rgbBlue)
+ || (info->bmiColors[i].rgbReserved != info2->bmiColors[i].rgbReserved))
+ {
+ equalContents = FALSE;
+ break;
+ }
+ }
+ ok(equalContents, "GetDIBits with DDB selected in DC: Got a different color table\n");
+ }
+
+ equalContents = TRUE;
+ for (i=0; i < info->bmiHeader.biSizeImage / sizeof(DWORD); i++)
+ {
+ if (((DWORD *)bits)[i] != ((DWORD *)bits2)[i])
+ {
+ equalContents = FALSE;
+ }
+ }
+ ok(equalContents, "GetDIBits with DDB selected in DC: Got different DIB bits\n");
+
+ HeapFree(GetProcessHeap(), 0, bits2);
+ HeapFree(GetProcessHeap(), 0, bits);
+ DeleteDC(dc);
+
+ SelectObject(ddb_dc, old_bmp);
+ DeleteDC(ddb_dc);
+ DeleteObject(ddb);
+
+ HeapFree(GetProcessHeap(), 0, info2);
+ HeapFree(GetProcessHeap(), 0, info);
+}
+
START_TEST(bitmap)
{
- HWND hWnd;
-
- hWnd = CreateWindowExA(0, "EDIT", NULL, 0,
- 10, 10, 300, 300,
- NULL, NULL, NULL, NULL);
- assert(hWnd);
- is_win9x = GetWindowLongW(hWnd, GWL_WNDPROC) == 0;
- DestroyWindow(hWnd);
+ is_win9x = GetWindowLongPtrW(GetDesktopWindow(), GWLP_WNDPROC) == 0;
test_createdibitmap();
test_dibsections();
+ test_mono_dibsection();
+ test_bitmap();
+ test_bmBits();
+ test_GetDIBits_selected_DIB(1);
+ test_GetDIBits_selected_DIB(4);
+ test_GetDIBits_selected_DIB(8);
+ test_GetDIBits_selected_DDB(TRUE);
+ test_GetDIBits_selected_DDB(FALSE);
}
diff --git a/reactos/regtests/winetests/gdi32/brush.c b/reactos/regtests/winetests/gdi32/brush.c
index f4e22b6b30d..c2aee7c138e 100755
--- a/reactos/regtests/winetests/gdi32/brush.c
+++ b/reactos/regtests/winetests/gdi32/brush.c
@@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include
@@ -56,7 +56,7 @@ static void test_solidbrush(void)
}
else
stockBrush = NULL;
- memset(&br, sizeof(br), 0);
+ memset(&br, 0, sizeof(br));
ret = GetObject(solidBrush, sizeof(br), &br);
ok( ret !=0, "GetObject on solid %s brush failed, error=%ld\n", stock[i].name, GetLastError());
ok(br.lbStyle==BS_SOLID, "%s brush has wrong style, got %d expected %d\n", stock[i].name, br.lbStyle, BS_SOLID);
diff --git a/reactos/regtests/winetests/gdi32/clipping.c b/reactos/regtests/winetests/gdi32/clipping.c
new file mode 100644
index 00000000000..079fbcc804c
--- /dev/null
+++ b/reactos/regtests/winetests/gdi32/clipping.c
@@ -0,0 +1,125 @@
+/*
+ * Unit test suite for clipping
+ *
+ * Copyright 2005 Huw Davies
+ *
+ * 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/test.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+
+static void test_GetRandomRgn(void)
+{
+ HWND hwnd = CreateWindowExA(0,"BUTTON","test",WS_VISIBLE|WS_POPUP,0,0,100,100,GetDesktopWindow(),0,0,0);
+ HDC hdc;
+ HRGN hrgn = CreateRectRgn(0, 0, 0, 0);
+ int ret;
+ RECT rc, rc2;
+ RECT ret_rc, window_rc;
+
+ ok( hwnd != 0, "CreateWindow failed\n" );
+
+ SetRect(&window_rc, 400, 300, 500, 400);
+ MoveWindow(hwnd, window_rc.left, window_rc.top, window_rc.right - window_rc.left, window_rc.bottom - window_rc.top, FALSE);
+ hdc = GetDC(hwnd);
+
+ ret = GetRandomRgn(hdc, hrgn, 1);
+ ok(ret == 0, "GetRandomRgn rets %d\n", ret);
+ ret = GetRandomRgn(hdc, hrgn, 2);
+ ok(ret == 0, "GetRandomRgn rets %d\n", ret);
+ ret = GetRandomRgn(hdc, hrgn, 3);
+ ok(ret == 0, "GetRandomRgn rets %d\n", ret);
+
+ /* Set a clip region */
+ SetRect(&rc, 20, 20, 80, 80);
+ IntersectClipRect(hdc, rc.left, rc.top, rc.right, rc.bottom);
+
+ ret = GetRandomRgn(hdc, hrgn, 1);
+ ok(ret != 0, "GetRandomRgn rets %d\n", ret);
+ GetRgnBox(hrgn, &ret_rc);
+ ok(EqualRect(&rc, &ret_rc), "GetRandomRgn %ld,%ld - %ld,%ld\n",
+ ret_rc.left, ret_rc.top, ret_rc.right, ret_rc.bottom);
+
+ ret = GetRandomRgn(hdc, hrgn, 2);
+ ok(ret == 0, "GetRandomRgn rets %d\n", ret);
+
+ ret = GetRandomRgn(hdc, hrgn, 3);
+ ok(ret != 0, "GetRandomRgn rets %d\n", ret);
+ GetRgnBox(hrgn, &ret_rc);
+ ok(EqualRect(&rc, &ret_rc), "GetRandomRgn %ld,%ld - %ld,%ld\n",
+ ret_rc.left, ret_rc.top, ret_rc.right, ret_rc.bottom);
+
+ /* Move the clip to the meta and clear the clip */
+ SetMetaRgn(hdc);
+
+ ret = GetRandomRgn(hdc, hrgn, 1);
+ ok(ret == 0, "GetRandomRgn rets %d\n", ret);
+ ret = GetRandomRgn(hdc, hrgn, 2);
+ ok(ret != 0, "GetRandomRgn rets %d\n", ret);
+ GetRgnBox(hrgn, &ret_rc);
+ ok(EqualRect(&rc, &ret_rc), "GetRandomRgn %ld,%ld - %ld,%ld\n",
+ ret_rc.left, ret_rc.top, ret_rc.right, ret_rc.bottom);
+
+ ret = GetRandomRgn(hdc, hrgn, 3);
+ ok(ret != 0, "GetRandomRgn rets %d\n", ret);
+ GetRgnBox(hrgn, &ret_rc);
+ ok(EqualRect(&rc, &ret_rc), "GetRandomRgn %ld,%ld - %ld,%ld\n",
+ ret_rc.left, ret_rc.top, ret_rc.right, ret_rc.bottom);
+
+ /* Set a new clip (still got the meta) */
+ SetRect(&rc2, 10, 30, 70, 90);
+ IntersectClipRect(hdc, rc2.left, rc2.top, rc2.right, rc2.bottom);
+
+ ret = GetRandomRgn(hdc, hrgn, 1);
+ ok(ret != 0, "GetRandomRgn rets %d\n", ret);
+ GetRgnBox(hrgn, &ret_rc);
+ ok(EqualRect(&rc2, &ret_rc), "GetRandomRgn %ld,%ld - %ld,%ld\n",
+ ret_rc.left, ret_rc.top, ret_rc.right, ret_rc.bottom);
+
+ ret = GetRandomRgn(hdc, hrgn, 2);
+ ok(ret != 0, "GetRandomRgn rets %d\n", ret);
+ GetRgnBox(hrgn, &ret_rc);
+ ok(EqualRect(&rc, &ret_rc), "GetRandomRgn %ld,%ld - %ld,%ld\n",
+ ret_rc.left, ret_rc.top, ret_rc.right, ret_rc.bottom);
+
+ IntersectRect(&rc2, &rc, &rc2);
+
+ ret = GetRandomRgn(hdc, hrgn, 3);
+ ok(ret != 0, "GetRandomRgn rets %d\n", ret);
+ GetRgnBox(hrgn, &ret_rc);
+ ok(EqualRect(&rc2, &ret_rc), "GetRandomRgn %ld,%ld - %ld,%ld\n",
+ ret_rc.left, ret_rc.top, ret_rc.right, ret_rc.bottom);
+
+
+ ret = GetRandomRgn(hdc, hrgn, SYSRGN);
+ ok(ret != 0, "GetRandomRgn rets %d\n", ret);
+ GetRgnBox(hrgn, &ret_rc);
+ if(GetVersion() & 0x80000000)
+ OffsetRect(&window_rc, -window_rc.left, -window_rc.top);
+ ok(EqualRect(&window_rc, &ret_rc), "GetRandomRgn %ld,%ld - %ld,%ld\n",
+ ret_rc.left, ret_rc.top, ret_rc.right, ret_rc.bottom);
+
+ DeleteObject(hrgn);
+ ReleaseDC(hwnd, hdc);
+ DestroyWindow(hwnd);
+}
+
+START_TEST(clipping)
+{
+ test_GetRandomRgn();
+}
diff --git a/reactos/regtests/winetests/gdi32/dc.c b/reactos/regtests/winetests/gdi32/dc.c
new file mode 100644
index 00000000000..5b50632750d
--- /dev/null
+++ b/reactos/regtests/winetests/gdi32/dc.c
@@ -0,0 +1,180 @@
+/*
+ * Unit tests for dc functions
+ *
+ * Copyright (c) 2005 Huw Davies
+ * Copyright (c) 2005 Dmitry Timoshkov
+ *
+ * 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
+#include
+
+#include "wine/test.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "winerror.h"
+
+static void dump_region(HRGN hrgn)
+{
+ DWORD i, size;
+ RGNDATA *data = NULL;
+ RECT *rect;
+
+ if (!hrgn)
+ {
+ printf( "(null) region\n" );
+ return;
+ }
+ if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
+ if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
+ GetRegionData( hrgn, size, data );
+ printf( "%ld rects:", data->rdh.nCount );
+ for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
+ printf( " (%ld,%ld)-(%ld,%ld)", rect->left, rect->top, rect->right, rect->bottom );
+ printf( "\n" );
+ HeapFree( GetProcessHeap(), 0, data );
+}
+
+static void test_savedc_2(void)
+{
+ HWND hwnd;
+ HDC hdc;
+ HRGN hrgn;
+ RECT rc, rc_clip;
+ int ret;
+
+ hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,
+ 0, 0, 0, NULL);
+ assert(hwnd != 0);
+ ShowWindow(hwnd, SW_SHOW);
+ UpdateWindow(hwnd);
+
+ hrgn = CreateRectRgn(0, 0, 0, 0);
+ assert(hrgn != 0);
+
+ hdc = GetDC(hwnd);
+ ok(hdc != NULL, "CreateDC rets %p\n", hdc);
+
+ ret = GetClipBox(hdc, &rc_clip);
+ ok(ret == SIMPLEREGION, "GetClipBox returned %d instead of SIMPLEREGION\n", ret);
+ ret = GetClipRgn(hdc, hrgn);
+ ok(ret == 0, "GetClipRgn returned %d instead of 0\n", ret);
+ ret = GetRgnBox(hrgn, &rc);
+ ok(ret == NULLREGION, "GetRgnBox returned %d (%ld,%ld-%ld,%ld) instead of NULLREGION\n",
+ ret, rc.left, rc.top, rc.right, rc.bottom);
+ /*dump_region(hrgn);*/
+ SetRect(&rc, 0, 0, 100, 100);
+ ok(EqualRect(&rc, &rc_clip),
+ "rects are not equal: (%ld,%ld-%ld,%ld) - (%ld,%ld-%ld,%ld)\n",
+ rc.left, rc.top, rc.right, rc.bottom,
+ rc_clip.left, rc_clip.top, rc_clip.right, rc_clip.bottom);
+
+ ret = SaveDC(hdc);
+todo_wine
+{
+ ok(ret == 1, "ret = %d\n", ret);
+}
+
+ ret = IntersectClipRect(hdc, 0, 0, 50, 50);
+#if 0 /* XP returns COMPLEXREGION although dump_region reports only 1 rect */
+ ok(ret == SIMPLEREGION, "IntersectClipRect returned %d instead of SIMPLEREGION\n", ret);
+#endif
+ if (ret != SIMPLEREGION)
+ {
+ trace("Windows BUG: IntersectClipRect returned %d instead of SIMPLEREGION\n", ret);
+ /* let's make sure that it's a simple region */
+ ret = GetClipRgn(hdc, hrgn);
+ ok(ret == 1, "GetClipRgn returned %d instead of 1\n", ret);
+ dump_region(hrgn);
+ }
+
+ ret = GetClipBox(hdc, &rc_clip);
+ ok(ret == SIMPLEREGION, "GetClipBox returned %d instead of SIMPLEREGION\n", ret);
+ SetRect(&rc, 0, 0, 50, 50);
+ ok(EqualRect(&rc, &rc_clip), "rects are not equal\n");
+
+ ret = RestoreDC(hdc, 1);
+ ok(ret, "ret = %d\n", ret);
+
+ ret = GetClipBox(hdc, &rc_clip);
+ ok(ret == SIMPLEREGION, "GetClipBox returned %d instead of SIMPLEREGION\n", ret);
+ SetRect(&rc, 0, 0, 100, 100);
+ ok(EqualRect(&rc, &rc_clip), "rects are not equal\n");
+
+ DeleteObject(hrgn);
+ ReleaseDC(hwnd, hdc);
+ DestroyWindow(hwnd);
+}
+
+static void test_savedc(void)
+{
+ HDC hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
+ int ret;
+
+ ok(hdc != NULL, "CreateDC rets %p\n", hdc);
+
+ ret = SaveDC(hdc);
+ ok(ret == 1, "ret = %d\n", ret);
+ ret = SaveDC(hdc);
+ ok(ret == 2, "ret = %d\n", ret);
+ ret = SaveDC(hdc);
+ ok(ret == 3, "ret = %d\n", ret);
+ ret = RestoreDC(hdc, -1);
+ ok(ret, "ret = %d\n", ret);
+ ret = SaveDC(hdc);
+ ok(ret == 3, "ret = %d\n", ret);
+ ret = RestoreDC(hdc, 1);
+ ok(ret, "ret = %d\n", ret);
+ ret = SaveDC(hdc);
+ ok(ret == 1, "ret = %d\n", ret);
+ ret = SaveDC(hdc);
+ ok(ret == 2, "ret = %d\n", ret);
+ ret = SaveDC(hdc);
+ ok(ret == 3, "ret = %d\n", ret);
+ ret = RestoreDC(hdc, -2);
+ ok(ret, "ret = %d\n", ret);
+ ret = SaveDC(hdc);
+ ok(ret == 2, "ret = %d\n", ret);
+ ret = RestoreDC(hdc, -2);
+ ok(ret, "ret = %d\n", ret);
+ ret = SaveDC(hdc);
+ ok(ret == 1, "ret = %d\n", ret);
+ ret = SaveDC(hdc);
+ ok(ret == 2, "ret = %d\n", ret);
+ ret = RestoreDC(hdc, -4);
+ ok(!ret, "ret = %d\n", ret);
+ ret = RestoreDC(hdc, 3);
+ ok(!ret, "ret = %d\n", ret);
+
+ /* Under win98 the following two succeed and both clear the save stack
+ ret = RestoreDC(hdc, -3);
+ ok(!ret, "ret = %d\n", ret);
+ ret = RestoreDC(hdc, 0);
+ ok(!ret, "ret = %d\n", ret);
+ */
+
+ ret = RestoreDC(hdc, 1);
+ ok(ret, "ret = %d\n", ret);
+
+ DeleteDC(hdc);
+}
+
+START_TEST(dc)
+{
+ test_savedc();
+ test_savedc_2();
+}
diff --git a/reactos/regtests/winetests/gdi32/font.c b/reactos/regtests/winetests/gdi32/font.c
new file mode 100644
index 00000000000..699d9b28e08
--- /dev/null
+++ b/reactos/regtests/winetests/gdi32/font.c
@@ -0,0 +1,441 @@
+/*
+ * Unit test suite for fonts
+ *
+ * Copyright 2002 Mike McCormack
+ * Copyright 2004 Dmitry Timoshkov
+ *
+ * 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
+#include
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+
+#include "wine/test.h"
+
+static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
+{
+ LOGFONTA getobj_lf;
+ int ret, minlen = 0;
+
+ if (!hfont)
+ return;
+
+ ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
+ /* NT4 tries to be clever and only returns the minimum length */
+ while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
+ minlen++;
+ minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
+ ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
+ ok(!memcmp(&lf, &lf, FIELD_OFFSET(LOGFONTA, lfFaceName)), "%s: fonts don't match\n", test);
+ ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName),
+ "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
+}
+
+static HFONT create_font(const char* test, const LOGFONTA* lf)
+{
+ HFONT hfont = CreateFontIndirectA(lf);
+ ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
+ if (hfont)
+ check_font(test, lf, hfont);
+ return hfont;
+}
+
+static void test_logfont(void)
+{
+ LOGFONTA lf;
+ HFONT hfont;
+
+ memset(&lf, 0, sizeof lf);
+
+ lf.lfCharSet = ANSI_CHARSET;
+ lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ lf.lfWeight = FW_DONTCARE;
+ lf.lfHeight = 16;
+ lf.lfWidth = 16;
+ lf.lfQuality = DEFAULT_QUALITY;
+
+ lstrcpyA(lf.lfFaceName, "Arial");
+ hfont = create_font("Arial", &lf);
+ DeleteObject(hfont);
+
+ memset(&lf, 'A', sizeof(lf));
+ hfont = CreateFontIndirectA(&lf);
+ ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
+
+ lf.lfFaceName[LF_FACESIZE - 1] = 0;
+ check_font("AAA...", &lf, hfont);
+ DeleteObject(hfont);
+}
+
+static INT CALLBACK font_enum_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
+{
+ if (type & RASTER_FONTTYPE)
+ {
+ LOGFONT *lf = (LOGFONT *)lParam;
+ *lf = *elf;
+ return 0; /* stop enumeration */
+ }
+
+ return 1; /* continue enumeration */
+}
+
+static void test_font_metrics(HDC hdc, HFONT hfont, const char *test_str,
+ INT test_str_len, const TEXTMETRICA *tm_orig,
+ const SIZE *size_orig, INT width_orig,
+ INT scale_x, INT scale_y)
+{
+ HFONT old_hfont;
+ TEXTMETRICA tm;
+ SIZE size;
+ INT width;
+
+ if (!hfont)
+ return;
+
+ old_hfont = SelectObject(hdc, hfont);
+
+ GetTextMetricsA(hdc, &tm);
+
+ ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "%ld != %ld\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
+ ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "%ld != %ld\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
+ ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "%ld != %ld\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
+ ok(tm.tmAveCharWidth == tm_orig->tmAveCharWidth * scale_x, "%ld != %ld\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
+
+ GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
+
+ ok(size.cx == size_orig->cx * scale_x, "%ld != %ld\n", size.cx, size_orig->cx * scale_x);
+ ok(size.cy == size_orig->cy * scale_y, "%ld != %ld\n", size.cy, size_orig->cy * scale_y);
+
+ GetCharWidthA(hdc, 'A', 'A', &width);
+
+ ok(width == width_orig * scale_x, "%d != %d\n", width, width_orig * scale_x);
+
+ SelectObject(hdc, old_hfont);
+}
+
+/* see whether GDI scales bitmap font metrics */
+static void test_bitmap_font(void)
+{
+ static const char test_str[11] = "Test String";
+ HDC hdc;
+ LOGFONTA bitmap_lf;
+ HFONT hfont, old_hfont;
+ TEXTMETRICA tm_orig;
+ SIZE size_orig;
+ INT ret, i, width_orig, height_orig;
+
+ hdc = GetDC(0);
+
+ /* "System" has only 1 pixel size defined, otherwise the test breaks */
+ ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
+ if (ret)
+ {
+ ReleaseDC(0, hdc);
+ trace("no bitmap fonts were found, skipping the test\n");
+ return;
+ }
+
+ trace("found bitmap font %s, height %ld\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
+
+ height_orig = bitmap_lf.lfHeight;
+ hfont = create_font("bitmap", &bitmap_lf);
+
+ old_hfont = SelectObject(hdc, hfont);
+ ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
+ ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
+ ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
+ SelectObject(hdc, old_hfont);
+ DeleteObject(hfont);
+
+ /* test fractional scaling */
+ for (i = 1; i < height_orig; i++)
+ {
+ hfont = create_font("fractional", &bitmap_lf);
+ test_font_metrics(hdc, hfont, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
+ DeleteObject(hfont);
+ }
+
+ /* test integer scaling 3x2 */
+ bitmap_lf.lfHeight = height_orig * 2;
+ bitmap_lf.lfWidth *= 3;
+ hfont = create_font("3x2", &bitmap_lf);
+todo_wine
+{
+ test_font_metrics(hdc, hfont, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
+}
+ DeleteObject(hfont);
+
+ /* test integer scaling 3x3 */
+ bitmap_lf.lfHeight = height_orig * 3;
+ bitmap_lf.lfWidth = 0;
+ hfont = create_font("3x3", &bitmap_lf);
+
+todo_wine
+{
+ test_font_metrics(hdc, hfont, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
+}
+ DeleteObject(hfont);
+
+ ReleaseDC(0, hdc);
+}
+
+static INT CALLBACK find_font_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
+{
+ LOGFONT *lf = (LOGFONT *)lParam;
+
+ if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
+ {
+ *lf = *elf;
+ return 0; /* stop enumeration */
+ }
+ return 1; /* continue enumeration */
+}
+
+static void test_bitmap_font_metrics(void)
+{
+ static const struct font_data
+ {
+ const char face_name[LF_FACESIZE];
+ int weight, height, ascent, descent, int_leading, ext_leading;
+ int ave_char_width, max_char_width;
+ } fd[] =
+ {
+ { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11 },
+ { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14 },
+ { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16 },
+ { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20 },
+ { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25 },
+ { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32 },
+ { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8 },
+ { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9 },
+ { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12 },
+ { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16 },
+ { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19 },
+ { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23 },
+ { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27 },
+ { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34 },
+ { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8 },
+ { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9 },
+ { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12 },
+ { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15 },
+ { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2 },
+ { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4 },
+ { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13 },
+ { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7 },
+ { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8 },
+ { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9 }
+ /* FIXME: add "Fixedsys", "Terminal" */
+ };
+ HDC hdc;
+ LOGFONT lf;
+ HFONT hfont, old_hfont;
+ TEXTMETRIC tm;
+ INT ret, i;
+
+ hdc = CreateCompatibleDC(0);
+ assert(hdc);
+
+ for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
+ {
+ memset(&lf, 0, sizeof(lf));
+
+ lf.lfHeight = fd[i].height;
+ strcpy(lf.lfFaceName, fd[i].face_name);
+ ret = EnumFontFamilies(hdc, fd[i].face_name, find_font_proc, (LPARAM)&lf);
+ if (ret)
+ {
+ trace("font %s height %d not found\n", fd[i].face_name, fd[i].height);
+ continue;
+ }
+
+ trace("found font %s, height %ld\n", lf.lfFaceName, lf.lfHeight);
+
+ hfont = create_font(lf.lfFaceName, &lf);
+ old_hfont = SelectObject(hdc, hfont);
+ ok(GetTextMetrics(hdc, &tm), "GetTextMetrics error %ld\n", GetLastError());
+
+ ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %ld != %d\n", fd[i].face_name, fd[i].height, tm.tmWeight, fd[i].weight);
+ ok(tm.tmHeight == fd[i].height, "%s(%d): tm.tmHeight %ld != %d\n", fd[i].face_name, fd[i].height, tm.tmHeight, fd[i].height);
+ ok(tm.tmAscent == fd[i].ascent, "%s(%d): tm.tmAscent %ld != %d\n", fd[i].face_name, fd[i].height, tm.tmAscent, fd[i].ascent);
+ ok(tm.tmDescent == fd[i].descent, "%s(%d): tm.tmDescent %ld != %d\n", fd[i].face_name, fd[i].height, tm.tmDescent, fd[i].descent);
+ ok(tm.tmInternalLeading == fd[i].int_leading, "%s(%d): tm.tmInternalLeading %ld != %d\n", fd[i].face_name, fd[i].height, tm.tmInternalLeading, fd[i].int_leading);
+ ok(tm.tmExternalLeading == fd[i].ext_leading, "%s(%d): tm.tmExternalLeading %ld != %d\n", fd[i].face_name, fd[i].height, tm.tmExternalLeading, fd[i].ext_leading);
+ ok(tm.tmAveCharWidth == fd[i].ave_char_width, "%s(%d): tm.tmAveCharWidth %ld != %d\n", fd[i].face_name, fd[i].height, tm.tmAveCharWidth, fd[i].ave_char_width);
+ ok(tm.tmMaxCharWidth == fd[i].max_char_width, "%s(%d): tm.tmMaxCharWidth %ld != %d\n", fd[i].face_name, fd[i].height, tm.tmMaxCharWidth, fd[i].max_char_width);
+
+ SelectObject(hdc, old_hfont);
+ DeleteObject(hfont);
+ }
+
+ DeleteDC(hdc);
+}
+
+static void test_GdiGetCharDimensions(void)
+{
+ HDC hdc;
+ TEXTMETRICW tm;
+ LONG ret;
+ SIZE size;
+ LONG avgwidth, height;
+ static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+ typedef LONG (WINAPI *fnGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height);
+ fnGdiGetCharDimensions GdiGetCharDimensions = (fnGdiGetCharDimensions)GetProcAddress(LoadLibrary("gdi32"), "GdiGetCharDimensions");
+ if (!GdiGetCharDimensions) return;
+
+ hdc = CreateCompatibleDC(NULL);
+
+ GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
+ avgwidth = ((size.cx / 26) + 1) / 2;
+
+ ret = GdiGetCharDimensions(hdc, &tm, &height);
+ ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %ld instead of %ld\n", avgwidth, ret);
+ ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %ld instead of %ld\n", tm.tmHeight, height);
+
+ ret = GdiGetCharDimensions(hdc, &tm, NULL);
+ ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %ld instead of %ld\n", avgwidth, ret);
+
+ ret = GdiGetCharDimensions(hdc, NULL, NULL);
+ ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %ld instead of %ld\n", avgwidth, ret);
+
+ height = 0;
+ ret = GdiGetCharDimensions(hdc, NULL, &height);
+ ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %ld instead of %ld\n", avgwidth, ret);
+ ok(height == size.cy, "GdiGetCharDimensions should have set height to %ld instead of %ld\n", size.cy, height);
+
+ DeleteDC(hdc);
+}
+
+static void test_GetCharABCWidthsW(void)
+{
+ BOOL ret;
+ ABC abc[1];
+ typedef BOOL (WINAPI *fnGetCharABCWidthsW)(HDC hdc, UINT first, UINT last, LPABC abc);
+ fnGetCharABCWidthsW GetCharABCWidthsW = (fnGetCharABCWidthsW)GetProcAddress(LoadLibrary("gdi32"), "GetCharABCWidthsW");
+ if (!GetCharABCWidthsW) return;
+
+ ret = GetCharABCWidthsW(NULL, 'a', 'a', abc);
+ ok(!ret, "GetCharABCWidthsW should have returned FALSE\n");
+}
+
+static void test_text_extents(void)
+{
+ static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
+ LPINT extents;
+ INT i, len, fit1, fit2;
+ LOGFONTA lf;
+ TEXTMETRICA tm;
+ HDC hdc;
+ HFONT hfont;
+ SIZE sz;
+ SIZE sz1, sz2;
+
+ memset(&lf, 0, sizeof(lf));
+ strcpy(lf.lfFaceName, "Arial");
+ lf.lfHeight = 20;
+
+ hfont = CreateFontIndirectA(&lf);
+ hdc = GetDC(0);
+ hfont = SelectObject(hdc, hfont);
+ GetTextMetricsA(hdc, &tm);
+ GetTextExtentPointA(hdc, "o", 1, &sz);
+ ok(sz.cy == tm.tmHeight, "cy %ld tmHeight %ld\n", sz.cy, tm.tmHeight);
+
+ len = lstrlenW(wt);
+ extents = HeapAlloc(GetProcessHeap(), 0, len * sizeof extents[0]);
+ memset(extents, 0, len * sizeof extents[0]);
+ extents[0] = 1; /* So that the increasing sequence test will fail
+ if the extents array is untouched. */
+ GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
+ GetTextExtentPointW(hdc, wt, len, &sz2);
+ ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
+ "results from GetTextExtentExPointW and GetTextExtentPointW differ\n");
+ for (i = 1; i < len; ++i)
+ ok(extents[i-1] <= extents[i],
+ "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
+ i);
+ ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
+ ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
+ ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
+ GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
+ ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
+ ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
+ GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
+ ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
+ GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
+ ok(extents[0] == extents[2] && extents[1] == extents[3],
+ "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
+ GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
+ ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
+ "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
+ HeapFree(GetProcessHeap(), 0, extents);
+
+ SelectObject(hdc, hfont);
+ DeleteObject(hfont);
+ ReleaseDC(NULL, hdc);
+}
+
+static void test_GetGlyphIndices()
+{
+ HDC hdc;
+ HFONT hfont;
+ DWORD charcount;
+ LOGFONTA lf;
+ DWORD flags = 0;
+ WCHAR testtext[] = {'T','e','s','t',0xffff,0};
+ WORD glyphs[(sizeof(testtext)/2)-1];
+ TEXTMETRIC textm;
+
+ typedef BOOL (WINAPI *fnGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
+ fnGetGlyphIndicesW GetGlyphIndicesW = (fnGetGlyphIndicesW)GetProcAddress(LoadLibrary("gdi32"),
+ "GetGlyphIndicesW");
+ if (!GetGlyphIndicesW) {
+ trace("GetGlyphIndices not available on platform\n");
+ return;
+ }
+
+ memset(&lf, 0, sizeof(lf));
+ strcpy(lf.lfFaceName, "Symbol");
+ lf.lfHeight = 20;
+
+ hfont = CreateFontIndirectA(&lf);
+ hdc = GetDC(0);
+
+ ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
+ flags |= GGI_MARK_NONEXISTING_GLYPHS;
+ charcount = GetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
+ ok(charcount == 5, "GetGlyphIndices count of glyphs should = 5 not %ld\n", charcount);
+ ok(glyphs[4] == 0x001f, "GetGlyphIndices should have returned a nonexistent char not %04x\n", glyphs[4]);
+ flags = 0;
+ charcount = GetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
+ ok(charcount == 5, "GetGlyphIndices count of glyphs should = 5 not %ld\n", charcount);
+ ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndices should have returned a %04x not %04x\n",
+ textm.tmDefaultChar, glyphs[4]);
+}
+
+START_TEST(font)
+{
+ test_logfont();
+ test_bitmap_font();
+ test_bitmap_font_metrics();
+ test_GdiGetCharDimensions();
+ test_GetCharABCWidthsW();
+ test_text_extents();
+ test_GetGlyphIndices();
+}
diff --git a/reactos/regtests/winetests/gdi32/gdi32.rbuild b/reactos/regtests/winetests/gdi32/gdi32.rbuild
index d9d1e40945f..e34147f9d60 100644
--- a/reactos/regtests/winetests/gdi32/gdi32.rbuild
+++ b/reactos/regtests/winetests/gdi32/gdi32.rbuild
@@ -8,7 +8,12 @@
advapi32
bitmap.c
brush.c
+ clipping.c
+ dc.c
gdiobj.c
+ font.c
+ mapping.c
metafile.c
+ palette.c
testlist.c
diff --git a/reactos/regtests/winetests/gdi32/gdiobj.c b/reactos/regtests/winetests/gdi32/gdiobj.c
index deed86fc3b1..21310b11685 100755
--- a/reactos/regtests/winetests/gdi32/gdiobj.c
+++ b/reactos/regtests/winetests/gdi32/gdiobj.c
@@ -16,10 +16,11 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include
+#include
#include "windef.h"
#include "winbase.h"
@@ -28,175 +29,6 @@
#include "wine/test.h"
-
-static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
-{
- LOGFONTA getobj_lf;
- int ret, minlen = 0;
-
- if (!hfont)
- return;
-
- ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
- /* NT4 tries to be clever and only returns the minimum length */
- while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
- minlen++;
- minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
- ok(ret == sizeof(LOGFONTA) || ret == minlen,
- "%s: GetObject returned %d expected %d or %d\n", test, ret, sizeof(LOGFONTA), minlen);
- ok(!memcmp(&lf, &lf, FIELD_OFFSET(LOGFONTA, lfFaceName)), "%s: fonts don't match\n", test);
- ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName),
- "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
-}
-
-static HFONT create_font(const char* test, const LOGFONTA* lf)
-{
- HFONT hfont = CreateFontIndirectA(lf);
- ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
- if (hfont)
- check_font(test, lf, hfont);
- return hfont;
-}
-
-static void test_logfont(void)
-{
- LOGFONTA lf;
- HFONT hfont;
-
- memset(&lf, 0, sizeof lf);
-
- lf.lfCharSet = ANSI_CHARSET;
- lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
- lf.lfWeight = FW_DONTCARE;
- lf.lfHeight = 16;
- lf.lfWidth = 16;
- lf.lfQuality = DEFAULT_QUALITY;
-
- lstrcpyA(lf.lfFaceName, "Arial");
- hfont = create_font("Arial", &lf);
- DeleteObject(hfont);
-
- memset(&lf, 'A', sizeof(lf));
- hfont = CreateFontIndirectA(&lf);
- ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
-
- lf.lfFaceName[LF_FACESIZE - 1] = 0;
- check_font("AAA...", &lf, hfont);
- DeleteObject(hfont);
-}
-
-static INT CALLBACK font_enum_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
-{
- if (type & RASTER_FONTTYPE)
- {
- LOGFONT *lf = (LOGFONT *)lParam;
- *lf = *elf;
- return 0; /* stop enumeration */
- }
-
- return 1; /* continue enumeration */
-}
-
-static void test_font_metrics(HDC hdc, HFONT hfont, const char *test_str,
- INT test_str_len, const TEXTMETRICA *tm_orig,
- const SIZE *size_orig, INT width_orig,
- INT scale_x, INT scale_y)
-{
- HFONT old_hfont;
- TEXTMETRICA tm;
- SIZE size;
- INT width;
-
- if (!hfont)
- return;
-
- old_hfont = SelectObject(hdc, hfont);
-
- GetTextMetricsA(hdc, &tm);
-
- ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "%ld != %ld\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
- ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "%ld != %ld\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
- ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "%ld != %ld\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
- ok(tm.tmAveCharWidth == tm_orig->tmAveCharWidth * scale_x, "%ld != %ld\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
-
- GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
-
- ok(size.cx == size_orig->cx * scale_x, "%ld != %ld\n", size.cx, size_orig->cx * scale_x);
- ok(size.cy == size_orig->cy * scale_y, "%ld != %ld\n", size.cy, size_orig->cy * scale_y);
-
- GetCharWidthA(hdc, 'A', 'A', &width);
-
- ok(width == width_orig * scale_x, "%d != %d\n", width, width_orig * scale_x);
-
- SelectObject(hdc, old_hfont);
-}
-
-/* see whether GDI scales bitmap font metrics */
-static void test_bitmap_font(void)
-{
- static const char test_str[11] = "Test String";
- HDC hdc;
- LOGFONTA bitmap_lf;
- HFONT hfont, old_hfont;
- TEXTMETRICA tm_orig;
- SIZE size_orig;
- INT ret, i, width_orig, height_orig;
-
- hdc = GetDC(0);
-
- /* "System" has only 1 pixel size defined, otherwise the test breaks */
- ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
- if (ret)
- {
- ReleaseDC(0, hdc);
- trace("no bitmap fonts were found, skipping the test\n");
- return;
- }
-
- trace("found bitmap font %s, height %ld\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
-
- height_orig = bitmap_lf.lfHeight;
- hfont = create_font("bitmap", &bitmap_lf);
-
- old_hfont = SelectObject(hdc, hfont);
- ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
- ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
- ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
- SelectObject(hdc, old_hfont);
- DeleteObject(hfont);
-
- /* test fractional scaling */
- for (i = 1; i < height_orig; i++)
- {
- hfont = create_font("fractional", &bitmap_lf);
- test_font_metrics(hdc, hfont, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
- DeleteObject(hfont);
- }
-
- /* test integer scaling 3x2 */
- bitmap_lf.lfHeight = height_orig * 2;
- bitmap_lf.lfWidth *= 3;
- hfont = create_font("3x2", &bitmap_lf);
-todo_wine
-{
- test_font_metrics(hdc, hfont, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
-}
- DeleteObject(hfont);
-
- /* test integer scaling 3x3 */
- bitmap_lf.lfHeight = height_orig * 3;
- bitmap_lf.lfWidth = 0;
- hfont = create_font("3x3", &bitmap_lf);
-
-todo_wine
-{
- test_font_metrics(hdc, hfont, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
-}
- DeleteObject(hfont);
-
- ReleaseDC(0, hdc);
-}
-
static void test_gdi_objects(void)
{
BYTE buff[256];
@@ -266,70 +98,177 @@ static void test_gdi_objects(void)
ReleaseDC(NULL, hdc);
}
-static void test_GdiGetCharDimensions(void)
+struct hgdiobj_event
{
HDC hdc;
- TEXTMETRICW tm;
- LONG ret;
- SIZE size;
- LONG avgwidth, height;
- static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
- typedef LONG (WINAPI *fnGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height);
- fnGdiGetCharDimensions GdiGetCharDimensions = (fnGdiGetCharDimensions)GetProcAddress(LoadLibrary("gdi32"), "GdiGetCharDimensions");
- if (!GdiGetCharDimensions) return;
+ HGDIOBJ hgdiobj1;
+ HGDIOBJ hgdiobj2;
+ HANDLE stop_event;
+ HANDLE ready_event;
+};
- hdc = CreateCompatibleDC(NULL);
+static DWORD WINAPI thread_proc(void *param)
+{
+ LOGPEN lp;
+ struct hgdiobj_event *hgdiobj_event = (struct hgdiobj_event *)param;
- GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
- avgwidth = ((size.cx / 26) + 1) / 2;
+ hgdiobj_event->hdc = CreateDC("display", NULL, NULL, NULL);
+ ok(hgdiobj_event->hdc != NULL, "CreateDC error %ld\n", GetLastError());
- ret = GdiGetCharDimensions(hdc, &tm, &height);
- ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %ld instead of %ld\n", avgwidth, ret);
- ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %ld instead of %ld\n", tm.tmHeight, height);
+ hgdiobj_event->hgdiobj1 = CreatePen(PS_DASHDOTDOT, 17, RGB(1, 2, 3));
+ ok(hgdiobj_event->hgdiobj1 != 0, "Failed to create pen\n");
- ret = GdiGetCharDimensions(hdc, &tm, NULL);
- ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %ld instead of %ld\n", avgwidth, ret);
+ hgdiobj_event->hgdiobj2 = CreateRectRgn(0, 1, 12, 17);
+ ok(hgdiobj_event->hgdiobj2 != 0, "Failed to create pen\n");
- ret = GdiGetCharDimensions(hdc, NULL, NULL);
- ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %ld instead of %ld\n", avgwidth, ret);
+ SetEvent(hgdiobj_event->ready_event);
+ ok(WaitForSingleObject(hgdiobj_event->stop_event, INFINITE) == WAIT_OBJECT_0,
+ "WaitForSingleObject error %ld\n", GetLastError());
- height = 0;
- ret = GdiGetCharDimensions(hdc, NULL, &height);
- ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %ld instead of %ld\n", avgwidth, ret);
- ok(height == size.cy, "GdiGetCharDimensions should have set height to %ld instead of %ld\n", size.cy, height);
+ ok(!GetObject(hgdiobj_event->hgdiobj1, sizeof(lp), &lp), "GetObject should fail\n");
+
+ ok(!GetDeviceCaps(hgdiobj_event->hdc, TECHNOLOGY), "GetDeviceCaps(TECHNOLOGY) should fail\n");
+
+ return 0;
+}
+
+static void test_thread_objects(void)
+{
+ LOGPEN lp;
+ DWORD tid, type;
+ HANDLE hthread;
+ struct hgdiobj_event hgdiobj_event;
+ INT ret;
+
+ hgdiobj_event.stop_event = CreateEvent(NULL, 0, 0, NULL);
+ ok(hgdiobj_event.stop_event != NULL, "CreateEvent error %ld\n", GetLastError());
+ hgdiobj_event.ready_event = CreateEvent(NULL, 0, 0, NULL);
+ ok(hgdiobj_event.ready_event != NULL, "CreateEvent error %ld\n", GetLastError());
+
+ hthread = CreateThread(NULL, 0, thread_proc, &hgdiobj_event, 0, &tid);
+ ok(hthread != NULL, "CreateThread error %ld\n", GetLastError());
+
+ ok(WaitForSingleObject(hgdiobj_event.ready_event, INFINITE) == WAIT_OBJECT_0,
+ "WaitForSingleObject error %ld\n", GetLastError());
+
+ ok(GetObject(hgdiobj_event.hgdiobj1, sizeof(lp), &lp) == sizeof(lp),
+ "GetObject error %ld\n", GetLastError());
+ ok(lp.lopnStyle == PS_DASHDOTDOT, "wrong pen style %d\n", lp.lopnStyle);
+ ok(lp.lopnWidth.x == 17, "wrong pen width.y %ld\n", lp.lopnWidth.x);
+ ok(lp.lopnWidth.y == 0, "wrong pen width.y %ld\n", lp.lopnWidth.y);
+ ok(lp.lopnColor == RGB(1, 2, 3), "wrong pen width.y %08lx\n", lp.lopnColor);
+
+ ret = GetDeviceCaps(hgdiobj_event.hdc, TECHNOLOGY);
+ ok(ret == DT_RASDISPLAY, "GetDeviceCaps(TECHNOLOGY) should return DT_RASDISPLAY not %d\n", ret);
+
+ ok(DeleteObject(hgdiobj_event.hgdiobj1), "DeleteObject error %ld\n", GetLastError());
+ ok(DeleteDC(hgdiobj_event.hdc), "DeleteDC error %ld\n", GetLastError());
+
+ type = GetObjectType(hgdiobj_event.hgdiobj2);
+ ok(type == OBJ_REGION, "GetObjectType returned %lu\n", type);
+
+ SetEvent(hgdiobj_event.stop_event);
+ ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0,
+ "WaitForSingleObject error %ld\n", GetLastError());
+ CloseHandle(hthread);
+
+ type = GetObjectType(hgdiobj_event.hgdiobj2);
+ ok(type == OBJ_REGION, "GetObjectType returned %lu\n", type);
+ ok(DeleteObject(hgdiobj_event.hgdiobj2), "DeleteObject error %ld\n", GetLastError());
+
+ CloseHandle(hgdiobj_event.stop_event);
+ CloseHandle(hgdiobj_event.ready_event);
+}
+
+static void test_GetCurrentObject(void)
+{
+ DWORD type;
+ HPEN hpen;
+ HBRUSH hbrush;
+ HPALETTE hpal;
+ HFONT hfont;
+ HBITMAP hbmp;
+ HRGN hrgn;
+ HDC hdc;
+ HCOLORSPACE hcs;
+ HGDIOBJ hobj;
+ LOGBRUSH lb;
+ LOGCOLORSPACEA lcs;
+
+ hdc = CreateCompatibleDC(0);
+ assert(hdc != 0);
+
+ type = GetObjectType(hdc);
+ ok(type == OBJ_MEMDC, "GetObjectType returned %lu\n", type);
+
+ hpen = CreatePen(PS_SOLID, 10, RGB(10, 20, 30));
+ assert(hpen != 0);
+ SelectObject(hdc, hpen);
+ hobj = GetCurrentObject(hdc, OBJ_PEN);
+ ok(hobj == hpen, "OBJ_PEN is wrong: %p\n", hobj);
+ hobj = GetCurrentObject(hdc, OBJ_EXTPEN);
+ ok(hobj == hpen, "OBJ_EXTPEN is wrong: %p\n", hobj);
+
+ hbrush = CreateSolidBrush(RGB(10, 20, 30));
+ assert(hbrush != 0);
+ SelectObject(hdc, hbrush);
+ hobj = GetCurrentObject(hdc, OBJ_BRUSH);
+ ok(hobj == hbrush, "OBJ_BRUSH is wrong: %p\n", hobj);
+
+ hpal = CreateHalftonePalette(hdc);
+ assert(hpal != 0);
+ SelectPalette(hdc, hpal, FALSE);
+ hobj = GetCurrentObject(hdc, OBJ_PAL);
+ ok(hobj == hpal, "OBJ_PAL is wrong: %p\n", hobj);
+
+ hfont = CreateFontA(10, 5, 0, 0, FW_DONTCARE, 0, 0, 0, ANSI_CHARSET,
+ OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
+ DEFAULT_PITCH, "MS Sans Serif");
+ assert(hfont != 0);
+ SelectObject(hdc, hfont);
+ hobj = GetCurrentObject(hdc, OBJ_FONT);
+ ok(hobj == hfont, "OBJ_FONT is wrong: %p\n", hobj);
+
+ hbmp = CreateBitmap(100, 100, 1, 1, NULL);
+ assert(hbmp != 0);
+ SelectObject(hdc, hbmp);
+ hobj = GetCurrentObject(hdc, OBJ_BITMAP);
+ ok(hobj == hbmp, "OBJ_BITMAP is wrong: %p\n", hobj);
+
+ assert(GetObject(hbrush, sizeof(lb), &lb) == sizeof(lb));
+ hpen = ExtCreatePen(PS_GEOMETRIC | PS_SOLID | PS_ENDCAP_SQUARE | PS_JOIN_BEVEL,
+ 10, &lb, 0, NULL);
+ assert(hpen != 0);
+ SelectObject(hdc, hpen);
+ hobj = GetCurrentObject(hdc, OBJ_PEN);
+ ok(hobj == hpen, "OBJ_PEN is wrong: %p\n", hobj);
+ hobj = GetCurrentObject(hdc, OBJ_EXTPEN);
+ ok(hobj == hpen, "OBJ_EXTPEN is wrong: %p\n", hobj);
+
+ hcs = GetColorSpace(hdc);
+ if (hcs)
+ {
+ trace("current color space is not NULL\n");
+ ok(GetLogColorSpaceA(hcs, &lcs, sizeof(lcs)), "GetLogColorSpace failed\n");
+ hcs = CreateColorSpaceA(&lcs);
+ ok(hcs != 0, "CreateColorSpace failed\n");
+ SelectObject(hdc, hcs);
+ hobj = GetCurrentObject(hdc, OBJ_COLORSPACE);
+ ok(hobj == hcs, "OBJ_COLORSPACE is wrong: %p\n", hobj);
+ }
+
+ hrgn = CreateRectRgn(1, 1, 100, 100);
+ assert(hrgn != 0);
+ SelectObject(hdc, hrgn);
+ hobj = GetCurrentObject(hdc, OBJ_REGION);
+ ok(!hobj, "OBJ_REGION is wrong: %p\n", hobj);
DeleteDC(hdc);
}
-static void test_text_extents(void)
-{
- LOGFONTA lf;
- TEXTMETRICA tm;
- HDC hdc;
- HFONT hfont;
- SIZE sz;
-
- memset(&lf, 0, sizeof(lf));
- strcpy(lf.lfFaceName, "Arial");
- lf.lfHeight = 20;
-
- hfont = CreateFontIndirectA(&lf);
- hdc = GetDC(0);
- hfont = SelectObject(hdc, hfont);
- GetTextMetricsA(hdc, &tm);
- GetTextExtentPointA(hdc, "o", 1, &sz);
- ok(sz.cy == tm.tmHeight, "cy %ld tmHeight %ld\n", sz.cy, tm.tmHeight);
-
- SelectObject(hdc, hfont);
- DeleteObject(hfont);
- ReleaseDC(NULL, hdc);
-}
-
START_TEST(gdiobj)
{
- test_logfont();
- test_bitmap_font();
test_gdi_objects();
- test_GdiGetCharDimensions();
- test_text_extents();
+ test_thread_objects();
+ test_GetCurrentObject();
}
diff --git a/reactos/regtests/winetests/gdi32/mapping.c b/reactos/regtests/winetests/gdi32/mapping.c
new file mode 100644
index 00000000000..2baeb2d8004
--- /dev/null
+++ b/reactos/regtests/winetests/gdi32/mapping.c
@@ -0,0 +1,160 @@
+/*
+ * Unit tests for mapping functions
+ *
+ * Copyright (c) 2005 Huw Davies
+ *
+ * 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
+#include
+#include
+
+#include "wine/test.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "winerror.h"
+
+
+void test_modify_world_transform(void)
+{
+ HDC hdc = GetDC(0);
+ int ret;
+
+ ret = SetGraphicsMode(hdc, GM_ADVANCED);
+ if(!ret) /* running in win9x so quit */
+ {
+ ReleaseDC(0, hdc);
+ return;
+ }
+
+ ret = ModifyWorldTransform(hdc, NULL, MWT_IDENTITY);
+ ok(ret, "ret = %d\n", ret);
+
+ ret = ModifyWorldTransform(hdc, NULL, MWT_LEFTMULTIPLY);
+ ok(!ret, "ret = %d\n", ret);
+
+ ret = ModifyWorldTransform(hdc, NULL, MWT_RIGHTMULTIPLY);
+ ok(!ret, "ret = %d\n", ret);
+
+ ReleaseDC(0, hdc);
+}
+
+void test_SetWindowExt(HDC hdc, LONG cx, LONG cy, LONG expected_vp_cx, LONG expected_vp_cy)
+{
+ SIZE windowExt, viewportExt;
+ POINT windowOrg, windowOrgAfter, viewportOrg, viewportOrgAfter;
+
+ GetWindowOrgEx(hdc, &windowOrg);
+ GetViewportOrgEx(hdc, &viewportOrg);
+
+ SetWindowExtEx(hdc, cx, cy, NULL);
+ GetWindowExtEx(hdc, &windowExt);
+ ok(windowExt.cx == cx && windowExt.cy == cy,
+ "Window extension: Expected %ldx%ld, got %ldx%ld\n",
+ cx, cy, windowExt.cx, windowExt.cy);
+
+ GetViewportExtEx(hdc, &viewportExt);
+ ok(viewportExt.cx == expected_vp_cx && viewportExt.cy == expected_vp_cy,
+ "Viewport extents have not been properly adjusted: Expected %ldx%ld, got %ldx%ld\n",
+ expected_vp_cx, expected_vp_cy, viewportExt.cx, viewportExt.cy);
+
+ GetWindowOrgEx(hdc, &windowOrgAfter);
+ ok(windowOrg.x == windowOrgAfter.x && windowOrg.y == windowOrgAfter.y,
+ "Window origin changed from (%ld,%ld) to (%ld,%ld)\n",
+ windowOrg.x, windowOrg.y, windowOrgAfter.x, windowOrgAfter.y);
+
+ GetViewportOrgEx(hdc, &viewportOrgAfter);
+ ok(viewportOrg.x == viewportOrgAfter.x && viewportOrg.y == viewportOrgAfter.y,
+ "Viewport origin changed from (%ld,%ld) to (%ld,%ld)\n",
+ viewportOrg.x, viewportOrg.y, viewportOrgAfter.x, viewportOrgAfter.y);
+}
+
+void test_SetViewportExt(HDC hdc, LONG cx, LONG cy, LONG expected_vp_cx, LONG expected_vp_cy)
+{
+ SIZE windowExt, windowExtAfter, viewportExt;
+ POINT windowOrg, windowOrgAfter, viewportOrg, viewportOrgAfter;
+
+ GetWindowOrgEx(hdc, &windowOrg);
+ GetViewportOrgEx(hdc, &viewportOrg);
+ GetWindowExtEx(hdc, &windowExt);
+
+ SetViewportExtEx(hdc, cx, cy, NULL);
+ GetViewportExtEx(hdc, &viewportExt);
+ ok(viewportExt.cx == expected_vp_cx && viewportExt.cy == expected_vp_cy,
+ "Viewport extents have not been properly adjusted: Expected %ldx%ld, got %ldx%ld\n",
+ expected_vp_cx, expected_vp_cy, viewportExt.cx, viewportExt.cy);
+
+ GetWindowExtEx(hdc, &windowExtAfter);
+ ok(windowExt.cx == windowExtAfter.cx && windowExt.cy == windowExtAfter.cy,
+ "Window extension changed from %ldx%ld to %ldx%ld\n",
+ windowExt.cx, windowExt.cy, windowExtAfter.cx, windowExtAfter.cy);
+
+ GetWindowOrgEx(hdc, &windowOrgAfter);
+ ok(windowOrg.x == windowOrgAfter.x && windowOrg.y == windowOrgAfter.y,
+ "Window origin changed from (%ld,%ld) to (%ld,%ld)\n",
+ windowOrg.x, windowOrg.y, windowOrgAfter.x, windowOrgAfter.y);
+
+ GetViewportOrgEx(hdc, &viewportOrgAfter);
+ ok(viewportOrg.x == viewportOrgAfter.x && viewportOrg.y == viewportOrgAfter.y,
+ "Viewport origin changed from (%ld,%ld) to (%ld,%ld)\n",
+ viewportOrg.x, viewportOrg.y, viewportOrgAfter.x, viewportOrgAfter.y);
+}
+
+void test_isotropic_mapping(void)
+{
+ SIZE win, vp;
+ HDC hdc = GetDC(0);
+
+ SetMapMode(hdc, MM_ISOTROPIC);
+
+ /* MM_ISOTROPIC is set up like MM_LOMETRIC.
+ Initial values after SetMapMode():
+ (1 inch = 25.4 mm)
+
+ Windows 9x: Windows NT:
+ Window Ext: 254 x -254 HORZSIZE*10 x VERTSIZE*10
+ Viewport Ext: LOGPIXELSX x LOGPIXELSY HORZRES x -VERTRES
+
+ To test without rounding errors, we have to use multiples of
+ these values!
+ */
+
+ GetWindowExtEx(hdc, &win);
+ GetViewportExtEx(hdc, &vp);
+
+ test_SetViewportExt(hdc, 10 * vp.cx, 10 * vp.cy, 10 * vp.cx, 10 * vp.cy);
+ test_SetWindowExt(hdc, win.cx, win.cy, 10 * vp.cx, 10 * vp.cy);
+ test_SetWindowExt(hdc, 2 * win.cx, win.cy, 10 * vp.cx, 5 * vp.cy);
+ test_SetWindowExt(hdc, win.cx, win.cy, 5 * vp.cx, 5 * vp.cy);
+ test_SetViewportExt(hdc, 4 * vp.cx, 2 * vp.cy, 2 * vp.cx, 2 * vp.cy);
+ test_SetViewportExt(hdc, vp.cx, 2 * vp.cy, vp.cx, vp.cy);
+ test_SetViewportExt(hdc, 2 * vp.cx, 2 * vp.cy, 2 * vp.cx, 2 * vp.cy);
+ test_SetViewportExt(hdc, 4 * vp.cx, 2 * vp.cy, 2 * vp.cx, 2 * vp.cy);
+ test_SetWindowExt(hdc, 4 * win.cx, 2 * win.cy, 2 * vp.cx, vp.cy);
+ test_SetViewportExt(hdc, -2 * vp.cx, -4 * vp.cy, -2 * vp.cx, -vp.cy);
+ test_SetViewportExt(hdc, -2 * vp.cx, -1 * vp.cy, -2 * vp.cx, -vp.cy);
+ test_SetWindowExt(hdc, -4 * win.cx, -2 * win.cy, -2 * vp.cx, -vp.cy);
+ test_SetWindowExt(hdc, 4 * win.cx, -4 * win.cy, -vp.cx, -vp.cy);
+
+ ReleaseDC(0, hdc);
+}
+
+START_TEST(mapping)
+{
+ test_modify_world_transform();
+ test_isotropic_mapping();
+}
diff --git a/reactos/regtests/winetests/gdi32/metafile.c b/reactos/regtests/winetests/gdi32/metafile.c
index 17f0138c803..3610bf89265 100755
--- a/reactos/regtests/winetests/gdi32/metafile.c
+++ b/reactos/regtests/winetests/gdi32/metafile.c
@@ -15,7 +15,7 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include
@@ -35,7 +35,28 @@ static BOOL emr_processed = FALSE;
#define LINE_X 55.0f
#define LINE_Y 15.0f
-static int CALLBACK emf_enum_proc(HDC hdc, HANDLETABLE *handle_table,
+static INT (WINAPI * pGetRelAbs)(HDC, DWORD);
+static INT (WINAPI * pSetRelAbs)(HDC, INT);
+
+#define GDI_GET_PROC(func) \
+ p ## func = (void *)GetProcAddress(hGDI, #func); \
+ if(!p ## func) \
+ trace("GetProcAddress(hGDI, \"%s\") failed\n", #func); \
+
+static void init_function_pointers(void)
+{
+ HMODULE hGDI;
+
+ pGetRelAbs = NULL;
+ pSetRelAbs = NULL;
+
+ hGDI = GetModuleHandleA("gdi32.dll");
+ assert(hGDI);
+ GDI_GET_PROC(GetRelAbs);
+ GDI_GET_PROC(SetRelAbs);
+}
+
+static int CALLBACK eto_emf_enum_proc(HDC hdc, HANDLETABLE *handle_table,
const ENHMETARECORD *emr, int n_objs, LPARAM param)
{
static int n_record;
@@ -55,6 +76,19 @@ static int CALLBACK emf_enum_proc(HDC hdc, HANDLETABLE *handle_table,
switch (emr->iType)
{
case EMR_HEADER:
+ ok(GetTextAlign(hdc) == 0, "text align %08x\n", GetTextAlign(hdc));
+ ok(GetBkColor(hdc) == RGB(0xff, 0xff, 0xff), "bk color %08lx\n", GetBkColor(hdc));
+ ok(GetTextColor(hdc) == RGB(0x0, 0x0, 0x0), "text color %08lx\n", GetTextColor(hdc));
+ ok(GetROP2(hdc) == R2_COPYPEN, "rop %d\n", GetROP2(hdc));
+ ok(GetArcDirection(hdc) == AD_COUNTERCLOCKWISE, "arc dir %d\n", GetArcDirection(hdc));
+ ok(GetPolyFillMode(hdc) == ALTERNATE, "poly fill %d\n", GetPolyFillMode(hdc));
+ ok(GetStretchBltMode(hdc) == BLACKONWHITE, "stretchblt mode %d\n", GetStretchBltMode(hdc));
+
+ /* GetBkMode, GetRelAbs do not get reset to the default value */
+ ok(GetBkMode(hdc) == OPAQUE, "bk mode %d\n", GetBkMode(hdc));
+ if(pSetRelAbs && pGetRelAbs)
+ ok(pGetRelAbs(hdc, 0) == RELATIVE, "relabs %d\n", pGetRelAbs(hdc, 0));
+
n_record = 0;
break;
@@ -189,21 +223,147 @@ static void test_ExtTextOut(void)
ret = PlayEnhMetaFile(hdcDisplay, hMetafile, &rc);
ok( ret, "PlayEnhMetaFile error %ld\n", GetLastError());
- ret = EnumEnhMetaFile(hdcDisplay, hMetafile, emf_enum_proc, dx, &rc);
+ SetTextAlign(hdcDisplay, TA_UPDATECP | TA_CENTER | TA_BASELINE | TA_RTLREADING );
+ SetBkColor(hdcDisplay, RGB(0xff, 0, 0));
+ SetTextColor(hdcDisplay, RGB(0, 0xff, 0));
+ SetROP2(hdcDisplay, R2_NOT);
+ SetArcDirection(hdcDisplay, AD_CLOCKWISE);
+ SetPolyFillMode(hdcDisplay, WINDING);
+ SetStretchBltMode(hdcDisplay, HALFTONE);
+
+ if(pSetRelAbs) pSetRelAbs(hdcDisplay, RELATIVE);
+ SetBkMode(hdcDisplay, OPAQUE);
+
+ ret = EnumEnhMetaFile(hdcDisplay, hMetafile, eto_emf_enum_proc, dx, &rc);
ok( ret, "EnumEnhMetaFile error %ld\n", GetLastError());
+ ok( GetTextAlign(hdcDisplay) == (TA_UPDATECP | TA_CENTER | TA_BASELINE | TA_RTLREADING),
+ "text align %08x\n", GetTextAlign(hdcDisplay));
+ ok( GetBkColor(hdcDisplay) == RGB(0xff, 0, 0), "bk color %08lx\n", GetBkColor(hdcDisplay));
+ ok( GetTextColor(hdcDisplay) == RGB(0, 0xff, 0), "text color %08lx\n", GetTextColor(hdcDisplay));
+ ok( GetROP2(hdcDisplay) == R2_NOT, "rop2 %d\n", GetROP2(hdcDisplay));
+ ok( GetArcDirection(hdcDisplay) == AD_CLOCKWISE, "arc dir %d\n", GetArcDirection(hdcDisplay));
+ ok( GetPolyFillMode(hdcDisplay) == WINDING, "poly fill %d\n", GetPolyFillMode(hdcDisplay));
+ ok( GetStretchBltMode(hdcDisplay) == HALFTONE, "stretchblt mode %d\n", GetStretchBltMode(hdcDisplay));
+
ok(emr_processed, "EnumEnhMetaFile couldn't find EMR_EXTTEXTOUTA or EMR_EXTTEXTOUTW record\n");
- ok(!EnumEnhMetaFile(hdcDisplay, hMetafile, emf_enum_proc, dx, NULL),
+ ok(!EnumEnhMetaFile(hdcDisplay, hMetafile, eto_emf_enum_proc, dx, NULL),
"A valid hdc has to require a valid rc\n");
- ok(EnumEnhMetaFile(NULL, hMetafile, emf_enum_proc, dx, NULL),
+ ok(EnumEnhMetaFile(NULL, hMetafile, eto_emf_enum_proc, dx, NULL),
"A null hdc does not require a valid rc\n");
ret = DeleteEnhMetaFile(hMetafile);
ok( ret, "DeleteEnhMetaFile error %ld\n", GetLastError());
ret = ReleaseDC(hwnd, hdcDisplay);
ok( ret, "ReleaseDC error %ld\n", GetLastError());
+ DestroyWindow(hwnd);
+}
+
+static int CALLBACK savedc_emf_enum_proc(HDC hdc, HANDLETABLE *handle_table,
+ const ENHMETARECORD *emr, int n_objs, LPARAM param)
+{
+ static int save_state;
+ static int restore_no;
+
+ switch (emr->iType)
+ {
+ case EMR_HEADER:
+ save_state = 0;
+ restore_no = 0;
+ break;
+
+ case EMR_SAVEDC:
+ save_state++;
+ break;
+
+ case EMR_RESTOREDC:
+ {
+ EMRRESTOREDC *restoredc = (EMRRESTOREDC *)emr;
+ switch(++restore_no)
+ {
+ case 1:
+ ok(restoredc->iRelative == -1, "first restore %ld\n", restoredc->iRelative);
+ break;
+
+ case 2:
+ ok(restoredc->iRelative == -3, "second restore %ld\n", restoredc->iRelative);
+ break;
+ case 3:
+ ok(restoredc->iRelative == -2, "third restore %ld\n", restoredc->iRelative);
+ break;
+ }
+ ok(restore_no <= 3, "restore_no %d\n", restore_no);
+ save_state += restoredc->iRelative;
+ break;
+ }
+ case EMR_EOF:
+ ok(save_state == 0, "EOF save_state %d\n", save_state);
+ break;
+ }
+
+
+ return 1;
+}
+
+void test_SaveDC(void)
+{
+ HDC hdcMetafile, hdcDisplay;
+ HENHMETAFILE hMetafile;
+ HWND hwnd;
+ int ret;
+ static const RECT rc = { 0, 0, 100, 100 };
+
+ /* Win9x doesn't play EMFs on invisible windows */
+ hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE,
+ 0, 0, 200, 200, 0, 0, 0, NULL);
+ ok(hwnd != 0, "CreateWindowExA error %ld\n", GetLastError());
+
+ hdcDisplay = GetDC(hwnd);
+ ok(hdcDisplay != 0, "GetDC error %ld\n", GetLastError());
+
+ hdcMetafile = CreateEnhMetaFileA(hdcDisplay, NULL, NULL, NULL);
+ ok(hdcMetafile != 0, "CreateEnhMetaFileA error %ld\n", GetLastError());
+
+ /* Need to write something to the emf, otherwise Windows won't play it back */
+ LineTo(hdcMetafile, 100, 100);
+
+ ret = SaveDC(hdcMetafile);
+ ok(ret == 1, "ret = %d\n", ret);
+
+ ret = SaveDC(hdcMetafile);
+ ok(ret == 2, "ret = %d\n", ret);
+
+ ret = SaveDC(hdcMetafile);
+ ok(ret == 3, "ret = %d\n", ret);
+
+ ret = RestoreDC(hdcMetafile, -1);
+ ok(ret, "ret = %d\n", ret);
+
+ ret = SaveDC(hdcMetafile);
+ ok(ret == 3, "ret = %d\n", ret);
+
+ ret = RestoreDC(hdcMetafile, 1);
+ ok(ret, "ret = %d\n", ret);
+
+ ret = SaveDC(hdcMetafile);
+ ok(ret == 1, "ret = %d\n", ret);
+
+ ret = SaveDC(hdcMetafile);
+ ok(ret == 2, "ret = %d\n", ret);
+
+ hMetafile = CloseEnhMetaFile(hdcMetafile);
+ ok(hMetafile != 0, "CloseEnhMetaFile error %ld\n", GetLastError());
+
+ ret = EnumEnhMetaFile(hdcDisplay, hMetafile, savedc_emf_enum_proc, 0, &rc);
+ ok( ret == 1, "EnumEnhMetaFile rets %d\n", ret);
+
+ ret = DeleteEnhMetaFile(hMetafile);
+ ok( ret, "DeleteEnhMetaFile error %ld\n", GetLastError());
+ ret = ReleaseDC(hwnd, hdcDisplay);
+ ok( ret, "ReleaseDC error %ld\n", GetLastError());
+ DestroyWindow(hwnd);
}
/* Win-format metafile (mfdrv) tests */
@@ -211,7 +371,7 @@ static void test_ExtTextOut(void)
/* with the nominal results. */
/* Maximum size of sample metafiles in bytes. */
-#define MF_BUFSIZE 256
+#define MF_BUFSIZE 512
/* 8x8 bitmap data for a pattern brush */
static const unsigned char SAMPLE_PATTERN_BRUSH[] = {
@@ -262,22 +422,205 @@ static const unsigned char MF_PATTERN_BRUSH_BITS[] = {
0x00, 0x00
};
+static const unsigned char MF_TEXTOUT_ON_PATH_BITS[] =
+{
+ 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x19, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x32, 0x0a,
+ 0x16, 0x00, 0x0b, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x54, 0x65, 0x73, 0x74, 0x03, 0x00, 0x05, 0x00,
+ 0x08, 0x00, 0x0c, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00
+};
+
+static const unsigned char EMF_TEXTOUT_ON_PATH_BITS[] =
+{
+ 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xe7, 0xff, 0xff, 0xff, 0xe9, 0xff, 0xff, 0xff,
+ 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
+ 0xf4, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
+ 0x40, 0x01, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x04, 0x00,
+ 0x80, 0xa9, 0x03, 0x00, 0x3b, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
+ 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc8, 0x41, 0x00, 0x80, 0xbb, 0x41,
+ 0x0b, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x54, 0x00, 0x00, 0x00,
+ 0x54, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
+ 0x3c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x14, 0x00, 0x00, 0x00
+};
+
+static const unsigned char MF_LINETO_BITS[] = {
+ 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x11, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x13, 0x02,
+ 0x0f, 0x00, 0x37, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00
+};
+
+static const unsigned char EMF_LINETO_BITS[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x37, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x61, 0x06, 0x00, 0x00, 0xb7, 0x01, 0x00, 0x00,
+ 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
+ 0x38, 0x01, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
+ 0x7c, 0x01, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x60, 0xcc, 0x05, 0x00,
+ 0xe0, 0x93, 0x04, 0x00, 0x46, 0x00, 0x00, 0x00,
+ 0x48, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00,
+ 0x47, 0x44, 0x49, 0x43, 0x01, 0x00, 0x00, 0x80,
+ 0x00, 0x03, 0x00, 0x00, 0x60, 0xe5, 0xf4, 0x73,
+ 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x11, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x13, 0x02,
+ 0x0f, 0x00, 0x37, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
+ 0x36, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x37, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
+ 0x25, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x80, 0x25, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+ 0x30, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
+ 0x0f, 0x00, 0x00, 0x80, 0x4b, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
+ 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00
+};
+
+static const unsigned char EMF_LINETO_MM_ANISOTROPIC_BITS[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x37, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x64, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
+ 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
+ 0x38, 0x01, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
+ 0x7c, 0x01, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x60, 0xcc, 0x05, 0x00,
+ 0xe0, 0x93, 0x04, 0x00, 0x46, 0x00, 0x00, 0x00,
+ 0x48, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00,
+ 0x47, 0x44, 0x49, 0x43, 0x01, 0x00, 0x00, 0x80,
+ 0x00, 0x03, 0x00, 0x00, 0xa4, 0xfe, 0xf4, 0x73,
+ 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x11, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x13, 0x02,
+ 0x0f, 0x00, 0x37, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x36, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x37, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
+ 0x25, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x80, 0x25, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+ 0x30, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
+ 0x0f, 0x00, 0x00, 0x80, 0x4b, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
+ 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00
+};
+
+static const unsigned char EMF_LINETO_MM_TEXT_BITS[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x37, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x61, 0x06, 0x00, 0x00, 0xb7, 0x01, 0x00, 0x00,
+ 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
+ 0xe4, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
+ 0x7c, 0x01, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x60, 0xcc, 0x05, 0x00,
+ 0xe0, 0x93, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
+ 0x00, 0x04, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
+ 0x00, 0x04, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00,
+ 0x0f, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x80,
+ 0x25, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x80, 0x30, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x80,
+ 0x4b, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x14, 0x00, 0x00, 0x00
+};
+
+/* For debugging or dumping the raw metafiles produced by
+ * new test functions.
+ */
+static INT CALLBACK mf_enum_proc(HDC hdc, HANDLETABLE *ht, METARECORD *mr,
+ INT nobj, LPARAM param)
+{
+ trace("hdc %p, mr->rdFunction %04x, mr->rdSize %lu, param %p\n",
+ hdc, mr->rdFunction, mr->rdSize, (void *)param);
+ return TRUE;
+}
+
/* For debugging or dumping the raw metafiles produced by
* new test functions.
*/
static void dump_mf_bits (const HMETAFILE mf, const char *desc)
{
- char buf[MF_BUFSIZE];
+ BYTE buf[MF_BUFSIZE];
UINT mfsize, i;
+ if (!winetest_debug) return;
+
mfsize = GetMetaFileBitsEx (mf, MF_BUFSIZE, buf);
ok (mfsize > 0, "%s: GetMetaFileBitsEx failed.\n", desc);
printf ("MetaFile %s has bits:\n{\n ", desc);
for (i=0; i 0, "%s: GetEnhMetaFileBits failed\n", desc);
+
+ printf("EMF %s has bits:\n{\n ", desc);
+ for (i = 0; i < mfsize; i++)
+ {
+ printf ("0x%02x", buf[i]);
+ if (i == mfsize-1)
+ printf ("\n");
+ else if (i % 8 == 7)
+ printf (",\n ");
+ else
+ printf (", ");
+ }
+ printf ("};\n");
+}
+
+static void dump_emf_records(const HENHMETAFILE mf, const char *desc)
+{
+ BYTE *emf;
+ BYTE buf[MF_BUFSIZE];
+ UINT mfsize, offset;
+
+ if (!winetest_debug) return;
+
+ mfsize = GetEnhMetaFileBits(mf, MF_BUFSIZE, buf);
+ ok (mfsize > 0, "%s: GetEnhMetaFileBits error %ld\n", desc, GetLastError());
+
+ printf("EMF %s has records:\n", desc);
+
+ emf = buf;
+ offset = 0;
+ while(offset < mfsize)
+ {
+ EMR *emr = (EMR *)(emf + offset);
+ printf("emr->iType %ld, emr->nSize %lu\n", emr->iType, emr->nSize);
+ /*trace("emr->iType 0x%04lx, emr->nSize 0x%04lx\n", emr->iType, emr->nSize);*/
+ offset += emr->nSize;
+ }
+}
+
+/* Compare the EMF produced by a test function with the
+ * expected raw EMF data in "bits".
+ * Return value is 0 for a perfect match,
+ * -1 if lengths aren't equal,
+ * otherwise returns the number of non-matching bytes.
+ */
+static int compare_emf_bits(const HENHMETAFILE mf, const unsigned char *bits,
+ UINT bsize, const char *desc, BOOL todo)
+{
+ unsigned char buf[MF_BUFSIZE];
+ UINT mfsize, i;
+ int diff;
+
+ mfsize = GetEnhMetaFileBits(mf, MF_BUFSIZE, buf);
+ ok (mfsize > 0, "%s: GetEnhMetaFileBits error %ld\n", desc, GetLastError());
+
+ if (mfsize < MF_BUFSIZE)
+ {
+ if (mfsize != bsize && todo)
+ {
+ todo_wine
+ ok(mfsize == bsize, "%s: mfsize=%d, bsize=%d\n", desc, mfsize, bsize);
+ }
+ else
+ ok(mfsize == bsize, "%s: mfsize=%d, bsize=%d\n", desc, mfsize, bsize);
+ }
+ else
+ ok(bsize >= MF_BUFSIZE, "%s: mfsize > bufsize (%d bytes), bsize=%d\n",
+ desc, mfsize, bsize);
+
+ if (mfsize != bsize)
+ return -1;
+
+ diff = 0;
+ for (i = 0; i < bsize; i++)
+ {
+ if (buf[i] != bits[i])
+ diff++;
+ }
+ if (diff != 0 && todo)
+ {
+ todo_wine
+ {
+ ok(diff == 0, "%s: mfsize=%d, bsize=%d, diff=%d\n",
+ desc, mfsize, bsize, diff);
+ }
+ return diff;
+ }
+ else
+ {
+ ok(diff == 0, "%s: mfsize=%d, bsize=%d, diff=%d\n",
+ desc, mfsize, bsize, diff);
+
+ return diff;
+ }
+}
+
/* Test a blank metafile. May be used as a template for new tests. */
static void test_mf_Blank(void)
@@ -333,6 +820,7 @@ static void test_mf_Blank(void)
HMETAFILE hMetafile;
INT caps;
BOOL ret;
+ INT type;
hdcMetafile = CreateMetaFileA(NULL);
ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %ld\n", GetLastError());
@@ -345,16 +833,155 @@ static void test_mf_Blank(void)
hMetafile = CloseMetaFile(hdcMetafile);
ok(hMetafile != 0, "CloseMetaFile error %ld\n", GetLastError());
+ type = GetObjectType(hMetafile);
+ ok(type == OBJ_METAFILE, "CloseMetaFile created object with type %d\n", type);
ok(!GetObjectType(hdcMetafile), "CloseMetaFile has to destroy metafile hdc\n");
if (compare_mf_bits (hMetafile, MF_BLANK_BITS, sizeof(MF_BLANK_BITS),
"mf_blank") != 0)
- dump_mf_bits (hMetafile, "mf_Blank");
+ {
+ dump_mf_bits(hMetafile, "mf_Blank");
+ EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
+ }
ret = DeleteMetaFile(hMetafile);
ok( ret, "DeleteMetaFile(%p) error %ld\n", hMetafile, GetLastError());
}
+static void test_CopyMetaFile(void)
+{
+ HDC hdcMetafile;
+ HMETAFILE hMetafile, hmf_copy;
+ BOOL ret;
+ char temp_path[MAX_PATH];
+ char mf_name[MAX_PATH];
+ INT type;
+
+ hdcMetafile = CreateMetaFileA(NULL);
+ ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %ld\n", GetLastError());
+ trace("hdcMetafile %p\n", hdcMetafile);
+
+ hMetafile = CloseMetaFile(hdcMetafile);
+ ok(hMetafile != 0, "CloseMetaFile error %ld\n", GetLastError());
+ type = GetObjectType(hMetafile);
+ ok(type == OBJ_METAFILE, "CloseMetaFile created object with type %d\n", type);
+
+ if (compare_mf_bits (hMetafile, MF_BLANK_BITS, sizeof(MF_BLANK_BITS),
+ "mf_blank") != 0)
+ {
+ dump_mf_bits(hMetafile, "mf_Blank");
+ EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
+ }
+
+ GetTempPathA(MAX_PATH, temp_path);
+ GetTempFileNameA(temp_path, "wmf", 0, mf_name);
+
+ hmf_copy = CopyMetaFileA(hMetafile, mf_name);
+ ok(hmf_copy != 0, "CopyMetaFile error %ld\n", GetLastError());
+
+ type = GetObjectType(hmf_copy);
+ ok(type == OBJ_METAFILE, "CopyMetaFile created object with type %d\n", type);
+
+ ret = DeleteMetaFile(hMetafile);
+ ok( ret, "DeleteMetaFile(%p) error %ld\n", hMetafile, GetLastError());
+
+ if (compare_mf_disk_bits(mf_name, MF_BLANK_BITS, sizeof(MF_BLANK_BITS), "mf_blank") != 0)
+ {
+ dump_mf_bits(hMetafile, "mf_Blank");
+ EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
+ }
+
+ ret = DeleteMetaFile(hmf_copy);
+ ok( ret, "DeleteMetaFile(%p) error %ld\n", hmf_copy, GetLastError());
+
+ DeleteFileA(mf_name);
+}
+
+static void test_SetMetaFileBits(void)
+{
+ HMETAFILE hmf;
+ INT type;
+ BOOL ret;
+ BYTE buf[256];
+ METAHEADER *mh;
+
+ hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), MF_GRAPHICS_BITS);
+ ok(hmf != 0, "SetMetaFileBitsEx error %ld\n", GetLastError());
+ type = GetObjectType(hmf);
+ ok(type == OBJ_METAFILE, "SetMetaFileBitsEx created object with type %d\n", type);
+
+ if (compare_mf_bits(hmf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS), "mf_Graphics") != 0)
+ {
+ dump_mf_bits(hmf, "mf_Graphics");
+ EnumMetaFile(0, hmf, mf_enum_proc, 0);
+ }
+
+ ret = DeleteMetaFile(hmf);
+ ok(ret, "DeleteMetaFile(%p) error %ld\n", hmf, GetLastError());
+
+ /* NULL data crashes XP SP1 */
+ /*hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), NULL);*/
+
+ /* Now with not zero size */
+ SetLastError(0xdeadbeef);
+ hmf = SetMetaFileBitsEx(0, MF_GRAPHICS_BITS);
+ ok(!hmf, "SetMetaFileBitsEx should fail\n");
+ ok(GetLastError() == ERROR_INVALID_DATA, "wrong error %ld\n", GetLastError());
+
+ /* Now with not even size */
+ SetLastError(0xdeadbeef);
+ hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS) - 1, MF_GRAPHICS_BITS);
+ ok(!hmf, "SetMetaFileBitsEx should fail\n");
+ ok(GetLastError() == 0xdeadbeef /* XP SP1 */, "wrong error %ld\n", GetLastError());
+
+ /* Now with zeroed out or faked some header fields */
+ assert(sizeof(buf) >= sizeof(MF_GRAPHICS_BITS));
+ memcpy(buf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS));
+ mh = (METAHEADER *)buf;
+ /* corruption of any of the below fields leads to a failure */
+ mh->mtType = 0;
+ mh->mtVersion = 0;
+ mh->mtHeaderSize = 0;
+ SetLastError(0xdeadbeef);
+ hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), buf);
+ ok(!hmf, "SetMetaFileBitsEx should fail\n");
+ ok(GetLastError() == ERROR_INVALID_DATA, "wrong error %ld\n", GetLastError());
+
+ /* Now with corrupted mtSize field */
+ memcpy(buf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS));
+ mh = (METAHEADER *)buf;
+ /* corruption of mtSize doesn't lead to a failure */
+ mh->mtSize *= 2;
+ hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), buf);
+ ok(hmf != 0, "SetMetaFileBitsEx error %ld\n", GetLastError());
+
+ if (compare_mf_bits(hmf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS), "mf_Graphics") != 0)
+ {
+ dump_mf_bits(hmf, "mf_Graphics");
+ EnumMetaFile(0, hmf, mf_enum_proc, 0);
+ }
+
+ ret = DeleteMetaFile(hmf);
+ ok(ret, "DeleteMetaFile(%p) error %ld\n", hmf, GetLastError());
+
+ /* Now with zeroed out mtSize field */
+ memcpy(buf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS));
+ mh = (METAHEADER *)buf;
+ /* zeroing mtSize doesn't lead to a failure */
+ mh->mtSize = 0;
+ hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), buf);
+ ok(hmf != 0, "SetMetaFileBitsEx error %ld\n", GetLastError());
+
+ if (compare_mf_bits(hmf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS), "mf_Graphics") != 0)
+ {
+ dump_mf_bits(hmf, "mf_Graphics");
+ EnumMetaFile(0, hmf, mf_enum_proc, 0);
+ }
+
+ ret = DeleteMetaFile(hmf);
+ ok(ret, "DeleteMetaFile(%p) error %ld\n", hmf, GetLastError());
+}
+
/* Simple APIs from mfdrv/graphics.c
*/
@@ -393,7 +1020,10 @@ static void test_mf_Graphics(void)
if (compare_mf_bits (hMetafile, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS),
"mf_Graphics") != 0)
- dump_mf_bits (hMetafile, "mf_Graphics");
+ {
+ dump_mf_bits(hMetafile, "mf_Graphics");
+ EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
+ }
ret = DeleteMetaFile(hMetafile);
ok( ret, "DeleteMetaFile(%p) error %ld\n",
@@ -412,8 +1042,8 @@ static void test_mf_PatternBrush(void)
orig_lb->lbStyle = BS_PATTERN;
orig_lb->lbColor = RGB(0, 0, 0);
- orig_lb->lbHatch = (INT) CreateBitmap (8, 8, 1, 1, SAMPLE_PATTERN_BRUSH);
- ok((HBITMAP *)orig_lb->lbHatch != NULL, "CreateBitmap error %ld.\n", GetLastError());
+ orig_lb->lbHatch = (ULONG_PTR)CreateBitmap (8, 8, 1, 1, SAMPLE_PATTERN_BRUSH);
+ ok((HBITMAP)orig_lb->lbHatch != NULL, "CreateBitmap error %ld.\n", GetLastError());
hBrush = CreateBrushIndirect (orig_lb);
ok(hBrush != 0, "CreateBrushIndirect error %ld\n", GetLastError());
@@ -431,18 +1061,103 @@ static void test_mf_PatternBrush(void)
if (compare_mf_bits (hMetafile, MF_PATTERN_BRUSH_BITS, sizeof(MF_PATTERN_BRUSH_BITS),
"mf_Pattern_Brush") != 0)
- dump_mf_bits (hMetafile, "mf_Pattern_Brush");
+ {
+ dump_mf_bits(hMetafile, "mf_Pattern_Brush");
+ EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
+ }
ret = DeleteMetaFile(hMetafile);
ok( ret, "DeleteMetaFile error %ld\n", GetLastError());
ret = DeleteObject(hBrush);
ok( ret, "DeleteObject(HBRUSH) error %ld\n", GetLastError());
- ret = DeleteObject((HBITMAP *)orig_lb->lbHatch);
+ ret = DeleteObject((HBITMAP)orig_lb->lbHatch);
ok( ret, "DeleteObject(HBITMAP) error %ld\n",
GetLastError());
HeapFree (GetProcessHeap(), 0, orig_lb);
}
+static void test_mf_ExtTextOut_on_path(void)
+{
+ HDC hdcMetafile;
+ HMETAFILE hMetafile;
+ BOOL ret;
+ static const INT dx[4] = { 3, 5, 8, 12 };
+
+ hdcMetafile = CreateMetaFileA(NULL);
+ ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %ld\n", GetLastError());
+ trace("hdcMetafile %p\n", hdcMetafile);
+
+ ret = BeginPath(hdcMetafile);
+ ok(!ret, "BeginPath on metafile DC should fail\n");
+
+ ret = ExtTextOutA(hdcMetafile, 11, 22, 0, NULL, "Test", 4, dx);
+ ok(ret, "ExtTextOut error %ld\n", GetLastError());
+
+ ret = EndPath(hdcMetafile);
+ ok(!ret, "EndPath on metafile DC should fail\n");
+
+ hMetafile = CloseMetaFile(hdcMetafile);
+ ok(hMetafile != 0, "CloseMetaFile error %ld\n", GetLastError());
+
+ if (compare_mf_bits(hMetafile, MF_TEXTOUT_ON_PATH_BITS, sizeof(MF_TEXTOUT_ON_PATH_BITS),
+ "mf_TextOut_on_path") != 0)
+ {
+ dump_mf_bits(hMetafile, "mf_TextOut_on_path");
+ EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
+ }
+
+ ret = DeleteMetaFile(hMetafile);
+ ok(ret, "DeleteMetaFile(%p) error %ld\n", hMetafile, GetLastError());
+}
+
+static void test_emf_ExtTextOut_on_path(void)
+{
+ HWND hwnd;
+ HDC hdcDisplay, hdcMetafile;
+ HENHMETAFILE hMetafile;
+ BOOL ret;
+ static const INT dx[4] = { 3, 5, 8, 12 };
+
+ /* Win9x doesn't play EMFs on invisible windows */
+ hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE,
+ 0, 0, 200, 200, 0, 0, 0, NULL);
+ ok(hwnd != 0, "CreateWindowExA error %ld\n", GetLastError());
+
+ hdcDisplay = GetDC(hwnd);
+ ok(hdcDisplay != 0, "GetDC error %ld\n", GetLastError());
+
+ hdcMetafile = CreateEnhMetaFileA(hdcDisplay, NULL, NULL, NULL);
+ ok(hdcMetafile != 0, "CreateEnhMetaFileA error %ld\n", GetLastError());
+
+ ret = BeginPath(hdcMetafile);
+ ok(ret, "BeginPath error %ld\n", GetLastError());
+
+ ret = ExtTextOutA(hdcMetafile, 11, 22, 0, NULL, "Test", 4, dx);
+ ok(ret, "ExtTextOut error %ld\n", GetLastError());
+
+ ret = EndPath(hdcMetafile);
+ ok(ret, "EndPath error %ld\n", GetLastError());
+
+ hMetafile = CloseEnhMetaFile(hdcMetafile);
+ ok(hMetafile != 0, "CloseEnhMetaFile error %ld\n", GetLastError());
+
+ /* this doesn't succeed yet: EMF has correct size, all EMF records
+ * are there, but their contents don't match for different reasons.
+ */
+ if (compare_emf_bits(hMetafile, EMF_TEXTOUT_ON_PATH_BITS, sizeof(EMF_TEXTOUT_ON_PATH_BITS),
+ "emf_TextOut_on_path", TRUE) != 0)
+ {
+ dump_emf_bits(hMetafile, "emf_TextOut_on_path");
+ dump_emf_records(hMetafile, "emf_TextOut_on_path");
+ }
+
+ ret = DeleteEnhMetaFile(hMetafile);
+ ok(ret, "DeleteEnhMetaFile error %ld\n", GetLastError());
+ ret = ReleaseDC(hwnd, hdcDisplay);
+ ok(ret, "ReleaseDC error %ld\n", GetLastError());
+ DestroyWindow(hwnd);
+}
+
static INT CALLBACK EmfEnumProc(HDC hdc, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR, INT nObj, LPARAM lpData)
{
LPMETAFILEPICT lpMFP = (LPMETAFILEPICT)lpData;
@@ -451,7 +1166,10 @@ static INT CALLBACK EmfEnumProc(HDC hdc, HANDLETABLE *lpHTable, const ENHMETAREC
* until a record is played which actually outputs something */
PlayEnhMetaFileRecord(hdc, lpHTable, lpEMFR, nObj);
LPtoDP(hdc, mapping, 2);
- trace("Meta record: iType = %ld, (%ld,%ld)-(%ld,%ld)\n", lpEMFR->iType, mapping[0].x, mapping[0].y, mapping[1].x, mapping[1].y);
+ trace("Meta record: iType %ld, nSize %ld, (%ld,%ld)-(%ld,%ld)\n",
+ lpEMFR->iType, lpEMFR->nSize,
+ mapping[0].x, mapping[0].y, mapping[1].x, mapping[1].y);
+
if (lpEMFR->iType == EMR_LINETO)
{
INT x0, y0, x1, y1;
@@ -493,6 +1211,13 @@ static HENHMETAFILE create_converted_emf(const METAFILEPICT *mfp)
ok(ret, "LineTo failed with error %ld\n", GetLastError());
hmf = CloseMetaFile(hdcMf);
ok(hmf != NULL, "CloseMetaFile failed with error %ld\n", GetLastError());
+
+ if (compare_mf_bits (hmf, MF_LINETO_BITS, sizeof(MF_LINETO_BITS), "mf_LineTo") != 0)
+ {
+ dump_mf_bits(hmf, "mf_LineTo");
+ EnumMetaFile(0, hmf, mf_enum_proc, 0);
+ }
+
size = GetMetaFileBitsEx(hmf, 0, NULL);
ok(size, "GetMetaFileBitsEx failed with error %ld\n", GetLastError());
pBits = HeapAlloc(GetProcessHeap(), 0, size);
@@ -514,7 +1239,16 @@ static void test_mf_conversions(void)
mfp.yExt = 100;
mfp.hMF = NULL;
hemf = create_converted_emf(&mfp);
+
+ if (compare_emf_bits(hemf, EMF_LINETO_MM_ANISOTROPIC_BITS, sizeof(EMF_LINETO_MM_ANISOTROPIC_BITS),
+ "emf_LineTo MM_ANISOTROPIC", TRUE) != 0)
+ {
+ dump_emf_bits(hemf, "emf_LineTo MM_ANISOTROPIC");
+ dump_emf_records(hemf, "emf_LineTo MM_ANISOTROPIC");
+ }
+
EnumEnhMetaFile(hdcOffscreen, hemf, EmfEnumProc, &mfp, &rect);
+
DeleteEnhMetaFile(hemf);
DeleteDC(hdcOffscreen);
}
@@ -530,7 +1264,16 @@ static void test_mf_conversions(void)
mfp.yExt = 0;
mfp.hMF = NULL;
hemf = create_converted_emf(&mfp);
+
+ if (compare_emf_bits(hemf, EMF_LINETO_MM_TEXT_BITS, sizeof(EMF_LINETO_MM_TEXT_BITS),
+ "emf_LineTo MM_TEXT", TRUE) != 0)
+ {
+ dump_emf_bits(hemf, "emf_LineTo MM_TEXT");
+ dump_emf_records(hemf, "emf_LineTo MM_TEXT");
+ }
+
EnumEnhMetaFile(hdcOffscreen, hemf, EmfEnumProc, &mfp, &rect);
+
DeleteEnhMetaFile(hemf);
DeleteDC(hdcOffscreen);
}
@@ -541,12 +1284,232 @@ static void test_mf_conversions(void)
HENHMETAFILE hemf;
RECT rect = { 0, 0, 100, 100 };
hemf = create_converted_emf(NULL);
+
+ if (compare_emf_bits(hemf, EMF_LINETO_BITS, sizeof(EMF_LINETO_BITS),
+ "emf_LineTo NULL", TRUE) != 0)
+ {
+ dump_emf_bits(hemf, "emf_LineTo NULL");
+ dump_emf_records(hemf, "emf_LineTo NULL");
+ }
+
EnumEnhMetaFile(hdcOffscreen, hemf, EmfEnumProc, NULL, &rect);
+
DeleteEnhMetaFile(hemf);
DeleteDC(hdcOffscreen);
}
}
+static BOOL getConvertedFrameAndBounds(UINT buffer_size, BYTE * buffer, BOOL mfpIsNull,
+ LONG mm, LONG xExt, LONG yExt,
+ RECTL * rclBounds, RECTL * rclFrame)
+{
+ METAFILEPICT mfp;
+ METAFILEPICT * mfpPtr = NULL;
+ HENHMETAFILE emf;
+ ENHMETAHEADER header;
+ UINT res;
+
+ if (!mfpIsNull)
+ {
+ mfp.mm = mm;
+ mfp.xExt = xExt;
+ mfp.yExt = yExt;
+ mfpPtr = &mfp;
+ }
+
+ emf = SetWinMetaFileBits(buffer_size, buffer, NULL, mfpPtr);
+ ok(emf != NULL, "SetWinMetaFileBits failed\n");
+ if (!emf) return FALSE;
+ res = GetEnhMetaFileHeader(emf, sizeof(header), &header);
+ ok(res != 0, "GetEnhMetaHeader failed\n");
+ DeleteEnhMetaFile(emf);
+ if (!res) return FALSE;
+
+ *rclBounds = header.rclBounds;
+ *rclFrame = header.rclFrame;
+ return TRUE;
+}
+
+static void checkConvertedFrameAndBounds(UINT buffer_size, BYTE * buffer, BOOL mfpIsNull,
+ LONG mm, LONG xExt, LONG yExt,
+ RECTL * rclBoundsExpected, RECTL * rclFrameExpected)
+{
+ RECTL rclBounds, rclFrame;
+
+ if (getConvertedFrameAndBounds(buffer_size, buffer, mfpIsNull, mm, xExt, yExt, &rclBounds, &rclFrame))
+ {
+ const char * msg;
+ char buf[64];
+
+ if (mfpIsNull)
+ {
+ msg = "mfp == NULL";
+ }
+ else
+ {
+ const char * mm_str;
+ switch (mm)
+ {
+ case MM_ANISOTROPIC: mm_str = "MM_ANISOTROPIC"; break;
+ case MM_ISOTROPIC: mm_str = "MM_ISOTROPIC"; break;
+ default: mm_str = "Unexpected";
+ }
+ sprintf(buf, "mm=%s, xExt=%ld, yExt=%ld", mm_str, xExt, yExt);
+ msg = buf;
+ }
+
+ ok(rclBounds.left == rclBoundsExpected->left, "rclBounds.left: Expected %ld, got %ld (%s)\n", rclBoundsExpected->left, rclBounds.left, msg);
+ ok(rclBounds.top == rclBoundsExpected->top, "rclBounds.top: Expected %ld, got %ld (%s)\n", rclBoundsExpected->top, rclBounds.top, msg);
+ ok(rclBounds.right == rclBoundsExpected->right, "rclBounds.right: Expected %ld, got %ld (%s)\n", rclBoundsExpected->right, rclBounds.right, msg);
+ ok(rclBounds.bottom == rclBoundsExpected->bottom, "rclBounds.bottom: Expected %ld, got %ld (%s)\n", rclBoundsExpected->bottom, rclBounds.bottom, msg);
+ ok(rclFrame.left == rclFrameExpected->left, "rclFrame.left: Expected %ld, got %ld (%s)\n", rclFrameExpected->left, rclFrame.left, msg);
+ ok(rclFrame.top == rclFrameExpected->top, "rclFrame.top: Expected %ld, got %ld (%s)\n", rclFrameExpected->top, rclFrame.top, msg);
+ ok(rclFrame.right == rclFrameExpected->right, "rclFrame.right: Expected %ld, got %ld (%s)\n", rclFrameExpected->right, rclFrame.right, msg);
+ ok(rclFrame.bottom == rclFrameExpected->bottom, "rclFrame.bottom: Expected %ld, got %ld (%s)\n", rclFrameExpected->bottom, rclFrame.bottom, msg);
+ }
+}
+
+static void test_SetWinMetaFileBits(void)
+{
+ HMETAFILE wmf;
+ HDC wmfDC;
+ BYTE * buffer;
+ UINT buffer_size;
+ RECT rect;
+ UINT res;
+ RECTL rclBoundsAnisotropic, rclFrameAnisotropic;
+ RECTL rclBoundsIsotropic, rclFrameIsotropic;
+ RECTL rclBounds, rclFrame;
+ HDC dc;
+ LONG diffx, diffy;
+
+ wmfDC = CreateMetaFile(NULL);
+ ok(wmfDC != NULL, "CreateMetaFile failed\n");
+ if (!wmfDC) return;
+
+ SetWindowExtEx(wmfDC, 100, 100, NULL);
+ rect.left = rect.top = 0;
+ rect.right = rect.bottom = 50;
+ FillRect(wmfDC, &rect, GetStockObject(BLACK_BRUSH));
+ wmf = CloseMetaFile(wmfDC);
+ ok(wmf != NULL, "Metafile creation failed\n");
+ if (!wmf) return;
+
+ buffer_size = GetMetaFileBitsEx(wmf, 0, NULL);
+ ok(buffer_size != 0, "GetMetaFileBitsEx failed\n");
+ if (buffer_size == 0)
+ {
+ DeleteMetaFile(wmf);
+ return;
+ }
+
+ buffer = (BYTE *)HeapAlloc(GetProcessHeap(), 0, buffer_size);
+ ok(buffer != NULL, "HeapAlloc failed\n");
+ if (!buffer)
+ {
+ DeleteMetaFile(wmf);
+ return;
+ }
+
+ res = GetMetaFileBitsEx(wmf, buffer_size, buffer);
+ ok(res == buffer_size, "GetMetaFileBitsEx failed\n");
+ DeleteMetaFile(wmf);
+ if (res != buffer_size)
+ {
+ HeapFree(GetProcessHeap(), 0, buffer);
+ return;
+ }
+
+ /* Get the reference bounds and frame */
+ getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 0, 0, &rclBoundsAnisotropic, &rclFrameAnisotropic);
+ getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 0, 0, &rclBoundsIsotropic, &rclFrameIsotropic);
+
+ ok(rclBoundsAnisotropic.left == 0 && rclBoundsAnisotropic.top == 0 &&
+ rclBoundsIsotropic.left == 0 && rclBoundsIsotropic.top == 0,
+ "SetWinMetaFileBits: Reference bounds: Left and top bound must be zero\n");
+
+ ok(rclBoundsAnisotropic.right >= rclBoundsIsotropic.right, "SetWinMetaFileBits: Reference bounds: Invalid right bound\n");
+ ok(rclBoundsAnisotropic.bottom >= rclBoundsIsotropic.bottom, "SetWinMetaFileBits: Reference bounds: Invalid bottom bound\n");
+ diffx = rclBoundsIsotropic.right - rclBoundsIsotropic.bottom;
+ if (diffx < 0) diffx = -diffx;
+ ok(diffx <= 1, "SetWinMetaFileBits (MM_ISOTROPIC): Reference bounds are not isotropic\n");
+
+ dc = CreateCompatibleDC(NULL);
+ todo_wine
+ {
+ ok(rclBoundsAnisotropic.right == GetDeviceCaps(dc, HORZRES) / 2 - 1 &&
+ rclBoundsAnisotropic.bottom == GetDeviceCaps(dc, VERTRES) / 2 - 1,
+ "SetWinMetaFileBits (MM_ANISOTROPIC): Reference bounds: The whole device surface must be used (%dx%d), but got (%ldx%ld)\n",
+ GetDeviceCaps(dc, HORZRES) / 2 - 1, GetDeviceCaps(dc, VERTRES) / 2 - 1, rclBoundsAnisotropic.right, rclBoundsAnisotropic.bottom);
+ }
+
+ /* Allow 1 mm difference (rounding errors) */
+ diffx = rclFrameAnisotropic.right / 100 - GetDeviceCaps(dc, HORZSIZE) / 2;
+ diffy = rclFrameAnisotropic.bottom / 100 - GetDeviceCaps(dc, VERTSIZE) / 2;
+ if (diffx < 0) diffx = -diffx;
+ if (diffy < 0) diffy = -diffy;
+ todo_wine
+ {
+ ok(diffx <= 1 && diffy <= 1,
+ "SetWinMetaFileBits (MM_ANISOTROPIC): Reference frame: The whole device surface must be used (%dx%d), but got (%ldx%ld)\n",
+ GetDeviceCaps(dc, HORZSIZE) / 2, GetDeviceCaps(dc, VERTSIZE) / 2, rclFrameAnisotropic.right / 100, rclFrameAnisotropic.bottom / 100);
+ }
+ DeleteDC(dc);
+
+ /* If the METAFILEPICT pointer is NULL, the MM_ANISOTROPIC mapping mode and the whole device surface are used */
+ checkConvertedFrameAndBounds(buffer_size, buffer, TRUE, 0, 0, 0, &rclBoundsAnisotropic, &rclFrameAnisotropic);
+
+ /* If xExt or yExt is zero or negative, the whole device surface is used */
+ checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 10000, 0, &rclBoundsAnisotropic, &rclFrameAnisotropic);
+ checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 10000, 0, &rclBoundsIsotropic, &rclFrameIsotropic);
+ checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 0, 10000, &rclBoundsAnisotropic, &rclFrameAnisotropic);
+ checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 0, 10000, &rclBoundsIsotropic, &rclFrameIsotropic);
+ checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, -10000, 0, &rclBoundsAnisotropic, &rclFrameAnisotropic);
+ checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, -10000, 0, &rclBoundsIsotropic, &rclFrameIsotropic);
+ checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 0, -10000, &rclBoundsAnisotropic, &rclFrameAnisotropic);
+ checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 0, -10000, &rclBoundsIsotropic, &rclFrameIsotropic);
+ checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, -10000, 10000, &rclBoundsAnisotropic, &rclFrameAnisotropic);
+ checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, -10000, 10000, &rclBoundsIsotropic, &rclFrameIsotropic);
+ checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 10000, -10000, &rclBoundsAnisotropic, &rclFrameAnisotropic);
+ checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 10000, -10000, &rclBoundsIsotropic, &rclFrameIsotropic);
+
+ /* MSDN says that negative xExt and yExt values specify a ratio.
+ Check that this is wrong and the whole device surface is used */
+ checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, -1000, -100, &rclBoundsAnisotropic, &rclFrameAnisotropic);
+ checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, -1000, -100, &rclBoundsIsotropic, &rclFrameIsotropic);
+
+ /* Ordinary conversions */
+
+ if (getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 30000, 20000, &rclBounds, &rclFrame))
+ {
+ ok(rclFrame.left == 0 && rclFrame.top == 0 && rclFrame.right == 30000 && rclFrame.bottom == 20000,
+ "SetWinMetaFileBits (MM_ANISOTROPIC): rclFrame contains invalid values\n");
+ ok(rclBounds.left == 0 && rclBounds.top == 0 && rclBounds.right > rclBounds.bottom,
+ "SetWinMetaFileBits (MM_ANISOTROPIC): rclBounds contains invalid values\n");
+ }
+
+ if (getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 30000, 20000, &rclBounds, &rclFrame))
+ {
+ ok(rclFrame.left == 0 && rclFrame.top == 0 && rclFrame.right == 30000 && rclFrame.bottom == 20000,
+ "SetWinMetaFileBits (MM_ISOTROPIC): rclFrame contains invalid values\n");
+ ok(rclBounds.left == 0 && rclBounds.top == 0,
+ "SetWinMetaFileBits (MM_ISOTROPIC): rclBounds contains invalid values\n");
+
+ /* Wine has a rounding error */
+ diffx = rclBounds.right - rclBounds.bottom;
+ if (diffx < 0) diffx = -diffx;
+ ok(diffx <= 1, "SetWinMetaFileBits (MM_ISOTROPIC): rclBounds is not isotropic\n");
+ }
+
+ if (getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_HIMETRIC, 30000, 20000, &rclBounds, &rclFrame))
+ {
+ ok(rclFrame.right - rclFrame.left != 30000 && rclFrame.bottom - rclFrame.top != 20000,
+ "SetWinMetaFileBits: xExt and yExt must be ignored for mapping modes other than MM_ANISOTROPIC and MM_ISOTROPIC\n");
+ }
+
+ HeapFree(GetProcessHeap(), 0, buffer);
+}
+
static BOOL (WINAPI *pGdiIsMetaPrintDC)(HDC);
static BOOL (WINAPI *pGdiIsMetaFileDC)(HDC);
static BOOL (WINAPI *pGdiIsPlayMetafileDC)(HDC);
@@ -597,16 +1560,24 @@ static void test_gdiis(void)
START_TEST(metafile)
{
+ init_function_pointers();
+
/* For enhanced metafiles (enhmfdrv) */
test_ExtTextOut();
+ test_SaveDC();
/* For win-format metafiles (mfdrv) */
test_mf_Blank();
test_mf_Graphics();
test_mf_PatternBrush();
+ test_CopyMetaFile();
+ test_SetMetaFileBits();
+ test_mf_ExtTextOut_on_path();
+ test_emf_ExtTextOut_on_path();
/* For metafile conversions */
test_mf_conversions();
+ test_SetWinMetaFileBits();
test_gdiis();
}
diff --git a/reactos/regtests/winetests/gdi32/palette.c b/reactos/regtests/winetests/gdi32/palette.c
new file mode 100644
index 00000000000..994763985f7
--- /dev/null
+++ b/reactos/regtests/winetests/gdi32/palette.c
@@ -0,0 +1,126 @@
+/*
+ * Unit test suite for palettes
+ *
+ * Copyright 2005 Glenn Wurster
+ *
+ * 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
+#include
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "mmsystem.h"
+
+#include "wine/test.h"
+
+static const PALETTEENTRY logpalettedata[8] = {
+ { 0x10, 0x20, 0x30, PC_NOCOLLAPSE },
+ { 0x20, 0x30, 0x40, PC_NOCOLLAPSE },
+ { 0x30, 0x40, 0x50, PC_NOCOLLAPSE },
+ { 0x40, 0x50, 0x60, PC_NOCOLLAPSE },
+ { 0x50, 0x60, 0x70, PC_NOCOLLAPSE },
+ { 0x60, 0x70, 0x80, PC_NOCOLLAPSE },
+ { 0x70, 0x80, 0x90, PC_NOCOLLAPSE },
+ { 0x80, 0x90, 0xA0, PC_NOCOLLAPSE },
+};
+
+static void test_DIB_PAL_COLORS(void) {
+ HDC hdc = GetDC( NULL );
+ HDC memhdc = CreateCompatibleDC( hdc );
+ HBITMAP hbmp, hbmpOld;
+ char bmpbuf[sizeof(BITMAPINFO) + 10 * sizeof(WORD)];
+ PBITMAPINFO bmp = (PBITMAPINFO)bmpbuf;
+ WORD * bmpPalPtr;
+ char logpalettebuf[sizeof(LOGPALETTE) + sizeof(logpalettedata)];
+ PLOGPALETTE logpalette = (PLOGPALETTE)logpalettebuf;
+ HPALETTE hpal, hpalOld;
+ COLORREF setColor, chkColor, getColor;
+ int i;
+
+ /* Initalize the logical palette with a few colours */
+ logpalette->palVersion = 0x300;
+ logpalette->palNumEntries = 8;
+ memcpy( logpalette->palPalEntry, logpalettedata, sizeof(logpalettedata) );
+ hpal = CreatePalette( logpalette );
+ hpalOld = SelectPalette( memhdc, hpal, FALSE );
+ ok( hpalOld != NULL, "error=%ld\n", GetLastError() );
+
+ /* Create a DIB BMP which references colours in the logical palette */
+ memset( bmp, 0x00, sizeof(BITMAPINFO) );
+ bmp->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmp->bmiHeader.biWidth = 1;
+ bmp->bmiHeader.biHeight = 1;
+ bmp->bmiHeader.biPlanes = 1;
+ bmp->bmiHeader.biBitCount = 8;
+ bmp->bmiHeader.biCompression = BI_RGB;
+ bmp->bmiHeader.biClrUsed = 10;
+ bmp->bmiHeader.biClrImportant = 0;
+ bmpPalPtr = (WORD *)&bmp->bmiColors;
+ for( i = 0; i < 8; i++ ) {
+ *bmpPalPtr++ = i;
+ }
+ *bmpPalPtr++ = 8; /* Pointer to logical palette index just outside range */
+ *bmpPalPtr++ = 19; /* Pointer to bad logical palette index */
+
+ hbmp = CreateDIBSection( memhdc, bmp, DIB_PAL_COLORS, 0, 0, 0 );
+ ok( hbmp != NULL, "error=%ld\n", GetLastError() );
+ hbmpOld = SelectObject( memhdc, hbmp );
+ ok( hbmpOld != NULL, "error=%ld\n", GetLastError() );
+
+ /* Test with a RGB to DIB_PAL_COLORS */
+ setColor = RGB( logpalettedata[1].peRed, logpalettedata[1].peGreen, logpalettedata[1].peBlue );
+ SetPixel( memhdc, 0, 0, setColor );
+ chkColor = RGB( logpalettedata[1].peRed, logpalettedata[1].peGreen, logpalettedata[1].peBlue );
+ getColor = GetPixel( memhdc, 0, 0 );
+ ok( getColor == chkColor, "getColor=%08X\n", (UINT)getColor );
+
+ /* Test with a valid DIBINDEX to DIB_PAL_COLORS */
+ setColor = DIBINDEX( 2 );
+ SetPixel( memhdc, 0, 0, setColor );
+ chkColor = RGB( logpalettedata[2].peRed, logpalettedata[2].peGreen, logpalettedata[2].peBlue );
+ getColor = GetPixel( memhdc, 0, 0 );
+ ok( getColor == chkColor, "getColor=%08X\n", (UINT)getColor );
+
+ /* Test with a invalid DIBINDEX to DIB_PAL_COLORS */
+ setColor = DIBINDEX( 12 );
+ SetPixel( memhdc, 0, 0, setColor );
+ chkColor = RGB( 0, 0, 0 );
+ getColor = GetPixel( memhdc, 0, 0 );
+ ok( getColor == chkColor, "getColor=%08X\n", (UINT)getColor );
+
+ /* Test for double wraparound on logical palette references from */
+ /* DIBINDEX by DIB_PAL_COLORS. */
+ setColor = DIBINDEX( 9 );
+ SetPixel( memhdc, 0, 0, setColor );
+ chkColor = RGB( logpalettedata[3].peRed, logpalettedata[3].peGreen, logpalettedata[3].peBlue );
+ getColor = GetPixel( memhdc, 0, 0 );
+ ok( getColor == chkColor, "getColor=%08X\n", (UINT)getColor );
+
+ SelectPalette( memhdc, hpalOld, FALSE );
+ DeleteObject( hpal );
+ SelectObject( memhdc, hbmpOld );
+ DeleteObject( hbmp );
+ DeleteDC( memhdc );
+ ReleaseDC( NULL, hdc );
+}
+
+START_TEST(palette)
+{
+ test_DIB_PAL_COLORS();
+}
diff --git a/reactos/regtests/winetests/gdi32/testlist.c b/reactos/regtests/winetests/gdi32/testlist.c
index cf5319b1b99..139d5fa5339 100644
--- a/reactos/regtests/winetests/gdi32/testlist.c
+++ b/reactos/regtests/winetests/gdi32/testlist.c
@@ -22,14 +22,14 @@ const struct test winetest_testlist[] =
{
{ "bitmap", func_bitmap },
{ "brush", func_brush },
-// { "clipping", func_clipping },
-// { "dc", func_dc },
-// { "font", func_font },
+ { "clipping", func_clipping },
+ { "dc", func_dc },
+ { "font", func_font },
{ "gdiobj", func_gdiobj },
// { "generated", func_generated },
-// { "mapping", func_mapping },
+ { "mapping", func_mapping },
{ "metafile", func_metafile },
-// { "palette", func_palette },
+ { "palette", func_palette },
// { "pen", func_pen },
{ 0, 0 }
};
diff --git a/reactos/subsystems/win32/win32k/include/brush.h b/reactos/subsystems/win32/win32k/include/brush.h
index 54b2a4b7369..e33e952fb90 100644
--- a/reactos/subsystems/win32/win32k/include/brush.h
+++ b/reactos/subsystems/win32/win32k/include/brush.h
@@ -72,6 +72,8 @@ typedef struct
#define BRUSHOBJ_FreeBrush(hBrush) GDIOBJ_FreeObj(GdiHandleTable, (HGDIOBJ)hBrush, GDI_OBJECT_TYPE_BRUSH)
#define BRUSHOBJ_LockBrush(hBrush) ((PGDIBRUSHOBJ)GDIOBJ_LockObj(GdiHandleTable, (HGDIOBJ)hBrush, GDI_OBJECT_TYPE_BRUSH))
#define BRUSHOBJ_UnlockBrush(pBrush) GDIOBJ_UnlockObjByPtr(GdiHandleTable, pBrush)
+
+INT FASTCALL BRUSH_GetObject (PGDIBRUSHOBJ GdiObject, INT Count, LPLOGBRUSH Buffer);
BOOL INTERNAL_CALL BRUSH_Cleanup(PVOID ObjectBody);
#endif
diff --git a/reactos/subsystems/win32/win32k/include/dc.h b/reactos/subsystems/win32/win32k/include/dc.h
index 00afe1ec3ea..c23f894f3ff 100644
--- a/reactos/subsystems/win32/win32k/include/dc.h
+++ b/reactos/subsystems/win32/win32k/include/dc.h
@@ -188,6 +188,11 @@ VOID FASTCALL DC_SetOwnership(HDC DC, PEPROCESS Owner);
VOID FASTCALL DC_UpdateXforms(PDC dc);
BOOL FASTCALL DC_InvertXform(const XFORM *xformSrc, XFORM *xformDest);
+VOID FASTCALL IntGetViewportExtEx(PDC dc, LPSIZE pt);
+VOID FASTCALL IntGetViewportOrgEx(PDC dc, LPPOINT pt);
+VOID FASTCALL IntGetWindowExtEx(PDC dc, LPSIZE pt);
+VOID FASTCALL IntGetWindowOrgEx(PDC dc, LPPOINT pt);
+
/* For Metafile and MetaEnhFile not in windows this struct taken from wine cvs 15/9-2006*/
typedef struct
{
@@ -195,5 +200,4 @@ typedef struct
BOOL on_disk; /* true if metafile is on disk */
} DD_ENHMETAFILEOBJ, *PDD_ENHMETAFILEOBJ;
-
-#endif
+#endif /* __WIN32K_DC_H */
diff --git a/reactos/subsystems/win32/win32k/include/path.h b/reactos/subsystems/win32/win32k/include/path.h
index 9fcce87cf83..3ba47d2d556 100644
--- a/reactos/subsystems/win32/win32k/include/path.h
+++ b/reactos/subsystems/win32/win32k/include/path.h
@@ -19,7 +19,7 @@ BOOL FASTCALL PATH_PolylineTo (PDC dc, const POINT *pts, DWORD cbPoints);
BOOL FASTCALL PATH_PolyPolygon ( PDC dc, const POINT* pts, const INT* counts, UINT polygons);
BOOL FASTCALL PATH_PolyPolyline( PDC dc, const POINT* pts, const DWORD* counts, DWORD polylines);
BOOL FASTCALL PATH_Rectangle (PDC dc, INT x1, INT y1, INT x2, INT y2);
-BOOL FASTCALL PATH_RoundRect (PDC dc, INT x1, INT y1, INT x2, INT y2, INT xradius, INT yradius);
+BOOL FASTCALL PATH_RoundRect(DC *dc, INT x1, INT y1, INT x2, INT y2, INT ell_width, INT ell_height);
BOOL FASTCALL PATH_PathToRegion (GdiPath *pPath, INT nPolyFillMode, HRGN *pHrgn);
#endif /* _WIN32K_PATH_H */
diff --git a/reactos/subsystems/win32/win32k/include/pen.h b/reactos/subsystems/win32/win32k/include/pen.h
index e8c2a51c2de..01cb035a686 100644
--- a/reactos/subsystems/win32/win32k/include/pen.h
+++ b/reactos/subsystems/win32/win32k/include/pen.h
@@ -11,4 +11,6 @@
#define PENOBJ_LockPen(hBMObj) ((PGDIBRUSHOBJ)GDIOBJ_LockObj(GdiHandleTable, (HGDIOBJ) hBMObj, GDI_OBJECT_TYPE_PEN))
#define PENOBJ_UnlockPen(pPenObj) GDIOBJ_UnlockObjByPtr(GdiHandleTable, pPenObj)
+INT STDCALL PEN_GetObject(PGDIBRUSHOBJ hPen, INT Count, PLOGPEN Buffer);
+
#endif
diff --git a/reactos/subsystems/win32/win32k/objects/bitmaps.c b/reactos/subsystems/win32/win32k/objects/bitmaps.c
index f2cd1180f35..5d0947f28cc 100644
--- a/reactos/subsystems/win32/win32k/objects/bitmaps.c
+++ b/reactos/subsystems/win32/win32k/objects/bitmaps.c
@@ -437,7 +437,12 @@ IntCreateBitmapIndirect(CONST BITMAP *BM)
Size.cx, Size.cy, BitsPixel, hBitmap);
bmp = BITMAPOBJ_LockBitmap( hBitmap );
- /* FIXME - bmp can be NULL!!!!!! */
+ if (bmp == NULL)
+ {
+ /* FIXME should we free the hBitmap or return it ?? */
+ return 0;
+ }
+
bmp->flFlags = BITMAPOBJ_IS_APIBITMAP;
BITMAPOBJ_UnlockBitmap( bmp );
@@ -1071,10 +1076,6 @@ NtGdiSetPixel(
DPRINT("0 NtGdiSetPixel X %ld Y %ld C %ld\n",X,Y,Color);
- if (((Color>>24) & 0xff)<0x10)
- {
- Color = ((Color>>16) & 0x0000ff) | ((Color<<16) & 0xff0000) | (Color & 0x00ff00);
- }
DPRINT("0 NtGdiSetPixel X %ld Y %ld C %ld\n",X,Y,Color);
@@ -1083,7 +1084,6 @@ NtGdiSetPixel(
Color = NtGdiGetPixel(hDC,X,Y);
DPRINT("1 NtGdiSetPixel X %ld Y %ld C %ld\n",X,Y,Color);
return Color;
-
}
Color = ((COLORREF) -1);
@@ -1561,8 +1561,12 @@ BITMAPOBJ_CopyBitmap(HBITMAP hBitmap)
INT STDCALL
BITMAP_GetObject(BITMAPOBJ * bmp, INT count, LPVOID buffer)
{
+ if( !buffer ) return sizeof(BITMAP);
+ if (count < sizeof(BITMAP)) return 0;
+
if(bmp->dib)
{
+
if(count < (INT) sizeof(DIBSECTION))
{
if (count > (INT) sizeof(BITMAP)) count = sizeof(BITMAP);
@@ -1584,7 +1588,8 @@ BITMAP_GetObject(BITMAPOBJ * bmp, INT count, LPVOID buffer)
Bitmap.bmWidthBytes = abs(bmp->SurfObj.lDelta);
Bitmap.bmPlanes = 1;
Bitmap.bmBitsPixel = BitsPerFormat(bmp->SurfObj.iBitmapFormat);
- Bitmap.bmBits = bmp->SurfObj.pvBits;
+ //Bitmap.bmBits = bmp->SurfObj.pvBits;
+ Bitmap.bmBits = NULL; /* not set accoring wine test confirm in win2k */
memcpy(buffer, &Bitmap, count);
return count;
}
diff --git a/reactos/subsystems/win32/win32k/objects/brush.c b/reactos/subsystems/win32/win32k/objects/brush.c
index ca2dbdea09c..4e74f8fc8f0 100644
--- a/reactos/subsystems/win32/win32k/objects/brush.c
+++ b/reactos/subsystems/win32/win32k/objects/brush.c
@@ -49,6 +49,67 @@ BRUSH_Cleanup(PVOID ObjectBody)
return TRUE;
}
+INT FASTCALL
+BRUSH_GetObject (PGDIBRUSHOBJ BrushObject, INT Count, LPLOGBRUSH Buffer)
+{
+ if (Buffer)
+ {
+
+ /* Set colour */
+ Buffer->lbColor = BrushObject->BrushAttr.lbColor;
+
+ /* set Hatch */
+ if ((BrushObject->flAttrs & GDIBRUSH_IS_HATCH)!=0)
+ {
+ /* FIXME : is this right value */
+ Buffer->lbHatch = (LONG)BrushObject->hbmPattern;
+ }
+ else
+ {
+ Buffer->lbHatch = 0;
+ }
+
+ Buffer->lbStyle = 0;
+
+ /* Get the type of style */
+ if ((BrushObject->flAttrs & GDIBRUSH_IS_SOLID)!=0)
+ {
+ Buffer->lbStyle = BS_SOLID;
+ }
+ else if ((BrushObject->flAttrs & GDIBRUSH_IS_NULL)!=0)
+ {
+ Buffer->lbStyle = BS_NULL; // BS_HOLLOW
+ }
+ else if ((BrushObject->flAttrs & GDIBRUSH_IS_HATCH)!=0)
+ {
+ Buffer->lbStyle = BS_HATCHED;
+ }
+ else if ((BrushObject->flAttrs & GDIBRUSH_IS_BITMAP)!=0)
+ {
+ Buffer->lbStyle = BS_PATTERN;
+ }
+ else if ((BrushObject->flAttrs & GDIBRUSH_IS_DIB)!=0)
+ {
+ Buffer->lbStyle = BS_DIBPATTERN;
+ }
+
+ /* FIXME
+ else if ((BrushObject->flAttrs & )!=0)
+ {
+ Buffer->lbStyle = BS_INDEXED;
+ }
+
+ else if ((BrushObject->flAttrs & )!=0)
+ {
+ Buffer->lbStyle = BS_DIBPATTERNPT;
+ }
+ */
+
+ }
+ return sizeof(BRUSHOBJ);
+}
+
+
XLATEOBJ* FASTCALL
IntGdiCreateBrushXlate(PDC Dc, GDIBRUSHOBJ *BrushObj, BOOLEAN *Failed)
{
@@ -402,7 +463,8 @@ IntGdiCreateSolidBrush(
ASSERT(BrushObject != NULL);
BrushObject->flAttrs |= GDIBRUSH_IS_SOLID;
- BrushObject->BrushAttr.lbColor = Color & 0xFFFFFF;
+
+ BrushObject->BrushAttr.lbColor = Color;
/* FIXME: Fill in the rest of fields!!! */
BRUSHOBJ_UnlockBrush(BrushObject);
diff --git a/reactos/subsystems/win32/win32k/objects/coord.c b/reactos/subsystems/win32/win32k/objects/coord.c
index ea37b6a4b40..1b91251e947 100644
--- a/reactos/subsystems/win32/win32k/objects/coord.c
+++ b/reactos/subsystems/win32/win32k/objects/coord.c
@@ -795,6 +795,12 @@ NtGdiSetViewportExtEx(HDC hDC,
1);
Size->cx = dc->vportExtX;
Size->cy = dc->vportExtY;
+
+ dc->vportExtX = XExtent;
+ dc->vportExtY = YExtent;
+
+ if (dc->w.MapMode == MM_ISOTROPIC)
+ IntFixIsotropicMapping(dc);
}
_SEH_HANDLE
{
@@ -810,11 +816,7 @@ NtGdiSetViewportExtEx(HDC hDC,
}
}
- dc->vportExtX = XExtent;
- dc->vportExtY = YExtent;
-
- if (dc->w.MapMode == MM_ISOTROPIC)
- IntFixIsotropicMapping(dc);
+
DC_UpdateXforms(dc);
DC_UnlockDc(dc);
diff --git a/reactos/subsystems/win32/win32k/objects/dc.c b/reactos/subsystems/win32/win32k/objects/dc.c
index f3a43d4607e..cb7b0278103 100644
--- a/reactos/subsystems/win32/win32k/objects/dc.c
+++ b/reactos/subsystems/win32/win32k/objects/dc.c
@@ -1716,6 +1716,7 @@ NtGdiGetDeviceCaps(HDC hDC,
DC_GET_VAL( INT, NtGdiGetMapMode, w.MapMode )
DC_GET_VAL( INT, NtGdiGetPolyFillMode, w.polyFillMode )
+
INT FASTCALL
IntGdiGetObject(HANDLE Handle, INT Count, LPVOID Buffer)
{
@@ -1733,14 +1734,15 @@ IntGdiGetObject(HANDLE Handle, INT Count, LPVOID Buffer)
ObjectType = GDIOBJ_GetObjectType(Handle);
switch (ObjectType)
{
-#if 0
+
case GDI_OBJECT_TYPE_PEN:
- Result = PEN_GetObject((PENOBJ *) GdiObject, Count, Buffer);
+ Result = PEN_GetObject((PGDIBRUSHOBJ) GdiObject, Count, (PLOGPEN) Buffer); // IntGdiCreatePenIndirect
break;
+
case GDI_OBJECT_TYPE_BRUSH:
- Result = BRUSH_GetObject((BRUSHOBJ *) GdiObject, Count, Buffer);
+ Result = BRUSH_GetObject((PGDIBRUSHOBJ ) GdiObject, Count, (LPLOGBRUSH)Buffer);
break;
-#endif
+
case GDI_OBJECT_TYPE_BITMAP:
Result = BITMAP_GetObject((BITMAPOBJ *) GdiObject, Count, Buffer);
break;
@@ -1938,55 +1940,57 @@ NtGdiRestoreDC(HDC hDC, INT SaveLevel)
return FALSE;
}
- if (SaveLevel == -1)
- SaveLevel = dc->saveLevel;
-
- if ((SaveLevel < 1) || (SaveLevel > dc->saveLevel))
+ if(abs(SaveLevel) > dc->saveLevel || SaveLevel == 0)
{
DC_UnlockDc(dc);
return FALSE;
}
- success = TRUE;
+ /* FIXME this calc are not 100% correct I think ??*/
+ if (SaveLevel < 0) SaveLevel = dc->saveLevel + SaveLevel + 1;
+
+ success=TRUE;
while (dc->saveLevel >= SaveLevel)
{
- HDC hdcs = DC_GetNextDC (dc);
+ HDC hdcs = DC_GetNextDC (dc);
- dcs = DC_LockDc (hdcs);
- if (dcs == NULL)
- {
- DC_UnlockDc(dc);
- return FALSE;
- }
- DC_SetNextDC (dcs, DC_GetNextDC (dcs));
- if (--dc->saveLevel < SaveLevel)
- {
- DC_UnlockDc( dc );
- DC_UnlockDc( dcs );
- NtGdiSetDCState(hDC, hdcs);
-#if 0
- if (!PATH_AssignGdiPath( &dc->w.path, &dcs->w.path ))
- {
- /* FIXME: This might not be quite right, since we're
- * returning FALSE but still destroying the saved DC state */
- success = FALSE;
- }
-#endif
- dc = DC_LockDc(hDC);
- if(!dc)
- {
- return FALSE;
- }
- }
- else
- {
- DC_UnlockDc( dcs );
- }
- NtGdiDeleteObjectApp (hdcs);
+ dcs = DC_LockDc (hdcs);
+ if (dcs == NULL)
+ {
+ DC_UnlockDc(dc);
+ return FALSE;
+ }
+
+ DC_SetNextDC (dc, DC_GetNextDC (dcs));
+ dcs->hNext = 0;
+
+ if (--dc->saveLevel < SaveLevel)
+ {
+ DC_UnlockDc( dc );
+ DC_UnlockDc( dcs );
+
+ NtGdiSetDCState(hDC, hdcs);
+ //if (!PATH_AssignGdiPath( &dc->path, &dcs->path ))
+ /* FIXME: This might not be quite right, since we're
+ * returning FALSE but still destroying the saved DC state
+ */
+ success=FALSE;
+ dc = DC_LockDc(hDC);
+ if(!dc)
+ {
+ return FALSE;
+ }
+ }
+ else
+ {
+ DC_UnlockDc( dcs );
+ }
+ NtGdiDeleteObjectApp (hdcs);
}
DC_UnlockDc( dc );
return success;
}
+
INT STDCALL
NtGdiSaveDC(HDC hDC)
diff --git a/reactos/subsystems/win32/win32k/objects/dibobj.c b/reactos/subsystems/win32/win32k/objects/dibobj.c
index 18b2eff6058..ca3eaa4d891 100644
--- a/reactos/subsystems/win32/win32k/objects/dibobj.c
+++ b/reactos/subsystems/win32/win32k/objects/dibobj.c
@@ -793,7 +793,16 @@ HBITMAP STDCALL NtGdiCreateDIBitmap(HDC hDc, const BITMAPINFOHEADER *Header,
PDC Dc;
HBITMAP Bmp;
-
+ if (Header == NULL)
+ {
+ return NULL;
+ }
+
+ if (Header->biSize == 0)
+ {
+ return NULL;
+ }
+
if (NULL == hDc)
{
BITMAPINFOHEADER *change_Header = (BITMAPINFOHEADER *)Header;
diff --git a/reactos/subsystems/win32/win32k/objects/metafile.c b/reactos/subsystems/win32/win32k/objects/metafile.c
index 908e2cdcfbd..fbe95b61bdc 100644
--- a/reactos/subsystems/win32/win32k/objects/metafile.c
+++ b/reactos/subsystems/win32/win32k/objects/metafile.c
@@ -37,21 +37,8 @@ NtGdiCloseEnhMetaFile(HDC hDC)
IO_STATUS_BLOCK Iosb;
NTSTATUS Status;
- DPRINT1("NtGdiCloseEnhMetaFile\n");
-
- /* Todo
- Rewrite it to own api call IntGdiCloseEmhMetaFile
-
- Translate follow api to kernel api
- // hMapping = CreateFileMappingW(Dc->hFile, NULL, PAGE_READONLY, 0, 0, NULL);
- // Dc->emh = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
- // hmf = EMF_Create_HENHMETAFILE( Dc->emh, (Dc->hFile != 0) );
-
-
- DC_SetOwnership(hdc,
- */
-
-
+
+
Dc = DC_LockDc(hDC);
if (Dc == NULL)
{
@@ -121,34 +108,47 @@ NtGdiCloseEnhMetaFile(HDC hDC)
LARGE_INTEGER Distance ;
IO_STATUS_BLOCK IoStatusBlock;
+ POBJECT_ATTRIBUTES ObjectAttributes = NULL;
+ ACCESS_MASK DesiredAccess;
+ PLARGE_INTEGER SectionSize = NULL;
+ DWORD flProtect;
+ ULONG Attributes;
+ LARGE_INTEGER SectionOffset;
+ ULONG ViewSize;
+ ULONG Protect;
+ LPVOID ViewBase;
+
Distance.u.LowPart = 0;
Distance.u.HighPart = 0;
FilePosition.CurrentByteOffset.QuadPart = Distance.QuadPart;
+ DPRINT1("Trying write to metafile and map it\n");
+
Status = NtSetInformationFile(Dc->hFile, &IoStatusBlock, &FilePosition,
sizeof(FILE_POSITION_INFORMATION), FilePositionInformation);
if (!NT_SUCCESS(Status))
{
- /* FIXME */
- // SetLastErrorByStatus(errCode);
+ // SetLastErrorByStatus(Status);
SetLastWin32Error(ERROR_INVALID_HANDLE);
NtClose( Dc->hFile );
DC_UnlockDc(Dc);
NtGdiDeleteObjectApp(hDC);
+
+ DPRINT1("NtSetInformationFile fail\n");
return hmf;
}
if (FilePosition.CurrentByteOffset.u.LowPart != 0)
{
- /* FIXME */
- // SetLastErrorByStatus(errCode);
+ // SetLastErrorByStatus(Status);
SetLastWin32Error(ERROR_INVALID_HANDLE);
NtClose( Dc->hFile );
DC_UnlockDc(Dc);
NtGdiDeleteObjectApp(hDC);
+ DPRINT1("FilePosition.CurrentByteOffset.u.LowPart is not 0\n");
return hmf;
}
@@ -166,19 +166,68 @@ NtGdiCloseEnhMetaFile(HDC hDC)
{
NtClose( Dc->hFile );
DC_UnlockDc(Dc);
- NtGdiDeleteObjectApp(hDC);
+ NtGdiDeleteObjectApp(hDC);
+ DPRINT1("fail to write 0\n");
return hmf;
}
EngFreeMem(Dc->emh);
- /* FIXME */
- // hMapping = CreateFileMappingW(Dc->hFile, NULL, PAGE_READONLY, 0, 0, NULL);
-
- /* FIXME */
- // Dc->emh = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
- NtClose( hMapping );
- NtClose( Dc->hFile );
+ /* create maping */
+ DesiredAccess = STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ;
+ Attributes = (PAGE_READONLY & (SEC_FILE | SEC_IMAGE | SEC_RESERVE | SEC_NOCACHE | SEC_COMMIT));
+ flProtect = PAGE_READONLY ^ (PAGE_READONLY & (SEC_FILE | SEC_IMAGE | SEC_RESERVE | SEC_NOCACHE | SEC_COMMIT));
+
+ if (!Attributes) Attributes = SEC_COMMIT;
+
+ if (Dc->hFile == INVALID_HANDLE_VALUE)
+ {
+ Dc->hFile = NULL;
+ if (!SectionSize)
+ {
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ hMapping = NULL;
+ DPRINT1("fail !SectionSize \n");
+ }
+ }
+ else
+ {
+ Status = NtCreateSection(&hMapping, DesiredAccess, ObjectAttributes, SectionSize, flProtect, Attributes, Dc->hFile);
+ if (!NT_SUCCESS(Status))
+ {
+ //SetLastErrorByStatus(Status);
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ hMapping = NULL;
+ DPRINT1("fail NtCreateSection \n");
+ }
+ }
+
+ /* MapViewOfFile */
+ SectionOffset.LowPart = 0;
+ SectionOffset.HighPart = 0;
+ ViewBase = NULL;
+ ViewSize = 0;
+
+ Protect = PAGE_READONLY;
+
+ Status = ZwMapViewOfSection(&hMapping, NtCurrentProcess(), &ViewBase, 0,
+ 0, &SectionOffset, &ViewSize, ViewShare, 0, Protect);
+ if (!NT_SUCCESS(Status))
+ {
+ //SetLastErrorByStatus(Status);
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ Dc->emh = NULL;
+ DPRINT1("fail ZwMapViewOfSection \n");
+ }
+ else
+ {
+ Dc->emh = ViewBase;
+ }
+ /* Close */
+ if (hMapping != NULL)
+ NtClose( hMapping );
+ if (Dc->hFile != NULL)
+ NtClose( Dc->hFile );
}
hmf = GDIOBJ_AllocObj(GdiHandleTable, GDI_OBJECT_TYPE_ENHMETAFILE);
diff --git a/reactos/subsystems/win32/win32k/objects/path.c b/reactos/subsystems/win32/win32k/objects/path.c
index 27de4689ca5..91862d5f3d5 100644
--- a/reactos/subsystems/win32/win32k/objects/path.c
+++ b/reactos/subsystems/win32/win32k/objects/path.c
@@ -33,12 +33,12 @@ BOOL FASTCALL PATH_AddFlatBezier (GdiPath *pPath, POINT *pt, BOOL closed);
BOOL FASTCALL PATH_DoArcPart (GdiPath *pPath, FLOAT_POINT corners[], double angleStart, double angleEnd, BOOL addMoveTo);
BOOL FASTCALL PATH_FillPath( PDC dc, GdiPath *pPath );
BOOL FASTCALL PATH_FlattenPath (GdiPath *pPath);
-VOID FASTCALL PATH_GetPathFromDC (PDC dc, GdiPath **ppPath);
VOID FASTCALL PATH_NormalizePoint (FLOAT_POINT corners[], const FLOAT_POINT *pPoint, double *pX, double *pY);
BOOL FASTCALL PATH_PathToRegion (GdiPath *pPath, INT nPolyFillMode, HRGN *pHrgn);
BOOL FASTCALL PATH_ReserveEntries (GdiPath *pPath, INT numEntries);
VOID FASTCALL PATH_ScaleNormalizedPoint (FLOAT_POINT corners[], double x, double y, POINT *pPoint);
-
+BOOL FASTCALL PATH_StrokePath(DC *dc, GdiPath *pPath);
+BOOL PATH_CheckCorners(DC *dc, POINT corners[], INT x1, INT y1, INT x2, INT y2);
INT FASTCALL
IntGdiGetArcDirection(DC *dc);
@@ -51,16 +51,12 @@ BOOL
STDCALL
NtGdiAbortPath(HDC hDC)
{
- GdiPath *pPath;
BOOL ret = TRUE;
PDC dc = DC_LockDc ( hDC );
if( !dc ) return FALSE;
- /* Get pointer to path */
- PATH_GetPathFromDC ( dc, &pPath );
-
- PATH_EmptyPath( pPath );
+ PATH_EmptyPath(&dc->w.path);
DC_UnlockDc ( dc );
return ret;
@@ -70,24 +66,20 @@ BOOL
STDCALL
NtGdiBeginPath( HDC hDC )
{
- GdiPath *pPath;
BOOL ret = TRUE;
PDC dc = DC_LockDc ( hDC );
if( !dc ) return FALSE;
-
- /* Get pointer to path */
- PATH_GetPathFromDC ( dc, &pPath );
/* If path is already open, do nothing */
- if ( pPath->state != PATH_Open )
+ if ( dc->w.path.state != PATH_Open )
{
/* Make sure that path is empty */
- PATH_EmptyPath( pPath );
+ PATH_EmptyPath( &dc->w.path );
/* Initialize variables for new path */
- pPath->newStroke = TRUE;
- pPath->state = PATH_Open;
+ dc->w.path.newStroke = TRUE;
+ dc->w.path.state = PATH_Open;
}
DC_UnlockDc ( dc );
@@ -142,22 +134,18 @@ BOOL
STDCALL
NtGdiEndPath(HDC hDC)
{
- GdiPath *pPath;
BOOL ret = TRUE;
PDC dc = DC_LockDc ( hDC );
if ( !dc ) return FALSE;
- /* Get pointer to path */
- PATH_GetPathFromDC ( dc, &pPath );
-
/* Check that path is currently being constructed */
- if( pPath->state != PATH_Open )
+ if( dc->w.path.state != PATH_Open )
{
ret = FALSE;
}
/* Set flag to indicate that path is finished */
- else pPath->state = PATH_Closed;
+ else dc->w.path.state = PATH_Closed;
DC_UnlockDc ( dc );
return ret;
@@ -167,21 +155,17 @@ BOOL
STDCALL
NtGdiFillPath(HDC hDC)
{
- GdiPath *pPath;
BOOL ret = TRUE;
PDC dc = DC_LockDc ( hDC );
if ( !dc ) return FALSE;
-
- /* Get pointer to path */
- PATH_GetPathFromDC ( dc, &pPath );
- ret = PATH_FillPath( dc, pPath );
+ ret = PATH_FillPath( dc, &dc->w.path );
if( ret )
{
/* FIXME: Should the path be emptied even if conversion
failed? */
- PATH_EmptyPath( pPath );
+ PATH_EmptyPath( &dc->w.path );
}
DC_UnlockDc ( dc );
@@ -259,8 +243,8 @@ NtGdiGetPath(
{
_SEH_TRY
{
- RtlCopyMemory(Points, pPath->pPoints, sizeof(POINT)*pPath->numEntriesUsed);
- RtlCopyMemory(Types, pPath->pFlags, sizeof(BYTE)*pPath->numEntriesUsed);
+ memcpy(Points, pPath->pPoints, sizeof(POINT)*pPath->numEntriesUsed);
+ memcpy(Types, pPath->pFlags, sizeof(BYTE)*pPath->numEntriesUsed);
/* Convert the points to logical coordinates */
IntDPtoLP(dc, Points, pPath->numEntriesUsed);
@@ -323,18 +307,39 @@ NtGdiSetMiterLimit(
BOOL
STDCALL
-NtGdiStrokeAndFillPath(HDC hDC)
+NtGdiStrokeAndFillPath(HDC hDC)
{
- UNIMPLEMENTED;
- return FALSE;
+ DC *pDc;
+ BOOL bRet = FALSE;
+
+ DPRINT("Enter %s\n", __FUNCTION__);
+
+ if(!(pDc = DC_LockDc(hDC))) return FALSE;
+
+ bRet = PATH_FillPath(pDc, &pDc->w.path);
+ if(bRet) bRet = PATH_StrokePath(pDc, &pDc->w.path);
+ if(bRet) PATH_EmptyPath(&pDc->w.path);
+
+ DC_UnlockDc(pDc);
+ return bRet;
}
BOOL
STDCALL
-NtGdiStrokePath(HDC hDC)
+NtGdiStrokePath(HDC hDC)
{
- UNIMPLEMENTED;
- return FALSE;
+ DC *pDc;
+ BOOL bRet = FALSE;
+
+ DPRINT("Enter %s\n", __FUNCTION__);
+
+ if(!(pDc = DC_LockDc(hDC))) return FALSE;
+
+ bRet = PATH_StrokePath(pDc, &pDc->w.path);
+ PATH_EmptyPath(&pDc->w.path);
+
+ DC_UnlockDc(pDc);
+ return bRet;
}
BOOL
@@ -348,30 +353,27 @@ NtGdiWidenPath(HDC hDC)
BOOL STDCALL NtGdiSelectClipPath(HDC hDC,
int Mode)
{
- GdiPath *pPath;
HRGN hrgnPath;
BOOL success = FALSE;
PDC dc = DC_LockDc ( hDC );
if( !dc ) return FALSE;
- PATH_GetPathFromDC ( dc, &pPath );
-
/* Check that path is closed */
- if( pPath->state != PATH_Closed )
+ if( dc->w.path.state != PATH_Closed )
{
SetLastWin32Error(ERROR_CAN_NOT_COMPLETE);
return FALSE;
}
/* Construct a region from the path */
- else if( PATH_PathToRegion( pPath, dc->w.polyFillMode, &hrgnPath ) )
+ else if( PATH_PathToRegion( &dc->w.path, dc->w.polyFillMode, &hrgnPath ) )
{
success = IntGdiExtSelectClipRgn( dc, hrgnPath, Mode ) != ERROR;
NtGdiDeleteObject( hrgnPath );
/* Empty the path */
if( success )
- PATH_EmptyPath( pPath );
+ PATH_EmptyPath( &dc->w.path);
/* FIXME: Should this function delete the path even if it failed? */
}
@@ -466,7 +468,7 @@ VOID
FASTCALL
PATH_InitGdiPath ( GdiPath *pPath )
{
- assert(pPath!=NULL);
+ ASSERT(pPath!=NULL);
pPath->state=PATH_Null;
pPath->pPoints=NULL;
@@ -483,7 +485,7 @@ VOID
FASTCALL
PATH_DestroyGdiPath ( GdiPath *pPath )
{
- assert(pPath!=NULL);
+ ASSERT(pPath!=NULL);
ExFreePool(pPath->pPoints);
ExFreePool(pPath->pFlags);
@@ -503,7 +505,7 @@ BOOL
FASTCALL
PATH_AssignGdiPath ( GdiPath *pPathDest, const GdiPath *pPathSrc )
{
- assert(pPathDest!=NULL && pPathSrc!=NULL);
+ ASSERT(pPathDest!=NULL && pPathSrc!=NULL);
/* Make sure destination arrays are big enough */
if ( !PATH_ReserveEntries(pPathDest, pPathSrc->numEntriesUsed) )
@@ -532,18 +534,14 @@ BOOL
FASTCALL
PATH_MoveTo ( PDC dc )
{
- GdiPath *pPath;
-
- /* Get pointer to path */
- PATH_GetPathFromDC ( dc, &pPath );
/* Check that path is open */
- if ( pPath->state != PATH_Open )
+ if ( dc->w.path.state != PATH_Open )
/* FIXME: Do we have to call SetLastError? */
return FALSE;
/* Start a new stroke */
- pPath->newStroke = TRUE;
+ dc->w.path.newStroke = TRUE;
return TRUE;
}
@@ -559,14 +557,10 @@ BOOL
FASTCALL
PATH_LineTo ( PDC dc, INT x, INT y )
{
- GdiPath *pPath;
POINT point, pointCurPos;
- /* Get pointer to path */
- PATH_GetPathFromDC ( dc, &pPath );
-
/* Check that path is open */
- if ( pPath->state != PATH_Open )
+ if ( dc->w.path.state != PATH_Open )
return FALSE;
/* Convert point to device coordinates */
@@ -575,17 +569,17 @@ PATH_LineTo ( PDC dc, INT x, INT y )
CoordLPtoDP ( dc, &point );
/* Add a PT_MOVETO if necessary */
- if ( pPath->newStroke )
+ if ( dc->w.path.newStroke )
{
- pPath->newStroke = FALSE;
+ dc->w.path.newStroke = FALSE;
IntGetCurrentPositionEx ( dc, &pointCurPos );
CoordLPtoDP ( dc, &pointCurPos );
- if ( !PATH_AddEntry(pPath, &pointCurPos, PT_MOVETO) )
+ if ( !PATH_AddEntry(&dc->w.path, &pointCurPos, PT_MOVETO) )
return FALSE;
}
/* Add a PT_LINETO entry */
- return PATH_AddEntry(pPath, &point, PT_LINETO);
+ return PATH_AddEntry(&dc->w.path, &point, PT_LINETO);
}
/* PATH_Rectangle
@@ -597,15 +591,11 @@ BOOL
FASTCALL
PATH_Rectangle ( PDC dc, INT x1, INT y1, INT x2, INT y2 )
{
- GdiPath *pPath;
POINT corners[2], pointTemp;
INT temp;
- /* Get pointer to path */
- PATH_GetPathFromDC ( dc, &pPath );
-
/* Check that path is open */
- if ( pPath->state != PATH_Open )
+ if ( dc->w.path.state != PATH_Open )
return FALSE;
/* Convert points to device coordinates */
@@ -642,15 +632,15 @@ PATH_Rectangle ( PDC dc, INT x1, INT y1, INT x2, INT y2 )
/* Add four points to the path */
pointTemp.x=corners[1].x;
pointTemp.y=corners[0].y;
- if ( !PATH_AddEntry(pPath, &pointTemp, PT_MOVETO) )
+ if ( !PATH_AddEntry(&dc->w.path, &pointTemp, PT_MOVETO) )
return FALSE;
- if ( !PATH_AddEntry(pPath, corners, PT_LINETO) )
+ if ( !PATH_AddEntry(&dc->w.path, corners, PT_LINETO) )
return FALSE;
pointTemp.x=corners[0].x;
pointTemp.y=corners[1].y;
- if ( !PATH_AddEntry(pPath, &pointTemp, PT_LINETO) )
+ if ( !PATH_AddEntry(&dc->w.path, &pointTemp, PT_LINETO) )
return FALSE;
- if ( !PATH_AddEntry(pPath, corners+1, PT_LINETO) )
+ if ( !PATH_AddEntry(&dc->w.path, corners+1, PT_LINETO) )
return FALSE;
/* Close the rectangle figure */
@@ -659,12 +649,63 @@ PATH_Rectangle ( PDC dc, INT x1, INT y1, INT x2, INT y2 )
return TRUE;
}
-BOOL
-FASTCALL
-PATH_RoundRect (PDC dc, INT x1, INT y1, INT x2, INT y2, INT xradius, INT yradius)
+/* PATH_RoundRect
+ *
+ * Should be called when a call to RoundRect is performed on a DC that has
+ * an open path. Returns TRUE if successful, else FALSE.
+ *
+ * FIXME: it adds the same entries to the path as windows does, but there
+ * is an error in the bezier drawing code so that there are small pixel-size
+ * gaps when the resulting path is drawn by StrokePath()
+ */
+FASTCALL BOOL PATH_RoundRect(DC *dc, INT x1, INT y1, INT x2, INT y2, INT ell_width, INT ell_height)
{
- UNIMPLEMENTED;
- return FALSE;
+ GdiPath *pPath = &dc->w.path;
+ POINT corners[2], pointTemp;
+ FLOAT_POINT ellCorners[2];
+
+ /* Check that path is open */
+ if(pPath->state!=PATH_Open)
+ return FALSE;
+
+ if(!PATH_CheckCorners(dc,corners,x1,y1,x2,y2))
+ return FALSE;
+
+ /* Add points to the roundrect path */
+ ellCorners[0].x = corners[1].x-ell_width;
+ ellCorners[0].y = corners[0].y;
+ ellCorners[1].x = corners[1].x;
+ ellCorners[1].y = corners[0].y+ell_height;
+ if(!PATH_DoArcPart(pPath, ellCorners, 0, -M_PI_2, TRUE))
+ return FALSE;
+ pointTemp.x = corners[0].x+ell_width/2;
+ pointTemp.y = corners[0].y;
+ if(!PATH_AddEntry(pPath, &pointTemp, PT_LINETO))
+ return FALSE;
+ ellCorners[0].x = corners[0].x;
+ ellCorners[1].x = corners[0].x+ell_width;
+ if(!PATH_DoArcPart(pPath, ellCorners, -M_PI_2, -M_PI, FALSE))
+ return FALSE;
+ pointTemp.x = corners[0].x;
+ pointTemp.y = corners[1].y-ell_height/2;
+ if(!PATH_AddEntry(pPath, &pointTemp, PT_LINETO))
+ return FALSE;
+ ellCorners[0].y = corners[1].y-ell_height;
+ ellCorners[1].y = corners[1].y;
+ if(!PATH_DoArcPart(pPath, ellCorners, M_PI, M_PI_2, FALSE))
+ return FALSE;
+ pointTemp.x = corners[1].x-ell_width/2;
+ pointTemp.y = corners[1].y;
+ if(!PATH_AddEntry(pPath, &pointTemp, PT_LINETO))
+ return FALSE;
+ ellCorners[0].x = corners[1].x-ell_width;
+ ellCorners[1].x = corners[1].x;
+ if(!PATH_DoArcPart(pPath, ellCorners, M_PI_2, 0, FALSE))
+ return FALSE;
+
+ IntGdiCloseFigure(dc);
+
+ return TRUE;
}
/* PATH_Ellipse
@@ -693,7 +734,6 @@ FASTCALL
PATH_Arc ( PDC dc, INT x1, INT y1, INT x2, INT y2,
INT xStart, INT yStart, INT xEnd, INT yEnd)
{
- GdiPath *pPath;
double angleStart, angleEnd, angleStartQuadrant, angleEndQuadrant=0.0;
/* Initialize angleEndQuadrant to silence gcc's warning */
double x, y;
@@ -709,11 +749,8 @@ PATH_Arc ( PDC dc, INT x1, INT y1, INT x2, INT y2,
clockwise = ( IntGdiGetArcDirection(dc) == AD_CLOCKWISE );
- /* Get pointer to path */
- PATH_GetPathFromDC ( dc, &pPath );
-
/* Check that path is open */
- if ( pPath->state != PATH_Open )
+ if ( dc->w.path.state != PATH_Open )
return FALSE;
/* FIXME: Do we have to close the current figure? */
@@ -763,7 +800,7 @@ PATH_Arc ( PDC dc, INT x1, INT y1, INT x2, INT y2,
if ( angleEnd <= angleStart )
{
angleEnd+=2*M_PI;
- assert(angleEnd>=angleStart);
+ ASSERT(angleEnd>=angleStart);
}
}
else
@@ -771,7 +808,7 @@ PATH_Arc ( PDC dc, INT x1, INT y1, INT x2, INT y2,
if(angleEnd>=angleStart)
{
angleEnd-=2*M_PI;
- assert(angleEnd<=angleStart);
+ ASSERT(angleEnd<=angleStart);
}
}
@@ -817,7 +854,7 @@ PATH_Arc ( PDC dc, INT x1, INT y1, INT x2, INT y2,
}
/* Add the Bezier spline to the path */
- PATH_DoArcPart ( pPath, corners, angleStartQuadrant, angleEndQuadrant, start );
+ PATH_DoArcPart ( &dc->w.path, corners, angleStartQuadrant, angleEndQuadrant, start );
start = FALSE;
} while(!end);
@@ -828,7 +865,6 @@ BOOL
FASTCALL
PATH_PolyBezierTo ( PDC dc, const POINT *pts, DWORD cbPoints )
{
- GdiPath *pPath;
POINT pt;
ULONG i;
@@ -836,19 +872,17 @@ PATH_PolyBezierTo ( PDC dc, const POINT *pts, DWORD cbPoints )
ASSERT ( pts );
ASSERT ( cbPoints );
- PATH_GetPathFromDC ( dc, &pPath );
-
/* Check that path is open */
- if ( pPath->state != PATH_Open )
+ if ( dc->w.path.state != PATH_Open )
return FALSE;
/* Add a PT_MOVETO if necessary */
- if ( pPath->newStroke )
+ if ( dc->w.path.newStroke )
{
- pPath->newStroke=FALSE;
+ dc->w.path.newStroke=FALSE;
IntGetCurrentPositionEx ( dc, &pt );
CoordLPtoDP ( dc, &pt );
- if ( !PATH_AddEntry(pPath, &pt, PT_MOVETO) )
+ if ( !PATH_AddEntry(&dc->w.path, &pt, PT_MOVETO) )
return FALSE;
}
@@ -856,7 +890,7 @@ PATH_PolyBezierTo ( PDC dc, const POINT *pts, DWORD cbPoints )
{
pt = pts[i];
CoordLPtoDP ( dc, &pt );
- PATH_AddEntry(pPath, &pt, PT_BEZIERTO);
+ PATH_AddEntry(&dc->w.path, &pt, PT_BEZIERTO);
}
return TRUE;
}
@@ -865,7 +899,6 @@ BOOL
FASTCALL
PATH_PolyBezier ( PDC dc, const POINT *pts, DWORD cbPoints )
{
- GdiPath *pPath;
POINT pt;
ULONG i;
@@ -873,17 +906,15 @@ PATH_PolyBezier ( PDC dc, const POINT *pts, DWORD cbPoints )
ASSERT ( pts );
ASSERT ( cbPoints );
- PATH_GetPathFromDC ( dc, &pPath );
-
/* Check that path is open */
- if ( pPath->state != PATH_Open )
+ if ( dc->w.path.state != PATH_Open )
return FALSE;
for ( i = 0; i < cbPoints; i++ )
{
pt = pts[i];
CoordLPtoDP ( dc, &pt );
- PATH_AddEntry ( pPath, &pt, (i == 0) ? PT_MOVETO : PT_BEZIERTO );
+ PATH_AddEntry ( &dc->w.path, &pt, (i == 0) ? PT_MOVETO : PT_BEZIERTO );
}
return TRUE;
@@ -893,7 +924,6 @@ BOOL
FASTCALL
PATH_Polyline ( PDC dc, const POINT *pts, DWORD cbPoints )
{
- GdiPath *pPath;
POINT pt;
ULONG i;
@@ -901,17 +931,15 @@ PATH_Polyline ( PDC dc, const POINT *pts, DWORD cbPoints )
ASSERT ( pts );
ASSERT ( cbPoints );
- PATH_GetPathFromDC ( dc, &pPath );
-
/* Check that path is open */
- if ( pPath->state != PATH_Open )
+ if ( dc->w.path.state != PATH_Open )
return FALSE;
for ( i = 0; i < cbPoints; i++ )
{
pt = pts[i];
CoordLPtoDP ( dc, &pt );
- PATH_AddEntry(pPath, &pt, (i == 0) ? PT_MOVETO : PT_LINETO);
+ PATH_AddEntry(&dc->w.path, &pt, (i == 0) ? PT_MOVETO : PT_LINETO);
}
return TRUE;
}
@@ -920,7 +948,6 @@ BOOL
FASTCALL
PATH_PolylineTo ( PDC dc, const POINT *pts, DWORD cbPoints )
{
- GdiPath *pPath;
POINT pt;
ULONG i;
@@ -928,19 +955,17 @@ PATH_PolylineTo ( PDC dc, const POINT *pts, DWORD cbPoints )
ASSERT ( pts );
ASSERT ( cbPoints );
- PATH_GetPathFromDC ( dc, &pPath );
-
/* Check that path is open */
- if ( pPath->state != PATH_Open )
+ if ( dc->w.path.state != PATH_Open )
return FALSE;
/* Add a PT_MOVETO if necessary */
- if ( pPath->newStroke )
+ if ( dc->w.path.newStroke )
{
- pPath->newStroke = FALSE;
+ dc->w.path.newStroke = FALSE;
IntGetCurrentPositionEx ( dc, &pt );
CoordLPtoDP ( dc, &pt );
- if ( !PATH_AddEntry(pPath, &pt, PT_MOVETO) )
+ if ( !PATH_AddEntry(&dc->w.path, &pt, PT_MOVETO) )
return FALSE;
}
@@ -948,7 +973,7 @@ PATH_PolylineTo ( PDC dc, const POINT *pts, DWORD cbPoints )
{
pt = pts[i];
CoordLPtoDP ( dc, &pt );
- PATH_AddEntry(pPath, &pt, PT_LINETO);
+ PATH_AddEntry(&dc->w.path, &pt, PT_LINETO);
}
return TRUE;
@@ -959,24 +984,21 @@ BOOL
FASTCALL
PATH_Polygon ( PDC dc, const POINT *pts, DWORD cbPoints )
{
- GdiPath *pPath;
POINT pt;
ULONG i;
ASSERT ( dc );
ASSERT ( pts );
- PATH_GetPathFromDC ( dc, &pPath );
-
/* Check that path is open */
- if ( pPath->state != PATH_Open )
+ if ( dc->w.path.state != PATH_Open )
return FALSE;
for(i = 0; i < cbPoints; i++)
{
pt = pts[i];
CoordLPtoDP ( dc, &pt );
- PATH_AddEntry(pPath, &pt, (i == 0) ? PT_MOVETO :
+ PATH_AddEntry(&dc->w.path, &pt, (i == 0) ? PT_MOVETO :
((i == cbPoints-1) ? PT_LINETO | PT_CLOSEFIGURE :
PT_LINETO));
}
@@ -987,7 +1009,6 @@ BOOL
FASTCALL
PATH_PolyPolygon ( PDC dc, const POINT* pts, const INT* counts, UINT polygons )
{
- GdiPath *pPath;
POINT pt, startpt;
ULONG poly, point, i;
@@ -996,10 +1017,8 @@ PATH_PolyPolygon ( PDC dc, const POINT* pts, const INT* counts, UINT polygons )
ASSERT ( counts );
ASSERT ( polygons );
- PATH_GetPathFromDC ( dc, &pPath );
-
/* Check that path is open */
- if ( pPath->state != PATH_Open );
+ if ( dc->w.path.state != PATH_Open );
return FALSE;
for(i = 0, poly = 0; poly < polygons; poly++)
@@ -1009,10 +1028,10 @@ PATH_PolyPolygon ( PDC dc, const POINT* pts, const INT* counts, UINT polygons )
pt = pts[i];
CoordLPtoDP ( dc, &pt );
if(point == 0) startpt = pt;
- PATH_AddEntry(pPath, &pt, (point == 0) ? PT_MOVETO : PT_LINETO);
+ PATH_AddEntry(&dc->w.path, &pt, (point == 0) ? PT_MOVETO : PT_LINETO);
}
/* win98 adds an extra line to close the figure for some reason */
- PATH_AddEntry(pPath, &startpt, PT_LINETO | PT_CLOSEFIGURE);
+ PATH_AddEntry(&dc->w.path, &startpt, PT_LINETO | PT_CLOSEFIGURE);
}
return TRUE;
}
@@ -1021,7 +1040,6 @@ BOOL
FASTCALL
PATH_PolyPolyline ( PDC dc, const POINT* pts, const DWORD* counts, DWORD polylines )
{
- GdiPath *pPath;
POINT pt;
ULONG poly, point, i;
@@ -1030,10 +1048,8 @@ PATH_PolyPolyline ( PDC dc, const POINT* pts, const DWORD* counts, DWORD polylin
ASSERT ( counts );
ASSERT ( polylines );
- PATH_GetPathFromDC ( dc, &pPath );
-
/* Check that path is open */
- if ( pPath->state != PATH_Open )
+ if ( dc->w.path.state != PATH_Open )
return FALSE;
for(i = 0, poly = 0; poly < polylines; poly++)
@@ -1042,7 +1058,7 @@ PATH_PolyPolyline ( PDC dc, const POINT* pts, const DWORD* counts, DWORD polylin
{
pt = pts[i];
CoordLPtoDP ( dc, &pt );
- PATH_AddEntry(pPath, &pt, (point == 0) ? PT_MOVETO : PT_LINETO);
+ PATH_AddEntry(&dc->w.path, &pt, (point == 0) ? PT_MOVETO : PT_LINETO);
}
}
return TRUE;
@@ -1052,6 +1068,46 @@ PATH_PolyPolyline ( PDC dc, const POINT* pts, const DWORD* counts, DWORD polylin
* Internal functions
*/
+/* PATH_CheckCorners
+ *
+ * Helper function for PATH_RoundRect() and PATH_Rectangle()
+ */
+BOOL PATH_CheckCorners(DC *dc, POINT corners[], INT x1, INT y1, INT x2, INT y2)
+{
+ INT temp;
+
+ /* Convert points to device coordinates */
+ corners[0].x=x1;
+ corners[0].y=y1;
+ corners[1].x=x2;
+ corners[1].y=y2;
+ CoordLPtoDP(dc, &corners[0]);
+ CoordLPtoDP(dc, &corners[1]);
+
+ /* Make sure first corner is top left and second corner is bottom right */
+ if(corners[0].x>corners[1].x)
+ {
+ temp=corners[0].x;
+ corners[0].x=corners[1].x;
+ corners[1].x=temp;
+ }
+ if(corners[0].y>corners[1].y)
+ {
+ temp=corners[0].y;
+ corners[0].y=corners[1].y;
+ corners[1].y=temp;
+ }
+
+ /* In GM_COMPATIBLE, don't include bottom and right edges */
+ if(dc->w.GraphicsMode==GM_COMPATIBLE)
+ {
+ corners[1].x--;
+ corners[1].y--;
+ }
+
+ return TRUE;
+}
+
/* PATH_AddFlatBezier
*
@@ -1085,7 +1141,7 @@ PATH_FlattenPath(GdiPath *pPath)
GdiPath newPath;
INT srcpt;
- memset(&newPath, 0, sizeof(newPath));
+ RtlZeroMemory(&newPath, sizeof(newPath));
newPath.state = PATH_Open;
for(srcpt = 0; srcpt < pPath->numEntriesUsed; srcpt++) {
switch(pPath->pFlags[srcpt] & ~PT_CLOSEFIGURE) {
@@ -1123,8 +1179,8 @@ PATH_PathToRegion ( GdiPath *pPath, INT nPolyFillMode, HRGN *pHrgn )
INT *pNumPointsInStroke;
HRGN hrgn = 0;
- assert ( pPath!=NULL );
- assert ( pHrgn!=NULL );
+ ASSERT(pPath!=NULL);
+ ASSERT(pHrgn!=NULL);
PATH_FlattenPath ( pPath );
@@ -1184,7 +1240,7 @@ VOID
FASTCALL
PATH_EmptyPath ( GdiPath *pPath )
{
- assert(pPath!=NULL);
+ ASSERT(pPath!=NULL);
pPath->state=PATH_Null;
pPath->numEntriesUsed=0;
@@ -1200,7 +1256,7 @@ BOOL
FASTCALL
PATH_AddEntry ( GdiPath *pPath, const POINT *pPoint, BYTE flags )
{
- assert(pPath!=NULL);
+ ASSERT(pPath!=NULL);
/* FIXME: If newStroke is true, perhaps we want to check that we're
* getting a PT_MOVETO
@@ -1242,8 +1298,8 @@ PATH_ReserveEntries ( GdiPath *pPath, INT numEntries )
POINT *pPointsNew;
BYTE *pFlagsNew;
- assert(pPath!=NULL);
- assert(numEntries>=0);
+ ASSERT(pPath!=NULL);
+ ASSERT(numEntries>=0);
/* Do we have to allocate more memory? */
if(numEntries > pPath->numEntriesAllocated)
@@ -1273,7 +1329,7 @@ PATH_ReserveEntries ( GdiPath *pPath, INT numEntries )
/* Copy old arrays to new arrays and discard old arrays */
if(pPath->pPoints)
{
- assert(pPath->pFlags);
+ ASSERT(pPath->pFlags);
memcpy(pPointsNew, pPath->pPoints, sizeof(POINT)*pPath->numEntriesUsed);
memcpy(pFlagsNew, pPath->pFlags, sizeof(BYTE)*pPath->numEntriesUsed);
@@ -1289,20 +1345,6 @@ PATH_ReserveEntries ( GdiPath *pPath, INT numEntries )
return TRUE;
}
-/* PATH_GetPathFromDC
- *
- * Retrieves a pointer to the GdiPath structure contained in an HDC and
- * places it in *ppPath. TRUE is returned if successful, FALSE otherwise.
- */
-VOID
-FASTCALL
-PATH_GetPathFromDC ( PDC dc, GdiPath **ppPath )
-{
- ASSERT ( dc );
- ASSERT ( ppPath );
- *ppPath = &dc->w.path;
-}
-
/* PATH_DoArcPart
*
* Creates a Bezier spline that corresponds to part of an arc and appends the
@@ -1322,7 +1364,7 @@ PATH_DoArcPart ( GdiPath *pPath, FLOAT_POINT corners[],
POINT point;
int i;
- assert(fabs(angleEnd-angleStart)<=M_PI_2);
+ ASSERT(fabs(angleEnd-angleStart)<=M_PI_2);
/* FIXME: Is there an easier way of computing this? */
@@ -1401,4 +1443,176 @@ PATH_NormalizePoint ( FLOAT_POINT corners[],
*pX=(double)(pPoint->x-corners[0].x)/(double)(corners[1].x-corners[0].x) * 2.0 - 1.0;
*pY=(double)(pPoint->y-corners[0].y)/(double)(corners[1].y-corners[0].y) * 2.0 - 1.0;
}
+
+
+BOOL FASTCALL PATH_StrokePath(DC *dc, GdiPath *pPath)
+{
+ BOOL ret = FALSE;
+ INT i=0;
+ INT nLinePts, nAlloc;
+ POINT *pLinePts = NULL;
+ POINT ptViewportOrg, ptWindowOrg;
+ SIZE szViewportExt, szWindowExt;
+ DWORD mapMode, graphicsMode;
+ XFORM xform;
+
+ DPRINT("Enter %s\n", __FUNCTION__);
+
+ if(pPath->state != PATH_Closed)
+ return FALSE;
+
+ /* Save the mapping mode info */
+ mapMode=dc->w.MapMode;
+ IntGetViewportExtEx(dc, &szViewportExt);
+ IntGetViewportOrgEx(dc, &ptViewportOrg);
+ IntGetWindowExtEx(dc, &szWindowExt);
+ IntGetWindowOrgEx(dc, &ptWindowOrg);
+ xform = dc->w.xformWorld2Wnd;
+
+ /* Set MM_TEXT */
+ dc->w.MapMode = MM_TEXT;
+ dc->vportOrgX = 0;
+ dc->vportOrgY = 0;
+ dc->wndOrgX = 0;
+ dc->wndOrgY = 0;
+ graphicsMode = dc->w.GraphicsMode;
+ dc->w.GraphicsMode = GM_ADVANCED;
+ IntGdiModifyWorldTransform(dc, &xform, MWT_IDENTITY);
+ dc->w.GraphicsMode = graphicsMode;
+
+ /* Allocate enough memory for the worst case without beziers (one PT_MOVETO
+ * and the rest PT_LINETO with PT_CLOSEFIGURE at the end) plus some buffer
+ * space in case we get one to keep the number of reallocations small. */
+ nAlloc = pPath->numEntriesUsed + 1 + 300;
+ pLinePts = ExAllocatePoolWithTag(PagedPool, nAlloc * sizeof(POINT), TAG_PATH);
+ if(!pLinePts)
+ {
+ DPRINT1("Can't allocate pool!\n");
+ SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+ goto end;
+ }
+ nLinePts = 0;
+
+ for(i = 0; i < pPath->numEntriesUsed; i++)
+ {
+ if((i == 0 || (pPath->pFlags[i-1] & PT_CLOSEFIGURE))
+ && (pPath->pFlags[i] != PT_MOVETO))
+ {
+ DPRINT1("Expected PT_MOVETO %s, got path flag %d\n",
+ i == 0 ? "as first point" : "after PT_CLOSEFIGURE",
+ (INT)pPath->pFlags[i]);
+ goto end;
+ }
+
+ switch(pPath->pFlags[i])
+ {
+ case PT_MOVETO:
+ DPRINT("Got PT_MOVETO (%ld, %ld)\n",
+ pPath->pPoints[i].x, pPath->pPoints[i].y);
+ if(nLinePts >= 2) IntGdiPolyline(dc, pLinePts, nLinePts);
+ nLinePts = 0;
+ pLinePts[nLinePts++] = pPath->pPoints[i];
+ break;
+ case PT_LINETO:
+ case (PT_LINETO | PT_CLOSEFIGURE):
+ DPRINT("Got PT_LINETO (%ld, %ld)\n",
+ pPath->pPoints[i].x, pPath->pPoints[i].y);
+ pLinePts[nLinePts++] = pPath->pPoints[i];
+ break;
+ case PT_BEZIERTO:
+ DPRINT("Got PT_BEZIERTO\n");
+ if(pPath->pFlags[i+1] != PT_BEZIERTO ||
+ (pPath->pFlags[i+2] & ~PT_CLOSEFIGURE) != PT_BEZIERTO)
+ {
+ DPRINT1("Path didn't contain 3 successive PT_BEZIERTOs\n");
+ ret = FALSE;
+ goto end;
+ }
+ else
+ {
+ INT nBzrPts, nMinAlloc;
+ POINT *pBzrPts = GDI_Bezier(&pPath->pPoints[i-1], 4, &nBzrPts);
+ /* Make sure we have allocated enough memory for the lines of
+ * this bezier and the rest of the path, assuming we won't get
+ * another one (since we won't reallocate again then). */
+ nMinAlloc = nLinePts + (pPath->numEntriesUsed - i) + nBzrPts;
+ if(nAlloc < nMinAlloc)
+ {
+ // Reallocate memory
+
+ POINT *Realloc = NULL;
+ nAlloc = nMinAlloc * 2;
+
+ Realloc = ExAllocatePoolWithTag(PagedPool,
+ nAlloc * sizeof(POINT),
+ TAG_PATH);
+
+ if(!Realloc)
+ {
+ DPRINT1("Can't allocate pool!\n");
+ goto end;
+ }
+
+ memcpy(Realloc, pLinePts, nLinePts*sizeof(POINT));
+ ExFreePool(pLinePts);
+ pLinePts = Realloc;
+ }
+ memcpy(&pLinePts[nLinePts], &pBzrPts[1], (nBzrPts - 1) * sizeof(POINT));
+ nLinePts += nBzrPts - 1;
+ ExFreePool(pBzrPts);
+ i += 2;
+ }
+ break;
+ default:
+ DPRINT1("Got path flag %d (not supported)\n", (INT)pPath->pFlags[i]);
+ goto end;
+ }
+
+ if(pPath->pFlags[i] & PT_CLOSEFIGURE)
+ {
+ pLinePts[nLinePts++] = pLinePts[0];
+ }
+ }//for
+
+ if(nLinePts >= 2)
+ IntGdiPolyline(dc, pLinePts, nLinePts);
+
+ ret = TRUE;
+
+end:
+ if(pLinePts)ExFreePool(pLinePts);
+
+ /* Restore the old mapping mode */
+ dc->w.MapMode = mapMode;
+ dc->wndExtX = szWindowExt.cx;
+ dc->wndExtY = szWindowExt.cy;
+ dc->wndOrgX = ptWindowOrg.x;
+ dc->wndOrgY = ptWindowOrg.y;
+
+ dc->vportExtX = szViewportExt.cx;
+ dc->vportExtY = szViewportExt.cy;
+ dc->vportOrgX = ptViewportOrg.x;
+ dc->vportOrgY = ptViewportOrg.y;
+
+ /* Restore the world transform */
+ dc->w.xformWorld2Wnd = xform;
+
+ /* If we've moved the current point then get its new position
+ which will be in device (MM_TEXT) co-ords, convert it to
+ logical co-ords and re-set it. This basically updates
+ dc->CurPosX|Y so that their values are in the correct mapping
+ mode.
+ */
+ if(i > 0)
+ {
+ POINT pt;
+ IntGetCurrentPositionEx(dc, &pt);
+ IntDPtoLP(dc, &pt, 1);
+ IntGdiMoveToEx(dc, pt.x, pt.y, NULL);
+ }
+
+ DPRINT("Leave %s, ret=%d\n", __FUNCTION__, ret);
+ return ret;
+}
+
/* EOF */
diff --git a/reactos/subsystems/win32/win32k/objects/pen.c b/reactos/subsystems/win32/win32k/objects/pen.c
index 7ba325fbefb..795b94086cb 100644
--- a/reactos/subsystems/win32/win32k/objects/pen.c
+++ b/reactos/subsystems/win32/win32k/objects/pen.c
@@ -84,7 +84,7 @@ IntGdiCreatePenIndirect(PLOGPEN LogPen)
break;
default:
- DPRINT1("FIXME: IntGdiCreatePenIndirect is UNIMPLEMENTED\n");
+ DPRINT1("FIXME: IntGdiCreatePenIndirect is UNIMPLEMENTED pen %x\n",LogPen->lopnStyle);
}
PENOBJ_UnlockPen(PenObject);
@@ -92,6 +92,23 @@ IntGdiCreatePenIndirect(PLOGPEN LogPen)
return hPen;
}
+INT STDCALL
+PEN_GetObject(PGDIBRUSHOBJ PenObject, INT Count, PLOGPEN Buffer)
+{
+
+ LOGPEN LogPen;
+
+ if( Buffer == NULL ) return sizeof(LOGPEN);
+
+ LogPen.lopnWidth = PenObject->ptPenWidth;
+ LogPen.lopnStyle = PenObject->ulPenStyle;
+ LogPen.lopnColor = PenObject->BrushAttr.lbColor;
+ memcpy(Buffer, &LogPen, Count);
+
+ return Count;
+
+}
+
/* PUBLIC FUNCTIONS ***********************************************************/
HPEN STDCALL
diff --git a/reactos/subsystems/win32/win32k/objects/text.c b/reactos/subsystems/win32/win32k/objects/text.c
index 9e5549c0022..84229a78d9c 100644
--- a/reactos/subsystems/win32/win32k/objects/text.c
+++ b/reactos/subsystems/win32/win32k/objects/text.c
@@ -3917,13 +3917,16 @@ TextIntRealizeFont(HFONT FontHandle)
INT FASTCALL
FontGetObject(PTEXTOBJ Font, INT Count, PVOID Buffer)
{
- if (Count < sizeof(LOGFONTW))
- {
- SetLastWin32Error(ERROR_BUFFER_OVERFLOW);
- return 0;
- }
+ if (Buffer)
+ {
+ if (Count < sizeof(LOGFONTW))
+ {
+ SetLastWin32Error(ERROR_BUFFER_OVERFLOW);
+ return 0;
+ }
- RtlCopyMemory(Buffer, &Font->logfont, sizeof(LOGFONTW));
+ RtlCopyMemory(Buffer, &Font->logfont, sizeof(LOGFONTW));
+ }
return sizeof(LOGFONTW);
}