Added GetRegionData gdi function. Added region test. Fixed some bugs.
[reactos.git] / reactos / subsys / win32k / objects / gdiobj.c
1 /*
2 * GDIOBJ.C - GDI object manipulation routines
3 *
4 * $Id: gdiobj.c,v 1.14 2002/07/22 07:55:48 ei Exp $
5 *
6 */
7
8 #undef WIN32_LEAN_AND_MEAN
9 #include <windows.h>
10 #include <ddk/ntddk.h>
11 #include <win32k/gdiobj.h>
12 #include <win32k/brush.h>
13 #include <win32k/pen.h>
14 #include <win32k/text.h>
15 #include <win32k/dc.h>
16 #include <win32k/bitmaps.h>
17 #include <win32k/region.h>
18 #define NDEBUG
19 #include <win32k/debug1.h>
20
21 // GDI stock objects
22
23 static LOGBRUSH WhiteBrush =
24 { BS_SOLID, RGB(255,255,255), 0 };
25
26 static LOGBRUSH LtGrayBrush =
27 /* FIXME : this should perhaps be BS_HATCHED, at least for 1 bitperpixel */
28 { BS_SOLID, RGB(192,192,192), 0 };
29
30 static LOGBRUSH GrayBrush =
31 /* FIXME : this should perhaps be BS_HATCHED, at least for 1 bitperpixel */
32 { BS_SOLID, RGB(128,128,128), 0 };
33
34 static LOGBRUSH DkGrayBrush =
35 /* This is BS_HATCHED, for 1 bitperpixel. This makes the spray work in pbrush */
36 /* NB_HATCH_STYLES is an index into HatchBrushes */
37 { BS_HATCHED, RGB(0,0,0), NB_HATCH_STYLES };
38
39 static LOGBRUSH BlackBrush =
40 { BS_SOLID, RGB(0,0,0), 0 };
41
42 static LOGBRUSH NullBrush =
43 { BS_NULL, 0, 0 };
44
45 static LOGPEN WhitePen =
46 { PS_SOLID, { 0, 0 }, RGB(255,255,255) };
47
48 static LOGPEN BlackPen =
49 { PS_SOLID, { 0, 0 }, RGB(0,0,0) };
50
51 static LOGPEN NullPen =
52 { PS_NULL, { 0, 0 }, 0 };
53
54 static LOGFONT OEMFixedFont =
55 { 0, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, OEM_CHARSET,
56 0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, L"" };
57
58 /* Filler to make the location counter dword aligned again. This is necessary
59 since (a) LOGFONT is packed, (b) gcc places initialised variables in the code
60 segment, and (c) Solaris assembler is stupid. */
61 static UINT align_OEMFixedFont = 1;
62
63 static LOGFONT AnsiFixedFont =
64 { 0, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
65 0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, L"" };
66
67 static UINT align_AnsiFixedFont = 1;
68
69 static LOGFONT AnsiVarFont =
70 { 0, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
71 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, L"MS Sans Serif" };
72
73 static UINT align_AnsiVarFont = 1;
74
75 static LOGFONT SystemFont =
76 { 0, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
77 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, L"System" };
78
79 static UINT align_SystemFont = 1;
80
81 static LOGFONT DeviceDefaultFont =
82 { 0, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
83 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, L"" };
84
85 static UINT align_DeviceDefaultFont = 1;
86
87 static LOGFONT SystemFixedFont =
88 { 0, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
89 0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, L"" };
90
91 static UINT align_SystemFixedFont = 1;
92
93 /* FIXME: Is this correct? */
94 static LOGFONT DefaultGuiFont =
95 { 0, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
96 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, L"MS Sans Serif" };
97
98 static UINT align_DefaultGuiFont = 1;
99
100 static HGDIOBJ *StockObjects[NB_STOCK_OBJECTS]; // we dont assign these statically as WINE does because we might redesign
101 // the way handles work, so it's more dynamic now
102
103
104 HBITMAP hPseudoStockBitmap; /* 1x1 bitmap for memory DCs */
105
106 static PGDI_HANDLE_TABLE HandleTable = 0;
107 static FAST_MUTEX HandleTableMutex;
108 static FAST_MUTEX RefCountHandling;
109
110 #define GDI_HANDLE_NUMBER 0x4000
111
112 static PGDI_HANDLE_TABLE
113 GDIOBJ_iAllocHandleTable (WORD Size)
114 {
115 PGDI_HANDLE_TABLE handleTable;
116
117 ExAcquireFastMutexUnsafe (&HandleTableMutex);
118 handleTable = ExAllocatePool(PagedPool,
119 sizeof (GDI_HANDLE_TABLE) +
120 sizeof (GDI_HANDLE_ENTRY) * Size);
121 ASSERT( handleTable );
122 memset (handleTable,
123 0,
124 sizeof (GDI_HANDLE_TABLE) + sizeof (GDI_HANDLE_ENTRY) * Size);
125 handleTable->wTableSize = Size;
126 ExReleaseFastMutexUnsafe (&HandleTableMutex);
127
128 return handleTable;
129 }
130
131 static PGDI_HANDLE_ENTRY
132 GDIOBJ_iGetHandleEntryForIndex (WORD TableIndex)
133 {
134 //DPRINT("GDIOBJ_iGetHandleEntryForIndex: TableIndex: %d,\n handle: %x, ptr: %x\n", TableIndex, HandleTable->Handles [TableIndex], &(HandleTable->Handles [TableIndex]) );
135 //DPRINT("GIG: HandleTable: %x, Handles: %x, \n TableIndex: %x, pt: %x\n", HandleTable, HandleTable->Handles, TableIndex, ((PGDI_HANDLE_ENTRY)HandleTable->Handles+TableIndex));
136 //DPRINT("GIG: Hndl: %x, mag: %x\n", ((PGDI_HANDLE_ENTRY)HandleTable->Handles+TableIndex), ((PGDI_HANDLE_ENTRY)HandleTable->Handles+TableIndex)->wMagic);
137 return ((PGDI_HANDLE_ENTRY)HandleTable->Handles+TableIndex);
138 }
139
140 static WORD
141 GDIOBJ_iGetNextOpenHandleIndex (void)
142 {
143 WORD tableIndex;
144
145 ExAcquireFastMutexUnsafe (&HandleTableMutex);
146 for (tableIndex = 1; tableIndex < HandleTable->wTableSize; tableIndex++)
147 {
148 if (HandleTable->Handles [tableIndex].wMagic == 0)
149 {
150 HandleTable->Handles [tableIndex].wMagic = GO_MAGIC_DONTCARE;
151 break;
152 }
153 }
154 ExReleaseFastMutexUnsafe (&HandleTableMutex);
155
156 return (tableIndex < HandleTable->wTableSize) ? tableIndex : 0;
157 }
158
159 /*-----------------7/12/2002 11:38AM----------------
160 * Allocate memory for GDI object and return handle to it
161 * Use GDIOBJ_Lock to obtain pointer to the new object.
162 * --------------------------------------------------*/
163 HGDIOBJ GDIOBJ_AllocObj(WORD Size, WORD Magic)
164 {
165 PGDIOBJHDR newObject;
166 PGDI_HANDLE_ENTRY handleEntry;
167
168 DPRINT("GDIOBJ_AllocObj: size: %d, magic: %x\n", Size, Magic);
169 newObject = ExAllocatePool (PagedPool, Size + sizeof (GDIOBJHDR));
170 if (newObject == NULL)
171 {
172 return NULL;
173 }
174 RtlZeroMemory (newObject, Size + sizeof (GDIOBJHDR));
175
176 newObject->wTableIndex = GDIOBJ_iGetNextOpenHandleIndex ();
177 newObject->dwCount = 0;
178 handleEntry = GDIOBJ_iGetHandleEntryForIndex (newObject->wTableIndex);
179 handleEntry->wMagic = Magic;
180 handleEntry->hProcessId = PsGetCurrentProcessId ();
181 handleEntry->pObject = newObject;
182 DPRINT("GDIOBJ_AllocObj: object handle %d\n", newObject->wTableIndex );
183 return (HGDIOBJ) newObject->wTableIndex;
184 }
185
186 BOOL GDIOBJ_FreeObj(HGDIOBJ hObj, WORD Magic)
187 {
188 PGDIOBJHDR objectHeader;
189 PGDI_HANDLE_ENTRY handleEntry;
190 PGDIOBJ Obj;
191 BOOL bRet = TRUE;
192
193 handleEntry = GDIOBJ_iGetHandleEntryForIndex ((WORD)hObj & 0xffff);
194 DPRINT("GDIOBJ_FreeObj: hObj: %d, magic: %x, handleEntry: %x\n", hObj, Magic, handleEntry );
195 if (handleEntry == 0 || (handleEntry->wMagic != Magic && handleEntry->wMagic != GO_MAGIC_DONTCARE )
196 || handleEntry->hProcessId != PsGetCurrentProcessId ())
197 return FALSE;
198
199 objectHeader = (PGDIOBJHDR) handleEntry->pObject;
200 ASSERT(objectHeader);
201
202 // check that the reference count is zero. if not then set flag
203 // and delete object when releaseobj is called
204 ExAcquireFastMutex(&RefCountHandling);
205 if( ( objectHeader->dwCount & ~0x80000000 ) > 0 ){
206 objectHeader->dwCount |= 0x80000000;
207 DPRINT("GDIOBJ_FreeObj: delayed object deletion");
208 ExReleaseFastMutex(&RefCountHandling);
209 return TRUE;
210 }
211 ExReleaseFastMutex(&RefCountHandling);
212
213 //allow object to delete internal data
214 Obj = (PGDIOBJ)((PCHAR)handleEntry->pObject + sizeof(GDIOBJHDR));
215 switch( handleEntry->wMagic ){
216 case GO_REGION_MAGIC:
217 bRet = RGNDATA_InternalDelete( (PROSRGNDATA) Obj );
218 break;
219 case GO_PEN_MAGIC:
220 case GO_PALETTE_MAGIC:
221 case GO_BITMAP_MAGIC:
222 bRet = Bitmap_InternalDelete( (PBITMAPOBJ) Obj );
223 break;
224 case GO_DC_MAGIC:
225 bRet = DC_InternalDeleteDC( (PDC) Obj );
226 break;
227 case GO_DISABLED_DC_MAGIC:
228 case GO_META_DC_MAGIC:
229 case GO_METAFILE_MAGIC:
230 case GO_METAFILE_DC_MAGIC:
231 case GO_ENHMETAFILE_MAGIC:
232 case GO_ENHMETAFILE_DC_MAGIC:
233
234 case GO_BRUSH_MAGIC:
235 case GO_FONT_MAGIC:
236 break;
237 }
238 handleEntry->hProcessId = 0;
239 ExFreePool (handleEntry->pObject);
240 handleEntry->pObject = 0;
241 // (RJJ) set wMagic last to avoid race condition
242 handleEntry->wMagic = 0;
243
244
245 return TRUE;
246 }
247
248 PGDIOBJ GDIOBJ_LockObj( HGDIOBJ hObj, WORD Magic )
249 {
250 PGDI_HANDLE_ENTRY handleEntry = GDIOBJ_iGetHandleEntryForIndex ((WORD) hObj & 0xffff);
251 PGDIOBJHDR objectHeader;
252
253 DPRINT("GDIOBJ_LockObj: hObj: %d, magic: %x, \n handleEntry: %x, mag %x\n", hObj, Magic, handleEntry, handleEntry->wMagic);
254 if (handleEntry == 0 || (handleEntry->wMagic != Magic && handleEntry->wMagic != GO_MAGIC_DONTCARE )
255 || handleEntry->hProcessId != PsGetCurrentProcessId () )
256 return NULL;
257
258 objectHeader = (PGDIOBJHDR) handleEntry->pObject;
259 ASSERT(objectHeader);
260
261 ExAcquireFastMutex(&RefCountHandling);
262 objectHeader->dwCount++;
263 ExReleaseFastMutex(&RefCountHandling);
264
265 DPRINT("GDIOBJ_LockObj: PGDIOBJ %x\n", ((PCHAR)objectHeader + sizeof(GDIOBJHDR)) );
266 return (PGDIOBJ)((PCHAR)objectHeader + sizeof(GDIOBJHDR));
267 }
268
269 BOOL GDIOBJ_UnlockObj( HGDIOBJ hObj, WORD Magic )
270 {
271 PGDI_HANDLE_ENTRY handleEntry = GDIOBJ_iGetHandleEntryForIndex ((WORD) hObj & 0xffff);
272 PGDIOBJHDR objectHeader;
273
274 DPRINT("GDIOBJ_UnlockObj: hObj: %d, magic: %x, \n handleEntry: %x\n", hObj, Magic, handleEntry);
275 if (handleEntry == 0 || (handleEntry->wMagic != Magic && handleEntry->wMagic != GO_MAGIC_DONTCARE )
276 || handleEntry->hProcessId != PsGetCurrentProcessId ())
277 return FALSE;
278
279 objectHeader = (PGDIOBJHDR) handleEntry->pObject;
280 ASSERT(objectHeader);
281
282 ExAcquireFastMutex(&RefCountHandling);
283 if( ( objectHeader->dwCount & ~0x80000000 ) == 0 ){
284 ExReleaseFastMutex(&RefCountHandling);
285 DPRINT( "GDIOBJ_UnLockObj: unlock object that is not locked\n" );
286 return FALSE;
287 }
288
289 objectHeader = (PGDIOBJHDR) handleEntry->pObject;
290 ASSERT(objectHeader);
291 objectHeader->dwCount--;
292
293 if( objectHeader->dwCount == 0x80000000 ){
294 //delayed object release
295 objectHeader->dwCount = 0;
296 ExReleaseFastMutex(&RefCountHandling);
297 DPRINT("GDIOBJ_UnlockObj: delayed delete\n");
298 return GDIOBJ_FreeObj( hObj, Magic );
299 }
300 ExReleaseFastMutex(&RefCountHandling);
301 return TRUE;
302 }
303
304 /*
305 PGDIOBJ GDIOBJ_AllocObject(WORD Size, WORD Magic)
306 {
307 PGDIOBJHDR newObject;
308 PGDI_HANDLE_ENTRY handleEntry;
309
310 newObject = ExAllocatePool (PagedPool, Size + sizeof (GDIOBJHDR));
311 if (newObject == NULL)
312 {
313 return NULL;
314 }
315 RtlZeroMemory (newObject, Size + sizeof (GDIOBJHDR));
316
317 newObject->wTableIndex = GDIOBJ_iGetNextOpenHandleIndex ();
318 handleEntry = GDIOBJ_iGetHandleEntryForIndex (newObject->wTableIndex);
319 handleEntry->wMagic = Magic;
320 handleEntry->hProcessId = PsGetCurrentProcessId ();
321 handleEntry->pObject = newObject;
322
323 return (PGDIOBJ)(((PCHAR) newObject) + sizeof (GDIOBJHDR));
324 }
325
326 BOOL GDIOBJ_FreeObject (PGDIOBJ Obj, WORD Magic)
327 {
328 PGDIOBJHDR objectHeader;
329 PGDI_HANDLE_ENTRY handleEntry;
330
331 objectHeader = (PGDIOBJHDR)(((PCHAR)Obj) - sizeof (GDIOBJHDR));
332 handleEntry = GDIOBJ_iGetHandleEntryForIndex (objectHeader->wTableIndex);
333 if (handleEntry == 0 || handleEntry->wMagic != Magic)
334 return FALSE;
335 handleEntry->hProcessId = 0;
336 handleEntry->pObject = 0;
337 // (RJJ) set wMagic last to avoid race condition
338 handleEntry->wMagic = 0;
339 ExFreePool (objectHeader);
340
341 return TRUE;
342 }
343
344 HGDIOBJ GDIOBJ_PtrToHandle (PGDIOBJ Obj, WORD Magic)
345 {
346 PGDIOBJHDR objectHeader;
347 PGDI_HANDLE_ENTRY handleEntry;
348
349 if (Obj == NULL)
350 return NULL;
351 objectHeader = (PGDIOBJHDR) (((PCHAR)Obj) - sizeof (GDIOBJHDR));
352 handleEntry = GDIOBJ_iGetHandleEntryForIndex (objectHeader->wTableIndex);
353 if (handleEntry == 0 ||
354 handleEntry->wMagic != Magic ||
355 handleEntry->hProcessId != PsGetCurrentProcessId () )
356 return NULL;
357
358 return (HGDIOBJ) objectHeader->wTableIndex;
359 }
360
361 PGDIOBJ GDIOBJ_HandleToPtr (HGDIOBJ ObjectHandle, WORD Magic)
362 {
363 PGDI_HANDLE_ENTRY handleEntry;
364
365 if (ObjectHandle == NULL)
366 return NULL;
367
368 handleEntry = GDIOBJ_iGetHandleEntryForIndex ((WORD)ObjectHandle & 0xffff);
369 if (handleEntry == 0 ||
370 (Magic != GO_MAGIC_DONTCARE && handleEntry->wMagic != Magic) ||
371 handleEntry->hProcessId != PsGetCurrentProcessId () )
372 return NULL;
373
374 return (PGDIOBJ) (((PCHAR)handleEntry->pObject) + sizeof (GDIOBJHDR));
375 }
376 */
377
378 WORD GDIOBJ_GetHandleMagic (HGDIOBJ ObjectHandle)
379 {
380 PGDI_HANDLE_ENTRY handleEntry;
381
382 if (ObjectHandle == NULL)
383 return 0;
384
385 handleEntry = GDIOBJ_iGetHandleEntryForIndex ((WORD)ObjectHandle & 0xffff);
386 if (handleEntry == 0 ||
387 handleEntry->hProcessId != PsGetCurrentProcessId ())
388 return 0;
389
390 return handleEntry->wMagic;
391 }
392
393 VOID
394 InitGdiObjectHandleTable (void)
395 {
396 DPRINT ("InitGdiObjectHandleTable\n");
397 ExInitializeFastMutex (&HandleTableMutex);
398 ExInitializeFastMutex (&RefCountHandling);
399 //per http://www.wd-mag.com/articles/1999/9902/9902b/9902b.htm?topic=articles
400 //gdi handle table can hold 0x4000 handles
401 HandleTable = GDIOBJ_iAllocHandleTable (GDI_HANDLE_NUMBER);
402 DPRINT("HandleTable: %x\n", HandleTable );
403 }
404
405 VOID CreateStockObjects(void)
406 {
407 // Create GDI Stock Objects from the logical structures we've defined
408
409 StockObjects[WHITE_BRUSH] = W32kCreateBrushIndirect(&WhiteBrush);
410 StockObjects[LTGRAY_BRUSH] = W32kCreateBrushIndirect(&LtGrayBrush);
411 StockObjects[GRAY_BRUSH] = W32kCreateBrushIndirect(&GrayBrush);
412 StockObjects[DKGRAY_BRUSH] = W32kCreateBrushIndirect(&DkGrayBrush);
413 StockObjects[BLACK_BRUSH] = W32kCreateBrushIndirect(&BlackBrush);
414 StockObjects[NULL_BRUSH] = W32kCreateBrushIndirect(&NullBrush);
415
416 StockObjects[WHITE_PEN] = W32kCreatePenIndirect(&WhitePen);
417 StockObjects[BLACK_PEN] = W32kCreatePenIndirect(&BlackPen);
418 StockObjects[NULL_PEN] = W32kCreatePenIndirect(&NullPen);
419
420 StockObjects[OEM_FIXED_FONT] = W32kCreateFontIndirect(&OEMFixedFont);
421 StockObjects[ANSI_FIXED_FONT] = W32kCreateFontIndirect(&AnsiFixedFont);
422 StockObjects[SYSTEM_FONT] = W32kCreateFontIndirect(&SystemFont);
423 StockObjects[DEVICE_DEFAULT_FONT] = W32kCreateFontIndirect(&DeviceDefaultFont);
424 StockObjects[SYSTEM_FIXED_FONT] = W32kCreateFontIndirect(&SystemFixedFont);
425 StockObjects[DEFAULT_GUI_FONT] = W32kCreateFontIndirect(&DefaultGuiFont);
426
427 StockObjects[DEFAULT_PALETTE] = (HGDIOBJ*)PALETTE_Init();
428 }
429
430 HGDIOBJ STDCALL W32kGetStockObject(INT Object)
431 {
432 HGDIOBJ ret;
433
434 /* if ((Object < 0) || (Object >= NB_STOCK_OBJECTS)) return 0;
435 if (!StockObjects[Object]) return 0;
436 ret = FIRST_STOCK_HANDLE + Object;
437
438 return ret; */
439
440 return StockObjects[Object]; // FIXME........
441 }
442
443 BOOL STDCALL W32kDeleteObject(HGDIOBJ hObject)
444 {
445 return GDIOBJ_FreeObj( hObject, GO_MAGIC_DONTCARE );
446 }
447
448 // dump all the objects for process. if process == 0 dump all the objects
449 VOID STDCALL W32kDumpGdiObjects( INT Process )
450 {
451 DWORD i;
452 PGDI_HANDLE_ENTRY handleEntry;
453 PGDIOBJHDR objectHeader;
454
455 for( i=1; i < GDI_HANDLE_NUMBER; i++ ){
456 handleEntry = GDIOBJ_iGetHandleEntryForIndex ((WORD) i & 0xffff);
457 if( handleEntry && handleEntry->wMagic != 0 ){
458 objectHeader = (PGDIOBJHDR) handleEntry->pObject;
459 DPRINT("\nHandle: %d, magic: %x \n process: %d, locks: %d", i, handleEntry->wMagic, handleEntry->hProcessId, objectHeader->dwCount);
460 }
461 }
462
463 }