https://git.reactos.org/?p=reactos.git;a=commitdiff;h=847b037fe98ec14bdcea2…
commit 847b037fe98ec14bdcea2cd9c3d356fecaa895cc
Author: Doug Lyons <douglyons(a)douglyons.com>
AuthorDate: Fri Jul 2 17:34:43 2021 -0500
Commit: GitHub <noreply(a)github.com>
CommitDate: Sat Jul 3 00:34:43 2021 +0200
[WIN32K] Revert NtGdiStretchDIBitsInternal to Previous Logic (#3774)
Fixes gdi32:dib / gdi32:bitmap tests and SIMS graphics.
JIRA issue: CORE-16236
---
win32ss/gdi/ntgdi/dibobj.c | 351 ++++++++++++++++++++++++++++++---------------
1 file changed, 237 insertions(+), 114 deletions(-)
diff --git a/win32ss/gdi/ntgdi/dibobj.c b/win32ss/gdi/ntgdi/dibobj.c
index c99cabe33c9..91abd424a35 100644
--- a/win32ss/gdi/ntgdi/dibobj.c
+++ b/win32ss/gdi/ntgdi/dibobj.c
@@ -512,7 +512,7 @@ NtGdiSetDIBitsToDeviceInternal(
ret = 0;
goto Exit;
}
- _SEH2_END
+ _SEH2_END;
ScanLines = min(ScanLines, abs(bmi->bmiHeader.biHeight) - StartScan);
if (ScanLines == 0)
@@ -1131,7 +1131,7 @@ NtGdiGetDIBitsInternal(
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
- _SEH2_YIELD(goto cleanup;)
+ goto cleanup;
}
_SEH2_END;
@@ -1212,7 +1212,6 @@ NtGdiStretchDIBitsInternal(
IN UINT cjMaxBits,
IN HANDLE hcmXform)
{
- BOOL bResult = FALSE;
SIZEL sizel;
RECTL rcSrc, rcDst;
PDC pdc;
@@ -1220,7 +1219,69 @@ NtGdiStretchDIBitsInternal(
PSURFACE psurfTmp = 0, psurfDst = 0;
PPALETTE ppalDIB = 0;
EXLATEOBJ exlo;
- PVOID pvBits;
+ PBYTE pvBits;
+
+ LPBITMAPINFO pbmiSafe;
+ UINT cjAlloc;
+ HBITMAP hBitmap, hOldBitmap = NULL;
+ HDC hdcMem;
+ HPALETTE hPal = NULL;
+ ULONG BmpFormat = 0;
+ INT LinesCopied = 0;
+
+ /* Check for bad iUsage */
+ if (dwUsage > 2) return 0;
+
+ /* We must have LPBITMAPINFO */
+ if (!pbmi)
+ {
+ DPRINT1("Error, Invalid Parameter.\n");
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+
+ /* Check if the size of the bitmap info is large enough */
+ if (cjMaxInfo < sizeof(BITMAPCOREHEADER))
+ {
+ return 0;
+ }
+
+ /* Use maximum size */
+ cjMaxInfo = min(cjMaxInfo, sizeof(BITMAPV5HEADER) + 256 * sizeof(RGBQUAD));
+
+ // HACK: the underlying code sucks and doesn't care for the size, so we
+ // give it the maximum ever needed
+ cjAlloc = sizeof(BITMAPV5HEADER) + 256 * sizeof(RGBQUAD);
+
+ /* Allocate a buffer the bitmapinfo */
+ pbmiSafe = ExAllocatePoolWithTag(PagedPool, cjAlloc, 'imBG');
+ if (!pbmiSafe)
+ {
+ /* Fail */
+ return 0;
+ }
+
+ /* Use SEH */
+ _SEH2_TRY
+ {
+ /* Probe and copy the BITMAPINFO */
+ ProbeForRead(pbmi, cjMaxInfo, 1);
+ RtlCopyMemory(pbmiSafe, pbmi, cjMaxInfo);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ ExFreePoolWithTag(pbmiSafe, 'imBG');
+ return 0;
+ }
+ _SEH2_END;
+
+ /* Check if the header size is large enough */
+ if ((pbmiSafe->bmiHeader.biSize < sizeof(BITMAPCOREHEADER)) ||
+ (pbmiSafe->bmiHeader.biSize > cjMaxInfo))
+ {
+ ExFreePoolWithTag(pbmiSafe, 'imBG');
+ return 0;
+ }
if (!(pdc = DC_LockDc(hdc)))
{
@@ -1242,31 +1303,9 @@ NtGdiStretchDIBitsInternal(
IntLPtoDP(pdc, (POINTL*)&sizel, 1);
DC_UnlockDc(pdc);
- /* Check if we can use NtGdiSetDIBitsToDeviceInternal */
- if ((sizel.cx == cxSrc) && (sizel.cy == cySrc) && (dwRop ==
SRCCOPY))
- {
- /* Yes, we can! */
- return NtGdiSetDIBitsToDeviceInternal(hdc,
- xDst,
- yDst,
- cxDst,
- cyDst,
- xSrc,
- ySrc,
- 0,
- cySrc,
- pjInit,
- pbmi,
- dwUsage,
- cjMaxBits,
- cjMaxInfo,
- TRUE,
- hcmXform);
- }
-
if (pjInit && (cjMaxBits > 0))
{
- pvBits = ExAllocatePoolWithTag(PagedPool, cjMaxBits, 'pmeT');
+ pvBits = ExAllocatePoolWithTag(PagedPool, cjMaxBits, TAG_DIB);
if (!pvBits)
{
return 0;
@@ -1279,110 +1318,194 @@ NtGdiStretchDIBitsInternal(
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
- ExFreePoolWithTag(pvBits, 'pmeT');
- _SEH2_YIELD(return 0);
+ ExFreePoolWithTag(pvBits, TAG_DIB);
+ return 0;
}
- _SEH2_END
+ _SEH2_END;
}
else
{
pvBits = NULL;
}
- /* FIXME: Locking twice is cheesy, coord tranlation in UM will fix it */
- if (!(pdc = DC_LockDc(hdc)))
+ /* Here we select between the dwRop with SRCCOPY or not. */
+ if (dwRop == SRCCOPY)
{
- DPRINT1("Could not lock dc\n");
- EngSetLastError(ERROR_INVALID_HANDLE);
- goto cleanup;
- }
+ hdcMem = NtGdiCreateCompatibleDC(hdc);
+ if (hdcMem == NULL)
+ {
+ DPRINT1("NtGdiCreateCompatibleDC failed to create hdc.\n");
+ EngSetLastError(ERROR_NO_SYSTEM_RESOURCES);
+ return 0;
+ }
- /* Calculate source and destination rect */
- rcSrc.left = xSrc;
- rcSrc.top = ySrc;
- rcSrc.right = xSrc + abs(cxSrc);
- rcSrc.bottom = ySrc + abs(cySrc);
- rcDst.left = xDst;
- rcDst.top = yDst;
- rcDst.right = rcDst.left + cxDst;
- rcDst.bottom = rcDst.top + cyDst;
- IntLPtoDP(pdc, (POINTL*)&rcDst, 2);
- RECTL_vOffsetRect(&rcDst, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y);
+ hBitmap = NtGdiCreateCompatibleBitmap(hdc,
+ abs(pbmiSafe->bmiHeader.biWidth),
+ abs(pbmiSafe->bmiHeader.biHeight));
+ if (hBitmap == NULL)
+ {
+ DPRINT1("NtGdiCreateCompatibleBitmap failed to create bitmap.\n");
+ DPRINT1("hdc : 0x%08x \n", hdc);
+ DPRINT1("width : 0x%08x \n", pbmiSafe->bmiHeader.biWidth);
+ DPRINT1("height : 0x%08x \n", pbmiSafe->bmiHeader.biHeight);
+ EngSetLastError(ERROR_NO_SYSTEM_RESOURCES);
+ return 0;
+ }
- if (pdc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
- {
- IntUpdateBoundsRect(pdc, &rcDst);
- }
+ /* Select the bitmap into hdcMem, and save a handle to the old bitmap */
+ hOldBitmap = NtGdiSelectBitmap(hdcMem, hBitmap);
- hbmTmp = GreCreateBitmapEx(pbmi->bmiHeader.biWidth,
- abs(pbmi->bmiHeader.biHeight),
- 0,
- BitmapFormat(pbmi->bmiHeader.biBitCount,
- pbmi->bmiHeader.biCompression),
- pbmi->bmiHeader.biHeight < 0 ? BMF_TOPDOWN : 0,
- cjMaxBits,
- pvBits,
- 0);
+ if (dwUsage == DIB_PAL_COLORS)
+ {
+ hPal = NtGdiGetDCObject(hdc, GDI_OBJECT_TYPE_PALETTE);
+ hPal = GdiSelectPalette(hdcMem, hPal, FALSE);
+ }
- if (!hbmTmp)
- {
- bResult = FALSE;
- goto cleanup;
+ pdc = DC_LockDc(hdcMem);
+ if (pdc != NULL)
+ {
+ IntSetDIBits(pdc, hBitmap, 0, abs(pbmiSafe->bmiHeader.biHeight), pvBits,
+ cjMaxBits, pbmiSafe, dwUsage);
+ DC_UnlockDc(pdc);
+ }
+
+ /* Origin for DIBitmap may be bottom left (positive biHeight) or top
+ left (negative biHeight) */
+ if (cxSrc == cxDst && cySrc == cyDst)
+ {
+ NtGdiBitBlt(hdc, xDst, yDst, cxDst, cyDst,
+ hdcMem, xSrc, abs(pbmiSafe->bmiHeader.biHeight) - cySrc -
ySrc,
+ dwRop, 0, 0);
+ }
+ else
+ {
+ NtGdiStretchBlt(hdc, xDst, yDst, cxDst, cyDst,
+ hdcMem, xSrc, abs(pbmiSafe->bmiHeader.biHeight) - cySrc -
ySrc,
+ cxSrc, cySrc, dwRop, 0);
+ }
+
+ /* cleanup */
+ if (hPal)
+ GdiSelectPalette(hdcMem, hPal, FALSE);
+
+ if (hOldBitmap)
+ NtGdiSelectBitmap(hdcMem, hOldBitmap);
+
+ NtGdiDeleteObjectApp(hdcMem);
+ GreDeleteObject(hBitmap);
+
+ } /* End of dwRop == SRCCOPY */
+ else
+ { /* Start of dwRop != SRCCOPY */
+ /* FIXME: Locking twice is cheesy, coord tranlation in UM will fix it */
+ if (!(pdc = DC_LockDc(hdc)))
+ {
+ DPRINT1("Could not lock dc\n");
+ EngSetLastError(ERROR_INVALID_HANDLE);
+ goto cleanup;
+ }
+
+ /* Calculate source and destination rect */
+ rcSrc.left = xSrc;
+ rcSrc.top = ySrc;
+ rcSrc.right = xSrc + abs(cxSrc);
+ rcSrc.bottom = ySrc + abs(cySrc);
+ rcDst.left = xDst;
+ rcDst.top = yDst;
+ rcDst.right = rcDst.left + cxDst;
+ rcDst.bottom = rcDst.top + cyDst;
+ IntLPtoDP(pdc, (POINTL*)&rcDst, 2);
+ RECTL_vOffsetRect(&rcDst, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y);
+
+ if (pdc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
+ {
+ IntUpdateBoundsRect(pdc, &rcDst);
+ }
+
+ BmpFormat = BitmapFormat(pbmiSafe->bmiHeader.biBitCount,
+ pbmiSafe->bmiHeader.biCompression);
+
+ hbmTmp = GreCreateBitmapEx(pbmiSafe->bmiHeader.biWidth,
+ abs(pbmiSafe->bmiHeader.biHeight),
+ 0,
+ BmpFormat,
+ pbmiSafe->bmiHeader.biHeight < 0 ? BMF_TOPDOWN :
0,
+ cjMaxBits,
+ pvBits,
+ 0);
+
+ if (!hbmTmp)
+ {
+ goto cleanup;
+ }
+
+ psurfTmp = SURFACE_ShareLockSurface(hbmTmp);
+ if (!psurfTmp)
+ {
+ goto cleanup;
+ }
+
+ /* Create a palette for the DIB */
+ ppalDIB = CreateDIBPalette(pbmiSafe, pdc, dwUsage);
+ if (!ppalDIB)
+ {
+ goto cleanup;
+ }
+
+ /* Prepare DC for blit */
+ DC_vPrepareDCsForBlit(pdc, &rcDst, NULL, NULL);
+
+ psurfDst = pdc->dclevel.pSurface;
+
+ /* Initialize XLATEOBJ */
+ EXLATEOBJ_vInitialize(&exlo,
+ ppalDIB,
+ psurfDst->ppal,
+ RGB(0xff, 0xff, 0xff),
+ pdc->pdcattr->crBackgroundClr,
+ pdc->pdcattr->crForegroundClr);
+
+ /* Perform the stretch operation */
+ IntEngStretchBlt(&psurfDst->SurfObj,
+ &psurfTmp->SurfObj,
+ NULL,
+ (CLIPOBJ *)&pdc->co,
+ &exlo.xlo,
+ &pdc->dclevel.ca,
+ &rcDst,
+ &rcSrc,
+ NULL,
+ &pdc->eboFill.BrushObject,
+ NULL,
+ WIN32_ROP3_TO_ENG_ROP4(dwRop));
+
+ /* Cleanup */
+ DC_vFinishBlit(pdc, NULL);
+ EXLATEOBJ_vCleanup(&exlo);
+
+ cleanup:
+ if (ppalDIB) PALETTE_ShareUnlockPalette(ppalDIB);
+ if (psurfTmp) SURFACE_ShareUnlockSurface(psurfTmp);
+ if (hbmTmp) GreDeleteObject(hbmTmp);
+ if (pdc) DC_UnlockDc(pdc);
}
- psurfTmp = SURFACE_ShareLockSurface(hbmTmp);
- if (!psurfTmp)
+ if (pbmiSafe) ExFreePoolWithTag(pbmiSafe, 'imBG');
+ if (pvBits) ExFreePoolWithTag(pvBits, TAG_DIB);
+
+ /* This is not what MSDN says is returned from this function, but it
+ * follows Wine's dlls/gdi32/dib.c function nulldrv_StretchDIBits
+ * and it fixes over 100 gdi32:dib regression tests. */
+ if (dwRop == SRCCOPY)
{
- bResult = FALSE;
- goto cleanup;
+ LinesCopied = abs(pbmiSafe->bmiHeader.biHeight);
}
-
- /* Create a palette for the DIB */
- ppalDIB = CreateDIBPalette(pbmi, pdc, dwUsage);
- if (!ppalDIB)
+ else
{
- bResult = FALSE;
- goto cleanup;
+ LinesCopied = pbmiSafe->bmiHeader.biHeight;
}
- /* Prepare DC for blit */
- DC_vPrepareDCsForBlit(pdc, &rcDst, NULL, NULL);
-
- psurfDst = pdc->dclevel.pSurface;
-
- /* Initialize XLATEOBJ */
- EXLATEOBJ_vInitialize(&exlo,
- ppalDIB,
- psurfDst->ppal,
- RGB(0xff, 0xff, 0xff),
- pdc->pdcattr->crBackgroundClr,
- pdc->pdcattr->crForegroundClr);
-
- /* Perform the stretch operation */
- bResult = IntEngStretchBlt(&psurfDst->SurfObj,
- &psurfTmp->SurfObj,
- NULL,
- (CLIPOBJ *)&pdc->co,
- &exlo.xlo,
- &pdc->dclevel.ca,
- &rcDst,
- &rcSrc,
- NULL,
- &pdc->eboFill.BrushObject,
- NULL,
- WIN32_ROP3_TO_ENG_ROP4(dwRop));
-
- /* Cleanup */
- DC_vFinishBlit(pdc, NULL);
- EXLATEOBJ_vCleanup(&exlo);
-cleanup:
- if (ppalDIB) PALETTE_ShareUnlockPalette(ppalDIB);
- if (psurfTmp) SURFACE_ShareUnlockSurface(psurfTmp);
- if (hbmTmp) GreDeleteObject(hbmTmp);
- if (pdc) DC_UnlockDc(pdc);
- if (pvBits) ExFreePoolWithTag(pvBits, 'pmeT');
-
- return bResult;
+ return LinesCopied;
}
@@ -1533,7 +1656,7 @@ NtGdiCreateDIBitmapInternal(
{
Status = _SEH2_GetExceptionCode();
}
- _SEH2_END
+ _SEH2_END;
if(!NT_SUCCESS(Status))
{
@@ -1715,7 +1838,7 @@ NtGdiCreateDIBSection(
{
Status = _SEH2_GetExceptionCode();
}
- _SEH2_END
+ _SEH2_END;
if(!NT_SUCCESS(Status))
{