reactos/win32ss/gdi/ntgdi/dcstate.c
jimtabor 94b4b5c127 [NtGDI] Fix ExtSelectClipRgn Tests
Fix results from tests, add (last one) gdi batch support for
ExtSelectClipRgn. Left commented out test code in tree this time.
Pass Katayama Hirofumi MZ SelectClipRgn tests. After commit will plug in
the last batch. After 12 years.

See CORE-13817 and CORE-15906.
2019-05-09 12:33:21 -05:00

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_FLAG_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_FLAG_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;
InterlockedIncrement(&pdc->ppdev->cPdevRefs);
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 */