[PATCH 2/4] user32: Implement stretching of cursor and icon objects in CopyImage().
Zebediah Figura
z.figura12 at gmail.com
Sun May 23 23:47:18 CDT 2021
Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
dlls/user32/cursoricon.c | 92 +++++++++++++--
dlls/user32/tests/cursoricon.c | 203 ++++++++++++++++++++++-----------
2 files changed, 219 insertions(+), 76 deletions(-)
diff --git a/dlls/user32/cursoricon.c b/dlls/user32/cursoricon.c
index ee6d27acf2e..fc95fa1c56f 100644
--- a/dlls/user32/cursoricon.c
+++ b/dlls/user32/cursoricon.c
@@ -2776,6 +2776,21 @@ HANDLE WINAPI LoadImageW( HINSTANCE hinst, LPCWSTR name, UINT type,
return 0;
}
+
+/* StretchBlt from src to dest; helper for CopyImage(). */
+static void stretch_bitmap( HBITMAP dst, HBITMAP src, int dst_width, int dst_height, int src_width, int src_height )
+{
+ HDC src_dc = CreateCompatibleDC( 0 ), dst_dc = CreateCompatibleDC( 0 );
+
+ SelectObject( src_dc, src );
+ SelectObject( dst_dc, dst );
+ StretchBlt( dst_dc, 0, 0, dst_width, dst_height, src_dc, 0, 0, src_width, src_height, SRCCOPY );
+
+ DeleteDC( src_dc );
+ DeleteDC( dst_dc );
+}
+
+
/******************************************************************************
* CopyImage (USER32.@) Creates new image and copies attributes to it
*
@@ -2974,23 +2989,84 @@ HANDLE WINAPI CopyImage( HANDLE hnd, UINT type, INT desiredx,
case IMAGE_ICON:
case IMAGE_CURSOR:
{
+ struct cursoricon_frame *frame;
struct cursoricon_object *icon;
- HICON res = 0;
int depth = (flags & LR_MONOCHROME) ? 1 : get_display_bpp();
+ ICONINFO info;
+ HICON res;
+
+ if (!(icon = get_icon_ptr( hnd ))) return 0;
+
+ if (icon->rsrc && (flags & LR_COPYFROMRESOURCE))
+ {
+ hnd = CURSORICON_Load( icon->module, icon->resname, desiredx, desiredy, depth,
+ !icon->is_icon, flags );
+ release_user_handle_ptr( icon );
+ if (!(icon = get_icon_ptr( hnd ))) return 0;
+ }
+ frame = get_icon_frame( icon, 0 );
if (flags & LR_DEFAULTSIZE)
{
if (!desiredx) desiredx = GetSystemMetrics( type == IMAGE_ICON ? SM_CXICON : SM_CXCURSOR );
if (!desiredy) desiredy = GetSystemMetrics( type == IMAGE_ICON ? SM_CYICON : SM_CYCURSOR );
}
-
- if (!(icon = get_icon_ptr( hnd ))) return 0;
-
- if (icon->rsrc && (flags & LR_COPYFROMRESOURCE))
- res = CURSORICON_Load( icon->module, icon->resname, desiredx, desiredy, depth,
- !icon->is_icon, flags );
else
- res = CopyIcon( hnd ); /* FIXME: change size if necessary */
+ {
+ if (!desiredx) desiredx = frame->width;
+ if (!desiredy) desiredy = frame->height;
+ }
+
+ info.fIcon = icon->is_icon;
+ info.xHotspot = icon->hotspot.x;
+ info.yHotspot = icon->hotspot.y;
+
+ if (desiredx == frame->width && desiredy == frame->height)
+ {
+ info.hbmColor = frame->color;
+ info.hbmMask = frame->mask;
+ res = CreateIconIndirect( &info );
+ }
+ else
+ {
+ if (frame->color)
+ {
+ if (!(info.hbmColor = create_color_bitmap( desiredx, desiredy )))
+ {
+ release_user_handle_ptr( icon );
+ return 0;
+ }
+ stretch_bitmap( info.hbmColor, frame->color, desiredx, desiredy,
+ frame->width, frame->height );
+
+ if (!(info.hbmMask = CreateBitmap( desiredx, desiredy, 1, 1, NULL )))
+ {
+ DeleteObject( info.hbmColor );
+ release_user_handle_ptr( icon );
+ return 0;
+ }
+ stretch_bitmap( info.hbmMask, frame->mask, desiredx, desiredy,
+ frame->width, frame->height );
+ }
+ else
+ {
+ info.hbmColor = NULL;
+
+ if (!(info.hbmMask = CreateBitmap( desiredx, desiredy * 2, 1, 1, NULL )))
+ {
+ release_user_handle_ptr( icon );
+ return 0;
+ }
+ stretch_bitmap( info.hbmColor, frame->color, desiredx, desiredy * 2,
+ frame->width, frame->height * 2 );
+ }
+
+ res = CreateIconIndirect( &info );
+
+ DeleteObject( info.hbmColor );
+ DeleteObject( info.hbmMask );
+ }
+
release_user_handle_ptr( icon );
if (res && (flags & LR_COPYDELETEORG)) DeleteObject( hnd );
diff --git a/dlls/user32/tests/cursoricon.c b/dlls/user32/tests/cursoricon.c
index f60c845f8bc..39ffe9d88e6 100644
--- a/dlls/user32/tests/cursoricon.c
+++ b/dlls/user32/tests/cursoricon.c
@@ -486,22 +486,53 @@ static BOOL color_match(COLORREF a, COLORREF b)
return (a & 0x00F8F8F8) == (b & 0x00F8F8F8);
}
-static void test_CopyImage_Check(HBITMAP bitmap, UINT flags, INT copyWidth, INT copyHeight,
- INT expectedWidth, INT expectedHeight, WORD expectedDepth, BOOL dibExpected)
+static void check_copy_image(HBITMAP bitmap, UINT type, UINT flags, INT copyWidth, INT copyHeight,
+ INT expectedWidth, INT expectedHeight, WORD expectedDepth, BOOL dibExpected)
{
HBITMAP copy;
BITMAP origBitmap;
BITMAP copyBitmap;
- BOOL orig_is_dib;
BOOL copy_is_dib;
+ BOOL ret;
- copy = CopyImage(bitmap, IMAGE_BITMAP, copyWidth, copyHeight, flags);
+ GetObjectA(bitmap, sizeof(origBitmap), &origBitmap);
+
+ winetest_push_context("%s, type %#x, flags %#x, size %ux%u",
+ origBitmap.bmBits ? "DIB" : "DDB", type, flags, copyWidth, copyHeight);
+
+ if (type == IMAGE_BITMAP)
+ {
+ copy = CopyImage(bitmap, type, copyWidth, copyHeight, flags);
+ }
+ else
+ {
+ ICONINFO info =
+ {
+ .fIcon = (type == IMAGE_ICON),
+ .hbmColor = bitmap,
+ .hbmMask = bitmap,
+ };
+ HICON icon = CreateIconIndirect(&info);
+ ok(!!icon, "Failed to create icon, error %u\n", GetLastError());
+ copy = CopyImage(icon, type, copyWidth, copyHeight, flags);
+ ret = DestroyIcon(icon);
+ ok(ret, "Failed to destroy icon, error %u\n", GetLastError());
+ }
ok(copy != NULL, "CopyImage() failed\n");
if (copy != NULL)
{
- GetObjectA(bitmap, sizeof(origBitmap), &origBitmap);
- GetObjectA(copy, sizeof(copyBitmap), ©Bitmap);
- orig_is_dib = (origBitmap.bmBits != NULL);
+ if (type == IMAGE_BITMAP)
+ {
+ GetObjectA(copy, sizeof(copyBitmap), ©Bitmap);
+ }
+ else
+ {
+ ICONINFO info;
+
+ ret = GetIconInfo((HICON)copy, &info);
+ ok(ret, "Failed to get icon info, error %u\n", GetLastError());
+ GetObjectA(info.hbmColor, sizeof(copyBitmap), ©Bitmap);
+ }
copy_is_dib = (copyBitmap.bmBits != NULL);
if (copy_is_dib && dibExpected
@@ -525,21 +556,49 @@ static void test_CopyImage_Check(HBITMAP bitmap, UINT flags, INT copyWidth, INT
expectedDepth = origBitmap.bmBitsPixel;
}
- ok((!(dibExpected ^ copy_is_dib)
- && (copyBitmap.bmWidth == expectedWidth)
- && (copyBitmap.bmHeight == expectedHeight)
- && (copyBitmap.bmBitsPixel == expectedDepth)),
- "CopyImage ((%s, %dx%d, %u bpp), %d, %d, %#x): Expected (%s, %dx%d, %u bpp), got (%s, %dx%d, %u bpp)\n",
- orig_is_dib ? "DIB" : "DDB", origBitmap.bmWidth, origBitmap.bmHeight, origBitmap.bmBitsPixel,
- copyWidth, copyHeight, flags,
- dibExpected ? "DIB" : "DDB", expectedWidth, expectedHeight, expectedDepth,
- copy_is_dib ? "DIB" : "DDB", copyBitmap.bmWidth, copyBitmap.bmHeight, copyBitmap.bmBitsPixel);
+ if (type != IMAGE_BITMAP)
+ {
+ dibExpected = FALSE;
+ expectedDepth = 32;
+ }
- DeleteObject(copy);
+ ok(copy_is_dib == dibExpected, "Expected %s, got %s\n",
+ dibExpected ? "DIB" : "DDB", copy_is_dib ? "DIB" : "DDB");
+ ok(copyBitmap.bmWidth == expectedWidth, "Expected width %u, got %u\n",
+ expectedWidth, copyBitmap.bmWidth);
+ ok(copyBitmap.bmHeight == expectedHeight, "Expected height %u, got %u\n",
+ expectedHeight, copyBitmap.bmHeight);
+ ok(copyBitmap.bmBitsPixel == expectedDepth, "Expected depth %u, got %u\n",
+ expectedDepth, copyBitmap.bmBitsPixel);
+
+ if (type != IMAGE_BITMAP)
+ {
+ ICONINFO info;
+
+ ret = GetIconInfo((HICON)copy, &info);
+ ok(ret, "Failed to get icon info, error %u\n", GetLastError());
+ GetObjectA(info.hbmMask, sizeof(copyBitmap), ©Bitmap);
+
+ ok(!copyBitmap.bmBits, "Expected DDB\n");
+ ok(copyBitmap.bmWidth == expectedWidth, "Expected mask width %u, got %u\n",
+ expectedWidth, copyBitmap.bmWidth);
+ ok(copyBitmap.bmHeight == expectedHeight, "Expected mask height %u, got %u\n",
+ expectedHeight, copyBitmap.bmHeight);
+ ok(copyBitmap.bmBitsPixel == 1, "Got mask depth %u\n", copyBitmap.bmBitsPixel);
+ }
+
+ if (type == IMAGE_BITMAP)
+ DeleteObject(copy);
+ else if (type == IMAGE_ICON)
+ DestroyIcon((HICON)copy);
+ else
+ DestroyCursor((HCURSOR)copy);
}
+
+ winetest_pop_context();
}
-static void test_CopyImage_Bitmap(int depth)
+static void do_test_copy_image(UINT type, UINT depth)
{
HBITMAP ddb, dib;
HDC screenDC;
@@ -582,53 +641,53 @@ static void test_CopyImage_Bitmap(int depth)
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);
+ check_copy_image(ddb, type, 0, 0, 0, 2, 2, depth == 1 ? 1 : screen_depth, FALSE);
+ check_copy_image(ddb, type, 0, 0, 5, 2, 5, depth == 1 ? 1 : screen_depth, FALSE);
+ check_copy_image(ddb, type, 0, 5, 0, 5, 2, depth == 1 ? 1 : screen_depth, FALSE);
+ check_copy_image(ddb, type, 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);
+ check_copy_image(ddb, type, LR_MONOCHROME, 0, 0, 2, 2, 1, FALSE);
+ check_copy_image(ddb, type, LR_MONOCHROME, 5, 0, 5, 2, 1, FALSE);
+ check_copy_image(ddb, type, LR_MONOCHROME, 0, 5, 2, 5, 1, FALSE);
+ check_copy_image(ddb, type, 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);
+ check_copy_image(ddb, type, LR_CREATEDIBSECTION, 0, 0, 2, 2, depth, TRUE);
+ check_copy_image(ddb, type, LR_CREATEDIBSECTION, 5, 0, 5, 2, depth, TRUE);
+ check_copy_image(ddb, type, LR_CREATEDIBSECTION, 0, 5, 2, 5, depth, TRUE);
+ check_copy_image(ddb, type, 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);
+ check_copy_image(ddb, type, LR_MONOCHROME | LR_CREATEDIBSECTION, 0, 0, 2, 2, depth, TRUE);
+ check_copy_image(ddb, type, LR_MONOCHROME | LR_CREATEDIBSECTION, 5, 0, 5, 2, depth, TRUE);
+ check_copy_image(ddb, type, LR_MONOCHROME | LR_CREATEDIBSECTION, 0, 5, 2, 5, depth, TRUE);
+ check_copy_image(ddb, type, 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);
+ check_copy_image(dib, type, 0, 0, 0, 2, 2, screen_depth, FALSE);
+ check_copy_image(dib, type, 0, 5, 0, 5, 2, screen_depth, FALSE);
+ check_copy_image(dib, type, 0, 0, 5, 2, 5, screen_depth, FALSE);
+ check_copy_image(dib, type, 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);
+ check_copy_image(dib, type, LR_MONOCHROME, 0, 0, 2, 2, 1, FALSE);
+ check_copy_image(dib, type, LR_MONOCHROME, 5, 0, 5, 2, 1, FALSE);
+ check_copy_image(dib, type, LR_MONOCHROME, 0, 5, 2, 5, 1, FALSE);
+ check_copy_image(dib, type, 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);
+ check_copy_image(dib, type, LR_CREATEDIBSECTION, 0, 0, 2, 2, depth, TRUE);
+ check_copy_image(dib, type, LR_CREATEDIBSECTION, 5, 0, 5, 2, depth, TRUE);
+ check_copy_image(dib, type, LR_CREATEDIBSECTION, 0, 5, 2, 5, depth, TRUE);
+ check_copy_image(dib, type, 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);
+ check_copy_image(dib, type, LR_MONOCHROME | LR_CREATEDIBSECTION, 0, 0, 2, 2, depth, TRUE);
+ check_copy_image(dib, type, LR_MONOCHROME | LR_CREATEDIBSECTION, 5, 0, 5, 2, depth, TRUE);
+ check_copy_image(dib, type, LR_MONOCHROME | LR_CREATEDIBSECTION, 0, 5, 2, 5, depth, TRUE);
+ check_copy_image(dib, type, LR_MONOCHROME | LR_CREATEDIBSECTION, 5, 5, 5, 5, depth, TRUE);
DeleteObject(dib);
@@ -651,10 +710,10 @@ static void test_CopyImage_Bitmap(int depth)
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);
+ check_copy_image(dib, type, 0, 0, 0, 2, 2, screen_depth, FALSE);
+ check_copy_image(dib, type, 0, 5, 0, 5, 2, screen_depth, FALSE);
+ check_copy_image(dib, type, 0, 0, 5, 2, 5, screen_depth, FALSE);
+ check_copy_image(dib, type, 0, 5, 5, 5, 5, screen_depth, FALSE);
DeleteObject(dib);
info->bmiHeader.biBitCount = 1;
@@ -666,10 +725,10 @@ static void test_CopyImage_Bitmap(int depth)
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);
+ check_copy_image(dib, type, 0, 0, 0, 2, 2, 1, FALSE);
+ check_copy_image(dib, type, 0, 5, 0, 5, 2, 1, FALSE);
+ check_copy_image(dib, type, 0, 0, 5, 2, 5, 1, FALSE);
+ check_copy_image(dib, type, 0, 5, 5, 5, 5, 1, FALSE);
DeleteObject(dib);
info->bmiHeader.biBitCount = 1;
@@ -681,10 +740,10 @@ static void test_CopyImage_Bitmap(int depth)
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);
+ check_copy_image(dib, type, 0, 0, 0, 2, 2, 1, FALSE);
+ check_copy_image(dib, type, 0, 5, 0, 5, 2, 1, FALSE);
+ check_copy_image(dib, type, 0, 0, 5, 2, 5, 1, FALSE);
+ check_copy_image(dib, type, 0, 5, 5, 5, 5, 1, FALSE);
DeleteObject(dib);
}
}
@@ -3018,6 +3077,19 @@ static void test_Image_StretchMode(void)
HeapFree(GetProcessHeap(), 0, bmi);
}
+static void test_copy_image(void)
+{
+ static const UINT types[] = {IMAGE_BITMAP, IMAGE_ICON, IMAGE_CURSOR};
+ static const UINT depths[] = {1, 4, 8, 16, 24, 32};
+ unsigned int i, j;
+
+ for (i = 0; i < ARRAY_SIZE(types); ++i)
+ {
+ for (j = 0; j < ARRAY_SIZE(depths); ++j)
+ do_test_copy_image(types[i], depths[j]);
+ }
+}
+
START_TEST(cursoricon)
{
pGetCursorInfo = (void *)GetProcAddress( GetModuleHandleA("user32.dll"), "GetCursorInfo" );
@@ -3039,12 +3111,7 @@ START_TEST(cursoricon)
return;
}
- test_CopyImage_Bitmap(1);
- test_CopyImage_Bitmap(4);
- test_CopyImage_Bitmap(8);
- test_CopyImage_Bitmap(16);
- test_CopyImage_Bitmap(24);
- test_CopyImage_Bitmap(32);
+ test_copy_image();
test_Image_StretchMode();
test_initial_cursor();
test_CreateIcon();
--
2.30.2
More information about the wine-devel
mailing list