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); }