diff --git a/win32ss/gdi/eng/surface.c b/win32ss/gdi/eng/surface.c index 3bfe6f89276..524ec7921ec 100644 --- a/win32ss/gdi/eng/surface.c +++ b/win32ss/gdi/eng/surface.c @@ -127,6 +127,10 @@ SURFACE_AllocSurface( PSURFACE psurf; SURFOBJ *pso; PVOID pvSection; + BOOLEAN bExtraBitsNeeded = FALSE; + + DPRINT("cy '%ld' iFormat '%ld' cjWidth '%ld' cjBufSize '%ld' pvBits '%p'\n", + cy, iFormat, cjWidth, cjBufSize, pvBits); NT_ASSERT(!pvBits || (iType == STYPE_BITMAP)); NT_ASSERT((iFormat <= BMF_32BPP) || (cjBufSize != 0)); @@ -171,9 +175,9 @@ SURFACE_AllocSurface( /* Make sure the buffer is large enough */ if (cjBufSize < cjBits) { - DPRINT1("Buffer is too small, required: %lu, got %lu\n", - cjBits, cjBufSize); - return NULL; + DPRINT("Buffer is too small, required: %lu, got %lu\n", + cjBits, cjBufSize); + bExtraBitsNeeded = TRUE; } } } @@ -185,8 +189,9 @@ SURFACE_AllocSurface( } /* Check if we need an extra large object */ - if ((iType == STYPE_BITMAP) && (pvBits == NULL) && - !(fjBitmap & BMF_USERMEM) && !(fjBitmap & BMF_KMSECTION)) + if (((iType == STYPE_BITMAP) && (pvBits == NULL) && + !(fjBitmap & BMF_USERMEM) && !(fjBitmap & BMF_KMSECTION)) || + bExtraBitsNeeded) { /* Allocate an object large enough to hold the bits */ cjObject = sizeof(SURFACE) + cjBits; diff --git a/win32ss/gdi/gdi32/objects/bitmap.c b/win32ss/gdi/gdi32/objects/bitmap.c index b029d4ad2df..c858710aeac 100644 --- a/win32ss/gdi/gdi32/objects/bitmap.c +++ b/win32ss/gdi/gdi32/objects/bitmap.c @@ -577,6 +577,9 @@ SetDIBits( INT LinesCopied = 0; BOOL newDC = FALSE; + if (fuColorUse != DIB_RGB_COLORS && fuColorUse != DIB_PAL_COLORS) + return 0; + if (!lpvBits || (GDI_HANDLE_GET_TYPE(hBitmap) != GDI_OBJECT_TYPE_BITMAP)) return 0; @@ -590,6 +593,16 @@ SetDIBits( } } + if (lpbmi->bmiHeader.biCompression == BI_BITFIELDS) + { + DWORD *masks = (DWORD *)lpbmi->bmiColors; + if (!masks[0] || !masks[1] || !masks[2]) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return 0; + } + } + hDCc = NtGdiGetDCforBitmap(hBitmap); // hDC can be NULL, so, get it from the bitmap. SavehDC = hDCc; if (!hDCc) // No DC associated with bitmap, Clone or Create one. @@ -666,10 +679,28 @@ SetDIBitsToDevice( UINT cjBmpScanSize = 0; BOOL Hit = FALSE; PVOID pvSafeBits = (PVOID) Bits; + UINT bmiHeight; + BOOL top_down; + INT src_y = 0; + + #define MaxScanLines 0x2000 + #define aligned(Address, Count) \ + (((ULONG_PTR)(void *)(Address)) % (Count) == 0) if (!ScanLines || !lpbmi || !Bits) return 0; + DPRINT("StartScan '%d' ScanLines '%d' Bits '%p'\n" + " lpbmi '%p' ColorUse '%d' SizeImage '%d'\n" + " biHeight '%d' biWidth '%d' biBitCount '%d'\n", + StartScan, ScanLines, Bits, lpbmi, ColorUse, + lpbmi->bmiHeader.biSizeImage, + lpbmi->bmiHeader.biHeight, lpbmi->bmiHeader.biWidth, + lpbmi->bmiHeader.biBitCount); + + if (lpbmi->bmiHeader.biWidth < 0) + return 0; + if (ColorUse && ColorUse != DIB_PAL_COLORS && ColorUse != DIB_PAL_COLORS + 1) return 0; @@ -677,6 +708,81 @@ SetDIBitsToDevice( if (!pConvertedInfo) return 0; + bmiHeight = abs(pConvertedInfo->bmiHeader.biHeight); + top_down = (pConvertedInfo->bmiHeader.biHeight < 0); + if ((StartScan > bmiHeight) && (ScanLines > bmiHeight)) + { + DPRINT("Returning ScanLines of '%d'.\n", ScanLines); + LinesCopied = ScanLines; + goto Exit; + } + + if (pConvertedInfo->bmiHeader.biHeight == 0) + { + LinesCopied = 0; + goto Exit; + } + + if (!aligned(Bits, 4) && (ScanLines > Height)) + { + LinesCopied = 0; + goto Exit; + } + + /* Below code modeled after Wine's nulldrv_SetDIBitsToDevice */ + if (StartScan <= YSrc + bmiHeight) + { + if ((pConvertedInfo->bmiHeader.biCompression == BI_RLE8) || + (pConvertedInfo->bmiHeader.biCompression == BI_RLE4)) + { + StartScan = 0; + ScanLines = bmiHeight; + } + else + { + if (StartScan >= bmiHeight) + { + LinesCopied = 0; + goto Exit; + } + if (!top_down && ScanLines > bmiHeight - StartScan) + { + ScanLines = bmiHeight - StartScan; + } + + src_y = StartScan + ScanLines - (YSrc + Height); + if (!top_down) + { + /* get rid of unnecessary lines */ + if ((src_y >= (INT)ScanLines || src_y < 0) && + pConvertedInfo->bmiHeader.biCompression != BI_BITFIELDS) + { + LinesCopied = ScanLines; + goto Exit; + } + if (YDest >= 0) + { + LinesCopied = ScanLines + StartScan; + ScanLines -= src_y; + } + else + { + LinesCopied = ScanLines - src_y; + } + } + else if (src_y >= ScanLines) + { + if ((lpbmi->bmiHeader.biHeight < 0) && (StartScan > MaxScanLines)) + ScanLines = lpbmi->bmiHeader.biHeight - StartScan; + DPRINT("Returning ScanLines of '%d'.\n", ScanLines); + LinesCopied = ScanLines; + goto Exit; + } + if (top_down) + LinesCopied = ScanLines; + } + } + HANDLE_METADC(INT, SetDIBitsToDevice, 0, @@ -769,11 +875,35 @@ SetDIBitsToDevice( pConvertedInfo->bmiHeader.biCompression == BI_PNG )) )*/ { LinesCopied = NtGdiSetDIBitsToDeviceInternal(hdc, XDest, YDest, Width, Height, XSrc, YSrc, - StartScan, ScanLines, (LPBYTE) pvSafeBits, (LPBITMAPINFO) pConvertedInfo, ColorUse, + StartScan, max(ScanLines, LinesCopied), (LPBYTE) pvSafeBits, (LPBITMAPINFO) pConvertedInfo, ColorUse, cjBmpScanSize, ConvertedInfoSize, TRUE, NULL); } + + if (bmiHeight > MaxScanLines) + { + LinesCopied = ScanLines; + } + if (YDest < 0) + { + if (top_down) + LinesCopied = ScanLines; + else + LinesCopied = ScanLines - src_y; + } + + if (pConvertedInfo->bmiHeader.biCompression == BI_RLE8 || + pConvertedInfo->bmiHeader.biCompression == BI_RLE4) + { + LinesCopied = bmiHeight; + } + + if (pConvertedInfo->bmiHeader.biHeight < 0) + { + LinesCopied = ScanLines; + } + Exit: if (Bits != pvSafeBits) RtlFreeHeap(RtlGetProcessHeap(), 0, pvSafeBits); diff --git a/win32ss/gdi/ntgdi/dibobj.c b/win32ss/gdi/ntgdi/dibobj.c index ec5fa69a469..430563ed2d7 100644 --- a/win32ss/gdi/ntgdi/dibobj.c +++ b/win32ss/gdi/ntgdi/dibobj.c @@ -501,6 +501,17 @@ NtGdiSetDIBitsToDeviceInternal( if (!Bits) return 0; + DPRINT("StartScan '%d' ScanLines '%d' Bits '%p'\n" + " bmi '%p' ColorUse '%d' SizeImage '%d'\n" + " Height %d Width %d\n" + " biHeight '%d' biWidth '%d' biBitCount '%d'\n" + " XSrc '%d' YSrc '%d' xDext '%d' yDest '%d'\n", + StartScan, ScanLines, Bits, bmi, ColorUse, + Height, Width, + bmi->bmiHeader.biSizeImage, bmi->bmiHeader.biHeight, + bmi->bmiHeader.biWidth, bmi->bmiHeader.biBitCount, + XSrc, YSrc, XDest, YDest); + pbmiSafe = ExAllocatePoolWithTag(PagedPool, cjMaxInfo, 'pmTG'); if (!pbmiSafe) return 0; @@ -518,7 +529,17 @@ NtGdiSetDIBitsToDeviceInternal( } _SEH2_END; - ScanLines = min(ScanLines, abs(bmi->bmiHeader.biHeight) - StartScan); + if (0 <= YDest && YDest <= Height) + { + ScanLines = min(abs(Height), ScanLines); + if (YSrc > 0 && YDest <= Height) + ScanLines += YSrc; + } + else + { + ScanLines = min(ScanLines, abs(bmi->bmiHeader.biHeight) - StartScan); + } + if (ScanLines == 0) { DPRINT1("ScanLines == 0\n"); @@ -562,6 +583,11 @@ NtGdiSetDIBitsToDeviceInternal( SourceSize.cx = bmi->bmiHeader.biWidth; SourceSize.cy = ScanLines; + if (0 < YDest && YDest <= Height) + { + if (YSrc > 0) + ScanLines += YSrc; + } //DIBWidth = WIDTH_BYTES_ALIGN32(SourceSize.cx, bmi->bmiHeader.biBitCount);