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