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