* Sync up to trunk head (r65394).
[reactos.git] / win32ss / gdi / ntgdi / dcstate.c
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: subsystems/win32/win32k/objects/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.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 /* Dereference the old font, reference the new one */
49 if (pdcDst->dclevel.plfnt) LFONT_ShareUnlockFont(pdcDst->dclevel.plfnt); /// @todo should aways be != NULL
50 GDIOBJ_vReferenceObjectByPointer(&pdcSrc->dclevel.plfnt->BaseObject);
51 pdcDst->dclevel.plfnt = pdcSrc->dclevel.plfnt;
52
53 /* Get/SetDCState() don't change hVisRgn field ("Undoc. Windows" p.559). */
54 if (!To)
55 {
56 IntGdiExtSelectClipRgn(pdcDst, pdcSrc->dclevel.prgnClip, RGN_COPY);
57 if (pdcDst->dclevel.prgnMeta)
58 {
59 REGION_Delete(pdcDst->dclevel.prgnMeta);
60 pdcDst->dclevel.prgnMeta = NULL;
61 }
62 if (pdcSrc->dclevel.prgnMeta)
63 {
64 pdcDst->dclevel.prgnMeta = IntSysCreateRectpRgn(0, 0, 0, 0);
65 IntGdiCombineRgn(pdcDst->dclevel.prgnMeta, pdcSrc->dclevel.prgnMeta, NULL, RGN_COPY);
66 }
67 pdcDst->fs |= DC_FLAG_DIRTY_RAO;
68 }
69 }
70
71
72 BOOL
73 FASTCALL
74 IntGdiCleanDC(HDC hDC)
75 {
76 PDC dc;
77 if (!hDC) return FALSE;
78 dc = DC_LockDc(hDC);
79 if (!dc) return FALSE;
80 // Clean the DC
81 if (defaultDCstate)
82 {
83 DC_vCopyState(defaultDCstate, dc, FALSE);
84 /* Update the brushes now, because they reference some objects (the DC palette)
85 * Which belong to the current process, and this DC might be used for another process
86 * after being cleaned up (for GetDC(0) for instance) */
87 DC_vUpdateFillBrush(dc);
88 DC_vUpdateBackgroundBrush(dc);
89 DC_vUpdateLineBrush(dc);
90 DC_vUpdateTextBrush(dc);
91 }
92
93 /* DC_vCopyState frees the Clip rgn and the Meta rgn. Take care of the other ones
94 * There is no need to clear prgnVis, as UserGetDC updates it immediately. */
95 if (dc->prgnRao)
96 REGION_Delete(dc->prgnRao);
97 if (dc->prgnAPI)
98 REGION_Delete(dc->prgnAPI);
99 dc->prgnRao = dc->prgnAPI = NULL;
100
101 dc->fs |= DC_FLAG_DIRTY_RAO;
102
103 DC_UnlockDc(dc);
104
105 return TRUE;
106 }
107
108
109 BOOL
110 APIENTRY
111 NtGdiResetDC(
112 IN HDC hdc,
113 IN LPDEVMODEW pdm,
114 OUT PBOOL pbBanding,
115 IN OPTIONAL VOID *pDriverInfo2,
116 OUT VOID *ppUMdhpdev)
117 {
118 UNIMPLEMENTED;
119 return 0;
120 }
121
122
123 VOID
124 NTAPI
125 DC_vRestoreDC(
126 IN PDC pdc,
127 INT iSaveLevel)
128 {
129 HDC hdcSave;
130 PDC pdcSave;
131
132 ASSERT(iSaveLevel > 0);
133 DPRINT("DC_vRestoreDC(%p, %ld)\n", pdc->BaseObject.hHmgr, iSaveLevel);
134
135 /* Loop the save levels */
136 while (pdc->dclevel.lSaveDepth > iSaveLevel)
137 {
138 hdcSave = pdc->dclevel.hdcSave;
139 DPRINT("RestoreDC = %p\n", hdcSave);
140
141 /* Set us as the owner */
142 if (!GreSetObjectOwner(hdcSave, GDI_OBJ_HMGR_POWNED))
143 {
144 /* Could not get ownership. That's bad! */
145 DPRINT1("Could not get ownership of saved DC (%p) for hdc %p!\n",
146 hdcSave, pdc->BaseObject.hHmgr);
147 return;// FALSE;
148 }
149
150 /* Lock the saved dc */
151 pdcSave = DC_LockDc(hdcSave);
152 if (!pdcSave)
153 {
154 /* WTF? Internal error! */
155 DPRINT1("Could not lock the saved DC (%p) for dc %p!\n",
156 hdcSave, pdc->BaseObject.hHmgr);
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, FALSE);
171
172 /* Only memory DC's change their surface */
173 if (pdc->dctype == DCTYPE_MEMORY)
174 DC_vSelectSurface(pdc, pdcSave->dclevel.pSurface);
175
176 // Restore Path by removing it, if the Save flag is set.
177 // BeginPath will takecare of the rest.
178 if (pdc->dclevel.hPath && pdc->dclevel.flPath & DCPATH_SAVE)
179 {
180 PATH_Delete(pdc->dclevel.hPath);
181 pdc->dclevel.hPath = 0;
182 pdc->dclevel.flPath &= ~DCPATH_SAVE;
183 }
184 }
185
186 /* Prevent save dc from being restored */
187 pdcSave->dclevel.lSaveDepth = 1;
188
189 /* Unlock it */
190 DC_UnlockDc(pdcSave);
191 /* Delete the saved dc */
192 GreDeleteObject(hdcSave);
193 }
194
195 DPRINT("Leave DC_vRestoreDC()\n");
196 }
197
198
199
200 BOOL
201 APIENTRY
202 NtGdiRestoreDC(
203 HDC hdc,
204 INT iSaveLevel)
205 {
206 PDC pdc;
207
208 DPRINT("NtGdiRestoreDC(%p, %d)\n", hdc, iSaveLevel);
209
210 /* Lock the original DC */
211 pdc = DC_LockDc(hdc);
212 if (!pdc)
213 {
214 EngSetLastError(ERROR_INVALID_HANDLE);
215 return FALSE;
216 }
217
218 ASSERT(pdc->dclevel.lSaveDepth > 0);
219
220 /* Negative values are relative to the stack top */
221 if (iSaveLevel < 0)
222 iSaveLevel = pdc->dclevel.lSaveDepth + iSaveLevel;
223
224 /* Check if we have a valid instance */
225 if (iSaveLevel <= 0 || iSaveLevel >= pdc->dclevel.lSaveDepth)
226 {
227 DPRINT("Illegal save level, requested: %ld, current: %ld\n",
228 iSaveLevel, pdc->dclevel.lSaveDepth);
229 DC_UnlockDc(pdc);
230 EngSetLastError(ERROR_INVALID_PARAMETER);
231 return FALSE;
232 }
233
234 /* Call the internal function */
235 DC_vRestoreDC(pdc, iSaveLevel);
236
237 DC_UnlockDc(pdc);
238
239 DPRINT("Leave NtGdiRestoreDC\n");
240 return TRUE;
241 }
242
243
244 INT
245 APIENTRY
246 NtGdiSaveDC(
247 HDC hDC)
248 {
249 HDC hdcSave;
250 PDC pdc, pdcSave;
251 INT lSaveDepth;
252
253 DPRINT("NtGdiSaveDC(%p)\n", hDC);
254
255 /* Lock the original dc */
256 pdc = DC_LockDc(hDC);
257 if (pdc == NULL)
258 {
259 DPRINT("Could not lock DC\n");
260 EngSetLastError(ERROR_INVALID_HANDLE);
261 return 0;
262 }
263
264 /* Allocate a new dc */
265 pdcSave = DC_AllocDcWithHandle();
266 if (pdcSave == NULL)
267 {
268 DPRINT("Could not allocate a new DC\n");
269 DC_UnlockDc(pdc);
270 return 0;
271 }
272 hdcSave = pdcSave->BaseObject.hHmgr;
273
274 InterlockedIncrement(&pdc->ppdev->cPdevRefs);
275 DC_vInitDc(pdcSave, DCTYPE_MEMORY, pdc->ppdev);
276
277 /* Handle references here correctly */
278 //pdcSrc->dclevel.pSurface = NULL;
279 //pdcSrc->dclevel.pbrFill = NULL;
280 //pdcSrc->dclevel.pbrLine = NULL;
281 //pdcSrc->dclevel.ppal = NULL;
282
283 /* Make it a kernel handle
284 (FIXME: Windows handles this differently, see Wiki) */
285 GDIOBJ_vSetObjectOwner(&pdcSave->BaseObject, GDI_OBJ_HMGR_PUBLIC);
286
287 /* Copy the current state */
288 DC_vCopyState(pdc, pdcSave, FALSE);
289
290 /* Only memory DC's change their surface */
291 if (pdc->dctype == DCTYPE_MEMORY)
292 DC_vSelectSurface(pdcSave, pdc->dclevel.pSurface);
293
294 /* Copy path */
295 /* FIXME: Why this way? */
296 pdcSave->dclevel.hPath = pdc->dclevel.hPath;
297 pdcSave->dclevel.flPath = pdc->dclevel.flPath | DCPATH_SAVESTATE;
298 if (pdcSave->dclevel.hPath) pdcSave->dclevel.flPath |= DCPATH_SAVE;
299
300 /* Set new dc as save dc */
301 pdc->dclevel.hdcSave = hdcSave;
302
303 /* Increase save depth, return old value */
304 lSaveDepth = pdc->dclevel.lSaveDepth++;
305
306 /* Cleanup and return */
307 DC_UnlockDc(pdcSave);
308 DC_UnlockDc(pdc);
309
310 DPRINT("Leave NtGdiSaveDC: %ld, hdcSave = %p\n", lSaveDepth, hdcSave);
311 return lSaveDepth;
312 }
313
314 /* EOF */