[Win32k]
[reactos.git] / reactos / 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)
17 {
18 /* Copy full DC attribute */
19 *pdcDst->pdcattr = *pdcSrc->pdcattr;
20
21 /* Get/SetDCState() don't change hVisRgn field ("Undoc. Windows" p.559). */
22 /* The VisRectRegion field needs to be set to a valid state */
23
24 /* Mark some fields as dirty */
25 pdcDst->pdcattr->ulDirty_ |= 0x0012001f;
26
27 /* Copy DC level */
28 pdcDst->dclevel.pColorSpace = pdcSrc->dclevel.pColorSpace;
29 pdcDst->dclevel.lSaveDepth = pdcSrc->dclevel.lSaveDepth;
30 pdcDst->dclevel.hdcSave = pdcSrc->dclevel.hdcSave;
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_vSelectSurface(pdcDst, pdcSrc->dclevel.pSurface);
43 DC_vSelectFillBrush(pdcDst, pdcSrc->dclevel.pbrFill);
44 DC_vSelectLineBrush(pdcDst, pdcSrc->dclevel.pbrLine);
45 DC_vSelectPalette(pdcDst, pdcSrc->dclevel.ppal);
46
47 // FIXME: handle refs
48 pdcDst->dclevel.plfnt = pdcSrc->dclevel.plfnt;
49
50 /* ROS hacks */
51 if (pdcDst->dctype != DC_TYPE_MEMORY)
52 {
53 pdcDst->rosdc.bitsPerPixel = pdcSrc->rosdc.bitsPerPixel;
54 }
55
56 GdiExtSelectClipRgn(pdcDst, pdcSrc->rosdc.hClipRgn, RGN_COPY);
57
58 }
59
60
61 BOOL FASTCALL
62 IntGdiCleanDC(HDC hDC)
63 {
64 PDC dc;
65 if (!hDC) return FALSE;
66 dc = DC_LockDc(hDC);
67 if (!dc) return FALSE;
68 // Clean the DC
69 if (defaultDCstate) DC_vCopyState(defaultDCstate, dc);
70
71 if (dc->dctype != DC_TYPE_MEMORY)
72 {
73 dc->rosdc.bitsPerPixel = defaultDCstate->rosdc.bitsPerPixel;
74 }
75
76 DC_UnlockDc(dc);
77
78 return TRUE;
79 }
80
81
82 BOOL
83 APIENTRY
84 NtGdiResetDC(
85 IN HDC hdc,
86 IN LPDEVMODEW pdm,
87 OUT PBOOL pbBanding,
88 IN OPTIONAL VOID *pDriverInfo2,
89 OUT VOID *ppUMdhpdev)
90 {
91 UNIMPLEMENTED;
92 return 0;
93 }
94
95
96 BOOL
97 APIENTRY
98 NtGdiRestoreDC(
99 HDC hdc,
100 INT iSaveLevel)
101 {
102 PDC pdc, pdcSave;
103 HDC hdcSave;
104 PEPROCESS pepCurrentProcess;
105
106 DPRINT("NtGdiRestoreDC(%lx, %d)\n", hdc, iSaveLevel);
107
108 /* Lock the original DC */
109 pdc = DC_LockDc(hdc);
110 if (!pdc)
111 {
112 SetLastWin32Error(ERROR_INVALID_HANDLE);
113 return FALSE;
114 }
115
116 ASSERT(pdc->dclevel.lSaveDepth > 0);
117
118 /* Negative values are relative to the stack top */
119 if (iSaveLevel < 0)
120 iSaveLevel = pdc->dclevel.lSaveDepth + iSaveLevel;
121
122 /* Check if we have a valid instance */
123 if (iSaveLevel <= 0 || iSaveLevel >= pdc->dclevel.lSaveDepth)
124 {
125 DPRINT("Illegal save level, requested: %ld, current: %ld\n",
126 iSaveLevel, pdc->dclevel.lSaveDepth);
127 DC_UnlockDc(pdc);
128 SetLastWin32Error(ERROR_INVALID_PARAMETER);
129 return FALSE;
130 }
131
132 /* Get current process */
133 pepCurrentProcess = PsGetCurrentProcess();
134
135 /* Loop the save levels */
136 while (pdc->dclevel.lSaveDepth > iSaveLevel)
137 {
138 hdcSave = pdc->dclevel.hdcSave;
139
140 /* Set us as the owner */
141 if (!GDIOBJ_SetOwnership(hdcSave, pepCurrentProcess))
142 {
143 /* Could not get ownership. That's bad! */
144 DPRINT1("Could not get ownership of saved DC (%p) for dc %p!\n",
145 hdcSave, hdc);
146 return FALSE;
147 }
148
149 /* Lock the saved dc */
150 pdcSave = DC_LockDc(hdcSave);
151 if (!pdcSave)
152 {
153 /* WTF? Internal error! */
154 DPRINT1("Could not lock the saved DC (%p) for dc %p!\n",
155 hdcSave, hdc);
156 DC_UnlockDc(pdc);
157 return FALSE;
158 }
159
160 /* Remove the saved dc from the queue */
161 pdc->dclevel.hdcSave = pdcSave->dclevel.hdcSave;
162
163 /* Decrement save level */
164 pdc->dclevel.lSaveDepth--;
165
166 /* Is this the state we want? */
167 if (pdc->dclevel.lSaveDepth == iSaveLevel)
168 {
169 /* Copy the state back */
170 DC_vCopyState(pdcSave, pdc);
171
172 // Restore Path by removing it, if the Save flag is set.
173 // BeginPath will takecare of the rest.
174 if (pdc->dclevel.hPath && pdc->dclevel.flPath & DCPATH_SAVE)
175 {
176 PATH_Delete(pdc->dclevel.hPath);
177 pdc->dclevel.hPath = 0;
178 pdc->dclevel.flPath &= ~DCPATH_SAVE;
179 }
180 }
181
182 /* Delete the saved dc */
183 GreDeleteObject(hdcSave);
184 }
185
186 DC_UnlockDc(pdc);
187
188 DPRINT("Leaving NtGdiRestoreDC\n");
189 return TRUE;
190 }
191
192
193 INT
194 APIENTRY
195 NtGdiSaveDC(
196 HDC hDC)
197 {
198 HDC hdcSave;
199 PDC pdc, pdcSave;
200 INT lSaveDepth;
201
202 DPRINT("NtGdiSaveDC(%lx)\n", hDC);
203
204 /* Lock the original dc */
205 pdc = DC_LockDc(hDC);
206 if (pdc == NULL)
207 {
208 DPRINT("Could not lock DC\n");
209 SetLastWin32Error(ERROR_INVALID_HANDLE);
210 return 0;
211 }
212
213 /* Allocate a new dc */
214 pdcSave = DC_AllocDC(NULL);
215 if (pdcSave == NULL)
216 {
217 DPRINT("Could not allocate a new DC\n");
218 DC_UnlockDc(pdc);
219 return 0;
220 }
221 hdcSave = pdcSave->BaseObject.hHmgr;
222
223 /* Make it a kernel handle
224 (FIXME: windows handles this different, see wiki)*/
225 GDIOBJ_SetOwnership(hdcSave, NULL);
226
227 /* Copy the current state */
228 DC_vCopyState(pdc, pdcSave);
229
230 /* Copy path. FIXME: why this way? */
231 pdcSave->dclevel.hPath = pdc->dclevel.hPath;
232 pdcSave->dclevel.flPath = pdc->dclevel.flPath | DCPATH_SAVESTATE;
233 if (pdcSave->dclevel.hPath) pdcSave->dclevel.flPath |= DCPATH_SAVE;
234
235 /* Set new dc as save dc */
236 pdc->dclevel.hdcSave = hdcSave;
237
238 /* Increase save depth, return old value */
239 lSaveDepth = pdc->dclevel.lSaveDepth++;
240
241 /* Cleanup and return */
242 DC_UnlockDc(pdcSave);
243 DC_UnlockDc(pdc);
244
245 DPRINT("Leave NtGdiSaveDC: %ld\n", lSaveDepth);
246 return lSaveDepth;
247 }
248