cmd: DIR command outputs free space for the path.
[wine.git] / dlls / win32u / dc.c
blob0ff624068cb2a008cbeacc801fb927086c569507
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 (type != WINE_GDI_DRIVER_VERSION)
721 ERR( "version mismatch: %u\n", (unsigned int)type );
722 else
723 funcs = hspool;
724 if (!funcs)
726 ERR( "no driver found\n" );
727 return 0;
730 if (!(dc = alloc_dc_ptr( NTGDI_OBJ_DC ))) return 0;
731 hdc = dc->hSelf;
733 if (is_display)
734 dc->hBitmap = NtGdiCreateClientObj( NTGDI_OBJ_SURF );
735 else
736 dc->hBitmap = GDI_inc_ref_count( GetStockObject( DEFAULT_BITMAP ));
738 TRACE("(device=%s, output=%s): returning %p\n",
739 debugstr_us(device), debugstr_us(output), dc->hSelf );
741 if (funcs->pCreateDC)
743 if (!funcs->pCreateDC( &dc->physDev, device ? device->Buffer : NULL,
744 output ? output->Buffer : NULL, devmode ))
746 WARN("creation aborted by device\n" );
747 free_dc_ptr( dc );
748 return 0;
752 if (is_display && device)
754 memcpy( dc->display, device->Buffer, device->Length );
755 dc->display[device->Length / sizeof(WCHAR)] = 0;
759 dc->attr->vis_rect.left = 0;
760 dc->attr->vis_rect.top = 0;
761 dc->attr->vis_rect.right = NtGdiGetDeviceCaps( hdc, DESKTOPHORZRES );
762 dc->attr->vis_rect.bottom = NtGdiGetDeviceCaps( hdc, DESKTOPVERTRES );
763 dc->is_display = !!is_display;
765 DC_InitDC( dc );
766 release_dc_ptr( dc );
768 if (driver_info && driver_info->cVersion == NTGDI_WIN16_DIB &&
769 !create_dib_surface( hdc, pdev ))
771 NtGdiDeleteObjectApp( hdc );
772 return 0;
774 return hdc;
778 /***********************************************************************
779 * NtGdiCreateCompatibleDC (win32u.@)
781 HDC WINAPI NtGdiCreateCompatibleDC( HDC hdc )
783 DC *dc, *origDC;
784 HDC ret;
785 const struct gdi_dc_funcs *funcs;
786 PHYSDEV physDev = NULL;
788 /* gdi_lock should not be locked */
790 if (hdc)
792 if (!(origDC = get_dc_ptr( hdc ))) return 0;
793 physDev = GET_DC_PHYSDEV( origDC, pCreateCompatibleDC );
794 funcs = physDev->funcs;
795 release_dc_ptr( origDC );
797 else funcs = get_display_driver();
799 if (!(dc = alloc_dc_ptr( NTGDI_OBJ_MEMDC ))) return 0;
801 TRACE("(%p): returning %p\n", hdc, dc->hSelf );
803 dc->hBitmap = GDI_inc_ref_count( GetStockObject( DEFAULT_BITMAP ));
804 dc->attr->vis_rect.left = 0;
805 dc->attr->vis_rect.top = 0;
806 dc->attr->vis_rect.right = 1;
807 dc->attr->vis_rect.bottom = 1;
808 dc->device_rect = dc->attr->vis_rect;
810 ret = dc->hSelf;
812 if (funcs->pCreateCompatibleDC && !funcs->pCreateCompatibleDC( physDev, &dc->physDev ))
814 WARN("creation aborted by device\n");
815 free_dc_ptr( dc );
816 return 0;
819 if (!dib_driver.pCreateDC( &dc->physDev, NULL, NULL, NULL ))
821 free_dc_ptr( dc );
822 return 0;
824 physDev = GET_DC_PHYSDEV( dc, pSelectBitmap );
825 physDev->funcs->pSelectBitmap( physDev, dc->hBitmap );
827 DC_InitDC( dc );
828 release_dc_ptr( dc );
829 return ret;
833 /***********************************************************************
834 * NtGdiResetDC (win32u.@)
836 BOOL WINAPI NtGdiResetDC( HDC hdc, const DEVMODEW *devmode, BOOL *banding,
837 DRIVER_INFO_2W *driver_info, void *dev )
839 DC *dc;
840 BOOL ret = FALSE;
842 if ((dc = get_dc_ptr( hdc )))
844 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pResetDC );
845 ret = physdev->funcs->pResetDC( physdev, devmode ) != 0;
846 if (ret) /* reset the visible region */
848 dc->dirty = 0;
849 dc->attr->vis_rect.left = 0;
850 dc->attr->vis_rect.top = 0;
851 dc->attr->vis_rect.right = NtGdiGetDeviceCaps( hdc, DESKTOPHORZRES );
852 dc->attr->vis_rect.bottom = NtGdiGetDeviceCaps( hdc, DESKTOPVERTRES );
853 if (dc->hVisRgn) NtGdiDeleteObjectApp( dc->hVisRgn );
854 dc->hVisRgn = 0;
855 update_dc_clipping( dc );
857 release_dc_ptr( dc );
859 return ret;
863 /***********************************************************************
864 * NtGdiGetDeviceCaps (win32u.@)
866 INT WINAPI NtGdiGetDeviceCaps( HDC hdc, INT cap )
868 DC *dc;
869 INT ret = 0;
871 if ((dc = get_dc_ptr( hdc )))
873 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pGetDeviceCaps );
874 ret = physdev->funcs->pGetDeviceCaps( physdev, cap );
875 release_dc_ptr( dc );
877 return ret;
881 static BOOL set_graphics_mode( DC *dc, int mode )
883 if (mode == dc->attr->graphics_mode) return TRUE;
884 if (mode <= 0 || mode > GM_LAST) return FALSE;
886 /* One would think that setting the graphics mode to GM_COMPATIBLE
887 * would also reset the world transformation matrix to the unity
888 * matrix. However, in Windows, this is not the case. This doesn't
889 * make a lot of sense to me, but that's the way it is.
891 dc->attr->graphics_mode = mode;
893 /* font metrics depend on the graphics mode */
894 NtGdiSelectFont(dc->hSelf, dc->hFont);
895 return TRUE;
899 DWORD set_stretch_blt_mode( HDC hdc, DWORD mode )
901 DWORD ret;
902 DC *dc;
903 if (!(dc = get_dc_ptr( hdc ))) return 0;
904 ret = dc->attr->stretch_blt_mode;
905 dc->attr->stretch_blt_mode = mode;
906 release_dc_ptr( dc );
907 return ret;
911 /***********************************************************************
912 * NtGdiGetAndSetDCDword (win32u.@)
914 BOOL WINAPI NtGdiGetAndSetDCDword( HDC hdc, UINT method, DWORD value, DWORD *prev_value )
916 PHYSDEV physdev;
917 BOOL ret = TRUE;
918 DWORD prev;
919 DC *dc;
921 if (!(dc = get_dc_ptr( hdc ))) return 0;
923 switch (method)
925 case NtGdiSetMapMode:
926 prev = dc->attr->map_mode;
927 ret = set_map_mode( dc, value );
928 break;
930 case NtGdiSetBkColor:
931 prev = dc->attr->background_color;
932 set_bk_color( dc, value );
933 break;
935 case NtGdiSetBkMode:
936 prev = dc->attr->background_mode;
937 dc->attr->background_mode = value;
938 break;
940 case NtGdiSetTextColor:
941 prev = dc->attr->text_color;
942 set_text_color( dc, value );
943 break;
945 case NtGdiSetDCBrushColor:
946 physdev = GET_DC_PHYSDEV( dc, pSetDCBrushColor );
947 prev = dc->attr->brush_color;
948 value = physdev->funcs->pSetDCBrushColor( physdev, value );
949 if (value != CLR_INVALID) dc->attr->brush_color = value;
950 break;
952 case NtGdiSetDCPenColor:
953 physdev = GET_DC_PHYSDEV( dc, pSetDCPenColor );
954 prev = dc->attr->pen_color;
955 value = physdev->funcs->pSetDCPenColor( physdev, value );
956 if (value != CLR_INVALID) dc->attr->pen_color = value;
957 break;
959 case NtGdiSetGraphicsMode:
960 prev = dc->attr->graphics_mode;
961 ret = set_graphics_mode( dc, value );
962 break;
964 case NtGdiSetROP2:
965 prev = dc->attr->rop_mode;
966 dc->attr->rop_mode = value;
967 break;
969 case NtGdiSetTextAlign:
970 prev = dc->attr->text_align;
971 dc->attr->text_align = value;
972 break;
974 default:
975 WARN( "unknown method %u\n", method );
976 ret = FALSE;
977 break;
980 release_dc_ptr( dc );
981 if (!ret || !prev_value) return FALSE;
982 *prev_value = prev;
983 return TRUE;
987 /***********************************************************************
988 * NtGdiGetDCDword (win32u.@)
990 BOOL WINAPI NtGdiGetDCDword( HDC hdc, UINT method, DWORD *result )
992 BOOL ret = TRUE;
993 DC *dc;
995 if (!(dc = get_dc_ptr( hdc ))) return 0;
997 switch (method)
999 case NtGdiGetArcDirection:
1000 *result = dc->attr->arc_direction;
1001 break;
1003 case NtGdiGetBkColor:
1004 *result = dc->attr->background_color;
1005 break;
1007 case NtGdiGetBkMode:
1008 *result = dc->attr->background_mode;
1009 break;
1011 case NtGdiGetDCBrushColor:
1012 *result = dc->attr->brush_color;
1013 break;
1015 case NtGdiGetDCPenColor:
1016 *result = dc->attr->pen_color;
1017 break;
1019 case NtGdiGetGraphicsMode:
1020 *result = dc->attr->graphics_mode;
1021 break;
1023 case NtGdiGetLayout:
1024 *result = dc->attr->layout;
1025 break;
1027 case NtGdiGetPolyFillMode:
1028 *result = dc->attr->poly_fill_mode;
1029 break;
1031 case NtGdiGetROP2:
1032 *result = dc->attr->rop_mode;
1033 break;
1035 case NtGdiGetTextColor:
1036 *result = dc->attr->text_color;
1037 break;
1039 case NtGdiIsMemDC:
1040 *result = get_gdi_object_type( hdc ) == NTGDI_OBJ_MEMDC;
1041 break;
1043 default:
1044 WARN( "unknown method %u\n", method );
1045 ret = FALSE;
1046 break;
1049 release_dc_ptr( dc );
1050 return ret;
1054 /***********************************************************************
1055 * NtGdiGetDCPoint (win32u.@)
1057 BOOL WINAPI NtGdiGetDCPoint( HDC hdc, UINT method, POINT *result )
1059 BOOL ret = TRUE;
1060 DC *dc;
1062 if (!(dc = get_dc_ptr( hdc ))) return 0;
1064 switch (method)
1066 case NtGdiGetBrushOrgEx:
1067 *result = dc->attr->brush_org;
1068 break;
1070 case NtGdiGetCurrentPosition:
1071 *result = dc->attr->cur_pos;
1072 break;
1074 case NtGdiGetDCOrg:
1075 result->x = dc->attr->vis_rect.left;
1076 result->y = dc->attr->vis_rect.top;
1077 break;
1079 default:
1080 WARN( "unknown method %u\n", method );
1081 ret = FALSE;
1082 break;
1085 release_dc_ptr( dc );
1086 return ret;
1090 /***********************************************************************
1091 * NtGdiSetBrushOrg (win32u.@)
1093 BOOL WINAPI NtGdiSetBrushOrg( HDC hdc, INT x, INT y, POINT *oldorg )
1095 DC *dc;
1097 if (!(dc = get_dc_ptr( hdc ))) return FALSE;
1098 if (oldorg) *oldorg = dc->attr->brush_org;
1099 dc->attr->brush_org.x = x;
1100 dc->attr->brush_org.y = y;
1101 release_dc_ptr( dc );
1102 return TRUE;
1106 BOOL set_viewport_org( HDC hdc, INT x, INT y, POINT *point )
1108 DC *dc;
1110 if (!(dc = get_dc_ptr( hdc ))) return FALSE;
1111 if (point) *point = dc->attr->vport_org;
1112 dc->attr->vport_org.x = x;
1113 dc->attr->vport_org.y = y;
1114 release_dc_ptr( dc );
1115 return NtGdiComputeXformCoefficients( hdc );
1119 /***********************************************************************
1120 * NtGdiGetTransform (win32u.@)
1122 * Undocumented
1124 * Returns one of the co-ordinate space transforms
1126 * PARAMS
1127 * hdc [I] Device context.
1128 * which [I] Which xform to return:
1129 * 0x203 World -> Page transform (that set by SetWorldTransform).
1130 * 0x304 Page -> Device transform (the mapping mode transform).
1131 * 0x204 World -> Device transform (the combination of the above two).
1132 * 0x402 Device -> World transform (the inversion of the above).
1133 * xform [O] The xform.
1136 BOOL WINAPI NtGdiGetTransform( HDC hdc, DWORD which, XFORM *xform )
1138 BOOL ret = TRUE;
1139 DC *dc = get_dc_ptr( hdc );
1140 if (!dc) return FALSE;
1142 switch(which)
1144 case 0x203:
1145 *xform = dc->xformWorld2Wnd;
1146 break;
1148 case 0x304:
1149 construct_window_to_viewport(dc, xform);
1150 break;
1152 case 0x204:
1153 *xform = dc->xformWorld2Vport;
1154 break;
1156 case 0x402:
1157 *xform = dc->xformVport2World;
1158 break;
1160 default:
1161 FIXME("Unknown code %x\n", (int)which);
1162 ret = FALSE;
1165 release_dc_ptr( dc );
1166 return ret;
1170 /***********************************************************************
1171 * set_dc_dce
1173 void set_dc_dce( HDC hdc, struct dce *dce )
1175 DC *dc;
1177 if (!(dc = get_dc_obj( hdc ))) return;
1178 if (dc->attr->disabled)
1180 GDI_ReleaseObj( hdc );
1181 return;
1183 dc->dce = dce;
1184 if (dce) dc->dirty = 1;
1185 GDI_ReleaseObj( hdc );
1189 /***********************************************************************
1190 * get_dc_dce
1192 struct dce *get_dc_dce( HDC hdc )
1194 DC *dc = get_dc_obj( hdc );
1195 struct dce *ret = NULL;
1197 if (!dc) return 0;
1198 if (!dc->attr->disabled) ret = dc->dce;
1199 GDI_ReleaseObj( hdc );
1200 return ret;
1204 /***********************************************************************
1205 * set_dce_flags
1207 WORD set_dce_flags( HDC hdc, WORD flags )
1209 DC *dc = get_dc_obj( hdc ); /* not get_dc_ptr, this needs to work from any thread */
1210 LONG ret = 0;
1212 if (!dc) return 0;
1214 TRACE("hDC %p, flags %04x\n",hdc,flags);
1216 if (flags & DCHF_INVALIDATEVISRGN)
1217 ret = InterlockedExchange( &dc->dirty, 1 );
1218 else if (flags & DCHF_VALIDATEVISRGN || !flags)
1219 ret = InterlockedExchange( &dc->dirty, 0 );
1221 if (flags & DCHF_DISABLEDC)
1222 ret = InterlockedExchange( &dc->attr->disabled, 1 );
1223 else if (flags & DCHF_ENABLEDC)
1224 ret = InterlockedExchange( &dc->attr->disabled, 0 );
1226 GDI_ReleaseObj( hdc );
1228 if (flags & DCHF_RESETDC) ret = reset_dc_state( hdc );
1229 return ret;
1232 /***********************************************************************
1233 * NtGdiGetDeviceGammaRamp (win32u.@)
1235 BOOL WINAPI NtGdiGetDeviceGammaRamp( HDC hdc, void *ptr )
1237 BOOL ret = FALSE;
1238 DC *dc = get_dc_ptr( hdc );
1240 TRACE("%p, %p\n", hdc, ptr);
1241 if( dc )
1243 if (get_gdi_object_type( hdc ) != NTGDI_OBJ_MEMDC)
1245 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pGetDeviceGammaRamp );
1246 ret = physdev->funcs->pGetDeviceGammaRamp( physdev, ptr );
1248 else RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
1249 release_dc_ptr( dc );
1251 return ret;
1254 static BOOL check_gamma_ramps(void *ptr)
1256 WORD *ramp = ptr;
1258 while (ramp < (WORD*)ptr + 3 * 256)
1260 float r_x, r_y, r_lx, r_ly, r_d, r_v, r_e, g_avg, g_min, g_max;
1261 unsigned i, f, l, g_n, c;
1263 f = ramp[0];
1264 l = ramp[255];
1265 if (f >= l)
1267 TRACE("inverted or flat gamma ramp (%d->%d), rejected\n", f, l);
1268 return FALSE;
1270 r_d = l - f;
1271 g_min = g_max = g_avg = 0.0;
1273 /* check gamma ramp entries to estimate the gamma */
1274 TRACE("analyzing gamma ramp (%d->%d)\n", f, l);
1275 for (i=1, g_n=0; i<255; i++)
1277 if (ramp[i] < f || ramp[i] > l)
1279 TRACE("strange gamma ramp ([%d]=%d for %d->%d), rejected\n", i, ramp[i], f, l);
1280 return FALSE;
1282 c = ramp[i] - f;
1283 if (!c) continue; /* avoid log(0) */
1285 /* normalize entry values into 0..1 range */
1286 r_x = i/255.0; r_y = c / r_d;
1287 /* compute logarithms of values */
1288 r_lx = log(r_x); r_ly = log(r_y);
1289 /* compute gamma for this entry */
1290 r_v = r_ly / r_lx;
1291 /* compute differential (error estimate) for this entry */
1292 /* some games use table-based logarithms that magnifies the error by 128 */
1293 r_e = -r_lx * 128 / (c * r_lx * r_lx);
1295 /* compute min & max while compensating for estimated error */
1296 if (!g_n || g_min > (r_v + r_e)) g_min = r_v + r_e;
1297 if (!g_n || g_max < (r_v - r_e)) g_max = r_v - r_e;
1299 /* add to average */
1300 g_avg += r_v;
1301 g_n++;
1304 if (!g_n)
1306 TRACE("no gamma data, shouldn't happen\n");
1307 return FALSE;
1309 g_avg /= g_n;
1310 TRACE("low bias is %d, high is %d, gamma is %5.3f\n", f, 65535-l, g_avg);
1312 /* check that the gamma is reasonably uniform across the ramp */
1313 if (g_max - g_min > 12.8)
1315 TRACE("ramp not uniform (max=%f, min=%f, avg=%f), rejected\n", g_max, g_min, g_avg);
1316 return FALSE;
1319 /* check that the gamma is not too bright */
1320 if (g_avg < 0.2)
1322 TRACE("too bright gamma ( %5.3f), rejected\n", g_avg);
1323 return FALSE;
1326 ramp += 256;
1329 return TRUE;
1332 /***********************************************************************
1333 * NtGdiSetDeviceGammaRamp (win32u.@)
1335 BOOL WINAPI NtGdiSetDeviceGammaRamp( HDC hdc, void *ptr )
1337 BOOL ret = FALSE;
1338 DC *dc = get_dc_ptr( hdc );
1340 TRACE( "%p, %p\n", hdc, ptr );
1341 if( dc )
1343 if (get_gdi_object_type( hdc ) != NTGDI_OBJ_MEMDC)
1345 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetDeviceGammaRamp );
1347 if (check_gamma_ramps(ptr))
1348 ret = physdev->funcs->pSetDeviceGammaRamp( physdev, ptr );
1350 else RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
1351 release_dc_ptr( dc );
1353 return ret;
1357 /***********************************************************************
1358 * NtGdiGetBoundsRect (win32u.@)
1360 UINT WINAPI NtGdiGetBoundsRect( HDC hdc, RECT *rect, UINT flags )
1362 PHYSDEV physdev;
1363 RECT device_rect;
1364 UINT ret;
1365 DC *dc = get_dc_ptr( hdc );
1367 if ( !dc ) return 0;
1369 physdev = GET_DC_PHYSDEV( dc, pGetBoundsRect );
1370 ret = physdev->funcs->pGetBoundsRect( physdev, &device_rect, DCB_RESET );
1371 if (!ret)
1373 release_dc_ptr( dc );
1374 return 0;
1376 if (dc->bounds_enabled && ret == DCB_SET) add_bounds_rect( &dc->bounds, &device_rect );
1378 if (rect)
1380 if (IsRectEmpty( &dc->bounds ))
1382 rect->left = rect->top = rect->right = rect->bottom = 0;
1383 ret = DCB_RESET;
1385 else
1387 *rect = dc->bounds;
1388 rect->left = max( rect->left, 0 );
1389 rect->top = max( rect->top, 0 );
1390 rect->right = min( rect->right, dc->attr->vis_rect.right - dc->attr->vis_rect.left );
1391 rect->bottom = min( rect->bottom, dc->attr->vis_rect.bottom - dc->attr->vis_rect.top );
1392 ret = DCB_SET;
1394 dp_to_lp( dc, (POINT *)rect, 2 );
1396 else ret = 0;
1398 if (flags & DCB_RESET) reset_bounds( &dc->bounds );
1399 release_dc_ptr( dc );
1400 return ret;
1404 /***********************************************************************
1405 * NtGdiSetBoundsRect (win32u.@)
1407 UINT WINAPI NtGdiSetBoundsRect( HDC hdc, const RECT *rect, UINT flags )
1409 PHYSDEV physdev;
1410 UINT ret;
1411 DC *dc;
1413 if ((flags & DCB_ENABLE) && (flags & DCB_DISABLE)) return 0;
1414 if (!(dc = get_dc_ptr( hdc ))) return 0;
1416 physdev = GET_DC_PHYSDEV( dc, pSetBoundsRect );
1417 ret = physdev->funcs->pSetBoundsRect( physdev, &dc->bounds, flags );
1418 if (!ret)
1420 release_dc_ptr( dc );
1421 return 0;
1424 ret = (dc->bounds_enabled ? DCB_ENABLE : DCB_DISABLE) |
1425 (IsRectEmpty( &dc->bounds ) ? ret & DCB_SET : DCB_SET);
1427 if (flags & DCB_RESET) reset_bounds( &dc->bounds );
1429 if ((flags & DCB_ACCUMULATE) && rect)
1431 RECT rc = *rect;
1433 lp_to_dp( dc, (POINT *)&rc, 2 );
1434 add_bounds_rect( &dc->bounds, &rc );
1437 if (flags & DCB_ENABLE) dc->bounds_enabled = TRUE;
1438 if (flags & DCB_DISABLE) dc->bounds_enabled = FALSE;
1440 release_dc_ptr( dc );
1441 return ret;
1445 /***********************************************************************
1446 * NtGdiSetLayout (win32u.@)
1448 * Sets left->right or right->left text layout flags of a dc.
1451 DWORD WINAPI NtGdiSetLayout( HDC hdc, LONG wox, DWORD layout )
1453 UINT old_layout = GDI_ERROR;
1454 DC *dc;
1456 if ((dc = get_dc_ptr( hdc )))
1458 old_layout = dc->attr->layout;
1459 dc->attr->layout = layout;
1460 if (layout != old_layout)
1462 if (layout & LAYOUT_RTL) dc->attr->map_mode = MM_ANISOTROPIC;
1463 DC_UpdateXforms( dc );
1465 release_dc_ptr( dc );
1468 TRACE("hdc : %p, old layout : %08x, new layout : %08x\n", hdc, old_layout, (int)layout);
1470 return old_layout;
1473 /**********************************************************************
1474 * __wine_get_icm_profile (win32u.@)
1476 BOOL WINAPI __wine_get_icm_profile( HDC hdc, BOOL allow_default, DWORD *size, WCHAR *filename )
1478 PHYSDEV physdev;
1479 DC *dc;
1480 BOOL ret;
1482 if (!(dc = get_dc_ptr(hdc))) return FALSE;
1484 physdev = GET_DC_PHYSDEV( dc, pGetICMProfile );
1485 ret = physdev->funcs->pGetICMProfile( physdev, allow_default, size, filename );
1486 release_dc_ptr(dc);
1487 return ret;
1490 /***********************************************************************
1491 * __wine_get_wgl_driver (win32u.@)
1493 struct opengl_funcs *__wine_get_wgl_driver( HDC hdc, UINT version )
1495 BOOL is_display, is_memdc;
1496 DC *dc;
1498 if (version != WINE_WGL_DRIVER_VERSION)
1500 ERR( "version mismatch, opengl32 wants %u but dibdrv has %u\n",
1501 version, WINE_WGL_DRIVER_VERSION );
1502 return NULL;
1505 if (!(dc = get_dc_obj( hdc ))) return NULL;
1506 if (dc->attr->disabled)
1508 GDI_ReleaseObj( hdc );
1509 return NULL;
1511 is_display = dc->is_display;
1512 is_memdc = get_gdi_object_type( hdc ) == NTGDI_OBJ_MEMDC;
1513 GDI_ReleaseObj( hdc );
1515 if (is_display) return user_driver->pwine_get_wgl_driver( version );
1516 if (is_memdc) return dibdrv_get_wgl_driver();
1517 return (void *)-1;