From: Giovanni Mascellani wine@mascellani.eu
Signed-off-by: Giovanni Mascellani gmascellani@codeweavers.com --- dlls/d2d1/d2d1.spec | 2 +- dlls/d2d1/factory.c | 59 ++++++++++++++++++++++++++++ dlls/d2d1/tests/d2d1.c | 87 ++++++++++++++++++++++++++++++++++++++++++ include/d2d1_1.idl | 2 + 4 files changed, 149 insertions(+), 1 deletion(-)
diff --git a/dlls/d2d1/d2d1.spec b/dlls/d2d1/d2d1.spec index 0ae894109fb..3fa85a93bae 100644 --- a/dlls/d2d1/d2d1.spec +++ b/dlls/d2d1/d2d1.spec @@ -3,7 +3,7 @@ @ stdcall D2D1MakeSkewMatrix(float float float float ptr) @ stdcall D2D1IsMatrixInvertible(ptr) @ stdcall D2D1InvertMatrix(ptr) -@ stub D2D1ConvertColorSpace +@ stdcall D2D1ConvertColorSpace(long long ptr) @ stdcall D2D1CreateDevice(ptr ptr ptr) @ stub D2D1CreateDeviceContext @ stdcall D2D1SinCos(float ptr ptr) diff --git a/dlls/d2d1/factory.c b/dlls/d2d1/factory.c index 6b6eab766c7..fcc09f59672 100644 --- a/dlls/d2d1/factory.c +++ b/dlls/d2d1/factory.c @@ -735,6 +735,65 @@ float WINAPI D2D1Vec3Length(float x, float y, float z) return sqrtf(x * x + y * y + z * z); }
+/* Formulae taken from https://en.wikipedia.org/wiki/SRGB. */ +static float srgb_transfer_function(float x) +{ + if (x <= 0.0f) + return 0.0f; + else if (x >= 1.0f) + return 1.0f; + else if (x <= 0.0031308f) + return 12.92f * x; + else + return 1.055f * powf(x, 1.0f / 2.4f) - 0.055f; +} + +static float srgb_inverse_transfer_function(float x) +{ + if (x <= 0.0f) + return 0.0f; + else if (x >= 1.0f) + return 1.0f; + else if (x <= 0.04045f) + return x / 12.92f; + else + return powf((x + 0.055f) / 1.055f, 2.4f); +} + +D2D1_COLOR_F WINAPI D2D1ConvertColorSpace(D2D1_COLOR_SPACE sourceColorSpace, + D2D1_COLOR_SPACE destinationColorSpace, const D2D1_COLOR_F *color) +{ + D2D1_COLOR_F ret; + + if (sourceColorSpace == D2D1_COLOR_SPACE_CUSTOM || destinationColorSpace == D2D1_COLOR_SPACE_CUSTOM) { + ret.r = 0.0f; + ret.g = 0.0f; + ret.b = 0.0f; + ret.a = 0.0f; + } else if (sourceColorSpace == destinationColorSpace) { + ret = *color; + } else if (sourceColorSpace == D2D1_COLOR_SPACE_SRGB && destinationColorSpace == D2D1_COLOR_SPACE_SCRGB) { + ret.r = srgb_inverse_transfer_function(color->r); + ret.g = srgb_inverse_transfer_function(color->g); + ret.b = srgb_inverse_transfer_function(color->b); + ret.a = color->a; + } else if (sourceColorSpace == D2D1_COLOR_SPACE_SCRGB && destinationColorSpace == D2D1_COLOR_SPACE_SRGB) { + ret.r = srgb_transfer_function(color->r); + ret.g = srgb_transfer_function(color->g); + ret.b = srgb_transfer_function(color->b); + ret.a = color->a; + } else { + FIXME("unknown combination sourceColorSpace %x, destinationColorSpace %x!\n", + sourceColorSpace, destinationColorSpace); + ret.r = 0.0f; + ret.g = 0.0f; + ret.b = 0.0f; + ret.a = 0.0f; + } + + return ret; +} + static BOOL get_config_key_dword(HKEY default_key, HKEY application_key, const char *name, DWORD *value) { DWORD type, data, size; diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c index 8d584605819..b672765792a 100644 --- a/dlls/d2d1/tests/d2d1.c +++ b/dlls/d2d1/tests/d2d1.c @@ -34,6 +34,8 @@ static HRESULT (WINAPI *pD2D1CreateDevice)(IDXGIDevice *dxgi_device, static void (WINAPI *pD2D1SinCos)(float angle, float *s, float *c); static float (WINAPI *pD2D1Tan)(float angle); static float (WINAPI *pD2D1Vec3Length)(float x, float y, float z); +static D2D1_COLOR_F (WINAPI *pD2D1ConvertColorSpace)(D2D1_COLOR_SPACE sourceColorSpace, + D2D1_COLOR_SPACE destinationColorSpace, const D2D1_COLOR_F *color);
static BOOL use_mt = TRUE;
@@ -9466,6 +9468,89 @@ static void test_math(BOOL d3d11) } }
+static void test_color_space(BOOL d3d11) +{ + D2D1_COLOR_SPACE srcS, dstS; + int i, j; + + static struct { + D2D1_COLOR_F srgb; + D2D1_COLOR_F scrgb; + } const test_data[] = { + {{0.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f, 0.0f}}, + {{0.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 0.0f, 1.0f}}, + {{1.0f, 1.0f, 1.0f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f}}, + /* Samples in the non-linear region. */ + {{0.2f, 0.4f, 0.6f, 0.8f}, {0.0331047624f, 0.132868335f, 0.318546832f, 0.8f}}, + {{0.3f, 0.5f, 0.7f, 0.9f}, {0.0732389688f, 0.214041144f, 0.447988421f, 0.9f}}, + /* Samples in the linear region. */ + {{0.0002f, 0.0004f, 0.0006f, 0.0008f}, {1.54798763e-005f, 3.09597526e-005f, 4.64396289e-005f, 0.0008f}}, + {{0.0003f, 0.0005f, 0.0007f, 0.0009f}, {2.32198145e-005f, 3.86996908e-005f, 5.41795634e-005f, 0.0009f}}, + }; + + if (!pD2D1ConvertColorSpace) + { + win_skip("D2D1ConvertColorSpace not available, skipping test.\n"); + return; + } + + for (srcS = 0; srcS < 3; srcS++) + for (dstS = 0; dstS < 3; dstS++) + for (i = 0; i < ARRAY_SIZE(test_data); i++) + for (j = 0; j < 3; j++) + { + D2D1_COLOR_F src = test_data[i].srgb, dst, expect; + BOOL change_expect = TRUE; + + if (srcS == D2D1_COLOR_SPACE_SCRGB) + src = test_data[i].scrgb; + if (srcS == D2D1_COLOR_SPACE_CUSTOM || dstS == D2D1_COLOR_SPACE_CUSTOM) + { + expect.r = 0.0f; + expect.g = 0.0f; + expect.b = 0.0f; + expect.a = 0.0f; + change_expect = FALSE; + } + else if (srcS == dstS) + expect = src; + else if (dstS == D2D1_COLOR_SPACE_SRGB) + expect = test_data[i].srgb; + else if (dstS == D2D1_COLOR_SPACE_SCRGB) + expect = test_data[i].scrgb; + else + ok(0, "Should not arrive here.\n"); + + /* Test underflowing or overflowing some components. */ + if (j == 1) + { + src.r = -0.5f; + src.a = -0.7f; + if (change_expect) + { + expect.r = srcS == dstS ? src.r : 0.0f; + expect.a = src.a; + } + } + else if (j == 2) + { + src.g = 1.5f; + src.a = 1.7f; + if (change_expect) + { + expect.g = srcS == dstS ? src.g : 1.0f; + expect.a = src.a; + } + } + + dst = pD2D1ConvertColorSpace(srcS, dstS, &src); + ok(compare_float(dst.r, expect.r, 1) && compare_float(dst.g, expect.g, 1) + && compare_float(dst.b, expect.b, 1) && compare_float(dst.a, expect.a, 1), + "Unexpected value {%.8e, %.8e, %.8e, %.8e} -> {%.8e, %.8e, %.8e, %.8e}, expected {%.8e, %.8e, %.8e, %.8e}, while converting %d -> %d.\n", + src.r, src.g, src.b, src.a, dst.r, dst.g, dst.b, dst.a, expect.r, expect.g, expect.b, expect.a, srcS, dstS); + } +} + START_TEST(d2d1) { HMODULE d2d1_dll = GetModuleHandleA("d2d1.dll"); @@ -9476,6 +9561,7 @@ START_TEST(d2d1) pD2D1SinCos = (void *)GetProcAddress(d2d1_dll, "D2D1SinCos"); pD2D1Tan = (void *)GetProcAddress(d2d1_dll, "D2D1Tan"); pD2D1Vec3Length = (void *)GetProcAddress(d2d1_dll, "D2D1Vec3Length"); + pD2D1ConvertColorSpace = (void *)GetProcAddress(d2d1_dll, "D2D1ConvertColorSpace");
use_mt = !getenv("WINETEST_NO_MT_D3D");
@@ -9523,6 +9609,7 @@ START_TEST(d2d1) queue_test(test_dpi); queue_test(test_wic_bitmap_format); queue_d3d10_test(test_math); + queue_d3d10_test(test_color_space);
run_queued_tests(); } diff --git a/include/d2d1_1.idl b/include/d2d1_1.idl index 1bcadab01d5..e98262c035f 100644 --- a/include/d2d1_1.idl +++ b/include/d2d1_1.idl @@ -962,3 +962,5 @@ interface ID2D1Multithread : IUnknown [local] void __stdcall D2D1SinCos(float angle, float *s, float *c); [local] float __stdcall D2D1Tan(float angle); [local] float __stdcall D2D1Vec3Length(float x, float y, float z); +[local] D2D1_COLOR_F __stdcall D2D1ConvertColorSpace(D2D1_COLOR_SPACE sourceColorSpace, + D2D1_COLOR_SPACE destinationColorSpace, const D2D1_COLOR_F *color);