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