- partial rewrite of NtGdiGetDIBitsInternal

- wrap all usermode read/writes in seh
- make it more compatible with XP. We now pass all current GetDIBits tests and win32k tests

svn path=/trunk/; revision=29326
This commit is contained in:
Ged Murphy 2007-10-01 11:53:31 +00:00
parent 82a49a076e
commit ecf21c9be9
2 changed files with 185 additions and 122 deletions

View file

@ -435,6 +435,7 @@ NtGdiSetDIBitsToDeviceInternal(
return ret; return ret;
} }
/* Converts a device-dependent bitmap to a DIB */ /* Converts a device-dependent bitmap to a DIB */
INT STDCALL INT STDCALL
NtGdiGetDIBitsInternal(HDC hDC, NtGdiGetDIBitsInternal(HDC hDC,
@ -447,67 +448,63 @@ NtGdiGetDIBitsInternal(HDC hDC,
UINT MaxBits, UINT MaxBits,
UINT MaxInfo) UINT MaxInfo)
{ {
BITMAPOBJ *BitmapObj;
SURFOBJ *DestSurfObj;
XLATEOBJ *XlateObj;
HBITMAP DestBitmap;
SIZEL DestSize;
HPALETTE hSourcePalette;
HPALETTE hDestPalette;
PPALGDI SourcePalette;
PPALGDI DestPalette;
ULONG SourcePaletteType;
ULONG DestPaletteType;
PDC Dc; PDC Dc;
POINTL SourcePoint; BITMAPOBJ *BitmapObj = NULL;
RECTL DestRect; HBITMAP hDestBitmap = NULL;
HPALETTE hSourcePalette = NULL;
HPALETTE hDestPalette = NULL;
PPALGDI SourcePalette = NULL;
PPALGDI DestPalette = NULL;
NTSTATUS Status = STATUS_SUCCESS;
ULONG Result = 0; ULONG Result = 0;
ULONG Index; BOOL bPaletteMatch = FALSE;
DPRINT("Entered NtGdiGetDIBitsInternal()\n");
/* Get handle for the palette in DC. */ /* Get handle for the palette in DC. */
Dc = DC_LockDc(hDC); Dc = DC_LockDc(hDC);
if (Dc == NULL) if (Dc == NULL) return 0;
{
SetLastWin32Error(ERROR_INVALID_HANDLE);
return 0;
}
if (Dc->IsIC) if (Dc->IsIC)
{ {
DC_UnlockDc(Dc); DC_UnlockDc(Dc);
return 0; return 0;
} }
/* Source palette obtained from the windows hdc */
hSourcePalette = Dc->w.hPalette; hSourcePalette = Dc->w.hPalette;
hDestPalette = Dc->w.hPalette; // unsure of this (Ged)
DC_UnlockDc(Dc); DC_UnlockDc(Dc);
/* Get pointer to the source bitmap object. */ /* don't do anything if we fail this */
if (Usage != DIB_RGB_COLORS && Usage != DIB_PAL_COLORS)
return 0;
/* Get a pointer to the source bitmap object */
BitmapObj = BITMAPOBJ_LockBitmap(hBitmap); BitmapObj = BITMAPOBJ_LockBitmap(hBitmap);
if (BitmapObj == NULL) if (BitmapObj == NULL)
{
SetLastWin32Error(ERROR_INVALID_HANDLE);
return 0; return 0;
}
/* fill out the BITMAPINFO struct */
if (Bits == NULL) if (Bits == NULL)
{
_SEH_TRY
{ {
if (Info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) if (Info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
{ {
ProbeForWrite(Info, sizeof(BITMAPINFO), 1);
BITMAPCOREHEADER* coreheader = (BITMAPCOREHEADER*) Info; BITMAPCOREHEADER* coreheader = (BITMAPCOREHEADER*) Info;
coreheader->bcWidth =BitmapObj->SurfObj.sizlBitmap.cx; coreheader->bcWidth =BitmapObj->SurfObj.sizlBitmap.cx;
coreheader->bcPlanes = 1; coreheader->bcPlanes = 1;
coreheader->bcBitCount = BitsPerFormat(BitmapObj->SurfObj.iBitmapFormat); coreheader->bcBitCount = BitsPerFormat(BitmapObj->SurfObj.iBitmapFormat);
coreheader->bcHeight = BitmapObj->SurfObj.sizlBitmap.cy; coreheader->bcHeight = BitmapObj->SurfObj.sizlBitmap.cy;
if (BitmapObj->SurfObj.lDelta > 0) if (BitmapObj->SurfObj.lDelta > 0)
coreheader->bcHeight = -coreheader->bcHeight; coreheader->bcHeight = -coreheader->bcHeight;
Result = BitmapObj->SurfObj.sizlBitmap.cy;
} }
if (Info->bmiHeader.biSize == sizeof(BITMAPINFOHEADER)) if (Info->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
{ {
ProbeForWrite(Info, sizeof(BITMAPINFO), 1);
Info->bmiHeader.biWidth = BitmapObj->SurfObj.sizlBitmap.cx; Info->bmiHeader.biWidth = BitmapObj->SurfObj.sizlBitmap.cx;
Info->bmiHeader.biHeight = BitmapObj->SurfObj.sizlBitmap.cy; Info->bmiHeader.biHeight = BitmapObj->SurfObj.sizlBitmap.cy;
/* Report negtive height for top-down bitmaps. */ /* Report negtive height for top-down bitmaps. */
@ -546,57 +543,39 @@ NtGdiGetDIBitsInternal(HDC hDC,
Info->bmiHeader.biYPelsPerMeter = 0; /* FIXME */ Info->bmiHeader.biYPelsPerMeter = 0; /* FIXME */
Info->bmiHeader.biClrUsed = 0; Info->bmiHeader.biClrUsed = 0;
Info->bmiHeader.biClrImportant = 1 << Info->bmiHeader.biBitCount; /* FIXME */ Info->bmiHeader.biClrImportant = 1 << Info->bmiHeader.biBitCount; /* FIXME */
}
}
}
_SEH_HANDLE
{
Status = _SEH_GetExceptionCode();
}
_SEH_END
if (NT_SUCCESS(Status))
{
Result = BitmapObj->SurfObj.sizlBitmap.cy; Result = BitmapObj->SurfObj.sizlBitmap.cy;
} }
} }
}
else else
{ {
if (StartScan > BitmapObj->SurfObj.sizlBitmap.cy) SIZEL DestSize;
ULONG SourcePaletteType = 0;
ULONG DestPaletteType;
POINTL SourcePoint;
ULONG Index;
_SEH_TRY
{ {
Result = 0; ProbeForRead(Info, sizeof(BITMAPINFO), 1);
if (Info->bmiHeader.biBitCount == BitsPerFormat(BitmapObj->SurfObj.iBitmapFormat))
{
hDestPalette = hSourcePalette;
bPaletteMatch = TRUE;
} }
else else
{ hDestPalette = BuildDIBPalette(Info, (PINT)&DestPaletteType); //hDestPalette = Dc->DevInfo->hpalDefault;
ScanLines = min(ScanLines, BitmapObj->SurfObj.sizlBitmap.cy - StartScan);
DestSize.cx = BitmapObj->SurfObj.sizlBitmap.cx;
DestSize.cy = ScanLines;
DestBitmap = NULL;
if (Info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
{
BITMAPCOREHEADER* coreheader = (BITMAPCOREHEADER*) Info;
DestBitmap = EngCreateBitmap(DestSize,
DIB_GetDIBWidthBytes(DestSize.cx, coreheader->bcBitCount),
BitmapFormat(coreheader->bcBitCount, BI_RGB),
0 < coreheader->bcHeight ? 0 : BMF_TOPDOWN,
Bits);
}
if (Info->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
{
INT one, two, three;
one = DIB_GetDIBWidthBytes(DestSize.cx, Info->bmiHeader.biBitCount),
two = ((DestSize.cx * Info->bmiHeader.biBitCount + 31) & ~31) >> 3;
three = DestSize.cx * (Info->bmiHeader.biBitCount >> 3);
DestBitmap = EngCreateBitmap(DestSize,
/* DIB_GetDIBWidthBytes(DestSize.cx, Info->bmiHeader.biBitCount), */
DestSize.cx * (Info->bmiHeader.biBitCount >> 3), /* HACK */
BitmapFormat(Info->bmiHeader.biBitCount, Info->bmiHeader.biCompression),
0 < Info->bmiHeader.biHeight ? 0 : BMF_TOPDOWN,
Bits);
}
if(DestBitmap == NULL)
{
BITMAPOBJ_UnlockBitmap(BitmapObj);
return 0;
}
DestSurfObj = EngLockSurface((HSURF)DestBitmap);
SourcePalette = PALETTE_LockPalette(hSourcePalette); SourcePalette = PALETTE_LockPalette(hSourcePalette);
/* FIXME - SourcePalette can be NULL!!! Don't assert here! */ /* FIXME - SourcePalette can be NULL!!! Don't assert here! */
@ -604,10 +583,18 @@ NtGdiGetDIBitsInternal(HDC hDC,
SourcePaletteType = SourcePalette->Mode; SourcePaletteType = SourcePalette->Mode;
PALETTE_UnlockPalette(SourcePalette); PALETTE_UnlockPalette(SourcePalette);
if (bPaletteMatch)
{
DestPalette = PALETTE_LockPalette(hDestPalette); DestPalette = PALETTE_LockPalette(hDestPalette);
/* FIXME - DestPalette can be NULL!!!! Don't assert here!!! */ /* FIXME - DestPalette can be NULL!!!! Don't assert here!!! */
//ASSERT(DestPalette); DPRINT1("DestPalette : %p\n", DestPalette);
ASSERT(DestPalette);
DestPaletteType = DestPalette->Mode; DestPaletteType = DestPalette->Mode;
}
else
{
DestPalette = SourcePalette;
}
/* Copy palette. */ /* Copy palette. */
/* FIXME: This is largely incomplete. */ /* FIXME: This is largely incomplete. */
@ -631,9 +618,65 @@ NtGdiGetDIBitsInternal(HDC hDC,
} }
} }
if (bPaletteMatch)
PALETTE_UnlockPalette(DestPalette); PALETTE_UnlockPalette(DestPalette);
XlateObj = IntEngCreateXlate(DestPaletteType, SourcePaletteType, hDestPalette, hSourcePalette); /* Create the destination bitmap to for the copy operation */
if (StartScan > BitmapObj->SurfObj.sizlBitmap.cy)
{
_SEH_YIELD(goto cleanup);
}
else
{
ScanLines = min(ScanLines, BitmapObj->SurfObj.sizlBitmap.cy - StartScan);
DestSize.cx = BitmapObj->SurfObj.sizlBitmap.cx;
DestSize.cy = ScanLines;
hDestBitmap = NULL;
ProbeForWrite(Bits, sizeof(BitmapObj->SurfObj.cjBits), 1);
if (Info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
{
BITMAPCOREHEADER* coreheader = (BITMAPCOREHEADER*) Info;
hDestBitmap = EngCreateBitmap(DestSize,
DIB_GetDIBWidthBytes(DestSize.cx, coreheader->bcBitCount),
BitmapFormat(coreheader->bcBitCount, BI_RGB),
0 < coreheader->bcHeight ? 0 : BMF_TOPDOWN,
Bits);
}
if (Info->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
{
hDestBitmap = EngCreateBitmap(DestSize,
/* DIB_GetDIBWidthBytes(DestSize.cx, Info->bmiHeader.biBitCount), */
DestSize.cx * (Info->bmiHeader.biBitCount >> 3), /* HACK */
BitmapFormat(Info->bmiHeader.biBitCount, Info->bmiHeader.biCompression),
0 < Info->bmiHeader.biHeight ? 0 : BMF_TOPDOWN,
Bits);
}
if (hDestBitmap == NULL)
_SEH_YIELD(goto cleanup);
}
}
_SEH_HANDLE
{
Status = _SEH_GetExceptionCode();
}
_SEH_END
if (NT_SUCCESS(Status))
{
XLATEOBJ *XlateObj;
SURFOBJ *DestSurfObj;
RECTL DestRect;
XlateObj = IntEngCreateXlate(DestPaletteType,
SourcePaletteType,
hDestPalette,
hSourcePalette);
SourcePoint.x = 0; SourcePoint.x = 0;
SourcePoint.y = BitmapObj->SurfObj.sizlBitmap.cy - (StartScan + ScanLines); SourcePoint.y = BitmapObj->SurfObj.sizlBitmap.cy - (StartScan + ScanLines);
@ -644,6 +687,8 @@ NtGdiGetDIBitsInternal(HDC hDC,
DestRect.right = DestSize.cx; DestRect.right = DestSize.cx;
DestRect.bottom = DestSize.cy; DestRect.bottom = DestSize.cy;
DestSurfObj = EngLockSurface((HSURF)hDestBitmap);
if (EngCopyBits(DestSurfObj, if (EngCopyBits(DestSurfObj,
&BitmapObj->SurfObj, &BitmapObj->SurfObj,
NULL, NULL,
@ -659,8 +704,17 @@ NtGdiGetDIBitsInternal(HDC hDC,
} }
} }
cleanup:
if (hDestBitmap != NULL)
EngDeleteSurface((HSURF)hDestBitmap);
if (hDestPalette != NULL && bPaletteMatch == FALSE)
PALETTE_FreePalette(hDestPalette);
BITMAPOBJ_UnlockBitmap(BitmapObj); BITMAPOBJ_UnlockBitmap(BitmapObj);
DPRINT("leaving NtGdiGetDIBitsInternal\n");
return Result; return Result;
} }
@ -1318,14 +1372,18 @@ BuildDIBPalette (CONST BITMAPINFO *bmi, PINT paletteType)
// Determine Bits Per Pixel // Determine Bits Per Pixel
bits = bmi->bmiHeader.biBitCount; bits = bmi->bmiHeader.biBitCount;
//DPRINT1("%d bits\n", bits);
// Determine paletteType from Bits Per Pixel // Determine paletteType from Bits Per Pixel
if (bits <= 8) if (bits <= 8)
{ {
//DPRINT1("8\n");
*paletteType = PAL_INDEXED; *paletteType = PAL_INDEXED;
RedMask = GreenMask = BlueMask = 0; RedMask = GreenMask = BlueMask = 0;
} }
else if(bits < 24) else if(bits < 24)
{ {
//DPRINT1("24\n");
*paletteType = PAL_BITFIELDS; *paletteType = PAL_BITFIELDS;
RedMask = 0xf800; RedMask = 0xf800;
GreenMask = 0x07e0; GreenMask = 0x07e0;
@ -1333,6 +1391,7 @@ BuildDIBPalette (CONST BITMAPINFO *bmi, PINT paletteType)
} }
else else
{ {
//DPRINT1("else\n");
*paletteType = PAL_BGR; *paletteType = PAL_BGR;
RedMask = 0xff0000; RedMask = 0xff0000;
GreenMask = 0x00ff00; GreenMask = 0x00ff00;
@ -1350,14 +1409,17 @@ BuildDIBPalette (CONST BITMAPINFO *bmi, PINT paletteType)
if (PAL_INDEXED == *paletteType) if (PAL_INDEXED == *paletteType)
{ {
//DPRINT1("in\n");
hPal = PALETTE_AllocPaletteIndexedRGB(ColorCount, (RGBQUAD*)bmi->bmiColors); hPal = PALETTE_AllocPaletteIndexedRGB(ColorCount, (RGBQUAD*)bmi->bmiColors);
} }
else else
{ {
//DPRINT1("out\n");
hPal = PALETTE_AllocPalette(*paletteType, ColorCount, hPal = PALETTE_AllocPalette(*paletteType, ColorCount,
(ULONG*) palEntries, (ULONG*) palEntries,
RedMask, GreenMask, BlueMask ); RedMask, GreenMask, BlueMask );
} }
//DPRINT1("returning %p\n", hPal);
return hPal; return hPal;
} }

View file

@ -1031,7 +1031,8 @@ GDIOBJ_UnlockObjByPtr(PGDI_HANDLE_TABLE HandleTable, PGDIOBJ Object)
GdiHdr->lockline = 0; GdiHdr->lockline = 0;
} }
#else #else
InterlockedDecrement((PLONG)&GdiHdr->Locks); if (InterlockedDecrement((PLONG)&GdiHdr->Locks) < 0)
DPRINT1("Trying to unlock non-existant object\n");
#endif #endif
} }