gdi32/dib.c: Write true bitmap height into info and copy scanlines in the correct order.

Jack Edmonds pocketcookies2 at gmail.com
Mon Feb 7 19:44:53 CST 2011


Fixes bug 25698 and addresses one of the test cases in bug 24278 (possibly resolves bug 24278 but more testing is required to be sure).

dib.c: Fills BITMAPINFOHEADER with correct width and height when bits == NULL and copying from a top-to-bottom bitmap.
For top-to-bottom bitmaps, reverses the source pointer rather than the destination pointer.
Ignoring the case when both source and destination are top-to-bottom bitmaps and treating this as if the destination is only a top-to-bottom bitmap.
---
 dlls/gdi32/dib.c          |  113 ++++++++++++++++++++++++---------------------
 dlls/gdi32/tests/bitmap.c |  112 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 173 insertions(+), 52 deletions(-)

diff --git a/dlls/gdi32/dib.c b/dlls/gdi32/dib.c
index 5067e49..bf7a525 100644
--- a/dlls/gdi32/dib.c
+++ b/dlls/gdi32/dib.c
@@ -636,54 +636,6 @@ INT WINAPI GetDIBits(
 
     switch (bpp)
     {
-    case 0:  /* query bitmap info only */
-        if (core_header)
-        {
-            BITMAPCOREHEADER* coreheader = (BITMAPCOREHEADER*) info;
-            coreheader->bcWidth = bmp->bitmap.bmWidth;
-            coreheader->bcHeight = bmp->bitmap.bmHeight;
-            coreheader->bcPlanes = 1;
-            coreheader->bcBitCount = bmp->bitmap.bmBitsPixel;
-        }
-        else
-        {
-            info->bmiHeader.biWidth = bmp->bitmap.bmWidth;
-            info->bmiHeader.biHeight = bmp->bitmap.bmHeight;
-            info->bmiHeader.biPlanes = 1;
-            info->bmiHeader.biSizeImage =
-                DIB_GetDIBImageBytes( bmp->bitmap.bmWidth,
-                                      bmp->bitmap.bmHeight,
-                                      bmp->bitmap.bmBitsPixel );
-            if (bmp->dib)
-            {
-                info->bmiHeader.biBitCount = bmp->dib->dsBm.bmBitsPixel;
-                switch (bmp->dib->dsBm.bmBitsPixel)
-                {
-                case 16:
-                case 32:
-                    info->bmiHeader.biCompression = BI_BITFIELDS;
-                    break;
-                default:
-                    info->bmiHeader.biCompression = BI_RGB;
-                    break;
-                }
-            }
-            else
-            {
-                info->bmiHeader.biCompression = (bmp->bitmap.bmBitsPixel > 8) ? BI_BITFIELDS : BI_RGB;
-                info->bmiHeader.biBitCount = bmp->bitmap.bmBitsPixel;
-            }
-            info->bmiHeader.biXPelsPerMeter = 0;
-            info->bmiHeader.biYPelsPerMeter = 0;
-            info->bmiHeader.biClrUsed = 0;
-            info->bmiHeader.biClrImportant = 0;
-
-            /* Windows 2000 doesn't touch the additional struct members if
-               it's a BITMAPV4HEADER or a BITMAPV5HEADER */
-        }
-        lines = abs(bmp->bitmap.bmHeight);
-        goto done;
-
     case 1:
     case 4:
     case 8:
@@ -877,10 +829,10 @@ INT WINAPI GetDIBits(
             LPBYTE dbits = bits, sbits = (LPBYTE) bmp->dib->dsBm.bmBits + (startscan * srcwidthb);
             unsigned int x, y, width, widthb;
 
-            if ((height < 0) ^ (bmp->dib->dsBmih.biHeight < 0))
+            if (bmp->dib->dsBmih.biHeight < 0)
             {
-                dbits = (LPBYTE)bits + (dstwidthb * (lines-1));
-                dstwidthb = -dstwidthb;
+                sbits += (srcwidthb * (abs(bmp->dib->dsBmih.biHeight) - startscan - 1));
+                srcwidthb = -srcwidthb;
             }
 
             switch( bpp ) {
@@ -1086,7 +1038,64 @@ INT WINAPI GetDIBits(
             }
         }
     }
-    else lines = abs(height);
+    else /* query bitmap info only */
+    {
+        if (core_header)
+        {
+            BITMAPCOREHEADER* coreheader = (BITMAPCOREHEADER*) info;
+            if (bmp->dib)
+            {
+                coreheader->bcWidth = bmp->dib->dsBmih.biWidth;
+                coreheader->bcHeight = bmp->dib->dsBmih.biHeight;
+            }
+            else
+            {
+                coreheader->bcWidth = bmp->bitmap.bmWidth;
+                coreheader->bcHeight = bmp->bitmap.bmHeight;
+            }
+            coreheader->bcPlanes = 1;
+            coreheader->bcBitCount = bmp->bitmap.bmBitsPixel;
+        }
+        else
+        {
+            if (bmp->dib)
+            {
+                info->bmiHeader.biHeight = bmp->dib->dsBmih.biHeight;
+                info->bmiHeader.biWidth = bmp->dib->dsBmih.biWidth;
+                info->bmiHeader.biBitCount = bmp->dib->dsBm.bmBitsPixel;
+                switch (bmp->dib->dsBm.bmBitsPixel)
+                {
+                case 16:
+                case 32:
+                    info->bmiHeader.biCompression = BI_BITFIELDS;
+                    break;
+                default:
+                    info->bmiHeader.biCompression = BI_RGB;
+                    break;
+                }
+            }
+            else
+            {
+                info->bmiHeader.biWidth = bmp->bitmap.bmWidth;
+                info->bmiHeader.biHeight = bmp->bitmap.bmHeight;
+                info->bmiHeader.biCompression = (bmp->bitmap.bmBitsPixel > 8) ? BI_BITFIELDS : BI_RGB;
+                info->bmiHeader.biBitCount = bmp->bitmap.bmBitsPixel;
+            }
+            info->bmiHeader.biPlanes = 1;
+            info->bmiHeader.biSizeImage =
+                DIB_GetDIBImageBytes( bmp->bitmap.bmWidth,
+                                      bmp->bitmap.bmHeight,
+                                      bmp->bitmap.bmBitsPixel );
+            info->bmiHeader.biXPelsPerMeter = 0;
+            info->bmiHeader.biYPelsPerMeter = 0;
+            info->bmiHeader.biClrUsed = 0;
+            info->bmiHeader.biClrImportant = 0;
+
+            /* Windows 2000 doesn't touch the additional struct members if
+               it's a BITMAPV4HEADER or a BITMAPV5HEADER */
+        }
+        lines = abs(bmp->bitmap.bmHeight);
+    }
 
     /* The knowledge base article Q81498 ("DIBs and Their Uses") states that
        if bits == NULL and bpp != 0, only biSizeImage and the color table are
diff --git a/dlls/gdi32/tests/bitmap.c b/dlls/gdi32/tests/bitmap.c
index d0d7a9c..a76d437 100644
--- a/dlls/gdi32/tests/bitmap.c
+++ b/dlls/gdi32/tests/bitmap.c
@@ -3050,6 +3050,116 @@ static void test_32bit_bitmap_blt(void)
     DeleteDC(hdcScreen);
 }
 
+static void test_GetDIBits_info_query(void)
+{
+    BITMAPINFO bi;
+    HBITMAP bmp;
+    HDC hdc;
+    int *picture;
+
+    hdc = GetDC(NULL);
+
+    bi.bmiHeader.biSize=sizeof(bi.bmiHeader);
+    bi.bmiHeader.biWidth=2;
+    bi.bmiHeader.biHeight=2;
+    bi.bmiHeader.biPlanes=1;
+    bi.bmiHeader.biBitCount=32;
+    bi.bmiHeader.biCompression=BI_RGB;
+    bmp = CreateDIBSection(hdc, &bi, DIB_RGB_COLORS, (void**)&picture, NULL, 0);
+    /*Clear the structure to make sure that we really are testing that the structure is being written to.*/
+    memset(&bi, 0, sizeof(bi));
+    /*Test with a BITMAPINFOHEADER.*/
+    bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+    GetDIBits(hdc, bmp, 0, 0, NULL, &bi, DIB_RGB_COLORS);
+    ok(bi.bmiHeader.biHeight == 2, "Height should be 2.");
+    ok(bi.bmiHeader.biWidth == 2, "Width should be 2.");
+    /*Clear the structure to make sure that we really are testing that the structure is being written to.*/
+    memset(&bi, 0, sizeof(bi));
+    /*Now test with a BITMAPCOREHEADER.*/
+    bi.bmiHeader.biSize=sizeof(BITMAPCOREHEADER);
+    GetDIBits(hdc, bmp, 0, 0, NULL, &bi, DIB_RGB_COLORS);
+    ok(((BITMAPCOREHEADER*)&bi)->bcHeight == 2, "Height should be 2.");
+    ok(((BITMAPCOREHEADER*)&bi)->bcWidth == 2, "Width should be 2.");
+    /*Clean up.*/
+    DeleteObject(bmp);
+
+    /*Test top to bottom bitmap.*/
+    bi.bmiHeader.biSize=sizeof(bi.bmiHeader);
+    bi.bmiHeader.biWidth=2;
+    bi.bmiHeader.biHeight=-2;
+    bi.bmiHeader.biPlanes=1;
+    bi.bmiHeader.biBitCount=32;
+    bi.bmiHeader.biCompression=BI_RGB;
+    bmp = CreateDIBSection(hdc, &bi, DIB_RGB_COLORS, (void**)&picture, NULL, 0);
+    /*Clear the structure to make sure that we really are testing that the structure is being written to.*/
+    memset(&bi, 0, sizeof(bi));
+    /*Test with a BITMAPINFOHEADER.*/
+    bi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
+    GetDIBits(hdc, bmp, 0, 0, NULL, &bi, DIB_RGB_COLORS);
+    ok(bi.bmiHeader.biHeight == -2, "Height should be -2.");
+    ok(bi.bmiHeader.biWidth == 2, "Width should be 2.");
+    /*Clear the structure to make sure that we really are testing that the structure is being written to.*/
+    memset(&bi, 0, sizeof(bi));
+    /*Now test with a BITMAPCOREHEADER.*/
+    bi.bmiHeader.biSize=sizeof(BITMAPCOREHEADER);
+    GetDIBits(hdc, bmp, 0, 0, NULL, &bi, DIB_RGB_COLORS);
+    ok(((BITMAPCOREHEADER*)&bi)->bcHeight == (WORD)-2, "Height should be -2.");
+    ok(((BITMAPCOREHEADER*)&bi)->bcWidth == (WORD)2, "Width should be 2.");
+    /*Clean up.*/
+    DeleteObject(bmp);
+}
+
+static void test_GetDIBits_single_pixel_destination(void)
+{
+    BITMAPINFO bi;
+    HBITMAP bmptb, bmpbt;
+    HDC hdc;
+    int pixelOut;
+    int *picture;
+    bi.bmiHeader.biSize=sizeof(bi.bmiHeader);
+    bi.bmiHeader.biWidth=2;
+    bi.bmiHeader.biHeight=2;
+    bi.bmiHeader.biPlanes=1;
+    bi.bmiHeader.biBitCount=32;
+    bi.bmiHeader.biCompression=BI_RGB;
+
+    /*Get the device context for the screen.*/
+    hdc=GetDC(NULL);
+
+    /*Create the bottom to top image (image's bottom scan line is at the top in memory).*/
+    bmpbt=CreateDIBSection(hdc, &bi, DIB_RGB_COLORS, (void**)&picture, NULL, 0);
+    /*Now that we have a pointer to the pixels, we write to them.*/
+    picture[0]=1;
+    picture[1]=2;
+    picture[2]=3;
+    picture[3]=4;
+    /*Create the top to bottom image (images' bottom scan line is at the bottom in memory).*/
+    bi.bmiHeader.biHeight=-2; /*We specify that we want a top to bottom image by specifying a negative height.*/
+    bmptb=CreateDIBSection(hdc, &bi, DIB_RGB_COLORS, (void**)&picture, NULL, 0);
+    /*Write to this top to bottom bitmap.*/
+    picture[0]=1;
+    picture[1]=2;
+    picture[2]=3;
+	picture[3]=4;
+
+    bi.bmiHeader.biWidth=1;
+
+    bi.bmiHeader.biHeight=2;
+    GetDIBits(hdc, bmpbt, 0, 1, &pixelOut, &bi, DIB_RGB_COLORS);
+    ok(pixelOut==1, "Bottom-up -> bottom-up should have first scanline.");
+    GetDIBits(hdc, bmptb, 0, 1, &pixelOut, &bi, DIB_RGB_COLORS);
+    ok(pixelOut==3, "Top-down -> bottom-up should have last scanline.");
+    
+    bi.bmiHeader.biHeight=-2;
+    GetDIBits(hdc, bmpbt, 0, 1, &pixelOut, &bi, DIB_RGB_COLORS);
+    ok(pixelOut==1, "Bottom-up -> top-down should have first scanline.");
+    GetDIBits(hdc, bmptb, 0, 1, &pixelOut, &bi, DIB_RGB_COLORS);
+    ok(pixelOut==3, "Top-down -> top-down should have last scanline.");
+
+    DeleteObject(bmpbt);
+    DeleteObject(bmptb);
+}
+
 START_TEST(bitmap)
 {
     HMODULE hdll;
@@ -3080,4 +3190,6 @@ START_TEST(bitmap)
     test_bitmapinfoheadersize();
     test_get16dibits();
     test_clipping();
+    test_GetDIBits_single_pixel_destination();
+    test_GetDIBits_info_query();
 }
-- 
1.7.1





More information about the wine-patches mailing list