reactos/subsystems/win32/win32k/objects/brush.c
Jérôme Gardou 421a63ff44 [WIN32K]
- Get rid of hDIBPalette in SURFACE structure
This allows more code cleanness

svn path=/branches/reactos-yarotows/; revision=47190
2010-05-12 22:56:24 +00:00

723 lines
18 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS win32 subsystem
* PURPOSE: Functions for brushes
* FILE: subsystem/win32/win32k/objects/brush.c
* PROGRAMER:
*/
#include <win32k.h>
#define NDEBUG
#include <debug.h>
#define GDIOBJATTRFREE 170
typedef struct _GDI_OBJ_ATTR_FREELIST
{
LIST_ENTRY Entry;
DWORD nEntries;
PVOID AttrList[GDIOBJATTRFREE];
} GDI_OBJ_ATTR_FREELIST, *PGDI_OBJ_ATTR_FREELIST;
typedef struct _GDI_OBJ_ATTR_ENTRY
{
RGN_ATTR Attr[GDIOBJATTRFREE];
} GDI_OBJ_ATTR_ENTRY, *PGDI_OBJ_ATTR_ENTRY;
static const USHORT HatchBrushes[NB_HATCH_STYLES][8] =
{
{0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF}, /* HS_HORIZONTAL */
{0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7}, /* HS_VERTICAL */
{0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F}, /* HS_FDIAGONAL */
{0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0xFE}, /* HS_BDIAGONAL */
{0xF7, 0xF7, 0xF7, 0xF7, 0x00, 0xF7, 0xF7, 0xF7}, /* HS_CROSS */
{0x7E, 0xBD, 0xDB, 0xE7, 0xE7, 0xDB, 0xBD, 0x7E} /* HS_DIAGCROSS */
};
PVOID
FASTCALL
AllocateObjectAttr(VOID)
{
PTHREADINFO pti;
PPROCESSINFO ppi;
PVOID pAttr;
PGDI_OBJ_ATTR_FREELIST pGdiObjAttrFreeList;
PGDI_OBJ_ATTR_ENTRY pGdiObjAttrEntry;
int i;
pti = PsGetCurrentThreadWin32Thread();
if (pti->pgdiBrushAttr)
{
pAttr = pti->pgdiBrushAttr; // Get the free one.
pti->pgdiBrushAttr = NULL;
return pAttr;
}
ppi = PsGetCurrentProcessWin32Process();
if (!ppi->pBrushAttrList) // If set point is null, allocate new group.
{
pGdiObjAttrEntry = EngAllocUserMem(sizeof(GDI_OBJ_ATTR_ENTRY), 0);
if (!pGdiObjAttrEntry)
{
DPRINT1("Attr Failed User Allocation!\n");
return NULL;
}
DPRINT("AllocObjectAttr User 0x%x\n",pGdiObjAttrEntry);
pGdiObjAttrFreeList = ExAllocatePoolWithTag( PagedPool,
sizeof(GDI_OBJ_ATTR_FREELIST),
GDITAG_BRUSH_FREELIST);
if ( !pGdiObjAttrFreeList )
{
EngFreeUserMem(pGdiObjAttrEntry);
return NULL;
}
RtlZeroMemory(pGdiObjAttrFreeList, sizeof(GDI_OBJ_ATTR_FREELIST));
DPRINT("AllocObjectAttr Ex 0x%x\n",pGdiObjAttrFreeList);
InsertHeadList( &ppi->GDIBrushAttrFreeList, &pGdiObjAttrFreeList->Entry);
pGdiObjAttrFreeList->nEntries = GDIOBJATTRFREE;
// Start at the bottom up and set end of free list point.
ppi->pBrushAttrList = &pGdiObjAttrEntry->Attr[GDIOBJATTRFREE-1];
// Build the free attr list.
for ( i = 0; i < GDIOBJATTRFREE; i++)
{
pGdiObjAttrFreeList->AttrList[i] = &pGdiObjAttrEntry->Attr[i];
}
}
pAttr = ppi->pBrushAttrList;
pGdiObjAttrFreeList = (PGDI_OBJ_ATTR_FREELIST)ppi->GDIBrushAttrFreeList.Flink;
// Free the list when it is full!
if ( pGdiObjAttrFreeList->nEntries-- == 1)
{ // No more free entries, so yank the list.
RemoveEntryList( &pGdiObjAttrFreeList->Entry );
ExFreePoolWithTag( pGdiObjAttrFreeList, GDITAG_BRUSH_FREELIST );
if ( IsListEmpty( &ppi->GDIBrushAttrFreeList ) )
{
ppi->pBrushAttrList = NULL;
return pAttr;
}
pGdiObjAttrFreeList = (PGDI_OBJ_ATTR_FREELIST)ppi->GDIBrushAttrFreeList.Flink;
}
ppi->pBrushAttrList = pGdiObjAttrFreeList->AttrList[pGdiObjAttrFreeList->nEntries-1];
return pAttr;
}
VOID
FASTCALL
FreeObjectAttr(PVOID pAttr)
{
PTHREADINFO pti;
PPROCESSINFO ppi;
PGDI_OBJ_ATTR_FREELIST pGdiObjAttrFreeList;
pti = PsGetCurrentThreadWin32Thread();
if (!pti) return;
if (!pti->pgdiBrushAttr)
{ // If it is null, just cache it for the next time.
pti->pgdiBrushAttr = pAttr;
return;
}
ppi = PsGetCurrentProcessWin32Process();
pGdiObjAttrFreeList = (PGDI_OBJ_ATTR_FREELIST)ppi->GDIBrushAttrFreeList.Flink;
// We add to the list of free entries, so this will grows!
if ( IsListEmpty(&ppi->GDIBrushAttrFreeList) ||
pGdiObjAttrFreeList->nEntries == GDIOBJATTRFREE )
{
pGdiObjAttrFreeList = ExAllocatePoolWithTag( PagedPool,
sizeof(GDI_OBJ_ATTR_FREELIST),
GDITAG_BRUSH_FREELIST);
if ( !pGdiObjAttrFreeList )
{
return;
}
InsertHeadList( &ppi->GDIBrushAttrFreeList, &pGdiObjAttrFreeList->Entry);
pGdiObjAttrFreeList->nEntries = 0;
}
// Up count, save the entry and set end of free list point.
++pGdiObjAttrFreeList->nEntries; // Top Down...
pGdiObjAttrFreeList->AttrList[pGdiObjAttrFreeList->nEntries-1] = pAttr;
ppi->pBrushAttrList = pAttr;
return;
}
BOOL
INTERNAL_CALL
BRUSH_Cleanup(PVOID ObjectBody)
{
PBRUSH pbrush = (PBRUSH)ObjectBody;
if (pbrush->flAttrs & (GDIBRUSH_IS_HATCH | GDIBRUSH_IS_BITMAP))
{
ASSERT(pbrush->hbmPattern);
GDIOBJ_SetOwnership(pbrush->hbmPattern, PsGetCurrentProcess());
GreDeleteObject(pbrush->hbmPattern);
}
/* Free the kmode styles array of EXTPENS */
if (pbrush->pStyle)
{
ExFreePool(pbrush->pStyle);
}
return TRUE;
}
INT
FASTCALL
BRUSH_GetObject(PBRUSH pbrush, INT Count, LPLOGBRUSH Buffer)
{
if (Buffer == NULL) return sizeof(LOGBRUSH);
if (Count == 0) return 0;
/* Set colour */
Buffer->lbColor = pbrush->BrushAttr.lbColor;
/* Set Hatch */
if ((pbrush->flAttrs & GDIBRUSH_IS_HATCH)!=0)
{
/* FIXME : this is not the right value */
Buffer->lbHatch = (LONG)pbrush->hbmPattern;
}
else
{
Buffer->lbHatch = 0;
}
Buffer->lbStyle = 0;
/* Get the type of style */
if ((pbrush->flAttrs & GDIBRUSH_IS_SOLID)!=0)
{
Buffer->lbStyle = BS_SOLID;
}
else if ((pbrush->flAttrs & GDIBRUSH_IS_NULL)!=0)
{
Buffer->lbStyle = BS_NULL; // BS_HOLLOW
}
else if ((pbrush->flAttrs & GDIBRUSH_IS_HATCH)!=0)
{
Buffer->lbStyle = BS_HATCHED;
}
else if ((pbrush->flAttrs & GDIBRUSH_IS_BITMAP)!=0)
{
Buffer->lbStyle = BS_PATTERN;
}
else if ((pbrush->flAttrs & GDIBRUSH_IS_DIB)!=0)
{
Buffer->lbStyle = BS_DIBPATTERN;
}
/* FIXME
else if ((pbrush->flAttrs & )!=0)
{
Buffer->lbStyle = BS_INDEXED;
}
else if ((pbrush->flAttrs & )!=0)
{
Buffer->lbStyle = BS_DIBPATTERNPT;
}
*/
/* FIXME */
return sizeof(LOGBRUSH);
}
/**
* @name CalculateColorTableSize
*
* Internal routine to calculate the number of color table entries.
*
* @param BitmapInfoHeader
* Input bitmap information header, can be any version of
* BITMAPINFOHEADER or BITMAPCOREHEADER.
*
* @param ColorSpec
* Pointer to variable which specifiing the color mode (DIB_RGB_COLORS
* or DIB_RGB_COLORS). On successful return this value is normalized
* according to the bitmap info.
*
* @param ColorTableSize
* On successful return this variable is filled with number of
* entries in color table for the image with specified parameters.
*
* @return
* TRUE if the input values together form a valid image, FALSE otherwise.
*/
BOOL
APIENTRY
CalculateColorTableSize(
CONST BITMAPINFOHEADER *BitmapInfoHeader,
UINT *ColorSpec,
UINT *ColorTableSize)
{
WORD BitCount;
DWORD ClrUsed;
DWORD Compression;
/*
* At first get some basic parameters from the passed BitmapInfoHeader
* structure. It can have one of the following formats:
* - BITMAPCOREHEADER (the oldest one with totally different layout
* from the others)
* - BITMAPINFOHEADER (the standard and most common header)
* - BITMAPV4HEADER (extension of BITMAPINFOHEADER)
* - BITMAPV5HEADER (extension of BITMAPV4HEADER)
*/
if (BitmapInfoHeader->biSize == sizeof(BITMAPCOREHEADER))
{
BitCount = ((LPBITMAPCOREHEADER)BitmapInfoHeader)->bcBitCount;
ClrUsed = 0;
Compression = BI_RGB;
}
else
{
BitCount = BitmapInfoHeader->biBitCount;
ClrUsed = BitmapInfoHeader->biClrUsed;
Compression = BitmapInfoHeader->biCompression;
}
switch (Compression)
{
case BI_BITFIELDS:
if (*ColorSpec == DIB_PAL_COLORS)
*ColorSpec = DIB_RGB_COLORS;
if (BitCount != 16 && BitCount != 32)
return FALSE;
/* For BITMAPV4HEADER/BITMAPV5HEADER the masks are included in
* the structure itself (bV4RedMask, bV4GreenMask, and bV4BlueMask).
* For BITMAPINFOHEADER the color masks are stored in the palette. */
if (BitmapInfoHeader->biSize > sizeof(BITMAPINFOHEADER))
*ColorTableSize = 0;
else
*ColorTableSize = 3;
return TRUE;
case BI_RGB:
switch (BitCount)
{
case 1:
*ColorTableSize = ClrUsed ? min(ClrUsed, 2) : 2;
return TRUE;
case 4:
*ColorTableSize = ClrUsed ? min(ClrUsed, 16) : 16;
return TRUE;
case 8:
*ColorTableSize = ClrUsed ? min(ClrUsed, 256) : 256;
return TRUE;
default:
if (*ColorSpec == DIB_PAL_COLORS)
*ColorSpec = DIB_RGB_COLORS;
if (BitCount != 16 && BitCount != 24 && BitCount != 32)
return FALSE;
*ColorTableSize = ClrUsed;
return TRUE;
}
case BI_RLE4:
if (BitCount == 4)
{
*ColorTableSize = ClrUsed ? min(ClrUsed, 16) : 16;
return TRUE;
}
return FALSE;
case BI_RLE8:
if (BitCount == 8)
{
*ColorTableSize = ClrUsed ? min(ClrUsed, 256) : 256;
return TRUE;
}
return FALSE;
case BI_JPEG:
case BI_PNG:
*ColorTableSize = ClrUsed;
return TRUE;
default:
return FALSE;
}
}
HBRUSH
APIENTRY
IntGdiCreateDIBBrush(
CONST BITMAPINFO *BitmapInfo,
UINT ColorSpec,
UINT BitmapInfoSize,
CONST VOID *PackedDIB)
{
HBRUSH hBrush;
PBRUSH pbrush;
HBITMAP hPattern;
ULONG_PTR DataPtr;
UINT PaletteEntryCount;
PSURFACE psurfPattern;
INT PaletteType;
HPALETTE hpal ;
if (BitmapInfo->bmiHeader.biSize < sizeof(BITMAPINFOHEADER))
{
SetLastWin32Error(ERROR_INVALID_PARAMETER);
return NULL;
}
if (!CalculateColorTableSize(&BitmapInfo->bmiHeader,
&ColorSpec,
&PaletteEntryCount))
{
SetLastWin32Error(ERROR_INVALID_PARAMETER);
return NULL;
}
// FIXME: What about BI_BITFIELDS
DataPtr = (ULONG_PTR)BitmapInfo + BitmapInfo->bmiHeader.biSize;
if (ColorSpec == DIB_RGB_COLORS)
DataPtr += PaletteEntryCount * sizeof(RGBQUAD);
else
DataPtr += PaletteEntryCount * sizeof(USHORT);
hPattern = IntGdiCreateBitmap(BitmapInfo->bmiHeader.biWidth,
BitmapInfo->bmiHeader.biHeight,
BitmapInfo->bmiHeader.biPlanes,
BitmapInfo->bmiHeader.biBitCount,
(PVOID)DataPtr);
if (hPattern == NULL)
{
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
return NULL;
}
psurfPattern = SURFACE_LockSurface(hPattern);
ASSERT(psurfPattern != NULL);
hpal = BuildDIBPalette(BitmapInfo, &PaletteType);
psurfPattern->ppal = PALETTE_ShareLockPalette(hpal);
/* Lazy delete palette, it will be freed when its shared reference is zeroed */
GreDeleteObject(hpal);
SURFACE_UnlockSurface(psurfPattern);
pbrush = BRUSH_AllocBrushWithHandle();
if (pbrush == NULL)
{
GreDeleteObject(hPattern);
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
return NULL;
}
hBrush = pbrush->BaseObject.hHmgr;
pbrush->flAttrs |= GDIBRUSH_IS_BITMAP | GDIBRUSH_IS_DIB;
pbrush->hbmPattern = hPattern;
/* FIXME: Fill in the rest of fields!!! */
GDIOBJ_SetOwnership(hPattern, NULL);
BRUSH_UnlockBrush(pbrush);
return hBrush;
}
HBRUSH
APIENTRY
IntGdiCreateHatchBrush(
INT Style,
COLORREF Color)
{
HBRUSH hBrush;
PBRUSH pbrush;
HBITMAP hPattern;
if (Style < 0 || Style >= NB_HATCH_STYLES)
{
return 0;
}
hPattern = IntGdiCreateBitmap(8, 8, 1, 1, (LPBYTE)HatchBrushes[Style]);
if (hPattern == NULL)
{
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
return NULL;
}
pbrush = BRUSH_AllocBrushWithHandle();
if (pbrush == NULL)
{
GreDeleteObject(hPattern);
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
return NULL;
}
hBrush = pbrush->BaseObject.hHmgr;
pbrush->flAttrs |= GDIBRUSH_IS_HATCH;
pbrush->hbmPattern = hPattern;
pbrush->BrushAttr.lbColor = Color & 0xFFFFFF;
GDIOBJ_SetOwnership(hPattern, NULL);
BRUSH_UnlockBrush(pbrush);
return hBrush;
}
HBRUSH
APIENTRY
IntGdiCreatePatternBrush(
HBITMAP hBitmap)
{
HBRUSH hBrush;
PBRUSH pbrush;
HBITMAP hPattern;
hPattern = BITMAP_CopyBitmap(hBitmap);
if (hPattern == NULL)
{
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
return NULL;
}
pbrush = BRUSH_AllocBrushWithHandle();
if (pbrush == NULL)
{
GreDeleteObject(hPattern);
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
return NULL;
}
hBrush = pbrush->BaseObject.hHmgr;
pbrush->flAttrs |= GDIBRUSH_IS_BITMAP;
pbrush->hbmPattern = hPattern;
/* FIXME: Fill in the rest of fields!!! */
GDIOBJ_SetOwnership(hPattern, NULL);
BRUSH_UnlockBrush(pbrush);
return hBrush;
}
HBRUSH
APIENTRY
IntGdiCreateSolidBrush(
COLORREF Color)
{
HBRUSH hBrush;
PBRUSH pbrush;
pbrush = BRUSH_AllocBrushWithHandle();
if (pbrush == NULL)
{
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
return NULL;
}
hBrush = pbrush->BaseObject.hHmgr;
pbrush->flAttrs |= GDIBRUSH_IS_SOLID;
pbrush->BrushAttr.lbColor = Color;
/* FIXME: Fill in the rest of fields!!! */
BRUSH_UnlockBrush(pbrush);
return hBrush;
}
HBRUSH
APIENTRY
IntGdiCreateNullBrush(VOID)
{
HBRUSH hBrush;
PBRUSH pbrush;
pbrush = BRUSH_AllocBrushWithHandle();
if (pbrush == NULL)
{
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
return NULL;
}
hBrush = pbrush->BaseObject.hHmgr;
pbrush->flAttrs |= GDIBRUSH_IS_NULL;
BRUSH_UnlockBrush(pbrush);
return hBrush;
}
VOID
FASTCALL
IntGdiSetSolidBrushColor(HBRUSH hBrush, COLORREF Color)
{
PBRUSH pbrush;
pbrush = BRUSH_LockBrush(hBrush);
if (pbrush->flAttrs & GDIBRUSH_IS_SOLID)
{
pbrush->BrushAttr.lbColor = Color & 0xFFFFFF;
}
BRUSH_UnlockBrush(pbrush);
}
/* PUBLIC FUNCTIONS ***********************************************************/
HBRUSH
APIENTRY
NtGdiCreateDIBBrush(
IN PVOID BitmapInfoAndData,
IN FLONG ColorSpec,
IN UINT BitmapInfoSize,
IN BOOL b8X8,
IN BOOL bPen,
IN PVOID PackedDIB)
{
BITMAPINFO *SafeBitmapInfoAndData;
NTSTATUS Status = STATUS_SUCCESS;
HBRUSH hBrush;
SafeBitmapInfoAndData = EngAllocMem(FL_ZERO_MEMORY, BitmapInfoSize, TAG_DIB);
if (SafeBitmapInfoAndData == NULL)
{
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
return NULL;
}
_SEH2_TRY
{
ProbeForRead(BitmapInfoAndData, BitmapInfoSize, 1);
RtlCopyMemory(SafeBitmapInfoAndData, BitmapInfoAndData, BitmapInfoSize);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
if (!NT_SUCCESS(Status))
{
EngFreeMem(SafeBitmapInfoAndData);
SetLastNtError(Status);
return 0;
}
hBrush = IntGdiCreateDIBBrush(SafeBitmapInfoAndData,
ColorSpec,
BitmapInfoSize,
PackedDIB);
EngFreeMem(SafeBitmapInfoAndData);
return hBrush;
}
HBRUSH
APIENTRY
NtGdiCreateHatchBrushInternal(
ULONG Style,
COLORREF Color,
BOOL bPen)
{
return IntGdiCreateHatchBrush(Style, Color);
}
HBRUSH
APIENTRY
NtGdiCreatePatternBrushInternal(
HBITMAP hBitmap,
BOOL bPen,
BOOL b8x8)
{
return IntGdiCreatePatternBrush(hBitmap);
}
HBRUSH
APIENTRY
NtGdiCreateSolidBrush(COLORREF Color,
IN OPTIONAL HBRUSH hbr)
{
return IntGdiCreateSolidBrush(Color);
}
/**
* \name NtGdiSetBrushOrg
*
* \brief Sets the brush origin that GDI assigns to
* the next brush an application selects into the specified device context.
*
* @implemented
*/
BOOL
APIENTRY
NtGdiSetBrushOrg(HDC hDC, INT XOrg, INT YOrg, LPPOINT Point)
{
PDC dc;
PDC_ATTR pdcattr;
dc = DC_LockDc(hDC);
if (dc == NULL)
{
SetLastWin32Error(ERROR_INVALID_HANDLE);
return FALSE;
}
pdcattr = dc->pdcattr;
if (Point != NULL)
{
NTSTATUS Status = STATUS_SUCCESS;
POINT SafePoint;
SafePoint.x = pdcattr->ptlBrushOrigin.x;
SafePoint.y = pdcattr->ptlBrushOrigin.y;
_SEH2_TRY
{
ProbeForWrite(Point, sizeof(POINT), 1);
*Point = SafePoint;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
if (!NT_SUCCESS(Status))
{
DC_UnlockDc(dc);
SetLastNtError(Status);
return FALSE;
}
}
pdcattr->ptlBrushOrigin.x = XOrg;
pdcattr->ptlBrushOrigin.y = YOrg;
IntptlBrushOrigin(dc, XOrg, YOrg );
DC_UnlockDc(dc);
return TRUE;
}
/* EOF */