[Win32k]
[reactos.git] / reactos / subsystems / win32 / win32k / objects / dcattr.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Functions for creation and destruction of DCs
5 * FILE: subsystem/win32/win32k/objects/dcattr.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
15 #define GDIDCATTRFREE 8
16
17 typedef struct _GDI_DC_ATTR_FREELIST
18 {
19 LIST_ENTRY Entry;
20 DWORD nEntries;
21 PVOID AttrList[GDIDCATTRFREE];
22 } GDI_DC_ATTR_FREELIST, *PGDI_DC_ATTR_FREELIST;
23
24 typedef struct _GDI_DC_ATTR_ENTRY
25 {
26 DC_ATTR Attr[GDIDCATTRFREE];
27 } GDI_DC_ATTR_ENTRY, *PGDI_DC_ATTR_ENTRY;
28
29
30 PDC_ATTR
31 FASTCALL
32 AllocateDcAttr(VOID)
33 {
34 PTHREADINFO pti;
35 PPROCESSINFO ppi;
36 PDC_ATTR pDc_Attr;
37 PGDI_DC_ATTR_FREELIST pGdiDcAttrFreeList;
38 PGDI_DC_ATTR_ENTRY pGdiDcAttrEntry;
39 int i;
40
41 pti = PsGetCurrentThreadWin32Thread();
42 if (pti->pgdiDcattr)
43 {
44 pDc_Attr = pti->pgdiDcattr; // Get the free one.
45 pti->pgdiDcattr = NULL;
46 return pDc_Attr;
47 }
48
49 ppi = PsGetCurrentProcessWin32Process();
50
51 if (!ppi->pDCAttrList) // If set point is null, allocate new group.
52 {
53 pGdiDcAttrEntry = EngAllocUserMem(sizeof(GDI_DC_ATTR_ENTRY), 0);
54
55 if (!pGdiDcAttrEntry)
56 {
57 DPRINT1("DcAttr Failed User Allocation!\n");
58 return NULL;
59 }
60
61 DPRINT("AllocDcAttr User 0x%x\n",pGdiDcAttrEntry);
62
63 pGdiDcAttrFreeList = ExAllocatePoolWithTag( PagedPool,
64 sizeof(GDI_DC_ATTR_FREELIST),
65 GDITAG_DC_FREELIST);
66 if ( !pGdiDcAttrFreeList )
67 {
68 EngFreeUserMem(pGdiDcAttrEntry);
69 return NULL;
70 }
71
72 RtlZeroMemory(pGdiDcAttrFreeList, sizeof(GDI_DC_ATTR_FREELIST));
73
74 DPRINT("AllocDcAttr Ex 0x%x\n",pGdiDcAttrFreeList);
75
76 InsertHeadList( &ppi->GDIDcAttrFreeList, &pGdiDcAttrFreeList->Entry);
77
78 pGdiDcAttrFreeList->nEntries = GDIDCATTRFREE;
79 // Start at the bottom up and set end of free list point.
80 ppi->pDCAttrList = &pGdiDcAttrEntry->Attr[GDIDCATTRFREE-1];
81 // Build the free attr list.
82 for ( i = 0; i < GDIDCATTRFREE; i++)
83 {
84 pGdiDcAttrFreeList->AttrList[i] = &pGdiDcAttrEntry->Attr[i];
85 }
86 }
87
88 pDc_Attr = ppi->pDCAttrList;
89 pGdiDcAttrFreeList = (PGDI_DC_ATTR_FREELIST)ppi->GDIDcAttrFreeList.Flink;
90
91 // Free the list when it is full!
92 if ( pGdiDcAttrFreeList->nEntries-- == 1)
93 { // No more free entries, so yank the list.
94 RemoveEntryList( &pGdiDcAttrFreeList->Entry );
95
96 ExFreePoolWithTag( pGdiDcAttrFreeList, GDITAG_DC_FREELIST );
97
98 if ( IsListEmpty( &ppi->GDIDcAttrFreeList ) )
99 {
100 ppi->pDCAttrList = NULL;
101 return pDc_Attr;
102 }
103
104 pGdiDcAttrFreeList = (PGDI_DC_ATTR_FREELIST)ppi->GDIDcAttrFreeList.Flink;
105 }
106
107 ppi->pDCAttrList = pGdiDcAttrFreeList->AttrList[pGdiDcAttrFreeList->nEntries-1];
108
109 return pDc_Attr;
110 }
111
112 VOID
113 FASTCALL
114 FreeDcAttr(PDC_ATTR pDc_Attr)
115 {
116 PTHREADINFO pti;
117 PPROCESSINFO ppi;
118 PGDI_DC_ATTR_FREELIST pGdiDcAttrFreeList;
119
120 pti = PsGetCurrentThreadWin32Thread();
121
122 if (!pti) return;
123
124 if (!pti->pgdiDcattr)
125 { // If it is null, just cache it for the next time.
126 pti->pgdiDcattr = pDc_Attr;
127 return;
128 }
129
130 ppi = PsGetCurrentProcessWin32Process();
131
132 pGdiDcAttrFreeList = (PGDI_DC_ATTR_FREELIST)ppi->GDIDcAttrFreeList.Flink;
133
134 // We add to the list of free entries, so this will grows!
135 if ( IsListEmpty(&ppi->GDIDcAttrFreeList) ||
136 pGdiDcAttrFreeList->nEntries == GDIDCATTRFREE )
137 {
138 pGdiDcAttrFreeList = ExAllocatePoolWithTag( PagedPool,
139 sizeof(GDI_DC_ATTR_FREELIST),
140 GDITAG_DC_FREELIST);
141 if ( !pGdiDcAttrFreeList )
142 {
143 return;
144 }
145 InsertHeadList( &ppi->GDIDcAttrFreeList, &pGdiDcAttrFreeList->Entry);
146 pGdiDcAttrFreeList->nEntries = 0;
147 }
148 // Up count, save the entry and set end of free list point.
149 ++pGdiDcAttrFreeList->nEntries; // Top Down...
150 pGdiDcAttrFreeList->AttrList[pGdiDcAttrFreeList->nEntries-1] = pDc_Attr;
151 ppi->pDCAttrList = pDc_Attr;
152
153 return;
154 }
155
156 VOID
157 FASTCALL
158 DC_AllocateDcAttr(HDC hDC)
159 {
160 PVOID NewMem = NULL;
161 PDC pDC;
162 HANDLE Pid = NtCurrentProcess();
163 ULONG MemSize = sizeof(DC_ATTR); //PAGE_SIZE it will allocate that size
164
165 NTSTATUS Status = ZwAllocateVirtualMemory(Pid,
166 &NewMem,
167 0,
168 &MemSize,
169 MEM_COMMIT|MEM_RESERVE,
170 PAGE_READWRITE);
171 KeEnterCriticalRegion();
172 {
173 INT Index = GDI_HANDLE_GET_INDEX((HGDIOBJ)hDC);
174 PGDI_TABLE_ENTRY Entry = &GdiHandleTable->Entries[Index];
175 // FIXME: dc could have been deleted!!! use GDIOBJ_InsertUserData
176 if (NT_SUCCESS(Status))
177 {
178 RtlZeroMemory(NewMem, MemSize);
179 Entry->UserData = NewMem;
180 DPRINT("DC_ATTR allocated! 0x%x\n",NewMem);
181 }
182 else
183 {
184 DPRINT("DC_ATTR not allocated!\n");
185 }
186 }
187 KeLeaveCriticalRegion();
188 pDC = DC_LockDc(hDC);
189 ASSERT(pDC->pdcattr == &pDC->dcattr);
190 if(NewMem)
191 {
192 pDC->pdcattr = NewMem; // Store pointer
193 }
194 DC_UnlockDc(pDC);
195 }
196
197 VOID
198 FASTCALL
199 DC_FreeDcAttr(HDC DCToFree )
200 {
201 HANDLE Pid = NtCurrentProcess();
202 PDC pDC = DC_LockDc(DCToFree);
203 if (pDC->pdcattr == &pDC->dcattr) return; // Internal DC object!
204 pDC->pdcattr = &pDC->dcattr;
205 DC_UnlockDc(pDC);
206
207 KeEnterCriticalRegion();
208 {
209 INT Index = GDI_HANDLE_GET_INDEX((HGDIOBJ)DCToFree);
210 PGDI_TABLE_ENTRY Entry = &GdiHandleTable->Entries[Index];
211 if(Entry->UserData)
212 {
213 ULONG MemSize = sizeof(DC_ATTR); //PAGE_SIZE;
214 NTSTATUS Status = ZwFreeVirtualMemory(Pid,
215 &Entry->UserData,
216 &MemSize,
217 MEM_RELEASE);
218 if (NT_SUCCESS(Status))
219 {
220 DPRINT("DC_FreeDC DC_ATTR 0x%x\n", Entry->UserData);
221 Entry->UserData = NULL;
222 }
223 }
224 }
225 KeLeaveCriticalRegion();
226 }
227
228
229 static
230 VOID
231 CopytoUserDcAttr(PDC dc, PDC_ATTR pdcattr)
232 {
233 NTSTATUS Status = STATUS_SUCCESS;
234 dc->dcattr.mxWorldToDevice = dc->dclevel.mxWorldToDevice;
235 dc->dcattr.mxDeviceToWorld = dc->dclevel.mxDeviceToWorld;
236 dc->dcattr.mxWorldToPage = dc->dclevel.mxWorldToPage;
237
238 _SEH2_TRY
239 {
240 ProbeForWrite( pdcattr,
241 sizeof(DC_ATTR),
242 1);
243 RtlCopyMemory( pdcattr,
244 &dc->dcattr,
245 sizeof(DC_ATTR));
246 }
247 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
248 {
249 Status = _SEH2_GetExceptionCode();
250 ASSERT(FALSE);
251 }
252 _SEH2_END;
253 }
254
255 // FIXME: wtf? 2 functions, where one has a typo in the name????
256 BOOL
257 FASTCALL
258 DCU_SyncDcAttrtoUser(PDC dc)
259 {
260 PDC_ATTR pdcattr = dc->pdcattr;
261
262 if (pdcattr == &dc->dcattr) return TRUE; // No need to copy self.
263 ASSERT(pdcattr);
264 CopytoUserDcAttr( dc, pdcattr);
265 return TRUE;
266 }
267
268 BOOL
269 FASTCALL
270 DCU_SynchDcAttrtoUser(HDC hDC)
271 {
272 BOOL Ret;
273 PDC pDC = DC_LockDc ( hDC );
274 if (!pDC) return FALSE;
275 Ret = DCU_SyncDcAttrtoUser(pDC);
276 DC_UnlockDc( pDC );
277 return Ret;
278 }
279