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