Author: jgardou
Date: Fri Nov 15 17:34:13 2013
New Revision: 60999
URL:
http://svn.reactos.org/svn/reactos?rev=60999&view=rev
Log:
[WIN32SS]
- Fix an assert in new cursoricon implementation
- Fix CreateIconIndirect behaviour regarding bits per pixel and bitmap dimensions
- Fix LookupIconIdFromDirectoryEx behaviour to fulfill last commited tests
CORE-7575 #comment LookupIconDirectoryEx and CreateIconIndirect now works as per tests
Modified:
trunk/reactos/win32ss/user/ntuser/cursoricon_new.c
trunk/reactos/win32ss/user/user32/windows/cursoricon_new.c
Modified: trunk/reactos/win32ss/user/ntuser/cursoricon_new.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/user/ntuser/cursor…
==============================================================================
--- trunk/reactos/win32ss/user/ntuser/cursoricon_new.c [iso-8859-1] (original)
+++ trunk/reactos/win32ss/user/ntuser/cursoricon_new.c [iso-8859-1] Fri Nov 15 17:34:13
2013
@@ -25,7 +25,7 @@
SYSTEM_CURSORINFO gSysCursorInfo;
BOOL
-InitCursorImpl()
+InitCursorImpl(VOID)
{
gSysCursorInfo.Enabled = FALSE;
gSysCursorInfo.ButtonsDown = 0;
@@ -154,7 +154,8 @@
{
if(CurIcon->CURSORF_flags & CURSORF_CURRENT)
{
- /* Mark the object as destroyed, and fail, as per wine tests */
+ /* Mark the object as destroyed, and fail, as per tests */
+ TRACE("Cursor is current, marking as destroyed.\n");
UserDeleteObject(CurIcon->head.h, TYPE_CURSOR);
return FALSE;
}
@@ -238,7 +239,9 @@
{
CurIcon = Win32Process->pCursorCache;
Win32Process->pCursorCache = CurIcon->pcurNext;
- ASSERT(CurIcon->head.cLockObj == 2);
+ /* One ref for the handle, one for the list,
+ * and potentially one from an other process via SetCursor */
+ ASSERT(CurIcon->head.cLockObj <= 3);
IntDestroyCurIconObject(CurIcon, TRUE);
}
}
@@ -1004,8 +1007,8 @@
if(IsShared)
{
/* Update process cache in case of shared cursor */
+ PPROCESSINFO ppi = CurIcon->head.ppi;
UserReferenceObject(CurIcon);
- PPROCESSINFO ppi = CurIcon->head.ppi;
CurIcon->pcurNext = ppi->pCursorCache;
ppi->pCursorCache = CurIcon;
}
@@ -1038,7 +1041,7 @@
UserDereferenceObject(CurIcon);
TRACE("Leave NtUserSetCursorIconData, ret=%i\n",Ret);
UserLeave();
-
+
return Ret;
}
Modified: trunk/reactos/win32ss/user/user32/windows/cursoricon_new.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/user/user32/window…
==============================================================================
--- trunk/reactos/win32ss/user/user32/windows/cursoricon_new.c [iso-8859-1] (original)
+++ trunk/reactos/win32ss/user/user32/windows/cursoricon_new.c [iso-8859-1] Fri Nov 15
17:34:13 2013
@@ -173,6 +173,52 @@
}
ERR("(%d): unknown/wrong size for header\n", header->biSize );
return -1;
+}
+
+/* copy an icon bitmap, even when it can't be selected into a DC */
+/* helper for CreateIconIndirect */
+static void stretch_blt_icon(HDC hdc_dst, int dst_width, int dst_height, HBITMAP src)
+{
+ HDC hdc = CreateCompatibleDC( 0 );
+ BITMAP bm;
+ HBITMAP hbmpPrev;
+
+ GetObjectW(src, sizeof(bm), &bm);
+
+ hbmpPrev = SelectObject(hdc, src);
+
+ if (!hbmpPrev) /* do it the hard way */
+ {
+ BITMAPINFO *info;
+ void *bits;
+
+ if (!(info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO,
bmiColors[256] )))) return;
+ info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ info->bmiHeader.biWidth = bm.bmWidth;
+ info->bmiHeader.biHeight = bm.bmHeight;
+ info->bmiHeader.biPlanes = GetDeviceCaps( hdc_dst, PLANES );
+ info->bmiHeader.biBitCount = GetDeviceCaps( hdc_dst, BITSPIXEL );
+ info->bmiHeader.biCompression = BI_RGB;
+ info->bmiHeader.biSizeImage = get_dib_image_size( bm.bmWidth, bm.bmHeight,
info->bmiHeader.biBitCount );
+ info->bmiHeader.biXPelsPerMeter = 0;
+ info->bmiHeader.biYPelsPerMeter = 0;
+ info->bmiHeader.biClrUsed = 0;
+ info->bmiHeader.biClrImportant = 0;
+ bits = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage );
+ if (bits && GetDIBits( hdc, src, 0, bm.bmHeight, bits, info,
DIB_RGB_COLORS ))
+ StretchDIBits( hdc_dst, 0, 0, dst_width, dst_height,
+ 0, 0, bm.bmWidth, bm.bmHeight, bits, info, DIB_RGB_COLORS,
SRCCOPY );
+
+ HeapFree( GetProcessHeap(), 0, bits );
+ HeapFree( GetProcessHeap(), 0, info );
+ }
+ else
+ {
+ StretchBlt( hdc_dst, 0, 0, dst_width, dst_height, hdc, 0, 0, bm.bmWidth,
bm.bmHeight, SRCCOPY );
+ SelectObject(hdc, hbmpPrev);
+ }
+
+ DeleteDC( hdc );
}
/***********************************************************************
@@ -576,12 +622,41 @@
BITMAP bm;
ZeroMemory(pCursorData, sizeof(*pCursorData));
- /* Use the CopyImage function, as it will gracefully convert our bitmap to the screen
bit depth */
if(pIconInfo->hbmColor)
{
- pCursorData->hbmColor = CopyImage(pIconInfo->hbmColor, IMAGE_BITMAP, 0, 0,
0);
- if(!pCursorData->hbmColor)
+ /* We must convert the color bitmap to screen format */
+ HDC hdcScreen, hdcMem;
+ HBITMAP hbmpPrev;
+
+ /* The mask dictates its dimensions */
+ if (!GetObject(pIconInfo->hbmMask, sizeof(bm), &bm))
return FALSE;
+ hdcScreen = CreateDCW(DISPLAYW, NULL, NULL, NULL);
+ if(!hdcScreen)
+ return FALSE;
+ hdcMem = CreateCompatibleDC(hdcScreen);
+ if(!hdcMem)
+ {
+ DeleteDC(hdcScreen);
+ return FALSE;
+ }
+ pCursorData->hbmColor = CreateCompatibleBitmap(hdcScreen, bm.bmWidth,
bm.bmHeight);
+ DeleteDC(hdcScreen);
+ if (!pCursorData->hbmColor)
+ {
+ DeleteDC(hdcMem);
+ return FALSE;
+ }
+ hbmpPrev = SelectObject(hdcMem, pCursorData->hbmColor);
+ if (!hbmpPrev)
+ {
+ DeleteDC(hdcMem);
+ DeleteObject(pCursorData->hbmColor);
+ return FALSE;
+ }
+ stretch_blt_icon( hdcMem, bm.bmWidth, bm.bmHeight, pIconInfo->hbmColor);
+ SelectObject(hdcMem, hbmpPrev);
+ DeleteDC(hdcMem);
}
pCursorData->hbmMask = CopyImage(pIconInfo->hbmMask, IMAGE_BITMAP, 0, 0,
LR_MONOCHROME);
if(!pCursorData->hbmMask)
@@ -1318,7 +1393,7 @@
if(!dir)
goto done;
- wResId = LookupIconIdFromDirectoryEx((PBYTE)dir, bIcon, cxDesired, cyDesired, fuLoad
& LR_MONOCHROME);
+ wResId = LookupIconIdFromDirectoryEx((PBYTE)dir, bIcon, cxDesired, cyDesired,
fuLoad);
FreeResource(handle);
/* Get the relevant resource pointer */
@@ -2008,11 +2083,11 @@
WORD bppDesired;
CURSORICONDIR* dir = (CURSORICONDIR*)presbits;
CURSORICONDIRENTRY* entry;
- int i, numMatch, iIndex = -1;
- WORD width, height;
- USHORT bitcount;
- ULONG cxyDiff, cxyDiffTmp;
-
+ int i, numMatch = 0, iIndex = -1;
+ WORD width, height, BitCount = 0;
+ BOOL notPaletted = FALSE;
+ ULONG bestScore = 0xFFFFFFFF, score;
+
TRACE("%p, %x, %i, %i, %x.\n", presbits, fIcon, cxDesired, cyDesired,
Flags);
if(!(dir && !dir->idReserved && (dir->idType & 3)))
@@ -2035,13 +2110,11 @@
}
if(!cxDesired)
- cxDesired = GetSystemMetrics(fIcon ? SM_CXICON : SM_CXCURSOR);
+ cxDesired = Flags & LR_DEFAULTSIZE ? GetSystemMetrics(fIcon ? SM_CXICON :
SM_CXCURSOR) : 256;
if(!cyDesired)
- cyDesired = GetSystemMetrics(fIcon ? SM_CYICON : SM_CYCURSOR);
+ cyDesired = Flags & LR_DEFAULTSIZE ? GetSystemMetrics(fIcon ? SM_CYICON :
SM_CYCURSOR) : 256;
/* Find the best match for the desired size */
- cxyDiff = 0xFFFFFFFF;
- numMatch = 0;
for(i = 0; i < dir->idCount; i++)
{
entry = &dir->idEntries[i];
@@ -2051,27 +2124,41 @@
/* 0 represents 256 */
if(!width) width = 256;
if(!height) height = 256;
- /* Let it be a 1-norm */
- cxyDiffTmp = max(abs(width - cxDesired), abs(height - cyDesired));
- if( cxyDiffTmp > cxyDiff)
+ /* Calculate the "score" (lower is better) */
+ score = 2*(abs(width - cxDesired) + abs(height - cyDesired));
+ if( score > bestScore)
continue;
- if( cxyDiffTmp == cxyDiff)
- {
+ /* Bigger than requested lowers the score */
+ if(width > cxDesired)
+ score -= width - cxDesired;
+ if(height > cyDesired)
+ score -= height - cyDesired;
+ if(score > bestScore)
+ continue;
+ if(score == bestScore)
+ {
+ if(entry->wBitCount > BitCount)
+ BitCount = entry->wBitCount;
numMatch++;
continue;
}
iIndex = i;
numMatch = 1;
- cxyDiff = cxyDiffTmp;
+ bestScore = score;
+ BitCount = entry->wBitCount;
}
if(numMatch == 1)
{
- /* Only one entry fit the asked dimensions */
+ /* Only one entry fits the asked dimensions */
return dir->idEntries[iIndex].wResId;
}
-
- bitcount = 0;
+
+ /* Avoid paletted icons on non-paletted device */
+ if (bppDesired > 8 && BitCount > 8)
+ notPaletted = TRUE;
+
+ BitCount = 0;
iIndex = -1;
/* Now find the entry with the best depth */
for(i = 0; i < dir->idCount; i++)
@@ -2083,25 +2170,33 @@
if(!width) width = 256;
if(!height) height = 256;
/* Check if this is the best match we had */
- cxyDiffTmp = max(abs(width - cxDesired), abs(height - cyDesired));
- if(cxyDiffTmp != cxyDiff)
+ score = 2*(abs(width - cxDesired) + abs(height - cyDesired));
+ if(width > cxDesired)
+ score -= width - cxDesired;
+ if(height > cyDesired)
+ score -= height - cyDesired;
+ if(score != bestScore)
continue;
/* Exact match? */
if(entry->wBitCount == bppDesired)
return entry->wResId;
/* We take the highest possible but smaller than the display depth */
- if((entry->wBitCount > bitcount) && (entry->wBitCount <
bppDesired))
- {
+ if((entry->wBitCount > BitCount) && (entry->wBitCount <
bppDesired))
+ {
+ /* Avoid paletted icons on non paletted devices */
+ if ((entry->wBitCount <= 8) && notPaletted)
+ continue;
iIndex = i;
- bitcount = entry->wBitCount;
- }
- }
-
+ BitCount = entry->wBitCount;
+ }
+ }
+
if(iIndex >= 0)
return dir->idEntries[iIndex].wResId;
- /* No inferior or equal depth available. Get the smallest one */
- bitcount = 0x7FFF;
+ /* No inferior or equal depth available. Get the smallest bigger one */
+ BitCount = 0xFFFF;
+ iIndex = 0;
for(i = 0; i < dir->idCount; i++)
{
entry = &dir->idEntries[i];
@@ -2111,14 +2206,20 @@
if(!width) width = 256;
if(!height) height = 256;
/* Check if this is the best match we had */
- cxyDiffTmp = max(abs(width - cxDesired), abs(height - cyDesired));
- if(cxyDiffTmp != cxyDiff)
+ score = 2*(abs(width - cxDesired) + abs(height - cyDesired));
+ if(width > cxDesired)
+ score -= width - cxDesired;
+ if(height > cyDesired)
+ score -= height - cyDesired;
+ if(score != bestScore)
continue;
/* Check the bit depth */
- if(entry->wBitCount < bitcount)
- {
+ if(entry->wBitCount < BitCount)
+ {
+ if((entry->wBitCount <= 8) && notPaletted)
+ continue;
iIndex = i;
- bitcount = entry->wBitCount;
+ BitCount = entry->wBitCount;
}
}