3e2693fec2c257306fbe2bfee2ec339a20853632
[reactos.git] / subsystems / win32 / win32k / objects / dcstate.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Functions for saving and restoring dc states
5 * FILE: subsystem/win32/win32k/objects/dcstate.c
6 * PROGRAMER: Timo Kreuzer (timo.kreuzer@rectos.org)
7 */
8
9 #include <w32k.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_ |= 0x0012001f; // Note: Use if, To is FALSE....
28
29 /* Copy DC level */
30 pdcDst->dclevel.pColorSpace = pdcSrc->dclevel.pColorSpace;
31 pdcDst->dclevel.lSaveDepth = pdcSrc->dclevel.lSaveDepth;
32 pdcDst->dclevel.hdcSave = pdcSrc->dclevel.hdcSave;
33 pdcDst->dclevel.laPath = pdcSrc->dclevel.laPath;
34 pdcDst->dclevel.ca = pdcSrc->dclevel.ca;
35 pdcDst->dclevel.mxWorldToDevice = pdcSrc->dclevel.mxWorldToDevice;
36 pdcDst->dclevel.mxDeviceToWorld = pdcSrc->dclevel.mxDeviceToWorld;
37 pdcDst->dclevel.mxWorldToPage = pdcSrc->dclevel.mxWorldToPage;
38 pdcDst->dclevel.efM11PtoD = pdcSrc->dclevel.efM11PtoD;
39 pdcDst->dclevel.efM22PtoD = pdcSrc->dclevel.efM22PtoD;
40 pdcDst->dclevel.sizl = pdcSrc->dclevel.sizl;
41 pdcDst->dclevel.hpal = pdcSrc->dclevel.hpal;
42
43 /* Handle references here correctly */
44 DC_vSelectSurface(pdcDst, pdcSrc->dclevel.pSurface);
45 DC_vSelectFillBrush(pdcDst, pdcSrc->dclevel.pbrFill);
46 DC_vSelectLineBrush(pdcDst, pdcSrc->dclevel.pbrLine);
47 DC_vSelectPalette(pdcDst, pdcSrc->dclevel.ppal);
48
49 // FIXME: handle refs
50 pdcDst->dclevel.plfnt = pdcSrc->dclevel.plfnt;
51
52 /* ROS hacks */
53 if (pdcDst->dctype != DC_TYPE_MEMORY)
54 {
55 pdcDst->rosdc.bitsPerPixel = pdcSrc->rosdc.bitsPerPixel;
56 }
57
58 /* Get/SetDCState() don't change hVisRgn field ("Undoc. Windows" p.559). */
59 if (To) // Copy "To" SaveDC state.
60 {
61 if (pdcSrc->rosdc.hClipRgn)
62 {
63 pdcDst->rosdc.hClipRgn = IntSysCreateRectRgn(0, 0, 0, 0);
64 NtGdiCombineRgn(pdcDst->rosdc.hClipRgn, pdcSrc->rosdc.hClipRgn, 0, RGN_COPY);
65 }
66 // FIXME! Handle prgnMeta!
67 }
68 else // Copy "!To" RestoreDC state.
69 { /* The VisRectRegion field needs to be set to a valid state */
70 GdiExtSelectClipRgn(pdcDst, pdcSrc->rosdc.hClipRgn, RGN_COPY);
71 }
72 }
73
74
75 BOOL FASTCALL
76 IntGdiCleanDC(HDC hDC)
77 {
78 PDC dc;
79 if (!hDC) return FALSE;
80 dc = DC_LockDc(hDC);
81 if (!dc) return FALSE;
82 // Clean the DC
83 if (defaultDCstate) DC_vCopyState(defaultDCstate, dc, FALSE);
84
85 if (dc->dctype != DC_TYPE_MEMORY)
86 {
87 dc->rosdc.bitsPerPixel = defaultDCstate->rosdc.bitsPerPixel;
88 }
89
90 DC_UnlockDc(dc);
91
92 return TRUE;
93 }
94
95
96 BOOL
97 APIENTRY
98 NtGdiResetDC(
99 IN HDC hdc,
100 IN LPDEVMODEW pdm,
101 OUT PBOOL pbBanding,
102 IN OPTIONAL VOID *pDriverInfo2,
103 OUT VOID *ppUMdhpdev)
104 {
105 UNIMPLEMENTED;
106 return 0;
107 }
108
109
110 VOID
111 NTAPI
112 DC_vRestoreDC(
113 IN PDC pdc,
114 INT iSaveLevel)
115 {
116 PEPROCESS pepCurrentProcess;
117 HDC hdcSave;
118 PDC pdcSave;
119
120 ASSERT(iSaveLevel > 0);
121 DPRINT("DC_vRestoreDC(%p, %ld)\n", pdc->BaseObject.hHmgr, iSaveLevel);
122
123 /* Get current process */
124 pepCurrentProcess = PsGetCurrentProcess();
125
126 /* Loop the save levels */
127 while (pdc->dclevel.lSaveDepth > iSaveLevel)
128 {
129 hdcSave = pdc->dclevel.hdcSave;
130 DPRINT("RestoreDC = %p\n", hdcSave);
131
132 /* Set us as the owner */
133 if (!GDIOBJ_SetOwnership(hdcSave, pepCurrentProcess))
134 {
135 /* Could not get ownership. That's bad! */
136 DPRINT1("Could not get ownership of saved DC (%p) for hdc %p!\n",
137 hdcSave, pdc->BaseObject.hHmgr);
138 return;// FALSE;
139 }
140
141 /* Lock the saved dc */
142 pdcSave = DC_LockDc(hdcSave);
143 if (!pdcSave)
144 {
145 /* WTF? Internal error! */
146 DPRINT1("Could not lock the saved DC (%p) for dc %p!\n",
147 hdcSave, pdc->BaseObject.hHmgr);
148 DC_UnlockDc(pdc);
149 return;// FALSE;
150 }
151
152 /* Remove the saved dc from the queue */
153 pdc->dclevel.hdcSave = pdcSave->dclevel.hdcSave;
154
155 /* Decrement save level */
156 pdc->dclevel.lSaveDepth--;
157
158 /* Is this the state we want? */
159 if (pdc->dclevel.lSaveDepth == iSaveLevel)
160 {
161 /* Copy the state back */
162 DC_vCopyState(pdcSave, pdc, FALSE);
163
164 // Restore Path by removing it, if the Save flag is set.
165 // BeginPath will takecare of the rest.
166 if (pdc->dclevel.hPath && pdc->dclevel.flPath & DCPATH_SAVE)
167 {
168 PATH_Delete(pdc->dclevel.hPath);
169 pdc->dclevel.hPath = 0;
170 pdc->dclevel.flPath &= ~DCPATH_SAVE;
171 }
172 }
173
174 /* Prevent save dc from being restored */
175 pdcSave->dclevel.lSaveDepth = 1;
176
177 /* Delete the saved dc */
178 GreDeleteObject(hdcSave);
179 }
180
181 DPRINT("Leave DC_vRestoreDC()\n");
182 }
183
184
185
186 BOOL
187 APIENTRY
188 NtGdiRestoreDC(
189 HDC hdc,
190 INT iSaveLevel)
191 {
192 PDC pdc;
193
194 DPRINT("NtGdiRestoreDC(%p, %d)\n", hdc, iSaveLevel);
195
196 /* Lock the original DC */
197 pdc = DC_LockDc(hdc);
198 if (!pdc)
199 {
200 SetLastWin32Error(ERROR_INVALID_HANDLE);
201 return FALSE;
202 }
203
204 ASSERT(pdc->dclevel.lSaveDepth > 0);
205
206 /* Negative values are relative to the stack top */
207 if (iSaveLevel < 0)
208 iSaveLevel = pdc->dclevel.lSaveDepth + iSaveLevel;
209
210 /* Check if we have a valid instance */
211 if (iSaveLevel <= 0 || iSaveLevel >= pdc->dclevel.lSaveDepth)
212 {
213 DPRINT("Illegal save level, requested: %ld, current: %ld\n",
214 iSaveLevel, pdc->dclevel.lSaveDepth);
215 DC_UnlockDc(pdc);
216 SetLastWin32Error(ERROR_INVALID_PARAMETER);
217 return FALSE;
218 }
219
220 /* Call the internal function */
221 DC_vRestoreDC(pdc, iSaveLevel);
222
223 DC_UnlockDc(pdc);
224
225 DPRINT("Leave NtGdiRestoreDC\n");
226 return TRUE;
227 }
228
229
230 INT
231 APIENTRY
232 NtGdiSaveDC(
233 HDC hDC)
234 {
235 HDC hdcSave;
236 PDC pdc, pdcSave;
237 INT lSaveDepth;
238
239 DPRINT("NtGdiSaveDC(%p)\n", hDC);
240
241 /* Lock the original dc */
242 pdc = DC_LockDc(hDC);
243 if (pdc == NULL)
244 {
245 DPRINT("Could not lock DC\n");
246 SetLastWin32Error(ERROR_INVALID_HANDLE);
247 return 0;
248 }
249
250 /* Allocate a new dc */
251 pdcSave = DC_AllocDcWithHandle();
252 if (pdcSave == NULL)
253 {
254 DPRINT("Could not allocate a new DC\n");
255 DC_UnlockDc(pdc);
256 return 0;
257 }
258 hdcSave = pdcSave->BaseObject.hHmgr;
259
260 InterlockedIncrement(&pdc->ppdev->cPdevRefs);
261 DC_vInitDc(pdcSave, DCTYPE_MEMORY, pdc->ppdev);
262
263 /* Make it a kernel handle
264 (FIXME: windows handles this different, see wiki)*/
265 GDIOBJ_SetOwnership(hdcSave, NULL);
266
267 /* Copy the current state */
268 DC_vCopyState(pdc, pdcSave, TRUE);
269
270 /* Copy path. FIXME: why this way? */
271 pdcSave->dclevel.hPath = pdc->dclevel.hPath;
272 pdcSave->dclevel.flPath = pdc->dclevel.flPath | DCPATH_SAVESTATE;
273 if (pdcSave->dclevel.hPath) pdcSave->dclevel.flPath |= DCPATH_SAVE;
274
275 /* Set new dc as save dc */
276 pdc->dclevel.hdcSave = hdcSave;
277
278 /* Increase save depth, return old value */
279 lSaveDepth = pdc->dclevel.lSaveDepth++;
280
281 /* Cleanup and return */
282 DC_UnlockDc(pdcSave);
283 DC_UnlockDc(pdc);
284
285 DPRINT("Leave NtGdiSaveDC: %ld, hdcSave = %p\n", lSaveDepth, hdcSave);
286 return lSaveDepth;
287 }
288