Author: tkreuzer Date: Wed Mar 25 07:20:59 2009 New Revision: 40219
URL: http://svn.reactos.org/svn/reactos?rev=40219&view=rev Log: Rewrite the dc state saving implementation. We were doing it wrong and ugly. Now it should work correctly. It's also much fewer and cleaner code.
Modified: trunk/reactos/subsystems/win32/win32k/include/dc.h trunk/reactos/subsystems/win32/win32k/ntuser/windc.c trunk/reactos/subsystems/win32/win32k/objects/dclife.c trunk/reactos/subsystems/win32/win32k/objects/dcstate.c
Modified: trunk/reactos/subsystems/win32/win32k/include/dc.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/win32k/inc... ============================================================================== --- trunk/reactos/subsystems/win32/win32k/include/dc.h [iso-8859-1] (original) +++ trunk/reactos/subsystems/win32/win32k/include/dc.h [iso-8859-1] Wed Mar 25 07:20:59 2009 @@ -237,18 +237,15 @@ VOID FASTCALL DC_AllocateDcAttr(HDC); VOID FASTCALL DC_FreeDcAttr(HDC); BOOL INTERNAL_CALL DC_Cleanup(PVOID ObjectBody); -HDC FASTCALL DC_GetNextDC (PDC pDC); -VOID FASTCALL DC_SetNextDC (PDC pDC, HDC hNextDC); BOOL FASTCALL DC_SetOwnership(HDC DC, PEPROCESS Owner); VOID FASTCALL DC_LockDisplay(HDC); VOID FASTCALL DC_UnlockDisplay(HDC); -VOID FASTCALL IntGdiCopyFromSaveState(PDC, PDC, HDC); -VOID FASTCALL IntGdiCopyToSaveState(PDC, PDC); BOOL FASTCALL IntGdiDeleteDC(HDC, BOOL);
VOID FASTCALL DC_UpdateXforms(PDC dc); BOOL FASTCALL DC_InvertXform(const XFORM *xformSrc, XFORM *xformDest); VOID FASTCALL DC_vUpdateViewportExt(PDC pdc); +VOID FASTCALL DC_vCopyState(PDC pdcSrc, PDC pdcDst);
BOOL FASTCALL DCU_SyncDcAttrtoUser(PDC); BOOL FASTCALL DCU_SynchDcAttrtoUser(HDC);
Modified: trunk/reactos/subsystems/win32/win32k/ntuser/windc.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/win32k/ntu... ============================================================================== --- trunk/reactos/subsystems/win32/win32k/ntuser/windc.c [iso-8859-1] (original) +++ trunk/reactos/subsystems/win32/win32k/ntuser/windc.c [iso-8859-1] Wed Mar 25 07:20:59 2009 @@ -2,7 +2,7 @@ * PROJECT: ReactOS Kernel * LICENSE: GPL - See COPYING in the top level directory * FILE: subsystems/win32/win32k/ntuser/windc.c - * PURPOSE: Keyboard layout management + * PURPOSE: Window DC management * COPYRIGHT: Copyright 2007 ReactOS * */ @@ -45,7 +45,7 @@ defaultDCstate = ExAllocatePoolWithTag(PagedPool, sizeof(DC), TAG_DC); RtlZeroMemory(defaultDCstate, sizeof(DC)); defaultDCstate->pdcattr = &defaultDCstate->dcattr; - IntGdiCopyToSaveState(dc, defaultDCstate); + DC_vCopyState(dc, defaultDCstate); DC_UnlockDc( dc ); } return hDC;
Modified: trunk/reactos/subsystems/win32/win32k/objects/dclife.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/win32k/obj... ============================================================================== --- trunk/reactos/subsystems/win32/win32k/objects/dclife.c [iso-8859-1] (original) +++ trunk/reactos/subsystems/win32/win32k/objects/dclife.c [iso-8859-1] Wed Mar 25 07:20:59 2009 @@ -112,6 +112,8 @@
NewDC->dclevel.hpal = NtGdiGetStockObject(DEFAULT_PALETTE); NewDC->dclevel.laPath.eMiterLimit = 10.0; + + NewDC->dclevel.lSaveDepth = 1;
return NewDC; } @@ -419,7 +421,7 @@ } RtlZeroMemory(defaultDCstate, sizeof(DC)); defaultDCstate->pdcattr = &defaultDCstate->dcattr; - IntGdiCopyToSaveState(dc, defaultDCstate); + DC_vCopyState(dc, defaultDCstate); DC_UnlockDc(dc); } return hDC; @@ -448,7 +450,7 @@ }
/* First delete all saved DCs */ - while (DCToDelete->dclevel.lSaveDepth) + while (DCToDelete->dclevel.lSaveDepth > 1) { PDC savedDC; HDC savedHDC;
Modified: trunk/reactos/subsystems/win32/win32k/objects/dcstate.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/win32k/obj... ============================================================================== --- trunk/reactos/subsystems/win32/win32k/objects/dcstate.c [iso-8859-1] (original) +++ trunk/reactos/subsystems/win32/win32k/objects/dcstate.c [iso-8859-1] Wed Mar 25 07:20:59 2009 @@ -11,231 +11,73 @@ #define NDEBUG #include <debug.h>
- VOID FASTCALL -IntGdiCopyToSaveState(PDC dc, PDC newdc) -{ - PDC_ATTR pdcattr, nDc_Attr; - - pdcattr = dc->pdcattr; - nDc_Attr = newdc->pdcattr; - - newdc->dclevel.flPath = dc->dclevel.flPath | DCPATH_SAVESTATE; - - nDc_Attr->dwLayout = pdcattr->dwLayout; - nDc_Attr->hpen = pdcattr->hpen; - nDc_Attr->hbrush = pdcattr->hbrush; - nDc_Attr->hlfntNew = pdcattr->hlfntNew; - newdc->rosdc.hBitmap = dc->rosdc.hBitmap; - newdc->dclevel.hpal = dc->dclevel.hpal; - newdc->rosdc.bitsPerPixel = dc->rosdc.bitsPerPixel; - nDc_Attr->jROP2 = pdcattr->jROP2; - nDc_Attr->jFillMode = pdcattr->jFillMode; - nDc_Attr->jStretchBltMode = pdcattr->jStretchBltMode; - nDc_Attr->lRelAbs = pdcattr->lRelAbs; - nDc_Attr->jBkMode = pdcattr->jBkMode; - nDc_Attr->lBkMode = pdcattr->lBkMode; - nDc_Attr->crBackgroundClr = pdcattr->crBackgroundClr; - nDc_Attr->crForegroundClr = pdcattr->crForegroundClr; - nDc_Attr->ulBackgroundClr = pdcattr->ulBackgroundClr; - nDc_Attr->ulForegroundClr = pdcattr->ulForegroundClr; - nDc_Attr->ptlBrushOrigin = pdcattr->ptlBrushOrigin; - nDc_Attr->lTextAlign = pdcattr->lTextAlign; - nDc_Attr->lTextExtra = pdcattr->lTextExtra; - nDc_Attr->cBreak = pdcattr->cBreak; - nDc_Attr->lBreakExtra = pdcattr->lBreakExtra; - nDc_Attr->iMapMode = pdcattr->iMapMode; - nDc_Attr->iGraphicsMode = pdcattr->iGraphicsMode; -#if 0 - /* Apparently, the DC origin is not changed by [GS]etDCState */ - newdc->ptlDCOrig.x = dc->ptlDCOrig.x; - newdc->ptlDCOrig.y = dc->ptlDCOrig.y; -#endif - nDc_Attr->ptlCurrent = pdcattr->ptlCurrent; - nDc_Attr->ptfxCurrent = pdcattr->ptfxCurrent; - newdc->dclevel.mxWorldToDevice = dc->dclevel.mxWorldToDevice; - newdc->dclevel.mxDeviceToWorld = dc->dclevel.mxDeviceToWorld; - newdc->dclevel.mxWorldToPage = dc->dclevel.mxWorldToPage; - nDc_Attr->flXform = pdcattr->flXform; - nDc_Attr->ptlWindowOrg = pdcattr->ptlWindowOrg; - nDc_Attr->szlWindowExt = pdcattr->szlWindowExt; - nDc_Attr->ptlViewportOrg = pdcattr->ptlViewportOrg; - nDc_Attr->szlViewportExt = pdcattr->szlViewportExt; - - newdc->dclevel.lSaveDepth = 0; - newdc->dctype = dc->dctype; - -#if 0 - PATH_InitGdiPath(&newdc->dclevel.hPath); -#endif +DC_vCopyState(PDC pdcSrc, PDC pdcDst) +{ + /* Copy full DC attribute */ + *pdcDst->pdcattr = *pdcSrc->pdcattr;
/* Get/SetDCState() don't change hVisRgn field ("Undoc. Windows" p.559). */ - - newdc->rosdc.hGCClipRgn = newdc->rosdc.hVisRgn = 0; - if (dc->rosdc.hClipRgn) - { - newdc->rosdc.hClipRgn = NtGdiCreateRectRgn(0, 0, 0, 0); - NtGdiCombineRgn(newdc->rosdc.hClipRgn, dc->rosdc.hClipRgn, 0, RGN_COPY); - } -} - -// FIXME: why 2 different functions that do the same? -VOID -FASTCALL -IntGdiCopyFromSaveState(PDC dc, PDC dcs, HDC hDC) -{ - PDC_ATTR pdcattr, sDc_Attr; - - pdcattr = dc->pdcattr; - sDc_Attr = dcs->pdcattr; - - dc->dclevel.flPath = dcs->dclevel.flPath & ~DCPATH_SAVESTATE; - - pdcattr->dwLayout = sDc_Attr->dwLayout; - pdcattr->jROP2 = sDc_Attr->jROP2; - pdcattr->jFillMode = sDc_Attr->jFillMode; - pdcattr->jStretchBltMode = sDc_Attr->jStretchBltMode; - pdcattr->lRelAbs = sDc_Attr->lRelAbs; - pdcattr->jBkMode = sDc_Attr->jBkMode; - pdcattr->crBackgroundClr = sDc_Attr->crBackgroundClr; - pdcattr->crForegroundClr = sDc_Attr->crForegroundClr; - pdcattr->lBkMode = sDc_Attr->lBkMode; - pdcattr->ulBackgroundClr = sDc_Attr->ulBackgroundClr; - pdcattr->ulForegroundClr = sDc_Attr->ulForegroundClr; - pdcattr->ptlBrushOrigin = sDc_Attr->ptlBrushOrigin; - - pdcattr->lTextAlign = sDc_Attr->lTextAlign; - pdcattr->lTextExtra = sDc_Attr->lTextExtra; - pdcattr->cBreak = sDc_Attr->cBreak; - pdcattr->lBreakExtra = sDc_Attr->lBreakExtra; - pdcattr->iMapMode = sDc_Attr->iMapMode; - pdcattr->iGraphicsMode = sDc_Attr->iGraphicsMode; -#if 0 - /* Apparently, the DC origin is not changed by [GS]etDCState */ - dc->ptlDCOrig.x = dcs->ptlDCOrig.x; - dc->ptlDCOrig.y = dcs->ptlDCOrig.y; -#endif - pdcattr->ptlCurrent = sDc_Attr->ptlCurrent; - pdcattr->ptfxCurrent = sDc_Attr->ptfxCurrent; - dc->dclevel.mxWorldToDevice = dcs->dclevel.mxWorldToDevice; - dc->dclevel.mxDeviceToWorld = dcs->dclevel.mxDeviceToWorld; - dc->dclevel.mxWorldToPage = dcs->dclevel.mxWorldToPage; - pdcattr->flXform = sDc_Attr->flXform; - pdcattr->ptlWindowOrg = sDc_Attr->ptlWindowOrg; - pdcattr->szlWindowExt = sDc_Attr->szlWindowExt; - pdcattr->ptlViewportOrg = sDc_Attr->ptlViewportOrg; - pdcattr->szlViewportExt = sDc_Attr->szlViewportExt; + /* The VisRectRegion field needs to be set to a valid state */ + + /* Mark some fields as dirty */ + pdcDst->pdcattr->ulDirty_ |= 0x0012001f; + + /* 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; + + /* Handle references here correctly */ + DC_vSelectSurface(pdcDst, pdcSrc->dclevel.pSurface); + + // FIXME: handle refs + pdcDst->dclevel.hpal = pdcSrc->dclevel.hpal; + pdcDst->dclevel.ppal = pdcSrc->dclevel.ppal; + pdcDst->dclevel.pbrFill = pdcSrc->dclevel.pbrFill; + pdcDst->dclevel.pbrLine = pdcSrc->dclevel.pbrLine; + pdcDst->dclevel.plfnt = pdcSrc->dclevel.plfnt; + + /* ROS hacks */ + pdcDst->rosdc.hBitmap = pdcSrc->rosdc.hBitmap; + + if (pdcDst->dctype != DC_TYPE_MEMORY) + { + pdcDst->rosdc.bitsPerPixel = pdcSrc->rosdc.bitsPerPixel; + } + + 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);
if (dc->dctype != DC_TYPE_MEMORY) { - dc->rosdc.bitsPerPixel = dcs->rosdc.bitsPerPixel; - } - -#if 0 - if (dcs->rosdc.hClipRgn) - { - if (!dc->rosdc.hClipRgn) - { - dc->rosdc.hClipRgn = NtGdiCreateRectRgn(0, 0, 0, 0); - } - NtGdiCombineRgn(dc->rosdc.hClipRgn, dcs->rosdc.hClipRgn, 0, RGN_COPY); - } - else - { - if (dc->rosdc.hClipRgn) - { - NtGdiDeleteObject(dc->rosdc.hClipRgn); - } - dc->rosdc.hClipRgn = 0; - } - { - int res; - res = CLIPPING_UpdateGCRegion(dc); - ASSERT(res != ERROR); - } + dc->rosdc.bitsPerPixel = defaultDCstate->rosdc.bitsPerPixel; + } + DC_UnlockDc(dc); -#else - GdiExtSelectClipRgn(dc, dcs->rosdc.hClipRgn, RGN_COPY); - DC_UnlockDc(dc); -#endif - if (!hDC) return; // Not a MemoryDC or SaveLevel DC, return. - - NtGdiSelectBitmap(hDC, dcs->rosdc.hBitmap); - NtGdiSelectBrush(hDC, sDc_Attr->hbrush); - NtGdiSelectFont(hDC, sDc_Attr->hlfntNew); - NtGdiSelectPen(hDC, sDc_Attr->hpen); - - IntGdiSetBkColor(hDC, sDc_Attr->crBackgroundClr); - IntGdiSetTextColor(hDC, sDc_Attr->crForegroundClr); - - GdiSelectPalette(hDC, dcs->dclevel.hpal, FALSE); - -#if 0 - GDISelectPalette16(hDC, dcs->dclevel.hpal, FALSE); -#endif -} - -HDC APIENTRY -IntGdiGetDCState(HDC hDC) -{ - PDC pdcNew, pdc; - HDC hdcNew; - - pdc = DC_LockDc(hDC); - if (pdc == NULL) - { - SetLastWin32Error(ERROR_INVALID_HANDLE); - return 0; - } - - pdcNew = DC_AllocDC(NULL); - if (pdcNew == NULL) - { - DC_UnlockDc(pdc); - return 0; - } - hdcNew = pdcNew->BaseObject.hHmgr; - - pdcNew->dclevel.hdcSave = hdcNew; - IntGdiCopyToSaveState(pdc, pdcNew); - - DC_UnlockDc(pdcNew); - DC_UnlockDc(pdc); - - return hdcNew; -} - -VOID -APIENTRY -IntGdiSetDCState(HDC hDC, HDC hDCSave) -{ - PDC dc, dcs; - - dc = DC_LockDc(hDC); - if (dc) - { - dcs = DC_LockDc(hDCSave); - if (dcs) - { - if (dcs->dclevel.flPath & DCPATH_SAVESTATE) - { - IntGdiCopyFromSaveState(dc, dcs, dc->dclevel.hdcSave); - } - else - { - DC_UnlockDc(dc); - } - DC_UnlockDc(dcs); - } - else - { - DC_UnlockDc(dc); - SetLastWin32Error(ERROR_INVALID_HANDLE); - } - } - else - SetLastWin32Error(ERROR_INVALID_HANDLE); + + return TRUE; }
@@ -252,132 +94,157 @@ return 0; }
-BOOL APIENTRY + +BOOL +APIENTRY NtGdiRestoreDC( - HDC hDC, - INT SaveLevel) -{ - PDC dc, dcs; - BOOL success; - - DPRINT("NtGdiRestoreDC(%lx, %d)\n", hDC, SaveLevel); - - dc = DC_LockDc(hDC); - if (!dc) + HDC hdc, + INT iSaveLevel) +{ + PDC pdc, pdcSave; + HDC hdcSave; + PEPROCESS pepCurrentProcess; + + DPRINT("NtGdiRestoreDC(%lx, %d)\n", hdc, iSaveLevel); + + /* Lock the original DC */ + pdc = DC_LockDc(hdc); + if (!pdc) { SetLastWin32Error(ERROR_INVALID_HANDLE); return FALSE; }
- if (SaveLevel < 0) - SaveLevel = dc->dclevel.lSaveDepth + SaveLevel + 1; - - if (SaveLevel < 0 || dc->dclevel.lSaveDepth<SaveLevel) - { - DC_UnlockDc(dc); + 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; }
- success=TRUE; - while (dc->dclevel.lSaveDepth >= SaveLevel) - { - HDC hdcs = dc->hdcNext; - - dcs = DC_LockDc(hdcs); - if (dcs == NULL) + /* Get current process */ + pepCurrentProcess = PsGetCurrentProcess(); + + /* Loop the save levels */ + while (pdc->dclevel.lSaveDepth > iSaveLevel) + { + hdcSave = pdc->dclevel.hdcSave; + + /* Set us as the owner */ + if (!GDIOBJ_SetOwnership(hdcSave, pepCurrentProcess)) { - DC_UnlockDc(dc); + /* Could not get ownership. That's bad! */ + DPRINT1("Could not get ownership of saved DC (%p) for dc %p!\n", + hdcSave, hdc); return FALSE; }
- dc->hdcNext = dcs->hdcNext; - dcs->hdcNext = 0; - - if (--dc->dclevel.lSaveDepth < SaveLevel) + /* Lock the saved dc */ + pdcSave = DC_LockDc(hdcSave); + if (!pdcSave) { - DC_UnlockDc(dc); - DC_UnlockDc(dcs); - - IntGdiSetDCState(hDC, hdcs); - - dc = DC_LockDc(hDC); - if (!dc) - { - return FALSE; - } + /* WTF? Internal error! */ + DPRINT1("Could not lock the saved DC (%p) for dc %p!\n", + hdcSave, hdc); + DC_UnlockDc(pdc); + 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); + // Restore Path by removing it, if the Save flag is set. // BeginPath will takecare of the rest. - if (dc->dclevel.hPath && dc->dclevel.flPath & DCPATH_SAVE) + if (pdc->dclevel.hPath && pdc->dclevel.flPath & DCPATH_SAVE) { - PATH_Delete(dc->dclevel.hPath); - dc->dclevel.hPath = 0; - dc->dclevel.flPath &= ~DCPATH_SAVE; + PATH_Delete(pdc->dclevel.hPath); + pdc->dclevel.hPath = 0; + pdc->dclevel.flPath &= ~DCPATH_SAVE; } } - else - { - DC_UnlockDc(dcs); - } - NtGdiDeleteObjectApp(hdcs); - } - DC_UnlockDc(dc); - return success; -} - - -INT APIENTRY + + /* Delete the saved dc */ + DC_FreeDC(hdcSave); + } + + DC_UnlockDc(pdc); + + DPRINT("Leaving NtGdiRestoreDC\n"); + return TRUE; +} + + +INT +APIENTRY NtGdiSaveDC( HDC hDC) { - HDC hdcs; - PDC dc, dcs; - INT ret; + HDC hdcSave; + PDC pdc, pdcSave; + INT lSaveDepth;
DPRINT("NtGdiSaveDC(%lx)\n", hDC);
- if (!(hdcs = IntGdiGetDCState(hDC))) - { - return 0; - } - - dcs = DC_LockDc(hdcs); - if (dcs == NULL) - { + /* Lock the original dc */ + pdc = DC_LockDc(hDC); + if (pdc == NULL) + { + DPRINT("Could not lock DC\n"); SetLastWin32Error(ERROR_INVALID_HANDLE); return 0; } - dc = DC_LockDc(hDC); - if (dc == NULL) - { - DC_UnlockDc(dcs); - SetLastWin32Error(ERROR_INVALID_HANDLE); + + /* Allocate a new dc */ + pdcSave = DC_AllocDC(NULL); + if (pdcSave == NULL) + { + DPRINT("Could not allocate a new DC\n"); + DC_UnlockDc(pdc); return 0; } - - /* - * Copy path. - */ - dcs->dclevel.hPath = dc->dclevel.hPath; - if (dcs->dclevel.hPath) dcs->dclevel.flPath |= DCPATH_SAVE; - - dcs->hdcNext = dc->hdcNext; - dc->hdcNext = hdcs; - ret = ++dc->dclevel.lSaveDepth; - DC_UnlockDc(dcs); - DC_UnlockDc(dc); - - return ret; -} - -BOOL FASTCALL -IntGdiCleanDC(HDC hDC) -{ - PDC dc; - if (!hDC) return FALSE; - dc = DC_LockDc(hDC); - if (!dc) return FALSE; - // Clean the DC - if (defaultDCstate) IntGdiCopyFromSaveState(dc, defaultDCstate, hDC); - return TRUE; -} - + hdcSave = pdcSave->BaseObject.hHmgr; + + /* Make it a kernel handle + (FIXME: windows handles this different, see wiki)*/ + GDIOBJ_SetOwnership(hdcSave, NULL); + + /* Copy the current state */ + DC_vCopyState(pdc, pdcSave); + + /* 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\n", lSaveDepth); + return lSaveDepth; +} +