mirror of
https://github.com/reactos/reactos.git
synced 2025-06-04 08:50:27 +00:00
[WIN32K]
- Improve the "infamous RLE hack" in SetDIBitsToDevice by using a mask bitmap corresponding to the valid RLE data [GDI32] - Improve some input checks svn path=/trunk/; revision=63920
This commit is contained in:
parent
ea6842d69a
commit
ec5927ad19
3 changed files with 178 additions and 7 deletions
|
@ -671,8 +671,7 @@ SetDIBitsToDevice(
|
|||
if (ColorUse && ColorUse != DIB_PAL_COLORS && ColorUse != DIB_PAL_COLORS + 1)
|
||||
return 0;
|
||||
|
||||
pConvertedInfo = ConvertBitmapInfo(lpbmi, ColorUse, &ConvertedInfoSize,
|
||||
FALSE);
|
||||
pConvertedInfo = ConvertBitmapInfo(lpbmi, ColorUse, &ConvertedInfoSize, FALSE);
|
||||
if (!pConvertedInfo)
|
||||
return 0;
|
||||
|
||||
|
@ -720,6 +719,15 @@ SetDIBitsToDevice(
|
|||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((pConvertedInfo->bmiHeader.biCompression == BI_RLE8) ||
|
||||
(pConvertedInfo->bmiHeader.biCompression == BI_RLE4))
|
||||
{
|
||||
/* For compressed data, we must set the whole thing */
|
||||
StartScan = 0;
|
||||
ScanLines = pConvertedInfo->bmiHeader.biHeight;
|
||||
}
|
||||
|
||||
cjBmpScanSize = DIB_BitmapMaxBitsSize((LPBITMAPINFO) lpbmi, ScanLines);
|
||||
|
||||
pvSafeBits = RtlAllocateHeap(GetProcessHeap(), 0, cjBmpScanSize);
|
||||
|
|
|
@ -296,6 +296,35 @@ ConvertBitmapInfo(
|
|||
RtlCopyMemory((PVOID)NewDataPtr, (PVOID)OldDataPtr, DataSize);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Verify some data validity */
|
||||
switch (BitmapInfo->bmiHeader.biCompression)
|
||||
{
|
||||
case BI_RLE8:
|
||||
if (BitmapInfo->bmiHeader.biBitCount != 8)
|
||||
return NULL;
|
||||
if (BitmapInfo->bmiHeader.biHeight < 0)
|
||||
return NULL;
|
||||
break;
|
||||
case BI_RLE4:
|
||||
if (BitmapInfo->bmiHeader.biBitCount != 4)
|
||||
return NULL;
|
||||
if (BitmapInfo->bmiHeader.biHeight < 0)
|
||||
return NULL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Non "standard" formats must have a valid size set */
|
||||
if ((BitmapInfo->bmiHeader.biCompression != BI_RGB) &&
|
||||
(BitmapInfo->bmiHeader.biCompression != BI_BITFIELDS))
|
||||
{
|
||||
if (BitmapInfo->bmiHeader.biSizeImage == 0)
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Size = NewBitmapInfo->bmiHeader.biSize;
|
||||
if (ColorSpec == DIB_RGB_COLORS)
|
||||
|
|
|
@ -375,6 +375,115 @@ cleanup:
|
|||
return result;
|
||||
}
|
||||
|
||||
static
|
||||
HBITMAP
|
||||
IntGdiCreateMaskFromRLE(
|
||||
DWORD Width,
|
||||
DWORD Height,
|
||||
ULONG Compression,
|
||||
const BYTE* Bits,
|
||||
DWORD BitsSize)
|
||||
{
|
||||
HBITMAP Mask;
|
||||
DWORD x, y;
|
||||
SURFOBJ* SurfObj;
|
||||
UINT i = 0;
|
||||
BYTE Data, NumPixels, ToSkip;
|
||||
|
||||
ASSERT((Compression == BI_RLE8) || (Compression == BI_RLE4));
|
||||
|
||||
/* Create the bitmap */
|
||||
Mask = GreCreateBitmapEx(Width, Height, 0, BMF_1BPP, 0, 0, NULL, 0);
|
||||
if (!Mask)
|
||||
return NULL;
|
||||
|
||||
SurfObj = EngLockSurface((HSURF)Mask);
|
||||
if (!SurfObj)
|
||||
{
|
||||
GreDeleteObject(Mask);
|
||||
return NULL;
|
||||
}
|
||||
ASSERT(SurfObj->pvBits != NULL);
|
||||
|
||||
x = y = 0;
|
||||
|
||||
while (i < BitsSize)
|
||||
{
|
||||
NumPixels = Bits[i];
|
||||
Data = Bits[i + 1];
|
||||
i += 2;
|
||||
|
||||
if (NumPixels != 0)
|
||||
{
|
||||
if ((x + NumPixels) > Width)
|
||||
NumPixels = Width - x;
|
||||
|
||||
if (NumPixels == 0)
|
||||
continue;
|
||||
|
||||
DIB_1BPP_HLine(SurfObj, x, x + NumPixels, y, 1);
|
||||
x += NumPixels;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Data < 3)
|
||||
{
|
||||
switch (Data)
|
||||
{
|
||||
case 0:
|
||||
/* End of line */
|
||||
y++;
|
||||
if (y == Height)
|
||||
goto done;
|
||||
x = 0;
|
||||
break;
|
||||
case 1:
|
||||
/* End of file */
|
||||
goto done;
|
||||
case 2:
|
||||
/* Jump */
|
||||
if (i >= (BitsSize - 1))
|
||||
goto done;
|
||||
x += Bits[i];
|
||||
if (x > Width)
|
||||
x = Width;
|
||||
y += Bits[i + 1];
|
||||
if (y >= Height)
|
||||
goto done;
|
||||
i += 2;
|
||||
break;
|
||||
}
|
||||
/* Done for this run */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Embedded data into the RLE */
|
||||
NumPixels = Data;
|
||||
if (Compression == BI_RLE8)
|
||||
ToSkip = NumPixels;
|
||||
else
|
||||
ToSkip = (NumPixels / 2) + (NumPixels & 1);
|
||||
|
||||
if ((i + ToSkip) > BitsSize)
|
||||
goto done;
|
||||
ToSkip = (ToSkip + 1) & ~1;
|
||||
|
||||
if ((x + NumPixels) > Width)
|
||||
NumPixels = Width - x;
|
||||
|
||||
if (NumPixels != 0)
|
||||
{
|
||||
DIB_1BPP_HLine(SurfObj, x, x + NumPixels, y, 1);
|
||||
x += NumPixels;
|
||||
}
|
||||
i += ToSkip;
|
||||
}
|
||||
|
||||
done:
|
||||
EngUnlockSurface(SurfObj);
|
||||
return Mask;
|
||||
}
|
||||
|
||||
W32KAPI
|
||||
INT
|
||||
APIENTRY
|
||||
|
@ -399,8 +508,8 @@ NtGdiSetDIBitsToDeviceInternal(
|
|||
INT ret = 0;
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
PDC pDC;
|
||||
HBITMAP hSourceBitmap = NULL;
|
||||
SURFOBJ *pDestSurf, *pSourceSurf = NULL;
|
||||
HBITMAP hSourceBitmap = NULL, hMaskBitmap = NULL;
|
||||
SURFOBJ *pDestSurf, *pSourceSurf = NULL, *pMaskSurf = NULL;
|
||||
SURFACE *pSurf;
|
||||
RECTL rcDest;
|
||||
POINTL ptSource;
|
||||
|
@ -492,6 +601,29 @@ NtGdiSetDIBitsToDeviceInternal(
|
|||
goto Exit;
|
||||
}
|
||||
|
||||
/* HACK: If this is a RLE bitmap, only the relevant pixels must be set. */
|
||||
if ((bmi->bmiHeader.biCompression == BI_RLE8) || (bmi->bmiHeader.biCompression == BI_RLE4))
|
||||
{
|
||||
ASSERT(ScanLines == bmi->bmiHeader.biHeight);
|
||||
hMaskBitmap = IntGdiCreateMaskFromRLE(bmi->bmiHeader.biWidth,
|
||||
ScanLines,
|
||||
bmi->bmiHeader.biCompression,
|
||||
Bits,
|
||||
cjMaxBits);
|
||||
if (!hMaskBitmap)
|
||||
{
|
||||
EngSetLastError(ERROR_NO_SYSTEM_RESOURCES);
|
||||
Status = STATUS_NO_MEMORY;
|
||||
goto Exit;
|
||||
}
|
||||
pMaskSurf = EngLockSurface((HSURF)hMaskBitmap);
|
||||
if (!pMaskSurf)
|
||||
{
|
||||
Status = STATUS_UNSUCCESSFUL;
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create a palette for the DIB */
|
||||
ppalDIB = CreateDIBPalette(bmi, pDC, ColorUse);
|
||||
if (!ppalDIB)
|
||||
|
@ -529,15 +661,15 @@ NtGdiSetDIBitsToDeviceInternal(
|
|||
ptSource.x, ptSource.y, SourceSize.cx, SourceSize.cy);
|
||||
Status = IntEngBitBlt(pDestSurf,
|
||||
pSourceSurf,
|
||||
NULL,
|
||||
pMaskSurf,
|
||||
&pDC->co.ClipObj,
|
||||
&exlo.xlo,
|
||||
&rcDest,
|
||||
&ptSource,
|
||||
pMaskSurf ? &ptSource : NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
ROP4_FROM_INDEX(R3_OPINDEX_SRCCOPY));
|
||||
pMaskSurf ? ROP4_MASK : ROP4_FROM_INDEX(R3_OPINDEX_SRCCOPY));
|
||||
|
||||
/* Cleanup EXLATEOBJ */
|
||||
EXLATEOBJ_vCleanup(&exlo);
|
||||
|
@ -555,6 +687,8 @@ Exit:
|
|||
|
||||
if (pSourceSurf) EngUnlockSurface(pSourceSurf);
|
||||
if (hSourceBitmap) EngDeleteSurface((HSURF)hSourceBitmap);
|
||||
if (pMaskSurf) EngUnlockSurface(pMaskSurf);
|
||||
if (hMaskBitmap) EngDeleteSurface((HSURF)hMaskBitmap);
|
||||
DC_UnlockDc(pDC);
|
||||
Exit2:
|
||||
ExFreePoolWithTag(pbmiSafe, 'pmTG');
|
||||
|
|
Loading…
Reference in a new issue