2 * GDIOBJ.C - GDI object manipulation routines
8 #undef WIN32_LEAN_AND_MEAN
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>
19 #include <win32k/debug1.h>
23 static LOGBRUSH WhiteBrush =
24 { BS_SOLID, RGB(255,255,255), 0 };
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 };
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 };
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 };
39 static LOGBRUSH BlackBrush =
40 { BS_SOLID, RGB(0,0,0), 0 };
42 static LOGBRUSH NullBrush =
45 static LOGPEN WhitePen =
46 { PS_SOLID, { 0, 0 }, RGB(255,255,255) };
48 static LOGPEN BlackPen =
49 { PS_SOLID, { 0, 0 }, RGB(0,0,0) };
51 static LOGPEN NullPen =
52 { PS_NULL, { 0, 0 }, 0 };
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"" };
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;
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"" };
67 static UINT align_AnsiFixedFont = 1;
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" };
73 static UINT align_AnsiVarFont = 1;
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" };
79 static UINT align_SystemFont = 1;
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"" };
85 static UINT align_DeviceDefaultFont = 1;
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"" };
91 static UINT align_SystemFixedFont = 1;
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" };
98 static UINT align_DefaultGuiFont = 1;
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
104 HBITMAP hPseudoStockBitmap; /* 1x1 bitmap for memory DCs */
106 static PGDI_HANDLE_TABLE HandleTable = 0;
107 static FAST_MUTEX HandleTableMutex;
108 static FAST_MUTEX RefCountHandling;
110 #define GDI_HANDLE_NUMBER 0x4000
112 static PGDI_HANDLE_TABLE
113 GDIOBJ_iAllocHandleTable (WORD Size)
115 PGDI_HANDLE_TABLE handleTable;
117 ExAcquireFastMutexUnsafe (&HandleTableMutex);
118 handleTable = ExAllocatePool(PagedPool,
119 sizeof (GDI_HANDLE_TABLE) +
120 sizeof (GDI_HANDLE_ENTRY) * Size);
121 ASSERT( handleTable );
124 sizeof (GDI_HANDLE_TABLE) + sizeof (GDI_HANDLE_ENTRY) * Size);
125 handleTable->wTableSize = Size;
126 ExReleaseFastMutexUnsafe (&HandleTableMutex);
131 static PGDI_HANDLE_ENTRY
132 GDIOBJ_iGetHandleEntryForIndex (WORD TableIndex)
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);
141 GDIOBJ_iGetNextOpenHandleIndex (void)
145 ExAcquireFastMutexUnsafe (&HandleTableMutex);
146 for (tableIndex = 1; tableIndex < HandleTable->wTableSize; tableIndex++)
148 if (HandleTable->Handles [tableIndex].wMagic == 0)
150 HandleTable->Handles [tableIndex].wMagic = GO_MAGIC_DONTCARE;
154 ExReleaseFastMutexUnsafe (&HandleTableMutex);
156 return (tableIndex < HandleTable->wTableSize) ? tableIndex : 0;
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)
165 PGDIOBJHDR newObject;
166 PGDI_HANDLE_ENTRY handleEntry;
168 DPRINT("GDIOBJ_AllocObj: size: %d, magic: %x\n", Size, Magic);
169 newObject = ExAllocatePool (PagedPool, Size + sizeof (GDIOBJHDR));
170 if (newObject == NULL)
172 DPRINT("GDIOBJ_AllocObj: failed\n");
175 RtlZeroMemory (newObject, Size + sizeof (GDIOBJHDR));
177 newObject->wTableIndex = GDIOBJ_iGetNextOpenHandleIndex ();
178 newObject->dwCount = 0;
179 handleEntry = GDIOBJ_iGetHandleEntryForIndex (newObject->wTableIndex);
180 handleEntry->wMagic = Magic;
181 handleEntry->hProcessId = PsGetCurrentProcessId ();
182 handleEntry->pObject = newObject;
183 DPRINT("GDIOBJ_AllocObj: object handle %d\n", newObject->wTableIndex );
184 return (HGDIOBJ) newObject->wTableIndex;
187 BOOL GDIOBJ_FreeObj(HGDIOBJ hObj, WORD Magic, DWORD Flag)
189 PGDIOBJHDR objectHeader;
190 PGDI_HANDLE_ENTRY handleEntry;
194 handleEntry = GDIOBJ_iGetHandleEntryForIndex ((WORD)hObj & 0xffff);
195 DPRINT("GDIOBJ_FreeObj: hObj: %d, magic: %x, handleEntry: %x\n", (WORD)hObj & 0xffff, Magic, handleEntry );
196 if (handleEntry == 0 || (handleEntry->wMagic != Magic && Magic != GO_MAGIC_DONTCARE )
197 || ((handleEntry->hProcessId != PsGetCurrentProcessId()) && !(Flag & GDIOBJFLAG_IGNOREPID))){
198 DPRINT("Can't Delete hObj: %d, magic: %x, pid:%d\n currpid:%d, flag:%d, hmm:%d\n",(WORD)hObj & 0xffff, handleEntry->wMagic, handleEntry->hProcessId, PsGetCurrentProcessId(), (Flag&GDIOBJFLAG_IGNOREPID), ((handleEntry->hProcessId != PsGetCurrentProcessId()) && !(Flag&GDIOBJFLAG_IGNOREPID)) );
202 objectHeader = (PGDIOBJHDR) handleEntry->pObject;
203 ASSERT(objectHeader);
204 DPRINT("FreeObj: locks: %x\n", objectHeader->dwCount );
205 if( !(Flag & GDIOBJFLAG_IGNORELOCK) ){
206 // check that the reference count is zero. if not then set flag
207 // and delete object when releaseobj is called
208 ExAcquireFastMutex(&RefCountHandling);
209 if( ( objectHeader->dwCount & ~0x80000000 ) > 0 ){
210 DPRINT("GDIOBJ_FreeObj: delayed object deletion: count %d\n", objectHeader->dwCount);
211 objectHeader->dwCount |= 0x80000000;
212 ExReleaseFastMutex(&RefCountHandling);
215 ExReleaseFastMutex(&RefCountHandling);
218 //allow object to delete internal data
219 Obj = (PGDIOBJ)((PCHAR)handleEntry->pObject + sizeof(GDIOBJHDR));
220 switch( handleEntry->wMagic ){
221 case GO_REGION_MAGIC:
222 bRet = RGNDATA_InternalDelete( (PROSRGNDATA) Obj );
224 case GO_BITMAP_MAGIC:
225 bRet = Bitmap_InternalDelete( (PBITMAPOBJ) Obj );
228 bRet = DC_InternalDeleteDC( (PDC) Obj );
231 case GO_PALETTE_MAGIC:
232 case GO_DISABLED_DC_MAGIC:
233 case GO_META_DC_MAGIC:
234 case GO_METAFILE_MAGIC:
235 case GO_METAFILE_DC_MAGIC:
236 case GO_ENHMETAFILE_MAGIC:
237 case GO_ENHMETAFILE_DC_MAGIC:
243 handleEntry->hProcessId = 0;
244 ExFreePool (handleEntry->pObject);
245 handleEntry->pObject = 0;
246 // (RJJ) set wMagic last to avoid race condition
247 handleEntry->wMagic = 0;
253 PGDIOBJ GDIOBJ_LockObj( HGDIOBJ hObj, WORD Magic )
255 PGDI_HANDLE_ENTRY handleEntry = GDIOBJ_iGetHandleEntryForIndex ((WORD) hObj & 0xffff);
256 PGDIOBJHDR objectHeader;
258 DPRINT("GDIOBJ_LockObj: hObj: %d, magic: %x, \n handleEntry: %x, mag %x\n", hObj, Magic, handleEntry, handleEntry->wMagic);
259 if (handleEntry == 0 || (handleEntry->wMagic != Magic && Magic != GO_MAGIC_DONTCARE )
260 || (handleEntry->hProcessId != (HANDLE)0xFFFFFFFF &&
261 handleEntry->hProcessId != PsGetCurrentProcessId ())){
262 DPRINT("GDIBOJ_LockObj failed for %d, magic: %d, reqMagic\n",(WORD) hObj & 0xffff, handleEntry->wMagic, Magic);
266 objectHeader = (PGDIOBJHDR) handleEntry->pObject;
267 ASSERT(objectHeader);
269 ExAcquireFastMutex(&RefCountHandling);
270 objectHeader->dwCount++;
271 ExReleaseFastMutex(&RefCountHandling);
273 DPRINT("GDIOBJ_LockObj: PGDIOBJ %x\n", ((PCHAR)objectHeader + sizeof(GDIOBJHDR)) );
274 return (PGDIOBJ)((PCHAR)objectHeader + sizeof(GDIOBJHDR));
277 BOOL GDIOBJ_UnlockObj( HGDIOBJ hObj, WORD Magic )
279 PGDI_HANDLE_ENTRY handleEntry = GDIOBJ_iGetHandleEntryForIndex ((WORD) hObj & 0xffff);
280 PGDIOBJHDR objectHeader;
282 DPRINT("GDIOBJ_UnlockObj: hObj: %d, magic: %x, \n handleEntry: %x\n", hObj, Magic, handleEntry);
283 if (handleEntry == 0 || (handleEntry->wMagic != Magic && Magic != GO_MAGIC_DONTCARE )
284 || (handleEntry->hProcessId != (HANDLE)0xFFFFFFFF &&
285 handleEntry->hProcessId != PsGetCurrentProcessId ())){
286 DPRINT( "GDIOBJ_UnLockObj: failed\n");
290 objectHeader = (PGDIOBJHDR) handleEntry->pObject;
291 ASSERT(objectHeader);
293 ExAcquireFastMutex(&RefCountHandling);
294 if( ( objectHeader->dwCount & ~0x80000000 ) == 0 ){
295 ExReleaseFastMutex(&RefCountHandling);
296 DPRINT( "GDIOBJ_UnLockObj: unlock object that is not locked\n" );
300 objectHeader = (PGDIOBJHDR) handleEntry->pObject;
301 ASSERT(objectHeader);
302 objectHeader->dwCount--;
304 if( objectHeader->dwCount == 0x80000000 ){
305 //delayed object release
306 objectHeader->dwCount = 0;
307 ExReleaseFastMutex(&RefCountHandling);
308 DPRINT("GDIOBJ_UnlockObj: delayed delete\n");
309 return GDIOBJ_FreeObj( hObj, Magic, GDIOBJFLAG_DEFAULT );
311 ExReleaseFastMutex(&RefCountHandling);
316 PGDIOBJ GDIOBJ_AllocObject(WORD Size, WORD Magic)
318 PGDIOBJHDR newObject;
319 PGDI_HANDLE_ENTRY handleEntry;
321 newObject = ExAllocatePool (PagedPool, Size + sizeof (GDIOBJHDR));
322 if (newObject == NULL)
326 RtlZeroMemory (newObject, Size + sizeof (GDIOBJHDR));
328 newObject->wTableIndex = GDIOBJ_iGetNextOpenHandleIndex ();
329 handleEntry = GDIOBJ_iGetHandleEntryForIndex (newObject->wTableIndex);
330 handleEntry->wMagic = Magic;
331 handleEntry->hProcessId = PsGetCurrentProcessId ();
332 handleEntry->pObject = newObject;
334 return (PGDIOBJ)(((PCHAR) newObject) + sizeof (GDIOBJHDR));
337 BOOL GDIOBJ_FreeObject (PGDIOBJ Obj, WORD Magic)
339 PGDIOBJHDR objectHeader;
340 PGDI_HANDLE_ENTRY handleEntry;
342 objectHeader = (PGDIOBJHDR)(((PCHAR)Obj) - sizeof (GDIOBJHDR));
343 handleEntry = GDIOBJ_iGetHandleEntryForIndex (objectHeader->wTableIndex);
344 if (handleEntry == 0 || handleEntry->wMagic != Magic)
346 handleEntry->hProcessId = 0;
347 handleEntry->pObject = 0;
348 // (RJJ) set wMagic last to avoid race condition
349 handleEntry->wMagic = 0;
350 ExFreePool (objectHeader);
355 HGDIOBJ GDIOBJ_PtrToHandle (PGDIOBJ Obj, WORD Magic)
357 PGDIOBJHDR objectHeader;
358 PGDI_HANDLE_ENTRY handleEntry;
362 objectHeader = (PGDIOBJHDR) (((PCHAR)Obj) - sizeof (GDIOBJHDR));
363 handleEntry = GDIOBJ_iGetHandleEntryForIndex (objectHeader->wTableIndex);
364 if (handleEntry == 0 ||
365 handleEntry->wMagic != Magic ||
366 handleEntry->hProcessId != PsGetCurrentProcessId () )
369 return (HGDIOBJ) objectHeader->wTableIndex;
372 PGDIOBJ GDIOBJ_HandleToPtr (HGDIOBJ ObjectHandle, WORD Magic)
374 PGDI_HANDLE_ENTRY handleEntry;
376 if (ObjectHandle == NULL)
379 handleEntry = GDIOBJ_iGetHandleEntryForIndex ((WORD)ObjectHandle & 0xffff);
380 if (handleEntry == 0 ||
381 (Magic != GO_MAGIC_DONTCARE && Magic != Magic) ||
382 handleEntry->hProcessId != PsGetCurrentProcessId () )
385 return (PGDIOBJ) (((PCHAR)handleEntry->pObject) + sizeof (GDIOBJHDR));
389 VOID GDIOBJ_MarkObjectGlobal(HGDIOBJ ObjectHandle)
391 PGDI_HANDLE_ENTRY handleEntry;
393 if (ObjectHandle == NULL)
396 handleEntry = GDIOBJ_iGetHandleEntryForIndex ((WORD)ObjectHandle & 0xffff);
397 if (handleEntry == 0)
400 handleEntry->hProcessId = (HANDLE)0xFFFFFFFF;
403 WORD GDIOBJ_GetHandleMagic (HGDIOBJ ObjectHandle)
405 PGDI_HANDLE_ENTRY handleEntry;
407 if (ObjectHandle == NULL)
410 handleEntry = GDIOBJ_iGetHandleEntryForIndex ((WORD)ObjectHandle & 0xffff);
411 if (handleEntry == 0 ||
412 (handleEntry->hProcessId != (HANDLE)0xFFFFFFFF &&
413 handleEntry->hProcessId != PsGetCurrentProcessId ()))
416 return handleEntry->wMagic;
420 InitGdiObjectHandleTable (void)
422 DPRINT ("InitGdiObjectHandleTable\n");
423 ExInitializeFastMutex (&HandleTableMutex);
424 ExInitializeFastMutex (&RefCountHandling);
425 //per http://www.wd-mag.com/articles/1999/9902/9902b/9902b.htm?topic=articles
426 //gdi handle table can hold 0x4000 handles
427 HandleTable = GDIOBJ_iAllocHandleTable (GDI_HANDLE_NUMBER);
428 DPRINT("HandleTable: %x\n", HandleTable );
430 InitEngHandleTable();
433 VOID CreateStockObjects(void)
435 // Create GDI Stock Objects from the logical structures we've defined
437 StockObjects[WHITE_BRUSH] = W32kCreateBrushIndirect(&WhiteBrush);
438 GDIOBJ_MarkObjectGlobal(StockObjects[WHITE_BRUSH]);
439 StockObjects[LTGRAY_BRUSH] = W32kCreateBrushIndirect(&LtGrayBrush);
440 GDIOBJ_MarkObjectGlobal(StockObjects[LTGRAY_BRUSH]);
441 StockObjects[GRAY_BRUSH] = W32kCreateBrushIndirect(&GrayBrush);
442 GDIOBJ_MarkObjectGlobal(StockObjects[GRAY_BRUSH]);
443 StockObjects[DKGRAY_BRUSH] = W32kCreateBrushIndirect(&DkGrayBrush);
444 GDIOBJ_MarkObjectGlobal(StockObjects[DKGRAY_BRUSH]);
445 StockObjects[BLACK_BRUSH] = W32kCreateBrushIndirect(&BlackBrush);
446 GDIOBJ_MarkObjectGlobal(StockObjects[BLACK_BRUSH]);
447 StockObjects[NULL_BRUSH] = W32kCreateBrushIndirect(&NullBrush);
448 GDIOBJ_MarkObjectGlobal(StockObjects[NULL_BRUSH]);
450 StockObjects[WHITE_PEN] = W32kCreatePenIndirect(&WhitePen);
451 GDIOBJ_MarkObjectGlobal(StockObjects[WHITE_PEN]);
452 StockObjects[BLACK_PEN] = W32kCreatePenIndirect(&BlackPen);
453 GDIOBJ_MarkObjectGlobal(StockObjects[BLACK_PEN]);
454 StockObjects[NULL_PEN] = W32kCreatePenIndirect(&NullPen);
455 GDIOBJ_MarkObjectGlobal(StockObjects[NULL_PEN]);
457 StockObjects[OEM_FIXED_FONT] = W32kCreateFontIndirect(&OEMFixedFont);
458 GDIOBJ_MarkObjectGlobal(StockObjects[OEM_FIXED_FONT]);
459 StockObjects[ANSI_FIXED_FONT] = W32kCreateFontIndirect(&AnsiFixedFont);
460 GDIOBJ_MarkObjectGlobal(StockObjects[ANSI_FIXED_FONT]);
461 StockObjects[SYSTEM_FONT] = W32kCreateFontIndirect(&SystemFont);
462 GDIOBJ_MarkObjectGlobal(StockObjects[SYSTEM_FONT]);
463 StockObjects[DEVICE_DEFAULT_FONT] =
464 W32kCreateFontIndirect(&DeviceDefaultFont);
465 GDIOBJ_MarkObjectGlobal(StockObjects[DEVICE_DEFAULT_FONT]);
466 StockObjects[SYSTEM_FIXED_FONT] = W32kCreateFontIndirect(&SystemFixedFont);
467 GDIOBJ_MarkObjectGlobal(StockObjects[SYSTEM_FIXED_FONT]);
468 StockObjects[DEFAULT_GUI_FONT] = W32kCreateFontIndirect(&DefaultGuiFont);
469 GDIOBJ_MarkObjectGlobal(StockObjects[DEFAULT_GUI_FONT]);
471 StockObjects[DEFAULT_PALETTE] = (HGDIOBJ*)PALETTE_Init();
474 HGDIOBJ STDCALL W32kGetStockObject(INT Object)
478 /* if ((Object < 0) || (Object >= NB_STOCK_OBJECTS)) return 0;
479 if (!StockObjects[Object]) return 0;
480 ret = FIRST_STOCK_HANDLE + Object;
484 return StockObjects[Object]; // FIXME........
487 BOOL STDCALL W32kDeleteObject(HGDIOBJ hObject)
489 return GDIOBJ_FreeObj( hObject, GO_MAGIC_DONTCARE, GDIOBJFLAG_DEFAULT );
492 BOOL STDCALL W32kCleanupForProcess( INT Process )
495 PGDI_HANDLE_ENTRY handleEntry;
496 PGDIOBJHDR objectHeader;
498 for( i=1; i < GDI_HANDLE_NUMBER; i++ ){
499 handleEntry = GDIOBJ_iGetHandleEntryForIndex ((WORD) i & 0xffff);
500 if( handleEntry && handleEntry->wMagic != 0 && handleEntry->hProcessId == Process){
501 objectHeader = (PGDIOBJHDR) handleEntry->pObject;
502 DPRINT("\nW32kCleanup: %d, magic: %x \n process: %d, locks: %d", i, handleEntry->wMagic, handleEntry->hProcessId, objectHeader->dwCount);
503 GDIOBJ_FreeObj( (WORD) i & 0xffff, GO_MAGIC_DONTCARE, GDIOBJFLAG_IGNOREPID|GDIOBJFLAG_IGNORELOCK );
509 // dump all the objects for process. if process == 0 dump all the objects
510 VOID STDCALL W32kDumpGdiObjects( INT Process )
513 PGDI_HANDLE_ENTRY handleEntry;
514 PGDIOBJHDR objectHeader;
516 for( i=1; i < GDI_HANDLE_NUMBER; i++ ){
517 handleEntry = GDIOBJ_iGetHandleEntryForIndex ((WORD) i & 0xffff);
518 if( handleEntry && handleEntry->wMagic != 0 ){
519 objectHeader = (PGDIOBJHDR) handleEntry->pObject;
520 DPRINT("\nHandle: %d, magic: %x \n process: %d, locks: %d", i, handleEntry->wMagic, handleEntry->hProcessId, objectHeader->dwCount);