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