gdi32: Don't hold the GDI lock while calling the driver painting functions.
[wine] / dlls / gdi32 / dc.c
1 /*
2  * GDI Device Context functions
3  *
4  * Copyright 1993 Alexandre Julliard
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include "config.h"
22
23 #include <assert.h>
24 #include <stdarg.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include "windef.h"
28 #include "winbase.h"
29 #include "wingdi.h"
30 #include "winreg.h"
31 #include "winternl.h"
32 #include "winerror.h"
33 #include "wownt32.h"
34 #include "gdi_private.h"
35 #include "wine/unicode.h"
36 #include "wine/debug.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(dc);
39
40 static const WCHAR displayW[] = { 'd','i','s','p','l','a','y',0 };
41
42 static BOOL DC_DeleteObject( HGDIOBJ handle, void *obj );
43
44 static const struct gdi_obj_funcs dc_funcs =
45 {
46     NULL,             /* pSelectObject */
47     NULL,             /* pGetObject16 */
48     NULL,             /* pGetObjectA */
49     NULL,             /* pGetObjectW */
50     NULL,             /* pUnrealizeObject */
51     DC_DeleteObject   /* pDeleteObject */
52 };
53
54
55 static inline DC *get_dc_obj( HDC hdc )
56 {
57     DC *dc = GDI_GetObjPtr( hdc, MAGIC_DONTCARE );
58     if (!dc) return NULL;
59
60     if ((GDIMAGIC(dc->header.wMagic) != DC_MAGIC) &&
61         (GDIMAGIC(dc->header.wMagic) != MEMORY_DC_MAGIC) &&
62         (GDIMAGIC(dc->header.wMagic) != METAFILE_DC_MAGIC) &&
63         (GDIMAGIC(dc->header.wMagic) != ENHMETAFILE_DC_MAGIC))
64     {
65         GDI_ReleaseObj( hdc );
66         SetLastError( ERROR_INVALID_HANDLE );
67         dc = NULL;
68     }
69     return dc;
70 }
71
72
73 /***********************************************************************
74  *           DC_AllocDC
75  */
76 DC *DC_AllocDC( const DC_FUNCTIONS *funcs, WORD magic )
77 {
78     HDC hdc;
79     DC *dc;
80
81     if (!(dc = GDI_AllocObject( sizeof(*dc), magic, (HGDIOBJ*)&hdc, &dc_funcs ))) return NULL;
82
83     dc->hSelf               = hdc;
84     dc->funcs               = funcs;
85     dc->physDev             = NULL;
86     dc->thread              = GetCurrentThreadId();
87     dc->refcount            = 1;
88     dc->dirty               = 0;
89     dc->saveLevel           = 0;
90     dc->saved_dc            = 0;
91     dc->dwHookData          = 0;
92     dc->hookProc            = NULL;
93     dc->hookThunk           = NULL;
94     dc->wndOrgX             = 0;
95     dc->wndOrgY             = 0;
96     dc->wndExtX             = 1;
97     dc->wndExtY             = 1;
98     dc->vportOrgX           = 0;
99     dc->vportOrgY           = 0;
100     dc->vportExtX           = 1;
101     dc->vportExtY           = 1;
102     dc->miterLimit          = 10.0f; /* 10.0 is the default, from MSDN */
103     dc->flags               = 0;
104     dc->layout              = 0;
105     dc->hClipRgn            = 0;
106     dc->hMetaRgn            = 0;
107     dc->hMetaClipRgn        = 0;
108     dc->hVisRgn             = 0;
109     dc->hPen                = GetStockObject( BLACK_PEN );
110     dc->hBrush              = GetStockObject( WHITE_BRUSH );
111     dc->hFont               = GetStockObject( SYSTEM_FONT );
112     dc->hBitmap             = 0;
113     dc->hDevice             = 0;
114     dc->hPalette            = GetStockObject( DEFAULT_PALETTE );
115     dc->gdiFont             = 0;
116     dc->ROPmode             = R2_COPYPEN;
117     dc->polyFillMode        = ALTERNATE;
118     dc->stretchBltMode      = BLACKONWHITE;
119     dc->relAbsMode          = ABSOLUTE;
120     dc->backgroundMode      = OPAQUE;
121     dc->backgroundColor     = RGB( 255, 255, 255 );
122     dc->dcBrushColor        = RGB( 255, 255, 255 );
123     dc->dcPenColor          = RGB( 0, 0, 0 );
124     dc->textColor           = RGB( 0, 0, 0 );
125     dc->brushOrgX           = 0;
126     dc->brushOrgY           = 0;
127     dc->textAlign           = TA_LEFT | TA_TOP | TA_NOUPDATECP;
128     dc->charExtra           = 0;
129     dc->breakExtra          = 0;
130     dc->breakRem            = 0;
131     dc->MapMode             = MM_TEXT;
132     dc->GraphicsMode        = GM_COMPATIBLE;
133     dc->pAbortProc          = NULL;
134     dc->CursPosX            = 0;
135     dc->CursPosY            = 0;
136     dc->ArcDirection        = AD_COUNTERCLOCKWISE;
137     dc->xformWorld2Wnd.eM11 = 1.0f;
138     dc->xformWorld2Wnd.eM12 = 0.0f;
139     dc->xformWorld2Wnd.eM21 = 0.0f;
140     dc->xformWorld2Wnd.eM22 = 1.0f;
141     dc->xformWorld2Wnd.eDx  = 0.0f;
142     dc->xformWorld2Wnd.eDy  = 0.0f;
143     dc->xformWorld2Vport    = dc->xformWorld2Wnd;
144     dc->xformVport2World    = dc->xformWorld2Wnd;
145     dc->vport2WorldValid    = TRUE;
146     dc->BoundsRect.left     = 0;
147     dc->BoundsRect.top      = 0;
148     dc->BoundsRect.right    = 0;
149     dc->BoundsRect.bottom   = 0;
150     dc->saved_visrgn        = NULL;
151     PATH_InitGdiPath(&dc->path);
152     return dc;
153 }
154
155
156
157 /***********************************************************************
158  *           DC_GetDCPtr
159  */
160 DC *DC_GetDCPtr( HDC hdc )
161 {
162     DC *dc = get_dc_obj( hdc );
163     if (!dc) return NULL;
164
165     if (!InterlockedCompareExchange( &dc->refcount, 1, 0 ))
166     {
167         dc->thread = GetCurrentThreadId();
168     }
169     else if (dc->thread != GetCurrentThreadId())
170     {
171         GDI_ReleaseObj( hdc );
172         SetLastError( ERROR_ACCESS_DENIED );
173         return NULL;
174     }
175     else InterlockedIncrement( &dc->refcount );
176
177     return dc;
178 }
179
180
181 /***********************************************************************
182  *           DC_ReleaseDCPtr
183  */
184 void DC_ReleaseDCPtr( DC *dc )
185 {
186     release_dc_ptr( dc );
187     GDI_ReleaseObj( dc->hSelf );
188 }
189
190
191 /***********************************************************************
192  *           DC_FreeDCPtr
193  */
194 BOOL DC_FreeDCPtr( DC *dc )
195 {
196     assert( dc->refcount == 1 );
197     return GDI_FreeObject( dc->hSelf, dc );
198 }
199
200
201 /***********************************************************************
202  *           get_dc_ptr
203  *
204  * Retrieve a DC pointer but release the GDI lock.
205  */
206 DC *get_dc_ptr( HDC hdc )
207 {
208     DC *dc = get_dc_obj( hdc );
209     if (!dc) return NULL;
210
211     if (!InterlockedCompareExchange( &dc->refcount, 1, 0 ))
212     {
213         dc->thread = GetCurrentThreadId();
214     }
215     else if (dc->thread != GetCurrentThreadId())
216     {
217         WARN( "dc %p belongs to thread %04x\n", hdc, dc->thread );
218         GDI_ReleaseObj( hdc );
219         return NULL;
220     }
221     else InterlockedIncrement( &dc->refcount );
222
223     GDI_ReleaseObj( hdc );
224     return dc;
225 }
226
227
228 /***********************************************************************
229  *           release_dc_ptr
230  */
231 void release_dc_ptr( DC *dc )
232 {
233     LONG ref;
234
235     dc->thread = 0;
236     ref = InterlockedDecrement( &dc->refcount );
237     assert( ref >= 0 );
238     if (ref) dc->thread = GetCurrentThreadId();  /* we still own it */
239 }
240
241
242 /***********************************************************************
243  *           update_dc
244  *
245  * Make sure the DC vis region is up to date.
246  * This function may call up to USER so the GDI lock should _not_
247  * be held when calling it.
248  */
249 void update_dc( DC *dc )
250 {
251     if (InterlockedExchange( &dc->dirty, 0 ) && dc->hookThunk)
252         dc->hookThunk( dc->hSelf, DCHC_INVALIDVISRGN, dc->dwHookData, 0 );
253 }
254
255
256 /***********************************************************************
257  *           DC_DeleteObject
258  */
259 static BOOL DC_DeleteObject( HGDIOBJ handle, void *obj )
260 {
261     GDI_ReleaseObj( handle );
262     return DeleteDC( handle );
263 }
264
265
266 /***********************************************************************
267  *           DC_InitDC
268  *
269  * Setup device-specific DC values for a newly created DC.
270  */
271 void DC_InitDC( DC* dc )
272 {
273     if (dc->funcs->pRealizeDefaultPalette) dc->funcs->pRealizeDefaultPalette( dc->physDev );
274     SetTextColor( dc->hSelf, dc->textColor );
275     SetBkColor( dc->hSelf, dc->backgroundColor );
276     SelectObject( dc->hSelf, dc->hPen );
277     SelectObject( dc->hSelf, dc->hBrush );
278     SelectObject( dc->hSelf, dc->hFont );
279     CLIPPING_UpdateGCRegion( dc );
280 }
281
282
283 /***********************************************************************
284  *           DC_InvertXform
285  *
286  * Computes the inverse of the transformation xformSrc and stores it to
287  * xformDest. Returns TRUE if successful or FALSE if the xformSrc matrix
288  * is singular.
289  */
290 static BOOL DC_InvertXform( const XFORM *xformSrc, XFORM *xformDest )
291 {
292     FLOAT determinant;
293
294     determinant = xformSrc->eM11*xformSrc->eM22 -
295         xformSrc->eM12*xformSrc->eM21;
296     if (determinant > -1e-12 && determinant < 1e-12)
297         return FALSE;
298
299     xformDest->eM11 =  xformSrc->eM22 / determinant;
300     xformDest->eM12 = -xformSrc->eM12 / determinant;
301     xformDest->eM21 = -xformSrc->eM21 / determinant;
302     xformDest->eM22 =  xformSrc->eM11 / determinant;
303     xformDest->eDx  = -xformSrc->eDx * xformDest->eM11 -
304                        xformSrc->eDy * xformDest->eM21;
305     xformDest->eDy  = -xformSrc->eDx * xformDest->eM12 -
306                        xformSrc->eDy * xformDest->eM22;
307
308     return TRUE;
309 }
310
311
312 /***********************************************************************
313  *           DC_UpdateXforms
314  *
315  * Updates the xformWorld2Vport, xformVport2World and vport2WorldValid
316  * fields of the specified DC by creating a transformation that
317  * represents the current mapping mode and combining it with the DC's
318  * world transform. This function should be called whenever the
319  * parameters associated with the mapping mode (window and viewport
320  * extents and origins) or the world transform change.
321  */
322 void DC_UpdateXforms( DC *dc )
323 {
324     XFORM xformWnd2Vport, oldworld2vport;
325     FLOAT scaleX, scaleY;
326
327     /* Construct a transformation to do the window-to-viewport conversion */
328     scaleX = (FLOAT)dc->vportExtX / (FLOAT)dc->wndExtX;
329     scaleY = (FLOAT)dc->vportExtY / (FLOAT)dc->wndExtY;
330     xformWnd2Vport.eM11 = scaleX;
331     xformWnd2Vport.eM12 = 0.0;
332     xformWnd2Vport.eM21 = 0.0;
333     xformWnd2Vport.eM22 = scaleY;
334     xformWnd2Vport.eDx  = (FLOAT)dc->vportOrgX -
335         scaleX * (FLOAT)dc->wndOrgX;
336     xformWnd2Vport.eDy  = (FLOAT)dc->vportOrgY -
337         scaleY * (FLOAT)dc->wndOrgY;
338
339     oldworld2vport = dc->xformWorld2Vport;
340     /* Combine with the world transformation */
341     CombineTransform( &dc->xformWorld2Vport, &dc->xformWorld2Wnd,
342         &xformWnd2Vport );
343
344     /* Create inverse of world-to-viewport transformation */
345     dc->vport2WorldValid = DC_InvertXform( &dc->xformWorld2Vport,
346         &dc->xformVport2World );
347
348     /* Reselect the font and pen back into the dc so that the size
349        gets updated. */
350     if(memcmp(&oldworld2vport, &dc->xformWorld2Vport, sizeof(oldworld2vport)))
351     {
352         SelectObject(dc->hSelf, GetCurrentObject(dc->hSelf, OBJ_FONT));
353         SelectObject(dc->hSelf, GetCurrentObject(dc->hSelf, OBJ_PEN));
354     }
355 }
356
357
358 /***********************************************************************
359  *           GetDCState   (Not a Windows API)
360  */
361 HDC WINAPI GetDCState( HDC hdc )
362 {
363     DC * newdc, * dc;
364     HGDIOBJ handle;
365
366     if (!(dc = DC_GetDCPtr( hdc ))) return 0;
367     if (!(newdc = GDI_AllocObject( sizeof(DC), GDIMAGIC(dc->header.wMagic), &handle, &dc_funcs )))
368     {
369       DC_ReleaseDCPtr( dc );
370       return 0;
371     }
372     TRACE("(%p): returning %p\n", hdc, handle );
373
374     newdc->flags            = dc->flags | DC_SAVED;
375     newdc->layout           = dc->layout;
376     newdc->hPen             = dc->hPen;
377     newdc->hBrush           = dc->hBrush;
378     newdc->hFont            = dc->hFont;
379     newdc->hBitmap          = dc->hBitmap;
380     newdc->hDevice          = dc->hDevice;
381     newdc->hPalette         = dc->hPalette;
382     newdc->ROPmode          = dc->ROPmode;
383     newdc->polyFillMode     = dc->polyFillMode;
384     newdc->stretchBltMode   = dc->stretchBltMode;
385     newdc->relAbsMode       = dc->relAbsMode;
386     newdc->backgroundMode   = dc->backgroundMode;
387     newdc->backgroundColor  = dc->backgroundColor;
388     newdc->textColor        = dc->textColor;
389     newdc->dcBrushColor     = dc->dcBrushColor;
390     newdc->dcPenColor       = dc->dcPenColor;
391     newdc->brushOrgX        = dc->brushOrgX;
392     newdc->brushOrgY        = dc->brushOrgY;
393     newdc->textAlign        = dc->textAlign;
394     newdc->charExtra        = dc->charExtra;
395     newdc->breakExtra       = dc->breakExtra;
396     newdc->breakRem         = dc->breakRem;
397     newdc->MapMode          = dc->MapMode;
398     newdc->GraphicsMode     = dc->GraphicsMode;
399     newdc->CursPosX         = dc->CursPosX;
400     newdc->CursPosY         = dc->CursPosY;
401     newdc->ArcDirection     = dc->ArcDirection;
402     newdc->xformWorld2Wnd   = dc->xformWorld2Wnd;
403     newdc->xformWorld2Vport = dc->xformWorld2Vport;
404     newdc->xformVport2World = dc->xformVport2World;
405     newdc->vport2WorldValid = dc->vport2WorldValid;
406     newdc->wndOrgX          = dc->wndOrgX;
407     newdc->wndOrgY          = dc->wndOrgY;
408     newdc->wndExtX          = dc->wndExtX;
409     newdc->wndExtY          = dc->wndExtY;
410     newdc->vportOrgX        = dc->vportOrgX;
411     newdc->vportOrgY        = dc->vportOrgY;
412     newdc->vportExtX        = dc->vportExtX;
413     newdc->vportExtY        = dc->vportExtY;
414     newdc->BoundsRect       = dc->BoundsRect;
415
416     newdc->hSelf = (HDC)handle;
417     newdc->thread    = GetCurrentThreadId();
418     newdc->refcount  = 1;
419     newdc->saveLevel = 0;
420     newdc->saved_dc  = 0;
421
422     PATH_InitGdiPath( &newdc->path );
423
424     newdc->pAbortProc = NULL;
425     newdc->hookThunk  = NULL;
426     newdc->hookProc   = 0;
427     newdc->saved_visrgn = NULL;
428
429     /* Get/SetDCState() don't change hVisRgn field ("Undoc. Windows" p.559). */
430
431     newdc->hVisRgn      = 0;
432     newdc->hClipRgn     = 0;
433     newdc->hMetaRgn     = 0;
434     newdc->hMetaClipRgn = 0;
435     if (dc->hClipRgn)
436     {
437         newdc->hClipRgn = CreateRectRgn( 0, 0, 0, 0 );
438         CombineRgn( newdc->hClipRgn, dc->hClipRgn, 0, RGN_COPY );
439     }
440     if (dc->hMetaRgn)
441     {
442         newdc->hMetaRgn = CreateRectRgn( 0, 0, 0, 0 );
443         CombineRgn( newdc->hMetaRgn, dc->hMetaRgn, 0, RGN_COPY );
444     }
445     /* don't bother recomputing hMetaClipRgn, we'll do that in SetDCState */
446
447     if(dc->gdiFont) {
448         newdc->gdiFont = dc->gdiFont;
449     } else
450         newdc->gdiFont = 0;
451
452     DC_ReleaseDCPtr( newdc );
453     DC_ReleaseDCPtr( dc );
454     return handle;
455 }
456
457
458 /***********************************************************************
459  *           SetDCState   (Not a Windows API)
460  */
461 void WINAPI SetDCState( HDC hdc, HDC hdcs )
462 {
463     DC *dc, *dcs;
464
465     if (!(dc = get_dc_ptr( hdc ))) return;
466     if (!(dcs = get_dc_ptr( hdcs )))
467     {
468         release_dc_ptr( dc );
469         return;
470     }
471     if (!dcs->flags & DC_SAVED)
472     {
473         release_dc_ptr( dc );
474         release_dc_ptr( dcs );
475         return;
476     }
477     TRACE("%p %p\n", hdc, hdcs );
478
479     update_dc( dc );
480     dc->flags            = dcs->flags & ~DC_SAVED;
481     dc->layout           = dcs->layout;
482     dc->hDevice          = dcs->hDevice;
483     dc->ROPmode          = dcs->ROPmode;
484     dc->polyFillMode     = dcs->polyFillMode;
485     dc->stretchBltMode   = dcs->stretchBltMode;
486     dc->relAbsMode       = dcs->relAbsMode;
487     dc->backgroundMode   = dcs->backgroundMode;
488     dc->backgroundColor  = dcs->backgroundColor;
489     dc->textColor        = dcs->textColor;
490     dc->dcBrushColor     = dcs->dcBrushColor;
491     dc->dcPenColor       = dcs->dcPenColor;
492     dc->brushOrgX        = dcs->brushOrgX;
493     dc->brushOrgY        = dcs->brushOrgY;
494     dc->textAlign        = dcs->textAlign;
495     dc->charExtra        = dcs->charExtra;
496     dc->breakExtra       = dcs->breakExtra;
497     dc->breakRem         = dcs->breakRem;
498     dc->MapMode          = dcs->MapMode;
499     dc->GraphicsMode     = dcs->GraphicsMode;
500     dc->CursPosX         = dcs->CursPosX;
501     dc->CursPosY         = dcs->CursPosY;
502     dc->ArcDirection     = dcs->ArcDirection;
503     dc->xformWorld2Wnd   = dcs->xformWorld2Wnd;
504     dc->xformWorld2Vport = dcs->xformWorld2Vport;
505     dc->xformVport2World = dcs->xformVport2World;
506     dc->vport2WorldValid = dcs->vport2WorldValid;
507     dc->BoundsRect       = dcs->BoundsRect;
508
509     dc->wndOrgX          = dcs->wndOrgX;
510     dc->wndOrgY          = dcs->wndOrgY;
511     dc->wndExtX          = dcs->wndExtX;
512     dc->wndExtY          = dcs->wndExtY;
513     dc->vportOrgX        = dcs->vportOrgX;
514     dc->vportOrgY        = dcs->vportOrgY;
515     dc->vportExtX        = dcs->vportExtX;
516     dc->vportExtY        = dcs->vportExtY;
517
518     if (dcs->hClipRgn)
519     {
520         if (!dc->hClipRgn) dc->hClipRgn = CreateRectRgn( 0, 0, 0, 0 );
521         CombineRgn( dc->hClipRgn, dcs->hClipRgn, 0, RGN_COPY );
522     }
523     else
524     {
525         if (dc->hClipRgn) DeleteObject( dc->hClipRgn );
526         dc->hClipRgn = 0;
527     }
528     if (dcs->hMetaRgn)
529     {
530         if (!dc->hMetaRgn) dc->hMetaRgn = CreateRectRgn( 0, 0, 0, 0 );
531         CombineRgn( dc->hMetaRgn, dcs->hMetaRgn, 0, RGN_COPY );
532     }
533     else
534     {
535         if (dc->hMetaRgn) DeleteObject( dc->hMetaRgn );
536         dc->hMetaRgn = 0;
537     }
538     CLIPPING_UpdateGCRegion( dc );
539
540     SelectObject( hdc, dcs->hBitmap );
541     SelectObject( hdc, dcs->hBrush );
542     SelectObject( hdc, dcs->hFont );
543     SelectObject( hdc, dcs->hPen );
544     SetBkColor( hdc, dcs->backgroundColor);
545     SetTextColor( hdc, dcs->textColor);
546     GDISelectPalette( hdc, dcs->hPalette, FALSE );
547     release_dc_ptr( dc );
548     release_dc_ptr( dcs );
549 }
550
551
552 /***********************************************************************
553  *           GetDCState   (GDI.179)
554  */
555 HDC16 WINAPI GetDCState16( HDC16 hdc )
556 {
557     return HDC_16( GetDCState( HDC_32(hdc) ));
558 }
559
560
561 /***********************************************************************
562  *           SetDCState   (GDI.180)
563  */
564 void WINAPI SetDCState16( HDC16 hdc, HDC16 hdcs )
565 {
566     SetDCState( HDC_32(hdc), HDC_32(hdcs) );
567 }
568
569
570 /***********************************************************************
571  *           SaveDC    (GDI32.@)
572  */
573 INT WINAPI SaveDC( HDC hdc )
574 {
575     HDC hdcs;
576     DC * dc, * dcs;
577     INT ret;
578
579     dc = DC_GetDCPtr( hdc );
580     if (!dc) return 0;
581
582     if(dc->funcs->pSaveDC)
583     {
584         ret = dc->funcs->pSaveDC( dc->physDev );
585         if(ret)
586             ret = ++dc->saveLevel;
587         DC_ReleaseDCPtr( dc );
588         return ret;
589     }
590
591     if (!(hdcs = GetDCState( hdc )))
592     {
593       DC_ReleaseDCPtr( dc );
594       return 0;
595     }
596     dcs = DC_GetDCPtr( hdcs );
597
598     /* Copy path. The reason why path saving / restoring is in SaveDC/
599      * RestoreDC and not in GetDCState/SetDCState is that the ...DCState
600      * functions are only in Win16 (which doesn't have paths) and that
601      * SetDCState doesn't allow us to signal an error (which can happen
602      * when copying paths).
603      */
604     if (!PATH_AssignGdiPath( &dcs->path, &dc->path ))
605     {
606         DC_ReleaseDCPtr( dc );
607         DC_ReleaseDCPtr( dcs );
608         DeleteDC( hdcs );
609         return 0;
610     }
611
612     dcs->saved_dc = dc->saved_dc;
613     dc->saved_dc = hdcs;
614     TRACE("(%p): returning %d\n", hdc, dc->saveLevel+1 );
615     ret = ++dc->saveLevel;
616     DC_ReleaseDCPtr( dcs );
617     DC_ReleaseDCPtr( dc );
618     return ret;
619 }
620
621
622 /***********************************************************************
623  *           RestoreDC    (GDI32.@)
624  */
625 BOOL WINAPI RestoreDC( HDC hdc, INT level )
626 {
627     DC * dc, * dcs;
628     BOOL success;
629
630     TRACE("%p %d\n", hdc, level );
631     if (!(dc = get_dc_ptr( hdc ))) return FALSE;
632
633     if(abs(level) > dc->saveLevel || level == 0)
634     {
635         release_dc_ptr( dc );
636         return FALSE;
637     }
638
639     update_dc( dc );
640
641     if(dc->funcs->pRestoreDC)
642     {
643         success = dc->funcs->pRestoreDC( dc->physDev, level );
644         if(level < 0) level = dc->saveLevel + level + 1;
645         if(success)
646             dc->saveLevel = level - 1;
647         release_dc_ptr( dc );
648         return success;
649     }
650
651     if (level < 0) level = dc->saveLevel + level + 1;
652     success=TRUE;
653     while (dc->saveLevel >= level)
654     {
655         HDC hdcs = dc->saved_dc;
656         if (!(dcs = get_dc_ptr( hdcs )))
657         {
658             success = FALSE;
659             break;
660         }
661         dc->saved_dc = dcs->saved_dc;
662         dcs->saved_dc = 0;
663         if (--dc->saveLevel < level)
664         {
665             SetDCState( hdc, hdcs );
666             if (!PATH_AssignGdiPath( &dc->path, &dcs->path ))
667                 /* FIXME: This might not be quite right, since we're
668                  * returning FALSE but still destroying the saved DC state */
669                 success=FALSE;
670         }
671         release_dc_ptr( dcs );
672         DeleteDC( hdcs );
673     }
674     release_dc_ptr( dc );
675     return success;
676 }
677
678
679 /***********************************************************************
680  *           CreateDCW    (GDI32.@)
681  */
682 HDC WINAPI CreateDCW( LPCWSTR driver, LPCWSTR device, LPCWSTR output,
683                       const DEVMODEW *initData )
684 {
685     HDC hdc;
686     DC * dc;
687     const DC_FUNCTIONS *funcs;
688     WCHAR buf[300];
689
690     GDI_CheckNotLock();
691
692     if (!device || !DRIVER_GetDriverName( device, buf, 300 ))
693     {
694         if (!driver)
695         {
696             ERR( "no device found for %s\n", debugstr_w(device) );
697             return 0;
698         }
699         strcpyW(buf, driver);
700     }
701
702     if (!(funcs = DRIVER_load_driver( buf )))
703     {
704         ERR( "no driver found for %s\n", debugstr_w(buf) );
705         return 0;
706     }
707     if (!(dc = DC_AllocDC( funcs, DC_MAGIC ))) goto error;
708     hdc = dc->hSelf;
709
710     dc->hBitmap = GetStockObject( DEFAULT_BITMAP );
711     if (!(dc->hVisRgn = CreateRectRgn( 0, 0, 1, 1 ))) goto error;
712
713     TRACE("(driver=%s, device=%s, output=%s): returning %p\n",
714           debugstr_w(driver), debugstr_w(device), debugstr_w(output), dc->hSelf );
715
716     if (dc->funcs->pCreateDC &&
717         !dc->funcs->pCreateDC( hdc, &dc->physDev, buf, device, output, initData ))
718     {
719         WARN("creation aborted by device\n" );
720         goto error;
721     }
722
723     SetRectRgn( dc->hVisRgn, 0, 0,
724                 GetDeviceCaps( hdc, DESKTOPHORZRES ), GetDeviceCaps( hdc, DESKTOPVERTRES ) );
725
726     DC_InitDC( dc );
727     DC_ReleaseDCPtr( dc );
728     return hdc;
729
730 error:
731     if (dc && dc->hVisRgn) DeleteObject( dc->hVisRgn );
732     if (dc) DC_FreeDCPtr( dc );
733     DRIVER_release_driver( funcs );
734     return 0;
735 }
736
737
738 /***********************************************************************
739  *           CreateDCA    (GDI32.@)
740  */
741 HDC WINAPI CreateDCA( LPCSTR driver, LPCSTR device, LPCSTR output,
742                       const DEVMODEA *initData )
743 {
744     UNICODE_STRING driverW, deviceW, outputW;
745     DEVMODEW *initDataW;
746     HDC ret;
747
748     if (driver) RtlCreateUnicodeStringFromAsciiz(&driverW, driver);
749     else driverW.Buffer = NULL;
750
751     if (device) RtlCreateUnicodeStringFromAsciiz(&deviceW, device);
752     else deviceW.Buffer = NULL;
753
754     if (output) RtlCreateUnicodeStringFromAsciiz(&outputW, output);
755     else outputW.Buffer = NULL;
756
757     initDataW = NULL;
758     if (initData)
759     {
760         /* don't convert initData for DISPLAY driver, it's not used */
761         if (!driverW.Buffer || strcmpiW( driverW.Buffer, displayW ))
762             initDataW = GdiConvertToDevmodeW(initData);
763     }
764
765     ret = CreateDCW( driverW.Buffer, deviceW.Buffer, outputW.Buffer, initDataW );
766
767     RtlFreeUnicodeString(&driverW);
768     RtlFreeUnicodeString(&deviceW);
769     RtlFreeUnicodeString(&outputW);
770     HeapFree(GetProcessHeap(), 0, initDataW);
771     return ret;
772 }
773
774
775 /***********************************************************************
776  *           CreateICA    (GDI32.@)
777  */
778 HDC WINAPI CreateICA( LPCSTR driver, LPCSTR device, LPCSTR output,
779                           const DEVMODEA* initData )
780 {
781       /* Nothing special yet for ICs */
782     return CreateDCA( driver, device, output, initData );
783 }
784
785
786 /***********************************************************************
787  *           CreateICW    (GDI32.@)
788  */
789 HDC WINAPI CreateICW( LPCWSTR driver, LPCWSTR device, LPCWSTR output,
790                           const DEVMODEW* initData )
791 {
792       /* Nothing special yet for ICs */
793     return CreateDCW( driver, device, output, initData );
794 }
795
796
797 /***********************************************************************
798  *           CreateCompatibleDC   (GDI32.@)
799  */
800 HDC WINAPI CreateCompatibleDC( HDC hdc )
801 {
802     DC *dc, *origDC;
803     const DC_FUNCTIONS *funcs = NULL;
804     PHYSDEV physDev = NULL;
805
806     GDI_CheckNotLock();
807
808     if ((origDC = DC_GetDCPtr( hdc )))
809     {
810         if (GetObjectType( hdc ) == OBJ_DC)
811         {
812             funcs = origDC->funcs;
813             physDev = origDC->physDev;
814         }
815         DC_ReleaseDCPtr( origDC ); /* can't hold the lock while loading the driver */
816         if (funcs) funcs = DRIVER_get_driver( funcs );
817     }
818
819     if (!funcs && !(funcs = DRIVER_load_driver( displayW ))) return 0;
820
821     if (!(dc = DC_AllocDC( funcs, MEMORY_DC_MAGIC ))) goto error;
822
823     TRACE("(%p): returning %p\n", hdc, dc->hSelf );
824
825     dc->hBitmap = GetStockObject( DEFAULT_BITMAP );
826     if (!(dc->hVisRgn = CreateRectRgn( 0, 0, 1, 1 ))) goto error;   /* default bitmap is 1x1 */
827
828     /* Copy the driver-specific physical device info into
829      * the new DC. The driver may use this read-only info
830      * while creating the compatible DC below. */
831     dc->physDev = physDev;
832
833     if (dc->funcs->pCreateDC &&
834         !dc->funcs->pCreateDC( dc->hSelf, &dc->physDev, NULL, NULL, NULL, NULL ))
835     {
836         WARN("creation aborted by device\n");
837         goto error;
838     }
839
840     DC_InitDC( dc );
841     DC_ReleaseDCPtr( dc );
842     return dc->hSelf;
843
844 error:
845     if (dc && dc->hVisRgn) DeleteObject( dc->hVisRgn );
846     if (dc) DC_FreeDCPtr( dc );
847     DRIVER_release_driver( funcs );
848     return 0;
849 }
850
851
852 /***********************************************************************
853  *           DeleteDC    (GDI32.@)
854  */
855 BOOL WINAPI DeleteDC( HDC hdc )
856 {
857     const DC_FUNCTIONS *funcs = NULL;
858     DC * dc;
859
860     TRACE("%p\n", hdc );
861
862     GDI_CheckNotLock();
863
864     if (!(dc = DC_GetDCPtr( hdc ))) return FALSE;
865     if (dc->refcount != 1)
866     {
867         FIXME( "not deleting busy DC %p refcount %u\n", dc->hSelf, dc->refcount );
868         DC_ReleaseDCPtr( dc );
869         return FALSE;
870     }
871
872     /* Call hook procedure to check whether is it OK to delete this DC */
873     if (dc->hookThunk)
874     {
875         DCHOOKPROC proc = dc->hookThunk;
876         DWORD_PTR data = dc->dwHookData;
877         DC_ReleaseDCPtr( dc );
878         if (!proc( hdc, DCHC_DELETEDC, data, 0 )) return FALSE;
879         if (!(dc = DC_GetDCPtr( hdc ))) return TRUE;  /* deleted by the hook */
880     }
881
882     while (dc->saveLevel)
883     {
884         DC * dcs;
885         HDC hdcs = dc->saved_dc;
886         if (!(dcs = DC_GetDCPtr( hdcs ))) break;
887         dc->saved_dc = dcs->saved_dc;
888         dc->saveLevel--;
889         if (dcs->hClipRgn) DeleteObject( dcs->hClipRgn );
890         if (dcs->hMetaRgn) DeleteObject( dcs->hMetaRgn );
891         if (dcs->hMetaClipRgn) DeleteObject( dcs->hMetaClipRgn );
892         if (dcs->hVisRgn) DeleteObject( dcs->hVisRgn );
893         PATH_DestroyGdiPath(&dcs->path);
894         DC_FreeDCPtr( dcs );
895     }
896
897     if (!(dc->flags & DC_SAVED))
898     {
899         SelectObject( hdc, GetStockObject(BLACK_PEN) );
900         SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
901         SelectObject( hdc, GetStockObject(SYSTEM_FONT) );
902         SelectObject( hdc, GetStockObject(DEFAULT_BITMAP) );
903         funcs = dc->funcs;
904         if (dc->funcs->pDeleteDC) dc->funcs->pDeleteDC(dc->physDev);
905         dc->physDev = NULL;
906     }
907
908     while (dc->saved_visrgn)
909     {
910         struct saved_visrgn *next = dc->saved_visrgn->next;
911         DeleteObject( dc->saved_visrgn->hrgn );
912         HeapFree( GetProcessHeap(), 0, dc->saved_visrgn );
913         dc->saved_visrgn = next;
914     }
915     if (dc->hClipRgn) DeleteObject( dc->hClipRgn );
916     if (dc->hMetaRgn) DeleteObject( dc->hMetaRgn );
917     if (dc->hMetaClipRgn) DeleteObject( dc->hMetaClipRgn );
918     if (dc->hVisRgn) DeleteObject( dc->hVisRgn );
919     PATH_DestroyGdiPath(&dc->path);
920
921     DC_FreeDCPtr( dc );
922     if (funcs) DRIVER_release_driver( funcs );  /* do that after releasing the GDI lock */
923     return TRUE;
924 }
925
926
927 /***********************************************************************
928  *           ResetDCW    (GDI32.@)
929  */
930 HDC WINAPI ResetDCW( HDC hdc, const DEVMODEW *devmode )
931 {
932     DC *dc;
933     HDC ret = hdc;
934
935     if ((dc = DC_GetDCPtr( hdc )))
936     {
937         if (dc->funcs->pResetDC) ret = dc->funcs->pResetDC( dc->physDev, devmode );
938         DC_ReleaseDCPtr( dc );
939     }
940     return ret;
941 }
942
943
944 /***********************************************************************
945  *           ResetDCA    (GDI32.@)
946  */
947 HDC WINAPI ResetDCA( HDC hdc, const DEVMODEA *devmode )
948 {
949     DEVMODEW *devmodeW;
950     HDC ret;
951
952     if (devmode) devmodeW = GdiConvertToDevmodeW(devmode);
953     else devmodeW = NULL;
954
955     ret = ResetDCW(hdc, devmodeW);
956
957     HeapFree(GetProcessHeap(), 0, devmodeW);
958     return ret;
959 }
960
961
962 /***********************************************************************
963  *           GetDeviceCaps    (GDI32.@)
964  */
965 INT WINAPI GetDeviceCaps( HDC hdc, INT cap )
966 {
967     DC *dc;
968     INT ret = 0;
969
970     if ((dc = DC_GetDCPtr( hdc )))
971     {
972         if (dc->funcs->pGetDeviceCaps) ret = dc->funcs->pGetDeviceCaps( dc->physDev, cap );
973         else switch(cap)  /* return meaningful values for some entries */
974         {
975         case HORZRES:     ret = 640; break;
976         case VERTRES:     ret = 480; break;
977         case BITSPIXEL:   ret = 1; break;
978         case PLANES:      ret = 1; break;
979         case NUMCOLORS:   ret = 2; break;
980         case ASPECTX:     ret = 36; break;
981         case ASPECTY:     ret = 36; break;
982         case ASPECTXY:    ret = 51; break;
983         case LOGPIXELSX:  ret = 72; break;
984         case LOGPIXELSY:  ret = 72; break;
985         case SIZEPALETTE: ret = 2; break;
986         }
987         DC_ReleaseDCPtr( dc );
988     }
989     return ret;
990 }
991
992
993 /***********************************************************************
994  *              GetBkColor (GDI32.@)
995  */
996 COLORREF WINAPI GetBkColor( HDC hdc )
997 {
998     COLORREF ret = 0;
999     DC * dc = DC_GetDCPtr( hdc );
1000     if (dc)
1001     {
1002         ret = dc->backgroundColor;
1003         DC_ReleaseDCPtr( dc );
1004     }
1005     return ret;
1006 }
1007
1008
1009 /***********************************************************************
1010  *           SetBkColor    (GDI32.@)
1011  */
1012 COLORREF WINAPI SetBkColor( HDC hdc, COLORREF color )
1013 {
1014     COLORREF oldColor;
1015     DC * dc = DC_GetDCPtr( hdc );
1016
1017     TRACE("hdc=%p color=0x%08x\n", hdc, color);
1018
1019     if (!dc) return CLR_INVALID;
1020     oldColor = dc->backgroundColor;
1021     if (dc->funcs->pSetBkColor)
1022     {
1023         color = dc->funcs->pSetBkColor(dc->physDev, color);
1024         if (color == CLR_INVALID)  /* don't change it */
1025         {
1026             color = oldColor;
1027             oldColor = CLR_INVALID;
1028         }
1029     }
1030     dc->backgroundColor = color;
1031     DC_ReleaseDCPtr( dc );
1032     return oldColor;
1033 }
1034
1035
1036 /***********************************************************************
1037  *              GetTextColor (GDI32.@)
1038  */
1039 COLORREF WINAPI GetTextColor( HDC hdc )
1040 {
1041     COLORREF ret = 0;
1042     DC * dc = DC_GetDCPtr( hdc );
1043     if (dc)
1044     {
1045         ret = dc->textColor;
1046         DC_ReleaseDCPtr( dc );
1047     }
1048     return ret;
1049 }
1050
1051
1052 /***********************************************************************
1053  *           SetTextColor    (GDI32.@)
1054  */
1055 COLORREF WINAPI SetTextColor( HDC hdc, COLORREF color )
1056 {
1057     COLORREF oldColor;
1058     DC * dc = DC_GetDCPtr( hdc );
1059
1060     TRACE(" hdc=%p color=0x%08x\n", hdc, color);
1061
1062     if (!dc) return CLR_INVALID;
1063     oldColor = dc->textColor;
1064     if (dc->funcs->pSetTextColor)
1065     {
1066         color = dc->funcs->pSetTextColor(dc->physDev, color);
1067         if (color == CLR_INVALID)  /* don't change it */
1068         {
1069             color = oldColor;
1070             oldColor = CLR_INVALID;
1071         }
1072     }
1073     dc->textColor = color;
1074     DC_ReleaseDCPtr( dc );
1075     return oldColor;
1076 }
1077
1078
1079 /***********************************************************************
1080  *              GetTextAlign (GDI32.@)
1081  */
1082 UINT WINAPI GetTextAlign( HDC hdc )
1083 {
1084     UINT ret = 0;
1085     DC * dc = DC_GetDCPtr( hdc );
1086     if (dc)
1087     {
1088         ret = dc->textAlign;
1089         DC_ReleaseDCPtr( dc );
1090     }
1091     return ret;
1092 }
1093
1094
1095 /***********************************************************************
1096  *           SetTextAlign    (GDI32.@)
1097  */
1098 UINT WINAPI SetTextAlign( HDC hdc, UINT align )
1099 {
1100     UINT ret;
1101     DC *dc = DC_GetDCPtr( hdc );
1102
1103     TRACE("hdc=%p align=%d\n", hdc, align);
1104
1105     if (!dc) return 0x0;
1106     ret = dc->textAlign;
1107     if (dc->funcs->pSetTextAlign)
1108         if (!dc->funcs->pSetTextAlign(dc->physDev, align))
1109             ret = GDI_ERROR;
1110     if (ret != GDI_ERROR)
1111         dc->textAlign = align;
1112     DC_ReleaseDCPtr( dc );
1113     return ret;
1114 }
1115
1116 /***********************************************************************
1117  *           GetDCOrgEx  (GDI32.@)
1118  */
1119 BOOL WINAPI GetDCOrgEx( HDC hDC, LPPOINT lpp )
1120 {
1121     DC * dc;
1122
1123     if (!lpp) return FALSE;
1124     if (!(dc = DC_GetDCPtr( hDC ))) return FALSE;
1125
1126     lpp->x = lpp->y = 0;
1127     if (dc->funcs->pGetDCOrgEx) dc->funcs->pGetDCOrgEx( dc->physDev, lpp );
1128     DC_ReleaseDCPtr( dc );
1129     return TRUE;
1130 }
1131
1132
1133 /***********************************************************************
1134  *           SetDCOrg   (GDI.117)
1135  */
1136 DWORD WINAPI SetDCOrg16( HDC16 hdc16, INT16 x, INT16 y )
1137 {
1138     DWORD prevOrg = 0;
1139     HDC hdc = HDC_32( hdc16 );
1140     DC *dc = DC_GetDCPtr( hdc );
1141     if (!dc) return 0;
1142     if (dc->funcs->pSetDCOrg) prevOrg = dc->funcs->pSetDCOrg( dc->physDev, x, y );
1143     DC_ReleaseDCPtr( dc );
1144     return prevOrg;
1145 }
1146
1147
1148 /***********************************************************************
1149  *              GetGraphicsMode (GDI32.@)
1150  */
1151 INT WINAPI GetGraphicsMode( HDC hdc )
1152 {
1153     INT ret = 0;
1154     DC * dc = DC_GetDCPtr( hdc );
1155     if (dc)
1156     {
1157         ret = dc->GraphicsMode;
1158         DC_ReleaseDCPtr( dc );
1159     }
1160     return ret;
1161 }
1162
1163
1164 /***********************************************************************
1165  *           SetGraphicsMode    (GDI32.@)
1166  */
1167 INT WINAPI SetGraphicsMode( HDC hdc, INT mode )
1168 {
1169     INT ret = 0;
1170     DC *dc = DC_GetDCPtr( hdc );
1171
1172     /* One would think that setting the graphics mode to GM_COMPATIBLE
1173      * would also reset the world transformation matrix to the unity
1174      * matrix. However, in Windows, this is not the case. This doesn't
1175      * make a lot of sense to me, but that's the way it is.
1176      */
1177     if (!dc) return 0;
1178     if ((mode > 0) && (mode <= GM_LAST))
1179     {
1180         ret = dc->GraphicsMode;
1181         dc->GraphicsMode = mode;
1182     }
1183     DC_ReleaseDCPtr( dc );
1184     return ret;
1185 }
1186
1187
1188 /***********************************************************************
1189  *              GetArcDirection (GDI32.@)
1190  */
1191 INT WINAPI GetArcDirection( HDC hdc )
1192 {
1193     INT ret = 0;
1194     DC * dc = DC_GetDCPtr( hdc );
1195     if (dc)
1196     {
1197         ret = dc->ArcDirection;
1198         DC_ReleaseDCPtr( dc );
1199     }
1200     return ret;
1201 }
1202
1203
1204 /***********************************************************************
1205  *           SetArcDirection    (GDI32.@)
1206  */
1207 INT WINAPI SetArcDirection( HDC hdc, INT nDirection )
1208 {
1209     DC * dc;
1210     INT nOldDirection = 0;
1211
1212     if (nDirection!=AD_COUNTERCLOCKWISE && nDirection!=AD_CLOCKWISE)
1213     {
1214         SetLastError(ERROR_INVALID_PARAMETER);
1215         return 0;
1216     }
1217
1218     if ((dc = DC_GetDCPtr( hdc )))
1219     {
1220         if (dc->funcs->pSetArcDirection)
1221         {
1222             dc->funcs->pSetArcDirection(dc->physDev, nDirection);
1223         }
1224         nOldDirection = dc->ArcDirection;
1225         dc->ArcDirection = nDirection;
1226         DC_ReleaseDCPtr( dc );
1227     }
1228     return nOldDirection;
1229 }
1230
1231
1232 /***********************************************************************
1233  *           GetWorldTransform    (GDI32.@)
1234  */
1235 BOOL WINAPI GetWorldTransform( HDC hdc, LPXFORM xform )
1236 {
1237     DC * dc;
1238     if (!xform) return FALSE;
1239     if (!(dc = DC_GetDCPtr( hdc ))) return FALSE;
1240     *xform = dc->xformWorld2Wnd;
1241     DC_ReleaseDCPtr( dc );
1242     return TRUE;
1243 }
1244
1245
1246 /***********************************************************************
1247  *           GetTransform    (GDI32.@)
1248  */
1249 BOOL WINAPI GetTransform( HDC hdc, DWORD unknown, LPXFORM xform )
1250 {
1251     if (unknown == 0x0203) return GetWorldTransform( hdc, xform );
1252     FIXME("stub: don't know what to do for code %x\n", unknown );
1253     return FALSE;
1254 }
1255
1256
1257 /***********************************************************************
1258  *           SetWorldTransform    (GDI32.@)
1259  */
1260 BOOL WINAPI SetWorldTransform( HDC hdc, const XFORM *xform )
1261 {
1262     BOOL ret = FALSE;
1263     DC *dc = DC_GetDCPtr( hdc );
1264
1265     if (!dc) return FALSE;
1266     if (!xform) goto done;
1267
1268     /* Check that graphics mode is GM_ADVANCED */
1269     if (dc->GraphicsMode!=GM_ADVANCED) goto done;
1270
1271     if (dc->funcs->pSetWorldTransform)
1272     {
1273         ret = dc->funcs->pSetWorldTransform(dc->physDev, xform);
1274         if (!ret) goto done;
1275     }
1276
1277     dc->xformWorld2Wnd = *xform;
1278     DC_UpdateXforms( dc );
1279     ret = TRUE;
1280  done:
1281     DC_ReleaseDCPtr( dc );
1282     return ret;
1283 }
1284
1285
1286 /****************************************************************************
1287  * ModifyWorldTransform [GDI32.@]
1288  * Modifies the world transformation for a device context.
1289  *
1290  * PARAMS
1291  *    hdc   [I] Handle to device context
1292  *    xform [I] XFORM structure that will be used to modify the world
1293  *              transformation
1294  *    iMode [I] Specifies in what way to modify the world transformation
1295  *              Possible values:
1296  *              MWT_IDENTITY
1297  *                 Resets the world transformation to the identity matrix.
1298  *                 The parameter xform is ignored.
1299  *              MWT_LEFTMULTIPLY
1300  *                 Multiplies xform into the world transformation matrix from
1301  *                 the left.
1302  *              MWT_RIGHTMULTIPLY
1303  *                 Multiplies xform into the world transformation matrix from
1304  *                 the right.
1305  *
1306  * RETURNS
1307  *  Success: TRUE.
1308  *  Failure: FALSE. Use GetLastError() to determine the cause.
1309  */
1310 BOOL WINAPI ModifyWorldTransform( HDC hdc, const XFORM *xform,
1311     DWORD iMode )
1312 {
1313     BOOL ret = FALSE;
1314     DC *dc = DC_GetDCPtr( hdc );
1315
1316     /* Check for illegal parameters */
1317     if (!dc) return FALSE;
1318     if (!xform && iMode != MWT_IDENTITY) goto done;
1319
1320     /* Check that graphics mode is GM_ADVANCED */
1321     if (dc->GraphicsMode!=GM_ADVANCED) goto done;
1322
1323     if (dc->funcs->pModifyWorldTransform)
1324     {
1325         ret = dc->funcs->pModifyWorldTransform(dc->physDev, xform, iMode);
1326         if (!ret) goto done;
1327     }
1328
1329     switch (iMode)
1330     {
1331         case MWT_IDENTITY:
1332             dc->xformWorld2Wnd.eM11 = 1.0f;
1333             dc->xformWorld2Wnd.eM12 = 0.0f;
1334             dc->xformWorld2Wnd.eM21 = 0.0f;
1335             dc->xformWorld2Wnd.eM22 = 1.0f;
1336             dc->xformWorld2Wnd.eDx  = 0.0f;
1337             dc->xformWorld2Wnd.eDy  = 0.0f;
1338             break;
1339         case MWT_LEFTMULTIPLY:
1340             CombineTransform( &dc->xformWorld2Wnd, xform,
1341                 &dc->xformWorld2Wnd );
1342             break;
1343         case MWT_RIGHTMULTIPLY:
1344             CombineTransform( &dc->xformWorld2Wnd, &dc->xformWorld2Wnd,
1345                 xform );
1346             break;
1347         default:
1348             goto done;
1349     }
1350
1351     DC_UpdateXforms( dc );
1352     ret = TRUE;
1353  done:
1354     DC_ReleaseDCPtr( dc );
1355     return ret;
1356 }
1357
1358
1359 /****************************************************************************
1360  * CombineTransform [GDI32.@]
1361  * Combines two transformation matrices.
1362  *
1363  * PARAMS
1364  *    xformResult [O] Stores the result of combining the two matrices
1365  *    xform1      [I] Specifies the first matrix to apply
1366  *    xform2      [I] Specifies the second matrix to apply
1367  *
1368  * REMARKS
1369  *    The same matrix can be passed in for more than one of the parameters.
1370  *
1371  * RETURNS
1372  *  Success: TRUE.
1373  *  Failure: FALSE. Use GetLastError() to determine the cause.
1374  */
1375 BOOL WINAPI CombineTransform( LPXFORM xformResult, const XFORM *xform1,
1376     const XFORM *xform2 )
1377 {
1378     XFORM xformTemp;
1379
1380     /* Check for illegal parameters */
1381     if (!xformResult || !xform1 || !xform2)
1382         return FALSE;
1383
1384     /* Create the result in a temporary XFORM, since xformResult may be
1385      * equal to xform1 or xform2 */
1386     xformTemp.eM11 = xform1->eM11 * xform2->eM11 +
1387                      xform1->eM12 * xform2->eM21;
1388     xformTemp.eM12 = xform1->eM11 * xform2->eM12 +
1389                      xform1->eM12 * xform2->eM22;
1390     xformTemp.eM21 = xform1->eM21 * xform2->eM11 +
1391                      xform1->eM22 * xform2->eM21;
1392     xformTemp.eM22 = xform1->eM21 * xform2->eM12 +
1393                      xform1->eM22 * xform2->eM22;
1394     xformTemp.eDx  = xform1->eDx  * xform2->eM11 +
1395                      xform1->eDy  * xform2->eM21 +
1396                      xform2->eDx;
1397     xformTemp.eDy  = xform1->eDx  * xform2->eM12 +
1398                      xform1->eDy  * xform2->eM22 +
1399                      xform2->eDy;
1400
1401     /* Copy the result to xformResult */
1402     *xformResult = xformTemp;
1403
1404     return TRUE;
1405 }
1406
1407
1408 /***********************************************************************
1409  *           SetDCHook   (GDI32.@)
1410  *
1411  * Note: this doesn't exist in Win32, we add it here because user32 needs it.
1412  */
1413 BOOL WINAPI SetDCHook( HDC hdc, DCHOOKPROC hookProc, DWORD_PTR dwHookData )
1414 {
1415     DC *dc = DC_GetDCPtr( hdc );
1416
1417     if (!dc) return FALSE;
1418
1419     if (!(dc->flags & DC_SAVED))
1420     {
1421         dc->dwHookData = dwHookData;
1422         dc->hookThunk = hookProc;
1423     }
1424     DC_ReleaseDCPtr( dc );
1425     return TRUE;
1426 }
1427
1428
1429 /* relay function to call the 16-bit DC hook proc */
1430 static BOOL WINAPI call_dc_hook16( HDC hdc, WORD code, DWORD_PTR data, LPARAM lParam )
1431 {
1432     WORD args[6];
1433     DWORD ret;
1434     FARPROC16 proc = NULL;
1435     DC *dc = DC_GetDCPtr( hdc );
1436
1437     if (!dc) return FALSE;
1438     proc = dc->hookProc;
1439     DC_ReleaseDCPtr( dc );
1440     if (!proc) return FALSE;
1441     args[5] = HDC_16(hdc);
1442     args[4] = code;
1443     args[3] = HIWORD(data);
1444     args[2] = LOWORD(data);
1445     args[1] = HIWORD(lParam);
1446     args[0] = LOWORD(lParam);
1447     WOWCallback16Ex( (DWORD)proc, WCB16_PASCAL, sizeof(args), args, &ret );
1448     return LOWORD(ret);
1449 }
1450
1451 /***********************************************************************
1452  *           SetDCHook   (GDI.190)
1453  */
1454 BOOL16 WINAPI SetDCHook16( HDC16 hdc16, FARPROC16 hookProc, DWORD dwHookData )
1455 {
1456     HDC hdc = HDC_32( hdc16 );
1457     DC *dc = DC_GetDCPtr( hdc );
1458     if (!dc) return FALSE;
1459
1460     dc->hookProc = hookProc;
1461     DC_ReleaseDCPtr( dc );
1462     return SetDCHook( hdc, call_dc_hook16, dwHookData );
1463 }
1464
1465
1466 /***********************************************************************
1467  *           GetDCHook   (GDI.191)
1468  */
1469 DWORD WINAPI GetDCHook16( HDC16 hdc16, FARPROC16 *phookProc )
1470 {
1471     HDC hdc = HDC_32( hdc16 );
1472     DC *dc = DC_GetDCPtr( hdc );
1473     DWORD ret;
1474
1475     if (!dc) return 0;
1476     *phookProc = dc->hookProc;
1477     ret = dc->dwHookData;
1478     DC_ReleaseDCPtr( dc );
1479     return ret;
1480 }
1481
1482
1483 /***********************************************************************
1484  *           SetHookFlags   (GDI.192)
1485  */
1486 WORD WINAPI SetHookFlags16(HDC16 hdc16, WORD flags)
1487 {
1488     HDC hdc = HDC_32( hdc16 );
1489     DC *dc = get_dc_obj( hdc );  /* not get_dc_ptr, this needs to work from any thread */
1490     LONG ret = 0;
1491
1492     if (!dc) return 0;
1493
1494     /* "Undocumented Windows" info is slightly confusing. */
1495
1496     TRACE("hDC %p, flags %04x\n",hdc,flags);
1497
1498     if (flags & DCHF_INVALIDATEVISRGN)
1499         ret = InterlockedExchange( &dc->dirty, 1 );
1500     else if (flags & DCHF_VALIDATEVISRGN || !flags)
1501         ret = InterlockedExchange( &dc->dirty, 0 );
1502
1503     GDI_ReleaseObj( dc );
1504     return ret;
1505 }
1506
1507 /***********************************************************************
1508  *           SetICMMode    (GDI32.@)
1509  */
1510 INT WINAPI SetICMMode(HDC hdc, INT iEnableICM)
1511 {
1512 /*FIXME  Asuming that ICM is always off, and cannot be turned on */
1513     if (iEnableICM == ICM_OFF) return ICM_OFF;
1514     if (iEnableICM == ICM_ON) return 0;
1515     if (iEnableICM == ICM_QUERY) return ICM_OFF;
1516     return 0;
1517 }
1518
1519 /***********************************************************************
1520  *           GetDeviceGammaRamp    (GDI32.@)
1521  */
1522 BOOL WINAPI GetDeviceGammaRamp(HDC hDC, LPVOID ptr)
1523 {
1524     BOOL ret = FALSE;
1525     DC *dc = DC_GetDCPtr( hDC );
1526
1527     if( dc )
1528     {
1529         if (dc->funcs->pGetDeviceGammaRamp)
1530             ret = dc->funcs->pGetDeviceGammaRamp(dc->physDev, ptr);
1531         DC_ReleaseDCPtr( dc );
1532     }
1533     return ret;
1534 }
1535
1536 /***********************************************************************
1537  *           SetDeviceGammaRamp    (GDI32.@)
1538  */
1539 BOOL WINAPI SetDeviceGammaRamp(HDC hDC, LPVOID ptr)
1540 {
1541     BOOL ret = FALSE;
1542     DC *dc = DC_GetDCPtr( hDC );
1543
1544     if( dc )
1545     {
1546         if (dc->funcs->pSetDeviceGammaRamp)
1547             ret = dc->funcs->pSetDeviceGammaRamp(dc->physDev, ptr);
1548         DC_ReleaseDCPtr( dc );
1549     }
1550     return ret;
1551 }
1552
1553 /***********************************************************************
1554  *           GetColorSpace    (GDI32.@)
1555  */
1556 HCOLORSPACE WINAPI GetColorSpace(HDC hdc)
1557 {
1558 /*FIXME    Need to to whatever GetColorSpace actually does */
1559     return 0;
1560 }
1561
1562 /***********************************************************************
1563  *           CreateColorSpaceA    (GDI32.@)
1564  */
1565 HCOLORSPACE WINAPI CreateColorSpaceA( LPLOGCOLORSPACEA lpLogColorSpace )
1566 {
1567   FIXME( "stub\n" );
1568   return 0;
1569 }
1570
1571 /***********************************************************************
1572  *           CreateColorSpaceW    (GDI32.@)
1573  */
1574 HCOLORSPACE WINAPI CreateColorSpaceW( LPLOGCOLORSPACEW lpLogColorSpace )
1575 {
1576   FIXME( "stub\n" );
1577   return 0;
1578 }
1579
1580 /***********************************************************************
1581  *           DeleteColorSpace     (GDI32.@)
1582  */
1583 BOOL WINAPI DeleteColorSpace( HCOLORSPACE hColorSpace )
1584 {
1585   FIXME( "stub\n" );
1586
1587   return TRUE;
1588 }
1589
1590 /***********************************************************************
1591  *           SetColorSpace     (GDI32.@)
1592  */
1593 HCOLORSPACE WINAPI SetColorSpace( HDC hDC, HCOLORSPACE hColorSpace )
1594 {
1595   FIXME( "stub\n" );
1596
1597   return hColorSpace;
1598 }
1599
1600 /***********************************************************************
1601  *           GetBoundsRect    (GDI32.@)
1602  */
1603 UINT WINAPI GetBoundsRect(HDC hdc, LPRECT rect, UINT flags)
1604 {
1605     UINT ret;
1606     DC *dc = DC_GetDCPtr( hdc );
1607
1608     if ( !dc ) return 0;
1609
1610     if (rect) *rect = dc->BoundsRect;
1611
1612     ret = ((dc->flags & DC_BOUNDS_SET) ? DCB_SET : DCB_RESET);
1613
1614     if (flags & DCB_RESET)
1615     {
1616         dc->BoundsRect.left   = 0;
1617         dc->BoundsRect.top    = 0;
1618         dc->BoundsRect.right  = 0;
1619         dc->BoundsRect.bottom = 0;
1620         dc->flags &= ~DC_BOUNDS_SET;
1621     }
1622     DC_ReleaseDCPtr( dc );
1623     return ret;
1624 }
1625
1626
1627 /***********************************************************************
1628  *           SetBoundsRect    (GDI32.@)
1629  */
1630 UINT WINAPI SetBoundsRect(HDC hdc, const RECT* rect, UINT flags)
1631 {
1632     UINT ret;
1633     DC *dc;
1634
1635     if ((flags & DCB_ENABLE) && (flags & DCB_DISABLE)) return 0;
1636     if (!(dc = DC_GetDCPtr( hdc ))) return 0;
1637
1638     ret = ((dc->flags & DC_BOUNDS_ENABLE) ? DCB_ENABLE : DCB_DISABLE) |
1639           ((dc->flags & DC_BOUNDS_SET) ? DCB_SET : DCB_RESET);
1640
1641     if (flags & DCB_RESET)
1642     {
1643         dc->BoundsRect.left   = 0;
1644         dc->BoundsRect.top    = 0;
1645         dc->BoundsRect.right  = 0;
1646         dc->BoundsRect.bottom = 0;
1647         dc->flags &= ~DC_BOUNDS_SET;
1648     }
1649
1650     if ((flags & DCB_ACCUMULATE) && rect && rect->left < rect->right && rect->top < rect->bottom)
1651     {
1652         if (dc->flags & DC_BOUNDS_SET)
1653         {
1654             dc->BoundsRect.left   = min( dc->BoundsRect.left, rect->left );
1655             dc->BoundsRect.top    = min( dc->BoundsRect.top, rect->top );
1656             dc->BoundsRect.right  = max( dc->BoundsRect.right, rect->right );
1657             dc->BoundsRect.bottom = max( dc->BoundsRect.bottom, rect->bottom );
1658         }
1659         else
1660         {
1661             dc->BoundsRect = *rect;
1662             dc->flags |= DC_BOUNDS_SET;
1663         }
1664     }
1665
1666     if (flags & DCB_ENABLE) dc->flags |= DC_BOUNDS_ENABLE;
1667     if (flags & DCB_DISABLE) dc->flags &= ~DC_BOUNDS_ENABLE;
1668
1669     DC_ReleaseDCPtr( dc );
1670     return ret;
1671 }
1672
1673
1674 /***********************************************************************
1675  *              GetRelAbs               (GDI32.@)
1676  */
1677 INT WINAPI GetRelAbs( HDC hdc, DWORD dwIgnore )
1678 {
1679     INT ret = 0;
1680     DC *dc = DC_GetDCPtr( hdc );
1681     if (dc)
1682     {
1683         ret = dc->relAbsMode;
1684         DC_ReleaseDCPtr( dc );
1685     }
1686     return ret;
1687 }
1688
1689
1690
1691
1692 /***********************************************************************
1693  *              GetBkMode (GDI32.@)
1694  */
1695 INT WINAPI GetBkMode( HDC hdc )
1696 {
1697     INT ret = 0;
1698     DC * dc = DC_GetDCPtr( hdc );
1699     if (dc)
1700     {
1701         ret = dc->backgroundMode;
1702         DC_ReleaseDCPtr( dc );
1703     }
1704     return ret;
1705 }
1706
1707
1708 /***********************************************************************
1709  *              SetBkMode (GDI32.@)
1710  */
1711 INT WINAPI SetBkMode( HDC hdc, INT mode )
1712 {
1713     INT ret;
1714     DC *dc;
1715     if ((mode <= 0) || (mode > BKMODE_LAST))
1716     {
1717         SetLastError(ERROR_INVALID_PARAMETER);
1718         return 0;
1719     }
1720     if (!(dc = DC_GetDCPtr( hdc ))) return 0;
1721
1722     ret = dc->backgroundMode;
1723     if (dc->funcs->pSetBkMode)
1724         if (!dc->funcs->pSetBkMode( dc->physDev, mode ))
1725             ret = 0;
1726     if (ret)
1727         dc->backgroundMode = mode;
1728     DC_ReleaseDCPtr( dc );
1729     return ret;
1730 }
1731
1732
1733 /***********************************************************************
1734  *              GetROP2 (GDI32.@)
1735  */
1736 INT WINAPI GetROP2( HDC hdc )
1737 {
1738     INT ret = 0;
1739     DC * dc = DC_GetDCPtr( hdc );
1740     if (dc)
1741     {
1742         ret = dc->ROPmode;
1743         DC_ReleaseDCPtr( dc );
1744     }
1745     return ret;
1746 }
1747
1748
1749 /***********************************************************************
1750  *              SetROP2 (GDI32.@)
1751  */
1752 INT WINAPI SetROP2( HDC hdc, INT mode )
1753 {
1754     INT ret;
1755     DC *dc;
1756     if ((mode < R2_BLACK) || (mode > R2_WHITE))
1757     {
1758         SetLastError(ERROR_INVALID_PARAMETER);
1759         return 0;
1760     }
1761     if (!(dc = DC_GetDCPtr( hdc ))) return 0;
1762     ret = dc->ROPmode;
1763     if (dc->funcs->pSetROP2)
1764         if (!dc->funcs->pSetROP2( dc->physDev, mode ))
1765             ret = 0;
1766     if (ret)
1767         dc->ROPmode = mode;
1768     DC_ReleaseDCPtr( dc );
1769     return ret;
1770 }
1771
1772
1773 /***********************************************************************
1774  *              SetRelAbs (GDI32.@)
1775  */
1776 INT WINAPI SetRelAbs( HDC hdc, INT mode )
1777 {
1778     INT ret;
1779     DC *dc;
1780     if ((mode != ABSOLUTE) && (mode != RELATIVE))
1781     {
1782         SetLastError(ERROR_INVALID_PARAMETER);
1783         return 0;
1784     }
1785     if (!(dc = DC_GetDCPtr( hdc ))) return 0;
1786     if (dc->funcs->pSetRelAbs)
1787         ret = dc->funcs->pSetRelAbs( dc->physDev, mode );
1788     else
1789     {
1790         ret = dc->relAbsMode;
1791         dc->relAbsMode = mode;
1792     }
1793     DC_ReleaseDCPtr( dc );
1794     return ret;
1795 }
1796
1797
1798 /***********************************************************************
1799  *              GetPolyFillMode (GDI32.@)
1800  */
1801 INT WINAPI GetPolyFillMode( HDC hdc )
1802 {
1803     INT ret = 0;
1804     DC * dc = DC_GetDCPtr( hdc );
1805     if (dc)
1806     {
1807         ret = dc->polyFillMode;
1808         DC_ReleaseDCPtr( dc );
1809     }
1810     return ret;
1811 }
1812
1813
1814 /***********************************************************************
1815  *              SetPolyFillMode (GDI32.@)
1816  */
1817 INT WINAPI SetPolyFillMode( HDC hdc, INT mode )
1818 {
1819     INT ret;
1820     DC *dc;
1821     if ((mode <= 0) || (mode > POLYFILL_LAST))
1822     {
1823         SetLastError(ERROR_INVALID_PARAMETER);
1824         return 0;
1825     }
1826     if (!(dc = DC_GetDCPtr( hdc ))) return 0;
1827     ret = dc->polyFillMode;
1828     if (dc->funcs->pSetPolyFillMode)
1829         if (!dc->funcs->pSetPolyFillMode( dc->physDev, mode ))
1830             ret = 0;
1831     if (ret)
1832         dc->polyFillMode = mode;
1833     DC_ReleaseDCPtr( dc );
1834     return ret;
1835 }
1836
1837
1838 /***********************************************************************
1839  *              GetStretchBltMode (GDI32.@)
1840  */
1841 INT WINAPI GetStretchBltMode( HDC hdc )
1842 {
1843     INT ret = 0;
1844     DC * dc = DC_GetDCPtr( hdc );
1845     if (dc)
1846     {
1847         ret = dc->stretchBltMode;
1848         DC_ReleaseDCPtr( dc );
1849     }
1850     return ret;
1851 }
1852
1853
1854 /***********************************************************************
1855  *              SetStretchBltMode (GDI32.@)
1856  */
1857 INT WINAPI SetStretchBltMode( HDC hdc, INT mode )
1858 {
1859     INT ret;
1860     DC *dc;
1861     if ((mode <= 0) || (mode > MAXSTRETCHBLTMODE))
1862     {
1863         SetLastError(ERROR_INVALID_PARAMETER);
1864         return 0;
1865     }
1866     if (!(dc = DC_GetDCPtr( hdc ))) return 0;
1867     ret = dc->stretchBltMode;
1868     if (dc->funcs->pSetStretchBltMode)
1869         if (!dc->funcs->pSetStretchBltMode( dc->physDev, mode ))
1870             ret = 0;
1871     if (ret)
1872         dc->stretchBltMode = mode;
1873     DC_ReleaseDCPtr( dc );
1874     return ret;
1875 }
1876
1877
1878 /***********************************************************************
1879  *              GetMapMode (GDI32.@)
1880  */
1881 INT WINAPI GetMapMode( HDC hdc )
1882 {
1883     INT ret = 0;
1884     DC * dc = DC_GetDCPtr( hdc );
1885     if (dc)
1886     {
1887         ret = dc->MapMode;
1888         DC_ReleaseDCPtr( dc );
1889     }
1890     return ret;
1891 }
1892
1893
1894 /***********************************************************************
1895  *              GetBrushOrgEx (GDI32.@)
1896  */
1897 BOOL WINAPI GetBrushOrgEx( HDC hdc, LPPOINT pt )
1898 {
1899     DC * dc = DC_GetDCPtr( hdc );
1900     if (!dc) return FALSE;
1901     pt->x = dc->brushOrgX;
1902     pt->y = dc->brushOrgY;
1903     DC_ReleaseDCPtr( dc );
1904     return TRUE;
1905 }
1906
1907
1908 /***********************************************************************
1909  *              GetCurrentPositionEx (GDI32.@)
1910  */
1911 BOOL WINAPI GetCurrentPositionEx( HDC hdc, LPPOINT pt )
1912 {
1913     DC * dc = DC_GetDCPtr( hdc );
1914     if (!dc) return FALSE;
1915     pt->x = dc->CursPosX;
1916     pt->y = dc->CursPosY;
1917     DC_ReleaseDCPtr( dc );
1918     return TRUE;
1919 }
1920
1921
1922 /***********************************************************************
1923  *              GetViewportExtEx (GDI32.@)
1924  */
1925 BOOL WINAPI GetViewportExtEx( HDC hdc, LPSIZE size )
1926 {
1927     DC * dc = DC_GetDCPtr( hdc );
1928     if (!dc) return FALSE;
1929     size->cx = dc->vportExtX;
1930     size->cy = dc->vportExtY;
1931     DC_ReleaseDCPtr( dc );
1932     return TRUE;
1933 }
1934
1935
1936 /***********************************************************************
1937  *              GetViewportOrgEx (GDI32.@)
1938  */
1939 BOOL WINAPI GetViewportOrgEx( HDC hdc, LPPOINT pt )
1940 {
1941     DC * dc = DC_GetDCPtr( hdc );
1942     if (!dc) return FALSE;
1943     pt->x = dc->vportOrgX;
1944     pt->y = dc->vportOrgY;
1945     DC_ReleaseDCPtr( dc );
1946     return TRUE;
1947 }
1948
1949
1950 /***********************************************************************
1951  *              GetWindowExtEx (GDI32.@)
1952  */
1953 BOOL WINAPI GetWindowExtEx( HDC hdc, LPSIZE size )
1954 {
1955     DC * dc = DC_GetDCPtr( hdc );
1956     if (!dc) return FALSE;
1957     size->cx = dc->wndExtX;
1958     size->cy = dc->wndExtY;
1959     DC_ReleaseDCPtr( dc );
1960     return TRUE;
1961 }
1962
1963
1964 /***********************************************************************
1965  *              GetWindowOrgEx (GDI32.@)
1966  */
1967 BOOL WINAPI GetWindowOrgEx( HDC hdc, LPPOINT pt )
1968 {
1969     DC * dc = DC_GetDCPtr( hdc );
1970     if (!dc) return FALSE;
1971     pt->x = dc->wndOrgX;
1972     pt->y = dc->wndOrgY;
1973     DC_ReleaseDCPtr( dc );
1974     return TRUE;
1975 }
1976
1977
1978 /***********************************************************************
1979  *              InquireVisRgn   (GDI.131)
1980  */
1981 HRGN16 WINAPI InquireVisRgn16( HDC16 hdc )
1982 {
1983     HRGN16 ret = 0;
1984     DC * dc = DC_GetDCPtr( HDC_32(hdc) );
1985     if (dc)
1986     {
1987         ret = HRGN_16(dc->hVisRgn);
1988         DC_ReleaseDCPtr( dc );
1989     }
1990     return ret;
1991 }
1992
1993
1994 /***********************************************************************
1995  *              GetClipRgn (GDI.173)
1996  */
1997 HRGN16 WINAPI GetClipRgn16( HDC16 hdc )
1998 {
1999     HRGN16 ret = 0;
2000     DC * dc = DC_GetDCPtr( HDC_32(hdc) );
2001     if (dc)
2002     {
2003         ret = HRGN_16(dc->hClipRgn);
2004         DC_ReleaseDCPtr( dc );
2005     }
2006     return ret;
2007 }
2008
2009
2010 /***********************************************************************
2011  *           GetLayout    (GDI32.@)
2012  *
2013  * Gets left->right or right->left text layout flags of a dc.
2014  *
2015  */
2016 DWORD WINAPI GetLayout(HDC hdc)
2017 {
2018     DWORD layout = GDI_ERROR;
2019
2020     DC * dc = DC_GetDCPtr( hdc );
2021     if (dc)
2022     {
2023         layout = dc->layout;
2024         DC_ReleaseDCPtr( dc );
2025     }
2026
2027     TRACE("hdc : %p, layout : %08x\n", hdc, layout);
2028
2029     return layout;
2030 }
2031
2032 /***********************************************************************
2033  *           SetLayout    (GDI32.@)
2034  *
2035  * Sets left->right or right->left text layout flags of a dc.
2036  *
2037  */
2038 DWORD WINAPI SetLayout(HDC hdc, DWORD layout)
2039 {
2040     DWORD oldlayout = GDI_ERROR;
2041
2042     DC * dc = DC_GetDCPtr( hdc );
2043     if (dc)
2044     {
2045         oldlayout = dc->layout;
2046         dc->layout = layout;
2047         DC_ReleaseDCPtr( dc );
2048     }
2049
2050     TRACE("hdc : %p, old layout : %08x, new layout : %08x\n", hdc, oldlayout, layout);
2051
2052     return oldlayout;
2053 }
2054
2055 /***********************************************************************
2056  *           GetDCBrushColor    (GDI32.@)
2057  *
2058  * Retrieves the current brush color for the specified device
2059  * context (DC).
2060  *
2061  */
2062 COLORREF WINAPI GetDCBrushColor(HDC hdc)
2063 {
2064     DC *dc;
2065     COLORREF dcBrushColor = CLR_INVALID;
2066
2067     TRACE("hdc(%p)\n", hdc);
2068
2069     dc = DC_GetDCPtr( hdc );
2070     if (dc)
2071     {
2072         dcBrushColor = dc->dcBrushColor;
2073         DC_ReleaseDCPtr( dc );
2074     }
2075
2076     return dcBrushColor;
2077 }
2078
2079 /***********************************************************************
2080  *           SetDCBrushColor    (GDI32.@)
2081  *
2082  * Sets the current device context (DC) brush color to the specified
2083  * color value. If the device cannot represent the specified color
2084  * value, the color is set to the nearest physical color.
2085  *
2086  */
2087 COLORREF WINAPI SetDCBrushColor(HDC hdc, COLORREF crColor)
2088 {
2089     DC *dc;
2090     COLORREF oldClr = CLR_INVALID;
2091
2092     TRACE("hdc(%p) crColor(%08x)\n", hdc, crColor);
2093
2094     dc = DC_GetDCPtr( hdc );
2095     if (dc)
2096     {
2097         if (dc->funcs->pSetDCBrushColor)
2098             crColor = dc->funcs->pSetDCBrushColor( dc->physDev, crColor );
2099         else if (dc->hBrush == GetStockObject( DC_BRUSH ))
2100         {
2101             /* If DC_BRUSH is selected, update driver pen color */
2102             HBRUSH hBrush = CreateSolidBrush( crColor );
2103             dc->funcs->pSelectBrush( dc->physDev, hBrush );
2104             DeleteObject( hBrush );
2105         }
2106
2107         if (crColor != CLR_INVALID)
2108         {
2109             oldClr = dc->dcBrushColor;
2110             dc->dcBrushColor = crColor;
2111         }
2112
2113         DC_ReleaseDCPtr( dc );
2114     }
2115
2116     return oldClr;
2117 }
2118
2119 /***********************************************************************
2120  *           GetDCPenColor    (GDI32.@)
2121  *
2122  * Retrieves the current pen color for the specified device
2123  * context (DC).
2124  *
2125  */
2126 COLORREF WINAPI GetDCPenColor(HDC hdc)
2127 {
2128     DC *dc;
2129     COLORREF dcPenColor = CLR_INVALID;
2130
2131     TRACE("hdc(%p)\n", hdc);
2132
2133     dc = DC_GetDCPtr( hdc );
2134     if (dc)
2135     {
2136         dcPenColor = dc->dcPenColor;
2137         DC_ReleaseDCPtr( dc );
2138     }
2139
2140     return dcPenColor;
2141 }
2142
2143 /***********************************************************************
2144  *           SetDCPenColor    (GDI32.@)
2145  *
2146  * Sets the current device context (DC) pen color to the specified
2147  * color value. If the device cannot represent the specified color
2148  * value, the color is set to the nearest physical color.
2149  *
2150  */
2151 COLORREF WINAPI SetDCPenColor(HDC hdc, COLORREF crColor)
2152 {
2153     DC *dc;
2154     COLORREF oldClr = CLR_INVALID;
2155
2156     TRACE("hdc(%p) crColor(%08x)\n", hdc, crColor);
2157
2158     dc = DC_GetDCPtr( hdc );
2159     if (dc)
2160     {
2161         if (dc->funcs->pSetDCPenColor)
2162             crColor = dc->funcs->pSetDCPenColor( dc->physDev, crColor );
2163         else if (dc->hPen == GetStockObject( DC_PEN ))
2164         {
2165             /* If DC_PEN is selected, update the driver pen color */
2166             LOGPEN logpen = { PS_SOLID, { 0, 0 }, crColor };
2167             HPEN hPen = CreatePenIndirect( &logpen );
2168             dc->funcs->pSelectPen( dc->physDev, hPen );
2169             DeleteObject( hPen );
2170         }
2171
2172         if (crColor != CLR_INVALID)
2173         {
2174             oldClr = dc->dcPenColor;
2175             dc->dcPenColor = crColor;
2176         }
2177
2178         DC_ReleaseDCPtr( dc );
2179     }
2180
2181     return oldClr;
2182 }
2183
2184 /***********************************************************************
2185  *           CancelDC    (GDI32.@)
2186  */
2187 BOOL WINAPI CancelDC(HDC hdc)
2188 {
2189     FIXME("stub\n");
2190     return TRUE;
2191 }
2192
2193 /***********************************************************************
2194  *           SetVirtualResolution   (GDI32.@)
2195  *
2196  * Undocumented on msdn.  Called when PowerPoint XP saves a file.
2197  */
2198 DWORD WINAPI SetVirtualResolution(HDC hdc, DWORD dw2, DWORD dw3, DWORD dw4, DWORD dw5)
2199 {
2200     FIXME("(%p %08x %08x %08x %08x): stub!\n", hdc, dw2, dw3, dw4, dw5);
2201     return FALSE;
2202 }
2203
2204 /*******************************************************************
2205  *      GetMiterLimit [GDI32.@]
2206  *
2207  *
2208  */
2209 BOOL WINAPI GetMiterLimit(HDC hdc, PFLOAT peLimit)
2210 {
2211     BOOL bRet = FALSE;
2212     DC *dc;
2213
2214     TRACE("(%p,%p)\n", hdc, peLimit);
2215
2216     dc = DC_GetDCPtr( hdc );
2217     if (dc)
2218     {
2219         if (peLimit)
2220             *peLimit = dc->miterLimit;
2221
2222         DC_ReleaseDCPtr( dc );
2223         bRet = TRUE;
2224     }
2225     return bRet;
2226 }
2227
2228 /*******************************************************************
2229  *      SetMiterLimit [GDI32.@]
2230  *
2231  *
2232  */
2233 BOOL WINAPI SetMiterLimit(HDC hdc, FLOAT eNewLimit, PFLOAT peOldLimit)
2234 {
2235     BOOL bRet = FALSE;
2236     DC *dc;
2237
2238     TRACE("(%p,%f,%p)\n", hdc, eNewLimit, peOldLimit);
2239
2240     dc = DC_GetDCPtr( hdc );
2241     if (dc)
2242     {
2243         if (peOldLimit)
2244             *peOldLimit = dc->miterLimit;
2245         dc->miterLimit = eNewLimit;
2246         DC_ReleaseDCPtr( dc );
2247         bRet = TRUE;
2248     }
2249     return bRet;
2250 }
2251
2252 /*******************************************************************
2253  *      GdiIsMetaPrintDC [GDI32.@]
2254  */
2255 BOOL WINAPI GdiIsMetaPrintDC(HDC hdc)
2256 {
2257     FIXME("%p\n", hdc);
2258     return FALSE;
2259 }
2260
2261 /*******************************************************************
2262  *      GdiIsMetaFileDC [GDI32.@]
2263  */
2264 BOOL WINAPI GdiIsMetaFileDC(HDC hdc)
2265 {
2266     TRACE("%p\n", hdc);
2267
2268     switch( GetObjectType( hdc ) )
2269     {
2270     case OBJ_METADC:
2271     case OBJ_ENHMETADC:
2272         return TRUE;
2273     }
2274     return FALSE;
2275 }
2276
2277 /*******************************************************************
2278  *      GdiIsPlayMetafileDC [GDI32.@]
2279  */
2280 BOOL WINAPI GdiIsPlayMetafileDC(HDC hdc)
2281 {
2282     FIXME("%p\n", hdc);
2283     return FALSE;
2284 }