[PATCH] gdiplus: GdipGraphicsClear() should overwrite pixels, not alpha blend

Damjan Jovanovic damjan.jov at gmail.com
Thu Dec 12 14:11:11 CST 2019


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.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=30506

Signed-off-by: Damjan Jovanovic <damjan.jov at gmail.com>
---
 dlls/gdiplus/graphics.c    | 26 +++++++++++++++------
 dlls/gdiplus/tests/image.c | 47 ++++++++++++++++++++++++++++++++++++--
 2 files changed, 64 insertions(+), 9 deletions(-)
-------------- next part --------------
diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c
index 3c83278a4b..e485e5c99f 100644
--- a/dlls/gdiplus/graphics.c
+++ b/dlls/gdiplus/graphics.c
@@ -372,6 +372,9 @@ static GpStatus alpha_blend_bmp_pixels(GpGraphics *graphics, INT dst_x, INT dst_
 {
     GpBitmap *dst_bitmap = (GpBitmap*)graphics->image;
     INT x, y;
+    CompositingMode comp_mode;
+
+    GdipGetCompositingMode(graphics, &comp_mode);
 
     for (y=0; y<src_height; y++)
     {
@@ -380,14 +383,19 @@ static GpStatus alpha_blend_bmp_pixels(GpGraphics *graphics, INT dst_x, INT dst_
             ARGB dst_color, src_color;
             src_color = ((ARGB*)(src + src_stride * y))[x];
 
-            if (!(src_color & 0xff000000))
-                continue;
-
-            GdipBitmapGetPixel(dst_bitmap, x+dst_x, y+dst_y, &dst_color);
-            if (fmt & PixelFormatPAlpha)
-                GdipBitmapSetPixel(dst_bitmap, x+dst_x, y+dst_y, color_over_fgpremult(dst_color, src_color));
+            if (comp_mode == CompositingModeSourceCopy)
+                GdipBitmapSetPixel(dst_bitmap, x+dst_x, y+dst_y, src_color);
             else
-                GdipBitmapSetPixel(dst_bitmap, x+dst_x, y+dst_y, color_over(dst_color, src_color));
+            {
+                if (!(src_color & 0xff000000))
+                    continue;
+
+                GdipBitmapGetPixel(dst_bitmap, x+dst_x, y+dst_y, &dst_color);
+                if (fmt & PixelFormatPAlpha)
+                    GdipBitmapSetPixel(dst_bitmap, x+dst_x, y+dst_y, color_over_fgpremult(dst_color, src_color));
+                else
+                    GdipBitmapSetPixel(dst_bitmap, x+dst_x, y+dst_y, color_over(dst_color, src_color));
+            }
         }
     }
 
@@ -4941,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);
 
@@ -4961,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 60591b0aca..62cd79fec6 100644
--- a/dlls/gdiplus/tests/image.c
+++ b/dlls/gdiplus/tests/image.c
@@ -4205,9 +4205,9 @@ static void test_DrawImage_SourceCopy(void)
     status = GdipDrawImageI(graphics, u2.image, 0, 0);
     expect(Ok, status);
 
-    todo_wine expect(0, dst_pixels[0]);
+    expect(0, dst_pixels[0]);
     expect(0xffff0000, dst_pixels[1]);
-    todo_wine expect(0, dst_pixels[2]);
+    expect(0, dst_pixels[2]);
     todo_wine expect(0, dst_pixels[3]);
 
     status = GdipDeleteGraphics(graphics);
@@ -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);
 }


More information about the wine-devel mailing list