mirror of
https://github.com/reactos/reactos.git
synced 2025-03-10 10:14:44 +00:00
663 lines
14 KiB
C
663 lines
14 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS kernel
|
|
* PURPOSE: GDI Driver Surace Functions
|
|
* FILE: subsys/win32k/eng/surface.c
|
|
* PROGRAMER: Jason Filby
|
|
* REVISION HISTORY:
|
|
* 3/7/1999: Created
|
|
* 9/11/2000: Updated to handle real pixel packed bitmaps (UPDATE TO DATE COMPLETED)
|
|
* TESTING TO BE DONE:
|
|
* - Create a GDI bitmap with all formats, perform all drawing operations on them, render to VGA surface
|
|
* refer to \test\microwin\src\engine\devdraw.c for info on correct pixel plotting for various formats
|
|
*/
|
|
|
|
#include <w32k.h>
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
enum Rle_EscapeCodes
|
|
{
|
|
RLE_EOL = 0, /* End of line */
|
|
RLE_END = 1, /* End of bitmap */
|
|
RLE_DELTA = 2 /* Delta */
|
|
};
|
|
|
|
INT FASTCALL BitsPerFormat(ULONG Format)
|
|
{
|
|
switch (Format)
|
|
{
|
|
case BMF_1BPP:
|
|
return 1;
|
|
|
|
case BMF_4BPP:
|
|
/* Fall through */
|
|
case BMF_4RLE:
|
|
return 4;
|
|
|
|
case BMF_8BPP:
|
|
/* Fall through */
|
|
case BMF_8RLE:
|
|
return 8;
|
|
|
|
case BMF_16BPP:
|
|
return 16;
|
|
|
|
case BMF_24BPP:
|
|
return 24;
|
|
|
|
case BMF_32BPP:
|
|
return 32;
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
ULONG FASTCALL BitmapFormat(WORD Bits, DWORD Compression)
|
|
{
|
|
switch (Compression)
|
|
{
|
|
case BI_RGB:
|
|
/* Fall through */
|
|
case BI_BITFIELDS:
|
|
switch (Bits)
|
|
{
|
|
case 1:
|
|
return BMF_1BPP;
|
|
case 4:
|
|
return BMF_4BPP;
|
|
case 8:
|
|
return BMF_8BPP;
|
|
case 16:
|
|
return BMF_16BPP;
|
|
case 24:
|
|
return BMF_24BPP;
|
|
case 32:
|
|
return BMF_32BPP;
|
|
}
|
|
return 0;
|
|
|
|
case BI_RLE4:
|
|
return BMF_4RLE;
|
|
|
|
case BI_RLE8:
|
|
return BMF_8RLE;
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
BOOL INTERNAL_CALL
|
|
SURFACE_Cleanup(PVOID ObjectBody)
|
|
{
|
|
PSURFACE psurf = (PSURFACE)ObjectBody;
|
|
PVOID pvBits = psurf->SurfObj.pvBits;
|
|
|
|
/* If this is an API bitmap, free the bits */
|
|
if (pvBits != NULL &&
|
|
(psurf->flFlags & BITMAPOBJ_IS_APIBITMAP))
|
|
{
|
|
/* Check if we have a DIB section */
|
|
if (psurf->hSecure)
|
|
{
|
|
// FIXME: IMPLEMENT ME!
|
|
// MmUnsecureVirtualMemory(psurf->hSecure);
|
|
if (psurf->hDIBSection)
|
|
{
|
|
/* DIB was created from a section */
|
|
NTSTATUS Status;
|
|
|
|
pvBits = (PVOID)((ULONG_PTR)pvBits - psurf->dwOffset);
|
|
Status = ZwUnmapViewOfSection(NtCurrentProcess(), pvBits);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("Could not unmap section view!\n");
|
|
// Should we BugCheck here?
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* DIB was allocated */
|
|
EngFreeUserMem(pvBits);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// FIXME: use TAG
|
|
ExFreePool(psurf->SurfObj.pvBits);
|
|
}
|
|
|
|
if (psurf->hDIBPalette != NULL)
|
|
{
|
|
GreDeleteObject(psurf->hDIBPalette);
|
|
}
|
|
}
|
|
|
|
if (NULL != psurf->BitsLock)
|
|
{
|
|
ExFreePoolWithTag(psurf->BitsLock, TAG_SURFACE);
|
|
psurf->BitsLock = NULL;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL INTERNAL_CALL
|
|
SURFACE_InitBitsLock(PSURFACE psurf)
|
|
{
|
|
psurf->BitsLock = ExAllocatePoolWithTag(NonPagedPool,
|
|
sizeof(FAST_MUTEX),
|
|
TAG_SURFACE);
|
|
if (NULL == psurf->BitsLock)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
ExInitializeFastMutex(psurf->BitsLock);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void INTERNAL_CALL
|
|
SURFACE_CleanupBitsLock(PSURFACE psurf)
|
|
{
|
|
if (NULL != psurf->BitsLock)
|
|
{
|
|
ExFreePoolWithTag(psurf->BitsLock, TAG_SURFACE);
|
|
psurf->BitsLock = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
HBITMAP APIENTRY
|
|
EngCreateDeviceBitmap(IN DHSURF dhsurf,
|
|
IN SIZEL Size,
|
|
IN ULONG Format)
|
|
{
|
|
HBITMAP NewBitmap;
|
|
SURFOBJ *pso;
|
|
|
|
NewBitmap = EngCreateBitmap(Size, DIB_GetDIBWidthBytes(Size.cx, BitsPerFormat(Format)), Format, 0, NULL);
|
|
if (!NewBitmap)
|
|
{
|
|
DPRINT1("EngCreateBitmap failed\n");
|
|
return 0;
|
|
}
|
|
|
|
pso = EngLockSurface((HSURF)NewBitmap);
|
|
if (!pso)
|
|
{
|
|
DPRINT1("EngLockSurface failed on newly created bitmap!\n");
|
|
GreDeleteObject(NewBitmap);
|
|
return NULL;
|
|
}
|
|
|
|
pso->dhsurf = dhsurf;
|
|
EngUnlockSurface(pso);
|
|
|
|
return NewBitmap;
|
|
}
|
|
|
|
VOID Decompress4bpp(SIZEL Size, BYTE *CompressedBits, BYTE *UncompressedBits, LONG Delta)
|
|
{
|
|
int x = 0;
|
|
int y = Size.cy - 1;
|
|
int c;
|
|
int length;
|
|
int width = ((Size.cx+1)/2);
|
|
int height = Size.cy - 1;
|
|
BYTE *begin = CompressedBits;
|
|
BYTE *bits = CompressedBits;
|
|
BYTE *temp;
|
|
while (y >= 0)
|
|
{
|
|
length = *bits++ / 2;
|
|
if (length)
|
|
{
|
|
c = *bits++;
|
|
while (length--)
|
|
{
|
|
if (x >= width) break;
|
|
temp = UncompressedBits + (((height - y) * Delta) + x);
|
|
x++;
|
|
*temp = c;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
length = *bits++;
|
|
switch (length)
|
|
{
|
|
case RLE_EOL:
|
|
x = 0;
|
|
y--;
|
|
break;
|
|
case RLE_END:
|
|
return;
|
|
case RLE_DELTA:
|
|
x += (*bits++)/2;
|
|
y -= (*bits++)/2;
|
|
break;
|
|
default:
|
|
length /= 2;
|
|
while (length--)
|
|
{
|
|
c = *bits++;
|
|
if (x < width)
|
|
{
|
|
temp = UncompressedBits + (((height - y) * Delta) + x);
|
|
x++;
|
|
*temp = c;
|
|
}
|
|
}
|
|
if ((bits - begin) & 1)
|
|
{
|
|
bits++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID Decompress8bpp(SIZEL Size, BYTE *CompressedBits, BYTE *UncompressedBits, LONG Delta)
|
|
{
|
|
int x = 0;
|
|
int y = Size.cy - 1;
|
|
int c;
|
|
int length;
|
|
int width = Size.cx;
|
|
int height = Size.cy - 1;
|
|
BYTE *begin = CompressedBits;
|
|
BYTE *bits = CompressedBits;
|
|
BYTE *temp;
|
|
while (y >= 0)
|
|
{
|
|
length = *bits++;
|
|
if (length)
|
|
{
|
|
c = *bits++;
|
|
while (length--)
|
|
{
|
|
if (x >= width) break;
|
|
temp = UncompressedBits + (((height - y) * Delta) + x);
|
|
x++;
|
|
*temp = c;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
length = *bits++;
|
|
switch (length)
|
|
{
|
|
case RLE_EOL:
|
|
x = 0;
|
|
y--;
|
|
break;
|
|
case RLE_END:
|
|
return;
|
|
case RLE_DELTA:
|
|
x += *bits++;
|
|
y -= *bits++;
|
|
break;
|
|
default:
|
|
while (length--)
|
|
{
|
|
c = *bits++;
|
|
if (x < width)
|
|
{
|
|
temp = UncompressedBits + (((height - y) * Delta) + x);
|
|
x++;
|
|
*temp = c;
|
|
}
|
|
}
|
|
if ((bits - begin) & 1)
|
|
{
|
|
bits++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
HBITMAP FASTCALL
|
|
IntCreateBitmap(IN SIZEL Size,
|
|
IN LONG Width,
|
|
IN ULONG Format,
|
|
IN ULONG Flags,
|
|
IN PVOID Bits)
|
|
{
|
|
HBITMAP hbmp;
|
|
SURFOBJ *pso;
|
|
PSURFACE psurf;
|
|
PVOID UncompressedBits;
|
|
ULONG UncompressedFormat;
|
|
|
|
if (Format == 0)
|
|
return 0;
|
|
|
|
psurf = SURFACE_AllocSurfaceWithHandle();
|
|
if (psurf == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
hbmp = psurf->BaseObject.hHmgr;
|
|
|
|
if (! SURFACE_InitBitsLock(psurf))
|
|
{
|
|
SURFACE_UnlockSurface(psurf);
|
|
SURFACE_FreeSurfaceByHandle(hbmp);
|
|
return 0;
|
|
}
|
|
pso = &psurf->SurfObj;
|
|
|
|
if (Format == BMF_4RLE)
|
|
{
|
|
pso->lDelta = DIB_GetDIBWidthBytes(Size.cx, BitsPerFormat(BMF_4BPP));
|
|
pso->cjBits = pso->lDelta * Size.cy;
|
|
UncompressedFormat = BMF_4BPP;
|
|
UncompressedBits = EngAllocMem(FL_ZERO_MEMORY, pso->cjBits, TAG_DIB);
|
|
Decompress4bpp(Size, (BYTE *)Bits, (BYTE *)UncompressedBits, pso->lDelta);
|
|
}
|
|
else if (Format == BMF_8RLE)
|
|
{
|
|
pso->lDelta = DIB_GetDIBWidthBytes(Size.cx, BitsPerFormat(BMF_8BPP));
|
|
pso->cjBits = pso->lDelta * Size.cy;
|
|
UncompressedFormat = BMF_8BPP;
|
|
UncompressedBits = EngAllocMem(FL_ZERO_MEMORY, pso->cjBits, TAG_DIB);
|
|
Decompress8bpp(Size, (BYTE *)Bits, (BYTE *)UncompressedBits, pso->lDelta);
|
|
}
|
|
else
|
|
{
|
|
pso->lDelta = abs(Width);
|
|
pso->cjBits = pso->lDelta * Size.cy;
|
|
UncompressedBits = Bits;
|
|
UncompressedFormat = Format;
|
|
}
|
|
|
|
if (UncompressedBits != NULL)
|
|
{
|
|
pso->pvBits = UncompressedBits;
|
|
}
|
|
else
|
|
{
|
|
if (pso->cjBits == 0)
|
|
{
|
|
pso->pvBits = NULL;
|
|
}
|
|
else
|
|
{
|
|
if (0 != (Flags & BMF_USERMEM))
|
|
{
|
|
pso->pvBits = EngAllocUserMem(pso->cjBits, 0);
|
|
}
|
|
else
|
|
{
|
|
pso->pvBits = EngAllocMem(0 != (Flags & BMF_NOZEROINIT) ?
|
|
0 : FL_ZERO_MEMORY,
|
|
pso->cjBits, TAG_DIB);
|
|
}
|
|
if (pso->pvBits == NULL)
|
|
{
|
|
SURFACE_UnlockSurface(psurf);
|
|
SURFACE_FreeSurfaceByHandle(hbmp);
|
|
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (0 == (Flags & BMF_TOPDOWN))
|
|
{
|
|
pso->pvScan0 = (PVOID)((ULONG_PTR)pso->pvBits + pso->cjBits - pso->lDelta);
|
|
pso->lDelta = - pso->lDelta;
|
|
}
|
|
else
|
|
{
|
|
pso->pvScan0 = pso->pvBits;
|
|
}
|
|
|
|
pso->dhsurf = 0; /* device managed surface */
|
|
pso->hsurf = (HSURF)hbmp;
|
|
pso->dhpdev = NULL;
|
|
pso->hdev = NULL;
|
|
pso->sizlBitmap = Size;
|
|
pso->iBitmapFormat = UncompressedFormat;
|
|
pso->iType = STYPE_BITMAP;
|
|
pso->fjBitmap = Flags & (BMF_TOPDOWN | BMF_NOZEROINIT);
|
|
pso->iUniq = 0;
|
|
|
|
psurf->flHooks = 0;
|
|
psurf->flFlags = 0;
|
|
psurf->dimension.cx = 0;
|
|
psurf->dimension.cy = 0;
|
|
|
|
psurf->hSecure = NULL;
|
|
psurf->hDIBSection = NULL;
|
|
|
|
SURFACE_UnlockSurface(psurf);
|
|
|
|
return hbmp;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
HBITMAP APIENTRY
|
|
EngCreateBitmap(IN SIZEL Size,
|
|
IN LONG Width,
|
|
IN ULONG Format,
|
|
IN ULONG Flags,
|
|
IN PVOID Bits)
|
|
{
|
|
HBITMAP hNewBitmap;
|
|
|
|
hNewBitmap = IntCreateBitmap(Size, Width, Format, Flags, Bits);
|
|
if ( !hNewBitmap )
|
|
return 0;
|
|
|
|
GDIOBJ_SetOwnership(hNewBitmap, NULL);
|
|
|
|
return hNewBitmap;
|
|
}
|
|
|
|
/*
|
|
* @unimplemented
|
|
*/
|
|
HSURF APIENTRY
|
|
EngCreateDeviceSurface(IN DHSURF dhsurf,
|
|
IN SIZEL Size,
|
|
IN ULONG Format)
|
|
{
|
|
HSURF hsurf;
|
|
SURFOBJ *pso;
|
|
PSURFACE psurf;
|
|
|
|
psurf = SURFACE_AllocSurfaceWithHandle();
|
|
if (!psurf)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
hsurf = psurf->BaseObject.hHmgr;
|
|
GDIOBJ_SetOwnership(hsurf, NULL);
|
|
|
|
if (!SURFACE_InitBitsLock(psurf))
|
|
{
|
|
SURFACE_UnlockSurface(psurf);
|
|
SURFACE_FreeSurfaceByHandle(hsurf);
|
|
return 0;
|
|
}
|
|
pso = &psurf->SurfObj;
|
|
|
|
pso->dhsurf = dhsurf;
|
|
pso->hsurf = hsurf;
|
|
pso->sizlBitmap = Size;
|
|
pso->iBitmapFormat = Format;
|
|
pso->lDelta = DIB_GetDIBWidthBytes(Size.cx, BitsPerFormat(Format));
|
|
pso->iType = STYPE_DEVICE;
|
|
pso->iUniq = 0;
|
|
|
|
psurf->flHooks = 0;
|
|
|
|
SURFACE_UnlockSurface(psurf);
|
|
|
|
return hsurf;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
APIENTRY
|
|
EngAssociateSurface(
|
|
IN HSURF hsurf,
|
|
IN HDEV hdev,
|
|
IN FLONG flHooks)
|
|
{
|
|
SURFOBJ *pso;
|
|
PSURFACE psurf;
|
|
PDEVOBJ* ppdev;
|
|
|
|
ppdev = (PDEVOBJ*)hdev;
|
|
|
|
/* Lock the surface */
|
|
psurf = SURFACE_LockSurface(hsurf);
|
|
if (!psurf)
|
|
{
|
|
return FALSE;
|
|
}
|
|
pso = &psurf->SurfObj;
|
|
|
|
/* Associate the hdev */
|
|
pso->hdev = hdev;
|
|
pso->dhpdev = ppdev->dhpdev;
|
|
|
|
/* Hook up specified functions */
|
|
psurf->flHooks = flHooks;
|
|
|
|
SURFACE_UnlockSurface(psurf);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL APIENTRY
|
|
EngModifySurface(
|
|
IN HSURF hsurf,
|
|
IN HDEV hdev,
|
|
IN FLONG flHooks,
|
|
IN FLONG flSurface,
|
|
IN DHSURF dhsurf,
|
|
OUT VOID *pvScan0,
|
|
IN LONG lDelta,
|
|
IN VOID *pvReserved)
|
|
{
|
|
SURFOBJ *pso;
|
|
PSURFACE psurf;
|
|
PDEVOBJ* ppdev;
|
|
|
|
psurf = SURFACE_LockSurface(hsurf);
|
|
if (psurf == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
ppdev = (PDEVOBJ*)hdev;
|
|
pso = &psurf->SurfObj;
|
|
pso->dhsurf = dhsurf;
|
|
pso->lDelta = lDelta;
|
|
pso->pvScan0 = pvScan0;
|
|
|
|
/* Associate the hdev */
|
|
pso->hdev = hdev;
|
|
pso->dhpdev = ppdev->dhpdev;
|
|
|
|
/* Hook up specified functions */
|
|
psurf->flHooks = flHooks;
|
|
|
|
SURFACE_UnlockSurface(psurf);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL APIENTRY
|
|
EngDeleteSurface(IN HSURF hsurf)
|
|
{
|
|
GDIOBJ_SetOwnership(hsurf, PsGetCurrentProcess());
|
|
SURFACE_FreeSurfaceByHandle(hsurf);
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL APIENTRY
|
|
EngEraseSurface(SURFOBJ *pso,
|
|
RECTL *Rect,
|
|
ULONG iColor)
|
|
{
|
|
ASSERT(pso);
|
|
ASSERT(Rect);
|
|
return FillSolid(pso, Rect, iColor);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
SURFOBJ * APIENTRY
|
|
NtGdiEngLockSurface(IN HSURF hsurf)
|
|
{
|
|
return EngLockSurface(hsurf);
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
SURFOBJ * APIENTRY
|
|
EngLockSurface(IN HSURF hsurf)
|
|
{
|
|
SURFACE *psurf = GDIOBJ_ShareLockObj(hsurf, GDI_OBJECT_TYPE_BITMAP);
|
|
|
|
if (psurf != NULL)
|
|
return &psurf->SurfObj;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID APIENTRY
|
|
NtGdiEngUnlockSurface(IN SURFOBJ *pso)
|
|
{
|
|
EngUnlockSurface(pso);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID APIENTRY
|
|
EngUnlockSurface(IN SURFOBJ *pso)
|
|
{
|
|
if (pso != NULL)
|
|
{
|
|
SURFACE *psurf = CONTAINING_RECORD(pso, SURFACE, SurfObj);
|
|
GDIOBJ_ShareUnlockObjByPtr((POBJ)psurf);
|
|
}
|
|
}
|
|
|
|
|
|
/* EOF */
|