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