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