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