user: CopyImage: Handle most flags
Michael Kaufmann
hallo at michael-kaufmann.ch
Wed Aug 9 09:14:49 CDT 2006
Changelog:
- CopyImage: Handle the flags LR_COPYDELETEORG, LR_CREATEDIBSECTION,
and LR_MONOCHROME
- New tests
- Should fix bug 5094
-------------- next part --------------
Index: dlls/user/cursoricon.c
===================================================================
RCS file: /home/wine/wine/dlls/user/cursoricon.c,v
retrieving revision 1.26
diff -u -r1.26 cursoricon.c
--- dlls/user/cursoricon.c 23 May 2006 12:48:46 -0000 1.26
+++ dlls/user/cursoricon.c 9 Aug 2006 13:50:50 -0000
@@ -2295,28 +2295,203 @@
* Success: Handle to newly created image
* Failure: NULL
*
- * FIXME
- * implementation still lacks nearly all features, see LR_* defines in winuser.h.
+ * BUGS
+ * Only Windows NT 4.0 supports the LR_COPYRETURNORG flag for bitmaps,
+ * all other versions (95/2000/XP have been tested) ignore it.
+ *
+ * NOTES
+ * If LR_CREATEDIBSECTION is absent, the copy will be monochrome for
+ * a monochrome source bitmap or if LR_MONOCHROME is present, otherwise
+ * the copy will have the same depth as the screen.
+ * The content of the image will only be copied if the bit depth of the
+ * original image is compatible with the bit depth of the screen, or
+ * if the source is a DIB section.
+ * The LR_MONOCHROME flag is ignored if LR_CREATEDIBSECTION is present.
*/
HICON WINAPI CopyImage( HANDLE hnd, UINT type, INT desiredx,
INT desiredy, UINT flags )
{
+ TRACE("hnd=%p, type=%u, desiredx=%d, desiredy=%d, flags=%x\n",
+ hnd, type, desiredx, desiredy, flags);
+
switch (type)
{
case IMAGE_BITMAP:
{
- HBITMAP res;
- BITMAP bm;
+ HBITMAP res = NULL;
+ DIBSECTION ds;
+ int objSize;
+ BITMAPINFO * bi;
+
+ objSize = GetObjectW( hnd, sizeof(ds), &ds );
+ if (!objSize) return 0;
+ if ((desiredx < 0) || (desiredy < 0)) return 0;
- if (!GetObjectW( hnd, sizeof(bm), &bm )) return 0;
- bm.bmBits = NULL;
- if ((res = CreateBitmapIndirect(&bm)))
+ if (flags & LR_COPYFROMRESOURCE)
{
- char *buf = HeapAlloc( GetProcessHeap(), 0, bm.bmWidthBytes * bm.bmHeight );
- GetBitmapBits( hnd, bm.bmWidthBytes * bm.bmHeight, buf );
- SetBitmapBits( res, bm.bmWidthBytes * bm.bmHeight, buf );
- HeapFree( GetProcessHeap(), 0, buf );
+ FIXME("The flag LR_COPYFROMRESOURCE is not implemented for bitmaps\n");
}
+
+ if (desiredx == 0) desiredx = ds.dsBm.bmWidth;
+ if (desiredy == 0) desiredy = ds.dsBm.bmHeight;
+
+ /* Allocate memory for a BITMAPINFOHEADER structure and a
+ color table. The maximum number of colors in a color table
+ is 256 which corresponds to a bitmap with depth 8.
+ Bitmaps with higher depths don't have color tables. */
+ bi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
+ if (!bi) return 0;
+
+ bi->bmiHeader.biSize = sizeof(bi->bmiHeader);
+ bi->bmiHeader.biPlanes = ds.dsBm.bmPlanes;
+ bi->bmiHeader.biBitCount = ds.dsBm.bmBitsPixel;
+ bi->bmiHeader.biCompression = BI_RGB;
+
+ if (flags & LR_CREATEDIBSECTION)
+ {
+ /* Create a DIB section. LR_MONOCHROME is ignored */
+ void * bits;
+ HDC dc = CreateCompatibleDC(NULL);
+
+ if (objSize == sizeof(DIBSECTION))
+ {
+ /* The source bitmap is a DIB.
+ Get its attributes to create an exact copy */
+ memcpy(bi, &ds.dsBmih, sizeof(BITMAPINFOHEADER));
+ }
+
+ /* Get the color table or the color masks */
+ GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
+
+ bi->bmiHeader.biWidth = desiredx;
+ bi->bmiHeader.biHeight = desiredy;
+ bi->bmiHeader.biSizeImage = 0;
+
+ res = CreateDIBSection(dc, bi, DIB_RGB_COLORS, &bits, NULL, 0);
+ DeleteDC(dc);
+ }
+ else
+ {
+ /* Create a device-dependent bitmap */
+
+ BOOL monochrome = (flags & LR_MONOCHROME);
+
+ if (objSize == sizeof(DIBSECTION))
+ {
+ /* The source bitmap is a DIB section.
+ Get its attributes */
+ HDC dc = CreateCompatibleDC(NULL);
+ bi->bmiHeader.biSize = sizeof(bi->bmiHeader);
+ bi->bmiHeader.biBitCount = ds.dsBm.bmBitsPixel;
+ GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
+ DeleteDC(dc);
+
+ if (!monochrome && ds.dsBm.bmBitsPixel == 1)
+ {
+ /* Look if the colors of the DIB are black and white */
+
+ monochrome =
+ (bi->bmiColors[0].rgbRed == 0xff
+ && bi->bmiColors[0].rgbGreen == 0xff
+ && bi->bmiColors[0].rgbBlue == 0xff
+ && bi->bmiColors[0].rgbReserved == 0
+ && bi->bmiColors[1].rgbRed == 0
+ && bi->bmiColors[1].rgbGreen == 0
+ && bi->bmiColors[1].rgbBlue == 0
+ && bi->bmiColors[1].rgbReserved == 0)
+ ||
+ (bi->bmiColors[0].rgbRed == 0
+ && bi->bmiColors[0].rgbGreen == 0
+ && bi->bmiColors[0].rgbBlue == 0
+ && bi->bmiColors[0].rgbReserved == 0
+ && bi->bmiColors[1].rgbRed == 0xff
+ && bi->bmiColors[1].rgbGreen == 0xff
+ && bi->bmiColors[1].rgbBlue == 0xff
+ && bi->bmiColors[1].rgbReserved == 0);
+ }
+ }
+ else if (!monochrome)
+ {
+ monochrome = ds.dsBm.bmBitsPixel == 1;
+ }
+
+ if (monochrome)
+ {
+ res = CreateBitmap(desiredx, desiredy, 1, 1, NULL);
+ }
+ else
+ {
+ HDC screenDC = GetDC(NULL);
+ res = CreateCompatibleBitmap(screenDC, desiredx, desiredy);
+ ReleaseDC(NULL, screenDC);
+ }
+ }
+
+ if (res)
+ {
+ /* Only copy the bitmap if it's a DIB section or if it's
+ compatible to the screen */
+ BOOL copyContents;
+
+ if (objSize == sizeof(DIBSECTION))
+ {
+ copyContents = TRUE;
+ }
+ else
+ {
+ HDC screenDC = GetDC(NULL);
+ int screen_depth = GetDeviceCaps(screenDC, BITSPIXEL);
+ ReleaseDC(NULL, screenDC);
+
+ copyContents = (ds.dsBm.bmBitsPixel == 1 || ds.dsBm.bmBitsPixel == screen_depth);
+ }
+
+ if (copyContents)
+ {
+ /* The source bitmap may already be selected in a device context,
+ use GetDIBits/StretchDIBits and not StretchBlt */
+
+ HDC dc;
+ void * bits;
+
+ dc = CreateCompatibleDC(NULL);
+
+ bi->bmiHeader.biWidth = ds.dsBm.bmWidth;
+ bi->bmiHeader.biHeight = ds.dsBm.bmHeight;
+ bi->bmiHeader.biSizeImage = 0;
+ bi->bmiHeader.biClrUsed = 0;
+ bi->bmiHeader.biClrImportant = 0;
+
+ /* Fill in biSizeImage */
+ GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
+ bits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bi->bmiHeader.biSizeImage);
+
+ if (bits)
+ {
+ HBITMAP oldBmp;
+
+ /* Get the image bits of the source bitmap */
+ GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, bits, bi, DIB_RGB_COLORS);
+
+ /* Copy it to the destination bitmap */
+ oldBmp = SelectObject(dc, res);
+ StretchDIBits(dc, 0, 0, desiredx, desiredy,
+ 0, 0, ds.dsBm.bmWidth, ds.dsBm.bmHeight,
+ bits, bi, DIB_RGB_COLORS, SRCCOPY);
+ SelectObject(dc, oldBmp);
+
+ HeapFree(GetProcessHeap(), 0, bits);
+ }
+
+ DeleteDC(dc);
+ }
+
+ if (flags & LR_COPYDELETEORG)
+ {
+ DeleteObject(hnd);
+ }
+ }
+ HeapFree(GetProcessHeap(), 0, bi);
return (HICON)res;
}
case IMAGE_ICON:
@@ -2325,6 +2500,7 @@
/* Should call CURSORICON_ExtCopy but more testing
* needs to be done before we change this
*/
+ if (flags) FIXME("Flags are ignored\n");
return CopyCursor(hnd);
}
return 0;
Index: dlls/user/tests/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/user/tests/Makefile.in,v
retrieving revision 1.18
diff -u -r1.18 Makefile.in
--- dlls/user/tests/Makefile.in 8 Jun 2006 10:07:29 -0000 1.18
+++ dlls/user/tests/Makefile.in 9 Aug 2006 13:51:06 -0000
@@ -8,6 +8,7 @@
CTESTS = \
class.c \
clipboard.c \
+ cursoricon.c \
dce.c \
dde.c \
dialog.c \
--- /dev/null 2006-08-09 17:25:45.021585648 +0200
+++ dlls/user/tests/cursoricon.c 2006-08-09 15:47:17.000000000 +0200
@@ -0,0 +1,246 @@
+/* Unit test suite for cursors and icons.
+ *
+ * Copyright 2006 Michael Kaufmann
+ *
+ * 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 <assert.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "wine/test.h"
+#include "windef.h"
+#include "winbase.h"
+#include "winreg.h"
+#include "wingdi.h"
+#include "winuser.h"
+
+static void test_CopyImage_Check(HBITMAP bitmap, UINT flags, LONG copyWidth, LONG copyHeight,
+ LONG expectedWidth, LONG expectedHeight, WORD expectedDepth, BOOL dibExpected)
+{
+ HBITMAP copy;
+ BITMAP origBitmap;
+ BITMAP copyBitmap;
+ BOOL orig_is_dib;
+ BOOL copy_is_dib;
+
+ copy = (HBITMAP) CopyImage(bitmap, IMAGE_BITMAP, copyWidth, copyHeight, flags);
+ ok(copy != NULL, "CopyImage() failed\n");
+ if (copy != NULL)
+ {
+ GetObject(bitmap, sizeof(origBitmap), &origBitmap) != 0,
+ GetObject(copy, sizeof(copyBitmap), ©Bitmap);
+ orig_is_dib = (origBitmap.bmBits != NULL);
+ copy_is_dib = (copyBitmap.bmBits != NULL);
+
+ if (copy_is_dib && dibExpected
+ && copyBitmap.bmBitsPixel == 24
+ && (expectedDepth == 16 || expectedDepth == 32))
+ {
+ /* Windows 95 doesn't create DIBs with a depth of 16 or 32 bit */
+ if (GetVersion() & 0x80000000)
+ {
+ expectedDepth = 24;
+ }
+ }
+
+ if (copy_is_dib && !dibExpected && !(flags & LR_CREATEDIBSECTION))
+ {
+ /* It's not forbidden to create a DIB section if the flag
+ LR_CREATEDIBSECTION is absent.
+ Windows 9x does this if the bitmap has a depth that doesn't
+ match the screen depth, Windows NT doesn't */
+ dibExpected = TRUE;
+ expectedDepth = origBitmap.bmBitsPixel;
+ }
+
+ ok((!(dibExpected ^ copy_is_dib)
+ && (copyBitmap.bmWidth == expectedWidth)
+ && (copyBitmap.bmHeight == expectedHeight)
+ && (copyBitmap.bmBitsPixel == expectedDepth)),
+ "CopyImage ((%s, %ldx%ld, %u bpp), %ld, %ld, %#x): Expected (%s, %ldx%ld, %u bpp), got (%s, %ldx%ld, %u bpp)\n",
+ orig_is_dib ? "DIB" : "DDB", (long)origBitmap.bmWidth, (long)origBitmap.bmHeight, (unsigned int)origBitmap.bmBitsPixel,
+ (long)copyWidth, (long)copyHeight, (unsigned int)flags,
+ dibExpected ? "DIB" : "DDB", (long)expectedWidth, (long)expectedHeight, (unsigned int)expectedDepth,
+ copy_is_dib ? "DIB" : "DDB", (long)copyBitmap.bmWidth, (long)copyBitmap.bmHeight, (unsigned int)copyBitmap.bmBitsPixel);
+
+ DeleteObject(copy);
+ }
+}
+
+static void test_CopyImage_Bitmap(int depth)
+{
+ HBITMAP ddb, dib;
+ HDC screenDC;
+ BITMAPINFO * info;
+ VOID * bits;
+ int screen_depth;
+ unsigned int i;
+
+ /* Create a device-independent bitmap (DIB) */
+ info = (BITMAPINFO *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
+ info->bmiHeader.biSize = sizeof(info->bmiHeader);
+ info->bmiHeader.biWidth = 2;
+ info->bmiHeader.biHeight = 2;
+ info->bmiHeader.biPlanes = 1;
+ info->bmiHeader.biBitCount = depth;
+ info->bmiHeader.biCompression = BI_RGB;
+
+ for (i=0; i < 256; i++)
+ {
+ info->bmiColors[i].rgbRed = i;
+ info->bmiColors[i].rgbGreen = i;
+ info->bmiColors[i].rgbBlue = 255 - i;
+ info->bmiColors[i].rgbReserved = 0;
+ }
+
+ dib = CreateDIBSection(NULL, info, DIB_RGB_COLORS, &bits, NULL, 0);
+
+ /* Create a device-dependent bitmap (DDB) */
+ screenDC = GetDC(NULL);
+ screen_depth = GetDeviceCaps(screenDC, BITSPIXEL);
+ if (depth == 1 || depth == screen_depth)
+ {
+ ddb = CreateBitmap(2, 2, 1, depth, NULL);
+ }
+ else
+ {
+ ddb = NULL;
+ }
+ ReleaseDC(NULL, screenDC);
+
+ if (ddb != NULL)
+ {
+ test_CopyImage_Check(ddb, 0, 0, 0, 2, 2, depth == 1 ? 1 : screen_depth, FALSE);
+ test_CopyImage_Check(ddb, 0, 0, 5, 2, 5, depth == 1 ? 1 : screen_depth, FALSE);
+ test_CopyImage_Check(ddb, 0, 5, 0, 5, 2, depth == 1 ? 1 : screen_depth, FALSE);
+ test_CopyImage_Check(ddb, 0, 5, 5, 5, 5, depth == 1 ? 1 : screen_depth, FALSE);
+
+ test_CopyImage_Check(ddb, LR_MONOCHROME, 0, 0, 2, 2, 1, FALSE);
+ test_CopyImage_Check(ddb, LR_MONOCHROME, 5, 0, 5, 2, 1, FALSE);
+ test_CopyImage_Check(ddb, LR_MONOCHROME, 0, 5, 2, 5, 1, FALSE);
+ test_CopyImage_Check(ddb, LR_MONOCHROME, 5, 5, 5, 5, 1, FALSE);
+
+ test_CopyImage_Check(ddb, LR_CREATEDIBSECTION, 0, 0, 2, 2, depth, TRUE);
+ test_CopyImage_Check(ddb, LR_CREATEDIBSECTION, 5, 0, 5, 2, depth, TRUE);
+ test_CopyImage_Check(ddb, LR_CREATEDIBSECTION, 0, 5, 2, 5, depth, TRUE);
+ test_CopyImage_Check(ddb, LR_CREATEDIBSECTION, 5, 5, 5, 5, depth, TRUE);
+
+ /* LR_MONOCHROME is ignored if LR_CREATEDIBSECTION is present */
+ test_CopyImage_Check(ddb, LR_MONOCHROME | LR_CREATEDIBSECTION, 0, 0, 2, 2, depth, TRUE);
+ test_CopyImage_Check(ddb, LR_MONOCHROME | LR_CREATEDIBSECTION, 5, 0, 5, 2, depth, TRUE);
+ test_CopyImage_Check(ddb, LR_MONOCHROME | LR_CREATEDIBSECTION, 0, 5, 2, 5, depth, TRUE);
+ test_CopyImage_Check(ddb, LR_MONOCHROME | LR_CREATEDIBSECTION, 5, 5, 5, 5, depth, TRUE);
+
+ DeleteObject(ddb);
+ }
+
+ if (depth != 1)
+ {
+ test_CopyImage_Check(dib, 0, 0, 0, 2, 2, screen_depth, FALSE);
+ test_CopyImage_Check(dib, 0, 5, 0, 5, 2, screen_depth, FALSE);
+ test_CopyImage_Check(dib, 0, 0, 5, 2, 5, screen_depth, FALSE);
+ test_CopyImage_Check(dib, 0, 5, 5, 5, 5, screen_depth, FALSE);
+ }
+
+ test_CopyImage_Check(dib, LR_MONOCHROME, 0, 0, 2, 2, 1, FALSE);
+ test_CopyImage_Check(dib, LR_MONOCHROME, 5, 0, 5, 2, 1, FALSE);
+ test_CopyImage_Check(dib, LR_MONOCHROME, 0, 5, 2, 5, 1, FALSE);
+ test_CopyImage_Check(dib, LR_MONOCHROME, 5, 5, 5, 5, 1, FALSE);
+
+ test_CopyImage_Check(dib, LR_CREATEDIBSECTION, 0, 0, 2, 2, depth, TRUE);
+ test_CopyImage_Check(dib, LR_CREATEDIBSECTION, 5, 0, 5, 2, depth, TRUE);
+ test_CopyImage_Check(dib, LR_CREATEDIBSECTION, 0, 5, 2, 5, depth, TRUE);
+ test_CopyImage_Check(dib, LR_CREATEDIBSECTION, 5, 5, 5, 5, depth, TRUE);
+
+ /* LR_MONOCHROME is ignored if LR_CREATEDIBSECTION is present */
+ test_CopyImage_Check(dib, LR_MONOCHROME | LR_CREATEDIBSECTION, 0, 0, 2, 2, depth, TRUE);
+ test_CopyImage_Check(dib, LR_MONOCHROME | LR_CREATEDIBSECTION, 5, 0, 5, 2, depth, TRUE);
+ test_CopyImage_Check(dib, LR_MONOCHROME | LR_CREATEDIBSECTION, 0, 5, 2, 5, depth, TRUE);
+ test_CopyImage_Check(dib, LR_MONOCHROME | LR_CREATEDIBSECTION, 5, 5, 5, 5, depth, TRUE);
+
+ DeleteObject(dib);
+
+ if (depth == 1)
+ {
+ /* Special case: A monochrome DIB is converted to a monochrome DDB if
+ the colors in the color table are black and white.
+
+ Skip this test on Windows 95, it always creates a monochrome DDB
+ in this case */
+
+ if (!(GetVersion() & 0x80000000))
+ {
+ info->bmiHeader.biBitCount = 1;
+ info->bmiColors[0].rgbRed = 0xFF;
+ info->bmiColors[0].rgbGreen = 0;
+ info->bmiColors[0].rgbBlue = 0;
+ info->bmiColors[1].rgbRed = 0;
+ info->bmiColors[1].rgbGreen = 0xFF;
+ info->bmiColors[1].rgbBlue = 0;
+
+ dib = CreateDIBSection(NULL, info, DIB_RGB_COLORS, &bits, NULL, 0);
+ test_CopyImage_Check(dib, 0, 0, 0, 2, 2, screen_depth, FALSE);
+ test_CopyImage_Check(dib, 0, 5, 0, 5, 2, screen_depth, FALSE);
+ test_CopyImage_Check(dib, 0, 0, 5, 2, 5, screen_depth, FALSE);
+ test_CopyImage_Check(dib, 0, 5, 5, 5, 5, screen_depth, FALSE);
+ DeleteObject(dib);
+
+ info->bmiHeader.biBitCount = 1;
+ info->bmiColors[0].rgbRed = 0;
+ info->bmiColors[0].rgbGreen = 0;
+ info->bmiColors[0].rgbBlue = 0;
+ info->bmiColors[1].rgbRed = 0xFF;
+ info->bmiColors[1].rgbGreen = 0xFF;
+ info->bmiColors[1].rgbBlue = 0xFF;
+
+ dib = CreateDIBSection(NULL, info, DIB_RGB_COLORS, &bits, NULL, 0);
+ test_CopyImage_Check(dib, 0, 0, 0, 2, 2, 1, FALSE);
+ test_CopyImage_Check(dib, 0, 5, 0, 5, 2, 1, FALSE);
+ test_CopyImage_Check(dib, 0, 0, 5, 2, 5, 1, FALSE);
+ test_CopyImage_Check(dib, 0, 5, 5, 5, 5, 1, FALSE);
+ DeleteObject(dib);
+
+ info->bmiHeader.biBitCount = 1;
+ info->bmiColors[0].rgbRed = 0xFF;
+ info->bmiColors[0].rgbGreen = 0xFF;
+ info->bmiColors[0].rgbBlue = 0xFF;
+ info->bmiColors[1].rgbRed = 0;
+ info->bmiColors[1].rgbGreen = 0;
+ info->bmiColors[1].rgbBlue = 0;
+
+ dib = CreateDIBSection(NULL, info, DIB_RGB_COLORS, &bits, NULL, 0);
+ test_CopyImage_Check(dib, 0, 0, 0, 2, 2, 1, FALSE);
+ test_CopyImage_Check(dib, 0, 5, 0, 5, 2, 1, FALSE);
+ test_CopyImage_Check(dib, 0, 0, 5, 2, 5, 1, FALSE);
+ test_CopyImage_Check(dib, 0, 5, 5, 5, 5, 1, FALSE);
+ DeleteObject(dib);
+ }
+ }
+
+ HeapFree(GetProcessHeap(), 0, info);
+}
+
+START_TEST(cursoricon)
+{
+ test_CopyImage_Bitmap(1);
+ test_CopyImage_Bitmap(4);
+ test_CopyImage_Bitmap(8);
+ test_CopyImage_Bitmap(16);
+ test_CopyImage_Bitmap(24);
+ test_CopyImage_Bitmap(32);
+}
More information about the wine-patches
mailing list