xref: /reactos/win32ss/gdi/ntgdi/dcstate.c (revision c2c66aff)
1 /*
2  * COPYRIGHT:         See COPYING in the top level directory
3  * PROJECT:           ReactOS Win32k subsystem
4  * PURPOSE:           Functions for saving and restoring dc states
5  * FILE:              win32ss/gdi/ntgdi/dcstate.c
6  * PROGRAMER:         Timo Kreuzer (timo.kreuzer@rectos.org)
7  */
8 
9 #include <win32k.h>
10 
11 #define NDEBUG
12 #include <debug.h>
13 
14 VOID
15 FASTCALL
16 DC_vCopyState(PDC pdcSrc, PDC pdcDst, BOOL To)
17 {
18     DPRINT("DC_vCopyState(%p, %p)\n", pdcSrc->BaseObject.hHmgr, pdcDst->BaseObject.hHmgr);
19 
20     /* Copy full DC attribute */
21     *pdcDst->pdcattr = *pdcSrc->pdcattr;
22 
23     /* Get/SetDCState() don't change hVisRgn field ("Undoc. Windows" p.559). */
24     /* The VisRectRegion field needs to be set to a valid state */
25 
26     /* Mark some fields as dirty */
27     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....
28 
29     /* Copy DC level */
30     pdcDst->dclevel.pColorSpace     = pdcSrc->dclevel.pColorSpace;
31     pdcDst->dclevel.laPath          = pdcSrc->dclevel.laPath;
32     pdcDst->dclevel.ca              = pdcSrc->dclevel.ca;
33     pdcDst->dclevel.mxWorldToDevice = pdcSrc->dclevel.mxWorldToDevice;
34     pdcDst->dclevel.mxDeviceToWorld = pdcSrc->dclevel.mxDeviceToWorld;
35     pdcDst->dclevel.mxWorldToPage   = pdcSrc->dclevel.mxWorldToPage;
36     pdcDst->dclevel.efM11PtoD       = pdcSrc->dclevel.efM11PtoD;
37     pdcDst->dclevel.efM22PtoD       = pdcSrc->dclevel.efM22PtoD;
38     pdcDst->dclevel.sizl            = pdcSrc->dclevel.sizl;
39     pdcDst->dclevel.hpal            = pdcSrc->dclevel.hpal;
40 
41     /* Handle references here correctly */
42     DC_vSelectFillBrush(pdcDst, pdcSrc->dclevel.pbrFill);
43     DC_vSelectLineBrush(pdcDst, pdcSrc->dclevel.pbrLine);
44     DC_vSelectPalette(pdcDst, pdcSrc->dclevel.ppal);
45 
46     /* Dereference the old font, reference the new one */
47     if (pdcDst->dclevel.plfnt) LFONT_ShareUnlockFont(pdcDst->dclevel.plfnt); /// @todo should aways be != NULL
48     GDIOBJ_vReferenceObjectByPointer(&pdcSrc->dclevel.plfnt->BaseObject);
49     pdcDst->dclevel.plfnt           = pdcSrc->dclevel.plfnt;
50 
51     /* Get/SetDCState() don't change hVisRgn field ("Undoc. Windows" p.559). */
52     if (!To)
53     {
54         IntGdiExtSelectClipRgn(pdcDst, pdcSrc->dclevel.prgnClip, RGN_COPY);
55         if (pdcDst->dclevel.prgnMeta)
56         {
57             REGION_Delete(pdcDst->dclevel.prgnMeta);
58             pdcDst->dclevel.prgnMeta = NULL;
59         }
60         if (pdcSrc->dclevel.prgnMeta)
61         {
62             pdcDst->dclevel.prgnMeta = IntSysCreateRectpRgn(0, 0, 0, 0);
63             IntGdiCombineRgn(pdcDst->dclevel.prgnMeta, pdcSrc->dclevel.prgnMeta, NULL, RGN_COPY);
64         }
65         pdcDst->fs |= DC_FLAG_DIRTY_RAO;
66     }
67 }
68 
69 
70 BOOL
71 FASTCALL
72 IntGdiCleanDC(HDC hDC)
73 {
74     PDC dc;
75     if (!hDC) return FALSE;
76     dc = DC_LockDc(hDC);
77     if (!dc) return FALSE;
78     // Clean the DC
79     if (defaultDCstate)
80     {
81         DC_vCopyState(defaultDCstate, dc, FALSE);
82         /* Update the brushes now, because they reference some objects (the DC palette)
83          * Which belong to the current process, and this DC might be used for another process
84          * after being cleaned up (for GetDC(0) for instance) */
85         DC_vUpdateFillBrush(dc);
86         DC_vUpdateBackgroundBrush(dc);
87         DC_vUpdateLineBrush(dc);
88         DC_vUpdateTextBrush(dc);
89     }
90 
91     // Remove Path and reset flags.
92     if (dc->dclevel.hPath)
93     {
94         DPRINT("Clean DC Remove Path\n");
95         if (!PATH_Delete(dc->dclevel.hPath))
96         {
97            DPRINT1("Failed to remove Path\n");
98         }
99         dc->dclevel.hPath = 0;
100         dc->dclevel.flPath = 0;
101     }
102 
103     /* DC_vCopyState frees the Clip rgn and the Meta rgn. Take care of the other ones
104      * There is no need to clear prgnVis, as UserGetDC updates it immediately. */
105     if (dc->prgnRao)
106         REGION_Delete(dc->prgnRao);
107     if (dc->prgnAPI)
108         REGION_Delete(dc->prgnAPI);
109     dc->prgnRao = dc->prgnAPI = NULL;
110 
111     dc->fs |= DC_FLAG_DIRTY_RAO;
112 
113     DC_UnlockDc(dc);
114 
115     return TRUE;
116 }
117 
118 __kernel_entry
119 BOOL
120 APIENTRY
121 NtGdiResetDC(
122     _In_ HDC hdc,
123     _In_ LPDEVMODEW pdm,
124     _Out_ PBOOL pbBanding,
125     _In_opt_ DRIVER_INFO_2W *pDriverInfo2,
126     _At_((PUMDHPDEV*)ppUMdhpdev, _Out_) PVOID ppUMdhpdev)
127 {
128     /* According to a comment in Windows SDK the size of the buffer for
129        pdm is (pdm->dmSize + pdm->dmDriverExtra) */
130     UNIMPLEMENTED;
131     return FALSE;
132 }
133 
134 
135 VOID
136 NTAPI
137 DC_vRestoreDC(
138     IN PDC pdc,
139     INT iSaveLevel)
140 {
141     HDC hdcSave;
142     PDC pdcSave;
143 
144     NT_ASSERT(iSaveLevel > 0);
145     DPRINT("DC_vRestoreDC(%p, %ld)\n", pdc->BaseObject.hHmgr, iSaveLevel);
146 
147     /* Loop the save levels */
148     while (pdc->dclevel.lSaveDepth > iSaveLevel)
149     {
150         hdcSave = pdc->dclevel.hdcSave;
151         DPRINT("RestoreDC = %p\n", hdcSave);
152 
153         /* Set us as the owner */
154         if (!GreSetObjectOwner(hdcSave, GDI_OBJ_HMGR_POWNED))
155         {
156             /* Could not get ownership. That's bad! */
157             DPRINT1("Could not get ownership of saved DC (%p) for hdc %p!\n",
158                     hdcSave, pdc->BaseObject.hHmgr);
159             NT_ASSERT(FALSE);
160             return;// FALSE;
161         }
162 
163         /* Lock the saved dc */
164         pdcSave = DC_LockDc(hdcSave);
165         if (!pdcSave)
166         {
167             /* WTF? Internal error! */
168             DPRINT1("Could not lock the saved DC (%p) for dc %p!\n",
169                     hdcSave, pdc->BaseObject.hHmgr);
170             NT_ASSERT(FALSE);
171             return;// FALSE;
172         }
173 
174         /* Remove the saved dc from the queue */
175         pdc->dclevel.hdcSave = pdcSave->dclevel.hdcSave;
176 
177         /* Decrement save level */
178         pdc->dclevel.lSaveDepth--;
179 
180         /* Is this the state we want? */
181         if (pdc->dclevel.lSaveDepth == iSaveLevel)
182         {
183             /* Copy the state back */
184             DC_vCopyState(pdcSave, pdc, FALSE);
185 
186             /* Only memory DC's change their surface */
187             if (pdc->dctype == DCTYPE_MEMORY)
188                 DC_vSelectSurface(pdc, pdcSave->dclevel.pSurface);
189 
190             if (pdcSave->dclevel.hPath)
191             {
192                PATH_RestorePath( pdc, pdcSave );
193             }
194         }
195 
196         /* Prevent save dc from being restored */
197         pdcSave->dclevel.lSaveDepth = 1;
198 
199         /* Unlock it */
200         DC_UnlockDc(pdcSave);
201         /* Delete the saved dc */
202         GreDeleteObject(hdcSave);
203     }
204 
205     DPRINT("Leave DC_vRestoreDC()\n");
206 }
207 
208 
209 
210 BOOL
211 APIENTRY
212 NtGdiRestoreDC(
213     HDC hdc,
214     INT iSaveLevel)
215 {
216     PDC pdc;
217 
218     DPRINT("NtGdiRestoreDC(%p, %d)\n", hdc, iSaveLevel);
219 
220     /* Lock the original DC */
221     pdc = DC_LockDc(hdc);
222     if (!pdc)
223     {
224         EngSetLastError(ERROR_INVALID_HANDLE);
225         return FALSE;
226     }
227 
228     ASSERT(pdc->dclevel.lSaveDepth > 0);
229 
230     /* Negative values are relative to the stack top */
231     if (iSaveLevel < 0)
232         iSaveLevel = pdc->dclevel.lSaveDepth + iSaveLevel;
233 
234     /* Check if we have a valid instance */
235     if (iSaveLevel <= 0 || iSaveLevel >= pdc->dclevel.lSaveDepth)
236     {
237         DPRINT("Illegal save level, requested: %ld, current: %ld\n",
238                iSaveLevel, pdc->dclevel.lSaveDepth);
239         DC_UnlockDc(pdc);
240         EngSetLastError(ERROR_INVALID_PARAMETER);
241         return FALSE;
242     }
243 
244     /* Call the internal function */
245     DC_vRestoreDC(pdc, iSaveLevel);
246 
247     DC_UnlockDc(pdc);
248 
249     DPRINT("Leave NtGdiRestoreDC\n");
250     return TRUE;
251 }
252 
253 
254 INT
255 APIENTRY
256 NtGdiSaveDC(
257     HDC hDC)
258 {
259     HDC hdcSave;
260     PDC pdc, pdcSave;
261     INT lSaveDepth;
262 
263     DPRINT("NtGdiSaveDC(%p)\n", hDC);
264 
265     /* Lock the original dc */
266     pdc = DC_LockDc(hDC);
267     if (pdc == NULL)
268     {
269         DPRINT("Could not lock DC\n");
270         EngSetLastError(ERROR_INVALID_HANDLE);
271         return 0;
272     }
273 
274     /* Allocate a new dc */
275     pdcSave = DC_AllocDcWithHandle(GDILoObjType_LO_DC_TYPE);
276     if (pdcSave == NULL)
277     {
278         DPRINT("Could not allocate a new DC\n");
279         DC_UnlockDc(pdc);
280         return 0;
281     }
282     hdcSave = pdcSave->BaseObject.hHmgr;
283 
284     InterlockedIncrement(&pdc->ppdev->cPdevRefs);
285     DC_vInitDc(pdcSave, DCTYPE_MEMORY, pdc->ppdev);
286 
287     /* Handle references here correctly */
288       //pdcSrc->dclevel.pSurface = NULL;
289       //pdcSrc->dclevel.pbrFill = NULL;
290       //pdcSrc->dclevel.pbrLine = NULL;
291       //pdcSrc->dclevel.ppal = NULL;
292 
293     /* Make it a kernel handle
294        (FIXME: Windows handles this differently, see Wiki) */
295     GDIOBJ_vSetObjectOwner(&pdcSave->BaseObject, GDI_OBJ_HMGR_PUBLIC);
296 
297     /* Copy the current state */
298     DC_vCopyState(pdc, pdcSave, FALSE);
299 
300     /* Only memory DC's change their surface */
301     if (pdc->dctype == DCTYPE_MEMORY)
302         DC_vSelectSurface(pdcSave, pdc->dclevel.pSurface);
303 
304     /* Copy path */
305     if (pdc->dclevel.hPath)
306     {
307        PATH_SavePath( pdcSave, pdc );
308     }
309     pdcSave->dclevel.flPath = pdc->dclevel.flPath | DCPATH_SAVESTATE;
310 
311     /* Set new dc as save dc */
312     pdcSave->dclevel.hdcSave = pdc->dclevel.hdcSave;
313     pdc->dclevel.hdcSave = hdcSave;
314 
315     /* Increase save depth, return old value */
316     lSaveDepth = pdc->dclevel.lSaveDepth++;
317 
318     /* Cleanup and return */
319     DC_UnlockDc(pdcSave);
320     DC_UnlockDc(pdc);
321 
322     DPRINT("Leave NtGdiSaveDC: %ld, hdcSave = %p\n", lSaveDepth, hdcSave);
323     return lSaveDepth;
324 }
325 
326 /* EOF */
327