https://git.reactos.org/?p=reactos.git;a=commitdiff;h=847b037fe98ec14bdcea2cd9c3d356fecaa895cc

commit 847b037fe98ec14bdcea2cd9c3d356fecaa895cc
Author:     Doug Lyons <[email protected]>
AuthorDate: Fri Jul 2 17:34:43 2021 -0500
Commit:     GitHub <[email protected]>
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))
     {

Reply via email to