reactos/win32ss/gdi/eng/engbrush.c
Hervé Poussineau a0cfdcd409 [WIN32SS] Introduce the MDEVOBJ structure
This will be used (later) to store the list of all enabled display devices.

Add a global variable gpmdev (should really be stored in DISPLAYINFO structure)
Replace global variable gppdevPrimary by pmdev->ppdevGlobal.
2022-04-15 23:09:16 +02:00

533 lines
13 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* PURPOSE: GDI Driver Brush Functions
* FILE: win32ss/gdi/eng/engbrush.c
* PROGRAMER: Jason Filby
* Timo Kreuzer
*/
#include <win32k.h>
DBG_DEFAULT_CHANNEL(EngBrush);
static const ULONG gaulHatchBrushes[HS_DDI_MAX][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 */
};
HSURF gahsurfHatch[HS_DDI_MAX];
/** Internal functions ********************************************************/
CODE_SEG("INIT")
NTSTATUS
NTAPI
InitBrushImpl(VOID)
{
ULONG i;
SIZEL sizl = {8, 8};
/* Loop all hatch styles */
for (i = 0; i < HS_DDI_MAX; i++)
{
/* Create a default hatch bitmap */
gahsurfHatch[i] = (HSURF)EngCreateBitmap(sizl,
0,
BMF_1BPP,
0,
(PVOID)gaulHatchBrushes[i]);
}
return STATUS_SUCCESS;
}
VOID
NTAPI
EBRUSHOBJ_vInit(EBRUSHOBJ *pebo,
PBRUSH pbrush,
PSURFACE psurf,
COLORREF crBackgroundClr,
COLORREF crForegroundClr,
PPALETTE ppalDC)
{
ASSERT(pebo);
ASSERT(pbrush);
pebo->BrushObject.flColorType = 0;
pebo->BrushObject.pvRbrush = NULL;
pebo->pbrush = pbrush;
pebo->pengbrush = NULL;
pebo->flattrs = pbrush->flAttrs;
pebo->psoMask = NULL;
/* Initialize 1 bpp fore and back colors */
pebo->crCurrentBack = crBackgroundClr;
pebo->crCurrentText = crForegroundClr;
pebo->psurfTrg = psurf;
/* We are initializing for a new memory DC */
if(!pebo->psurfTrg)
pebo->psurfTrg = psurfDefaultBitmap;
ASSERT(pebo->psurfTrg);
ASSERT(pebo->psurfTrg->ppal);
/* Initialize palettes */
pebo->ppalSurf = pebo->psurfTrg->ppal;
GDIOBJ_vReferenceObjectByPointer(&pebo->ppalSurf->BaseObject);
pebo->ppalDC = ppalDC;
if(!pebo->ppalDC)
pebo->ppalDC = gppalDefault;
GDIOBJ_vReferenceObjectByPointer(&pebo->ppalDC->BaseObject);
pebo->ppalDIB = NULL;
if (pbrush->flAttrs & BR_IS_NULL)
{
/* NULL brushes don't need a color */
pebo->BrushObject.iSolidColor = 0;
}
else if (pbrush->flAttrs & BR_IS_SOLID)
{
/* Set the RGB color */
EBRUSHOBJ_vSetSolidRGBColor(pebo, pbrush->BrushAttr.lbColor);
}
else
{
/* This is a pattern brush that needs realization */
pebo->BrushObject.iSolidColor = 0xFFFFFFFF;
/* Use foreground color of hatch brushes */
if (pbrush->flAttrs & BR_IS_HATCH)
pebo->crCurrentText = pbrush->BrushAttr.lbColor;
}
}
VOID
NTAPI
EBRUSHOBJ_vInitFromDC(EBRUSHOBJ *pebo,
PBRUSH pbrush, PDC pdc)
{
EBRUSHOBJ_vInit(pebo, pbrush, pdc->dclevel.pSurface,
pdc->pdcattr->crBackgroundClr, pdc->pdcattr->crForegroundClr,
pdc->dclevel.ppal);
}
VOID
FASTCALL
EBRUSHOBJ_vSetSolidRGBColor(EBRUSHOBJ *pebo, COLORREF crColor)
{
ULONG iSolidColor;
EXLATEOBJ exlo;
/* Never use with non-solid brushes */
ASSERT(pebo->flattrs & BR_IS_SOLID);
/* Set the RGB color */
crColor &= 0xFFFFFF;
pebo->crRealize = crColor;
pebo->ulRGBColor = crColor;
/* Initialize an XLATEOBJ RGB -> surface */
EXLATEOBJ_vInitialize(&exlo,
&gpalRGB,
pebo->ppalSurf,
pebo->crCurrentBack,
0,
0);
/* Translate the brush color to the target format */
iSolidColor = XLATEOBJ_iXlate(&exlo.xlo, crColor);
pebo->BrushObject.iSolidColor = iSolidColor;
/* Clean up the XLATEOBJ */
EXLATEOBJ_vCleanup(&exlo);
}
VOID
NTAPI
EBRUSHOBJ_vCleanup(EBRUSHOBJ *pebo)
{
/* Check if there's a GDI realisation */
if (pebo->pengbrush)
{
/* Unlock the bitmap again */
SURFACE_ShareUnlockSurface(pebo->pengbrush);
pebo->pengbrush = NULL;
}
/* Check if there's a driver's realisation */
if (pebo->BrushObject.pvRbrush)
{
/* Free allocated driver memory */
EngFreeMem(pebo->BrushObject.pvRbrush);
pebo->BrushObject.pvRbrush = NULL;
}
if (pebo->psoMask != NULL)
{
SURFACE_ShareUnlockSurface(pebo->psoMask);
pebo->psoMask = NULL;
}
/* Dereference the palettes */
if (pebo->ppalSurf)
{
PALETTE_ShareUnlockPalette(pebo->ppalSurf);
}
if (pebo->ppalDC)
{
PALETTE_ShareUnlockPalette(pebo->ppalDC);
}
if (pebo->ppalDIB)
{
PALETTE_ShareUnlockPalette(pebo->ppalDIB);
}
}
VOID
NTAPI
EBRUSHOBJ_vUpdateFromDC(
EBRUSHOBJ *pebo,
PBRUSH pbrush,
PDC pdc)
{
/* Cleanup the brush */
EBRUSHOBJ_vCleanup(pebo);
/* Reinitialize */
EBRUSHOBJ_vInitFromDC(pebo, pbrush, pdc);
}
/**
* This function is not exported, because it makes no sense for
* The driver to punt back to this function */
BOOL
APIENTRY
EngRealizeBrush(
BRUSHOBJ *pbo,
SURFOBJ *psoDst,
SURFOBJ *psoPattern,
SURFOBJ *psoMask,
XLATEOBJ *pxlo,
ULONG iHatch)
{
EBRUSHOBJ *pebo;
HBITMAP hbmpRealize;
SURFOBJ *psoRealize;
PSURFACE psurfRealize;
POINTL ptlSrc = {0, 0};
RECTL rclDest;
ULONG lWidth;
/* Calculate width in bytes of the realized brush */
lWidth = WIDTH_BYTES_ALIGN32(psoPattern->sizlBitmap.cx,
BitsPerFormat(psoDst->iBitmapFormat));
/* Allocate a bitmap */
hbmpRealize = EngCreateBitmap(psoPattern->sizlBitmap,
lWidth,
psoDst->iBitmapFormat,
BMF_NOZEROINIT,
NULL);
if (!hbmpRealize)
{
return FALSE;
}
/* Lock the bitmap */
psurfRealize = SURFACE_ShareLockSurface(hbmpRealize);
/* Already delete the pattern bitmap (will be kept until dereferenced) */
EngDeleteSurface((HSURF)hbmpRealize);
if (!psurfRealize)
{
return FALSE;
}
/* Copy the bits to the new format bitmap */
rclDest.left = rclDest.top = 0;
rclDest.right = psoPattern->sizlBitmap.cx;
rclDest.bottom = psoPattern->sizlBitmap.cy;
psoRealize = &psurfRealize->SurfObj;
EngCopyBits(psoRealize, psoPattern, NULL, pxlo, &rclDest, &ptlSrc);
pebo = CONTAINING_RECORD(pbo, EBRUSHOBJ, BrushObject);
pebo->pengbrush = (PVOID)psurfRealize;
return TRUE;
}
static
PPALETTE
FixupDIBBrushPalette(
_In_ PPALETTE ppalDIB,
_In_ PPALETTE ppalDC)
{
PPALETTE ppalNew;
ULONG i, iPalIndex, crColor;
/* Allocate a new palette */
ppalNew = PALETTE_AllocPalette(PAL_INDEXED,
ppalDIB->NumColors,
NULL,
0,
0,
0);
if (ppalNew == NULL)
{
ERR("Failed to allcate palette for brush\n");
return NULL;
}
/* Loop all colors */
for (i = 0; i < ppalDIB->NumColors; i++)
{
/* Get the RGB color, which is the index into the DC palette */
iPalIndex = PALETTE_ulGetRGBColorFromIndex(ppalDIB, i);
/* Roll over when index is too big */
iPalIndex %= ppalDC->NumColors;
/* Set the indexed DC color as the new color */
crColor = PALETTE_ulGetRGBColorFromIndex(ppalDC, iPalIndex);
PALETTE_vSetRGBColorForIndex(ppalNew, i, crColor);
}
/* Return the new palette */
return ppalNew;
}
BOOL
NTAPI
EBRUSHOBJ_bRealizeBrush(EBRUSHOBJ *pebo, BOOL bCallDriver)
{
BOOL bResult;
PFN_DrvRealizeBrush pfnRealizeBrush = NULL;
PSURFACE psurfPattern;
SURFOBJ *psoMask;
PPDEVOBJ ppdev;
EXLATEOBJ exlo;
PPALETTE ppalPattern;
PBRUSH pbr = pebo->pbrush;
HBITMAP hbmPattern;
ULONG iHatch;
/* All EBRUSHOBJs have a surface, see EBRUSHOBJ_vInit */
ASSERT(pebo->psurfTrg);
ppdev = (PPDEVOBJ)pebo->psurfTrg->SurfObj.hdev;
if (!ppdev)
ppdev = gpmdev->ppdevGlobal;
if (bCallDriver)
{
/* Get the Drv function */
pfnRealizeBrush = ppdev->DriverFunctions.RealizeBrush;
if (pfnRealizeBrush == NULL)
{
ERR("No DrvRealizeBrush. Cannot realize brush\n");
return FALSE;
}
/* Get the mask */
psoMask = EBRUSHOBJ_psoMask(pebo);
}
else
{
/* Use the Eng function */
pfnRealizeBrush = EngRealizeBrush;
/* We don't handle the mask bitmap here. We do this only on demand */
psoMask = NULL;
}
/* Check if this is a hatch brush */
if (pbr->flAttrs & BR_IS_HATCH)
{
/* Get the hatch brush pattern from the PDEV */
hbmPattern = (HBITMAP)ppdev->ahsurf[pbr->iHatch];
iHatch = pbr->iHatch;
}
else
{
/* Use the brushes pattern */
hbmPattern = pbr->hbmPattern;
iHatch = -1;
}
psurfPattern = SURFACE_ShareLockSurface(hbmPattern);
ASSERT(psurfPattern);
ASSERT(psurfPattern->ppal);
/* DIB brushes with DIB_PAL_COLORS usage need a new palette */
if (pbr->flAttrs & BR_IS_DIBPALCOLORS)
{
/* Create a palette with the colors from the DC */
ppalPattern = FixupDIBBrushPalette(psurfPattern->ppal, pebo->ppalDC);
if (ppalPattern == NULL)
{
ERR("FixupDIBBrushPalette() failed.\n");
return FALSE;
}
pebo->ppalDIB = ppalPattern;
}
else
{
/* The palette is already as it should be */
ppalPattern = psurfPattern->ppal;
}
/* Initialize XLATEOBJ for the brush */
EXLATEOBJ_vInitialize(&exlo,
ppalPattern,
pebo->psurfTrg->ppal,
0,
pebo->crCurrentBack,
pebo->crCurrentText);
/* Create the realization */
bResult = pfnRealizeBrush(&pebo->BrushObject,
&pebo->psurfTrg->SurfObj,
&psurfPattern->SurfObj,
psoMask,
&exlo.xlo,
iHatch);
/* Cleanup the XLATEOBJ */
EXLATEOBJ_vCleanup(&exlo);
/* Unlock surface */
SURFACE_ShareUnlockSurface(psurfPattern);
return bResult;
}
PVOID
NTAPI
EBRUSHOBJ_pvGetEngBrush(EBRUSHOBJ *pebo)
{
BOOL bResult;
if (!pebo->pengbrush)
{
bResult = EBRUSHOBJ_bRealizeBrush(pebo, FALSE);
if (!bResult)
{
if (pebo->pengbrush)
EngDeleteSurface(pebo->pengbrush);
pebo->pengbrush = NULL;
}
}
return pebo->pengbrush;
}
SURFOBJ*
NTAPI
EBRUSHOBJ_psoPattern(EBRUSHOBJ *pebo)
{
PSURFACE psurfPattern;
psurfPattern = EBRUSHOBJ_pvGetEngBrush(pebo);
return psurfPattern ? &psurfPattern->SurfObj : NULL;
}
SURFOBJ*
NTAPI
EBRUSHOBJ_psoMask(EBRUSHOBJ *pebo)
{
HBITMAP hbmMask;
PSURFACE psurfMask;
PPDEVOBJ ppdev;
/* Check if we don't have a mask yet */
if (pebo->psoMask == NULL)
{
/* Check if this is a hatch brush */
if (pebo->flattrs & BR_IS_HATCH)
{
/* Get the PDEV */
ppdev = (PPDEVOBJ)pebo->psurfTrg->SurfObj.hdev;
if (!ppdev)
ppdev = gpmdev->ppdevGlobal;
/* Use the hatch bitmap as the mask */
hbmMask = (HBITMAP)ppdev->ahsurf[pebo->pbrush->iHatch];
psurfMask = SURFACE_ShareLockSurface(hbmMask);
if (psurfMask == NULL)
{
ERR("Failed to lock hatch brush for PDEV %p, iHatch %lu\n",
ppdev, pebo->pbrush->iHatch);
return NULL;
}
NT_ASSERT(psurfMask->SurfObj.iBitmapFormat == BMF_1BPP);
pebo->psoMask = &psurfMask->SurfObj;
}
}
return pebo->psoMask;
}
/** Exported DDI functions ****************************************************/
/*
* @implemented
*/
PVOID APIENTRY
BRUSHOBJ_pvAllocRbrush(
IN BRUSHOBJ *pbo,
IN ULONG cj)
{
pbo->pvRbrush = EngAllocMem(0, cj, GDITAG_RBRUSH);
return pbo->pvRbrush;
}
/*
* @implemented
*/
PVOID APIENTRY
BRUSHOBJ_pvGetRbrush(
IN BRUSHOBJ *pbo)
{
EBRUSHOBJ *pebo = CONTAINING_RECORD(pbo, EBRUSHOBJ, BrushObject);
BOOL bResult;
if (!pbo->pvRbrush)
{
bResult = EBRUSHOBJ_bRealizeBrush(pebo, TRUE);
if (!bResult)
{
if (pbo->pvRbrush)
{
EngFreeMem(pbo->pvRbrush);
pbo->pvRbrush = NULL;
}
}
}
return pbo->pvRbrush;
}
/*
* @implemented
*/
ULONG APIENTRY
BRUSHOBJ_ulGetBrushColor(
IN BRUSHOBJ *pbo)
{
EBRUSHOBJ *pebo = CONTAINING_RECORD(pbo, EBRUSHOBJ, BrushObject);
return pebo->ulRGBColor;
}
/* EOF */