maintainers: Update the Direct3D section.
[wine.git] / dlls / gdi32 / objects.c
blob42bf6fcf111472630ce4c7fd8e5547c0de96b029
1 /*
2 * GDI functions
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 <stdlib.h>
24 #include "ntstatus.h"
25 #define WIN32_NO_STATUS
26 #include "gdi_private.h"
27 #include "ntuser.h"
28 #include "winreg.h"
29 #include "winnls.h"
30 #include "initguid.h"
31 #include "devguid.h"
32 #include "setupapi.h"
34 #include "wine/rbtree.h"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(gdi);
40 DEFINE_DEVPROPKEY(DEVPROPKEY_GPU_LUID, 0x60b193cb, 0x5276, 0x4d0f, 0x96, 0xfc, 0xf1, 0x73, 0xab, 0xad, 0x3e, 0xc6, 2);
42 #define FIRST_GDI_HANDLE 32
44 HMODULE gdi32_module;
46 struct hdc_list
48 HDC hdc;
49 void (*delete)( HDC hdc, HGDIOBJ handle );
50 struct hdc_list *next;
53 struct obj_map_entry
55 struct wine_rb_entry entry;
56 struct hdc_list *list;
57 HGDIOBJ obj;
60 static CRITICAL_SECTION obj_map_cs;
61 static CRITICAL_SECTION_DEBUG obj_map_debug =
63 0, 0, &obj_map_cs,
64 { &obj_map_debug.ProcessLocksList, &obj_map_debug.ProcessLocksList },
65 0, 0, { (DWORD_PTR)(__FILE__ ": obj_map_cs") }
67 static CRITICAL_SECTION obj_map_cs = { &obj_map_debug, -1, 0, 0, 0, 0 };
69 static GDI_SHARED_MEMORY *get_gdi_shared(void)
71 #ifndef _WIN64
72 if (NtCurrentTeb()->GdiBatchCount)
74 TEB64 *teb64 = (TEB64 *)(UINT_PTR)NtCurrentTeb()->GdiBatchCount;
75 PEB64 *peb64 = (PEB64 *)(UINT_PTR)teb64->Peb;
76 return (GDI_SHARED_MEMORY *)(UINT_PTR)peb64->GdiSharedHandleTable;
78 #endif
79 return (GDI_SHARED_MEMORY *)NtCurrentTeb()->Peb->GdiSharedHandleTable;
82 static BOOL is_stock_object( HGDIOBJ obj )
84 unsigned int handle = HandleToULong( obj );
85 return !!(handle & NTGDI_HANDLE_STOCK_OBJECT);
88 static inline GDI_HANDLE_ENTRY *handle_entry( HGDIOBJ handle )
90 GDI_SHARED_MEMORY *gdi_shared = get_gdi_shared();
91 unsigned int idx = LOWORD(handle);
93 if (idx < GDI_MAX_HANDLE_COUNT && gdi_shared->Handles[idx].Type)
95 if (!HIWORD( handle ) || HIWORD( handle ) == gdi_shared->Handles[idx].Unique)
96 return &gdi_shared->Handles[idx];
98 if (handle) WARN( "invalid handle %p\n", handle );
99 return NULL;
102 static HGDIOBJ entry_to_handle( GDI_HANDLE_ENTRY *entry )
104 unsigned int idx = entry - get_gdi_shared()->Handles;
105 return ULongToHandle( idx | (entry->Unique << NTGDI_HANDLE_TYPE_SHIFT) );
108 static DWORD get_object_type( HGDIOBJ obj )
110 GDI_HANDLE_ENTRY *entry = handle_entry( obj );
111 return entry ? entry->ExtType << NTGDI_HANDLE_TYPE_SHIFT : 0;
114 void set_gdi_client_ptr( HGDIOBJ obj, void *ptr )
116 GDI_HANDLE_ENTRY *entry = handle_entry( obj );
117 if (entry) entry->UserPointer = (UINT_PTR)ptr;
120 void *get_gdi_client_ptr( HGDIOBJ obj, DWORD type )
122 GDI_HANDLE_ENTRY *entry = handle_entry( obj );
123 if (!entry || (type && entry->ExtType << NTGDI_HANDLE_TYPE_SHIFT != type))
124 return NULL;
125 return (void *)(UINT_PTR)entry->UserPointer;
128 HGDIOBJ get_full_gdi_handle( HGDIOBJ obj )
130 GDI_HANDLE_ENTRY *entry = handle_entry( obj );
131 return entry ? entry_to_handle( entry ) : 0;
134 /***********************************************************************
135 * DllMain
137 * GDI initialization.
139 BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved )
141 if (reason != DLL_PROCESS_ATTACH) return TRUE;
143 DisableThreadLibraryCalls( inst );
144 gdi32_module = inst;
145 return TRUE;
148 /***********************************************************************
149 * GetObjectType (GDI32.@)
151 DWORD WINAPI GetObjectType( HGDIOBJ handle )
153 DWORD type = get_object_type( handle );
155 TRACE( "%p -> %lu\n", handle, type );
157 switch (type)
159 case NTGDI_OBJ_PEN: return OBJ_PEN;
160 case NTGDI_OBJ_BRUSH: return OBJ_BRUSH;
161 case NTGDI_OBJ_DC: return OBJ_DC;
162 case NTGDI_OBJ_METADC: return OBJ_METADC;
163 case NTGDI_OBJ_PAL: return OBJ_PAL;
164 case NTGDI_OBJ_FONT: return OBJ_FONT;
165 case NTGDI_OBJ_BITMAP: return OBJ_BITMAP;
166 case NTGDI_OBJ_REGION: return OBJ_REGION;
167 case NTGDI_OBJ_METAFILE: return OBJ_METAFILE;
168 case NTGDI_OBJ_MEMDC: return OBJ_MEMDC;
169 case NTGDI_OBJ_EXTPEN: return OBJ_EXTPEN;
170 case NTGDI_OBJ_ENHMETADC: return OBJ_ENHMETADC;
171 case NTGDI_OBJ_ENHMETAFILE: return OBJ_ENHMETAFILE;
172 default:
173 SetLastError( ERROR_INVALID_HANDLE );
174 return 0;
178 static int obj_map_cmp( const void *key, const struct wine_rb_entry *entry )
180 struct obj_map_entry *obj_entry = WINE_RB_ENTRY_VALUE( entry, struct obj_map_entry, entry );
181 UINT_PTR a = (UINT_PTR)key;
182 UINT_PTR b = (UINT_PTR)obj_entry->obj;
183 if (a > b) return 1;
184 if (a < b) return -1;
185 return 0;
188 struct wine_rb_tree obj_map = { obj_map_cmp };
190 /***********************************************************************
191 * DeleteObject (GDI32.@)
193 * Delete a Gdi object.
195 BOOL WINAPI DeleteObject( HGDIOBJ obj )
197 struct hdc_list *hdc_list = NULL;
198 struct wine_rb_entry *entry;
200 obj = get_full_gdi_handle( obj );
201 switch (gdi_handle_type( obj ))
203 case NTGDI_OBJ_DC:
204 case NTGDI_OBJ_MEMDC:
205 case NTGDI_OBJ_ENHMETADC:
206 case NTGDI_OBJ_METADC:
207 return DeleteDC( obj );
210 EnterCriticalSection( &obj_map_cs );
212 if ((entry = wine_rb_get( &obj_map, obj )))
214 struct obj_map_entry *obj_entry = WINE_RB_ENTRY_VALUE( entry, struct obj_map_entry, entry );
215 wine_rb_remove( &obj_map, entry );
216 hdc_list = obj_entry->list;
217 HeapFree( GetProcessHeap(), 0, obj_entry );
220 LeaveCriticalSection( &obj_map_cs );
222 while (hdc_list)
224 struct hdc_list *next = hdc_list->next;
226 TRACE( "hdc %p has interest in %p\n", hdc_list->hdc, obj );
228 hdc_list->delete( hdc_list->hdc, obj );
229 HeapFree( GetProcessHeap(), 0, hdc_list );
230 hdc_list = next;
233 return NtGdiDeleteObjectApp( obj );
236 /***********************************************************************
237 * GDI_hdc_using_object
239 * Call this if the dc requires DeleteObject notification
241 void GDI_hdc_using_object( HGDIOBJ obj, HDC hdc, void (*delete)( HDC hdc, HGDIOBJ handle ))
243 struct hdc_list *hdc_list;
244 GDI_HANDLE_ENTRY *entry;
246 TRACE( "obj %p hdc %p\n", obj, hdc );
248 EnterCriticalSection( &obj_map_cs );
249 if (!is_stock_object( obj ) && (entry = handle_entry( obj )))
251 struct obj_map_entry *map_entry;
252 struct wine_rb_entry *entry;
254 if (!(entry = wine_rb_get( &obj_map, obj )))
256 if (!(map_entry = HeapAlloc( GetProcessHeap(), 0, sizeof(*map_entry) )))
258 LeaveCriticalSection( &obj_map_cs );
259 return;
261 map_entry->obj = obj;
262 map_entry->list = NULL;
263 wine_rb_put( &obj_map, obj, &map_entry->entry );
265 else map_entry = WINE_RB_ENTRY_VALUE( entry, struct obj_map_entry, entry );
267 for (hdc_list = map_entry->list; hdc_list; hdc_list = hdc_list->next)
268 if (hdc_list->hdc == hdc) break;
270 if (!hdc_list)
272 if (!(hdc_list = HeapAlloc( GetProcessHeap(), 0, sizeof(*hdc_list) )))
274 LeaveCriticalSection( &obj_map_cs );
275 return;
277 hdc_list->hdc = hdc;
278 hdc_list->delete = delete;
279 hdc_list->next = map_entry->list;
280 map_entry->list = hdc_list;
283 LeaveCriticalSection( &obj_map_cs );
286 /***********************************************************************
287 * GDI_hdc_not_using_object
290 void GDI_hdc_not_using_object( HGDIOBJ obj, HDC hdc )
292 struct wine_rb_entry *entry;
294 TRACE( "obj %p hdc %p\n", obj, hdc );
296 EnterCriticalSection( &obj_map_cs );
297 if ((entry = wine_rb_get( &obj_map, obj )))
299 struct obj_map_entry *map_entry = WINE_RB_ENTRY_VALUE( entry, struct obj_map_entry, entry );
300 struct hdc_list **list_ptr, *hdc_list;
302 for (list_ptr = &map_entry->list; *list_ptr; list_ptr = &(*list_ptr)->next)
304 if ((*list_ptr)->hdc != hdc) continue;
306 hdc_list = *list_ptr;
307 *list_ptr = hdc_list->next;
308 HeapFree( GetProcessHeap(), 0, hdc_list );
309 if (list_ptr == &map_entry->list && !*list_ptr)
311 wine_rb_remove( &obj_map, &map_entry->entry );
312 HeapFree( GetProcessHeap(), 0, map_entry );
314 break;
317 LeaveCriticalSection( &obj_map_cs );
320 /***********************************************************************
321 * SelectObject (GDI32.@)
323 * Select a Gdi object into a device context.
325 HGDIOBJ WINAPI SelectObject( HDC hdc, HGDIOBJ obj )
327 DC_ATTR *dc_attr;
328 HGDIOBJ ret;
330 TRACE( "(%p,%p)\n", hdc, obj );
332 obj = get_full_gdi_handle( obj );
333 if (is_meta_dc( hdc )) return METADC_SelectObject( hdc, obj );
334 if (!(dc_attr = get_dc_attr( hdc ))) return 0;
335 if (dc_attr->emf && !EMFDC_SelectObject( dc_attr, obj )) return 0;
337 switch (get_object_type( obj ))
339 case NTGDI_OBJ_PEN:
340 case NTGDI_OBJ_EXTPEN:
341 ret = NtGdiSelectPen( hdc, obj );
342 break;
343 case NTGDI_OBJ_BRUSH:
344 ret = NtGdiSelectBrush( hdc, obj );
345 break;
346 case NTGDI_OBJ_FONT:
347 ret = NtGdiSelectFont( hdc, obj );
348 break;
349 case NTGDI_OBJ_BITMAP:
350 ret = NtGdiSelectBitmap( hdc, obj );
351 break;
352 case NTGDI_OBJ_REGION:
353 ret = ULongToHandle(SelectClipRgn( hdc, obj ));
354 break;
355 default:
356 return 0;
359 if (!ret) SetLastError( ERROR_INVALID_HANDLE );
360 return ret;
363 /***********************************************************************
364 * GetObjectW (GDI32.@)
366 INT WINAPI GetObjectW( HGDIOBJ handle, INT count, void *buffer )
368 int result;
370 TRACE( "%p %d %p\n", handle, count, buffer );
372 result = NtGdiExtGetObjectW( handle, count, buffer );
373 if (!result && count)
375 switch(get_object_type( handle ))
377 case 0:
378 case NTGDI_OBJ_BITMAP:
379 case NTGDI_OBJ_BRUSH:
380 case NTGDI_OBJ_FONT:
381 case NTGDI_OBJ_PAL:
382 case NTGDI_OBJ_PEN:
383 case NTGDI_OBJ_EXTPEN:
384 break;
385 default:
386 SetLastError( ERROR_INVALID_HANDLE );
389 return result;
392 /***********************************************************************
393 * GetCurrentObject (GDI32.@)
395 HGDIOBJ WINAPI GetCurrentObject( HDC hdc, UINT type )
397 unsigned int obj_type;
399 switch (type)
401 case OBJ_EXTPEN: obj_type = NTGDI_OBJ_EXTPEN; break;
402 case OBJ_PEN: obj_type = NTGDI_OBJ_PEN; break;
403 case OBJ_BRUSH: obj_type = NTGDI_OBJ_BRUSH; break;
404 case OBJ_PAL: obj_type = NTGDI_OBJ_PAL; break;
405 case OBJ_FONT: obj_type = NTGDI_OBJ_FONT; break;
406 case OBJ_BITMAP: obj_type = NTGDI_OBJ_SURF; break;
407 case OBJ_REGION:
408 /* tests show that OBJ_REGION is explicitly ignored */
409 return 0;
410 default:
411 FIXME( "(%p,%d): unknown type.\n", hdc, type );
412 return 0;
415 return NtGdiGetDCObject( hdc, obj_type );
418 /***********************************************************************
419 * GetStockObject (GDI32.@)
421 HGDIOBJ WINAPI GetStockObject( INT obj )
423 if (obj < 0 || obj > STOCK_LAST + 1 || obj == 9) return 0;
425 /* Wine stores stock objects in predictable order, see init_stock_objects */
426 switch (obj)
428 case OEM_FIXED_FONT:
429 if (GetDpiForSystem() != 96) obj = 9;
430 break;
431 case SYSTEM_FONT:
432 if (GetDpiForSystem() != 96) obj = STOCK_LAST + 2;
433 break;
434 case SYSTEM_FIXED_FONT:
435 if (GetDpiForSystem() != 96) obj = STOCK_LAST + 3;
436 break;
437 case DEFAULT_GUI_FONT:
438 if (GetDpiForSystem() != 96) obj = STOCK_LAST + 4;
439 break;
442 return entry_to_handle( handle_entry( ULongToHandle( obj + FIRST_GDI_HANDLE )));
445 /***********************************************************************
446 * GetObjectA (GDI32.@)
448 INT WINAPI GetObjectA( HGDIOBJ handle, INT count, void *buffer )
450 TRACE("%p %d %p\n", handle, count, buffer );
452 if (get_object_type( handle ) == NTGDI_OBJ_FONT)
454 LOGFONTA *lfA = buffer;
455 LOGFONTW lf;
457 if (!buffer) return sizeof(*lfA);
458 if (!GetObjectW( handle, sizeof(lf), &lf )) return 0;
459 if (count > sizeof(*lfA)) count = sizeof(*lfA);
460 memcpy( lfA, &lf, min( count, FIELD_OFFSET(LOGFONTA, lfFaceName) ));
461 if (count > FIELD_OFFSET(LOGFONTA, lfFaceName))
463 WideCharToMultiByte( CP_ACP, 0, lf.lfFaceName, -1, lfA->lfFaceName,
464 count - FIELD_OFFSET(LOGFONTA, lfFaceName), NULL, NULL );
465 if (count == sizeof(*lfA)) lfA->lfFaceName[LF_FACESIZE - 1] = 0;
467 return count;
470 return GetObjectW( handle, count, buffer );
473 /***********************************************************************
474 * CreatePenIndirect (GDI32.@)
476 HPEN WINAPI CreatePenIndirect( const LOGPEN *pen )
478 return CreatePen( pen->lopnStyle, pen->lopnWidth.x, pen->lopnColor );
481 /***********************************************************************
482 * CreatePen (GDI32.@)
484 HPEN WINAPI CreatePen( INT style, INT width, COLORREF color )
486 if (style < 0 || style > PS_INSIDEFRAME) style = PS_SOLID;
487 return NtGdiCreatePen( style, width, color, NULL );
490 /***********************************************************************
491 * ExtCreatePen (GDI32.@)
493 HPEN WINAPI ExtCreatePen( DWORD style, DWORD width, const LOGBRUSH *brush, DWORD style_count,
494 const DWORD *style_bits )
496 ULONG brush_style = brush->lbStyle;
497 ULONG_PTR hatch = brush->lbHatch;
498 HPEN pen;
500 if (brush_style == BS_DIBPATTERN)
502 if (!(hatch = (ULONG_PTR)GlobalLock( (HGLOBAL)hatch ))) return 0;
503 brush_style = BS_DIBPATTERNPT;
506 pen = NtGdiExtCreatePen( style, width, brush_style, brush->lbColor, brush->lbHatch, hatch,
507 style_count, style_bits, /* FIXME */ 0, FALSE, NULL );
509 if (brush->lbStyle == BS_DIBPATTERN) GlobalUnlock( (HGLOBAL)brush->lbHatch );
510 return pen;
513 /***********************************************************************
514 * CreateBrushIndirect (GDI32.@)
516 HBRUSH WINAPI CreateBrushIndirect( const LOGBRUSH *brush )
518 switch (brush->lbStyle)
520 case BS_NULL:
521 return GetStockObject( NULL_BRUSH );
522 case BS_SOLID:
523 return CreateSolidBrush( brush->lbColor );
524 case BS_HATCHED:
525 return CreateHatchBrush( brush->lbHatch, brush->lbColor );
526 case BS_PATTERN:
527 case BS_PATTERN8X8:
528 return CreatePatternBrush( (HBITMAP)brush->lbHatch );
529 case BS_DIBPATTERN:
530 return CreateDIBPatternBrush( (HGLOBAL)brush->lbHatch, brush->lbColor );
531 case BS_DIBPATTERNPT:
532 return CreateDIBPatternBrushPt( (void *)brush->lbHatch, brush->lbColor );
533 default:
534 WARN( "invalid brush style %u\n", brush->lbStyle );
535 return 0;
539 /***********************************************************************
540 * CreateSolidBrush (GDI32.@)
542 HBRUSH WINAPI CreateSolidBrush( COLORREF color )
544 return NtGdiCreateSolidBrush( color, NULL );
547 /***********************************************************************
548 * CreateHatchBrush (GDI32.@)
550 HBRUSH WINAPI CreateHatchBrush( INT style, COLORREF color )
552 return NtGdiCreateHatchBrushInternal( style, color, FALSE );
555 /***********************************************************************
556 * CreatePatternBrush (GDI32.@)
558 HBRUSH WINAPI CreatePatternBrush( HBITMAP bitmap )
560 return NtGdiCreatePatternBrushInternal( bitmap, FALSE, FALSE );
563 /***********************************************************************
564 * CreateDIBPatternBrush (GDI32.@)
566 HBRUSH WINAPI CreateDIBPatternBrush( HGLOBAL hbitmap, UINT coloruse )
568 HBRUSH brush;
569 void *mem;
571 TRACE( "%p\n", hbitmap );
573 if (!(mem = GlobalLock( hbitmap ))) return 0;
574 brush = NtGdiCreateDIBBrush( mem, coloruse, /* FIXME */ 0, FALSE, FALSE, hbitmap );
575 GlobalUnlock( hbitmap );
576 return brush;
579 /***********************************************************************
580 * CreateDIBPatternBrushPt (GDI32.@)
582 HBRUSH WINAPI CreateDIBPatternBrushPt( const void *data, UINT coloruse )
584 return NtGdiCreateDIBBrush( data, coloruse, /* FIXME */ 0, FALSE, FALSE, data );
587 /***********************************************************************
588 * CreateBitmapIndirect (GDI32.@)
590 HBITMAP WINAPI CreateBitmapIndirect( const BITMAP *bmp )
592 if (!bmp || bmp->bmType)
594 SetLastError( ERROR_INVALID_PARAMETER );
595 return NULL;
598 return CreateBitmap( bmp->bmWidth, bmp->bmHeight, bmp->bmPlanes,
599 bmp->bmBitsPixel, bmp->bmBits );
602 /******************************************************************************
603 * CreateBitmap (GDI32.@)
605 * Creates a bitmap with the specified info.
607 HBITMAP WINAPI CreateBitmap( INT width, INT height, UINT planes,
608 UINT bpp, const void *bits )
610 if (!width || !height)
611 return GetStockObject( STOCK_LAST + 1 ); /* default 1x1 bitmap */
613 return NtGdiCreateBitmap( width, height, planes, bpp, bits );
616 /******************************************************************************
617 * CreateCompatibleBitmap (GDI32.@)
619 * Creates a bitmap compatible with the DC.
621 HBITMAP WINAPI CreateCompatibleBitmap( HDC hdc, INT width, INT height )
623 if (!width || !height)
624 return GetStockObject( STOCK_LAST + 1 ); /* default 1x1 bitmap */
626 return NtGdiCreateCompatibleBitmap( hdc, width, height );
629 /******************************************************************************
630 * CreateDiscardableBitmap (GDI32.@)
632 * Creates a discardable bitmap.
634 HBITMAP WINAPI CreateDiscardableBitmap( HDC hdc, INT width, INT height )
636 return CreateCompatibleBitmap( hdc, width, height );
639 /***********************************************************************
640 * ExtCreateRegion (GDI32.@)
642 * Creates a region as specified by the transformation data and region data.
644 HRGN WINAPI ExtCreateRegion( const XFORM *xform, DWORD count, const RGNDATA *data )
646 if (!data)
648 SetLastError( ERROR_INVALID_PARAMETER );
649 return 0;
652 return NtGdiExtCreateRegion( xform, count, data );
655 /***********************************************************************
656 * CreatePolyPolygonRgn (GDI32.@)
658 HRGN WINAPI CreatePolyPolygonRgn( const POINT *points, const INT *counts, INT count, INT mode )
660 ULONG ret = NtGdiPolyPolyDraw( ULongToHandle(mode), points, (const ULONG *)counts,
661 count, NtGdiPolyPolygonRgn );
662 return ULongToHandle( ret );
665 /***********************************************************************
666 * CreateRectRgnIndirect (GDI32.@)
668 * Creates a simple rectangular region.
670 HRGN WINAPI CreateRectRgnIndirect( const RECT* rect )
672 return NtGdiCreateRectRgn( rect->left, rect->top, rect->right, rect->bottom );
675 /***********************************************************************
676 * CreateEllipticRgnIndirect (GDI32.@)
678 * Creates an elliptical region.
680 HRGN WINAPI CreateEllipticRgnIndirect( const RECT *rect )
682 return NtGdiCreateEllipticRgn( rect->left, rect->top, rect->right, rect->bottom );
685 /***********************************************************************
686 * CreatePolygonRgn (GDI32.@)
688 HRGN WINAPI CreatePolygonRgn( const POINT *points, INT count, INT mode )
690 return CreatePolyPolygonRgn( points, &count, 1, mode );
693 /***********************************************************************
694 * MirrorRgn (GDI32.@)
696 BOOL WINAPI MirrorRgn( HWND hwnd, HRGN hrgn )
698 return NtUserMirrorRgn( hwnd, hrgn );
701 /***********************************************************************
702 * CreateColorSpaceA (GDI32.@)
704 HCOLORSPACE WINAPI CreateColorSpaceA( LOGCOLORSPACEA *cs )
706 FIXME( "stub\n" );
707 return 0;
710 /***********************************************************************
711 * CreateColorSpaceW (GDI32.@)
713 HCOLORSPACE WINAPI CreateColorSpaceW( LOGCOLORSPACEW *cs )
715 FIXME( "stub\n" );
716 return 0;
719 /***********************************************************************
720 * DeleteColorSpace (GDI32.@)
722 BOOL WINAPI DeleteColorSpace( HCOLORSPACE cs )
724 FIXME( "stub\n" );
725 return TRUE;
728 /***********************************************************************
729 * GetColorSpace (GDI32.@)
731 HCOLORSPACE WINAPI GetColorSpace( HDC hdc )
733 FIXME( "stub\n" );
734 return 0;
737 /***********************************************************************
738 * SetColorSpace (GDI32.@)
740 HCOLORSPACE WINAPI SetColorSpace( HDC hdc, HCOLORSPACE cs )
742 FIXME( "stub\n" );
743 return cs;
746 /***********************************************************************
747 * CreatePalette (GDI32.@)
749 HPALETTE WINAPI CreatePalette( const LOGPALETTE *palette )
751 if (!palette) return 0;
752 return NtGdiCreatePaletteInternal( palette, palette->palNumEntries );
755 /***********************************************************************
756 * GetPaletteEntries (GDI32.@)
758 UINT WINAPI GetPaletteEntries( HPALETTE palette, UINT start, UINT count, PALETTEENTRY *entries )
760 return NtGdiDoPalette( palette, start, count, entries, NtGdiGetPaletteEntries, TRUE );
763 /***********************************************************************
764 * SetPaletteEntries (GDI32.@)
766 UINT WINAPI SetPaletteEntries( HPALETTE palette, UINT start, UINT count,
767 const PALETTEENTRY *entries )
769 palette = get_full_gdi_handle( palette );
770 return NtGdiDoPalette( palette, start, count, (void *)entries, NtGdiSetPaletteEntries, FALSE );
773 /***********************************************************************
774 * AnimatePalette (GDI32.@)
776 BOOL WINAPI AnimatePalette( HPALETTE palette, UINT start, UINT count, const PALETTEENTRY *entries )
778 palette = get_full_gdi_handle( palette );
779 return NtGdiDoPalette( palette, start, count, (void *)entries, NtGdiAnimatePalette, FALSE );
782 /* first and last 10 entries are the default system palette entries */
783 static const PALETTEENTRY default_system_palette_low[] =
785 { 0x00, 0x00, 0x00 }, { 0x80, 0x00, 0x00 }, { 0x00, 0x80, 0x00 }, { 0x80, 0x80, 0x00 },
786 { 0x00, 0x00, 0x80 }, { 0x80, 0x00, 0x80 }, { 0x00, 0x80, 0x80 }, { 0xc0, 0xc0, 0xc0 },
787 { 0xc0, 0xdc, 0xc0 }, { 0xa6, 0xca, 0xf0 }
789 static const PALETTEENTRY default_system_palette_high[] =
791 { 0xff, 0xfb, 0xf0 }, { 0xa0, 0xa0, 0xa4 }, { 0x80, 0x80, 0x80 }, { 0xff, 0x00, 0x00 },
792 { 0x00, 0xff, 0x00 }, { 0xff, 0xff, 0x00 }, { 0x00, 0x00, 0xff }, { 0xff, 0x00, 0xff },
793 { 0x00, 0xff, 0xff }, { 0xff, 0xff, 0xff }
796 /***********************************************************************
797 * GetSystemPaletteEntries (GDI32.@)
799 * Gets range of palette entries.
801 UINT WINAPI GetSystemPaletteEntries( HDC hdc, UINT start, UINT count, PALETTEENTRY *entries )
803 UINT i, ret;
805 ret = NtGdiDoPalette( hdc, start, count, (void *)entries,
806 NtGdiGetSystemPaletteEntries, FALSE );
807 if (ret) return ret;
809 /* always fill output, even if hdc is an invalid handle */
810 if (!entries || start >= 256) return 0;
811 if (start + count > 256) count = 256 - start;
813 for (i = 0; i < count; i++)
815 if (start + i < 10)
816 entries[i] = default_system_palette_low[start + i];
817 else if (start + i >= 246)
818 entries[i] = default_system_palette_high[start + i - 246];
819 else
820 memset( &entries[i], 0, sizeof(entries[i]) );
823 return 0;
826 /***********************************************************************
827 * CreateDIBitmap (GDI32.@)
829 HBITMAP WINAPI CreateDIBitmap( HDC hdc, const BITMAPINFOHEADER *header, DWORD init,
830 const void *bits, const BITMAPINFO *data, UINT coloruse )
832 int width, height;
834 if (!header) return 0;
836 if (header->biSize == sizeof(BITMAPCOREHEADER))
838 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)header;
839 width = core->bcWidth;
840 height = core->bcHeight;
842 else if (header->biSize >= sizeof(BITMAPINFOHEADER))
844 if (header->biCompression == BI_JPEG || header->biCompression == BI_PNG) return 0;
845 width = header->biWidth;
846 height = header->biHeight;
848 else return 0;
850 if (!width || !height) return GetStockObject( STOCK_LAST + 1 ); /* default 1x1 bitmap */
851 return NtGdiCreateDIBitmapInternal( hdc, width, height, init, bits, data, coloruse,
852 0, 0, 0, 0 );
855 /***********************************************************************
856 * CreateDIBSection (GDI32.@)
858 HBITMAP WINAPI DECLSPEC_HOTPATCH CreateDIBSection( HDC hdc, const BITMAPINFO *bmi, UINT usage,
859 void **bits, HANDLE section, DWORD offset )
861 return NtGdiCreateDIBSection( hdc, section, offset, bmi, usage, 0, 0, 0, bits );
864 /***********************************************************************
865 * GetDIBits (win32u.@)
867 INT WINAPI DECLSPEC_HOTPATCH GetDIBits( HDC hdc, HBITMAP hbitmap, UINT startscan, UINT lines,
868 void *bits, BITMAPINFO *info, UINT coloruse )
870 return NtGdiGetDIBitsInternal( hdc, hbitmap, startscan, lines, bits, info, coloruse, 0, 0 );
873 /***********************************************************************
874 * GetDIBColorTable (GDI32.@)
876 UINT WINAPI GetDIBColorTable( HDC hdc, UINT start, UINT count, RGBQUAD *colors )
878 return NtGdiDoPalette( hdc, start, count, colors, NtGdiGetDIBColorTable, TRUE );
881 /***********************************************************************
882 * SetDIBColorTable (GDI32.@)
884 UINT WINAPI SetDIBColorTable( HDC hdc, UINT start, UINT count, const RGBQUAD *colors )
886 return NtGdiDoPalette( hdc, start, count, (void *)colors, NtGdiSetDIBColorTable, FALSE );
889 static HANDLE get_display_device_init_mutex( void )
891 HANDLE mutex = CreateMutexW( NULL, FALSE, L"display_device_init" );
893 WaitForSingleObject( mutex, INFINITE );
894 return mutex;
897 static void release_display_device_init_mutex( HANDLE mutex )
899 ReleaseMutex( mutex );
900 CloseHandle( mutex );
903 /***********************************************************************
904 * D3DKMTOpenAdapterFromGdiDisplayName (GDI32.@)
906 NTSTATUS WINAPI D3DKMTOpenAdapterFromGdiDisplayName( D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME *desc )
908 WCHAR *end, key_nameW[MAX_PATH], bufferW[MAX_PATH];
909 HDEVINFO devinfo = INVALID_HANDLE_VALUE;
910 NTSTATUS status = STATUS_UNSUCCESSFUL;
911 D3DKMT_OPENADAPTERFROMLUID luid_desc;
912 SP_DEVINFO_DATA device_data;
913 DWORD size, state_flags;
914 DEVPROPTYPE type;
915 HANDLE mutex;
916 int index;
918 TRACE("(%p)\n", desc);
920 if (!desc)
921 return STATUS_UNSUCCESSFUL;
923 TRACE("DeviceName: %s\n", wine_dbgstr_w( desc->DeviceName ));
924 if (wcsnicmp( desc->DeviceName, L"\\\\.\\DISPLAY", lstrlenW(L"\\\\.\\DISPLAY") ))
925 return STATUS_UNSUCCESSFUL;
927 index = wcstol( desc->DeviceName + lstrlenW(L"\\\\.\\DISPLAY"), &end, 10 ) - 1;
928 if (*end)
929 return STATUS_UNSUCCESSFUL;
931 /* Get adapter LUID from SetupAPI */
932 mutex = get_display_device_init_mutex();
934 size = sizeof( bufferW );
935 swprintf( key_nameW, MAX_PATH, L"\\Device\\Video%d", index );
936 if (RegGetValueW( HKEY_LOCAL_MACHINE, L"HARDWARE\\DEVICEMAP\\VIDEO", key_nameW,
937 RRF_RT_REG_SZ, NULL, bufferW, &size ))
938 goto done;
940 /* Strip \Registry\Machine\ prefix and retrieve Wine specific data set by the display driver */
941 lstrcpyW( key_nameW, bufferW + 18 );
942 size = sizeof( state_flags );
943 if (RegGetValueW( HKEY_CURRENT_CONFIG, key_nameW, L"StateFlags", RRF_RT_REG_DWORD, NULL,
944 &state_flags, &size ))
945 goto done;
947 if (!(state_flags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP))
948 goto done;
950 size = sizeof( bufferW );
951 if (RegGetValueW( HKEY_CURRENT_CONFIG, key_nameW, L"GPUID", RRF_RT_REG_SZ, NULL, bufferW, &size ))
952 goto done;
954 devinfo = SetupDiCreateDeviceInfoList( &GUID_DEVCLASS_DISPLAY, NULL );
955 device_data.cbSize = sizeof( device_data );
956 SetupDiOpenDeviceInfoW( devinfo, bufferW, NULL, 0, &device_data );
957 if (!SetupDiGetDevicePropertyW( devinfo, &device_data, &DEVPROPKEY_GPU_LUID, &type,
958 (BYTE *)&luid_desc.AdapterLuid, sizeof( luid_desc.AdapterLuid ),
959 NULL, 0))
960 goto done;
962 if ((status = NtGdiDdDDIOpenAdapterFromLuid( &luid_desc ))) goto done;
964 desc->hAdapter = luid_desc.hAdapter;
965 desc->AdapterLuid = luid_desc.AdapterLuid;
966 desc->VidPnSourceId = index;
968 done:
969 SetupDiDestroyDeviceInfoList( devinfo );
970 release_display_device_init_mutex( mutex );
971 return status;
974 /***********************************************************************
975 * SetObjectOwner (GDI32.@)
977 void WINAPI SetObjectOwner( HGDIOBJ handle, HANDLE owner )
979 /* Nothing to do */
982 /***********************************************************************
983 * GdiInitializeLanguagePack (GDI32.@)
985 DWORD WINAPI GdiInitializeLanguagePack( DWORD arg )
987 FIXME( "stub\n" );
988 return 0;
991 /***********************************************************************
992 * GdiGetBatchLimit (GDI32.@)
994 DWORD WINAPI GdiGetBatchLimit(void)
996 return 1; /* FIXME */
999 /***********************************************************************
1000 * GdiSetBatchLimit (GDI32.@)
1002 DWORD WINAPI GdiSetBatchLimit( DWORD limit )
1004 return 1; /* FIXME */
1007 /* Solid colors to enumerate */
1008 static const COLORREF solid_colors[] =
1010 RGB(0x00,0x00,0x00), RGB(0xff,0xff,0xff),
1011 RGB(0xff,0x00,0x00), RGB(0x00,0xff,0x00),
1012 RGB(0x00,0x00,0xff), RGB(0xff,0xff,0x00),
1013 RGB(0xff,0x00,0xff), RGB(0x00,0xff,0xff),
1014 RGB(0x80,0x00,0x00), RGB(0x00,0x80,0x00),
1015 RGB(0x80,0x80,0x00), RGB(0x00,0x00,0x80),
1016 RGB(0x80,0x00,0x80), RGB(0x00,0x80,0x80),
1017 RGB(0x80,0x80,0x80), RGB(0xc0,0xc0,0xc0)
1020 /***********************************************************************
1021 * EnumObjects (GDI32.@)
1023 INT WINAPI EnumObjects( HDC hdc, INT type, GOBJENUMPROC enum_func, LPARAM param )
1025 UINT i;
1026 INT retval = 0;
1027 LOGPEN pen;
1028 LOGBRUSH brush;
1030 TRACE( "%p %d %p %08Ix\n", hdc, type, enum_func, param );
1032 switch(type)
1034 case OBJ_PEN:
1035 /* Enumerate solid pens */
1036 for (i = 0; i < ARRAY_SIZE(solid_colors); i++)
1038 pen.lopnStyle = PS_SOLID;
1039 pen.lopnWidth.x = 1;
1040 pen.lopnWidth.y = 0;
1041 pen.lopnColor = solid_colors[i];
1042 retval = enum_func( &pen, param );
1043 TRACE( "solid pen %08lx, ret=%d\n", solid_colors[i], retval );
1044 if (!retval) break;
1046 break;
1048 case OBJ_BRUSH:
1049 /* Enumerate solid brushes */
1050 for (i = 0; i < ARRAY_SIZE(solid_colors); i++)
1052 brush.lbStyle = BS_SOLID;
1053 brush.lbColor = solid_colors[i];
1054 brush.lbHatch = 0;
1055 retval = enum_func( &brush, param );
1056 TRACE( "solid brush %08lx, ret=%d\n", solid_colors[i], retval );
1057 if (!retval) break;
1060 /* Now enumerate hatched brushes */
1061 for (i = HS_HORIZONTAL; retval && i <= HS_DIAGCROSS; i++)
1063 brush.lbStyle = BS_HATCHED;
1064 brush.lbColor = RGB(0,0,0);
1065 brush.lbHatch = i;
1066 retval = enum_func( &brush, param );
1067 TRACE( "hatched brush %d, ret=%d\n", i, retval );
1069 break;
1071 default:
1072 /* FIXME: implement Win32 types */
1073 WARN( "(%d): Invalid type\n", type );
1074 break;
1077 return retval;
1080 /***********************************************************************
1081 * CombineTransform (GDI32.@)
1083 * Combines two transformation matrices.
1085 BOOL WINAPI CombineTransform( XFORM *result, const XFORM *xform1, const XFORM *xform2 )
1087 XFORM r;
1089 if (!result || !xform1 || !xform2) return FALSE;
1091 /* Create the result in a temporary XFORM, since result may be
1092 * equal to xform1 or xform2 */
1093 r.eM11 = xform1->eM11 * xform2->eM11 + xform1->eM12 * xform2->eM21;
1094 r.eM12 = xform1->eM11 * xform2->eM12 + xform1->eM12 * xform2->eM22;
1095 r.eM21 = xform1->eM21 * xform2->eM11 + xform1->eM22 * xform2->eM21;
1096 r.eM22 = xform1->eM21 * xform2->eM12 + xform1->eM22 * xform2->eM22;
1097 r.eDx = xform1->eDx * xform2->eM11 + xform1->eDy * xform2->eM21 + xform2->eDx;
1098 r.eDy = xform1->eDx * xform2->eM12 + xform1->eDy * xform2->eM22 + xform2->eDy;
1100 *result = r;
1101 return TRUE;
1104 /***********************************************************************
1105 * LineDDA (GDI32.@)
1107 BOOL WINAPI LineDDA( INT x_start, INT y_start, INT x_end, INT y_end,
1108 LINEDDAPROC callback, LPARAM lparam )
1110 INT xadd = 1, yadd = 1;
1111 INT err,erradd;
1112 INT cnt;
1113 INT dx = x_end - x_start;
1114 INT dy = y_end - y_start;
1116 TRACE( "(%d, %d), (%d, %d), %p, %Ix\n", x_start, y_start,
1117 x_end, y_end, callback, lparam );
1119 if (dx < 0)
1121 dx = -dx;
1122 xadd = -1;
1124 if (dy < 0)
1126 dy = -dy;
1127 yadd = -1;
1129 if (dx > dy) /* line is "more horizontal" */
1131 err = 2*dy - dx; erradd = 2*dy - 2*dx;
1132 for(cnt = 0;cnt < dx; cnt++)
1134 callback( x_start, y_start, lparam );
1135 if (err > 0)
1137 y_start += yadd;
1138 err += erradd;
1140 else err += 2*dy;
1141 x_start += xadd;
1144 else /* line is "more vertical" */
1146 err = 2*dx - dy; erradd = 2*dx - 2*dy;
1147 for(cnt = 0; cnt < dy; cnt++)
1149 callback( x_start, y_start, lparam );
1150 if (err > 0)
1152 x_start += xadd;
1153 err += erradd;
1155 else err += 2*dx;
1156 y_start += yadd;
1159 return TRUE;
1162 /***********************************************************************
1163 * GdiDllInitialize (GDI32.@)
1165 * Stub entry point, some games (CoD: Black Ops 3) call it directly.
1167 BOOL WINAPI GdiDllInitialize( HINSTANCE inst, DWORD reason, LPVOID reserved )
1169 FIXME( "stub\n" );
1170 return TRUE;