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