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