[YAROTOWS] Reintegrate the branch. For a brighter future.
[reactos.git] / reactos / subsystems / win32 / win32k / objects / dcstate.c
index 3f10a70..889a873 100644 (file)
@@ -1,20 +1,22 @@
 /*
  * COPYRIGHT:         See COPYING in the top level directory
  * PROJECT:           ReactOS kernel
- * PURPOSE:           Functions for creation and destruction of DCs
+ * 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>
+#include <win32k.h>
 
 #define NDEBUG
 #include <debug.h>
 
 VOID
 FASTCALL
-DC_vCopyState(PDC pdcSrc, PDC pdcDst)
+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;
 
@@ -22,7 +24,7 @@ DC_vCopyState(PDC pdcSrc, PDC pdcDst)
     /* The VisRectRegion field needs to be set to a valid state */
 
     /* Mark some fields as dirty */
-    pdcDst->pdcattr->ulDirty_ |= 0x0012001f;
+    pdcDst->pdcattr->ulDirty_ |= 0x0012001f; // Note: Use if, To is FALSE....
 
     /* Copy DC level */
     pdcDst->dclevel.pColorSpace     = pdcSrc->dclevel.pColorSpace;
@@ -36,27 +38,30 @@ DC_vCopyState(PDC pdcSrc, PDC pdcDst)
     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.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)
+    /* Get/SetDCState() don't change hVisRgn field ("Undoc. Windows" p.559). */
+    if (To) // Copy "To" SaveDC state.
     {
-        pdcDst->rosdc.bitsPerPixel = pdcSrc->rosdc.bitsPerPixel;
+        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);
     }
-
-    GdiExtSelectClipRgn(pdcDst, pdcSrc->rosdc.hClipRgn, RGN_COPY);
-
 }
 
 
@@ -68,12 +73,7 @@ IntGdiCleanDC(HDC hDC)
     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 = defaultDCstate->rosdc.bitsPerPixel;
-    }
+    if (defaultDCstate) DC_vCopyState(defaultDCstate, dc, FALSE);
 
     DC_UnlockDc(dc);
 
@@ -95,41 +95,18 @@ NtGdiResetDC(
 }
 
 
-BOOL
-APIENTRY
-NtGdiRestoreDC(
-    HDC hdc,
+VOID
+NTAPI
+DC_vRestoreDC(
+    IN PDC pdc,
     INT iSaveLevel)
 {
-    PDC pdc, pdcSave;
-    HDC hdcSave;
     PEPROCESS pepCurrentProcess;
+    HDC hdcSave;
+    PDC pdcSave;
 
-    DPRINT("NtGdiRestoreDC(%lx, %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;
-    }
+    ASSERT(iSaveLevel > 0);
+    DPRINT("DC_vRestoreDC(%p, %ld)\n", pdc->BaseObject.hHmgr, iSaveLevel);
 
     /* Get current process */
     pepCurrentProcess = PsGetCurrentProcess();
@@ -138,14 +115,15 @@ NtGdiRestoreDC(
     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 dc %p!\n",
-                    hdcSave, hdc);
-            return FALSE;
+            DPRINT1("Could not get ownership of saved DC (%p) for hdc %p!\n",
+                    hdcSave, pdc->BaseObject.hHmgr);
+            return;// FALSE;
         }
 
         /* Lock the saved dc */
@@ -154,9 +132,8 @@ NtGdiRestoreDC(
         {
             /* WTF? Internal error! */
             DPRINT1("Could not lock the saved DC (%p) for dc %p!\n",
-                    hdcSave, hdc);
-            DC_UnlockDc(pdc);
-            return FALSE;
+                    hdcSave, pdc->BaseObject.hHmgr);
+            return;// FALSE;
         }
 
         /* Remove the saved dc from the queue */
@@ -169,7 +146,11 @@ NtGdiRestoreDC(
         if (pdc->dclevel.lSaveDepth == iSaveLevel)
         {
             /* Copy the state back */
-            DC_vCopyState(pdcSave, pdc);
+            DC_vCopyState(pdcSave, pdc, FALSE);
+
+            /* Only memory DC's change their surface */
+            if (pdc->dctype == DCTYPE_MEMORY)
+                DC_vSelectSurface(pdc, pdcSave->dclevel.pSurface);
 
             // Restore Path by removing it, if the Save flag is set.
             // BeginPath will takecare of the rest.
@@ -181,13 +162,60 @@ NtGdiRestoreDC(
             }
         }
 
+        /* Prevent save dc from being restored */
+        pdcSave->dclevel.lSaveDepth = 1;
+
+        /* Unlock it */
+        DC_UnlockDc(pdcSave);
         /* Delete the saved dc */
-        DC_FreeDC(hdcSave);
+        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("Leaving NtGdiRestoreDC\n");
+    DPRINT("Leave NtGdiRestoreDC\n");
     return TRUE;
 }
 
@@ -201,7 +229,7 @@ NtGdiSaveDC(
     PDC pdc, pdcSave;
     INT lSaveDepth;
 
-    DPRINT("NtGdiSaveDC(%lx)\n", hDC);
+    DPRINT("NtGdiSaveDC(%p)\n", hDC);
 
     /* Lock the original dc */
     pdc = DC_LockDc(hDC);
@@ -213,7 +241,7 @@ NtGdiSaveDC(
     }
 
     /* Allocate a new dc */
-    pdcSave = DC_AllocDC(NULL);
+    pdcSave = DC_AllocDcWithHandle();
     if (pdcSave == NULL)
     {
         DPRINT("Could not allocate a new DC\n");
@@ -222,12 +250,25 @@ NtGdiSaveDC(
     }
     hdcSave = pdcSave->BaseObject.hHmgr;
 
-    /* Make it a kernel handle 
+    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 different, see wiki)*/
     GDIOBJ_SetOwnership(hdcSave, NULL);
 
     /* Copy the current state */
-    DC_vCopyState(pdc, pdcSave);
+    DC_vCopyState(pdc, pdcSave, TRUE);
+
+    /* Only memory DC's change their surface */
+    if (pdc->dctype == DCTYPE_MEMORY)
+        DC_vSelectSurface(pdcSave, pdc->dclevel.pSurface);
 
     /* Copy path. FIXME: why this way? */
     pdcSave->dclevel.hPath = pdc->dclevel.hPath;
@@ -244,7 +285,7 @@ NtGdiSaveDC(
     DC_UnlockDc(pdcSave);
     DC_UnlockDc(pdc);
 
-    DPRINT("Leave NtGdiSaveDC: %ld\n", lSaveDepth);
+    DPRINT("Leave NtGdiSaveDC: %ld, hdcSave = %p\n", lSaveDepth, hdcSave);
     return lSaveDepth;
 }