mirror of
https://github.com/reactos/reactos.git
synced 2024-08-28 22:28:36 +00:00
![Hermès Bélusca-Maïto](/assets/img/avatar_default.png)
The names of these new flags match the documented ones at https://reactos.org/wiki/Techwiki:Win32k/DC https://books.google.hr/books?id=-O92IIF1Bj4C&pg=PA197&lpg=PA197 and the gdikdx debug extension.
328 lines
9.2 KiB
C
328 lines
9.2 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS Win32k subsystem
|
|
* PURPOSE: Functions for saving and restoring dc states
|
|
* FILE: win32ss/gdi/ntgdi/dcstate.c
|
|
* PROGRAMER: Timo Kreuzer (timo.kreuzer@rectos.org)
|
|
*/
|
|
|
|
#include <win32k.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_ |= (DIRTY_FILL|DIRTY_LINE|DIRTY_TEXT|DIRTY_BACKGROUND|DIRTY_CHARSET|DC_ICM_NOT_CALIBRATED|DC_ICM_NOT_SET); // Note: Use if, To is FALSE....
|
|
|
|
/* Copy DC level */
|
|
pdcDst->dclevel.pColorSpace = pdcSrc->dclevel.pColorSpace;
|
|
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_vSelectFillBrush(pdcDst, pdcSrc->dclevel.pbrFill);
|
|
DC_vSelectLineBrush(pdcDst, pdcSrc->dclevel.pbrLine);
|
|
DC_vSelectPalette(pdcDst, pdcSrc->dclevel.ppal);
|
|
|
|
/* Dereference the old font, reference the new one */
|
|
if (pdcDst->dclevel.plfnt) LFONT_ShareUnlockFont(pdcDst->dclevel.plfnt); /// @todo should aways be != NULL
|
|
GDIOBJ_vReferenceObjectByPointer(&pdcSrc->dclevel.plfnt->BaseObject);
|
|
pdcDst->dclevel.plfnt = pdcSrc->dclevel.plfnt;
|
|
|
|
/* Get/SetDCState() don't change hVisRgn field ("Undoc. Windows" p.559). */
|
|
if (!To)
|
|
{
|
|
IntGdiExtSelectClipRgn(pdcDst, pdcSrc->dclevel.prgnClip, RGN_COPY);
|
|
if (pdcDst->dclevel.prgnMeta)
|
|
{
|
|
REGION_Delete(pdcDst->dclevel.prgnMeta);
|
|
pdcDst->dclevel.prgnMeta = NULL;
|
|
}
|
|
/* The only way to reset the Meta Region to its original state is to return to a previously saved version of the DC with SaveDC. */
|
|
if (pdcSrc->dclevel.prgnMeta)
|
|
{
|
|
pdcDst->dclevel.prgnMeta = IntSysCreateRectpRgn(0, 0, 0, 0);
|
|
IntGdiCombineRgn(pdcDst->dclevel.prgnMeta, pdcSrc->dclevel.prgnMeta, NULL, RGN_COPY);
|
|
}
|
|
pdcDst->fs |= DC_DIRTY_RAO;
|
|
}
|
|
}
|
|
|
|
|
|
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);
|
|
/* Update the brushes now, because they reference some objects (the DC palette)
|
|
* Which belong to the current process, and this DC might be used for another process
|
|
* after being cleaned up (for GetDC(0) for instance) */
|
|
DC_vUpdateFillBrush(dc);
|
|
DC_vUpdateBackgroundBrush(dc);
|
|
DC_vUpdateLineBrush(dc);
|
|
DC_vUpdateTextBrush(dc);
|
|
}
|
|
|
|
// Remove Path and reset flags.
|
|
if (dc->dclevel.hPath)
|
|
{
|
|
DPRINT("Clean DC Remove Path\n");
|
|
if (!PATH_Delete(dc->dclevel.hPath))
|
|
{
|
|
DPRINT1("Failed to remove Path\n");
|
|
}
|
|
dc->dclevel.hPath = 0;
|
|
dc->dclevel.flPath = 0;
|
|
}
|
|
|
|
/* DC_vCopyState frees the Clip rgn and the Meta rgn. Take care of the other ones
|
|
* There is no need to clear prgnVis, as UserGetDC updates it immediately. */
|
|
if (dc->prgnRao)
|
|
REGION_Delete(dc->prgnRao);
|
|
if (dc->prgnAPI)
|
|
REGION_Delete(dc->prgnAPI);
|
|
dc->prgnRao = dc->prgnAPI = NULL;
|
|
|
|
dc->fs |= DC_DIRTY_RAO;
|
|
|
|
DC_UnlockDc(dc);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
__kernel_entry
|
|
BOOL
|
|
APIENTRY
|
|
NtGdiResetDC(
|
|
_In_ HDC hdc,
|
|
_In_ LPDEVMODEW pdm,
|
|
_Out_ PBOOL pbBanding,
|
|
_In_opt_ DRIVER_INFO_2W *pDriverInfo2,
|
|
_At_((PUMDHPDEV*)ppUMdhpdev, _Out_) PVOID ppUMdhpdev)
|
|
{
|
|
/* According to a comment in Windows SDK the size of the buffer for
|
|
pdm is (pdm->dmSize + pdm->dmDriverExtra) */
|
|
UNIMPLEMENTED;
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
VOID
|
|
NTAPI
|
|
DC_vRestoreDC(
|
|
IN PDC pdc,
|
|
INT iSaveLevel)
|
|
{
|
|
HDC hdcSave;
|
|
PDC pdcSave;
|
|
|
|
NT_ASSERT(iSaveLevel > 0);
|
|
DPRINT("DC_vRestoreDC(%p, %ld)\n", pdc->BaseObject.hHmgr, iSaveLevel);
|
|
|
|
/* Loop the save levels */
|
|
while (pdc->dclevel.lSaveDepth > iSaveLevel)
|
|
{
|
|
hdcSave = pdc->dclevel.hdcSave;
|
|
DPRINT("RestoreDC = %p\n", hdcSave);
|
|
|
|
/* Set us as the owner */
|
|
if (!GreSetObjectOwner(hdcSave, GDI_OBJ_HMGR_POWNED))
|
|
{
|
|
/* Could not get ownership. That's bad! */
|
|
DPRINT1("Could not get ownership of saved DC (%p) for hdc %p!\n",
|
|
hdcSave, pdc->BaseObject.hHmgr);
|
|
NT_ASSERT(FALSE);
|
|
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);
|
|
NT_ASSERT(FALSE);
|
|
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);
|
|
|
|
/* Only memory DC's change their surface */
|
|
if (pdc->dctype == DCTYPE_MEMORY)
|
|
DC_vSelectSurface(pdc, pdcSave->dclevel.pSurface);
|
|
|
|
if (pdcSave->dclevel.hPath)
|
|
{
|
|
PATH_RestorePath( pdc, pdcSave );
|
|
}
|
|
}
|
|
|
|
/* Prevent save dc from being restored */
|
|
pdcSave->dclevel.lSaveDepth = 1;
|
|
|
|
/* Unlock it */
|
|
DC_UnlockDc(pdcSave);
|
|
/* 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)
|
|
{
|
|
EngSetLastError(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);
|
|
EngSetLastError(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");
|
|
EngSetLastError(ERROR_INVALID_HANDLE);
|
|
return 0;
|
|
}
|
|
|
|
/* Allocate a new dc */
|
|
pdcSave = DC_AllocDcWithHandle(GDILoObjType_LO_DC_TYPE);
|
|
if (pdcSave == NULL)
|
|
{
|
|
DPRINT("Could not allocate a new DC\n");
|
|
DC_UnlockDc(pdc);
|
|
return 0;
|
|
}
|
|
hdcSave = pdcSave->BaseObject.hHmgr;
|
|
|
|
PDEVOBJ_vReference(pdc->ppdev);
|
|
DC_vInitDc(pdcSave, DCTYPE_MEMORY, pdc->ppdev);
|
|
|
|
/* Handle references here correctly */
|
|
//pdcSrc->dclevel.pSurface = NULL;
|
|
//pdcSrc->dclevel.pbrFill = NULL;
|
|
//pdcSrc->dclevel.pbrLine = NULL;
|
|
//pdcSrc->dclevel.ppal = NULL;
|
|
|
|
/* Make it a kernel handle
|
|
(FIXME: Windows handles this differently, see Wiki) */
|
|
GDIOBJ_vSetObjectOwner(&pdcSave->BaseObject, GDI_OBJ_HMGR_PUBLIC);
|
|
|
|
/* Copy the current state */
|
|
DC_vCopyState(pdc, pdcSave, FALSE);
|
|
|
|
/* Only memory DC's change their surface */
|
|
if (pdc->dctype == DCTYPE_MEMORY)
|
|
DC_vSelectSurface(pdcSave, pdc->dclevel.pSurface);
|
|
|
|
/* Copy path */
|
|
if (pdc->dclevel.hPath)
|
|
{
|
|
PATH_SavePath( pdcSave, pdc );
|
|
}
|
|
pdcSave->dclevel.flPath = pdc->dclevel.flPath | DCPATH_SAVESTATE;
|
|
|
|
/* Set new dc as save dc */
|
|
pdcSave->dclevel.hdcSave = pdc->dclevel.hdcSave;
|
|
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;
|
|
}
|
|
|
|
/* EOF */
|