[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

svn path=/trunk/; revision=60999
This commit is contained in:
Jérôme Gardou 2013-11-15 17:34:13 +00:00
parent 225b2406ac
commit ccf756f902
2 changed files with 140 additions and 36 deletions

View file

@ -25,7 +25,7 @@ DBG_DEFAULT_CHANNEL(UserIcon);
SYSTEM_CURSORINFO gSysCursorInfo; SYSTEM_CURSORINFO gSysCursorInfo;
BOOL BOOL
InitCursorImpl() InitCursorImpl(VOID)
{ {
gSysCursorInfo.Enabled = FALSE; gSysCursorInfo.Enabled = FALSE;
gSysCursorInfo.ButtonsDown = 0; gSysCursorInfo.ButtonsDown = 0;
@ -154,7 +154,8 @@ IntDestroyCurIconObject(PCURICON_OBJECT CurIcon, BOOLEAN bForce)
{ {
if(CurIcon->CURSORF_flags & CURSORF_CURRENT) 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); UserDeleteObject(CurIcon->head.h, TYPE_CURSOR);
return FALSE; return FALSE;
} }
@ -238,7 +239,9 @@ IntCleanupCurIcons(struct _EPROCESS *Process, PPROCESSINFO Win32Process)
{ {
CurIcon = Win32Process->pCursorCache; CurIcon = Win32Process->pCursorCache;
Win32Process->pCursorCache = CurIcon->pcurNext; 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); IntDestroyCurIconObject(CurIcon, TRUE);
} }
} }
@ -1004,8 +1007,8 @@ NtUserSetCursorIconData(
if(IsShared) if(IsShared)
{ {
/* Update process cache in case of shared cursor */ /* Update process cache in case of shared cursor */
UserReferenceObject(CurIcon);
PPROCESSINFO ppi = CurIcon->head.ppi; PPROCESSINFO ppi = CurIcon->head.ppi;
UserReferenceObject(CurIcon);
CurIcon->pcurNext = ppi->pCursorCache; CurIcon->pcurNext = ppi->pCursorCache;
ppi->pCursorCache = CurIcon; ppi->pCursorCache = CurIcon;
} }
@ -1038,7 +1041,7 @@ done:
UserDereferenceObject(CurIcon); UserDereferenceObject(CurIcon);
TRACE("Leave NtUserSetCursorIconData, ret=%i\n",Ret); TRACE("Leave NtUserSetCursorIconData, ret=%i\n",Ret);
UserLeave(); UserLeave();
return Ret; return Ret;
} }

View file

@ -175,6 +175,52 @@ static int DIB_GetBitmapInfo( const BITMAPINFOHEADER *header, LONG *width,
return -1; 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 );
}
/*********************************************************************** /***********************************************************************
* bmi_has_alpha * bmi_has_alpha
*/ */
@ -576,12 +622,41 @@ static BOOL CURSORICON_GetCursorDataFromIconInfo(
BITMAP bm; BITMAP bm;
ZeroMemory(pCursorData, sizeof(*pCursorData)); ZeroMemory(pCursorData, sizeof(*pCursorData));
/* Use the CopyImage function, as it will gracefully convert our bitmap to the screen bit depth */
if(pIconInfo->hbmColor) if(pIconInfo->hbmColor)
{ {
pCursorData->hbmColor = CopyImage(pIconInfo->hbmColor, IMAGE_BITMAP, 0, 0, 0); /* We must convert the color bitmap to screen format */
if(!pCursorData->hbmColor) HDC hdcScreen, hdcMem;
HBITMAP hbmpPrev;
/* The mask dictates its dimensions */
if (!GetObject(pIconInfo->hbmMask, sizeof(bm), &bm))
return FALSE; 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); pCursorData->hbmMask = CopyImage(pIconInfo->hbmMask, IMAGE_BITMAP, 0, 0, LR_MONOCHROME);
if(!pCursorData->hbmMask) if(!pCursorData->hbmMask)
@ -1318,7 +1393,7 @@ CURSORICON_LoadImageW(
if(!dir) if(!dir)
goto done; goto done;
wResId = LookupIconIdFromDirectoryEx((PBYTE)dir, bIcon, cxDesired, cyDesired, fuLoad & LR_MONOCHROME); wResId = LookupIconIdFromDirectoryEx((PBYTE)dir, bIcon, cxDesired, cyDesired, fuLoad);
FreeResource(handle); FreeResource(handle);
/* Get the relevant resource pointer */ /* Get the relevant resource pointer */
@ -2008,11 +2083,11 @@ int WINAPI LookupIconIdFromDirectoryEx(
WORD bppDesired; WORD bppDesired;
CURSORICONDIR* dir = (CURSORICONDIR*)presbits; CURSORICONDIR* dir = (CURSORICONDIR*)presbits;
CURSORICONDIRENTRY* entry; CURSORICONDIRENTRY* entry;
int i, numMatch, iIndex = -1; int i, numMatch = 0, iIndex = -1;
WORD width, height; WORD width, height, BitCount = 0;
USHORT bitcount; BOOL notPaletted = FALSE;
ULONG cxyDiff, cxyDiffTmp; ULONG bestScore = 0xFFFFFFFF, score;
TRACE("%p, %x, %i, %i, %x.\n", presbits, fIcon, cxDesired, cyDesired, Flags); TRACE("%p, %x, %i, %i, %x.\n", presbits, fIcon, cxDesired, cyDesired, Flags);
if(!(dir && !dir->idReserved && (dir->idType & 3))) if(!(dir && !dir->idReserved && (dir->idType & 3)))
@ -2035,13 +2110,11 @@ int WINAPI LookupIconIdFromDirectoryEx(
} }
if(!cxDesired) if(!cxDesired)
cxDesired = GetSystemMetrics(fIcon ? SM_CXICON : SM_CXCURSOR); cxDesired = Flags & LR_DEFAULTSIZE ? GetSystemMetrics(fIcon ? SM_CXICON : SM_CXCURSOR) : 256;
if(!cyDesired) 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 */ /* Find the best match for the desired size */
cxyDiff = 0xFFFFFFFF;
numMatch = 0;
for(i = 0; i < dir->idCount; i++) for(i = 0; i < dir->idCount; i++)
{ {
entry = &dir->idEntries[i]; entry = &dir->idEntries[i];
@ -2051,27 +2124,41 @@ int WINAPI LookupIconIdFromDirectoryEx(
/* 0 represents 256 */ /* 0 represents 256 */
if(!width) width = 256; if(!width) width = 256;
if(!height) height = 256; if(!height) height = 256;
/* Let it be a 1-norm */ /* Calculate the "score" (lower is better) */
cxyDiffTmp = max(abs(width - cxDesired), abs(height - cyDesired)); score = 2*(abs(width - cxDesired) + abs(height - cyDesired));
if( cxyDiffTmp > cxyDiff) if( score > bestScore)
continue; 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++; numMatch++;
continue; continue;
} }
iIndex = i; iIndex = i;
numMatch = 1; numMatch = 1;
cxyDiff = cxyDiffTmp; bestScore = score;
BitCount = entry->wBitCount;
} }
if(numMatch == 1) if(numMatch == 1)
{ {
/* Only one entry fit the asked dimensions */ /* Only one entry fits the asked dimensions */
return dir->idEntries[iIndex].wResId; return dir->idEntries[iIndex].wResId;
} }
/* Avoid paletted icons on non-paletted device */
if (bppDesired > 8 && BitCount > 8)
notPaletted = TRUE;
bitcount = 0; BitCount = 0;
iIndex = -1; iIndex = -1;
/* Now find the entry with the best depth */ /* Now find the entry with the best depth */
for(i = 0; i < dir->idCount; i++) for(i = 0; i < dir->idCount; i++)
@ -2083,25 +2170,33 @@ int WINAPI LookupIconIdFromDirectoryEx(
if(!width) width = 256; if(!width) width = 256;
if(!height) height = 256; if(!height) height = 256;
/* Check if this is the best match we had */ /* Check if this is the best match we had */
cxyDiffTmp = max(abs(width - cxDesired), abs(height - cyDesired)); score = 2*(abs(width - cxDesired) + abs(height - cyDesired));
if(cxyDiffTmp != cxyDiff) if(width > cxDesired)
score -= width - cxDesired;
if(height > cyDesired)
score -= height - cyDesired;
if(score != bestScore)
continue; continue;
/* Exact match? */ /* Exact match? */
if(entry->wBitCount == bppDesired) if(entry->wBitCount == bppDesired)
return entry->wResId; return entry->wResId;
/* We take the highest possible but smaller than the display depth */ /* 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; iIndex = i;
bitcount = entry->wBitCount; BitCount = entry->wBitCount;
} }
} }
if(iIndex >= 0) if(iIndex >= 0)
return dir->idEntries[iIndex].wResId; return dir->idEntries[iIndex].wResId;
/* No inferior or equal depth available. Get the smallest one */ /* No inferior or equal depth available. Get the smallest bigger one */
bitcount = 0x7FFF; BitCount = 0xFFFF;
iIndex = 0;
for(i = 0; i < dir->idCount; i++) for(i = 0; i < dir->idCount; i++)
{ {
entry = &dir->idEntries[i]; entry = &dir->idEntries[i];
@ -2111,14 +2206,20 @@ int WINAPI LookupIconIdFromDirectoryEx(
if(!width) width = 256; if(!width) width = 256;
if(!height) height = 256; if(!height) height = 256;
/* Check if this is the best match we had */ /* Check if this is the best match we had */
cxyDiffTmp = max(abs(width - cxDesired), abs(height - cyDesired)); score = 2*(abs(width - cxDesired) + abs(height - cyDesired));
if(cxyDiffTmp != cxyDiff) if(width > cxDesired)
score -= width - cxDesired;
if(height > cyDesired)
score -= height - cyDesired;
if(score != bestScore)
continue; continue;
/* Check the bit depth */ /* Check the bit depth */
if(entry->wBitCount < bitcount) if(entry->wBitCount < BitCount)
{ {
if((entry->wBitCount <= 8) && notPaletted)
continue;
iIndex = i; iIndex = i;
bitcount = entry->wBitCount; BitCount = entry->wBitCount;
} }
} }