4 * Copyright 1993 Alexandre Julliard
5 * Copyright 2021 Jacek Caban for CodeWeavers
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "gdi_private.h"
26 #include "wine/rbtree.h"
27 #include "wine/debug.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(gdi
);
35 void (*delete)( HDC hdc
, HGDIOBJ handle
);
36 struct hdc_list
*next
;
41 struct wine_rb_entry entry
;
42 struct hdc_list
*list
;
46 static CRITICAL_SECTION obj_map_cs
;
47 static CRITICAL_SECTION_DEBUG obj_map_debug
=
50 { &obj_map_debug
.ProcessLocksList
, &obj_map_debug
.ProcessLocksList
},
51 0, 0, { (DWORD_PTR
)(__FILE__
": obj_map_cs") }
53 static CRITICAL_SECTION obj_map_cs
= { &obj_map_debug
, -1, 0, 0, 0, 0 };
55 static GDI_SHARED_MEMORY
*get_gdi_shared(void)
58 if (NtCurrentTeb()->GdiBatchCount
)
60 TEB64
*teb64
= (TEB64
*)(UINT_PTR
)NtCurrentTeb()->GdiBatchCount
;
61 PEB64
*peb64
= (PEB64
*)(UINT_PTR
)teb64
->Peb
;
62 return (GDI_SHARED_MEMORY
*)(UINT_PTR
)peb64
->GdiSharedHandleTable
;
65 return (GDI_SHARED_MEMORY
*)NtCurrentTeb()->Peb
->GdiSharedHandleTable
;
68 static BOOL
is_stock_object( HGDIOBJ obj
)
70 unsigned int handle
= HandleToULong( obj
);
71 return !!(handle
& NTGDI_HANDLE_STOCK_OBJECT
);
74 static inline GDI_HANDLE_ENTRY
*handle_entry( HGDIOBJ handle
)
76 GDI_SHARED_MEMORY
*gdi_shared
= get_gdi_shared();
77 unsigned int idx
= LOWORD(handle
);
79 if (idx
< GDI_MAX_HANDLE_COUNT
&& gdi_shared
->Handles
[idx
].Type
)
81 if (!HIWORD( handle
) || HIWORD( handle
) == gdi_shared
->Handles
[idx
].Unique
)
82 return &gdi_shared
->Handles
[idx
];
84 if (handle
) WARN( "invalid handle %p\n", handle
);
88 static WORD
get_object_type( HGDIOBJ obj
)
90 GDI_HANDLE_ENTRY
*entry
= handle_entry( obj
);
91 return entry
? entry
->ExtType
: 0;
94 void set_gdi_client_ptr( HGDIOBJ obj
, void *ptr
)
96 GDI_HANDLE_ENTRY
*entry
= handle_entry( obj
);
97 if (entry
) entry
->UserPointer
= (UINT_PTR
)ptr
;
100 void *get_gdi_client_ptr( HGDIOBJ obj
, WORD type
)
102 GDI_HANDLE_ENTRY
*entry
= handle_entry( obj
);
103 if (!entry
|| (type
&& entry
->ExtType
!= type
) || !entry
->UserPointer
)
105 return (void *)(UINT_PTR
)entry
->UserPointer
;
108 /***********************************************************************
109 * GetObjectType (GDI32.@)
111 DWORD WINAPI
GetObjectType( HGDIOBJ handle
)
113 DWORD type
= get_object_type( handle
);
115 TRACE( "%p -> %u\n", handle
, type
);
119 case NTGDI_OBJ_PEN
: return OBJ_PEN
;
120 case NTGDI_OBJ_BRUSH
: return OBJ_BRUSH
;
121 case NTGDI_OBJ_DC
: return OBJ_DC
;
122 case NTGDI_OBJ_METADC
: return OBJ_METADC
;
123 case NTGDI_OBJ_PAL
: return OBJ_PAL
;
124 case NTGDI_OBJ_FONT
: return OBJ_FONT
;
125 case NTGDI_OBJ_BITMAP
: return OBJ_BITMAP
;
126 case NTGDI_OBJ_REGION
: return OBJ_REGION
;
127 case NTGDI_OBJ_METAFILE
: return OBJ_METAFILE
;
128 case NTGDI_OBJ_MEMDC
: return OBJ_MEMDC
;
129 case NTGDI_OBJ_EXTPEN
: return OBJ_EXTPEN
;
130 case NTGDI_OBJ_ENHMETADC
: return OBJ_ENHMETADC
;
131 case NTGDI_OBJ_ENHMETAFILE
: return OBJ_ENHMETAFILE
;
133 SetLastError( ERROR_INVALID_HANDLE
);
138 static int obj_map_cmp( const void *key
, const struct wine_rb_entry
*entry
)
140 struct obj_map_entry
*obj_entry
= WINE_RB_ENTRY_VALUE( entry
, struct obj_map_entry
, entry
);
141 return HandleToLong( key
) - HandleToLong( obj_entry
->obj
);
144 struct wine_rb_tree obj_map
= { obj_map_cmp
};
146 /***********************************************************************
147 * DeleteObject (GDI32.@)
149 * Delete a Gdi object.
151 BOOL WINAPI
DeleteObject( HGDIOBJ obj
)
153 struct hdc_list
*hdc_list
= NULL
;
154 struct wine_rb_entry
*entry
;
156 EnterCriticalSection( &obj_map_cs
);
158 if ((entry
= wine_rb_get( &obj_map
, obj
)))
160 struct obj_map_entry
*obj_entry
= WINE_RB_ENTRY_VALUE( entry
, struct obj_map_entry
, entry
);
161 wine_rb_remove( &obj_map
, entry
);
162 hdc_list
= obj_entry
->list
;
163 HeapFree( GetProcessHeap(), 0, obj_entry
);
166 LeaveCriticalSection( &obj_map_cs
);
170 struct hdc_list
*next
= hdc_list
->next
;
172 TRACE( "hdc %p has interest in %p\n", hdc_list
->hdc
, obj
);
174 hdc_list
->delete( hdc_list
->hdc
, obj
);
175 HeapFree( GetProcessHeap(), 0, hdc_list
);
179 return NtGdiDeleteObjectApp( obj
);
182 /***********************************************************************
183 * GDI_hdc_using_object
185 * Call this if the dc requires DeleteObject notification
187 void GDI_hdc_using_object( HGDIOBJ obj
, HDC hdc
, void (*delete)( HDC hdc
, HGDIOBJ handle
))
189 struct hdc_list
*hdc_list
;
190 GDI_HANDLE_ENTRY
*entry
;
192 TRACE( "obj %p hdc %p\n", obj
, hdc
);
194 EnterCriticalSection( &obj_map_cs
);
195 if (!is_stock_object( obj
) && (entry
= handle_entry( obj
)))
197 struct obj_map_entry
*map_entry
;
198 struct wine_rb_entry
*entry
;
200 if (!(entry
= wine_rb_get( &obj_map
, obj
)))
202 if (!(map_entry
= HeapAlloc( GetProcessHeap(), 0, sizeof(*map_entry
) )))
204 LeaveCriticalSection( &obj_map_cs
);
207 map_entry
->obj
= obj
;
208 map_entry
->list
= NULL
;
209 wine_rb_put( &obj_map
, obj
, &map_entry
->entry
);
211 else map_entry
= WINE_RB_ENTRY_VALUE( entry
, struct obj_map_entry
, entry
);
213 for (hdc_list
= map_entry
->list
; hdc_list
; hdc_list
= hdc_list
->next
)
214 if (hdc_list
->hdc
== hdc
) break;
218 if (!(hdc_list
= HeapAlloc( GetProcessHeap(), 0, sizeof(*hdc_list
) )))
220 LeaveCriticalSection( &obj_map_cs
);
224 hdc_list
->delete = delete;
225 hdc_list
->next
= map_entry
->list
;
226 map_entry
->list
= hdc_list
;
229 LeaveCriticalSection( &obj_map_cs
);
232 /***********************************************************************
233 * GDI_hdc_not_using_object
236 void GDI_hdc_not_using_object( HGDIOBJ obj
, HDC hdc
)
238 struct wine_rb_entry
*entry
;
240 TRACE( "obj %p hdc %p\n", obj
, hdc
);
242 EnterCriticalSection( &obj_map_cs
);
243 if ((entry
= wine_rb_get( &obj_map
, obj
)))
245 struct obj_map_entry
*map_entry
= WINE_RB_ENTRY_VALUE( entry
, struct obj_map_entry
, entry
);
246 struct hdc_list
**list_ptr
, *hdc_list
;
248 for (list_ptr
= &map_entry
->list
; *list_ptr
; list_ptr
= &(*list_ptr
)->next
)
250 if ((*list_ptr
)->hdc
!= hdc
) continue;
252 hdc_list
= *list_ptr
;
253 *list_ptr
= hdc_list
->next
;
254 HeapFree( GetProcessHeap(), 0, hdc_list
);
255 if (list_ptr
== &map_entry
->list
&& !*list_ptr
)
257 wine_rb_remove( &obj_map
, &map_entry
->entry
);
258 HeapFree( GetProcessHeap(), 0, map_entry
);
263 LeaveCriticalSection( &obj_map_cs
);
266 /***********************************************************************
267 * SelectObject (GDI32.@)
269 * Select a Gdi object into a device context.
271 HGDIOBJ WINAPI
SelectObject( HDC hdc
, HGDIOBJ obj
)
276 TRACE( "(%p,%p)\n", hdc
, obj
);
278 if (is_meta_dc( hdc
)) return METADC_SelectObject( hdc
, obj
);
279 if (!(dc_attr
= get_dc_attr( hdc
))) return 0;
280 if (dc_attr
->emf
&& !EMFDC_SelectObject( dc_attr
, obj
)) return 0;
282 switch (get_object_type( obj
))
285 case NTGDI_OBJ_EXTPEN
:
286 ret
= NtGdiSelectPen( hdc
, obj
);
288 case NTGDI_OBJ_BRUSH
:
289 ret
= NtGdiSelectBrush( hdc
, obj
);
292 ret
= NtGdiSelectFont( hdc
, obj
);
294 case NTGDI_OBJ_BITMAP
:
295 ret
= NtGdiSelectBitmap( hdc
, obj
);
297 case NTGDI_OBJ_REGION
:
298 ret
= ULongToHandle(SelectClipRgn( hdc
, obj
));
304 if (!ret
) SetLastError( ERROR_INVALID_HANDLE
);
308 /***********************************************************************
309 * GetObjectW (GDI32.@)
311 INT WINAPI
GetObjectW( HGDIOBJ handle
, INT count
, void *buffer
)
315 TRACE( "%p %d %p\n", handle
, count
, buffer
);
317 result
= NtGdiExtGetObjectW( handle
, count
, buffer
);
318 if (!result
&& count
)
320 switch(get_object_type( handle
))
323 case NTGDI_OBJ_BITMAP
:
324 case NTGDI_OBJ_BRUSH
:
328 case NTGDI_OBJ_EXTPEN
:
331 SetLastError( ERROR_INVALID_HANDLE
);
337 /***********************************************************************
338 * GetObjectA (GDI32.@)
340 INT WINAPI
GetObjectA( HGDIOBJ handle
, INT count
, void *buffer
)
342 TRACE("%p %d %p\n", handle
, count
, buffer
);
344 if (get_object_type( handle
) == NTGDI_OBJ_FONT
)
346 LOGFONTA
*lfA
= buffer
;
349 if (!buffer
) return sizeof(*lfA
);
350 if (!GetObjectW( handle
, sizeof(lf
), &lf
)) return 0;
351 if (count
> sizeof(*lfA
)) count
= sizeof(*lfA
);
352 memcpy( lfA
, &lf
, min( count
, FIELD_OFFSET(LOGFONTA
, lfFaceName
) ));
353 if (count
> FIELD_OFFSET(LOGFONTA
, lfFaceName
))
355 WideCharToMultiByte( CP_ACP
, 0, lf
.lfFaceName
, -1, lfA
->lfFaceName
,
356 count
- FIELD_OFFSET(LOGFONTA
, lfFaceName
), NULL
, NULL
);
357 if (count
== sizeof(*lfA
)) lfA
->lfFaceName
[LF_FACESIZE
- 1] = 0;
362 return GetObjectW( handle
, count
, buffer
);
365 /***********************************************************************
366 * CreatePenIndirect (GDI32.@)
368 HPEN WINAPI
CreatePenIndirect( const LOGPEN
*pen
)
370 return CreatePen( pen
->lopnStyle
, pen
->lopnWidth
.x
, pen
->lopnColor
);
373 /***********************************************************************
374 * CreatePen (GDI32.@)
376 HPEN WINAPI
CreatePen( INT style
, INT width
, COLORREF color
)
378 if (style
< 0 || style
> PS_INSIDEFRAME
) style
= PS_SOLID
;
379 return NtGdiCreatePen( style
, width
, color
, NULL
);
382 /***********************************************************************
383 * CreateBitmapIndirect (GDI32.@)
385 HBITMAP WINAPI
CreateBitmapIndirect( const BITMAP
*bmp
)
387 if (!bmp
|| bmp
->bmType
)
389 SetLastError( ERROR_INVALID_PARAMETER
);
393 return CreateBitmap( bmp
->bmWidth
, bmp
->bmHeight
, bmp
->bmPlanes
,
394 bmp
->bmBitsPixel
, bmp
->bmBits
);
397 /******************************************************************************
398 * CreateBitmap (GDI32.@)
400 * Creates a bitmap with the specified info.
402 HBITMAP WINAPI
CreateBitmap( INT width
, INT height
, UINT planes
,
403 UINT bpp
, const void *bits
)
405 if (!width
|| !height
)
406 return GetStockObject( STOCK_LAST
+ 1 ); /* default 1x1 bitmap */
408 return NtGdiCreateBitmap( width
, height
, planes
, bpp
, bits
);
411 /******************************************************************************
412 * CreateDiscardableBitmap (GDI32.@)
414 * Creates a discardable bitmap.
416 HBITMAP WINAPI
CreateDiscardableBitmap( HDC hdc
, INT width
, INT height
)
418 return CreateCompatibleBitmap( hdc
, width
, height
);
421 /***********************************************************************
422 * ExtCreateRegion (GDI32.@)
424 * Creates a region as specified by the transformation data and region data.
426 HRGN WINAPI
ExtCreateRegion( const XFORM
*xform
, DWORD count
, const RGNDATA
*data
)
430 SetLastError( ERROR_INVALID_PARAMETER
);
434 return NtGdiExtCreateRegion( xform
, count
, data
);
437 /***********************************************************************
438 * CreatePolyPolygonRgn (GDI32.@)
440 HRGN WINAPI
CreatePolyPolygonRgn( const POINT
*points
, const INT
*counts
, INT count
, INT mode
)
442 ULONG ret
= NtGdiPolyPolyDraw( ULongToHandle(mode
), points
, (const UINT
*)counts
,
443 count
, NtGdiPolyPolygonRgn
);
444 return ULongToHandle( ret
);
447 /***********************************************************************
448 * CreateRectRgnIndirect (GDI32.@)
450 * Creates a simple rectangular region.
452 HRGN WINAPI
CreateRectRgnIndirect( const RECT
* rect
)
454 return NtGdiCreateRectRgn( rect
->left
, rect
->top
, rect
->right
, rect
->bottom
);
457 /***********************************************************************
458 * CreateEllipticRgnIndirect (GDI32.@)
460 * Creates an elliptical region.
462 HRGN WINAPI
CreateEllipticRgnIndirect( const RECT
*rect
)
464 return NtGdiCreateEllipticRgn( rect
->left
, rect
->top
, rect
->right
, rect
->bottom
);
467 /***********************************************************************
468 * CreatePolygonRgn (GDI32.@)
470 HRGN WINAPI
CreatePolygonRgn( const POINT
*points
, INT count
, INT mode
)
472 return CreatePolyPolygonRgn( points
, &count
, 1, mode
);
475 /***********************************************************************
476 * CreateColorSpaceA (GDI32.@)
478 HCOLORSPACE WINAPI
CreateColorSpaceA( LOGCOLORSPACEA
*cs
)
484 /***********************************************************************
485 * CreateColorSpaceW (GDI32.@)
487 HCOLORSPACE WINAPI
CreateColorSpaceW( LOGCOLORSPACEW
*cs
)
493 /***********************************************************************
494 * DeleteColorSpace (GDI32.@)
496 BOOL WINAPI
DeleteColorSpace( HCOLORSPACE cs
)
502 /***********************************************************************
503 * GetColorSpace (GDI32.@)
505 HCOLORSPACE WINAPI
GetColorSpace( HDC hdc
)
511 /***********************************************************************
512 * SetColorSpace (GDI32.@)
514 HCOLORSPACE WINAPI
SetColorSpace( HDC hdc
, HCOLORSPACE cs
)