quartz: Fix discontinuities in wave parser.
[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     else if (hdc) return 0;
789
790     if (!funcs && !(funcs = DRIVER_load_driver( displayW ))) return 0;
791
792     if (!(dc = alloc_dc_ptr( funcs, MEMORY_DC_MAGIC ))) goto error;
793
794     TRACE("(%p): returning %p\n", hdc, dc->hSelf );
795
796     dc->hBitmap = GetStockObject( DEFAULT_BITMAP );
797     if (!(dc->hVisRgn = CreateRectRgn( 0, 0, 1, 1 ))) goto error;   /* default bitmap is 1x1 */
798
799     /* Copy the driver-specific physical device info into
800      * the new DC. The driver may use this read-only info
801      * while creating the compatible DC below. */
802     dc->physDev = physDev;
803     ret = dc->hSelf;
804
805     if (dc->funcs->pCreateDC &&
806         !dc->funcs->pCreateDC( dc->hSelf, &dc->physDev, NULL, NULL, NULL, NULL ))
807     {
808         WARN("creation aborted by device\n");
809         goto error;
810     }
811
812     DC_InitDC( dc );
813     release_dc_ptr( dc );
814     return ret;
815
816 error:
817     if (dc && dc->hVisRgn) DeleteObject( dc->hVisRgn );
818     if (dc) free_dc_ptr( dc );
819     DRIVER_release_driver( funcs );
820     return 0;
821 }
822
823
824 /***********************************************************************
825  *           DeleteDC    (GDI32.@)
826  */
827 BOOL WINAPI DeleteDC( HDC hdc )
828 {
829     const DC_FUNCTIONS *funcs = NULL;
830     DC * dc;
831
832     TRACE("%p\n", hdc );
833
834     GDI_CheckNotLock();
835
836     if (!(dc = get_dc_ptr( hdc ))) return FALSE;
837     if (dc->refcount != 1)
838     {
839         FIXME( "not deleting busy DC %p refcount %u\n", dc->hSelf, dc->refcount );
840         release_dc_ptr( dc );
841         return FALSE;
842     }
843
844     /* Call hook procedure to check whether is it OK to delete this DC */
845     if (dc->hookThunk && !dc->hookThunk( hdc, DCHC_DELETEDC, dc->dwHookData, 0 ))
846     {
847         release_dc_ptr( dc );
848         return FALSE;
849     }
850
851     while (dc->saveLevel)
852     {
853         DC * dcs;
854         HDC hdcs = dc->saved_dc;
855         if (!(dcs = get_dc_ptr( hdcs ))) break;
856         dc->saved_dc = dcs->saved_dc;
857         dc->saveLevel--;
858         if (dcs->hClipRgn) DeleteObject( dcs->hClipRgn );
859         if (dcs->hMetaRgn) DeleteObject( dcs->hMetaRgn );
860         if (dcs->hMetaClipRgn) DeleteObject( dcs->hMetaClipRgn );
861         if (dcs->hVisRgn) DeleteObject( dcs->hVisRgn );
862         PATH_DestroyGdiPath(&dcs->path);
863         free_dc_ptr( dcs );
864     }
865
866     if (!(dc->flags & DC_SAVED))
867     {
868         SelectObject( hdc, GetStockObject(BLACK_PEN) );
869         SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
870         SelectObject( hdc, GetStockObject(SYSTEM_FONT) );
871         SelectObject( hdc, GetStockObject(DEFAULT_BITMAP) );
872         funcs = dc->funcs;
873         if (dc->funcs->pDeleteDC) dc->funcs->pDeleteDC(dc->physDev);
874         dc->physDev = NULL;
875     }
876
877     while (dc->saved_visrgn)
878     {
879         struct saved_visrgn *next = dc->saved_visrgn->next;
880         DeleteObject( dc->saved_visrgn->hrgn );
881         HeapFree( GetProcessHeap(), 0, dc->saved_visrgn );
882         dc->saved_visrgn = next;
883     }
884     if (dc->hClipRgn) DeleteObject( dc->hClipRgn );
885     if (dc->hMetaRgn) DeleteObject( dc->hMetaRgn );
886     if (dc->hMetaClipRgn) DeleteObject( dc->hMetaClipRgn );
887     if (dc->hVisRgn) DeleteObject( dc->hVisRgn );
888     PATH_DestroyGdiPath(&dc->path);
889
890     free_dc_ptr( dc );
891     if (funcs) DRIVER_release_driver( funcs );  /* do that after releasing the GDI lock */
892     return TRUE;
893 }
894
895
896 /***********************************************************************
897  *           ResetDCW    (GDI32.@)
898  */
899 HDC WINAPI ResetDCW( HDC hdc, const DEVMODEW *devmode )
900 {
901     DC *dc;
902     HDC ret = hdc;
903
904     if ((dc = get_dc_ptr( hdc )))
905     {
906         if (dc->funcs->pResetDC) ret = dc->funcs->pResetDC( dc->physDev, devmode );
907         release_dc_ptr( dc );
908     }
909     return ret;
910 }
911
912
913 /***********************************************************************
914  *           ResetDCA    (GDI32.@)
915  */
916 HDC WINAPI ResetDCA( HDC hdc, const DEVMODEA *devmode )
917 {
918     DEVMODEW *devmodeW;
919     HDC ret;
920
921     if (devmode) devmodeW = GdiConvertToDevmodeW(devmode);
922     else devmodeW = NULL;
923
924     ret = ResetDCW(hdc, devmodeW);
925
926     HeapFree(GetProcessHeap(), 0, devmodeW);
927     return ret;
928 }
929
930
931 /***********************************************************************
932  *           GetDeviceCaps    (GDI32.@)
933  */
934 INT WINAPI GetDeviceCaps( HDC hdc, INT cap )
935 {
936     DC *dc;
937     INT ret = 0;
938
939     if ((dc = get_dc_ptr( hdc )))
940     {
941         if (dc->funcs->pGetDeviceCaps) ret = dc->funcs->pGetDeviceCaps( dc->physDev, cap );
942         else switch(cap)  /* return meaningful values for some entries */
943         {
944         case HORZRES:     ret = 640; break;
945         case VERTRES:     ret = 480; break;
946         case BITSPIXEL:   ret = 1; break;
947         case PLANES:      ret = 1; break;
948         case NUMCOLORS:   ret = 2; break;
949         case ASPECTX:     ret = 36; break;
950         case ASPECTY:     ret = 36; break;
951         case ASPECTXY:    ret = 51; break;
952         case LOGPIXELSX:  ret = 72; break;
953         case LOGPIXELSY:  ret = 72; break;
954         case SIZEPALETTE: ret = 2; break;
955         }
956         release_dc_ptr( dc );
957     }
958     return ret;
959 }
960
961
962 /***********************************************************************
963  *              GetBkColor (GDI32.@)
964  */
965 COLORREF WINAPI GetBkColor( HDC hdc )
966 {
967     COLORREF ret = 0;
968     DC * dc = get_dc_ptr( hdc );
969     if (dc)
970     {
971         ret = dc->backgroundColor;
972         release_dc_ptr( dc );
973     }
974     return ret;
975 }
976
977
978 /***********************************************************************
979  *           SetBkColor    (GDI32.@)
980  */
981 COLORREF WINAPI SetBkColor( HDC hdc, COLORREF color )
982 {
983     COLORREF oldColor;
984     DC * dc = get_dc_ptr( hdc );
985
986     TRACE("hdc=%p color=0x%08x\n", hdc, color);
987
988     if (!dc) return CLR_INVALID;
989     oldColor = dc->backgroundColor;
990     if (dc->funcs->pSetBkColor)
991     {
992         color = dc->funcs->pSetBkColor(dc->physDev, color);
993         if (color == CLR_INVALID)  /* don't change it */
994         {
995             color = oldColor;
996             oldColor = CLR_INVALID;
997         }
998     }
999     dc->backgroundColor = color;
1000     release_dc_ptr( dc );
1001     return oldColor;
1002 }
1003
1004
1005 /***********************************************************************
1006  *              GetTextColor (GDI32.@)
1007  */
1008 COLORREF WINAPI GetTextColor( HDC hdc )
1009 {
1010     COLORREF ret = 0;
1011     DC * dc = get_dc_ptr( hdc );
1012     if (dc)
1013     {
1014         ret = dc->textColor;
1015         release_dc_ptr( dc );
1016     }
1017     return ret;
1018 }
1019
1020
1021 /***********************************************************************
1022  *           SetTextColor    (GDI32.@)
1023  */
1024 COLORREF WINAPI SetTextColor( HDC hdc, COLORREF color )
1025 {
1026     COLORREF oldColor;
1027     DC * dc = get_dc_ptr( hdc );
1028
1029     TRACE(" hdc=%p color=0x%08x\n", hdc, color);
1030
1031     if (!dc) return CLR_INVALID;
1032     oldColor = dc->textColor;
1033     if (dc->funcs->pSetTextColor)
1034     {
1035         color = dc->funcs->pSetTextColor(dc->physDev, color);
1036         if (color == CLR_INVALID)  /* don't change it */
1037         {
1038             color = oldColor;
1039             oldColor = CLR_INVALID;
1040         }
1041     }
1042     dc->textColor = color;
1043     release_dc_ptr( dc );
1044     return oldColor;
1045 }
1046
1047
1048 /***********************************************************************
1049  *              GetTextAlign (GDI32.@)
1050  */
1051 UINT WINAPI GetTextAlign( HDC hdc )
1052 {
1053     UINT ret = 0;
1054     DC * dc = get_dc_ptr( hdc );
1055     if (dc)
1056     {
1057         ret = dc->textAlign;
1058         release_dc_ptr( dc );
1059     }
1060     return ret;
1061 }
1062
1063
1064 /***********************************************************************
1065  *           SetTextAlign    (GDI32.@)
1066  */
1067 UINT WINAPI SetTextAlign( HDC hdc, UINT align )
1068 {
1069     UINT ret;
1070     DC *dc = get_dc_ptr( hdc );
1071
1072     TRACE("hdc=%p align=%d\n", hdc, align);
1073
1074     if (!dc) return 0x0;
1075     ret = dc->textAlign;
1076     if (dc->funcs->pSetTextAlign)
1077         if (!dc->funcs->pSetTextAlign(dc->physDev, align))
1078             ret = GDI_ERROR;
1079     if (ret != GDI_ERROR)
1080         dc->textAlign = align;
1081     release_dc_ptr( dc );
1082     return ret;
1083 }
1084
1085 /***********************************************************************
1086  *           GetDCOrgEx  (GDI32.@)
1087  */
1088 BOOL WINAPI GetDCOrgEx( HDC hDC, LPPOINT lpp )
1089 {
1090     DC * dc;
1091
1092     if (!lpp) return FALSE;
1093     if (!(dc = get_dc_ptr( hDC ))) return FALSE;
1094
1095     lpp->x = lpp->y = 0;
1096     if (dc->funcs->pGetDCOrgEx) dc->funcs->pGetDCOrgEx( dc->physDev, lpp );
1097     release_dc_ptr( dc );
1098     return TRUE;
1099 }
1100
1101
1102 /***********************************************************************
1103  *           SetDCOrg   (GDI.117)
1104  */
1105 DWORD WINAPI SetDCOrg16( HDC16 hdc16, INT16 x, INT16 y )
1106 {
1107     DWORD prevOrg = 0;
1108     HDC hdc = HDC_32( hdc16 );
1109     DC *dc = get_dc_ptr( hdc );
1110     if (!dc) return 0;
1111     if (dc->funcs->pSetDCOrg) prevOrg = dc->funcs->pSetDCOrg( dc->physDev, x, y );
1112     release_dc_ptr( dc );
1113     return prevOrg;
1114 }
1115
1116
1117 /***********************************************************************
1118  *              GetGraphicsMode (GDI32.@)
1119  */
1120 INT WINAPI GetGraphicsMode( HDC hdc )
1121 {
1122     INT ret = 0;
1123     DC * dc = get_dc_ptr( hdc );
1124     if (dc)
1125     {
1126         ret = dc->GraphicsMode;
1127         release_dc_ptr( dc );
1128     }
1129     return ret;
1130 }
1131
1132
1133 /***********************************************************************
1134  *           SetGraphicsMode    (GDI32.@)
1135  */
1136 INT WINAPI SetGraphicsMode( HDC hdc, INT mode )
1137 {
1138     INT ret = 0;
1139     DC *dc = get_dc_ptr( hdc );
1140
1141     /* One would think that setting the graphics mode to GM_COMPATIBLE
1142      * would also reset the world transformation matrix to the unity
1143      * matrix. However, in Windows, this is not the case. This doesn't
1144      * make a lot of sense to me, but that's the way it is.
1145      */
1146     if (!dc) return 0;
1147     if ((mode > 0) && (mode <= GM_LAST))
1148     {
1149         ret = dc->GraphicsMode;
1150         dc->GraphicsMode = mode;
1151     }
1152     release_dc_ptr( dc );
1153     return ret;
1154 }
1155
1156
1157 /***********************************************************************
1158  *              GetArcDirection (GDI32.@)
1159  */
1160 INT WINAPI GetArcDirection( HDC hdc )
1161 {
1162     INT ret = 0;
1163     DC * dc = get_dc_ptr( hdc );
1164     if (dc)
1165     {
1166         ret = dc->ArcDirection;
1167         release_dc_ptr( dc );
1168     }
1169     return ret;
1170 }
1171
1172
1173 /***********************************************************************
1174  *           SetArcDirection    (GDI32.@)
1175  */
1176 INT WINAPI SetArcDirection( HDC hdc, INT nDirection )
1177 {
1178     DC * dc;
1179     INT nOldDirection = 0;
1180
1181     if (nDirection!=AD_COUNTERCLOCKWISE && nDirection!=AD_CLOCKWISE)
1182     {
1183         SetLastError(ERROR_INVALID_PARAMETER);
1184         return 0;
1185     }
1186
1187     if ((dc = get_dc_ptr( hdc )))
1188     {
1189         if (dc->funcs->pSetArcDirection)
1190         {
1191             dc->funcs->pSetArcDirection(dc->physDev, nDirection);
1192         }
1193         nOldDirection = dc->ArcDirection;
1194         dc->ArcDirection = nDirection;
1195         release_dc_ptr( dc );
1196     }
1197     return nOldDirection;
1198 }
1199
1200
1201 /***********************************************************************
1202  *           GetWorldTransform    (GDI32.@)
1203  */
1204 BOOL WINAPI GetWorldTransform( HDC hdc, LPXFORM xform )
1205 {
1206     DC * dc;
1207     if (!xform) return FALSE;
1208     if (!(dc = get_dc_ptr( hdc ))) return FALSE;
1209     *xform = dc->xformWorld2Wnd;
1210     release_dc_ptr( dc );
1211     return TRUE;
1212 }
1213
1214
1215 /***********************************************************************
1216  *           GetTransform    (GDI32.@)
1217  */
1218 BOOL WINAPI GetTransform( HDC hdc, DWORD unknown, LPXFORM xform )
1219 {
1220     if (unknown == 0x0203) return GetWorldTransform( hdc, xform );
1221     FIXME("stub: don't know what to do for code %x\n", unknown );
1222     return FALSE;
1223 }
1224
1225
1226 /***********************************************************************
1227  *           SetWorldTransform    (GDI32.@)
1228  */
1229 BOOL WINAPI SetWorldTransform( HDC hdc, const XFORM *xform )
1230 {
1231     BOOL ret = FALSE;
1232     DC *dc = get_dc_ptr( hdc );
1233
1234     if (!dc) return FALSE;
1235     if (!xform) goto done;
1236
1237     /* Check that graphics mode is GM_ADVANCED */
1238     if (dc->GraphicsMode!=GM_ADVANCED) goto done;
1239
1240     if (dc->funcs->pSetWorldTransform)
1241     {
1242         ret = dc->funcs->pSetWorldTransform(dc->physDev, xform);
1243         if (!ret) goto done;
1244     }
1245
1246     dc->xformWorld2Wnd = *xform;
1247     DC_UpdateXforms( dc );
1248     ret = TRUE;
1249  done:
1250     release_dc_ptr( dc );
1251     return ret;
1252 }
1253
1254
1255 /****************************************************************************
1256  * ModifyWorldTransform [GDI32.@]
1257  * Modifies the world transformation for a device context.
1258  *
1259  * PARAMS
1260  *    hdc   [I] Handle to device context
1261  *    xform [I] XFORM structure that will be used to modify the world
1262  *              transformation
1263  *    iMode [I] Specifies in what way to modify the world transformation
1264  *              Possible values:
1265  *              MWT_IDENTITY
1266  *                 Resets the world transformation to the identity matrix.
1267  *                 The parameter xform is ignored.
1268  *              MWT_LEFTMULTIPLY
1269  *                 Multiplies xform into the world transformation matrix from
1270  *                 the left.
1271  *              MWT_RIGHTMULTIPLY
1272  *                 Multiplies xform into the world transformation matrix from
1273  *                 the right.
1274  *
1275  * RETURNS
1276  *  Success: TRUE.
1277  *  Failure: FALSE. Use GetLastError() to determine the cause.
1278  */
1279 BOOL WINAPI ModifyWorldTransform( HDC hdc, const XFORM *xform,
1280     DWORD iMode )
1281 {
1282     BOOL ret = FALSE;
1283     DC *dc = get_dc_ptr( hdc );
1284
1285     /* Check for illegal parameters */
1286     if (!dc) return FALSE;
1287     if (!xform && iMode != MWT_IDENTITY) goto done;
1288
1289     /* Check that graphics mode is GM_ADVANCED */
1290     if (dc->GraphicsMode!=GM_ADVANCED) goto done;
1291
1292     if (dc->funcs->pModifyWorldTransform)
1293     {
1294         ret = dc->funcs->pModifyWorldTransform(dc->physDev, xform, iMode);
1295         if (!ret) goto done;
1296     }
1297
1298     switch (iMode)
1299     {
1300         case MWT_IDENTITY:
1301             dc->xformWorld2Wnd.eM11 = 1.0f;
1302             dc->xformWorld2Wnd.eM12 = 0.0f;
1303             dc->xformWorld2Wnd.eM21 = 0.0f;
1304             dc->xformWorld2Wnd.eM22 = 1.0f;
1305             dc->xformWorld2Wnd.eDx  = 0.0f;
1306             dc->xformWorld2Wnd.eDy  = 0.0f;
1307             break;
1308         case MWT_LEFTMULTIPLY:
1309             CombineTransform( &dc->xformWorld2Wnd, xform,
1310                 &dc->xformWorld2Wnd );
1311             break;
1312         case MWT_RIGHTMULTIPLY:
1313             CombineTransform( &dc->xformWorld2Wnd, &dc->xformWorld2Wnd,
1314                 xform );
1315             break;
1316         default:
1317             goto done;
1318     }
1319
1320     DC_UpdateXforms( dc );
1321     ret = TRUE;
1322  done:
1323     release_dc_ptr( dc );
1324     return ret;
1325 }
1326
1327
1328 /****************************************************************************
1329  * CombineTransform [GDI32.@]
1330  * Combines two transformation matrices.
1331  *
1332  * PARAMS
1333  *    xformResult [O] Stores the result of combining the two matrices
1334  *    xform1      [I] Specifies the first matrix to apply
1335  *    xform2      [I] Specifies the second matrix to apply
1336  *
1337  * REMARKS
1338  *    The same matrix can be passed in for more than one of the parameters.
1339  *
1340  * RETURNS
1341  *  Success: TRUE.
1342  *  Failure: FALSE. Use GetLastError() to determine the cause.
1343  */
1344 BOOL WINAPI CombineTransform( LPXFORM xformResult, const XFORM *xform1,
1345     const XFORM *xform2 )
1346 {
1347     XFORM xformTemp;
1348
1349     /* Check for illegal parameters */
1350     if (!xformResult || !xform1 || !xform2)
1351         return FALSE;
1352
1353     /* Create the result in a temporary XFORM, since xformResult may be
1354      * equal to xform1 or xform2 */
1355     xformTemp.eM11 = xform1->eM11 * xform2->eM11 +
1356                      xform1->eM12 * xform2->eM21;
1357     xformTemp.eM12 = xform1->eM11 * xform2->eM12 +
1358                      xform1->eM12 * xform2->eM22;
1359     xformTemp.eM21 = xform1->eM21 * xform2->eM11 +
1360                      xform1->eM22 * xform2->eM21;
1361     xformTemp.eM22 = xform1->eM21 * xform2->eM12 +
1362                      xform1->eM22 * xform2->eM22;
1363     xformTemp.eDx  = xform1->eDx  * xform2->eM11 +
1364                      xform1->eDy  * xform2->eM21 +
1365                      xform2->eDx;
1366     xformTemp.eDy  = xform1->eDx  * xform2->eM12 +
1367                      xform1->eDy  * xform2->eM22 +
1368                      xform2->eDy;
1369
1370     /* Copy the result to xformResult */
1371     *xformResult = xformTemp;
1372
1373     return TRUE;
1374 }
1375
1376
1377 /***********************************************************************
1378  *           SetDCHook   (GDI32.@)
1379  *
1380  * Note: this doesn't exist in Win32, we add it here because user32 needs it.
1381  */
1382 BOOL WINAPI SetDCHook( HDC hdc, DCHOOKPROC hookProc, DWORD_PTR dwHookData )
1383 {
1384     DC *dc = get_dc_ptr( hdc );
1385
1386     if (!dc) return FALSE;
1387
1388     if (!(dc->flags & DC_SAVED))
1389     {
1390         dc->dwHookData = dwHookData;
1391         dc->hookThunk = hookProc;
1392     }
1393     release_dc_ptr( dc );
1394     return TRUE;
1395 }
1396
1397
1398 /***********************************************************************
1399  *           GetDCHook   (GDI32.@)
1400  *
1401  * Note: this doesn't exist in Win32, we add it here because user32 needs it.
1402  */
1403 DWORD_PTR WINAPI GetDCHook( HDC hdc, DCHOOKPROC *proc )
1404 {
1405     DC *dc = get_dc_ptr( hdc );
1406     DWORD_PTR ret;
1407
1408     if (!dc) return 0;
1409     if (proc) *proc = dc->hookThunk;
1410     ret = dc->dwHookData;
1411     release_dc_ptr( dc );
1412     return ret;
1413 }
1414
1415
1416 /* relay function to call the 16-bit DC hook proc */
1417 static BOOL WINAPI call_dc_hook16( HDC hdc, WORD code, DWORD_PTR data, LPARAM lParam )
1418 {
1419     WORD args[6];
1420     DWORD ret = 0;
1421     DC *dc = get_dc_ptr( hdc );
1422
1423     if (!dc) return FALSE;
1424     if (dc->hookProc)
1425     {
1426         args[5] = HDC_16(hdc);
1427         args[4] = code;
1428         args[3] = HIWORD(data);
1429         args[2] = LOWORD(data);
1430         args[1] = HIWORD(lParam);
1431         args[0] = LOWORD(lParam);
1432         WOWCallback16Ex( (DWORD)dc->hookProc, WCB16_PASCAL, sizeof(args), args, &ret );
1433     }
1434     release_dc_ptr( dc );
1435     return LOWORD(ret);
1436 }
1437
1438 /***********************************************************************
1439  *           SetDCHook   (GDI.190)
1440  */
1441 BOOL16 WINAPI SetDCHook16( HDC16 hdc16, FARPROC16 hookProc, DWORD dwHookData )
1442 {
1443     DC *dc = get_dc_ptr( HDC_32(hdc16) );
1444
1445     if (!dc) return FALSE;
1446     if (!(dc->flags & DC_SAVED))
1447     {
1448         dc->dwHookData = dwHookData;
1449         dc->hookThunk = call_dc_hook16;
1450         dc->hookProc = hookProc;
1451     }
1452     release_dc_ptr( dc );
1453     return TRUE;
1454 }
1455
1456
1457 /***********************************************************************
1458  *           GetDCHook   (GDI.191)
1459  */
1460 DWORD WINAPI GetDCHook16( HDC16 hdc16, FARPROC16 *phookProc )
1461 {
1462     HDC hdc = HDC_32( hdc16 );
1463     DC *dc = get_dc_ptr( hdc );
1464     DWORD ret;
1465
1466     if (!dc) return 0;
1467     *phookProc = dc->hookProc;
1468     ret = dc->dwHookData;
1469     release_dc_ptr( dc );
1470     return ret;
1471 }
1472
1473
1474 /***********************************************************************
1475  *           SetHookFlags   (GDI32.@)
1476  *
1477  * Note: this doesn't exist in Win32, we add it here because user32 needs it.
1478  */
1479 WORD WINAPI SetHookFlags( HDC hdc, WORD flags )
1480 {
1481     DC *dc = get_dc_obj( hdc );  /* not get_dc_ptr, this needs to work from any thread */
1482     LONG ret = 0;
1483
1484     if (!dc) return 0;
1485
1486     /* "Undocumented Windows" info is slightly confusing. */
1487
1488     TRACE("hDC %p, flags %04x\n",hdc,flags);
1489
1490     if (flags & DCHF_INVALIDATEVISRGN)
1491         ret = InterlockedExchange( &dc->dirty, 1 );
1492     else if (flags & DCHF_VALIDATEVISRGN || !flags)
1493         ret = InterlockedExchange( &dc->dirty, 0 );
1494
1495     GDI_ReleaseObj( dc );
1496     return ret;
1497 }
1498
1499 /***********************************************************************
1500  *           SetICMMode    (GDI32.@)
1501  */
1502 INT WINAPI SetICMMode(HDC hdc, INT iEnableICM)
1503 {
1504 /*FIXME:  Assume that ICM is always off, and cannot be turned on */
1505     if (iEnableICM == ICM_OFF) return ICM_OFF;
1506     if (iEnableICM == ICM_ON) return 0;
1507     if (iEnableICM == ICM_QUERY) return ICM_OFF;
1508     return 0;
1509 }
1510
1511 /***********************************************************************
1512  *           GetDeviceGammaRamp    (GDI32.@)
1513  */
1514 BOOL WINAPI GetDeviceGammaRamp(HDC hDC, LPVOID ptr)
1515 {
1516     BOOL ret = FALSE;
1517     DC *dc = get_dc_ptr( hDC );
1518
1519     if( dc )
1520     {
1521         if (dc->funcs->pGetDeviceGammaRamp)
1522             ret = dc->funcs->pGetDeviceGammaRamp(dc->physDev, ptr);
1523         release_dc_ptr( dc );
1524     }
1525     return ret;
1526 }
1527
1528 /***********************************************************************
1529  *           SetDeviceGammaRamp    (GDI32.@)
1530  */
1531 BOOL WINAPI SetDeviceGammaRamp(HDC hDC, LPVOID ptr)
1532 {
1533     BOOL ret = FALSE;
1534     DC *dc = get_dc_ptr( hDC );
1535
1536     if( dc )
1537     {
1538         if (dc->funcs->pSetDeviceGammaRamp)
1539             ret = dc->funcs->pSetDeviceGammaRamp(dc->physDev, ptr);
1540         release_dc_ptr( dc );
1541     }
1542     return ret;
1543 }
1544
1545 /***********************************************************************
1546  *           GetColorSpace    (GDI32.@)
1547  */
1548 HCOLORSPACE WINAPI GetColorSpace(HDC hdc)
1549 {
1550 /*FIXME    Need to to whatever GetColorSpace actually does */
1551     return 0;
1552 }
1553
1554 /***********************************************************************
1555  *           CreateColorSpaceA    (GDI32.@)
1556  */
1557 HCOLORSPACE WINAPI CreateColorSpaceA( LPLOGCOLORSPACEA lpLogColorSpace )
1558 {
1559   FIXME( "stub\n" );
1560   return 0;
1561 }
1562
1563 /***********************************************************************
1564  *           CreateColorSpaceW    (GDI32.@)
1565  */
1566 HCOLORSPACE WINAPI CreateColorSpaceW( LPLOGCOLORSPACEW lpLogColorSpace )
1567 {
1568   FIXME( "stub\n" );
1569   return 0;
1570 }
1571
1572 /***********************************************************************
1573  *           DeleteColorSpace     (GDI32.@)
1574  */
1575 BOOL WINAPI DeleteColorSpace( HCOLORSPACE hColorSpace )
1576 {
1577   FIXME( "stub\n" );
1578
1579   return TRUE;
1580 }
1581
1582 /***********************************************************************
1583  *           SetColorSpace     (GDI32.@)
1584  */
1585 HCOLORSPACE WINAPI SetColorSpace( HDC hDC, HCOLORSPACE hColorSpace )
1586 {
1587   FIXME( "stub\n" );
1588
1589   return hColorSpace;
1590 }
1591
1592 /***********************************************************************
1593  *           GetBoundsRect    (GDI32.@)
1594  */
1595 UINT WINAPI GetBoundsRect(HDC hdc, LPRECT rect, UINT flags)
1596 {
1597     UINT ret;
1598     DC *dc = get_dc_ptr( hdc );
1599
1600     if ( !dc ) return 0;
1601
1602     if (rect) *rect = dc->BoundsRect;
1603
1604     ret = ((dc->flags & DC_BOUNDS_SET) ? DCB_SET : DCB_RESET);
1605
1606     if (flags & DCB_RESET)
1607     {
1608         dc->BoundsRect.left   = 0;
1609         dc->BoundsRect.top    = 0;
1610         dc->BoundsRect.right  = 0;
1611         dc->BoundsRect.bottom = 0;
1612         dc->flags &= ~DC_BOUNDS_SET;
1613     }
1614     release_dc_ptr( dc );
1615     return ret;
1616 }
1617
1618
1619 /***********************************************************************
1620  *           SetBoundsRect    (GDI32.@)
1621  */
1622 UINT WINAPI SetBoundsRect(HDC hdc, const RECT* rect, UINT flags)
1623 {
1624     UINT ret;
1625     DC *dc;
1626
1627     if ((flags & DCB_ENABLE) && (flags & DCB_DISABLE)) return 0;
1628     if (!(dc = get_dc_ptr( hdc ))) return 0;
1629
1630     ret = ((dc->flags & DC_BOUNDS_ENABLE) ? DCB_ENABLE : DCB_DISABLE) |
1631           ((dc->flags & DC_BOUNDS_SET) ? DCB_SET : DCB_RESET);
1632
1633     if (flags & DCB_RESET)
1634     {
1635         dc->BoundsRect.left   = 0;
1636         dc->BoundsRect.top    = 0;
1637         dc->BoundsRect.right  = 0;
1638         dc->BoundsRect.bottom = 0;
1639         dc->flags &= ~DC_BOUNDS_SET;
1640     }
1641
1642     if ((flags & DCB_ACCUMULATE) && rect && rect->left < rect->right && rect->top < rect->bottom)
1643     {
1644         if (dc->flags & DC_BOUNDS_SET)
1645         {
1646             dc->BoundsRect.left   = min( dc->BoundsRect.left, rect->left );
1647             dc->BoundsRect.top    = min( dc->BoundsRect.top, rect->top );
1648             dc->BoundsRect.right  = max( dc->BoundsRect.right, rect->right );
1649             dc->BoundsRect.bottom = max( dc->BoundsRect.bottom, rect->bottom );
1650         }
1651         else
1652         {
1653             dc->BoundsRect = *rect;
1654             dc->flags |= DC_BOUNDS_SET;
1655         }
1656     }
1657
1658     if (flags & DCB_ENABLE) dc->flags |= DC_BOUNDS_ENABLE;
1659     if (flags & DCB_DISABLE) dc->flags &= ~DC_BOUNDS_ENABLE;
1660
1661     release_dc_ptr( dc );
1662     return ret;
1663 }
1664
1665
1666 /***********************************************************************
1667  *              GetRelAbs               (GDI32.@)
1668  */
1669 INT WINAPI GetRelAbs( HDC hdc, DWORD dwIgnore )
1670 {
1671     INT ret = 0;
1672     DC *dc = get_dc_ptr( hdc );
1673     if (dc)
1674     {
1675         ret = dc->relAbsMode;
1676         release_dc_ptr( dc );
1677     }
1678     return ret;
1679 }
1680
1681
1682
1683
1684 /***********************************************************************
1685  *              GetBkMode (GDI32.@)
1686  */
1687 INT WINAPI GetBkMode( HDC hdc )
1688 {
1689     INT ret = 0;
1690     DC * dc = get_dc_ptr( hdc );
1691     if (dc)
1692     {
1693         ret = dc->backgroundMode;
1694         release_dc_ptr( dc );
1695     }
1696     return ret;
1697 }
1698
1699
1700 /***********************************************************************
1701  *              SetBkMode (GDI32.@)
1702  */
1703 INT WINAPI SetBkMode( HDC hdc, INT mode )
1704 {
1705     INT ret;
1706     DC *dc;
1707     if ((mode <= 0) || (mode > BKMODE_LAST))
1708     {
1709         SetLastError(ERROR_INVALID_PARAMETER);
1710         return 0;
1711     }
1712     if (!(dc = get_dc_ptr( hdc ))) return 0;
1713
1714     ret = dc->backgroundMode;
1715     if (dc->funcs->pSetBkMode)
1716         if (!dc->funcs->pSetBkMode( dc->physDev, mode ))
1717             ret = 0;
1718     if (ret)
1719         dc->backgroundMode = mode;
1720     release_dc_ptr( dc );
1721     return ret;
1722 }
1723
1724
1725 /***********************************************************************
1726  *              GetROP2 (GDI32.@)
1727  */
1728 INT WINAPI GetROP2( HDC hdc )
1729 {
1730     INT ret = 0;
1731     DC * dc = get_dc_ptr( hdc );
1732     if (dc)
1733     {
1734         ret = dc->ROPmode;
1735         release_dc_ptr( dc );
1736     }
1737     return ret;
1738 }
1739
1740
1741 /***********************************************************************
1742  *              SetROP2 (GDI32.@)
1743  */
1744 INT WINAPI SetROP2( HDC hdc, INT mode )
1745 {
1746     INT ret;
1747     DC *dc;
1748     if ((mode < R2_BLACK) || (mode > R2_WHITE))
1749     {
1750         SetLastError(ERROR_INVALID_PARAMETER);
1751         return 0;
1752     }
1753     if (!(dc = get_dc_ptr( hdc ))) return 0;
1754     ret = dc->ROPmode;
1755     if (dc->funcs->pSetROP2)
1756         if (!dc->funcs->pSetROP2( dc->physDev, mode ))
1757             ret = 0;
1758     if (ret)
1759         dc->ROPmode = mode;
1760     release_dc_ptr( dc );
1761     return ret;
1762 }
1763
1764
1765 /***********************************************************************
1766  *              SetRelAbs (GDI32.@)
1767  */
1768 INT WINAPI SetRelAbs( HDC hdc, INT mode )
1769 {
1770     INT ret;
1771     DC *dc;
1772     if ((mode != ABSOLUTE) && (mode != RELATIVE))
1773     {
1774         SetLastError(ERROR_INVALID_PARAMETER);
1775         return 0;
1776     }
1777     if (!(dc = get_dc_ptr( hdc ))) return 0;
1778     if (dc->funcs->pSetRelAbs)
1779         ret = dc->funcs->pSetRelAbs( dc->physDev, mode );
1780     else
1781     {
1782         ret = dc->relAbsMode;
1783         dc->relAbsMode = mode;
1784     }
1785     release_dc_ptr( dc );
1786     return ret;
1787 }
1788
1789
1790 /***********************************************************************
1791  *              GetPolyFillMode (GDI32.@)
1792  */
1793 INT WINAPI GetPolyFillMode( HDC hdc )
1794 {
1795     INT ret = 0;
1796     DC * dc = get_dc_ptr( hdc );
1797     if (dc)
1798     {
1799         ret = dc->polyFillMode;
1800         release_dc_ptr( dc );
1801     }
1802     return ret;
1803 }
1804
1805
1806 /***********************************************************************
1807  *              SetPolyFillMode (GDI32.@)
1808  */
1809 INT WINAPI SetPolyFillMode( HDC hdc, INT mode )
1810 {
1811     INT ret;
1812     DC *dc;
1813     if ((mode <= 0) || (mode > POLYFILL_LAST))
1814     {
1815         SetLastError(ERROR_INVALID_PARAMETER);
1816         return 0;
1817     }
1818     if (!(dc = get_dc_ptr( hdc ))) return 0;
1819     ret = dc->polyFillMode;
1820     if (dc->funcs->pSetPolyFillMode)
1821         if (!dc->funcs->pSetPolyFillMode( dc->physDev, mode ))
1822             ret = 0;
1823     if (ret)
1824         dc->polyFillMode = mode;
1825     release_dc_ptr( dc );
1826     return ret;
1827 }
1828
1829
1830 /***********************************************************************
1831  *              GetStretchBltMode (GDI32.@)
1832  */
1833 INT WINAPI GetStretchBltMode( HDC hdc )
1834 {
1835     INT ret = 0;
1836     DC * dc = get_dc_ptr( hdc );
1837     if (dc)
1838     {
1839         ret = dc->stretchBltMode;
1840         release_dc_ptr( dc );
1841     }
1842     return ret;
1843 }
1844
1845
1846 /***********************************************************************
1847  *              SetStretchBltMode (GDI32.@)
1848  */
1849 INT WINAPI SetStretchBltMode( HDC hdc, INT mode )
1850 {
1851     INT ret;
1852     DC *dc;
1853     if ((mode <= 0) || (mode > MAXSTRETCHBLTMODE))
1854     {
1855         SetLastError(ERROR_INVALID_PARAMETER);
1856         return 0;
1857     }
1858     if (!(dc = get_dc_ptr( hdc ))) return 0;
1859     ret = dc->stretchBltMode;
1860     if (dc->funcs->pSetStretchBltMode)
1861         if (!dc->funcs->pSetStretchBltMode( dc->physDev, mode ))
1862             ret = 0;
1863     if (ret)
1864         dc->stretchBltMode = mode;
1865     release_dc_ptr( dc );
1866     return ret;
1867 }
1868
1869
1870 /***********************************************************************
1871  *              GetMapMode (GDI32.@)
1872  */
1873 INT WINAPI GetMapMode( HDC hdc )
1874 {
1875     INT ret = 0;
1876     DC * dc = get_dc_ptr( hdc );
1877     if (dc)
1878     {
1879         ret = dc->MapMode;
1880         release_dc_ptr( dc );
1881     }
1882     return ret;
1883 }
1884
1885
1886 /***********************************************************************
1887  *              GetBrushOrgEx (GDI32.@)
1888  */
1889 BOOL WINAPI GetBrushOrgEx( HDC hdc, LPPOINT pt )
1890 {
1891     DC * dc = get_dc_ptr( hdc );
1892     if (!dc) return FALSE;
1893     pt->x = dc->brushOrgX;
1894     pt->y = dc->brushOrgY;
1895     release_dc_ptr( dc );
1896     return TRUE;
1897 }
1898
1899
1900 /***********************************************************************
1901  *              GetCurrentPositionEx (GDI32.@)
1902  */
1903 BOOL WINAPI GetCurrentPositionEx( HDC hdc, LPPOINT pt )
1904 {
1905     DC * dc = get_dc_ptr( hdc );
1906     if (!dc) return FALSE;
1907     pt->x = dc->CursPosX;
1908     pt->y = dc->CursPosY;
1909     release_dc_ptr( dc );
1910     return TRUE;
1911 }
1912
1913
1914 /***********************************************************************
1915  *              GetViewportExtEx (GDI32.@)
1916  */
1917 BOOL WINAPI GetViewportExtEx( HDC hdc, LPSIZE size )
1918 {
1919     DC * dc = get_dc_ptr( hdc );
1920     if (!dc) return FALSE;
1921     size->cx = dc->vportExtX;
1922     size->cy = dc->vportExtY;
1923     release_dc_ptr( dc );
1924     return TRUE;
1925 }
1926
1927
1928 /***********************************************************************
1929  *              GetViewportOrgEx (GDI32.@)
1930  */
1931 BOOL WINAPI GetViewportOrgEx( HDC hdc, LPPOINT pt )
1932 {
1933     DC * dc = get_dc_ptr( hdc );
1934     if (!dc) return FALSE;
1935     pt->x = dc->vportOrgX;
1936     pt->y = dc->vportOrgY;
1937     release_dc_ptr( dc );
1938     return TRUE;
1939 }
1940
1941
1942 /***********************************************************************
1943  *              GetWindowExtEx (GDI32.@)
1944  */
1945 BOOL WINAPI GetWindowExtEx( HDC hdc, LPSIZE size )
1946 {
1947     DC * dc = get_dc_ptr( hdc );
1948     if (!dc) return FALSE;
1949     size->cx = dc->wndExtX;
1950     size->cy = dc->wndExtY;
1951     release_dc_ptr( dc );
1952     return TRUE;
1953 }
1954
1955
1956 /***********************************************************************
1957  *              GetWindowOrgEx (GDI32.@)
1958  */
1959 BOOL WINAPI GetWindowOrgEx( HDC hdc, LPPOINT pt )
1960 {
1961     DC * dc = get_dc_ptr( hdc );
1962     if (!dc) return FALSE;
1963     pt->x = dc->wndOrgX;
1964     pt->y = dc->wndOrgY;
1965     release_dc_ptr( dc );
1966     return TRUE;
1967 }
1968
1969
1970 /***********************************************************************
1971  *              InquireVisRgn   (GDI.131)
1972  */
1973 HRGN16 WINAPI InquireVisRgn16( HDC16 hdc )
1974 {
1975     HRGN16 ret = 0;
1976     DC * dc = get_dc_ptr( HDC_32(hdc) );
1977     if (dc)
1978     {
1979         ret = HRGN_16(dc->hVisRgn);
1980         release_dc_ptr( dc );
1981     }
1982     return ret;
1983 }
1984
1985
1986 /***********************************************************************
1987  *              GetClipRgn (GDI.173)
1988  */
1989 HRGN16 WINAPI GetClipRgn16( HDC16 hdc )
1990 {
1991     HRGN16 ret = 0;
1992     DC * dc = get_dc_ptr( HDC_32(hdc) );
1993     if (dc)
1994     {
1995         ret = HRGN_16(dc->hClipRgn);
1996         release_dc_ptr( dc );
1997     }
1998     return ret;
1999 }
2000
2001
2002 /***********************************************************************
2003  *           GetLayout    (GDI32.@)
2004  *
2005  * Gets left->right or right->left text layout flags of a dc.
2006  *
2007  */
2008 DWORD WINAPI GetLayout(HDC hdc)
2009 {
2010     DWORD layout = GDI_ERROR;
2011
2012     DC * dc = get_dc_ptr( hdc );
2013     if (dc)
2014     {
2015         layout = dc->layout;
2016         release_dc_ptr( dc );
2017     }
2018
2019     TRACE("hdc : %p, layout : %08x\n", hdc, layout);
2020
2021     return layout;
2022 }
2023
2024 /***********************************************************************
2025  *           SetLayout    (GDI32.@)
2026  *
2027  * Sets left->right or right->left text layout flags of a dc.
2028  *
2029  */
2030 DWORD WINAPI SetLayout(HDC hdc, DWORD layout)
2031 {
2032     DWORD oldlayout = GDI_ERROR;
2033
2034     DC * dc = get_dc_ptr( hdc );
2035     if (dc)
2036     {
2037         oldlayout = dc->layout;
2038         dc->layout = layout;
2039         release_dc_ptr( dc );
2040     }
2041
2042     TRACE("hdc : %p, old layout : %08x, new layout : %08x\n", hdc, oldlayout, layout);
2043
2044     return oldlayout;
2045 }
2046
2047 /***********************************************************************
2048  *           GetDCBrushColor    (GDI32.@)
2049  *
2050  * Retrieves the current brush color for the specified device
2051  * context (DC).
2052  *
2053  */
2054 COLORREF WINAPI GetDCBrushColor(HDC hdc)
2055 {
2056     DC *dc;
2057     COLORREF dcBrushColor = CLR_INVALID;
2058
2059     TRACE("hdc(%p)\n", hdc);
2060
2061     dc = get_dc_ptr( hdc );
2062     if (dc)
2063     {
2064         dcBrushColor = dc->dcBrushColor;
2065         release_dc_ptr( dc );
2066     }
2067
2068     return dcBrushColor;
2069 }
2070
2071 /***********************************************************************
2072  *           SetDCBrushColor    (GDI32.@)
2073  *
2074  * Sets the current device context (DC) brush color to the specified
2075  * color value. If the device cannot represent the specified color
2076  * value, the color is set to the nearest physical color.
2077  *
2078  */
2079 COLORREF WINAPI SetDCBrushColor(HDC hdc, COLORREF crColor)
2080 {
2081     DC *dc;
2082     COLORREF oldClr = CLR_INVALID;
2083
2084     TRACE("hdc(%p) crColor(%08x)\n", hdc, crColor);
2085
2086     dc = get_dc_ptr( hdc );
2087     if (dc)
2088     {
2089         if (dc->funcs->pSetDCBrushColor)
2090             crColor = dc->funcs->pSetDCBrushColor( dc->physDev, crColor );
2091         else if (dc->hBrush == GetStockObject( DC_BRUSH ))
2092         {
2093             /* If DC_BRUSH is selected, update driver pen color */
2094             HBRUSH hBrush = CreateSolidBrush( crColor );
2095             dc->funcs->pSelectBrush( dc->physDev, hBrush );
2096             DeleteObject( hBrush );
2097         }
2098
2099         if (crColor != CLR_INVALID)
2100         {
2101             oldClr = dc->dcBrushColor;
2102             dc->dcBrushColor = crColor;
2103         }
2104
2105         release_dc_ptr( dc );
2106     }
2107
2108     return oldClr;
2109 }
2110
2111 /***********************************************************************
2112  *           GetDCPenColor    (GDI32.@)
2113  *
2114  * Retrieves the current pen color for the specified device
2115  * context (DC).
2116  *
2117  */
2118 COLORREF WINAPI GetDCPenColor(HDC hdc)
2119 {
2120     DC *dc;
2121     COLORREF dcPenColor = CLR_INVALID;
2122
2123     TRACE("hdc(%p)\n", hdc);
2124
2125     dc = get_dc_ptr( hdc );
2126     if (dc)
2127     {
2128         dcPenColor = dc->dcPenColor;
2129         release_dc_ptr( dc );
2130     }
2131
2132     return dcPenColor;
2133 }
2134
2135 /***********************************************************************
2136  *           SetDCPenColor    (GDI32.@)
2137  *
2138  * Sets the current device context (DC) pen color to the specified
2139  * color value. If the device cannot represent the specified color
2140  * value, the color is set to the nearest physical color.
2141  *
2142  */
2143 COLORREF WINAPI SetDCPenColor(HDC hdc, COLORREF crColor)
2144 {
2145     DC *dc;
2146     COLORREF oldClr = CLR_INVALID;
2147
2148     TRACE("hdc(%p) crColor(%08x)\n", hdc, crColor);
2149
2150     dc = get_dc_ptr( hdc );
2151     if (dc)
2152     {
2153         if (dc->funcs->pSetDCPenColor)
2154             crColor = dc->funcs->pSetDCPenColor( dc->physDev, crColor );
2155         else if (dc->hPen == GetStockObject( DC_PEN ))
2156         {
2157             /* If DC_PEN is selected, update the driver pen color */
2158             LOGPEN logpen = { PS_SOLID, { 0, 0 }, crColor };
2159             HPEN hPen = CreatePenIndirect( &logpen );
2160             dc->funcs->pSelectPen( dc->physDev, hPen );
2161             DeleteObject( hPen );
2162         }
2163
2164         if (crColor != CLR_INVALID)
2165         {
2166             oldClr = dc->dcPenColor;
2167             dc->dcPenColor = crColor;
2168         }
2169
2170         release_dc_ptr( dc );
2171     }
2172
2173     return oldClr;
2174 }
2175
2176 /***********************************************************************
2177  *           CancelDC    (GDI32.@)
2178  */
2179 BOOL WINAPI CancelDC(HDC hdc)
2180 {
2181     FIXME("stub\n");
2182     return TRUE;
2183 }
2184
2185 /***********************************************************************
2186  *           SetVirtualResolution   (GDI32.@)
2187  *
2188  * Undocumented on msdn.  Called when PowerPoint XP saves a file.
2189  */
2190 DWORD WINAPI SetVirtualResolution(HDC hdc, DWORD dw2, DWORD dw3, DWORD dw4, DWORD dw5)
2191 {
2192     FIXME("(%p %08x %08x %08x %08x): stub!\n", hdc, dw2, dw3, dw4, dw5);
2193     return FALSE;
2194 }
2195
2196 /*******************************************************************
2197  *      GetMiterLimit [GDI32.@]
2198  *
2199  *
2200  */
2201 BOOL WINAPI GetMiterLimit(HDC hdc, PFLOAT peLimit)
2202 {
2203     BOOL bRet = FALSE;
2204     DC *dc;
2205
2206     TRACE("(%p,%p)\n", hdc, peLimit);
2207
2208     dc = get_dc_ptr( hdc );
2209     if (dc)
2210     {
2211         if (peLimit)
2212             *peLimit = dc->miterLimit;
2213
2214         release_dc_ptr( dc );
2215         bRet = TRUE;
2216     }
2217     return bRet;
2218 }
2219
2220 /*******************************************************************
2221  *      SetMiterLimit [GDI32.@]
2222  *
2223  *
2224  */
2225 BOOL WINAPI SetMiterLimit(HDC hdc, FLOAT eNewLimit, PFLOAT peOldLimit)
2226 {
2227     BOOL bRet = FALSE;
2228     DC *dc;
2229
2230     TRACE("(%p,%f,%p)\n", hdc, eNewLimit, peOldLimit);
2231
2232     dc = get_dc_ptr( hdc );
2233     if (dc)
2234     {
2235         if (peOldLimit)
2236             *peOldLimit = dc->miterLimit;
2237         dc->miterLimit = eNewLimit;
2238         release_dc_ptr( dc );
2239         bRet = TRUE;
2240     }
2241     return bRet;
2242 }
2243
2244 /*******************************************************************
2245  *      GdiIsMetaPrintDC [GDI32.@]
2246  */
2247 BOOL WINAPI GdiIsMetaPrintDC(HDC hdc)
2248 {
2249     FIXME("%p\n", hdc);
2250     return FALSE;
2251 }
2252
2253 /*******************************************************************
2254  *      GdiIsMetaFileDC [GDI32.@]
2255  */
2256 BOOL WINAPI GdiIsMetaFileDC(HDC hdc)
2257 {
2258     TRACE("%p\n", hdc);
2259
2260     switch( GetObjectType( hdc ) )
2261     {
2262     case OBJ_METADC:
2263     case OBJ_ENHMETADC:
2264         return TRUE;
2265     }
2266     return FALSE;
2267 }
2268
2269 /*******************************************************************
2270  *      GdiIsPlayMetafileDC [GDI32.@]
2271  */
2272 BOOL WINAPI GdiIsPlayMetafileDC(HDC hdc)
2273 {
2274     FIXME("%p\n", hdc);
2275     return FALSE;
2276 }