diff --git a/rostests/winetests/gdiplus/CMakeLists.txt b/rostests/winetests/gdiplus/CMakeLists.txt index 28dd4c58177..702d55410f3 100644 --- a/rostests/winetests/gdiplus/CMakeLists.txt +++ b/rostests/winetests/gdiplus/CMakeLists.txt @@ -11,6 +11,7 @@ list(APPEND SOURCE graphicspath.c image.c matrix.c + metafile.c pathiterator.c pen.c region.c diff --git a/rostests/winetests/gdiplus/brush.c b/rostests/winetests/gdiplus/brush.c index 5eed6074f4b..cde7b564e22 100644 --- a/rostests/winetests/gdiplus/brush.c +++ b/rostests/winetests/gdiplus/brush.c @@ -773,22 +773,59 @@ static void test_gradientsurroundcolorcount(void) { GpStatus status; GpPathGradient *grad; - ARGB *color; - INT count = 3; + ARGB color[3]; + INT count; status = GdipCreatePathGradient(blendcount_ptf, 2, WrapModeClamp, &grad); expect(Ok, status); - color = GdipAlloc(sizeof(ARGB[3])); + count = 0; + status = GdipGetPathGradientSurroundColorCount(grad, &count); + expect(Ok, status); + expect(2, count); + color[0] = color[1] = color[2] = 0xdeadbeef; + count = 3; + status = GdipGetPathGradientSurroundColorsWithCount(grad, color, &count); + expect(Ok, status); + expect(1, count); + expect(0xffffffff, color[0]); + expect(0xffffffff, color[1]); + expect(0xdeadbeef, color[2]); + + color[0] = color[1] = color[2] = 0xdeadbeef; + count = 2; + status = GdipGetPathGradientSurroundColorsWithCount(grad, color, &count); + expect(Ok, status); + expect(1, count); + expect(0xffffffff, color[0]); + expect(0xffffffff, color[1]); + expect(0xdeadbeef, color[2]); + + color[0] = color[1] = color[2] = 0xdeadbeef; + count = 1; + status = GdipGetPathGradientSurroundColorsWithCount(grad, color, &count); + expect(InvalidParameter, status); + expect(1, count); + expect(0xdeadbeef, color[0]); + expect(0xdeadbeef, color[1]); + expect(0xdeadbeef, color[2]); + + color[0] = color[1] = color[2] = 0xdeadbeef; + count = 0; + status = GdipGetPathGradientSurroundColorsWithCount(grad, color, &count); + expect(InvalidParameter, status); + expect(0, count); + expect(0xdeadbeef, color[0]); + expect(0xdeadbeef, color[1]); + expect(0xdeadbeef, color[2]); + + count = 3; status = GdipSetPathGradientSurroundColorsWithCount(grad, color, &count); expect(InvalidParameter, status); - GdipFree(color); count = 2; - color = GdipAlloc(sizeof(ARGB[2])); - color[0] = 0x00ff0000; color[1] = 0x0000ff00; @@ -806,7 +843,7 @@ static void test_gradientsurroundcolorcount(void) } status = GdipSetPathGradientSurroundColorsWithCount(grad, color, &count); - todo_wine expect(Ok, status); + expect(Ok, status); expect(2, count); status = GdipGetPathGradientSurroundColorCount(NULL, &count); @@ -817,11 +854,418 @@ static void test_gradientsurroundcolorcount(void) count = 0; status = GdipGetPathGradientSurroundColorCount(grad, &count); - todo_wine expect(Ok, status); - todo_wine expect(2, count); + expect(Ok, status); + expect(2, count); + + color[0] = color[1] = color[2] = 0xdeadbeef; + count = 2; + status = GdipGetPathGradientSurroundColorsWithCount(grad, color, &count); + expect(Ok, status); + expect(2, count); + expect(0x00ff0000, color[0]); + expect(0x0000ff00, color[1]); + expect(0xdeadbeef, color[2]); + + count = 1; + status = GdipSetPathGradientSurroundColorsWithCount(grad, color, &count); + expect(Ok, status); + expect(1, count); + + count = 0; + status = GdipGetPathGradientSurroundColorCount(grad, &count); + expect(Ok, status); + expect(2, count); + + /* If all colors are the same, count is set to 1. */ + color[0] = color[1] = 0; + count = 2; + status = GdipSetPathGradientSurroundColorsWithCount(grad, color, &count); + expect(Ok, status); + expect(2, count); + + color[0] = color[1] = color[2] = 0xdeadbeef; + count = 2; + status = GdipGetPathGradientSurroundColorsWithCount(grad, color, &count); + expect(Ok, status); + expect(1, count); + expect(0x00000000, color[0]); + expect(0x00000000, color[1]); + expect(0xdeadbeef, color[2]); + + color[0] = color[1] = 0xff00ff00; + count = 2; + status = GdipSetPathGradientSurroundColorsWithCount(grad, color, &count); + expect(Ok, status); + expect(2, count); + + color[0] = color[1] = color[2] = 0xdeadbeef; + count = 2; + status = GdipGetPathGradientSurroundColorsWithCount(grad, color, &count); + expect(Ok, status); + expect(1, count); + expect(0xff00ff00, color[0]); + expect(0xff00ff00, color[1]); + expect(0xdeadbeef, color[2]); + + count = 0; + status = GdipSetPathGradientSurroundColorsWithCount(grad, color, &count); + expect(InvalidParameter, status); + expect(0, count); - GdipFree(color); GdipDeleteBrush((GpBrush*)grad); + + status = GdipCreatePathGradient(getbounds_ptf, 3, WrapModeClamp, &grad); + expect(Ok, status); + + color[0] = color[1] = color[2] = 0xdeadbeef; + count = 3; + status = GdipGetPathGradientSurroundColorsWithCount(grad, color, &count); + expect(Ok, status); + expect(1, count); + expect(0xffffffff, color[0]); + expect(0xffffffff, color[1]); + expect(0xffffffff, color[2]); + + color[0] = color[1] = color[2] = 0xdeadbeef; + count = 2; + status = GdipGetPathGradientSurroundColorsWithCount(grad, color, &count); + expect(InvalidParameter, status); + expect(2, count); + expect(0xdeadbeef, color[0]); + expect(0xdeadbeef, color[1]); + expect(0xdeadbeef, color[2]); + + count = 0; + status = GdipGetPathGradientSurroundColorCount(grad, &count); + expect(Ok, status); + expect(3, count); + + GdipDeleteBrush((GpBrush*)grad); +} + +static void test_pathgradientpath(void) +{ + GpStatus status; + GpPath *path=NULL; + GpPathGradient *grad=NULL; + + status = GdipCreatePathGradient(blendcount_ptf, 2, WrapModeClamp, &grad); + expect(Ok, status); + + status = GdipGetPathGradientPath(grad, NULL); + expect(NotImplemented, status); + + status = GdipCreatePath(FillModeWinding, &path); + expect(Ok, status); + + status = GdipGetPathGradientPath(NULL, path); + expect(NotImplemented, status); + + status = GdipGetPathGradientPath(grad, path); + expect(NotImplemented, status); + + status = GdipDeletePath(path); + expect(Ok, status); + + status = GdipDeleteBrush((GpBrush*)grad); + expect(Ok, status); +} + +static void test_pathgradientcenterpoint(void) +{ + static const GpPointF path_points[] = {{0,0}, {3,0}, {0,4}}; + GpStatus status; + GpPathGradient *grad; + GpPointF point; + + status = GdipCreatePathGradient(path_points+1, 2, WrapModeClamp, &grad); + expect(Ok, status); + + status = GdipGetPathGradientCenterPoint(NULL, &point); + expect(InvalidParameter, status); + + status = GdipGetPathGradientCenterPoint(grad, NULL); + expect(InvalidParameter, status); + + status = GdipGetPathGradientCenterPoint(grad, &point); + expect(Ok, status); + expectf(1.5, point.X); + expectf(2.0, point.Y); + + status = GdipSetPathGradientCenterPoint(NULL, &point); + expect(InvalidParameter, status); + + status = GdipSetPathGradientCenterPoint(grad, NULL); + expect(InvalidParameter, status); + + point.X = 10.0; + point.Y = 15.0; + status = GdipSetPathGradientCenterPoint(grad, &point); + expect(Ok, status); + + point.X = point.Y = -1; + status = GdipGetPathGradientCenterPoint(grad, &point); + expect(Ok, status); + expectf(10.0, point.X); + expectf(15.0, point.Y); + + status = GdipDeleteBrush((GpBrush*)grad); + expect(Ok, status); + + status = GdipCreatePathGradient(path_points, 3, WrapModeClamp, &grad); + expect(Ok, status); + + status = GdipGetPathGradientCenterPoint(grad, &point); + expect(Ok, status); + todo_wine expectf(1.0, point.X); + todo_wine expectf(4.0/3.0, point.Y); + + status = GdipDeleteBrush((GpBrush*)grad); + expect(Ok, status); +} + +static void test_pathgradientpresetblend(void) +{ + static const GpPointF path_points[] = {{0,0}, {3,0}, {0,4}}; + GpStatus status; + GpPathGradient *grad; + INT count; + int i; + const REAL positions[5] = {0.0f, 0.2f, 0.5f, 0.8f, 1.0f}; + const REAL two_positions[2] = {0.0f, 1.0f}; + const ARGB colors[5] = {0xff0000ff, 0xff00ff00, 0xff00ffff, 0xffff0000, 0xffffffff}; + REAL res_positions[6] = {0.3f, 0.0f, 0.0f, 0.0f, 0.0f}; + ARGB res_colors[6] = {0xdeadbeef, 0, 0, 0, 0}; + + status = GdipCreatePathGradient(path_points+1, 2, WrapModeClamp, &grad); + expect(Ok, status); + + status = GdipGetPathGradientPresetBlendCount(NULL, &count); + expect(InvalidParameter, status); + + status = GdipGetPathGradientPresetBlendCount(grad, NULL); + expect(InvalidParameter, status); + + status = GdipGetPathGradientPresetBlendCount(grad, &count); + expect(Ok, status); + expect(0, count); + + status = GdipGetPathGradientPresetBlend(NULL, res_colors, res_positions, 1); + expect(InvalidParameter, status); + + status = GdipGetPathGradientPresetBlend(grad, NULL, res_positions, 1); + expect(InvalidParameter, status); + + status = GdipGetPathGradientPresetBlend(grad, res_colors, NULL, 1); + expect(InvalidParameter, status); + + status = GdipGetPathGradientPresetBlend(grad, res_colors, res_positions, 0); + expect(InvalidParameter, status); + + status = GdipGetPathGradientPresetBlend(grad, res_colors, res_positions, -1); + expect(OutOfMemory, status); + + status = GdipGetPathGradientPresetBlend(grad, res_colors, res_positions, 1); + expect(InvalidParameter, status); + + status = GdipGetPathGradientPresetBlend(grad, res_colors, res_positions, 2); + expect(GenericError, status); + + status = GdipSetPathGradientPresetBlend(NULL, colors, positions, 5); + expect(InvalidParameter, status); + + status = GdipSetPathGradientPresetBlend(grad, NULL, positions, 5); + expect(InvalidParameter, status); + + if (0) + { + /* crashes on windows xp */ + status = GdipSetPathGradientPresetBlend(grad, colors, NULL, 5); + expect(InvalidParameter, status); + } + + status = GdipSetPathGradientPresetBlend(grad, colors, positions, 0); + expect(InvalidParameter, status); + + status = GdipSetPathGradientPresetBlend(grad, colors, positions, -1); + expect(InvalidParameter, status); + + status = GdipSetPathGradientPresetBlend(grad, colors, positions, 1); + expect(InvalidParameter, status); + + /* leave off the 0.0 position */ + status = GdipSetPathGradientPresetBlend(grad, &colors[1], &positions[1], 4); + expect(InvalidParameter, status); + + /* leave off the 1.0 position */ + status = GdipSetPathGradientPresetBlend(grad, colors, positions, 4); + expect(InvalidParameter, status); + + status = GdipSetPathGradientPresetBlend(grad, colors, positions, 5); + expect(Ok, status); + + status = GdipGetPathGradientPresetBlendCount(grad, &count); + expect(Ok, status); + expect(5, count); + + if (0) + { + /* Native GdipGetPathGradientPresetBlend seems to copy starting from + * the end of each array and do no bounds checking. This is so braindead + * I'm not going to copy it. */ + + res_colors[0] = 0xdeadbeef; + res_positions[0] = 0.3; + + status = GdipGetPathGradientPresetBlend(grad, &res_colors[1], &res_positions[1], 4); + expect(Ok, status); + + expect(0xdeadbeef, res_colors[0]); + expectf(0.3, res_positions[0]); + + for (i=1; i<5; i++) + { + expect(colors[i], res_colors[i]); + expectf(positions[i], res_positions[i]); + } + + status = GdipGetPathGradientPresetBlend(grad, res_colors, res_positions, 6); + expect(Ok, status); + + for (i=0; i<5; i++) + { + expect(colors[i], res_colors[i+1]); + expectf(positions[i], res_positions[i+1]); + } + } + + status = GdipGetPathGradientPresetBlend(grad, res_colors, res_positions, 5); + expect(Ok, status); + + for (i=0; i<5; i++) + { + expect(colors[i], res_colors[i]); + expectf(positions[i], res_positions[i]); + } + + status = GdipGetPathGradientPresetBlend(grad, res_colors, res_positions, 0); + expect(InvalidParameter, status); + + status = GdipGetPathGradientPresetBlend(grad, res_colors, res_positions, -1); + expect(OutOfMemory, status); + + status = GdipGetPathGradientPresetBlend(grad, res_colors, res_positions, 1); + expect(InvalidParameter, status); + + status = GdipSetPathGradientPresetBlend(grad, colors, two_positions, 2); + expect(Ok, status); + + status = GdipDeleteBrush((GpBrush*)grad); + expect(Ok, status); +} + +static void test_pathgradientblend(void) +{ + static const GpPointF path_points[] = {{0,0}, {3,0}, {0,4}}; + GpPathGradient *brush; + GpStatus status; + INT count, i; + const REAL factors[5] = {0.0f, 0.1f, 0.5f, 0.9f, 1.0f}; + const REAL positions[5] = {0.0f, 0.2f, 0.5f, 0.8f, 1.0f}; + REAL res_factors[6] = {0.3f, 0.0f, 0.0f, 0.0f, 0.0f}; + REAL res_positions[6] = {0.3f, 0.0f, 0.0f, 0.0f, 0.0f}; + + status = GdipCreatePathGradient(path_points, 3, WrapModeClamp, &brush); + expect(Ok, status); + + status = GdipGetPathGradientBlendCount(NULL, &count); + expect(InvalidParameter, status); + + status = GdipGetPathGradientBlendCount(brush, NULL); + expect(InvalidParameter, status); + + status = GdipGetPathGradientBlendCount(brush, &count); + expect(Ok, status); + expect(1, count); + + status = GdipGetPathGradientBlend(NULL, res_factors, res_positions, 1); + expect(InvalidParameter, status); + + status = GdipGetPathGradientBlend(brush, NULL, res_positions, 1); + expect(InvalidParameter, status); + + status = GdipGetPathGradientBlend(brush, res_factors, NULL, 1); + expect(InvalidParameter, status); + + status = GdipGetPathGradientBlend(brush, res_factors, res_positions, 0); + expect(InvalidParameter, status); + + status = GdipGetPathGradientBlend(brush, res_factors, res_positions, -1); + expect(InvalidParameter, status); + + status = GdipGetPathGradientBlend(brush, res_factors, res_positions, 1); + expect(Ok, status); + + status = GdipGetPathGradientBlend(brush, res_factors, res_positions, 2); + expect(Ok, status); + + status = GdipSetPathGradientBlend(NULL, factors, positions, 5); + expect(InvalidParameter, status); + + status = GdipSetPathGradientBlend(brush, NULL, positions, 5); + expect(InvalidParameter, status); + + status = GdipSetPathGradientBlend(brush, factors, NULL, 5); + expect(InvalidParameter, status); + + status = GdipSetPathGradientBlend(brush, factors, positions, 0); + expect(InvalidParameter, status); + + status = GdipSetPathGradientBlend(brush, factors, positions, -1); + expect(InvalidParameter, status); + + /* leave off the 0.0 position */ + status = GdipSetPathGradientBlend(brush, &factors[1], &positions[1], 4); + expect(InvalidParameter, status); + + /* leave off the 1.0 position */ + status = GdipSetPathGradientBlend(brush, factors, positions, 4); + expect(InvalidParameter, status); + + status = GdipSetPathGradientBlend(brush, factors, positions, 5); + expect(Ok, status); + + status = GdipGetPathGradientBlendCount(brush, &count); + expect(Ok, status); + expect(5, count); + + status = GdipGetPathGradientBlend(brush, res_factors, res_positions, 4); + expect(InsufficientBuffer, status); + + status = GdipGetPathGradientBlend(brush, res_factors, res_positions, 5); + expect(Ok, status); + + for (i=0; i<5; i++) + { + expectf(factors[i], res_factors[i]); + expectf(positions[i], res_positions[i]); + } + + status = GdipGetPathGradientBlend(brush, res_factors, res_positions, 6); + expect(Ok, status); + + status = GdipSetPathGradientBlend(brush, factors, positions, 1); + expect(Ok, status); + + status = GdipGetPathGradientBlendCount(brush, &count); + expect(Ok, status); + expect(1, count); + + status = GdipGetPathGradientBlend(brush, res_factors, res_positions, 1); + expect(Ok, status); + + status = GdipDeleteBrush((GpBrush*)brush); + expect(Ok, status); } START_TEST(brush) @@ -848,6 +1292,10 @@ START_TEST(brush) test_lineblend(); test_linelinearblend(); test_gradientsurroundcolorcount(); + test_pathgradientpath(); + test_pathgradientcenterpoint(); + test_pathgradientpresetblend(); + test_pathgradientblend(); GdiplusShutdown(gdiplusToken); } diff --git a/rostests/winetests/gdiplus/font.c b/rostests/winetests/gdiplus/font.c index 98c4114acc0..982db392866 100644 --- a/rostests/winetests/gdiplus/font.c +++ b/rostests/winetests/gdiplus/font.c @@ -2,6 +2,7 @@ * Unit test suite for fonts * * Copyright (C) 2007 Google (Evan Stade) + * Copyright (C) 2012 Dmitry Timoshkov * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -24,10 +25,9 @@ #include "gdiplus.h" #include "wine/test.h" -#define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got) -#define expectf(expected, got) ok(fabs(expected - got) < 0.0001, "Expected %.2f, got %.2f\n", expected, got) +#define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got) +#define expectf(expected, got) ok(fabs(expected - got) < 0.0001, "Expected %f, got %f\n", expected, got) -static const WCHAR arial[] = {'A','r','i','a','l','\0'}; static const WCHAR nonexistent[] = {'T','h','i','s','F','o','n','t','s','h','o','u','l','d','N','o','t','E','x','i','s','t','\0'}; static const WCHAR MSSansSerif[] = {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'}; static const WCHAR MicrosoftSansSerif[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f','\0'}; @@ -50,12 +50,7 @@ static void test_createfont(void) expect (FontFamilyNotFound, stat); stat = GdipDeleteFont(font); expect (InvalidParameter, stat); - stat = GdipCreateFontFamilyFromName(arial, NULL, &fontfamily); - if(stat == FontFamilyNotFound) - { - skip("Arial not installed\n"); - return; - } + stat = GdipCreateFontFamilyFromName(Tahoma, NULL, &fontfamily); expect (Ok, stat); stat = GdipCreateFont(fontfamily, 12, FontStyleRegular, UnitPoint, &font); expect (Ok, stat); @@ -67,7 +62,7 @@ static void test_createfont(void) expect(Ok, stat); stat = GdipGetFamilyName(fontfamily2, familyname, 0); expect(Ok, stat); - ok (lstrcmpiW(arial, familyname) == 0, "Expected arial, got %s\n", + ok (lstrcmpiW(Tahoma, familyname) == 0, "Expected Tahoma, got %s\n", wine_dbgstr_w(familyname)); stat = GdipDeleteFontFamily(fontfamily2); expect(Ok, stat); @@ -96,12 +91,17 @@ static void test_logfont(void) { LOGFONTA lfa, lfa2; GpFont *font; + GpFontFamily *family; GpStatus stat; GpGraphics *graphics; HDC hdc = GetDC(0); INT style; + REAL rval; + UINT16 em_height, line_spacing; + Unit unit; GdipCreateFromHDC(hdc, &graphics); + memset(&lfa, 0, sizeof(LOGFONTA)); memset(&lfa2, 0xff, sizeof(LOGFONTA)); @@ -110,14 +110,9 @@ static void test_logfont(void) stat = GdipCreateFontFromLogfontA(hdc, &lfa, &font); expect(NotTrueTypeFont, stat); - lstrcpyA(lfa.lfFaceName, "Arial"); + lstrcpyA(lfa.lfFaceName, "Tahoma"); stat = GdipCreateFontFromLogfontA(hdc, &lfa, &font); - if (stat == FileNotFound) - { - skip("Arial not installed.\n"); - return; - } expect(Ok, stat); stat = GdipGetLogFontA(font, graphics, &lfa2); expect(Ok, stat); @@ -146,7 +141,7 @@ static void test_logfont(void) lfa.lfItalic = lfa.lfUnderline = lfa.lfStrikeOut = TRUE; memset(&lfa2, 0xff, sizeof(LOGFONTA)); - lstrcpyA(lfa.lfFaceName, "Arial"); + lstrcpyA(lfa.lfFaceName, "Tahoma"); stat = GdipCreateFontFromLogfontA(hdc, &lfa, &font); expect(Ok, stat); @@ -173,6 +168,60 @@ static void test_logfont(void) ok (style == (FontStyleItalic | FontStyleUnderline | FontStyleStrikeout), "Expected , got %d\n", style); + stat = GdipGetFontUnit(font, &unit); + expect(Ok, stat); + expect(UnitWorld, unit); + + stat = GdipGetFontHeight(font, graphics, &rval); + expect(Ok, stat); + expectf(25.347656, rval); + stat = GdipGetFontSize(font, &rval); + expect(Ok, stat); + expectf(21.0, rval); + + stat = GdipGetFamily(font, &family); + expect(Ok, stat); + stat = GdipGetEmHeight(family, FontStyleRegular, &em_height); + expect(Ok, stat); + expect(2048, em_height); + stat = GdipGetLineSpacing(family, FontStyleRegular, &line_spacing); + expect(Ok, stat); + expect(2472, line_spacing); + GdipDeleteFontFamily(family); + + GdipDeleteFont(font); + + memset(&lfa, 0, sizeof(lfa)); + lfa.lfHeight = -25; + lstrcpyA(lfa.lfFaceName, "Tahoma"); + stat = GdipCreateFontFromLogfontA(hdc, &lfa, &font); + expect(Ok, stat); + memset(&lfa2, 0xff, sizeof(lfa2)); + stat = GdipGetLogFontA(font, graphics, &lfa2); + expect(Ok, stat); + expect(lfa.lfHeight, lfa2.lfHeight); + + stat = GdipGetFontUnit(font, &unit); + expect(Ok, stat); + expect(UnitWorld, unit); + + stat = GdipGetFontHeight(font, graphics, &rval); + expect(Ok, stat); + expectf(30.175781, rval); + stat = GdipGetFontSize(font, &rval); + expect(Ok, stat); + expectf(25.0, rval); + + stat = GdipGetFamily(font, &family); + expect(Ok, stat); + stat = GdipGetEmHeight(family, FontStyleRegular, &em_height); + expect(Ok, stat); + expect(2048, em_height); + stat = GdipGetLineSpacing(family, FontStyleRegular, &line_spacing); + expect(Ok, stat); + expect(2472, line_spacing); + GdipDeleteFontFamily(family); + GdipDeleteFont(font); GdipDeleteGraphics(graphics); @@ -186,7 +235,7 @@ static void test_fontfamily (void) GpStatus stat; /* FontFamily cannot be NULL */ - stat = GdipCreateFontFamilyFromName (arial , NULL, NULL); + stat = GdipCreateFontFamilyFromName (Tahoma , NULL, NULL); expect (InvalidParameter, stat); /* FontFamily must be able to actually find the family. @@ -200,17 +249,12 @@ static void test_fontfamily (void) expect (FontFamilyNotFound, stat); if(stat == Ok) GdipDeleteFontFamily(family); - stat = GdipCreateFontFamilyFromName (arial, NULL, &family); - if(stat == FontFamilyNotFound) - { - skip("Arial not installed\n"); - return; - } + stat = GdipCreateFontFamilyFromName (Tahoma, NULL, &family); expect (Ok, stat); stat = GdipGetFamilyName (family, itsName, LANG_NEUTRAL); expect (Ok, stat); - expect (0, lstrcmpiW(itsName, arial)); + expect (0, lstrcmpiW(itsName, Tahoma)); if (0) { @@ -226,7 +270,7 @@ static void test_fontfamily (void) GdipDeleteFontFamily(family); stat = GdipGetFamilyName(clonedFontFamily, itsName, LANG_NEUTRAL); expect(Ok, stat); - expect(0, lstrcmpiW(itsName, arial)); + expect(0, lstrcmpiW(itsName, Tahoma)); GdipDeleteFontFamily(clonedFontFamily); } @@ -237,28 +281,25 @@ static void test_fontfamily_properties (void) GpStatus stat; UINT16 result = 0; - stat = GdipCreateFontFamilyFromName(arial, NULL, &FontFamily); - if(stat == FontFamilyNotFound) - skip("Arial not installed\n"); - else - { - stat = GdipGetLineSpacing(FontFamily, FontStyleRegular, &result); - expect(Ok, stat); - ok (result == 2355, "Expected 2355, got %d\n", result); - result = 0; - stat = GdipGetEmHeight(FontFamily, FontStyleRegular, &result); - expect(Ok, stat); - ok(result == 2048, "Expected 2048, got %d\n", result); - result = 0; - stat = GdipGetCellAscent(FontFamily, FontStyleRegular, &result); - expect(Ok, stat); - ok(result == 1854, "Expected 1854, got %d\n", result); - result = 0; - stat = GdipGetCellDescent(FontFamily, FontStyleRegular, &result); - expect(Ok, stat); - ok(result == 434, "Expected 434, got %d\n", result); - GdipDeleteFontFamily(FontFamily); - } + stat = GdipCreateFontFamilyFromName(Tahoma, NULL, &FontFamily); + expect(Ok, stat); + + stat = GdipGetLineSpacing(FontFamily, FontStyleRegular, &result); + expect(Ok, stat); + ok (result == 2472, "Expected 2472, got %d\n", result); + result = 0; + stat = GdipGetEmHeight(FontFamily, FontStyleRegular, &result); + expect(Ok, stat); + ok(result == 2048, "Expected 2048, got %d\n", result); + result = 0; + stat = GdipGetCellAscent(FontFamily, FontStyleRegular, &result); + expect(Ok, stat); + ok(result == 2049, "Expected 2049, got %d\n", result); + result = 0; + stat = GdipGetCellDescent(FontFamily, FontStyleRegular, &result); + expect(Ok, stat); + ok(result == 423, "Expected 423, got %d\n", result); + GdipDeleteFontFamily(FontFamily); stat = GdipCreateFontFamilyFromName(TimesNewRoman, NULL, &FontFamily); if(stat == FontFamilyNotFound) @@ -362,13 +403,9 @@ static void test_heightgivendpi(void) GpFont* font = NULL; GpFontFamily* fontfamily = NULL; REAL height; + Unit unit; - stat = GdipCreateFontFamilyFromName(arial, NULL, &fontfamily); - if(stat == FontFamilyNotFound) - { - skip("Arial not installed\n"); - return; - } + stat = GdipCreateFontFamilyFromName(Tahoma, NULL, &fontfamily); expect(Ok, stat); stat = GdipCreateFont(fontfamily, 30, FontStyleRegular, UnitPixel, &font); @@ -382,15 +419,20 @@ static void test_heightgivendpi(void) stat = GdipGetFontHeightGivenDPI(font, 96, &height); expect(Ok, stat); - expectf((REAL)34.497070, height); + expectf(36.210938, height); GdipDeleteFont(font); height = 12345; stat = GdipCreateFont(fontfamily, 30, FontStyleRegular, UnitWorld, &font); expect(Ok, stat); + + stat = GdipGetFontUnit(font, &unit); + expect(Ok, stat); + expect(UnitWorld, unit); + stat = GdipGetFontHeightGivenDPI(font, 96, &height); expect(Ok, stat); - expectf((REAL)34.497070, height); + expectf(36.210938, height); GdipDeleteFont(font); height = 12345; @@ -398,36 +440,288 @@ static void test_heightgivendpi(void) expect(Ok, stat); stat = GdipGetFontHeightGivenDPI(font, 96, &height); expect(Ok, stat); - expectf((REAL)45.996094, height); + expectf(48.281250, height); GdipDeleteFont(font); height = 12345; stat = GdipCreateFont(fontfamily, 30, FontStyleRegular, UnitInch, &font); expect(Ok, stat); + + stat = GdipGetFontUnit(font, &unit); + expect(Ok, stat); + expect(UnitInch, unit); + stat = GdipGetFontHeightGivenDPI(font, 96, &height); expect(Ok, stat); - expectf((REAL)3311.718750, height); + expectf(3476.250000, height); GdipDeleteFont(font); height = 12345; stat = GdipCreateFont(fontfamily, 30, FontStyleRegular, UnitDocument, &font); expect(Ok, stat); + + stat = GdipGetFontUnit(font, &unit); + expect(Ok, stat); + expect(UnitDocument, unit); + stat = GdipGetFontHeightGivenDPI(font, 96, &height); expect(Ok, stat); - expectf((REAL)11.039062, height); + expectf(11.587500, height); GdipDeleteFont(font); height = 12345; stat = GdipCreateFont(fontfamily, 30, FontStyleRegular, UnitMillimeter, &font); expect(Ok, stat); + + stat = GdipGetFontUnit(font, &unit); + expect(Ok, stat); + expect(UnitMillimeter, unit); + stat = GdipGetFontHeightGivenDPI(font, 96, &height); expect(Ok, stat); - expectf((REAL)130.382614, height); + expectf(136.860245, height); GdipDeleteFont(font); GdipDeleteFontFamily(fontfamily); } +static int CALLBACK font_enum_proc(const LOGFONTW *lfe, const TEXTMETRICW *ntme, + DWORD type, LPARAM lparam) +{ + NEWTEXTMETRICW *ntm = (NEWTEXTMETRICW *)lparam; + + if (type != TRUETYPE_FONTTYPE) return 1; + + *ntm = *(NEWTEXTMETRICW *)ntme; + return 0; +} + +struct font_metrics +{ + UINT16 em_height, line_spacing, ascent, descent; + REAL font_height, font_size; + INT lfHeight; +}; + +static void gdi_get_font_metrics(LOGFONTW *lf, struct font_metrics *fm) +{ + HDC hdc; + HFONT hfont; + NEWTEXTMETRICW ntm; + OUTLINETEXTMETRICW otm; + int ret; + + hdc = CreateCompatibleDC(0); + + /* it's the only way to get extended NEWTEXTMETRIC fields */ + ret = EnumFontFamiliesExW(hdc, lf, font_enum_proc, (LPARAM)&ntm, 0); + ok(!ret, "EnumFontFamiliesExW failed to find %s\n", wine_dbgstr_w(lf->lfFaceName)); + + hfont = CreateFontIndirectW(lf); + SelectObject(hdc, hfont); + + otm.otmSize = sizeof(otm); + ret = GetOutlineTextMetricsW(hdc, otm.otmSize, &otm); + ok(ret, "GetOutlineTextMetrics failed\n"); + + DeleteDC(hdc); + DeleteObject(hfont); + + fm->lfHeight = -otm.otmTextMetrics.tmAscent; + fm->line_spacing = ntm.ntmCellHeight; + fm->font_size = (REAL)otm.otmTextMetrics.tmAscent; + fm->font_height = (REAL)fm->line_spacing * fm->font_size / (REAL)ntm.ntmSizeEM; + fm->em_height = ntm.ntmSizeEM; + fm->ascent = ntm.ntmSizeEM; + fm->descent = ntm.ntmCellHeight - ntm.ntmSizeEM; +} + +static void gdip_get_font_metrics(GpFont *font, struct font_metrics *fm) +{ + INT style; + GpFontFamily *family; + GpStatus stat; + + stat = GdipGetFontStyle(font, &style); + expect(Ok, stat); + + stat = GdipGetFontHeight(font, NULL, &fm->font_height); + expect(Ok, stat); + stat = GdipGetFontSize(font, &fm->font_size); + expect(Ok, stat); + + fm->lfHeight = (INT)(fm->font_size * -1.0); + + stat = GdipGetFamily(font, &family); + expect(Ok, stat); + + stat = GdipGetEmHeight(family, style, &fm->em_height); + expect(Ok, stat); + stat = GdipGetLineSpacing(family, style, &fm->line_spacing); + expect(Ok, stat); + stat = GdipGetCellAscent(family, style, &fm->ascent); + expect(Ok, stat); + stat = GdipGetCellDescent(family, style, &fm->descent); + expect(Ok, stat); + + GdipDeleteFontFamily(family); +} + +static void cmp_font_metrics(struct font_metrics *fm1, struct font_metrics *fm2, int line) +{ + ok_(__FILE__, line)(fm1->lfHeight == fm2->lfHeight, "lfHeight %d != %d\n", fm1->lfHeight, fm2->lfHeight); + ok_(__FILE__, line)(fm1->em_height == fm2->em_height, "em_height %u != %u\n", fm1->em_height, fm2->em_height); + ok_(__FILE__, line)(fm1->line_spacing == fm2->line_spacing, "line_spacing %u != %u\n", fm1->line_spacing, fm2->line_spacing); + ok_(__FILE__, line)(abs(fm1->ascent - fm2->ascent) <= 1, "ascent %u != %u\n", fm1->ascent, fm2->ascent); + ok_(__FILE__, line)(abs(fm1->descent - fm2->descent) <= 1, "descent %u != %u\n", fm1->descent, fm2->descent); + ok(fm1->font_height > 0.0, "fm1->font_height should be positive, got %f\n", fm1->font_height); + ok(fm2->font_height > 0.0, "fm2->font_height should be positive, got %f\n", fm2->font_height); + ok_(__FILE__, line)(fm1->font_height == fm2->font_height, "font_height %f != %f\n", fm1->font_height, fm2->font_height); + ok(fm1->font_size > 0.0, "fm1->font_size should be positive, got %f\n", fm1->font_size); + ok(fm2->font_size > 0.0, "fm2->font_size should be positive, got %f\n", fm2->font_size); + ok_(__FILE__, line)(fm1->font_size == fm2->font_size, "font_size %f != %f\n", fm1->font_size, fm2->font_size); +} + +static void test_font_metrics(void) +{ + LOGFONTW lf; + GpFont *font; + GpFontFamily *family; + GpGraphics *graphics; + GpStatus stat; + Unit unit; + struct font_metrics fm_gdi, fm_gdip; + HDC hdc; + + hdc = CreateCompatibleDC(0); + stat = GdipCreateFromHDC(hdc, &graphics); + expect(Ok, stat); + + memset(&lf, 0, sizeof(lf)); + + /* Tahoma,-13 */ + lstrcpyW(lf.lfFaceName, Tahoma); + lf.lfHeight = -13; + stat = GdipCreateFontFromLogfontW(hdc, &lf, &font); + expect(Ok, stat); + + stat = GdipGetFontUnit(font, &unit); + expect(Ok, stat); + expect(UnitWorld, unit); + + gdip_get_font_metrics(font, &fm_gdip); + trace("gdiplus:\n"); + trace("%s,%d: EmHeight %u, LineSpacing %u, CellAscent %u, CellDescent %u, FontHeight %f, FontSize %f\n", + wine_dbgstr_w(lf.lfFaceName), lf.lfHeight, + fm_gdip.em_height, fm_gdip.line_spacing, fm_gdip.ascent, fm_gdip.descent, + fm_gdip.font_height, fm_gdip.font_size); + + gdi_get_font_metrics(&lf, &fm_gdi); + trace("gdi:\n"); + trace("%s,%d: EmHeight %u, LineSpacing %u, CellAscent %u, CellDescent %u, FontHeight %f, FontSize %f\n", + wine_dbgstr_w(lf.lfFaceName), lf.lfHeight, + fm_gdi.em_height, fm_gdi.line_spacing, fm_gdi.ascent, fm_gdi.descent, + fm_gdi.font_height, fm_gdi.font_size); + + cmp_font_metrics(&fm_gdip, &fm_gdi, __LINE__); + + stat = GdipGetLogFontW(font, graphics, &lf); + expect(Ok, stat); + ok(lf.lfHeight < 0, "lf.lfHeight should be negative, got %d\n", lf.lfHeight); + gdi_get_font_metrics(&lf, &fm_gdi); + trace("gdi:\n"); + trace("%s,%d: EmHeight %u, LineSpacing %u, CellAscent %u, CellDescent %u, FontHeight %f, FontSize %f\n", + wine_dbgstr_w(lf.lfFaceName), lf.lfHeight, + fm_gdi.em_height, fm_gdi.line_spacing, fm_gdi.ascent, fm_gdi.descent, + fm_gdi.font_height, fm_gdi.font_size); + ok((REAL)lf.lfHeight * -1.0 == fm_gdi.font_size, "expected %f, got %f\n", (REAL)lf.lfHeight * -1.0, fm_gdi.font_size); + + cmp_font_metrics(&fm_gdip, &fm_gdi, __LINE__); + + GdipDeleteFont(font); + + /* Tahoma,13 */ + lstrcpyW(lf.lfFaceName, Tahoma); + lf.lfHeight = 13; + stat = GdipCreateFontFromLogfontW(hdc, &lf, &font); + expect(Ok, stat); + + stat = GdipGetFontUnit(font, &unit); + expect(Ok, stat); + expect(UnitWorld, unit); + + gdip_get_font_metrics(font, &fm_gdip); + trace("gdiplus:\n"); + trace("%s,%d: EmHeight %u, LineSpacing %u, CellAscent %u, CellDescent %u, FontHeight %f, FontSize %f\n", + wine_dbgstr_w(lf.lfFaceName), lf.lfHeight, + fm_gdip.em_height, fm_gdip.line_spacing, fm_gdip.ascent, fm_gdip.descent, + fm_gdip.font_height, fm_gdip.font_size); + + gdi_get_font_metrics(&lf, &fm_gdi); + trace("gdi:\n"); + trace("%s,%d: EmHeight %u, LineSpacing %u, CellAscent %u, CellDescent %u, FontHeight %f, FontSize %f\n", + wine_dbgstr_w(lf.lfFaceName), lf.lfHeight, + fm_gdi.em_height, fm_gdi.line_spacing, fm_gdi.ascent, fm_gdi.descent, + fm_gdi.font_height, fm_gdi.font_size); + + cmp_font_metrics(&fm_gdip, &fm_gdi, __LINE__); + + stat = GdipGetLogFontW(font, graphics, &lf); + expect(Ok, stat); + ok(lf.lfHeight < 0, "lf.lfHeight should be negative, got %d\n", lf.lfHeight); + gdi_get_font_metrics(&lf, &fm_gdi); + trace("gdi:\n"); + trace("%s,%d: EmHeight %u, LineSpacing %u, CellAscent %u, CellDescent %u, FontHeight %f, FontSize %f\n", + wine_dbgstr_w(lf.lfFaceName), lf.lfHeight, + fm_gdi.em_height, fm_gdi.line_spacing, fm_gdi.ascent, fm_gdi.descent, + fm_gdi.font_height, fm_gdi.font_size); + ok((REAL)lf.lfHeight * -1.0 == fm_gdi.font_size, "expected %f, got %f\n", (REAL)lf.lfHeight * -1.0, fm_gdi.font_size); + + cmp_font_metrics(&fm_gdip, &fm_gdi, __LINE__); + + GdipDeleteFont(font); + + stat = GdipCreateFontFamilyFromName(Tahoma, NULL, &family); + expect(Ok, stat); + + /* Tahoma,13 */ + stat = GdipCreateFont(family, 13.0, FontStyleRegular, UnitPixel, &font); + expect(Ok, stat); + + gdip_get_font_metrics(font, &fm_gdip); + trace("gdiplus:\n"); + trace("%s,%d: EmHeight %u, LineSpacing %u, CellAscent %u, CellDescent %u, FontHeight %f, FontSize %f\n", + wine_dbgstr_w(lf.lfFaceName), lf.lfHeight, + fm_gdip.em_height, fm_gdip.line_spacing, fm_gdip.ascent, fm_gdip.descent, + fm_gdip.font_height, fm_gdip.font_size); + + stat = GdipGetLogFontW(font, graphics, &lf); + expect(Ok, stat); + ok(lf.lfHeight < 0, "lf.lfHeight should be negative, got %d\n", lf.lfHeight); + gdi_get_font_metrics(&lf, &fm_gdi); + trace("gdi:\n"); + trace("%s,%d: EmHeight %u, LineSpacing %u, CellAscent %u, CellDescent %u, FontHeight %f, FontSize %f\n", + wine_dbgstr_w(lf.lfFaceName), lf.lfHeight, + fm_gdi.em_height, fm_gdi.line_spacing, fm_gdi.ascent, fm_gdi.descent, + fm_gdi.font_height, fm_gdi.font_size); + ok((REAL)lf.lfHeight * -1.0 == fm_gdi.font_size, "expected %f, got %f\n", (REAL)lf.lfHeight * -1.0, fm_gdi.font_size); + + cmp_font_metrics(&fm_gdip, &fm_gdi, __LINE__); + + stat = GdipGetLogFontW(font, NULL, &lf); + expect(InvalidParameter, stat); + + GdipDeleteFont(font); + + stat = GdipCreateFont(family, -13.0, FontStyleRegular, UnitPixel, &font); + expect(InvalidParameter, stat); + + GdipDeleteFontFamily(family); + + GdipDeleteGraphics(graphics); + DeleteDC(hdc); +} + START_TEST(font) { struct GdiplusStartupInput gdiplusStartupInput; @@ -440,6 +734,7 @@ START_TEST(font) GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); + test_font_metrics(); test_createfont(); test_logfont(); test_fontfamily(); diff --git a/rostests/winetests/gdiplus/metafile.c b/rostests/winetests/gdiplus/metafile.c new file mode 100644 index 00000000000..9530b0c540b --- /dev/null +++ b/rostests/winetests/gdiplus/metafile.c @@ -0,0 +1,568 @@ +/* + * Unit test suite for metafiles + * + * Copyright (C) 2011 Vincent Povirk for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "windows.h" +#include +#include "gdiplus.h" +#include "wine/test.h" + +#define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got) + +typedef struct emfplus_record +{ + ULONG todo; + ULONG record_type; + ULONG playback_todo; +} emfplus_record; + +typedef struct emfplus_check_state +{ + const char *desc; + int count; + const struct emfplus_record *expected; + GpMetafile *metafile; +} emfplus_check_state; + +static void check_record(int count, const char *desc, const struct emfplus_record *expected, const struct emfplus_record *actual) +{ + if (expected->todo) + todo_wine ok(expected->record_type == actual->record_type, + "%s.%i: Expected record type 0x%x, got 0x%x\n", desc, count, + expected->record_type, actual->record_type); + else + ok(expected->record_type == actual->record_type, + "%s.%i: Expected record type 0x%x, got 0x%x\n", desc, count, + expected->record_type, actual->record_type); +} + +typedef struct EmfPlusRecordHeader +{ + WORD Type; + WORD Flags; + DWORD Size; + DWORD DataSize; +} EmfPlusRecordHeader; + +static int CALLBACK enum_emf_proc(HDC hDC, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR, + int nObj, LPARAM lpData) +{ + emfplus_check_state *state = (emfplus_check_state*)lpData; + emfplus_record actual; + + if (lpEMFR->iType == EMR_GDICOMMENT) + { + const EMRGDICOMMENT *comment = (const EMRGDICOMMENT*)lpEMFR; + + if (comment->cbData >= 4 && memcmp(comment->Data, "EMF+", 4) == 0) + { + int offset = 4; + + while (offset + sizeof(EmfPlusRecordHeader) <= comment->cbData) + { + const EmfPlusRecordHeader *record = (const EmfPlusRecordHeader*)&comment->Data[offset]; + + ok(record->Size == record->DataSize + sizeof(EmfPlusRecordHeader), + "%s: EMF+ record datasize %u and size %u mismatch\n", state->desc, record->DataSize, record->Size); + + ok(offset + record->DataSize <= comment->cbData, + "%s: EMF+ record truncated\n", state->desc); + + if (offset + record->DataSize > comment->cbData) + return 0; + + if (state->expected[state->count].record_type) + { + actual.todo = 0; + actual.record_type = record->Type; + + check_record(state->count, state->desc, &state->expected[state->count], &actual); + + state->count++; + } + else + { + ok(0, "%s: Unexpected EMF+ 0x%x record\n", state->desc, record->Type); + } + + offset += record->Size; + } + + ok(offset == comment->cbData, "%s: truncated EMF+ record data?\n", state->desc); + + return 1; + } + } + + if (state->expected[state->count].record_type) + { + actual.todo = 0; + actual.record_type = lpEMFR->iType; + + check_record(state->count, state->desc, &state->expected[state->count], &actual); + + state->count++; + } + else + { + ok(0, "%s: Unexpected EMF 0x%x record\n", state->desc, lpEMFR->iType); + } + + return 1; +} + +static void check_emfplus(HENHMETAFILE hemf, const emfplus_record *expected, const char *desc) +{ + emfplus_check_state state; + + state.desc = desc; + state.count = 0; + state.expected = expected; + + EnumEnhMetaFile(0, hemf, enum_emf_proc, &state, NULL); + + if (expected[state.count].todo) + todo_wine ok(expected[state.count].record_type == 0, "%s: Got %i records, expecting more\n", desc, state.count); + else + ok(expected[state.count].record_type == 0, "%s: Got %i records, expecting more\n", desc, state.count); +} + +static BOOL CALLBACK enum_metafile_proc(EmfPlusRecordType record_type, unsigned int flags, + unsigned int dataSize, const unsigned char *pStr, void *userdata) +{ + emfplus_check_state *state = (emfplus_check_state*)userdata; + emfplus_record actual; + + actual.todo = 0; + actual.record_type = record_type; + + if (dataSize == 0) + ok(pStr == NULL, "non-NULL pStr\n"); + + if (state->expected[state->count].record_type) + { + check_record(state->count, state->desc, &state->expected[state->count], &actual); + + state->count++; + } + else + { + ok(0, "%s: Unexpected EMF 0x%x record\n", state->desc, record_type); + } + + return TRUE; +} + +static void check_metafile(GpMetafile *metafile, const emfplus_record *expected, const char *desc, + const GpPointF *dst_points, const GpRectF *src_rect, Unit src_unit) +{ + GpStatus stat; + HDC hdc; + GpGraphics *graphics; + emfplus_check_state state; + + state.desc = desc; + state.count = 0; + state.expected = expected; + state.metafile = metafile; + + hdc = CreateCompatibleDC(0); + + stat = GdipCreateFromHDC(hdc, &graphics); + expect(Ok, stat); + + stat = GdipEnumerateMetafileSrcRectDestPoints(graphics, metafile, dst_points, + 3, src_rect, src_unit, enum_metafile_proc, &state, NULL); + expect(Ok, stat); + + if (expected[state.count].todo) + todo_wine ok(expected[state.count].record_type == 0, "%s: Got %i records, expecting more\n", desc, state.count); + else + ok(expected[state.count].record_type == 0, "%s: Got %i records, expecting more\n", desc, state.count); + + GdipDeleteGraphics(graphics); + + DeleteDC(hdc); +} + +static BOOL CALLBACK play_metafile_proc(EmfPlusRecordType record_type, unsigned int flags, + unsigned int dataSize, const unsigned char *pStr, void *userdata) +{ + emfplus_check_state *state = (emfplus_check_state*)userdata; + GpStatus stat; + + stat = GdipPlayMetafileRecord(state->metafile, record_type, flags, dataSize, pStr); + + if (state->expected[state->count].record_type) + { + if (state->expected[state->count].playback_todo) + todo_wine ok(stat == Ok, "%s.%i: GdipPlayMetafileRecord failed with stat %i\n", state->desc, state->count, stat); + else + ok(stat == Ok, "%s.%i: GdipPlayMetafileRecord failed with stat %i\n", state->desc, state->count, stat); + state->count++; + } + else + { + if (state->expected[state->count].playback_todo) + todo_wine ok(0, "%s: too many records\n", state->desc); + else + ok(0, "%s: too many records\n", state->desc); + + return FALSE; + } + + return TRUE; +} + +static void play_metafile(GpMetafile *metafile, GpGraphics *graphics, const emfplus_record *expected, + const char *desc, const GpPointF *dst_points, const GpRectF *src_rect, Unit src_unit) +{ + GpStatus stat; + emfplus_check_state state; + + state.desc = desc; + state.count = 0; + state.expected = expected; + state.metafile = metafile; + + stat = GdipEnumerateMetafileSrcRectDestPoints(graphics, metafile, dst_points, + 3, src_rect, src_unit, play_metafile_proc, &state, NULL); + expect(Ok, stat); +} + +static const emfplus_record empty_records[] = { + {0, EMR_HEADER}, + {0, EmfPlusRecordTypeHeader}, + {0, EmfPlusRecordTypeEndOfFile}, + {0, EMR_EOF}, + {0} +}; + +static void test_empty(void) +{ + GpStatus stat; + GpMetafile *metafile; + GpGraphics *graphics; + HDC hdc; + HENHMETAFILE hemf, dummy; + BOOL ret; + static const GpRectF frame = {0.0, 0.0, 100.0, 100.0}; + static const GpPointF dst_points[3] = {{0.0,0.0},{100.0,0.0},{0.0,100.0}}; + static const WCHAR description[] = {'w','i','n','e','t','e','s','t',0}; + + hdc = CreateCompatibleDC(0); + + stat = GdipRecordMetafile(NULL, EmfTypeEmfPlusOnly, &frame, MetafileFrameUnitPixel, description, &metafile); + expect(InvalidParameter, stat); + + stat = GdipRecordMetafile(hdc, MetafileTypeInvalid, &frame, MetafileFrameUnitPixel, description, &metafile); + expect(InvalidParameter, stat); + + stat = GdipRecordMetafile(hdc, MetafileTypeWmf, &frame, MetafileFrameUnitPixel, description, &metafile); + expect(InvalidParameter, stat); + + stat = GdipRecordMetafile(hdc, MetafileTypeWmfPlaceable, &frame, MetafileFrameUnitPixel, description, &metafile); + expect(InvalidParameter, stat); + + stat = GdipRecordMetafile(hdc, MetafileTypeEmfPlusDual+1, &frame, MetafileFrameUnitPixel, description, &metafile); + expect(InvalidParameter, stat); + + stat = GdipRecordMetafile(hdc, EmfTypeEmfPlusOnly, &frame, MetafileFrameUnitPixel, description, NULL); + expect(InvalidParameter, stat); + + stat = GdipRecordMetafile(hdc, EmfTypeEmfPlusOnly, &frame, MetafileFrameUnitPixel, description, &metafile); + expect(Ok, stat); + + DeleteDC(hdc); + + if (stat != Ok) + return; + + stat = GdipGetHemfFromMetafile(metafile, &hemf); + expect(InvalidParameter, stat); + + stat = GdipGetImageGraphicsContext((GpImage*)metafile, &graphics); + expect(Ok, stat); + + stat = GdipGetHemfFromMetafile(metafile, &hemf); + expect(InvalidParameter, stat); + + stat = GdipDeleteGraphics(graphics); + expect(Ok, stat); + + check_metafile(metafile, empty_records, "empty metafile", dst_points, &frame, UnitPixel); + + stat = GdipGetHemfFromMetafile(metafile, &hemf); + expect(Ok, stat); + + stat = GdipGetHemfFromMetafile(metafile, &dummy); + expect(InvalidParameter, stat); + + stat = GdipDisposeImage((GpImage*)metafile); + expect(Ok, stat); + + check_emfplus(hemf, empty_records, "empty emf"); + + ret = DeleteEnhMetaFile(hemf); + ok(ret != 0, "Failed to delete enhmetafile %p\n", hemf); +} + +static const emfplus_record getdc_records[] = { + {0, EMR_HEADER}, + {0, EmfPlusRecordTypeHeader}, + {0, EmfPlusRecordTypeGetDC}, + {0, EMR_CREATEBRUSHINDIRECT}, + {0, EMR_SELECTOBJECT}, + {0, EMR_RECTANGLE}, + {0, EMR_SELECTOBJECT}, + {0, EMR_DELETEOBJECT}, + {0, EmfPlusRecordTypeEndOfFile}, + {0, EMR_EOF}, + {0} +}; + +static void test_getdc(void) +{ + GpStatus stat; + GpMetafile *metafile; + GpGraphics *graphics; + HDC hdc, metafile_dc; + HENHMETAFILE hemf; + BOOL ret; + static const GpRectF frame = {0.0, 0.0, 100.0, 100.0}; + static const GpPointF dst_points[3] = {{0.0,0.0},{100.0,0.0},{0.0,100.0}}; + static const GpPointF dst_points_half[3] = {{0.0,0.0},{50.0,0.0},{0.0,50.0}}; + static const WCHAR description[] = {'w','i','n','e','t','e','s','t',0}; + HBRUSH hbrush, holdbrush; + GpBitmap *bitmap; + ARGB color; + + hdc = CreateCompatibleDC(0); + + stat = GdipRecordMetafile(hdc, EmfTypeEmfPlusOnly, &frame, MetafileFrameUnitPixel, description, &metafile); + expect(Ok, stat); + + DeleteDC(hdc); + + if (stat != Ok) + return; + + stat = GdipGetHemfFromMetafile(metafile, &hemf); + expect(InvalidParameter, stat); + + stat = GdipGetImageGraphicsContext((GpImage*)metafile, &graphics); + expect(Ok, stat); + + stat = GdipGetDC(graphics, &metafile_dc); + expect(Ok, stat); + + if (stat != Ok) + { + GdipDeleteGraphics(graphics); + GdipDisposeImage((GpImage*)metafile); + return; + } + + hbrush = CreateSolidBrush(0xff0000); + + holdbrush = SelectObject(metafile_dc, hbrush); + + Rectangle(metafile_dc, 25, 25, 75, 75); + + SelectObject(metafile_dc, holdbrush); + + DeleteObject(hbrush); + + stat = GdipReleaseDC(graphics, metafile_dc); + expect(Ok, stat); + + stat = GdipDeleteGraphics(graphics); + expect(Ok, stat); + + check_metafile(metafile, getdc_records, "getdc metafile", dst_points, &frame, UnitPixel); + + stat = GdipCreateBitmapFromScan0(100, 100, 0, PixelFormat32bppARGB, NULL, &bitmap); + expect(Ok, stat); + + stat = GdipGetImageGraphicsContext((GpImage*)bitmap, &graphics); + expect(Ok, stat); + + play_metafile(metafile, graphics, getdc_records, "getdc playback", dst_points, &frame, UnitPixel); + + stat = GdipBitmapGetPixel(bitmap, 15, 15, &color); + expect(Ok, stat); + expect(0, color); + + stat = GdipBitmapGetPixel(bitmap, 50, 50, &color); + expect(Ok, stat); + expect(0xff0000ff, color); + + stat = GdipBitmapSetPixel(bitmap, 50, 50, 0); + expect(Ok, stat); + + play_metafile(metafile, graphics, getdc_records, "getdc playback", dst_points_half, &frame, UnitPixel); + + stat = GdipBitmapGetPixel(bitmap, 15, 15, &color); + expect(Ok, stat); + expect(0xff0000ff, color); + + stat = GdipBitmapGetPixel(bitmap, 50, 50, &color); + expect(Ok, stat); + expect(0, color); + + stat = GdipDeleteGraphics(graphics); + expect(Ok, stat); + + stat = GdipDisposeImage((GpImage*)bitmap); + expect(Ok, stat); + + stat = GdipGetHemfFromMetafile(metafile, &hemf); + expect(Ok, stat); + + stat = GdipDisposeImage((GpImage*)metafile); + expect(Ok, stat); + + check_emfplus(hemf, getdc_records, "getdc emf"); + + ret = DeleteEnhMetaFile(hemf); + ok(ret != 0, "Failed to delete enhmetafile %p\n", hemf); +} + +static const emfplus_record emfonly_records[] = { + {0, EMR_HEADER}, + {0, EMR_CREATEBRUSHINDIRECT}, + {0, EMR_SELECTOBJECT}, + {0, EMR_RECTANGLE}, + {0, EMR_SELECTOBJECT}, + {0, EMR_DELETEOBJECT}, + {0, EMR_EOF}, + {0} +}; + +static void test_emfonly(void) +{ + GpStatus stat; + GpMetafile *metafile; + GpGraphics *graphics; + HDC hdc, metafile_dc; + HENHMETAFILE hemf; + BOOL ret; + static const GpRectF frame = {0.0, 0.0, 100.0, 100.0}; + static const GpPointF dst_points[3] = {{0.0,0.0},{100.0,0.0},{0.0,100.0}}; + static const WCHAR description[] = {'w','i','n','e','t','e','s','t',0}; + HBRUSH hbrush, holdbrush; + GpBitmap *bitmap; + ARGB color; + + hdc = CreateCompatibleDC(0); + + stat = GdipRecordMetafile(hdc, EmfTypeEmfOnly, &frame, MetafileFrameUnitPixel, description, &metafile); + expect(Ok, stat); + + DeleteDC(hdc); + + if (stat != Ok) + return; + + stat = GdipGetHemfFromMetafile(metafile, &hemf); + expect(InvalidParameter, stat); + + stat = GdipGetImageGraphicsContext((GpImage*)metafile, &graphics); + expect(Ok, stat); + + stat = GdipGetDC(graphics, &metafile_dc); + expect(Ok, stat); + + if (stat != Ok) + { + GdipDeleteGraphics(graphics); + GdipDisposeImage((GpImage*)metafile); + return; + } + + hbrush = CreateSolidBrush(0xff0000); + + holdbrush = SelectObject(metafile_dc, hbrush); + + Rectangle(metafile_dc, 25, 25, 75, 75); + + SelectObject(metafile_dc, holdbrush); + + DeleteObject(hbrush); + + stat = GdipReleaseDC(graphics, metafile_dc); + expect(Ok, stat); + + stat = GdipDeleteGraphics(graphics); + expect(Ok, stat); + + check_metafile(metafile, emfonly_records, "emfonly metafile", dst_points, &frame, UnitPixel); + + stat = GdipCreateBitmapFromScan0(100, 100, 0, PixelFormat32bppARGB, NULL, &bitmap); + expect(Ok, stat); + + stat = GdipGetImageGraphicsContext((GpImage*)bitmap, &graphics); + expect(Ok, stat); + + play_metafile(metafile, graphics, emfonly_records, "emfonly playback", dst_points, &frame, UnitPixel); + + stat = GdipBitmapGetPixel(bitmap, 15, 15, &color); + expect(Ok, stat); + expect(0, color); + + stat = GdipBitmapGetPixel(bitmap, 50, 50, &color); + expect(Ok, stat); + expect(0xff0000ff, color); + + stat = GdipDeleteGraphics(graphics); + expect(Ok, stat); + + stat = GdipDisposeImage((GpImage*)bitmap); + expect(Ok, stat); + + stat = GdipGetHemfFromMetafile(metafile, &hemf); + expect(Ok, stat); + + stat = GdipDisposeImage((GpImage*)metafile); + expect(Ok, stat); + + check_emfplus(hemf, emfonly_records, "emfonly emf"); + + ret = DeleteEnhMetaFile(hemf); + ok(ret != 0, "Failed to delete enhmetafile %p\n", hemf); +} + +START_TEST(metafile) +{ + struct GdiplusStartupInput gdiplusStartupInput; + ULONG_PTR gdiplusToken; + + gdiplusStartupInput.GdiplusVersion = 1; + gdiplusStartupInput.DebugEventCallback = NULL; + gdiplusStartupInput.SuppressBackgroundThread = 0; + gdiplusStartupInput.SuppressExternalCodecs = 0; + + GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); + + test_empty(); + test_getdc(); + test_emfonly(); + + GdiplusShutdown(gdiplusToken); +} diff --git a/rostests/winetests/gdiplus/testlist.c b/rostests/winetests/gdiplus/testlist.c index 05456c6b9f7..5d6e08bec41 100644 --- a/rostests/winetests/gdiplus/testlist.c +++ b/rostests/winetests/gdiplus/testlist.c @@ -13,6 +13,7 @@ extern void func_graphics(void); extern void func_graphicspath(void); extern void func_image(void); extern void func_matrix(void); +extern void func_metafile(void); extern void func_pathiterator(void); extern void func_pen(void); extern void func_region(void); @@ -21,12 +22,13 @@ extern void func_stringformat(void); const struct test winetest_testlist[] = { { "brush", func_brush }, - { "customlinecap", func_customlinecap }, + { "customlinecap", func_customlinecap }, { "font", func_font }, { "graphics", func_graphics }, { "graphicspath", func_graphicspath }, { "image", func_image }, { "matrix", func_matrix }, + { "metafile", func_metafile }, { "pathiterator", func_pathiterator }, { "pen", func_pen }, { "region", func_region },