From: Damjan Jovanovic Subject: [PATCH v2 2/2] gdiplus: GdipGraphicsClear() should overwrite pixels, not alpha blend Message-Id: Date: Fri, 13 Dec 2019 05:17:54 +0200 All sample code in the Python Pyglet library suffers from terrible text corruption, caused by the inability to erase the background between rendering sequential font glyphs, resulting in leftovers from previous letters mixing with the image of new letters. This is because it attempts to erase the background by calling GdipGraphicsClear() with ARGB color 0x00000000 (completely transparent black), and in our gdiplus alpha blending that into the background has no effect. It should be using CompositeModeSourceCopy to overwrite the background with that brush instead. Try 2 split the patch. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=30506 Signed-off-by: Damjan Jovanovic --- dlls/gdiplus/graphics.c | 4 ++++ dlls/gdiplus/tests/image.c | 43 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c index e0a013896f..e485e5c99f 100644 --- a/dlls/gdiplus/graphics.c +++ b/dlls/gdiplus/graphics.c @@ -4949,6 +4949,7 @@ GpStatus WINGDIPAPI GdipGraphicsClear(GpGraphics *graphics, ARGB color) GpSolidFill *brush; GpStatus stat; GpRectF wnd_rect; + CompositingMode prev_comp_mode; TRACE("(%p, %x)\n", graphics, color); @@ -4969,8 +4970,11 @@ GpStatus WINGDIPAPI GdipGraphicsClear(GpGraphics *graphics, ARGB color) return stat; } + GdipGetCompositingMode(graphics, &prev_comp_mode); + GdipSetCompositingMode(graphics, CompositingModeSourceCopy); GdipFillRectangle(graphics, (GpBrush*)brush, wnd_rect.X, wnd_rect.Y, wnd_rect.Width, wnd_rect.Height); + GdipSetCompositingMode(graphics, prev_comp_mode); GdipDeleteBrush((GpBrush*)brush); diff --git a/dlls/gdiplus/tests/image.c b/dlls/gdiplus/tests/image.c index 74c471e9ac..62cd79fec6 100644 --- a/dlls/gdiplus/tests/image.c +++ b/dlls/gdiplus/tests/image.c @@ -5485,6 +5485,48 @@ todo_wine HeapFree(GetProcessHeap(), 0, data); } +static void test_graphics_clear(void) +{ + BYTE argb[8] = { 0x11,0x22,0x33,0x80, 0xff,0xff,0xff,0 }; + BYTE cleared[8] = { 0,0,0,0, 0,0,0,0 }; + BYTE *bits; + GpBitmap *bitmap; + GpGraphics *graphics; + BitmapData data; + GpStatus status; + int match; + + status = GdipCreateBitmapFromScan0(2, 1, 8, PixelFormat32bppARGB, argb, &bitmap); + expect(Ok, status); + + status = GdipGetImageGraphicsContext((GpImage*)bitmap, &graphics); + expect(Ok, status); + + status = GdipGraphicsClear(graphics, 0x00000000); + expect(Ok, status); + + status = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead, PixelFormat32bppARGB, &data); + expect(Ok, status); + ok(data.Width == 2, "expected 2, got %d\n", data.Width); + ok(data.Height == 1, "expected 1, got %d\n", data.Height); + ok(data.Stride == 8, "expected 8, got %d\n", data.Stride); + ok(data.PixelFormat == PixelFormat32bppARGB, "expected PixelFormat32bppARGB, got %d\n", data.PixelFormat); + match = !memcmp(data.Scan0, cleared, sizeof(cleared)); + ok(match, "bits don't match\n"); + if (!match) + { + bits = data.Scan0; + trace("format %#x, bits %02x,%02x,%02x,%02x %02x,%02x,%02x,%02x\n", PixelFormat32bppPARGB, + bits[0], bits[1], bits[2], bits[3], bits[4], bits[5], bits[6], bits[7]); + } + status = GdipBitmapUnlockBits(bitmap, &data); + expect(Ok, status); + + status = GdipDeleteGraphics(graphics); + expect(Ok, status); + GdipDisposeImage((GpImage *)bitmap); +} + START_TEST(image) { HMODULE mod = GetModuleHandleA("gdiplus.dll"); @@ -5560,6 +5602,7 @@ START_TEST(image) test_histogram(); test_imageabort(); test_GdipLoadImageFromStream(); + test_graphics_clear(); GdiplusShutdown(gdiplusToken); }