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