include: Be consistent in naming regarding MSF's block.
[wine.git] / dlls / win32u / dc.c
blob8379cd353eff42ed76aef7a0bdd073c0e03bda54
1 /*
2 * GDI Device Context functions
4 * Copyright 1993 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #if 0
22 #pragma makedep unix
23 #endif
25 #include <assert.h>
26 #include <stdarg.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <pthread.h>
31 #include "windef.h"
32 #include "winbase.h"
33 #include "wingdi.h"
34 #include "winreg.h"
35 #include "winnls.h"
36 #include "winternl.h"
37 #include "winerror.h"
38 #include "ntgdi_private.h"
39 #include "wine/wgl.h"
40 #include "wine/wgl_driver.h"
42 #include "wine/debug.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(dc);
46 static pthread_mutex_t dc_attr_lock = PTHREAD_MUTEX_INITIALIZER;
48 struct dc_attr_bucket
50 struct list entry;
51 DC_ATTR *entries;
52 DC_ATTR *next_free;
53 DC_ATTR *next_unused;
56 static struct list dc_attr_buckets = LIST_INIT( dc_attr_buckets );
58 static BOOL DC_DeleteObject( HGDIOBJ handle );
60 static const struct gdi_obj_funcs dc_funcs =
62 NULL, /* pGetObjectW */
63 NULL, /* pUnrealizeObject */
64 DC_DeleteObject /* pDeleteObject */
68 static inline DC *get_dc_obj( HDC hdc )
70 DWORD type;
71 DC *dc = get_any_obj_ptr( hdc, &type );
72 if (!dc) return NULL;
74 switch (type)
76 case NTGDI_OBJ_DC:
77 case NTGDI_OBJ_MEMDC:
78 case NTGDI_OBJ_ENHMETADC:
79 return dc;
80 default:
81 GDI_ReleaseObj( hdc );
82 RtlSetLastWin32Error( ERROR_INVALID_HANDLE );
83 return NULL;
87 /* alloc DC_ATTR from a pool of memory accessible from client */
88 static DC_ATTR *alloc_dc_attr(void)
90 struct dc_attr_bucket *bucket;
91 DC_ATTR *dc_attr = NULL;
93 pthread_mutex_lock( &dc_attr_lock );
95 LIST_FOR_EACH_ENTRY( bucket, &dc_attr_buckets, struct dc_attr_bucket, entry )
97 if (bucket->next_free)
99 dc_attr = bucket->next_free;
100 bucket->next_free = *(void **)bucket->next_free;
101 break;
103 if ((char *)bucket->next_unused - (char *)bucket->entries + sizeof(*dc_attr) <=
104 system_info.AllocationGranularity)
106 dc_attr = bucket->next_unused++;
107 break;
111 if (!dc_attr && (bucket = malloc( sizeof(*bucket) )))
113 SIZE_T size = system_info.AllocationGranularity;
114 bucket->entries = NULL;
115 if (!NtAllocateVirtualMemory( GetCurrentProcess(), (void **)&bucket->entries, zero_bits(),
116 &size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE ))
118 bucket->next_free = NULL;
119 bucket->next_unused = bucket->entries + 1;
120 dc_attr = bucket->entries;
121 list_add_head( &dc_attr_buckets, &bucket->entry );
123 else free( bucket );
126 if (dc_attr) memset( dc_attr, 0, sizeof( *dc_attr ));
128 pthread_mutex_unlock( &dc_attr_lock );
130 return dc_attr;
134 static void free_dc_attr( DC_ATTR *dc_attr )
136 struct dc_attr_bucket *bucket;
138 pthread_mutex_lock( &dc_attr_lock );
140 LIST_FOR_EACH_ENTRY( bucket, &dc_attr_buckets, struct dc_attr_bucket, entry )
142 if (bucket->entries > dc_attr || dc_attr >= bucket->next_unused) continue;
143 *(void **)dc_attr = bucket->next_free;
144 bucket->next_free = dc_attr;
145 break;
148 pthread_mutex_unlock( &dc_attr_lock );
152 /***********************************************************************
153 * set_initial_dc_state
155 static void set_initial_dc_state( DC *dc )
157 dc->attr->wnd_org.x = 0;
158 dc->attr->wnd_org.y = 0;
159 dc->attr->wnd_ext.cx = 1;
160 dc->attr->wnd_ext.cy = 1;
161 dc->attr->vport_org.x = 0;
162 dc->attr->vport_org.y = 0;
163 dc->attr->vport_ext.cx = 1;
164 dc->attr->vport_ext.cy = 1;
165 dc->attr->miter_limit = 10.0f; /* 10.0 is the default, from MSDN */
166 dc->attr->layout = 0;
167 dc->attr->rop_mode = R2_COPYPEN;
168 dc->attr->font_code_page = CP_ACP;
169 dc->attr->poly_fill_mode = ALTERNATE;
170 dc->attr->stretch_blt_mode = BLACKONWHITE;
171 dc->attr->rel_abs_mode = ABSOLUTE;
172 dc->attr->background_mode = OPAQUE;
173 dc->attr->background_color = RGB( 255, 255, 255 );
174 dc->attr->brush_color = RGB( 255, 255, 255 );
175 dc->attr->pen_color = RGB( 0, 0, 0 );
176 dc->attr->text_color = RGB( 0, 0, 0 );
177 dc->attr->brush_org.x = 0;
178 dc->attr->brush_org.y = 0;
179 dc->attr->mapper_flags = 0;
180 dc->attr->text_align = TA_LEFT | TA_TOP | TA_NOUPDATECP;
181 dc->attr->char_extra = 0;
182 dc->breakExtra = 0;
183 dc->breakRem = 0;
184 dc->attr->map_mode = MM_TEXT;
185 dc->attr->graphics_mode = GM_COMPATIBLE;
186 dc->attr->cur_pos.x = 0;
187 dc->attr->cur_pos.y = 0;
188 dc->attr->arc_direction = AD_COUNTERCLOCKWISE;
189 dc->xformWorld2Wnd.eM11 = 1.0f;
190 dc->xformWorld2Wnd.eM12 = 0.0f;
191 dc->xformWorld2Wnd.eM21 = 0.0f;
192 dc->xformWorld2Wnd.eM22 = 1.0f;
193 dc->xformWorld2Wnd.eDx = 0.0f;
194 dc->xformWorld2Wnd.eDy = 0.0f;
195 dc->xformWorld2Vport = dc->xformWorld2Wnd;
196 dc->xformVport2World = dc->xformWorld2Wnd;
197 dc->vport2WorldValid = TRUE;
199 reset_bounds( &dc->bounds );
202 /***********************************************************************
203 * alloc_dc_ptr
205 DC *alloc_dc_ptr( DWORD magic )
207 DC *dc;
209 if (!(dc = calloc( 1, sizeof(*dc) ))) return NULL;
210 if (!(dc->attr = alloc_dc_attr()))
212 free( dc );
213 return NULL;
216 dc->nulldrv.funcs = &null_driver;
217 dc->physDev = &dc->nulldrv;
218 dc->thread = GetCurrentThreadId();
219 dc->refcount = 1;
220 dc->hPen = GDI_inc_ref_count( GetStockObject( BLACK_PEN ));
221 dc->hBrush = GDI_inc_ref_count( GetStockObject( WHITE_BRUSH ));
222 dc->hFont = GDI_inc_ref_count( GetStockObject( SYSTEM_FONT ));
223 dc->hPalette = GetStockObject( DEFAULT_PALETTE );
225 set_initial_dc_state( dc );
227 if (!(dc->hSelf = alloc_gdi_handle( &dc->obj, magic, &dc_funcs )))
229 free_dc_attr( dc->attr );
230 free( dc );
231 return NULL;
233 dc->nulldrv.hdc = dc->hSelf;
234 dc->attr->hdc = HandleToUlong( dc->hSelf );
235 set_gdi_client_ptr( dc->hSelf, dc->attr );
237 if (!font_driver.pCreateDC( &dc->physDev, NULL, NULL, NULL ))
239 free_dc_ptr( dc );
240 return NULL;
242 return dc;
247 /***********************************************************************
248 * free_dc_state
250 static void free_dc_state( DC *dc )
252 if (dc->hClipRgn) NtGdiDeleteObjectApp( dc->hClipRgn );
253 if (dc->hMetaRgn) NtGdiDeleteObjectApp( dc->hMetaRgn );
254 if (dc->hVisRgn) NtGdiDeleteObjectApp( dc->hVisRgn );
255 if (dc->region) NtGdiDeleteObjectApp( dc->region );
256 if (dc->path) free_gdi_path( dc->path );
257 free_dc_attr( dc->attr );
258 free( dc );
262 /***********************************************************************
263 * free_dc_ptr
265 void free_dc_ptr( DC *dc )
267 assert( dc->refcount == 1 );
269 while (dc->physDev != &dc->nulldrv)
271 PHYSDEV physdev = dc->physDev;
272 dc->physDev = physdev->next;
273 physdev->funcs->pDeleteDC( physdev );
275 GDI_dec_ref_count( dc->hPen );
276 GDI_dec_ref_count( dc->hBrush );
277 GDI_dec_ref_count( dc->hFont );
278 if (dc->hBitmap)
280 if (dc->is_display)
281 NtGdiDeleteClientObj( dc->hBitmap );
282 else
283 GDI_dec_ref_count( dc->hBitmap );
285 free_gdi_handle( dc->hSelf );
286 free_dc_state( dc );
290 /***********************************************************************
291 * get_dc_ptr
293 * Retrieve a DC pointer but release the GDI lock.
295 DC *get_dc_ptr( HDC hdc )
297 DC *dc = get_dc_obj( hdc );
298 if (!dc) return NULL;
299 if (dc->attr->disabled)
301 GDI_ReleaseObj( hdc );
302 return NULL;
305 if (!InterlockedCompareExchange( &dc->refcount, 1, 0 ))
307 dc->thread = GetCurrentThreadId();
309 else if (dc->thread != GetCurrentThreadId())
311 WARN( "dc %p belongs to thread %04x\n", hdc, dc->thread );
312 GDI_ReleaseObj( hdc );
313 return NULL;
315 else InterlockedIncrement( &dc->refcount );
317 GDI_ReleaseObj( hdc );
318 return dc;
322 /***********************************************************************
323 * release_dc_ptr
325 void release_dc_ptr( DC *dc )
327 LONG ref;
329 dc->thread = 0;
330 ref = InterlockedDecrement( &dc->refcount );
331 assert( ref >= 0 );
332 if (ref) dc->thread = GetCurrentThreadId(); /* we still own it */
336 static void set_bk_color( DC *dc, COLORREF color )
338 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetBkColor );
339 dc->attr->background_color = physdev->funcs->pSetBkColor( physdev, color );
343 static void set_text_color( DC *dc, COLORREF color )
345 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetTextColor );
346 dc->attr->text_color = physdev->funcs->pSetTextColor( physdev, color );
350 /***********************************************************************
351 * DC_InitDC
353 * Setup device-specific DC values for a newly created DC.
355 void DC_InitDC( DC* dc )
357 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pRealizeDefaultPalette );
358 physdev->funcs->pRealizeDefaultPalette( physdev );
359 set_text_color( dc, dc->attr->text_color );
360 set_bk_color( dc, dc->attr->background_color );
361 NtGdiSelectPen( dc->hSelf, dc->hPen );
362 NtGdiSelectBrush( dc->hSelf, dc->hBrush );
363 NtGdiSelectFont( dc->hSelf, dc->hFont );
364 update_dc_clipping( dc );
365 NtGdiSetVirtualResolution( dc->hSelf, 0, 0, 0, 0 );
366 physdev = GET_DC_PHYSDEV( dc, pSetBoundsRect );
367 physdev->funcs->pSetBoundsRect( physdev, &dc->bounds, dc->bounds_enabled ? DCB_ENABLE : DCB_DISABLE );
371 /***********************************************************************
372 * DC_InvertXform
374 * Computes the inverse of the transformation xformSrc and stores it to
375 * xformDest. Returns TRUE if successful or FALSE if the xformSrc matrix
376 * is singular.
378 static BOOL DC_InvertXform( const XFORM *xformSrc, XFORM *xformDest )
380 double determinant;
382 determinant = xformSrc->eM11*xformSrc->eM22 -
383 xformSrc->eM12*xformSrc->eM21;
384 if (determinant > -1e-12 && determinant < 1e-12)
385 return FALSE;
387 xformDest->eM11 = xformSrc->eM22 / determinant;
388 xformDest->eM12 = -xformSrc->eM12 / determinant;
389 xformDest->eM21 = -xformSrc->eM21 / determinant;
390 xformDest->eM22 = xformSrc->eM11 / determinant;
391 xformDest->eDx = -xformSrc->eDx * xformDest->eM11 -
392 xformSrc->eDy * xformDest->eM21;
393 xformDest->eDy = -xformSrc->eDx * xformDest->eM12 -
394 xformSrc->eDy * xformDest->eM22;
396 return TRUE;
399 /* Construct a transformation to do the window-to-viewport conversion */
400 static void construct_window_to_viewport(DC *dc, XFORM *xform)
402 double scaleX, scaleY;
403 scaleX = (double)dc->attr->vport_ext.cx / (double)dc->attr->wnd_ext.cx;
404 scaleY = (double)dc->attr->vport_ext.cy / (double)dc->attr->wnd_ext.cy;
406 if (dc->attr->layout & LAYOUT_RTL) scaleX = -scaleX;
407 xform->eM11 = scaleX;
408 xform->eM12 = 0.0;
409 xform->eM21 = 0.0;
410 xform->eM22 = scaleY;
411 xform->eDx = (double)dc->attr->vport_org.x - scaleX * (double)dc->attr->wnd_org.x;
412 xform->eDy = (double)dc->attr->vport_org.y - scaleY * (double)dc->attr->wnd_org.y;
413 if (dc->attr->layout & LAYOUT_RTL)
414 xform->eDx = dc->attr->vis_rect.right - dc->attr->vis_rect.left - 1 - xform->eDx;
417 /***********************************************************************
418 * linear_xform_cmp
420 * Compares the linear transform portion of two XFORMs (i.e. the 2x2 submatrix).
421 * Returns 0 if they match.
423 static inline int linear_xform_cmp( const XFORM *a, const XFORM *b )
425 return memcmp( a, b, FIELD_OFFSET( XFORM, eDx ) );
428 /***********************************************************************
429 * DC_UpdateXforms
431 * Updates the xformWorld2Vport, xformVport2World and vport2WorldValid
432 * fields of the specified DC by creating a transformation that
433 * represents the current mapping mode and combining it with the DC's
434 * world transform. This function should be called whenever the
435 * parameters associated with the mapping mode (window and viewport
436 * extents and origins) or the world transform change.
438 void DC_UpdateXforms( DC *dc )
440 XFORM xformWnd2Vport, oldworld2vport;
442 construct_window_to_viewport(dc, &xformWnd2Vport);
444 oldworld2vport = dc->xformWorld2Vport;
445 /* Combine with the world transformation */
446 combine_transform( &dc->xformWorld2Vport, &dc->xformWorld2Wnd, &xformWnd2Vport );
448 /* Create inverse of world-to-viewport transformation */
449 dc->vport2WorldValid = DC_InvertXform( &dc->xformWorld2Vport,
450 &dc->xformVport2World );
452 /* Reselect the font and pen back into the dc so that the size
453 gets updated. */
454 if (linear_xform_cmp( &oldworld2vport, &dc->xformWorld2Vport ) &&
455 get_gdi_object_type( dc->hSelf ) != NTGDI_OBJ_METADC)
457 NtGdiSelectFont(dc->hSelf, dc->hFont);
458 NtGdiSelectPen(dc->hSelf, dc->hPen);
463 /***********************************************************************
464 * reset_dc_state
466 static BOOL reset_dc_state( HDC hdc )
468 DC *dc, *dcs, *next;
470 if (!(dc = get_dc_ptr( hdc ))) return FALSE;
472 set_initial_dc_state( dc );
473 set_bk_color( dc, RGB( 255, 255, 255 ));
474 set_text_color( dc, RGB( 0, 0, 0 ));
475 NtGdiSelectBrush( hdc, GetStockObject( WHITE_BRUSH ));
476 NtGdiSelectFont( hdc, GetStockObject( SYSTEM_FONT ));
477 NtGdiSelectPen( hdc, GetStockObject( BLACK_PEN ));
478 NtGdiSetVirtualResolution( hdc, 0, 0, 0, 0 );
479 NtUserSelectPalette( hdc, GetStockObject( DEFAULT_PALETTE ), FALSE );
480 NtGdiSetBoundsRect( hdc, NULL, DCB_DISABLE );
481 NtGdiAbortPath( hdc );
483 if (dc->hClipRgn) NtGdiDeleteObjectApp( dc->hClipRgn );
484 if (dc->hMetaRgn) NtGdiDeleteObjectApp( dc->hMetaRgn );
485 dc->hClipRgn = 0;
486 dc->hMetaRgn = 0;
487 update_dc_clipping( dc );
489 for (dcs = dc->saved_dc; dcs; dcs = next)
491 next = dcs->saved_dc;
492 free_dc_state( dcs );
494 dc->saved_dc = NULL;
495 dc->attr->save_level = 0;
496 release_dc_ptr( dc );
497 return TRUE;
501 /***********************************************************************
502 * DC_DeleteObject
504 static BOOL DC_DeleteObject( HGDIOBJ handle )
506 DC *dc;
508 TRACE( "%p\n", handle );
510 if (!(dc = get_dc_ptr( handle ))) return FALSE;
511 if (dc->refcount != 1)
513 FIXME( "not deleting busy DC %p refcount %u\n", dc->hSelf, (int)dc->refcount );
514 release_dc_ptr( dc );
515 return FALSE;
518 /* Call hook procedure to check whether is it OK to delete this DC,
519 * gdi_lock should not be locked */
520 if (dc->dce && !delete_dce( dc->dce ))
522 release_dc_ptr( dc );
523 return TRUE;
525 reset_dc_state( handle );
526 free_dc_ptr( dc );
527 return TRUE;
531 /***********************************************************************
532 * NtGdiSaveDC (win32u.@)
534 INT WINAPI NtGdiSaveDC( HDC hdc )
536 DC *dc, *newdc;
537 INT ret;
539 if (!(dc = get_dc_ptr( hdc ))) return 0;
541 if (!(newdc = calloc( 1, sizeof(*newdc ))))
543 release_dc_ptr( dc );
544 return 0;
546 if (!(newdc->attr = alloc_dc_attr() ))
548 free( newdc );
549 release_dc_ptr( dc );
550 return 0;
553 *newdc->attr = *dc->attr;
554 newdc->hPen = dc->hPen;
555 newdc->hBrush = dc->hBrush;
556 newdc->hFont = dc->hFont;
557 newdc->hBitmap = dc->hBitmap;
558 newdc->hPalette = dc->hPalette;
559 newdc->breakExtra = dc->breakExtra;
560 newdc->breakRem = dc->breakRem;
561 newdc->xformWorld2Wnd = dc->xformWorld2Wnd;
562 newdc->xformWorld2Vport = dc->xformWorld2Vport;
563 newdc->xformVport2World = dc->xformVport2World;
564 newdc->vport2WorldValid = dc->vport2WorldValid;
566 /* Get/SetDCState() don't change hVisRgn field ("Undoc. Windows" p.559). */
568 if (dc->hClipRgn)
570 newdc->hClipRgn = NtGdiCreateRectRgn( 0, 0, 0, 0 );
571 NtGdiCombineRgn( newdc->hClipRgn, dc->hClipRgn, 0, RGN_COPY );
573 if (dc->hMetaRgn)
575 newdc->hMetaRgn = NtGdiCreateRectRgn( 0, 0, 0, 0 );
576 NtGdiCombineRgn( newdc->hMetaRgn, dc->hMetaRgn, 0, RGN_COPY );
579 if (!PATH_SavePath( newdc, dc ))
581 release_dc_ptr( dc );
582 free_dc_state( newdc );
583 return 0;
586 newdc->saved_dc = dc->saved_dc;
587 dc->saved_dc = newdc;
588 ret = ++dc->attr->save_level;
589 release_dc_ptr( dc );
590 return ret;
594 /***********************************************************************
595 * NtGdiRestoreDC (win32u.@)
597 BOOL WINAPI NtGdiRestoreDC( HDC hdc, INT level )
599 DC *dc, *dcs, *first_dcs;
600 INT save_level;
602 TRACE("%p %d\n", hdc, level );
603 if (!(dc = get_dc_ptr( hdc ))) return FALSE;
604 update_dc( dc );
606 /* find the state level to restore */
607 if (abs(level) > dc->attr->save_level || level == 0)
609 release_dc_ptr( dc );
610 return FALSE;
613 if (level < 0) level = dc->attr->save_level + level + 1;
614 first_dcs = dc->saved_dc;
615 for (dcs = first_dcs, save_level = dc->attr->save_level; save_level > level; save_level--)
616 dcs = dcs->saved_dc;
618 /* restore the state */
620 if (!PATH_RestorePath( dc, dcs ))
622 release_dc_ptr( dc );
623 return FALSE;
626 dc->attr->layout = dcs->attr->layout;
627 dc->attr->rop_mode = dcs->attr->rop_mode;
628 dc->attr->poly_fill_mode = dcs->attr->poly_fill_mode;
629 dc->attr->stretch_blt_mode = dcs->attr->stretch_blt_mode;
630 dc->attr->rel_abs_mode = dcs->attr->rel_abs_mode;
631 dc->attr->background_mode = dcs->attr->background_mode;
632 dc->attr->background_color = dcs->attr->background_color;
633 dc->attr->text_color = dcs->attr->text_color;
634 dc->attr->brush_color = dcs->attr->brush_color;
635 dc->attr->pen_color = dcs->attr->pen_color;
636 dc->attr->brush_org = dcs->attr->brush_org;
637 dc->attr->mapper_flags = dcs->attr->mapper_flags;
638 dc->attr->text_align = dcs->attr->text_align;
639 dc->attr->char_extra = dcs->attr->char_extra;
640 dc->attr->map_mode = dcs->attr->map_mode;
641 dc->attr->graphics_mode = dcs->attr->graphics_mode;
642 dc->attr->cur_pos = dcs->attr->cur_pos;
643 dc->attr->arc_direction = dcs->attr->arc_direction;
644 dc->attr->wnd_org = dcs->attr->wnd_org;
645 dc->attr->wnd_ext = dcs->attr->wnd_ext;
646 dc->attr->vport_org = dcs->attr->vport_org;
647 dc->attr->vport_ext = dcs->attr->vport_ext;
648 dc->attr->virtual_res = dcs->attr->virtual_res;
649 dc->attr->virtual_size = dcs->attr->virtual_size;
651 dc->breakExtra = dcs->breakExtra;
652 dc->breakRem = dcs->breakRem;
653 dc->xformWorld2Wnd = dcs->xformWorld2Wnd;
654 dc->xformWorld2Vport = dcs->xformWorld2Vport;
655 dc->xformVport2World = dcs->xformVport2World;
656 dc->vport2WorldValid = dcs->vport2WorldValid;
658 if (dcs->hClipRgn)
660 if (!dc->hClipRgn) dc->hClipRgn = NtGdiCreateRectRgn( 0, 0, 0, 0 );
661 NtGdiCombineRgn( dc->hClipRgn, dcs->hClipRgn, 0, RGN_COPY );
663 else
665 if (dc->hClipRgn) NtGdiDeleteObjectApp( dc->hClipRgn );
666 dc->hClipRgn = 0;
668 if (dcs->hMetaRgn)
670 if (!dc->hMetaRgn) dc->hMetaRgn = NtGdiCreateRectRgn( 0, 0, 0, 0 );
671 NtGdiCombineRgn( dc->hMetaRgn, dcs->hMetaRgn, 0, RGN_COPY );
673 else
675 if (dc->hMetaRgn) NtGdiDeleteObjectApp( dc->hMetaRgn );
676 dc->hMetaRgn = 0;
678 DC_UpdateXforms( dc );
679 update_dc_clipping( dc );
681 NtGdiSelectBitmap( hdc, dcs->hBitmap );
682 NtGdiSelectBrush( hdc, dcs->hBrush );
683 NtGdiSelectFont( hdc, dcs->hFont );
684 NtGdiSelectPen( hdc, dcs->hPen );
685 set_bk_color( dc, dcs->attr->background_color);
686 set_text_color( dc, dcs->attr->text_color);
687 NtUserSelectPalette( hdc, dcs->hPalette, FALSE );
689 dc->saved_dc = dcs->saved_dc;
690 dcs->saved_dc = 0;
691 dc->attr->save_level = save_level - 1;
693 /* now destroy all the saved DCs */
695 while (first_dcs)
697 DC *next = first_dcs->saved_dc;
698 free_dc_state( first_dcs );
699 first_dcs = next;
701 release_dc_ptr( dc );
702 return TRUE;
706 /***********************************************************************
707 * NtGdiOpenDCW (win32u.@)
709 HDC WINAPI NtGdiOpenDCW( UNICODE_STRING *device, const DEVMODEW *devmode, UNICODE_STRING *output,
710 ULONG type, BOOL is_display, HANDLE hspool, DRIVER_INFO_2W *driver_info,
711 void *pdev )
713 const struct gdi_dc_funcs *funcs = NULL;
714 HDC hdc;
715 DC * dc;
717 /* gdi_lock should not be locked */
718 if (is_display)
719 funcs = get_display_driver();
720 else if (hspool)
722 const struct gdi_dc_funcs * (CDECL *wine_get_gdi_driver)( unsigned int ) = hspool;
723 funcs = wine_get_gdi_driver( WINE_GDI_DRIVER_VERSION );
725 if (!funcs)
727 ERR( "no driver found\n" );
728 return 0;
731 if (!(dc = alloc_dc_ptr( NTGDI_OBJ_DC ))) return 0;
732 hdc = dc->hSelf;
734 if (is_display)
735 dc->hBitmap = NtGdiCreateClientObj( NTGDI_OBJ_SURF );
736 else
737 dc->hBitmap = GDI_inc_ref_count( GetStockObject( DEFAULT_BITMAP ));
739 TRACE("(device=%s, output=%s): returning %p\n",
740 debugstr_us(device), debugstr_us(output), dc->hSelf );
742 if (funcs->pCreateDC)
744 if (!funcs->pCreateDC( &dc->physDev, device ? device->Buffer : NULL,
745 output ? output->Buffer : NULL, devmode ))
747 WARN("creation aborted by device\n" );
748 free_dc_ptr( dc );
749 return 0;
753 if (is_display && device)
755 memcpy( dc->display, device->Buffer, device->Length );
756 dc->display[device->Length / sizeof(WCHAR)] = 0;
760 dc->attr->vis_rect.left = 0;
761 dc->attr->vis_rect.top = 0;
762 dc->attr->vis_rect.right = NtGdiGetDeviceCaps( hdc, DESKTOPHORZRES );
763 dc->attr->vis_rect.bottom = NtGdiGetDeviceCaps( hdc, DESKTOPVERTRES );
764 dc->is_display = !!is_display;
766 DC_InitDC( dc );
767 release_dc_ptr( dc );
769 if (driver_info && driver_info->cVersion == NTGDI_WIN16_DIB &&
770 !create_dib_surface( hdc, pdev ))
772 NtGdiDeleteObjectApp( hdc );
773 return 0;
775 return hdc;
779 /***********************************************************************
780 * NtGdiCreateCompatibleDC (win32u.@)
782 HDC WINAPI NtGdiCreateCompatibleDC( HDC hdc )
784 DC *dc, *origDC;
785 HDC ret;
786 const struct gdi_dc_funcs *funcs;
787 PHYSDEV physDev = NULL;
789 /* gdi_lock should not be locked */
791 if (hdc)
793 if (!(origDC = get_dc_ptr( hdc ))) return 0;
794 physDev = GET_DC_PHYSDEV( origDC, pCreateCompatibleDC );
795 funcs = physDev->funcs;
796 release_dc_ptr( origDC );
798 else funcs = get_display_driver();
800 if (!(dc = alloc_dc_ptr( NTGDI_OBJ_MEMDC ))) return 0;
802 TRACE("(%p): returning %p\n", hdc, dc->hSelf );
804 dc->hBitmap = GDI_inc_ref_count( GetStockObject( DEFAULT_BITMAP ));
805 dc->attr->vis_rect.left = 0;
806 dc->attr->vis_rect.top = 0;
807 dc->attr->vis_rect.right = 1;
808 dc->attr->vis_rect.bottom = 1;
809 dc->device_rect = dc->attr->vis_rect;
811 ret = dc->hSelf;
813 if (funcs->pCreateCompatibleDC && !funcs->pCreateCompatibleDC( physDev, &dc->physDev ))
815 WARN("creation aborted by device\n");
816 free_dc_ptr( dc );
817 return 0;
820 if (!dib_driver.pCreateDC( &dc->physDev, NULL, NULL, NULL ))
822 free_dc_ptr( dc );
823 return 0;
825 physDev = GET_DC_PHYSDEV( dc, pSelectBitmap );
826 physDev->funcs->pSelectBitmap( physDev, dc->hBitmap );
828 DC_InitDC( dc );
829 release_dc_ptr( dc );
830 return ret;
834 /***********************************************************************
835 * NtGdiResetDC (win32u.@)
837 BOOL WINAPI NtGdiResetDC( HDC hdc, const DEVMODEW *devmode, BOOL *banding,
838 DRIVER_INFO_2W *driver_info, void *dev )
840 DC *dc;
841 BOOL ret = FALSE;
843 if ((dc = get_dc_ptr( hdc )))
845 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pResetDC );
846 ret = physdev->funcs->pResetDC( physdev, devmode ) != 0;
847 if (ret) /* reset the visible region */
849 dc->dirty = 0;
850 dc->attr->vis_rect.left = 0;
851 dc->attr->vis_rect.top = 0;
852 dc->attr->vis_rect.right = NtGdiGetDeviceCaps( hdc, DESKTOPHORZRES );
853 dc->attr->vis_rect.bottom = NtGdiGetDeviceCaps( hdc, DESKTOPVERTRES );
854 if (dc->hVisRgn) NtGdiDeleteObjectApp( dc->hVisRgn );
855 dc->hVisRgn = 0;
856 update_dc_clipping( dc );
858 release_dc_ptr( dc );
860 return ret;
864 /***********************************************************************
865 * NtGdiGetDeviceCaps (win32u.@)
867 INT WINAPI NtGdiGetDeviceCaps( HDC hdc, INT cap )
869 DC *dc;
870 INT ret = 0;
872 if ((dc = get_dc_ptr( hdc )))
874 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pGetDeviceCaps );
875 ret = physdev->funcs->pGetDeviceCaps( physdev, cap );
876 release_dc_ptr( dc );
878 return ret;
882 static BOOL set_graphics_mode( DC *dc, int mode )
884 if (mode == dc->attr->graphics_mode) return TRUE;
885 if (mode <= 0 || mode > GM_LAST) return FALSE;
887 /* One would think that setting the graphics mode to GM_COMPATIBLE
888 * would also reset the world transformation matrix to the unity
889 * matrix. However, in Windows, this is not the case. This doesn't
890 * make a lot of sense to me, but that's the way it is.
892 dc->attr->graphics_mode = mode;
894 /* font metrics depend on the graphics mode */
895 NtGdiSelectFont(dc->hSelf, dc->hFont);
896 return TRUE;
900 DWORD set_stretch_blt_mode( HDC hdc, DWORD mode )
902 DWORD ret;
903 DC *dc;
904 if (!(dc = get_dc_ptr( hdc ))) return 0;
905 ret = dc->attr->stretch_blt_mode;
906 dc->attr->stretch_blt_mode = mode;
907 release_dc_ptr( dc );
908 return ret;
912 /***********************************************************************
913 * NtGdiGetAndSetDCDword (win32u.@)
915 BOOL WINAPI NtGdiGetAndSetDCDword( HDC hdc, UINT method, DWORD value, DWORD *prev_value )
917 PHYSDEV physdev;
918 BOOL ret = TRUE;
919 DWORD prev;
920 DC *dc;
922 if (!(dc = get_dc_ptr( hdc ))) return 0;
924 switch (method)
926 case NtGdiSetMapMode:
927 prev = dc->attr->map_mode;
928 ret = set_map_mode( dc, value );
929 break;
931 case NtGdiSetBkColor:
932 prev = dc->attr->background_color;
933 set_bk_color( dc, value );
934 break;
936 case NtGdiSetBkMode:
937 prev = dc->attr->background_mode;
938 dc->attr->background_mode = value;
939 break;
941 case NtGdiSetTextColor:
942 prev = dc->attr->text_color;
943 set_text_color( dc, value );
944 break;
946 case NtGdiSetDCBrushColor:
947 physdev = GET_DC_PHYSDEV( dc, pSetDCBrushColor );
948 prev = dc->attr->brush_color;
949 value = physdev->funcs->pSetDCBrushColor( physdev, value );
950 if (value != CLR_INVALID) dc->attr->brush_color = value;
951 break;
953 case NtGdiSetDCPenColor:
954 physdev = GET_DC_PHYSDEV( dc, pSetDCPenColor );
955 prev = dc->attr->pen_color;
956 value = physdev->funcs->pSetDCPenColor( physdev, value );
957 if (value != CLR_INVALID) dc->attr->pen_color = value;
958 break;
960 case NtGdiSetGraphicsMode:
961 prev = dc->attr->graphics_mode;
962 ret = set_graphics_mode( dc, value );
963 break;
965 case NtGdiSetROP2:
966 prev = dc->attr->rop_mode;
967 dc->attr->rop_mode = value;
968 break;
970 case NtGdiSetTextAlign:
971 prev = dc->attr->text_align;
972 dc->attr->text_align = value;
973 break;
975 default:
976 WARN( "unknown method %u\n", method );
977 ret = FALSE;
978 break;
981 release_dc_ptr( dc );
982 if (!ret || !prev_value) return FALSE;
983 *prev_value = prev;
984 return TRUE;
988 /***********************************************************************
989 * NtGdiGetDCDword (win32u.@)
991 BOOL WINAPI NtGdiGetDCDword( HDC hdc, UINT method, DWORD *result )
993 BOOL ret = TRUE;
994 DC *dc;
996 if (!(dc = get_dc_ptr( hdc ))) return 0;
998 switch (method)
1000 case NtGdiGetArcDirection:
1001 *result = dc->attr->arc_direction;
1002 break;
1004 case NtGdiGetBkColor:
1005 *result = dc->attr->background_color;
1006 break;
1008 case NtGdiGetBkMode:
1009 *result = dc->attr->background_mode;
1010 break;
1012 case NtGdiGetDCBrushColor:
1013 *result = dc->attr->brush_color;
1014 break;
1016 case NtGdiGetDCPenColor:
1017 *result = dc->attr->pen_color;
1018 break;
1020 case NtGdiGetGraphicsMode:
1021 *result = dc->attr->graphics_mode;
1022 break;
1024 case NtGdiGetLayout:
1025 *result = dc->attr->layout;
1026 break;
1028 case NtGdiGetPolyFillMode:
1029 *result = dc->attr->poly_fill_mode;
1030 break;
1032 case NtGdiGetROP2:
1033 *result = dc->attr->rop_mode;
1034 break;
1036 case NtGdiGetTextColor:
1037 *result = dc->attr->text_color;
1038 break;
1040 case NtGdiIsMemDC:
1041 *result = get_gdi_object_type( hdc ) == NTGDI_OBJ_MEMDC;
1042 break;
1044 default:
1045 WARN( "unknown method %u\n", method );
1046 ret = FALSE;
1047 break;
1050 release_dc_ptr( dc );
1051 return ret;
1055 /***********************************************************************
1056 * NtGdiGetDCPoint (win32u.@)
1058 BOOL WINAPI NtGdiGetDCPoint( HDC hdc, UINT method, POINT *result )
1060 BOOL ret = TRUE;
1061 DC *dc;
1063 if (!(dc = get_dc_ptr( hdc ))) return 0;
1065 switch (method)
1067 case NtGdiGetBrushOrgEx:
1068 *result = dc->attr->brush_org;
1069 break;
1071 case NtGdiGetCurrentPosition:
1072 *result = dc->attr->cur_pos;
1073 break;
1075 case NtGdiGetDCOrg:
1076 result->x = dc->attr->vis_rect.left;
1077 result->y = dc->attr->vis_rect.top;
1078 break;
1080 default:
1081 WARN( "unknown method %u\n", method );
1082 ret = FALSE;
1083 break;
1086 release_dc_ptr( dc );
1087 return ret;
1091 /***********************************************************************
1092 * NtGdiSetBrushOrg (win32u.@)
1094 BOOL WINAPI NtGdiSetBrushOrg( HDC hdc, INT x, INT y, POINT *oldorg )
1096 DC *dc;
1098 if (!(dc = get_dc_ptr( hdc ))) return FALSE;
1099 if (oldorg) *oldorg = dc->attr->brush_org;
1100 dc->attr->brush_org.x = x;
1101 dc->attr->brush_org.y = y;
1102 release_dc_ptr( dc );
1103 return TRUE;
1107 BOOL set_viewport_org( HDC hdc, INT x, INT y, POINT *point )
1109 DC *dc;
1111 if (!(dc = get_dc_ptr( hdc ))) return FALSE;
1112 if (point) *point = dc->attr->vport_org;
1113 dc->attr->vport_org.x = x;
1114 dc->attr->vport_org.y = y;
1115 release_dc_ptr( dc );
1116 return NtGdiComputeXformCoefficients( hdc );
1120 /***********************************************************************
1121 * NtGdiGetTransform (win32u.@)
1123 * Undocumented
1125 * Returns one of the co-ordinate space transforms
1127 * PARAMS
1128 * hdc [I] Device context.
1129 * which [I] Which xform to return:
1130 * 0x203 World -> Page transform (that set by SetWorldTransform).
1131 * 0x304 Page -> Device transform (the mapping mode transform).
1132 * 0x204 World -> Device transform (the combination of the above two).
1133 * 0x402 Device -> World transform (the inversion of the above).
1134 * xform [O] The xform.
1137 BOOL WINAPI NtGdiGetTransform( HDC hdc, DWORD which, XFORM *xform )
1139 BOOL ret = TRUE;
1140 DC *dc = get_dc_ptr( hdc );
1141 if (!dc) return FALSE;
1143 switch(which)
1145 case 0x203:
1146 *xform = dc->xformWorld2Wnd;
1147 break;
1149 case 0x304:
1150 construct_window_to_viewport(dc, xform);
1151 break;
1153 case 0x204:
1154 *xform = dc->xformWorld2Vport;
1155 break;
1157 case 0x402:
1158 *xform = dc->xformVport2World;
1159 break;
1161 default:
1162 FIXME("Unknown code %x\n", (int)which);
1163 ret = FALSE;
1166 release_dc_ptr( dc );
1167 return ret;
1171 /***********************************************************************
1172 * set_dc_dce
1174 void set_dc_dce( HDC hdc, struct dce *dce )
1176 DC *dc;
1178 if (!(dc = get_dc_obj( hdc ))) return;
1179 if (dc->attr->disabled)
1181 GDI_ReleaseObj( hdc );
1182 return;
1184 dc->dce = dce;
1185 if (dce) dc->dirty = 1;
1186 GDI_ReleaseObj( hdc );
1190 /***********************************************************************
1191 * get_dc_dce
1193 struct dce *get_dc_dce( HDC hdc )
1195 DC *dc = get_dc_obj( hdc );
1196 struct dce *ret = NULL;
1198 if (!dc) return 0;
1199 if (!dc->attr->disabled) ret = dc->dce;
1200 GDI_ReleaseObj( hdc );
1201 return ret;
1205 /***********************************************************************
1206 * set_dce_flags
1208 WORD set_dce_flags( HDC hdc, WORD flags )
1210 DC *dc = get_dc_obj( hdc ); /* not get_dc_ptr, this needs to work from any thread */
1211 LONG ret = 0;
1213 if (!dc) return 0;
1215 TRACE("hDC %p, flags %04x\n",hdc,flags);
1217 if (flags & DCHF_INVALIDATEVISRGN)
1218 ret = InterlockedExchange( &dc->dirty, 1 );
1219 else if (flags & DCHF_VALIDATEVISRGN || !flags)
1220 ret = InterlockedExchange( &dc->dirty, 0 );
1222 if (flags & DCHF_DISABLEDC)
1223 ret = InterlockedExchange( &dc->attr->disabled, 1 );
1224 else if (flags & DCHF_ENABLEDC)
1225 ret = InterlockedExchange( &dc->attr->disabled, 0 );
1227 GDI_ReleaseObj( hdc );
1229 if (flags & DCHF_RESETDC) ret = reset_dc_state( hdc );
1230 return ret;
1233 /***********************************************************************
1234 * NtGdiGetDeviceGammaRamp (win32u.@)
1236 BOOL WINAPI NtGdiGetDeviceGammaRamp( HDC hdc, void *ptr )
1238 BOOL ret = FALSE;
1239 DC *dc = get_dc_ptr( hdc );
1241 TRACE("%p, %p\n", hdc, ptr);
1242 if( dc )
1244 if (get_gdi_object_type( hdc ) != NTGDI_OBJ_MEMDC)
1246 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pGetDeviceGammaRamp );
1247 ret = physdev->funcs->pGetDeviceGammaRamp( physdev, ptr );
1249 else RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
1250 release_dc_ptr( dc );
1252 return ret;
1255 static BOOL check_gamma_ramps(void *ptr)
1257 WORD *ramp = ptr;
1259 while (ramp < (WORD*)ptr + 3 * 256)
1261 float r_x, r_y, r_lx, r_ly, r_d, r_v, r_e, g_avg, g_min, g_max;
1262 unsigned i, f, l, g_n, c;
1264 f = ramp[0];
1265 l = ramp[255];
1266 if (f >= l)
1268 TRACE("inverted or flat gamma ramp (%d->%d), rejected\n", f, l);
1269 return FALSE;
1271 r_d = l - f;
1272 g_min = g_max = g_avg = 0.0;
1274 /* check gamma ramp entries to estimate the gamma */
1275 TRACE("analyzing gamma ramp (%d->%d)\n", f, l);
1276 for (i=1, g_n=0; i<255; i++)
1278 if (ramp[i] < f || ramp[i] > l)
1280 TRACE("strange gamma ramp ([%d]=%d for %d->%d), rejected\n", i, ramp[i], f, l);
1281 return FALSE;
1283 c = ramp[i] - f;
1284 if (!c) continue; /* avoid log(0) */
1286 /* normalize entry values into 0..1 range */
1287 r_x = i/255.0; r_y = c / r_d;
1288 /* compute logarithms of values */
1289 r_lx = log(r_x); r_ly = log(r_y);
1290 /* compute gamma for this entry */
1291 r_v = r_ly / r_lx;
1292 /* compute differential (error estimate) for this entry */
1293 /* some games use table-based logarithms that magnifies the error by 128 */
1294 r_e = -r_lx * 128 / (c * r_lx * r_lx);
1296 /* compute min & max while compensating for estimated error */
1297 if (!g_n || g_min > (r_v + r_e)) g_min = r_v + r_e;
1298 if (!g_n || g_max < (r_v - r_e)) g_max = r_v - r_e;
1300 /* add to average */
1301 g_avg += r_v;
1302 g_n++;
1305 if (!g_n)
1307 TRACE("no gamma data, shouldn't happen\n");
1308 return FALSE;
1310 g_avg /= g_n;
1311 TRACE("low bias is %d, high is %d, gamma is %5.3f\n", f, 65535-l, g_avg);
1313 /* check that the gamma is reasonably uniform across the ramp */
1314 if (g_max - g_min > 12.8)
1316 TRACE("ramp not uniform (max=%f, min=%f, avg=%f), rejected\n", g_max, g_min, g_avg);
1317 return FALSE;
1320 /* check that the gamma is not too bright */
1321 if (g_avg < 0.2)
1323 TRACE("too bright gamma ( %5.3f), rejected\n", g_avg);
1324 return FALSE;
1327 ramp += 256;
1330 return TRUE;
1333 /***********************************************************************
1334 * NtGdiSetDeviceGammaRamp (win32u.@)
1336 BOOL WINAPI NtGdiSetDeviceGammaRamp( HDC hdc, void *ptr )
1338 BOOL ret = FALSE;
1339 DC *dc = get_dc_ptr( hdc );
1341 TRACE( "%p, %p\n", hdc, ptr );
1342 if( dc )
1344 if (get_gdi_object_type( hdc ) != NTGDI_OBJ_MEMDC)
1346 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetDeviceGammaRamp );
1348 if (check_gamma_ramps(ptr))
1349 ret = physdev->funcs->pSetDeviceGammaRamp( physdev, ptr );
1351 else RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
1352 release_dc_ptr( dc );
1354 return ret;
1358 /***********************************************************************
1359 * NtGdiGetBoundsRect (win32u.@)
1361 UINT WINAPI NtGdiGetBoundsRect( HDC hdc, RECT *rect, UINT flags )
1363 PHYSDEV physdev;
1364 RECT device_rect;
1365 UINT ret;
1366 DC *dc = get_dc_ptr( hdc );
1368 if ( !dc ) return 0;
1370 physdev = GET_DC_PHYSDEV( dc, pGetBoundsRect );
1371 ret = physdev->funcs->pGetBoundsRect( physdev, &device_rect, DCB_RESET );
1372 if (!ret)
1374 release_dc_ptr( dc );
1375 return 0;
1377 if (dc->bounds_enabled && ret == DCB_SET) add_bounds_rect( &dc->bounds, &device_rect );
1379 if (rect)
1381 if (IsRectEmpty( &dc->bounds ))
1383 rect->left = rect->top = rect->right = rect->bottom = 0;
1384 ret = DCB_RESET;
1386 else
1388 *rect = dc->bounds;
1389 rect->left = max( rect->left, 0 );
1390 rect->top = max( rect->top, 0 );
1391 rect->right = min( rect->right, dc->attr->vis_rect.right - dc->attr->vis_rect.left );
1392 rect->bottom = min( rect->bottom, dc->attr->vis_rect.bottom - dc->attr->vis_rect.top );
1393 ret = DCB_SET;
1395 dp_to_lp( dc, (POINT *)rect, 2 );
1397 else ret = 0;
1399 if (flags & DCB_RESET) reset_bounds( &dc->bounds );
1400 release_dc_ptr( dc );
1401 return ret;
1405 /***********************************************************************
1406 * NtGdiSetBoundsRect (win32u.@)
1408 UINT WINAPI NtGdiSetBoundsRect( HDC hdc, const RECT *rect, UINT flags )
1410 PHYSDEV physdev;
1411 UINT ret;
1412 DC *dc;
1414 if ((flags & DCB_ENABLE) && (flags & DCB_DISABLE)) return 0;
1415 if (!(dc = get_dc_ptr( hdc ))) return 0;
1417 physdev = GET_DC_PHYSDEV( dc, pSetBoundsRect );
1418 ret = physdev->funcs->pSetBoundsRect( physdev, &dc->bounds, flags );
1419 if (!ret)
1421 release_dc_ptr( dc );
1422 return 0;
1425 ret = (dc->bounds_enabled ? DCB_ENABLE : DCB_DISABLE) |
1426 (IsRectEmpty( &dc->bounds ) ? ret & DCB_SET : DCB_SET);
1428 if (flags & DCB_RESET) reset_bounds( &dc->bounds );
1430 if ((flags & DCB_ACCUMULATE) && rect)
1432 RECT rc = *rect;
1434 lp_to_dp( dc, (POINT *)&rc, 2 );
1435 add_bounds_rect( &dc->bounds, &rc );
1438 if (flags & DCB_ENABLE) dc->bounds_enabled = TRUE;
1439 if (flags & DCB_DISABLE) dc->bounds_enabled = FALSE;
1441 release_dc_ptr( dc );
1442 return ret;
1446 /***********************************************************************
1447 * NtGdiSetLayout (win32u.@)
1449 * Sets left->right or right->left text layout flags of a dc.
1452 DWORD WINAPI NtGdiSetLayout( HDC hdc, LONG wox, DWORD layout )
1454 UINT old_layout = GDI_ERROR;
1455 DC *dc;
1457 if ((dc = get_dc_ptr( hdc )))
1459 old_layout = dc->attr->layout;
1460 dc->attr->layout = layout;
1461 if (layout != old_layout)
1463 if (layout & LAYOUT_RTL) dc->attr->map_mode = MM_ANISOTROPIC;
1464 DC_UpdateXforms( dc );
1466 release_dc_ptr( dc );
1469 TRACE("hdc : %p, old layout : %08x, new layout : %08x\n", hdc, old_layout, (int)layout);
1471 return old_layout;
1474 /**********************************************************************
1475 * __wine_get_icm_profile (win32u.@)
1477 BOOL CDECL __wine_get_icm_profile( HDC hdc, BOOL allow_default, DWORD *size, WCHAR *filename )
1479 PHYSDEV physdev;
1480 DC *dc;
1481 BOOL ret;
1483 if (!(dc = get_dc_ptr(hdc))) return FALSE;
1485 physdev = GET_DC_PHYSDEV( dc, pGetICMProfile );
1486 ret = physdev->funcs->pGetICMProfile( physdev, allow_default, size, filename );
1487 release_dc_ptr(dc);
1488 return ret;
1491 /***********************************************************************
1492 * __wine_get_wgl_driver (win32u.@)
1494 struct opengl_funcs *__wine_get_wgl_driver( HDC hdc, UINT version )
1496 BOOL is_display, is_memdc;
1497 DC *dc;
1499 if (version != WINE_WGL_DRIVER_VERSION)
1501 ERR( "version mismatch, opengl32 wants %u but dibdrv has %u\n",
1502 version, WINE_WGL_DRIVER_VERSION );
1503 return NULL;
1506 if (!(dc = get_dc_obj( hdc ))) return NULL;
1507 if (dc->attr->disabled)
1509 GDI_ReleaseObj( hdc );
1510 return NULL;
1512 is_display = dc->is_display;
1513 is_memdc = get_gdi_object_type( hdc ) == NTGDI_OBJ_MEMDC;
1514 GDI_ReleaseObj( hdc );
1516 if (is_display) return user_driver->pwine_get_wgl_driver( version );
1517 if (is_memdc) return dibdrv_get_wgl_driver();
1518 return (void *)-1;