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..dcca6c4fc4b 100644 --- a/win32ss/gdi/gdi32/objects/bitmap.c +++ b/win32ss/gdi/gdi32/objects/bitmap.c @@ -666,6 +666,10 @@ SetDIBitsToDevice( UINT cjBmpScanSize = 0; BOOL Hit = FALSE; PVOID pvSafeBits = (PVOID) Bits; + UINT bmiHeight; + + #define aligned(Address, Count) \ + (((ULONG_PTR)(void *)(Address)) % (Count) == 0) if (!ScanLines || !lpbmi || !Bits) return 0; @@ -677,6 +681,61 @@ SetDIBitsToDevice( if (!pConvertedInfo) return 0; + if (pConvertedInfo->bmiHeader.biHeight == 0) + { + return 0; + } + + if (!aligned(Bits, 4) && (ScanLines > Height)) + { + return 0; + } + + /* Below code modeled after Wine's nulldrv_SetDIBitsToDevice */ + bmiHeight = abs(pConvertedInfo->bmiHeader.biHeight); + if (StartScan <= YSrc + bmiHeight) + { + BOOL top_down; + UINT src_y = 0; + + top_down = (pConvertedInfo->bmiHeader.biHeight < 0); + if ((pConvertedInfo->bmiHeader.biCompression == BI_RLE8) || + (pConvertedInfo->bmiHeader.biCompression == BI_RLE4)) + { + StartScan = 0; + ScanLines = bmiHeight; + } + else + { + if (StartScan >= bmiHeight) + { + return 0; + } + if (!top_down && ScanLines > bmiHeight - StartScan) + { + ScanLines = bmiHeight - StartScan; + } + src_y = StartScan + ScanLines - (YSrc + Height); + if (src_y > 0) + { + if (!top_down) + { + /* get rid of unnecessary lines */ + if (src_y >= ScanLines) + { + return 0; + } + ScanLines -= src_y; + } + else if (src_y >= ScanLines) + { + return ScanLines; + } + } + LinesCopied = ScanLines; + } + } + HANDLE_METADC(INT, SetDIBitsToDevice, 0, diff --git a/win32ss/gdi/ntgdi/dibobj.c b/win32ss/gdi/ntgdi/dibobj.c index ec5fa69a469..59f42f86b5c 100644 --- a/win32ss/gdi/ntgdi/dibobj.c +++ b/win32ss/gdi/ntgdi/dibobj.c @@ -518,7 +518,10 @@ NtGdiSetDIBitsToDeviceInternal( } _SEH2_END; - ScanLines = min(ScanLines, abs(bmi->bmiHeader.biHeight) - StartScan); + ScanLines = min(abs(Height), ScanLines); + if (YSrc > 0) + ScanLines += YSrc; + if (ScanLines == 0) { DPRINT1("ScanLines == 0\n"); @@ -562,6 +565,8 @@ NtGdiSetDIBitsToDeviceInternal( SourceSize.cx = bmi->bmiHeader.biWidth; SourceSize.cy = ScanLines; + if (YSrc > 0) + ScanLines += YSrc; //DIBWidth = WIDTH_BYTES_ALIGN32(SourceSize.cx, bmi->bmiHeader.biBitCount);