reactos/subsystems/win32/win32k/objects/dcattr.c
Jérôme Gardou 88c9e7c6e8 Sync with trunk (r47116), hopefully without breaking anything.
svn path=/branches/reactos-yarotows/; revision=47117
2010-05-07 07:41:13 +00:00

286 lines
7.1 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* PURPOSE: Functions for creation and destruction of DCs
* FILE: subsystem/win32/win32k/objects/dcattr.c
* PROGRAMER: Timo Kreuzer (timo.kreuzer@rectos.org)
*/
#include <win32k.h>
#define NDEBUG
#include <debug.h>
#define GDIDCATTRFREE 8
typedef struct _GDI_DC_ATTR_FREELIST
{
LIST_ENTRY Entry;
DWORD nEntries;
PVOID AttrList[GDIDCATTRFREE];
} GDI_DC_ATTR_FREELIST, *PGDI_DC_ATTR_FREELIST;
typedef struct _GDI_DC_ATTR_ENTRY
{
DC_ATTR Attr[GDIDCATTRFREE];
} GDI_DC_ATTR_ENTRY, *PGDI_DC_ATTR_ENTRY;
PDC_ATTR
FASTCALL
AllocateDcAttr(VOID)
{
PTHREADINFO pti;
PPROCESSINFO ppi;
PDC_ATTR pDc_Attr;
PGDI_DC_ATTR_FREELIST pGdiDcAttrFreeList;
PGDI_DC_ATTR_ENTRY pGdiDcAttrEntry;
int i;
pti = PsGetCurrentThreadWin32Thread();
if (pti->pgdiDcattr)
{
pDc_Attr = pti->pgdiDcattr; // Get the free one.
pti->pgdiDcattr = NULL;
return pDc_Attr;
}
ppi = PsGetCurrentProcessWin32Process();
if (!ppi->pDCAttrList) // If set point is null, allocate new group.
{
pGdiDcAttrEntry = EngAllocUserMem(sizeof(GDI_DC_ATTR_ENTRY), 0);
if (!pGdiDcAttrEntry)
{
DPRINT1("DcAttr Failed User Allocation!\n");
return NULL;
}
DPRINT("AllocDcAttr User 0x%x\n",pGdiDcAttrEntry);
pGdiDcAttrFreeList = ExAllocatePoolWithTag( PagedPool,
sizeof(GDI_DC_ATTR_FREELIST),
GDITAG_DC_FREELIST);
if ( !pGdiDcAttrFreeList )
{
EngFreeUserMem(pGdiDcAttrEntry);
return NULL;
}
RtlZeroMemory(pGdiDcAttrFreeList, sizeof(GDI_DC_ATTR_FREELIST));
DPRINT("AllocDcAttr Ex 0x%x\n",pGdiDcAttrFreeList);
InsertHeadList( &ppi->GDIDcAttrFreeList, &pGdiDcAttrFreeList->Entry);
pGdiDcAttrFreeList->nEntries = GDIDCATTRFREE;
// Start at the bottom up and set end of free list point.
ppi->pDCAttrList = &pGdiDcAttrEntry->Attr[GDIDCATTRFREE-1];
// Build the free attr list.
for ( i = 0; i < GDIDCATTRFREE; i++)
{
pGdiDcAttrFreeList->AttrList[i] = &pGdiDcAttrEntry->Attr[i];
}
}
pDc_Attr = ppi->pDCAttrList;
pGdiDcAttrFreeList = (PGDI_DC_ATTR_FREELIST)ppi->GDIDcAttrFreeList.Flink;
// Free the list when it is full!
if ( pGdiDcAttrFreeList->nEntries-- == 1)
{ // No more free entries, so yank the list.
RemoveEntryList( &pGdiDcAttrFreeList->Entry );
ExFreePoolWithTag( pGdiDcAttrFreeList, GDITAG_DC_FREELIST );
if ( IsListEmpty( &ppi->GDIDcAttrFreeList ) )
{
ppi->pDCAttrList = NULL;
return pDc_Attr;
}
pGdiDcAttrFreeList = (PGDI_DC_ATTR_FREELIST)ppi->GDIDcAttrFreeList.Flink;
}
ppi->pDCAttrList = pGdiDcAttrFreeList->AttrList[pGdiDcAttrFreeList->nEntries-1];
return pDc_Attr;
}
VOID
FASTCALL
FreeDcAttr(PDC_ATTR pDc_Attr)
{
PTHREADINFO pti;
PPROCESSINFO ppi;
PGDI_DC_ATTR_FREELIST pGdiDcAttrFreeList;
pti = PsGetCurrentThreadWin32Thread();
if (!pti) return;
if (!pti->pgdiDcattr)
{ // If it is null, just cache it for the next time.
pti->pgdiDcattr = pDc_Attr;
return;
}
ppi = PsGetCurrentProcessWin32Process();
pGdiDcAttrFreeList = (PGDI_DC_ATTR_FREELIST)ppi->GDIDcAttrFreeList.Flink;
// We add to the list of free entries, so this will grows!
if ( IsListEmpty(&ppi->GDIDcAttrFreeList) ||
pGdiDcAttrFreeList->nEntries == GDIDCATTRFREE )
{
pGdiDcAttrFreeList = ExAllocatePoolWithTag( PagedPool,
sizeof(GDI_DC_ATTR_FREELIST),
GDITAG_DC_FREELIST);
if ( !pGdiDcAttrFreeList )
{
return;
}
InsertHeadList( &ppi->GDIDcAttrFreeList, &pGdiDcAttrFreeList->Entry);
pGdiDcAttrFreeList->nEntries = 0;
}
// Up count, save the entry and set end of free list point.
++pGdiDcAttrFreeList->nEntries; // Top Down...
pGdiDcAttrFreeList->AttrList[pGdiDcAttrFreeList->nEntries-1] = pDc_Attr;
ppi->pDCAttrList = pDc_Attr;
return;
}
BOOL
FASTCALL
DC_AllocDcAttr(PDC pdc)
{
DC_AllocateDcAttr(pdc->BaseObject.hHmgr);
*pdc->pdcattr = pdc->dcattr;
return TRUE;
}
// CHECK against current head
VOID
FASTCALL
DC_AllocateDcAttr(HDC hDC)
{
PVOID NewMem = NULL;
PDC pDC;
HANDLE Pid = NtCurrentProcess();
ULONG MemSize = sizeof(DC_ATTR); //PAGE_SIZE it will allocate that size
NTSTATUS Status = ZwAllocateVirtualMemory(Pid,
&NewMem,
0,
&MemSize,
MEM_COMMIT|MEM_RESERVE,
PAGE_READWRITE);
{
INT Index = GDI_HANDLE_GET_INDEX((HGDIOBJ)hDC);
PGDI_TABLE_ENTRY Entry = &GdiHandleTable->Entries[Index];
// FIXME: dc could have been deleted!!! use GDIOBJ_InsertUserData
if (NT_SUCCESS(Status))
{
RtlZeroMemory(NewMem, MemSize);
Entry->UserData = NewMem;
DPRINT("DC_ATTR allocated! 0x%x\n",NewMem);
}
else
{
DPRINT("DC_ATTR not allocated!\n");
}
}
pDC = DC_LockDc(hDC);
ASSERT(pDC->pdcattr == &pDC->dcattr);
if(NewMem)
{
pDC->pdcattr = NewMem; // Store pointer
}
DC_UnlockDc(pDC);
}
VOID
NTAPI
DC_vFreeDcAttr(PDC pdc)
{
HANDLE Pid = NtCurrentProcess();
INT Index;
PGDI_TABLE_ENTRY pent;
if (pdc->pdcattr == &pdc->dcattr)
{
// Internal DC object!
return;
}
pdc->pdcattr = &pdc->dcattr;
Index = GDI_HANDLE_GET_INDEX(pdc->BaseObject.hHmgr);
pent = &GdiHandleTable->Entries[Index];
if(pent->UserData)
{
ULONG MemSize = sizeof(DC_ATTR);
NTSTATUS Status = ZwFreeVirtualMemory(Pid,
&pent->UserData,
&MemSize,
MEM_RELEASE);
if (!NT_SUCCESS(Status))
{
DPRINT1("DC_FreeDC failed to free DC_ATTR 0x%p\n", pent->UserData);
ASSERT(FALSE);
}
pent->UserData = NULL;
}
}
static
VOID
CopytoUserDcAttr(PDC dc, PDC_ATTR pdcattr)
{
NTSTATUS Status = STATUS_SUCCESS;
dc->dcattr.mxWorldToDevice = dc->dclevel.mxWorldToDevice;
dc->dcattr.mxDeviceToWorld = dc->dclevel.mxDeviceToWorld;
dc->dcattr.mxWorldToPage = dc->dclevel.mxWorldToPage;
_SEH2_TRY
{
ProbeForWrite(pdcattr, sizeof(DC_ATTR), 1);
RtlCopyMemory(pdcattr, &dc->dcattr, sizeof(DC_ATTR));
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
ASSERT(FALSE);
}
_SEH2_END;
}
// FIXME: wtf? 2 functions, where one has a typo in the name????
BOOL
FASTCALL
DCU_SyncDcAttrtoUser(PDC dc)
{
PDC_ATTR pdcattr = dc->pdcattr;
if (pdcattr == &dc->dcattr) return TRUE; // No need to copy self.
ASSERT(pdcattr);
CopytoUserDcAttr( dc, pdcattr);
return TRUE;
}
// LOL! DCU_ Sync hDc Attr to User,,, need it speeled out for you?
BOOL
FASTCALL
DCU_SynchDcAttrtoUser(HDC hDC)
{
BOOL Ret;
PDC pDC = DC_LockDc ( hDC );
if (!pDC) return FALSE;
Ret = DCU_SyncDcAttrtoUser(pDC);
DC_UnlockDc( pDC );
return Ret;
}