From f9fb67dfef77c3157e4b415c273aa9b99113d187 Mon Sep 17 00:00:00 2001 From: Mathias Kosch Date: Mon, 22 Sep 2008 01:22:00 +0200 Subject: gdi32: "StretchDIBits" with value of zero for "xSrc" and "ySrc" This path fixes Bug#13344. The function "StretchDIBits" behaves odd in case of "top-down" bitmaps with values of zero for "xSrc" and "ySrc". Tests using Windows Server 2003 shew that in this particular case the source rectangle is selected starting at the upper left corner of the bitmap. In all other cases the rectangle is aligned to the bottom of the bitmap. I provided a test case which tests several combinations, especially those with some of the values set to zero. It passes under "Windows Server 2003 R2 SP2" and Wine 1.1.5 (only) with this path applied. --- dlls/gdi32/dib.c | 20 +++- dlls/gdi32/tests/Makefile.in | 1 + dlls/gdi32/tests/dib.c | 257 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 276 insertions(+), 2 deletions(-) create mode 100644 dlls/gdi32/tests/dib.c diff --git a/dlls/gdi32/dib.c b/dlls/gdi32/dib.c index 440857d..a59a02e 100644 --- a/dlls/gdi32/dib.c +++ b/dlls/gdi32/dib.c @@ -212,6 +212,7 @@ INT WINAPI StretchDIBits(HDC hdc, INT xDst, INT yDst, INT widthDst, DWORD compr, size; HBITMAP hBitmap; BOOL fastpath = FALSE; + int ySrcAdjusted; release_dc_ptr( dc ); @@ -227,6 +228,16 @@ INT WINAPI StretchDIBits(HDC hdc, INT xDst, INT yDst, INT widthDst, return 0; } + /* Computation of source coordinates behaves different in case of "top down" + bitmaps and values of zero for "xSrc" and "ySrc": */ + if (height < 0) + { + height = -height; /* Positive from now on. */ + ySrcAdjusted = ((xSrc) || (ySrc)) ? height - heightSrc - ySrc : 0; + } + else + ySrcAdjusted = height - heightSrc - ySrc; + hBitmap = GetCurrentObject(hdc, OBJ_BITMAP); if (xDst == 0 && yDst == 0 && xSrc == 0 && ySrc == 0 && @@ -286,8 +297,13 @@ INT WINAPI StretchDIBits(HDC hdc, INT xDst, INT yDst, INT widthDst, * ericP (2000/09/09) */ + /* This might not work for values of "dwRop" much different than "SRCCOPY". + * Further testing is required. + * mkosch (2008/09/22) + */ + /* copy existing bitmap from destination dc */ - StretchBlt( hdcMem, xSrc, abs(height) - heightSrc - ySrc, + StretchBlt( hdcMem, xSrc, ySrcAdjusted, widthSrc, heightSrc, hdc, xDst, yDst, widthDst, heightDst, dwRop ); } @@ -297,7 +313,7 @@ INT WINAPI StretchDIBits(HDC hdc, INT xDst, INT yDst, INT widthDst, /* Origin for DIBitmap may be bottom left (positive biHeight) or top left (negative biHeight) */ if (ret) StretchBlt( hdc, xDst, yDst, widthDst, heightDst, - hdcMem, xSrc, abs(height) - heightSrc - ySrc, + hdcMem, xSrc, ySrcAdjusted, widthSrc, heightSrc, dwRop ); if(hpal) SelectPalette(hdcMem, hpal, FALSE); diff --git a/dlls/gdi32/tests/Makefile.in b/dlls/gdi32/tests/Makefile.in index 866615c..86c931b 100644 --- a/dlls/gdi32/tests/Makefile.in +++ b/dlls/gdi32/tests/Makefile.in @@ -10,6 +10,7 @@ CTESTS = \ brush.c \ clipping.c \ dc.c \ + dib.c \ font.c \ gdiobj.c \ generated.c \ diff --git a/dlls/gdi32/tests/dib.c b/dlls/gdi32/tests/dib.c new file mode 100644 index 0000000..08b4c54 --- /dev/null +++ b/dlls/gdi32/tests/dib.c @@ -0,0 +1,257 @@ +/* + * Unit tests for dib functions + * + * Copyright (c) 2008 Mathias Kosch + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" + +#include "wine/test.h" + + +static void test_StretchDIBits_internal(int xSrc, int ySrc, int xDest, int yDest, + int nWidth, int nHeight, bool bTopDown) +{ + struct PIXEL + { + uint8_t blue; + uint8_t green; + uint8_t red; + } __attribute__ ((__packed__)); + + + bool bMatching; + int x, y, nBitmapWidth, nBitmapHeight, nNewBitmapWidth, nNewBitmapHeight; + size_t i, nSize; + struct PIXEL *pBitmapData = NULL, *pNewBitmapData = NULL; + struct PIXEL *pStartLine, *pNewStartLine; + HDC hDC = NULL, hMemDC = NULL; + HBITMAP hBitmap = NULL, hOldBitmap = NULL; + BITMAPINFO bmi, bmiNew; + + + /* Compute bitmap widths and heights. The should be multiples of 4. */ + nBitmapWidth = ((nWidth+xSrc+37) | 3)+1; + nBitmapHeight = ((nHeight+ySrc+43) | 3)+1; + nNewBitmapWidth = ((nWidth+xDest+103) | 3)+1; + nNewBitmapHeight = ((nHeight+yDest+57) | 3)+1; + + /* Creating bitmap structure for bitmap: */ + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = nBitmapWidth; + bmi.bmiHeader.biHeight = nBitmapHeight; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 24; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biSizeImage = 0; + bmi.bmiHeader.biXPelsPerMeter = 0; + bmi.bmiHeader.biYPelsPerMeter = 0; + bmi.bmiHeader.biClrUsed = 0; + bmi.bmiHeader.biClrImportant = 0; + if (bTopDown) + bmi.bmiHeader.biHeight = -bmi.bmiHeader.biHeight; + + /* Creating bitmap structure for new bitmap: */ + bmiNew.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmiNew.bmiHeader.biWidth = nNewBitmapWidth; + bmiNew.bmiHeader.biHeight = nNewBitmapHeight; + bmiNew.bmiHeader.biPlanes = 1; + bmiNew.bmiHeader.biBitCount = 24; + bmiNew.bmiHeader.biCompression = BI_RGB; + bmiNew.bmiHeader.biSizeImage = 0; + bmiNew.bmiHeader.biXPelsPerMeter = 0; + bmiNew.bmiHeader.biYPelsPerMeter = 0; + bmiNew.bmiHeader.biClrUsed = 0; + bmiNew.bmiHeader.biClrImportant = 0; + if (bTopDown) + bmiNew.bmiHeader.biHeight = -bmiNew.bmiHeader.biHeight; + + /* Allocating storage for bitmap data */ + pBitmapData = (struct PIXEL*)malloc(nBitmapWidth*nBitmapHeight*sizeof(struct PIXEL)); + if (!pBitmapData) + ok(0, "Memory allocation failed.\n"); + pNewBitmapData = (struct PIXEL*)malloc(nNewBitmapWidth*nNewBitmapHeight*sizeof(struct PIXEL)); + if (!pNewBitmapData) + ok(0, "Memory allocation failed.\n"); + + /* Creating device context. */ + hDC = GetDC(NULL); + hMemDC = CreateCompatibleDC(hDC); + if (!hMemDC) + ok(0, "Device context creation failed.\n"); + if (hMemDC) + { + hBitmap = CreateCompatibleBitmap(hDC, nNewBitmapWidth, nNewBitmapHeight); + if (!hBitmap) + ok(0, "Compatible bitmap creation failed.\n"); + if (hBitmap) + { + hOldBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap); + if (!hOldBitmap) + ok(0, "Bitmap selection failed.\n"); + } + } + + if ((pBitmapData) && (pNewBitmapData) && (hOldBitmap)) + { + /* Initializing bitmap with random color data: */ + nSize = nBitmapWidth*nBitmapHeight; + for (i = 0; i < nSize; i++) + { + pBitmapData[i].blue = rand(); + pBitmapData[i].green = rand(); + pBitmapData[i].red = rand(); + } + + /* Drawing bitmap data as "bottom up" bitmap into first dc: */ + if (!StretchDIBits(hMemDC, xDest, yDest, nWidth, nHeight, + xSrc, ySrc, nWidth, nHeight, + pBitmapData, &bmi, DIB_RGB_COLORS, SRCCOPY)) + ok(0, "StretchDIBits failed.\n"); + else + { + /* Retrieving bitmap data: */ + if (!GetDIBits(hMemDC, hBitmap, 0, nNewBitmapHeight, pNewBitmapData, &bmiNew, DIB_RGB_COLORS)) + ok(0, "GetDIBits failed.\n"); + else + { + /* Computing starting lines for comparision. "StretchDIBits" + seems to behave odd in case "xSrc" an "ySrc" is 0. */ + if (bTopDown) + { + if ((xSrc) || (ySrc)) + pStartLine = pBitmapData+(nBitmapHeight-nHeight-ySrc)*nBitmapWidth; + else + pStartLine = pBitmapData; + pNewStartLine = pNewBitmapData+yDest*nNewBitmapWidth; + } + else + { + pStartLine = pBitmapData+(nHeight+ySrc-1)*nBitmapWidth; + pNewStartLine = pNewBitmapData+(nNewBitmapHeight-yDest-1)*nNewBitmapWidth; + } + + /* Comparing bitmap data with supposed data. */ + bMatching = true; + for (y = 0; y < nHeight; y++) + { + for (x = 0; x < nWidth; x++) + { + if ((pStartLine[x+xSrc].blue != pNewStartLine[x+xDest].blue) || + (pStartLine[x+xSrc].green != pNewStartLine[x+xDest].green) || + (pStartLine[x+xSrc].red != pNewStartLine[x+xDest].red)) + { + bMatching = false; + break; + } + } + if (bTopDown) + { + pStartLine += nBitmapWidth; + pNewStartLine += nNewBitmapWidth; + } + else + { + pStartLine -= nBitmapWidth; + pNewStartLine -= nNewBitmapWidth; + } + } + ok(bMatching != false, "Bitmap data not matching. [bTopDown=%s, StretchDIBits(hMemDC,"\ + " %d, %d, %d, %d, %d, %d, %d, %d, pBitmapData, &bmi, DIB_RGB_COLORS, SRCCOPY)]\n", + (bTopDown) ? "true" : "false", xDest, yDest, nWidth, nHeight, xSrc, ySrc, nWidth, nHeight); + } + } + } + + if (hOldBitmap) + SelectObject(hMemDC, hOldBitmap); + if (hBitmap) + DeleteObject(hBitmap); + if (hMemDC) + DeleteDC(hMemDC); + free(pNewBitmapData); + free(pBitmapData); +} + + +static void test_StretchDIBits() +{ + test_StretchDIBits_internal(33, 61, 103, 227, 663, 459, false); + test_StretchDIBits_internal(33, 61, 103, 227, 663, 459, true); + + test_StretchDIBits_internal(0, 61, 103, 227, 663, 459, false); + test_StretchDIBits_internal(0, 61, 103, 227, 663, 459, true); + + test_StretchDIBits_internal(33, 0, 103, 227, 663, 459, false); + test_StretchDIBits_internal(33, 0, 103, 227, 663, 459, true); + + test_StretchDIBits_internal(0, 0, 103, 227, 663, 459, false); + test_StretchDIBits_internal(0, 0, 103, 227, 663, 459, true); + + test_StretchDIBits_internal(33, 61, 0, 227, 663, 459, false); + test_StretchDIBits_internal(33, 61, 0, 227, 663, 459, true); + + test_StretchDIBits_internal(0, 61, 0, 227, 663, 459, false); + test_StretchDIBits_internal(0, 61, 0, 227, 663, 459, true); + + test_StretchDIBits_internal(33, 0, 0, 227, 663, 459, false); + test_StretchDIBits_internal(33, 0, 0, 227, 663, 459, true); + + test_StretchDIBits_internal(0, 0, 0, 227, 663, 459, false); + test_StretchDIBits_internal(0, 0, 0, 227, 663, 459, true); + + test_StretchDIBits_internal(33, 61, 103, 0, 663, 459, false); + test_StretchDIBits_internal(33, 61, 103, 0, 663, 459, true); + + test_StretchDIBits_internal(0, 61, 103, 0, 663, 459, false); + test_StretchDIBits_internal(0, 61, 103, 0, 663, 459, true); + + test_StretchDIBits_internal(33, 0, 103, 0, 663, 459, false); + test_StretchDIBits_internal(33, 0, 103, 0, 663, 459, true); + + test_StretchDIBits_internal(0, 0, 103, 0, 663, 459, false); + test_StretchDIBits_internal(0, 0, 103, 0, 663, 459, true); + + test_StretchDIBits_internal(33, 61, 0, 0, 663, 459, false); + test_StretchDIBits_internal(33, 61, 0, 0, 663, 459, true); + + test_StretchDIBits_internal(0, 61, 0, 0, 663, 459, false); + test_StretchDIBits_internal(0, 61, 0, 0, 663, 459, true); + + test_StretchDIBits_internal(33, 0, 0, 0, 663, 459, false); + test_StretchDIBits_internal(33, 0, 0, 0, 663, 459, true); + + test_StretchDIBits_internal(0, 0, 0, 0, 663, 459, false); + test_StretchDIBits_internal(0, 0, 0, 0, 663, 459, true); +} + + +START_TEST(dib) +{ + // Initializing random number generator: + srand(time(NULL)); + + test_StretchDIBits(); +} -- 1.5.6