mirror of
https://github.com/reactos/reactos.git
synced 2024-11-20 06:15:26 +00:00
94b4b5c127
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.
327 lines
9.2 KiB
C
327 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 */
|