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