[PATCH] gdi32: fix PatBlt() drawing with negative width/height

Damjan Jovanovic damjan.jov at gmail.com
Sat Nov 14 03:56:57 CST 2020


In a (x, y, w, h) rectangle passed to PatBlt(), a negative w results in
the rectangle drawn being (x+w, y, -w, h), and negative h results in
(x, y+h, w, -h). Wine instead does (x+w+1, y, -w, h) and
(x, y+h+1, w, -h), so the rectangle drawn is shifted
1 pixel row too far down and/or 1 pixel column too far right.
This patch recalculates the rectangle dimensions correctly.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=27584
Signed-off-by: Damjan Jovanovic <damjan.jov at gmail.com>
---
 dlls/gdi32/bitblt.c       | 11 +++++++++++
 dlls/gdi32/tests/bitmap.c | 36 ++++++++++++++++++++++++++++++++++++
 2 files changed, 47 insertions(+)
-------------- next part --------------
diff --git a/dlls/gdi32/bitblt.c b/dlls/gdi32/bitblt.c
index d2cc746c3fe..445ce1ab1f2 100644
--- a/dlls/gdi32/bitblt.c
+++ b/dlls/gdi32/bitblt.c
@@ -539,6 +539,17 @@ BOOL WINAPI PatBlt( HDC hdc, INT left, INT top, INT width, INT height, DWORD rop
 
         update_dc( dc );
 
+        if (width < 0)
+        {
+            left += width;
+            width = -width;
+        }
+        if (height < 0)
+        {
+            top += height;
+            height = -height;
+        }
+
         dst.log_x      = left;
         dst.log_y      = top;
         dst.log_width  = width;
diff --git a/dlls/gdi32/tests/bitmap.c b/dlls/gdi32/tests/bitmap.c
index fe3482671b2..a3969cf25d6 100644
--- a/dlls/gdi32/tests/bitmap.c
+++ b/dlls/gdi32/tests/bitmap.c
@@ -3074,6 +3074,41 @@ static void test_BitBlt(void)
     DeleteDC(hdcScreen);
 }
 
+static void test_PatBlt(void)
+{
+    HDC hdc;
+    HBITMAP hbmp, holdbmp;
+    HBRUSH holdbrush;
+    RECT r;
+    const DWORD b = 0;
+    const DWORD w = 0xffffff;
+
+    hdc = CreateCompatibleDC(0);
+    ok(hdc != NULL, "CreateCompatibleDC returned %p\n", hdc);
+    hbmp = CreateBitmap(3, 3, 1, 1, NULL);
+    ok(hbmp != NULL, "CreateBitmap returned %p\n", hbmp);
+    holdbmp = SelectObject(hdc, hbmp);
+    holdbrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
+    SetRect(&r, 0, 0, 3, 3);
+
+    FillRect(hdc, &r, GetStockObject(WHITE_BRUSH));
+    PatBlt(hdc, 0, 0, 2, 1, PATCOPY);
+    ok(GetPixel(hdc, 0, 0) == b && GetPixel(hdc, 1, 0) == b && GetPixel(hdc, 2, 0) == w, "row 0 wrong\n");
+    ok(GetPixel(hdc, 0, 1) == w && GetPixel(hdc, 1, 1) == w && GetPixel(hdc, 2, 1) == w, "row 1 wrong\n");
+    ok(GetPixel(hdc, 0, 2) == w && GetPixel(hdc, 1, 2) == w && GetPixel(hdc, 2, 2) == w, "row 2 wrong\n");
+
+    FillRect(hdc, &r, GetStockObject(WHITE_BRUSH));
+    PatBlt(hdc, 2, 2, -2, -1, PATCOPY);
+    ok(GetPixel(hdc, 0, 0) == w && GetPixel(hdc, 1, 0) == w && GetPixel(hdc, 2, 0) == w, "row 0 wrong\n");
+    ok(GetPixel(hdc, 0, 1) == b && GetPixel(hdc, 1, 1) == b && GetPixel(hdc, 2, 1) == w, "row 1 wrong\n");
+    ok(GetPixel(hdc, 0, 2) == w && GetPixel(hdc, 1, 2) == w && GetPixel(hdc, 2, 2) == w, "row 2 wrong\n");
+
+    SelectObject(hdc, holdbrush);
+    SelectObject(hdc, holdbmp);
+    DeleteObject(hbmp);
+    DeleteDC(hdc);
+}
+
 static void check_StretchBlt_pixel(HDC hdcDst, HDC hdcSrc, UINT32 *dstBuffer, UINT32 *srcBuffer,
                                    DWORD dwRop, UINT32 expected, int line)
 {
@@ -5962,6 +5997,7 @@ START_TEST(bitmap)
     test_select_object();
     test_CreateBitmap();
     test_BitBlt();
+    test_PatBlt();
     test_StretchBlt();
     test_StretchDIBits();
     test_GdiAlphaBlend();


More information about the wine-devel mailing list