xref: /reactos/win32ss/gdi/ntgdi/dcstate.c (revision 09dde2cf)
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         /* 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. */
61         if (pdcSrc->dclevel.prgnMeta)
62         {
63             pdcDst->dclevel.prgnMeta = IntSysCreateRectpRgn(0, 0, 0, 0);
64             IntGdiCombineRgn(pdcDst->dclevel.prgnMeta, pdcSrc->dclevel.prgnMeta, NULL, RGN_COPY);
65         }
66         pdcDst->fs |= DC_DIRTY_RAO;
67     }
68 }
69 
70 
71 BOOL
72 FASTCALL
73 IntGdiCleanDC(HDC hDC)
74 {
75     PDC dc;
76     if (!hDC) return FALSE;
77     dc = DC_LockDc(hDC);
78     if (!dc) return FALSE;
79     // Clean the DC
80     if (defaultDCstate)
81     {
82         DC_vCopyState(defaultDCstate, dc, FALSE);
83         /* Update the brushes now, because they reference some objects (the DC palette)
84          * Which belong to the current process, and this DC might be used for another process
85          * after being cleaned up (for GetDC(0) for instance) */
86         DC_vUpdateFillBrush(dc);
87         DC_vUpdateBackgroundBrush(dc);
88         DC_vUpdateLineBrush(dc);
89         DC_vUpdateTextBrush(dc);
90     }
91 
92     // Remove Path and reset flags.
93     if (dc->dclevel.hPath)
94     {
95         DPRINT("Clean DC Remove Path\n");
96         if (!PATH_Delete(dc->dclevel.hPath))
97         {
98            DPRINT1("Failed to remove Path\n");
99         }
100         dc->dclevel.hPath = 0;
101         dc->dclevel.flPath = 0;
102     }
103 
104     /* DC_vCopyState frees the Clip rgn and the Meta rgn. Take care of the other ones
105      * There is no need to clear prgnVis, as UserGetDC updates it immediately. */
106     if (dc->prgnRao)
107         REGION_Delete(dc->prgnRao);
108     if (dc->prgnAPI)
109         REGION_Delete(dc->prgnAPI);
110     dc->prgnRao = dc->prgnAPI = NULL;
111 
112     dc->fs |= DC_DIRTY_RAO;
113 
114     DC_UnlockDc(dc);
115 
116     return TRUE;
117 }
118 
119 __kernel_entry
120 BOOL
121 APIENTRY
122 NtGdiResetDC(
123     _In_ HDC hdc,
124     _In_ LPDEVMODEW pdm,
125     _Out_ PBOOL pbBanding,
126     _In_opt_ DRIVER_INFO_2W *pDriverInfo2,
127     _At_((PUMDHPDEV*)ppUMdhpdev, _Out_) PVOID ppUMdhpdev)
128 {
129     /* According to a comment in Windows SDK the size of the buffer for
130        pdm is (pdm->dmSize + pdm->dmDriverExtra) */
131     UNIMPLEMENTED;
132     return FALSE;
133 }
134 
135 
136 VOID
137 NTAPI
138 DC_vRestoreDC(
139     IN PDC pdc,
140     INT iSaveLevel)
141 {
142     HDC hdcSave;
143     PDC pdcSave;
144 
145     NT_ASSERT(iSaveLevel > 0);
146     DPRINT("DC_vRestoreDC(%p, %ld)\n", pdc->BaseObject.hHmgr, iSaveLevel);
147 
148     /* Loop the save levels */
149     while (pdc->dclevel.lSaveDepth > iSaveLevel)
150     {
151         hdcSave = pdc->dclevel.hdcSave;
152         DPRINT("RestoreDC = %p\n", hdcSave);
153 
154         /* Set us as the owner */
155         if (!GreSetObjectOwner(hdcSave, GDI_OBJ_HMGR_POWNED))
156         {
157             /* Could not get ownership. That's bad! */
158             DPRINT1("Could not get ownership of saved DC (%p) for hdc %p!\n",
159                     hdcSave, pdc->BaseObject.hHmgr);
160             NT_ASSERT(FALSE);
161             return;// FALSE;
162         }
163 
164         /* Lock the saved dc */
165         pdcSave = DC_LockDc(hdcSave);
166         if (!pdcSave)
167         {
168             /* WTF? Internal error! */
169             DPRINT1("Could not lock the saved DC (%p) for dc %p!\n",
170                     hdcSave, pdc->BaseObject.hHmgr);
171             NT_ASSERT(FALSE);
172             return;// FALSE;
173         }
174 
175         /* Remove the saved dc from the queue */
176         pdc->dclevel.hdcSave = pdcSave->dclevel.hdcSave;
177 
178         /* Decrement save level */
179         pdc->dclevel.lSaveDepth--;
180 
181         /* Is this the state we want? */
182         if (pdc->dclevel.lSaveDepth == iSaveLevel)
183         {
184             /* Copy the state back */
185             DC_vCopyState(pdcSave, pdc, FALSE);
186 
187             /* Only memory DC's change their surface */
188             if (pdc->dctype == DCTYPE_MEMORY)
189                 DC_vSelectSurface(pdc, pdcSave->dclevel.pSurface);
190 
191             if (pdcSave->dclevel.hPath)
192             {
193                PATH_RestorePath( pdc, pdcSave );
194             }
195         }
196 
197         /* Prevent save dc from being restored */
198         pdcSave->dclevel.lSaveDepth = 1;
199 
200         /* Unlock it */
201         DC_UnlockDc(pdcSave);
202         /* Delete the saved dc */
203         GreDeleteObject(hdcSave);
204     }
205 
206     DPRINT("Leave DC_vRestoreDC()\n");
207 }
208 
209 
210 
211 BOOL
212 APIENTRY
213 NtGdiRestoreDC(
214     HDC hdc,
215     INT iSaveLevel)
216 {
217     PDC pdc;
218 
219     DPRINT("NtGdiRestoreDC(%p, %d)\n", hdc, iSaveLevel);
220 
221     /* Lock the original DC */
222     pdc = DC_LockDc(hdc);
223     if (!pdc)
224     {
225         EngSetLastError(ERROR_INVALID_HANDLE);
226         return FALSE;
227     }
228 
229     ASSERT(pdc->dclevel.lSaveDepth > 0);
230 
231     /* Negative values are relative to the stack top */
232     if (iSaveLevel < 0)
233         iSaveLevel = pdc->dclevel.lSaveDepth + iSaveLevel;
234 
235     /* Check if we have a valid instance */
236     if (iSaveLevel <= 0 || iSaveLevel >= pdc->dclevel.lSaveDepth)
237     {
238         DPRINT("Illegal save level, requested: %ld, current: %ld\n",
239                iSaveLevel, pdc->dclevel.lSaveDepth);
240         DC_UnlockDc(pdc);
241         EngSetLastError(ERROR_INVALID_PARAMETER);
242         return FALSE;
243     }
244 
245     /* Call the internal function */
246     DC_vRestoreDC(pdc, iSaveLevel);
247 
248     DC_UnlockDc(pdc);
249 
250     DPRINT("Leave NtGdiRestoreDC\n");
251     return TRUE;
252 }
253 
254 
255 INT
256 APIENTRY
257 NtGdiSaveDC(
258     HDC hDC)
259 {
260     HDC hdcSave;
261     PDC pdc, pdcSave;
262     INT lSaveDepth;
263 
264     DPRINT("NtGdiSaveDC(%p)\n", hDC);
265 
266     /* Lock the original dc */
267     pdc = DC_LockDc(hDC);
268     if (pdc == NULL)
269     {
270         DPRINT("Could not lock DC\n");
271         EngSetLastError(ERROR_INVALID_HANDLE);
272         return 0;
273     }
274 
275     /* Allocate a new dc */
276     pdcSave = DC_AllocDcWithHandle(GDILoObjType_LO_DC_TYPE);
277     if (pdcSave == NULL)
278     {
279         DPRINT("Could not allocate a new DC\n");
280         DC_UnlockDc(pdc);
281         return 0;
282     }
283     hdcSave = pdcSave->BaseObject.hHmgr;
284 
285     PDEVOBJ_vReference(pdc->ppdev);
286     DC_vInitDc(pdcSave, DCTYPE_MEMORY, pdc->ppdev);
287 
288     /* Handle references here correctly */
289       //pdcSrc->dclevel.pSurface = NULL;
290       //pdcSrc->dclevel.pbrFill = NULL;
291       //pdcSrc->dclevel.pbrLine = NULL;
292       //pdcSrc->dclevel.ppal = NULL;
293 
294     /* Make it a kernel handle
295        (FIXME: Windows handles this differently, see Wiki) */
296     GDIOBJ_vSetObjectOwner(&pdcSave->BaseObject, GDI_OBJ_HMGR_PUBLIC);
297 
298     /* Copy the current state */
299     DC_vCopyState(pdc, pdcSave, FALSE);
300 
301     /* Only memory DC's change their surface */
302     if (pdc->dctype == DCTYPE_MEMORY)
303         DC_vSelectSurface(pdcSave, pdc->dclevel.pSurface);
304 
305     /* Copy path */
306     if (pdc->dclevel.hPath)
307     {
308        PATH_SavePath( pdcSave, pdc );
309     }
310     pdcSave->dclevel.flPath = pdc->dclevel.flPath | DCPATH_SAVESTATE;
311 
312     /* Set new dc as save dc */
313     pdcSave->dclevel.hdcSave = pdc->dclevel.hdcSave;
314     pdc->dclevel.hdcSave = hdcSave;
315 
316     /* Increase save depth, return old value */
317     lSaveDepth = pdc->dclevel.lSaveDepth++;
318 
319     /* Cleanup and return */
320     DC_UnlockDc(pdcSave);
321     DC_UnlockDc(pdc);
322 
323     DPRINT("Leave NtGdiSaveDC: %ld, hdcSave = %p\n", lSaveDepth, hdcSave);
324     return lSaveDepth;
325 }
326 
327 /* EOF */
328