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/cursori... ============================================================================== --- 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/windows... ============================================================================== --- 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; } }