reactos/subsystems/win32/win32k/objects/dcstate.c

288 lines
7.6 KiB
C
Raw Normal View History

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* PURPOSE: Functions for saving and restoring dc states
* FILE: subsystem/win32/win32k/objects/dcstate.c
* PROGRAMER: Timo Kreuzer (timo.kreuzer@rectos.org)
*/
#include <w32k.h>
#define NDEBUG
#include <debug.h>
VOID
FASTCALL
DC_vCopyState(PDC pdcSrc, PDC pdcDst, BOOL To)
{
DPRINT("DC_vCopyState(%p, %p)\n", pdcSrc->BaseObject.hHmgr, pdcDst->BaseObject.hHmgr);
/* Copy full DC attribute */
*pdcDst->pdcattr = *pdcSrc->pdcattr;
/* Get/SetDCState() don't change hVisRgn field ("Undoc. Windows" p.559). */
/* The VisRectRegion field needs to be set to a valid state */
/* Mark some fields as dirty */
pdcDst->pdcattr->ulDirty_ |= 0x0012001f; // Note: Use if, To is FALSE....
/* Copy DC level */
pdcDst->dclevel.pColorSpace = pdcSrc->dclevel.pColorSpace;
pdcDst->dclevel.lSaveDepth = pdcSrc->dclevel.lSaveDepth;
pdcDst->dclevel.hdcSave = pdcSrc->dclevel.hdcSave;
pdcDst->dclevel.laPath = pdcSrc->dclevel.laPath;
pdcDst->dclevel.ca = pdcSrc->dclevel.ca;
pdcDst->dclevel.mxWorldToDevice = pdcSrc->dclevel.mxWorldToDevice;
pdcDst->dclevel.mxDeviceToWorld = pdcSrc->dclevel.mxDeviceToWorld;
pdcDst->dclevel.mxWorldToPage = pdcSrc->dclevel.mxWorldToPage;
pdcDst->dclevel.efM11PtoD = pdcSrc->dclevel.efM11PtoD;
pdcDst->dclevel.efM22PtoD = pdcSrc->dclevel.efM22PtoD;
pdcDst->dclevel.sizl = pdcSrc->dclevel.sizl;
pdcDst->dclevel.hpal = pdcSrc->dclevel.hpal;
/* Handle references here correctly */
DC_vSelectSurface(pdcDst, pdcSrc->dclevel.pSurface);
DC_vSelectFillBrush(pdcDst, pdcSrc->dclevel.pbrFill);
DC_vSelectLineBrush(pdcDst, pdcSrc->dclevel.pbrLine);
DC_vSelectPalette(pdcDst, pdcSrc->dclevel.ppal);
// FIXME: handle refs
pdcDst->dclevel.plfnt = pdcSrc->dclevel.plfnt;
/* ROS hacks */
if (pdcDst->dctype != DC_TYPE_MEMORY)
{
pdcDst->rosdc.bitsPerPixel = pdcSrc->rosdc.bitsPerPixel;
}
/* Get/SetDCState() don't change hVisRgn field ("Undoc. Windows" p.559). */
if (To) // Copy "To" SaveDC state.
{
if (pdcSrc->rosdc.hClipRgn)
{
pdcDst->rosdc.hClipRgn = IntSysCreateRectRgn(0, 0, 0, 0);
NtGdiCombineRgn(pdcDst->rosdc.hClipRgn, pdcSrc->rosdc.hClipRgn, 0, RGN_COPY);
}
// FIXME! Handle prgnMeta!
}
else // Copy "!To" RestoreDC state.
{ /* The VisRectRegion field needs to be set to a valid state */
GdiExtSelectClipRgn(pdcDst, pdcSrc->rosdc.hClipRgn, RGN_COPY);
}
}
BOOL FASTCALL
IntGdiCleanDC(HDC hDC)
{
PDC dc;
if (!hDC) return FALSE;
dc = DC_LockDc(hDC);
if (!dc) return FALSE;
// Clean the DC
if (defaultDCstate) DC_vCopyState(defaultDCstate, dc, FALSE);
if (dc->dctype != DC_TYPE_MEMORY)
{
dc->rosdc.bitsPerPixel = defaultDCstate->rosdc.bitsPerPixel;
}
DC_UnlockDc(dc);
return TRUE;
}
BOOL
APIENTRY
NtGdiResetDC(
IN HDC hdc,
IN LPDEVMODEW pdm,
OUT PBOOL pbBanding,
IN OPTIONAL VOID *pDriverInfo2,
OUT VOID *ppUMdhpdev)
{
UNIMPLEMENTED;
return 0;
}
VOID
NTAPI
DC_vRestoreDC(
IN PDC pdc,
INT iSaveLevel)
{
PEPROCESS pepCurrentProcess;
HDC hdcSave;
PDC pdcSave;
ASSERT(iSaveLevel > 0);
DPRINT("DC_vRestoreDC(%p, %ld)\n", pdc->BaseObject.hHmgr, iSaveLevel);
/* Get current process */
pepCurrentProcess = PsGetCurrentProcess();
/* Loop the save levels */
while (pdc->dclevel.lSaveDepth > iSaveLevel)
{
hdcSave = pdc->dclevel.hdcSave;
DPRINT("RestoreDC = %p\n", hdcSave);
/* Set us as the owner */
if (!GDIOBJ_SetOwnership(hdcSave, pepCurrentProcess))
{
/* Could not get ownership. That's bad! */
DPRINT1("Could not get ownership of saved DC (%p) for hdc %p!\n",
hdcSave, pdc->BaseObject.hHmgr);
return;// FALSE;
}
/* Lock the saved dc */
pdcSave = DC_LockDc(hdcSave);
if (!pdcSave)
{
/* WTF? Internal error! */
DPRINT1("Could not lock the saved DC (%p) for dc %p!\n",
hdcSave, pdc->BaseObject.hHmgr);
return;// FALSE;
}
/* Remove the saved dc from the queue */
pdc->dclevel.hdcSave = pdcSave->dclevel.hdcSave;
/* Decrement save level */
pdc->dclevel.lSaveDepth--;
/* Is this the state we want? */
if (pdc->dclevel.lSaveDepth == iSaveLevel)
{
/* Copy the state back */
DC_vCopyState(pdcSave, pdc, FALSE);
// Restore Path by removing it, if the Save flag is set.
// BeginPath will takecare of the rest.
if (pdc->dclevel.hPath && pdc->dclevel.flPath & DCPATH_SAVE)
{
PATH_Delete(pdc->dclevel.hPath);
pdc->dclevel.hPath = 0;
pdc->dclevel.flPath &= ~DCPATH_SAVE;
}
}
/* Prevent save dc from being restored */
pdcSave->dclevel.lSaveDepth = 1;
/* Delete the saved dc */
GreDeleteObject(hdcSave);
}
DPRINT("Leave DC_vRestoreDC()\n");
}
BOOL
APIENTRY
NtGdiRestoreDC(
HDC hdc,
INT iSaveLevel)
{
PDC pdc;
DPRINT("NtGdiRestoreDC(%p, %d)\n", hdc, iSaveLevel);
/* Lock the original DC */
pdc = DC_LockDc(hdc);
if (!pdc)
{
SetLastWin32Error(ERROR_INVALID_HANDLE);
return FALSE;
}
ASSERT(pdc->dclevel.lSaveDepth > 0);
/* Negative values are relative to the stack top */
if (iSaveLevel < 0)
iSaveLevel = pdc->dclevel.lSaveDepth + iSaveLevel;
/* Check if we have a valid instance */
if (iSaveLevel <= 0 || iSaveLevel >= pdc->dclevel.lSaveDepth)
{
DPRINT("Illegal save level, requested: %ld, current: %ld\n",
iSaveLevel, pdc->dclevel.lSaveDepth);
DC_UnlockDc(pdc);
SetLastWin32Error(ERROR_INVALID_PARAMETER);
return FALSE;
}
/* Call the internal function */
DC_vRestoreDC(pdc, iSaveLevel);
DC_UnlockDc(pdc);
DPRINT("Leave NtGdiRestoreDC\n");
return TRUE;
}
INT
APIENTRY
NtGdiSaveDC(
HDC hDC)
{
HDC hdcSave;
PDC pdc, pdcSave;
INT lSaveDepth;
DPRINT("NtGdiSaveDC(%p)\n", hDC);
/* Lock the original dc */
pdc = DC_LockDc(hDC);
if (pdc == NULL)
{
DPRINT("Could not lock DC\n");
SetLastWin32Error(ERROR_INVALID_HANDLE);
return 0;
}
/* Allocate a new dc */
pdcSave = DC_AllocDcWithHandle();
if (pdcSave == NULL)
{
DPRINT("Could not allocate a new DC\n");
DC_UnlockDc(pdc);
return 0;
}
hdcSave = pdcSave->BaseObject.hHmgr;
InterlockedIncrement(&pdc->ppdev->cPdevRefs);
DC_vInitDc(pdcSave, DCTYPE_MEMORY, pdc->ppdev);
/* Make it a kernel handle
(FIXME: windows handles this different, see wiki)*/
GDIOBJ_SetOwnership(hdcSave, NULL);
/* Copy the current state */
DC_vCopyState(pdc, pdcSave, TRUE);
/* Copy path. FIXME: why this way? */
pdcSave->dclevel.hPath = pdc->dclevel.hPath;
pdcSave->dclevel.flPath = pdc->dclevel.flPath | DCPATH_SAVESTATE;
if (pdcSave->dclevel.hPath) pdcSave->dclevel.flPath |= DCPATH_SAVE;
/* Set new dc as save dc */
pdc->dclevel.hdcSave = hdcSave;
/* Increase save depth, return old value */
lSaveDepth = pdc->dclevel.lSaveDepth++;
/* Cleanup and return */
DC_UnlockDc(pdcSave);
DC_UnlockDc(pdc);
DPRINT("Leave NtGdiSaveDC: %ld, hdcSave = %p\n", lSaveDepth, hdcSave);
return lSaveDepth;
}