[PATCH v2 0/2] MR10162: d2d1: Clamp opacity value for d2d_device_context_draw_bitmap().
Some applications call DrawBitmap() with the opacity value set to 255.0f and end up showing white in the end result. Tests show that the opacity value should be clamped to legitimate values. Command lists store the original opacity value according to tests. -- v2: d2d1: Clamp opacity value for brushes. d2d1/tests: Test brushes with out of range opacity values. https://gitlab.winehq.org/wine/wine/-/merge_requests/10162
From: Zhiyi Zhang <zzhang@codeweavers.com> --- dlls/d2d1/tests/d2d1.c | 127 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c index 012f3005d09..51b0fa856a9 100644 --- a/dlls/d2d1/tests/d2d1.c +++ b/dlls/d2d1/tests/d2d1.c @@ -2438,9 +2438,11 @@ static void test_color_brush(BOOL d3d11) D2D1_COLOR_F color, tmp_color; struct d2d1_test_context ctx; ID2D1SolidColorBrush *brush; + struct resource_readback rb; ID2D1RenderTarget *rt; D2D1_RECT_F rect; float opacity; + DWORD colour; HRESULT hr; BOOL match; @@ -2513,6 +2515,40 @@ static void test_color_brush(BOOL d3d11) ok(match, "Surface does not match.\n"); ID2D1SolidColorBrush_Release(brush); + + /* Test solid color brushes with out of range opacity values */ + ID2D1RenderTarget_SetDpi(rt, 96.0f, 96.0f); + ID2D1RenderTarget_SetAntialiasMode(rt, D2D1_ANTIALIAS_MODE_PER_PRIMITIVE); + ID2D1RenderTarget_BeginDraw(rt); + set_matrix_identity(&matrix); + ID2D1RenderTarget_SetTransform(rt, &matrix); + set_color(&color, 0.0f, 0.0f, 0.0f, 1.0f); + ID2D1RenderTarget_Clear(rt, &color); + set_color(&color, 0.5f, 0.0f, 0.0f, 1.0f); + hr = ID2D1RenderTarget_CreateSolidColorBrush(rt, &color, NULL, &brush); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ID2D1SolidColorBrush_SetOpacity(brush, 255.0f); + opacity = ID2D1SolidColorBrush_GetOpacity(brush); + ok(opacity == 255.0f, "Got unexpected opacity %.8e.\n", opacity); + set_rect(&rect, 0.0f, 0.0f, 1.0f, 1.0f); + ID2D1RenderTarget_FillRectangle(rt, &rect, (ID2D1Brush *)brush); + ID2D1SolidColorBrush_SetOpacity(brush, -255.0f); + opacity = ID2D1SolidColorBrush_GetOpacity(brush); + ok(opacity == -255.0f, "Got unexpected opacity %.8e.\n", opacity); + set_rect(&rect, 1.0f, 0.0f, 2.0f, 1.0f); + ID2D1RenderTarget_FillRectangle(rt, &rect, (ID2D1Brush *)brush); + ID2D1SolidColorBrush_Release(brush); + hr = ID2D1RenderTarget_EndDraw(rt, NULL, NULL); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + get_surface_readback(&ctx, &rb); + colour = get_readback_colour(&rb, 0, 0); + todo_wine + ok(compare_colour(colour, 0xff7f0000, 1), "Got unexpected colour 0x%08lx.\n", colour); + colour = get_readback_colour(&rb, 1, 0); + ok(compare_colour(colour, 0xff010000, 1), "Got unexpected colour 0x%08lx.\n", colour); + release_resource_readback(&rb); + release_test_context(&ctx); } @@ -2527,6 +2563,7 @@ static void test_bitmap_brush(BOOL d3d11) D2D1_RECT_F src_rect, dst_rect; struct d2d1_test_context ctx; D2D1_EXTEND_MODE extend_mode; + struct resource_readback rb; ID2D1BitmapBrush1 *brush1; ID2D1BitmapBrush *brush; D2D1_SIZE_F image_size; @@ -2538,6 +2575,7 @@ static void test_bitmap_brush(BOOL d3d11) unsigned int i; ULONG refcount; float opacity; + DWORD colour; HRESULT hr; BOOL match; @@ -2568,6 +2606,10 @@ static void test_bitmap_brush(BOOL d3d11) 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, }; + static const DWORD opacity_test_bitmap_data[] = + { + 0xff7f0000 + }; if (!init_test_context(&ctx, d3d11)) return; @@ -2900,6 +2942,91 @@ static void test_bitmap_brush(BOOL d3d11) ID2D1BitmapBrush_Release(brush); refcount = ID2D1Bitmap_Release(bitmap); ok(!refcount, "Bitmap has %lu references left.\n", refcount); + + /* Test ID2D1RenderTarget_DrawBitmap() with out of range opacity values */ + set_size_u(&size, 1, 1); + bitmap_desc.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM; + bitmap_desc.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED; + bitmap_desc.dpiX = 96.0f; + bitmap_desc.dpiY = 96.0f; + hr = ID2D1RenderTarget_CreateBitmap(rt, size, opacity_test_bitmap_data, + sizeof(*bitmap_data), &bitmap_desc, &bitmap); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + ID2D1RenderTarget_SetDpi(rt, 96.0f, 96.0f); + ID2D1RenderTarget_SetAntialiasMode(rt, D2D1_ANTIALIAS_MODE_PER_PRIMITIVE); + ID2D1RenderTarget_BeginDraw(rt); + set_color(&color, 0.0f, 0.0f, 0.0f, 1.0f); + ID2D1RenderTarget_Clear(rt, &color); + set_rect(&dst_rect, 0.0f, 0.0f, 1.0f, 1.0f); + ID2D1RenderTarget_DrawBitmap(rt, bitmap, &dst_rect, 255.0f, + D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR, NULL); + set_rect(&dst_rect, 1.0f, 0.0f, 2.0f, 1.0f); + ID2D1RenderTarget_DrawBitmap(rt, bitmap, &dst_rect, -255.0f, + D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR, NULL); + hr = ID2D1RenderTarget_EndDraw(rt, NULL, NULL); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + get_surface_readback(&ctx, &rb); + colour = get_readback_colour(&rb, 0, 0); + todo_wine + ok(compare_colour(colour, 0xff7f0000, 1), "Got unexpected colour 0x%08lx.\n", colour); + colour = get_readback_colour(&rb, 1, 0); + ok(compare_colour(colour, 0xff010000, 1), "Got unexpected colour 0x%08lx.\n", colour); + release_resource_readback(&rb); + + /* Test ID2D1DeviceContext_DrawBitmap() with out of range opacity values */ + ID2D1DeviceContext_BeginDraw(ctx.context); + set_color(&color, 0.0f, 0.0f, 0.0f, 1.0f); + ID2D1DeviceContext_Clear(ctx.context, &color); + set_rect(&dst_rect, 0.0f, 0.0f, 1.0f, 1.0f); + ID2D1DeviceContext_DrawBitmap(ctx.context, bitmap, &dst_rect, 255.0f, + D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, NULL, NULL); + set_rect(&dst_rect, 1.0f, 0.0f, 2.0f, 1.0f); + ID2D1DeviceContext_DrawBitmap(ctx.context, bitmap, &dst_rect, -255.0f, + D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, NULL, NULL); + hr = ID2D1DeviceContext_EndDraw(ctx.context, NULL, NULL); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + get_surface_readback(&ctx, &rb); + colour = get_readback_colour(&rb, 0, 0); + todo_wine + ok(compare_colour(colour, 0xff7f0000, 1), "Got unexpected colour 0x%08lx.\n", colour); + colour = get_readback_colour(&rb, 1, 0); + ok(compare_colour(colour, 0xff010000, 1), "Got unexpected colour 0x%08lx.\n", colour); + release_resource_readback(&rb); + + /* Test bitmap brushes with out of range opacity values */ + ID2D1RenderTarget_BeginDraw(rt); + set_matrix_identity(&matrix); + ID2D1RenderTarget_SetTransform(rt, &matrix); + set_color(&color, 0.0f, 0.0f, 0.0f, 1.0f); + ID2D1RenderTarget_Clear(rt, &color); + hr = ID2D1RenderTarget_CreateBitmapBrush(rt, bitmap, NULL, NULL, &brush); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ID2D1BitmapBrush_SetOpacity(brush, 255.0f); + opacity = ID2D1BitmapBrush_GetOpacity(brush); + ok(opacity == 255.0f, "Got unexpected opacity %.8e.\n", opacity); + set_rect(&dst_rect, 0.0f, 0.0f, 1.0f, 1.0f); + ID2D1RenderTarget_FillRectangle(rt, &dst_rect, (ID2D1Brush *)brush); + ID2D1BitmapBrush_SetOpacity(brush, -255.0f); + opacity = ID2D1BitmapBrush_GetOpacity(brush); + ok(opacity == -255.0f, "Got unexpected opacity %.8e.\n", opacity); + set_rect(&dst_rect, 1.0f, 0.0f, 2.0f, 1.0f); + ID2D1RenderTarget_FillRectangle(rt, &dst_rect, (ID2D1Brush *)brush); + ID2D1BitmapBrush_Release(brush); + hr = ID2D1RenderTarget_EndDraw(rt, NULL, NULL); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + get_surface_readback(&ctx, &rb); + colour = get_readback_colour(&rb, 0, 0); + todo_wine + ok(compare_colour(colour, 0xff7f0000, 1), "Got unexpected colour 0x%08lx.\n", colour); + colour = get_readback_colour(&rb, 1, 0); + ok(compare_colour(colour, 0xff010000, 1), "Got unexpected colour 0x%08lx.\n", colour); + release_resource_readback(&rb); + + ID2D1Bitmap_Release(bitmap); release_test_context(&ctx); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10162
From: Zhiyi Zhang <zzhang@codeweavers.com> Some applications call DrawBitmap() with the opacity value set to 255.0f and end up showing white in the end result. Tests show that the opacity value should be clamped to legitimate values. Command lists store the original opacity value according to tests. --- dlls/d2d1/brush.c | 2 +- dlls/d2d1/tests/d2d1.c | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/dlls/d2d1/brush.c b/dlls/d2d1/brush.c index 50754a2f21a..ea09e6eebbd 100644 --- a/dlls/d2d1/brush.c +++ b/dlls/d2d1/brush.c @@ -1385,7 +1385,7 @@ BOOL d2d_brush_fill_cb(const struct d2d_brush *brush, struct d2d_brush_cb *cb) } cb->type = brush->type; - cb->opacity = brush->opacity; + cb->opacity = max(0.0f, min(brush->opacity, 1.0f)); switch (brush->type) { diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c index 51b0fa856a9..2d64e8440f4 100644 --- a/dlls/d2d1/tests/d2d1.c +++ b/dlls/d2d1/tests/d2d1.c @@ -2543,7 +2543,6 @@ static void test_color_brush(BOOL d3d11) get_surface_readback(&ctx, &rb); colour = get_readback_colour(&rb, 0, 0); - todo_wine ok(compare_colour(colour, 0xff7f0000, 1), "Got unexpected colour 0x%08lx.\n", colour); colour = get_readback_colour(&rb, 1, 0); ok(compare_colour(colour, 0xff010000, 1), "Got unexpected colour 0x%08lx.\n", colour); @@ -2969,7 +2968,6 @@ static void test_bitmap_brush(BOOL d3d11) get_surface_readback(&ctx, &rb); colour = get_readback_colour(&rb, 0, 0); - todo_wine ok(compare_colour(colour, 0xff7f0000, 1), "Got unexpected colour 0x%08lx.\n", colour); colour = get_readback_colour(&rb, 1, 0); ok(compare_colour(colour, 0xff010000, 1), "Got unexpected colour 0x%08lx.\n", colour); @@ -2990,7 +2988,6 @@ static void test_bitmap_brush(BOOL d3d11) get_surface_readback(&ctx, &rb); colour = get_readback_colour(&rb, 0, 0); - todo_wine ok(compare_colour(colour, 0xff7f0000, 1), "Got unexpected colour 0x%08lx.\n", colour); colour = get_readback_colour(&rb, 1, 0); ok(compare_colour(colour, 0xff010000, 1), "Got unexpected colour 0x%08lx.\n", colour); @@ -3020,7 +3017,6 @@ static void test_bitmap_brush(BOOL d3d11) get_surface_readback(&ctx, &rb); colour = get_readback_colour(&rb, 0, 0); - todo_wine ok(compare_colour(colour, 0xff7f0000, 1), "Got unexpected colour 0x%08lx.\n", colour); colour = get_readback_colour(&rb, 1, 0); ok(compare_colour(colour, 0xff010000, 1), "Got unexpected colour 0x%08lx.\n", colour); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10162
v2: Clamp opacity for brushes. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10162#note_130320
This merge request was approved by Nikolay Sivov. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10162
participants (3)
-
Nikolay Sivov (@nsivov) -
Zhiyi Zhang -
Zhiyi Zhang (@zhiyi)