diff --git a/win32ss/gdi/ntgdi/dibobj.c b/win32ss/gdi/ntgdi/dibobj.c index acd8da28d2..5e30d974f4 100644 --- a/win32ss/gdi/ntgdi/dibobj.c +++ b/win32ss/gdi/ntgdi/dibobj.c @@ -1212,7 +1212,6 @@ NtGdiStretchDIBitsInternal( IN UINT cjMaxBits, IN HANDLE hcmXform) { - BOOL bResult = FALSE; SIZEL sizel; RECTL rcSrc, rcDst; PDC pdc; @@ -1220,7 +1219,16 @@ NtGdiStretchDIBitsInternal( PSURFACE psurfTmp = 0, psurfDst = 0; PPALETTE ppalDIB = 0; EXLATEOBJ exlo; - PVOID pvBits; + + HBITMAP hBitmap, hOldBitmap = NULL; + HDC hdcMem; + HPALETTE hPal = NULL; + PBYTE safeBits; + LONG height; + LONG width; + WORD planes, bpp; + DWORD compr, size; + INT LinesCopied = 0; if (!(pdc = DC_LockDc(hdc))) { @@ -1236,153 +1244,249 @@ NtGdiStretchDIBitsInternal( return TRUE; } + if (!pbmi) + { + EngSetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + + /* Check for ability to READ pbmi */ + _SEH2_TRY + { + ProbeForRead(pbmi, cjMaxInfo, 1); + if (DIB_GetBitmapInfo(&pbmi->bmiHeader, &width, &height, &planes, +&bpp, &compr, &size) == -1) + { + DPRINT1("Invalid bitmap\n"); + _SEH2_YIELD(goto cleanup;) + } + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + DPRINT1("Error, failed to read the DIB bits\n"); + EngSetLastError(ERROR_INVALID_PARAMETER); + _SEH2_YIELD(goto cleanup;) + } + _SEH2_END + /* Transform dest size */ sizel.cx = cxDst; sizel.cy = cyDst; 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); - } - + /* Handle pjInit as Optional parameter */ if (pjInit && (cjMaxBits > 0)) { - pvBits = ExAllocatePoolWithTag(PagedPool, cjMaxBits, 'pmeT'); - if (!pvBits) + safeBits = ExAllocatePoolWithTag(PagedPool, cjMaxBits, TAG_DIB); + if(!safeBits) { + EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); return 0; } _SEH2_TRY { - ProbeForRead(pjInit, cjMaxBits, 1); - RtlCopyMemory(pvBits, pjInit, cjMaxBits); + RtlCopyMemory(safeBits, pjInit, cjMaxBits); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { - ExFreePoolWithTag(pvBits, 'pmeT'); + ExFreePoolWithTag(safeBits, TAG_DIB); _SEH2_YIELD(return 0); } _SEH2_END } else { - pvBits = NULL; + safeBits = NULL; } - /* FIXME: Locking twice is cheesy, coord tranlation in UM will fix it */ - if (!(pdc = DC_LockDc(hdc))) + + /* Here we have the old patch with SIMS good versus gdi32:bitmap good */ + 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(pbmi->bmiHeader.biWidth), + abs(pbmi->bmiHeader.biHeight)); + if (hBitmap == NULL) + { + DPRINT1("NtGdiCreateCompatibleBitmap failed to create bitmap.\n"); + DPRINT1("hdc : 0x%08x \n", hdc); + DPRINT1("pbmi->bmiHeader.biWidth : 0x%08x \n", pbmi->bmiHeader.biWidth); + DPRINT1("pbmi->bmiHeader.biHeight : 0x%08x \n", pbmi->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; - } + if (pbmi->bmiHeader.biCompression == BI_RLE4 || + pbmi->bmiHeader.biCompression == BI_RLE8) + { + /* copy existing bitmap from destination dc */ + if (cxSrc == cyDst && cySrc == cyDst) + NtGdiBitBlt(hdcMem, xSrc, abs(pbmi->bmiHeader.biHeight) - cySrc - ySrc, + cxSrc, cySrc, hdc, xDst, yDst, dwRop, 0, 0); + else + NtGdiStretchBlt(hdcMem, xSrc, abs(pbmi->bmiHeader.biHeight) - cySrc - ySrc, + cxSrc, cySrc, hdc, xDst, yDst, cxDst, cyDst, + dwRop, 0); + } - psurfTmp = SURFACE_ShareLockSurface(hbmTmp); - if (!psurfTmp) - { - bResult = FALSE; - goto cleanup; - } + pdc = DC_LockDc(hdcMem); + if (pdc != NULL) + { + IntSetDIBits(pdc, hBitmap, 0, abs(pbmi->bmiHeader.biHeight), safeBits, + cjMaxBits, pbmi, dwUsage); - /* Create a palette for the DIB */ - ppalDIB = CreateDIBPalette(pbmi, pdc, dwUsage); - if (!ppalDIB) - { - bResult = FALSE; - goto cleanup; - } + DC_UnlockDc(pdc); + } - /* Prepare DC for blit */ - DC_vPrepareDCsForBlit(pdc, &rcDst, NULL, NULL); + /* 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(pbmi->bmiHeader.biHeight) - cySrc - ySrc, + dwRop, 0, 0); + else + NtGdiStretchBlt(hdc, xDst, yDst, cxDst, cyDst, + hdcMem, xSrc, abs(pbmi->bmiHeader.biHeight) - cySrc - ySrc, + cxSrc, cySrc, dwRop, 0); - psurfDst = pdc->dclevel.pSurface; + /* cleanup */ + if (hPal) + GdiSelectPalette(hdcMem, hPal, FALSE); - /* 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'); + 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); + } + + 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, + safeBits, + 0); + + if (!hbmTmp) + { + goto cleanup; + } + + psurfTmp = SURFACE_ShareLockSurface(hbmTmp); + if (!psurfTmp) + { + + goto cleanup; + } + + /* Create a palette for the DIB */ + ppalDIB = CreateDIBPalette(pbmi, 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); + if (safeBits) ExFreePoolWithTag(safeBits, 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 */ + if (dwRop == SRCCOPY) + LinesCopied = abs(pbmi->bmiHeader.biHeight); + else + LinesCopied = pbmi->bmiHeader.biHeight; + + if (cySrc < 0) LinesCopied = 0; + LinesCopied = min(max(abs(cyDst), abs(cySrc)), LinesCopied); - return bResult; + return LinesCopied; }