Add register preservation when using lawrx instruction.
[wine] / objects / 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #include <stdlib.h>
24 #include <string.h>
25 #include "windef.h"
26 #include "wingdi.h"
27 #include "winerror.h"
28 #include "wownt32.h"
29 #include "wine/winuser16.h"
30 #include "gdi.h"
31 #include "heap.h"
32 #include "wine/debug.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(dc);
35
36 static BOOL DC_DeleteObject( HGDIOBJ handle, void *obj );
37
38 static const struct gdi_obj_funcs dc_funcs =
39 {
40     NULL,             /* pSelectObject */
41     NULL,             /* pGetObject16 */
42     NULL,             /* pGetObjectA */
43     NULL,             /* pGetObjectW */
44     NULL,             /* pUnrealizeObject */
45     DC_DeleteObject   /* pDeleteObject */
46 };
47
48 /***********************************************************************
49  *           DC_AllocDC
50  */
51 DC *DC_AllocDC( const DC_FUNCTIONS *funcs )
52 {
53     HDC hdc;
54     DC *dc;
55
56     if (!(dc = GDI_AllocObject( sizeof(*dc), DC_MAGIC, (HGDIOBJ*)&hdc, &dc_funcs ))) return NULL;
57
58     dc->hSelf               = hdc;
59     dc->funcs               = funcs;
60     dc->physDev             = NULL;
61     dc->saveLevel           = 0;
62     dc->dwHookData          = 0;
63     dc->hookProc            = NULL;
64     dc->hookThunk           = NULL;
65     dc->wndOrgX             = 0;
66     dc->wndOrgY             = 0;
67     dc->wndExtX             = 1;
68     dc->wndExtY             = 1;
69     dc->vportOrgX           = 0;
70     dc->vportOrgY           = 0;
71     dc->vportExtX           = 1;
72     dc->vportExtY           = 1;
73     dc->flags               = 0;
74     dc->hClipRgn            = 0;
75     dc->hVisRgn             = 0;
76     dc->hGCClipRgn          = 0;
77     dc->hPen                = GetStockObject( BLACK_PEN );
78     dc->hBrush              = GetStockObject( WHITE_BRUSH );
79     dc->hFont               = GetStockObject( SYSTEM_FONT );
80     dc->hBitmap             = 0;
81     dc->hDevice             = 0;
82     dc->hPalette            = GetStockObject( DEFAULT_PALETTE );
83     dc->gdiFont             = 0;
84     dc->ROPmode             = R2_COPYPEN;
85     dc->polyFillMode        = ALTERNATE;
86     dc->stretchBltMode      = BLACKONWHITE;
87     dc->relAbsMode          = ABSOLUTE;
88     dc->backgroundMode      = OPAQUE;
89     dc->backgroundColor     = RGB( 255, 255, 255 );
90     dc->textColor           = RGB( 0, 0, 0 );
91     dc->brushOrgX           = 0;
92     dc->brushOrgY           = 0;
93     dc->textAlign           = TA_LEFT | TA_TOP | TA_NOUPDATECP;
94     dc->charExtra           = 0;
95     dc->breakTotalExtra     = 0;
96     dc->breakCount          = 0;
97     dc->breakExtra          = 0;
98     dc->breakRem            = 0;
99     dc->totalExtent.left    = 0;
100     dc->totalExtent.top     = 0;
101     dc->totalExtent.right   = 0;
102     dc->totalExtent.bottom  = 0;
103     dc->bitsPerPixel        = 1;
104     dc->MapMode             = MM_TEXT;
105     dc->GraphicsMode        = GM_COMPATIBLE;
106     dc->pAbortProc          = NULL;
107     dc->CursPosX            = 0;
108     dc->CursPosY            = 0;
109     dc->ArcDirection        = AD_COUNTERCLOCKWISE;
110     dc->xformWorld2Wnd.eM11 = 1.0f;
111     dc->xformWorld2Wnd.eM12 = 0.0f;
112     dc->xformWorld2Wnd.eM21 = 0.0f;
113     dc->xformWorld2Wnd.eM22 = 1.0f;
114     dc->xformWorld2Wnd.eDx  = 0.0f;
115     dc->xformWorld2Wnd.eDy  = 0.0f;
116     dc->xformWorld2Vport    = dc->xformWorld2Wnd;
117     dc->xformVport2World    = dc->xformWorld2Wnd;
118     dc->vport2WorldValid    = TRUE;
119     PATH_InitGdiPath(&dc->path);
120     return dc;
121 }
122
123
124
125 /***********************************************************************
126  *           DC_GetDCPtr
127  */
128 DC *DC_GetDCPtr( HDC hdc )
129 {
130     GDIOBJHDR *ptr = GDI_GetObjPtr( hdc, MAGIC_DONTCARE );
131     if (!ptr) return NULL;
132     if ((GDIMAGIC(ptr->wMagic) == DC_MAGIC) ||
133         (GDIMAGIC(ptr->wMagic) == METAFILE_DC_MAGIC) ||
134         (GDIMAGIC(ptr->wMagic) == ENHMETAFILE_DC_MAGIC))
135         return (DC *)ptr;
136     GDI_ReleaseObj( hdc );
137     SetLastError( ERROR_INVALID_HANDLE );
138     return NULL;
139 }
140
141 /***********************************************************************
142  *           DC_GetDCUpdate
143  *
144  * Retrieve a DC ptr while making sure the visRgn is updated.
145  * This function may call up to USER so the GDI lock should _not_
146  * be held when calling it.
147  */
148 DC *DC_GetDCUpdate( HDC hdc )
149 {
150     DC *dc = DC_GetDCPtr( hdc );
151     if (!dc) return NULL;
152     while (dc->flags & DC_DIRTY)
153     {
154         dc->flags &= ~DC_DIRTY;
155         if (!(dc->flags & (DC_SAVED | DC_MEMORY)))
156         {
157             DCHOOKPROC proc = dc->hookThunk;
158             if (proc)
159             {
160                 DWORD data = dc->dwHookData;
161                 GDI_ReleaseObj( hdc );
162                 proc( HDC_16(hdc), DCHC_INVALIDVISRGN, data, 0 );
163                 if (!(dc = DC_GetDCPtr( hdc ))) break;
164                 /* otherwise restart the loop in case it became dirty again in the meantime */
165             }
166         }
167     }
168     return dc;
169 }
170
171
172 /***********************************************************************
173  *           DC_DeleteObject
174  */
175 static BOOL DC_DeleteObject( HGDIOBJ handle, void *obj )
176 {
177     GDI_ReleaseObj( handle );
178     return DeleteDC( handle );
179 }
180
181
182 /***********************************************************************
183  *           DC_InitDC
184  *
185  * Setup device-specific DC values for a newly created DC.
186  */
187 void DC_InitDC( DC* dc )
188 {
189     if (dc->funcs->pRealizeDefaultPalette) dc->funcs->pRealizeDefaultPalette( dc->physDev );
190     SetTextColor( dc->hSelf, dc->textColor );
191     SetBkColor( dc->hSelf, dc->backgroundColor );
192     SelectObject( dc->hSelf, dc->hPen );
193     SelectObject( dc->hSelf, dc->hBrush );
194     SelectObject( dc->hSelf, dc->hFont );
195     CLIPPING_UpdateGCRegion( dc );
196 }
197
198
199 /***********************************************************************
200  *           DC_InvertXform
201  *
202  * Computes the inverse of the transformation xformSrc and stores it to
203  * xformDest. Returns TRUE if successful or FALSE if the xformSrc matrix
204  * is singular.
205  */
206 static BOOL DC_InvertXform( const XFORM *xformSrc, XFORM *xformDest )
207 {
208     FLOAT determinant;
209
210     determinant = xformSrc->eM11*xformSrc->eM22 -
211         xformSrc->eM12*xformSrc->eM21;
212     if (determinant > -1e-12 && determinant < 1e-12)
213         return FALSE;
214
215     xformDest->eM11 =  xformSrc->eM22 / determinant;
216     xformDest->eM12 = -xformSrc->eM12 / determinant;
217     xformDest->eM21 = -xformSrc->eM21 / determinant;
218     xformDest->eM22 =  xformSrc->eM11 / determinant;
219     xformDest->eDx  = -xformSrc->eDx * xformDest->eM11 -
220                        xformSrc->eDy * xformDest->eM21;
221     xformDest->eDy  = -xformSrc->eDx * xformDest->eM12 -
222                        xformSrc->eDy * xformDest->eM22;
223
224     return TRUE;
225 }
226
227
228 /***********************************************************************
229  *           DC_UpdateXforms
230  *
231  * Updates the xformWorld2Vport, xformVport2World and vport2WorldValid
232  * fields of the specified DC by creating a transformation that
233  * represents the current mapping mode and combining it with the DC's
234  * world transform. This function should be called whenever the
235  * parameters associated with the mapping mode (window and viewport
236  * extents and origins) or the world transform change.
237  */
238 void DC_UpdateXforms( DC *dc )
239 {
240     XFORM xformWnd2Vport;
241     FLOAT scaleX, scaleY;
242
243     /* Construct a transformation to do the window-to-viewport conversion */
244     scaleX = (FLOAT)dc->vportExtX / (FLOAT)dc->wndExtX;
245     scaleY = (FLOAT)dc->vportExtY / (FLOAT)dc->wndExtY;
246     xformWnd2Vport.eM11 = scaleX;
247     xformWnd2Vport.eM12 = 0.0;
248     xformWnd2Vport.eM21 = 0.0;
249     xformWnd2Vport.eM22 = scaleY;
250     xformWnd2Vport.eDx  = (FLOAT)dc->vportOrgX -
251         scaleX * (FLOAT)dc->wndOrgX;
252     xformWnd2Vport.eDy  = (FLOAT)dc->vportOrgY -
253         scaleY * (FLOAT)dc->wndOrgY;
254
255     /* Combine with the world transformation */
256     CombineTransform( &dc->xformWorld2Vport, &dc->xformWorld2Wnd,
257         &xformWnd2Vport );
258
259     /* Create inverse of world-to-viewport transformation */
260     dc->vport2WorldValid = DC_InvertXform( &dc->xformWorld2Vport,
261         &dc->xformVport2World );
262 }
263
264
265 /***********************************************************************
266  *           GetDCState   (Not a Windows API)
267  */
268 HDC WINAPI GetDCState( HDC hdc )
269 {
270     DC * newdc, * dc;
271     HGDIOBJ handle;
272
273     if (!(dc = DC_GetDCPtr( hdc ))) return 0;
274     if (!(newdc = GDI_AllocObject( sizeof(DC), DC_MAGIC, &handle, &dc_funcs )))
275     {
276       GDI_ReleaseObj( hdc );
277       return 0;
278     }
279     TRACE("(%p): returning %p\n", hdc, handle );
280
281     newdc->flags            = dc->flags | DC_SAVED;
282     newdc->hPen             = dc->hPen;
283     newdc->hBrush           = dc->hBrush;
284     newdc->hFont            = dc->hFont;
285     newdc->hBitmap          = dc->hBitmap;
286     newdc->hDevice          = dc->hDevice;
287     newdc->hPalette         = dc->hPalette;
288     newdc->totalExtent      = dc->totalExtent;
289     newdc->bitsPerPixel     = dc->bitsPerPixel;
290     newdc->ROPmode          = dc->ROPmode;
291     newdc->polyFillMode     = dc->polyFillMode;
292     newdc->stretchBltMode   = dc->stretchBltMode;
293     newdc->relAbsMode       = dc->relAbsMode;
294     newdc->backgroundMode   = dc->backgroundMode;
295     newdc->backgroundColor  = dc->backgroundColor;
296     newdc->textColor        = dc->textColor;
297     newdc->brushOrgX        = dc->brushOrgX;
298     newdc->brushOrgY        = dc->brushOrgY;
299     newdc->textAlign        = dc->textAlign;
300     newdc->charExtra        = dc->charExtra;
301     newdc->breakTotalExtra  = dc->breakTotalExtra;
302     newdc->breakCount       = dc->breakCount;
303     newdc->breakExtra       = dc->breakExtra;
304     newdc->breakRem         = dc->breakRem;
305     newdc->MapMode          = dc->MapMode;
306     newdc->GraphicsMode     = dc->GraphicsMode;
307     newdc->CursPosX         = dc->CursPosX;
308     newdc->CursPosY         = dc->CursPosY;
309     newdc->ArcDirection     = dc->ArcDirection;
310     newdc->xformWorld2Wnd   = dc->xformWorld2Wnd;
311     newdc->xformWorld2Vport = dc->xformWorld2Vport;
312     newdc->xformVport2World = dc->xformVport2World;
313     newdc->vport2WorldValid = dc->vport2WorldValid;
314     newdc->wndOrgX          = dc->wndOrgX;
315     newdc->wndOrgY          = dc->wndOrgY;
316     newdc->wndExtX          = dc->wndExtX;
317     newdc->wndExtY          = dc->wndExtY;
318     newdc->vportOrgX        = dc->vportOrgX;
319     newdc->vportOrgY        = dc->vportOrgY;
320     newdc->vportExtX        = dc->vportExtX;
321     newdc->vportExtY        = dc->vportExtY;
322
323     newdc->hSelf = (HDC)handle;
324     newdc->saveLevel = 0;
325
326     PATH_InitGdiPath( &newdc->path );
327
328     newdc->pAbortProc = NULL;
329     newdc->hookThunk  = NULL;
330     newdc->hookProc   = 0;
331
332     /* Get/SetDCState() don't change hVisRgn field ("Undoc. Windows" p.559). */
333
334     newdc->hGCClipRgn = newdc->hVisRgn = 0;
335     if (dc->hClipRgn)
336     {
337         newdc->hClipRgn = CreateRectRgn( 0, 0, 0, 0 );
338         CombineRgn( newdc->hClipRgn, dc->hClipRgn, 0, RGN_COPY );
339     }
340     else
341         newdc->hClipRgn = 0;
342
343     if(dc->gdiFont) {
344         newdc->gdiFont = dc->gdiFont;
345     } else
346         newdc->gdiFont = 0;
347
348     GDI_ReleaseObj( handle );
349     GDI_ReleaseObj( hdc );
350     return handle;
351 }
352
353
354 /***********************************************************************
355  *           SetDCState   (Not a Windows API)
356  */
357 void WINAPI SetDCState( HDC hdc, HDC hdcs )
358 {
359     DC *dc, *dcs;
360
361     if (!(dc = DC_GetDCUpdate( hdc ))) return;
362     if (!(dcs = DC_GetDCPtr( hdcs )))
363     {
364       GDI_ReleaseObj( hdc );
365       return;
366     }
367     if (!dcs->flags & DC_SAVED)
368     {
369       GDI_ReleaseObj( hdc );
370       GDI_ReleaseObj( hdcs );
371       return;
372     }
373     TRACE("%p %p\n", hdc, hdcs );
374
375     dc->flags            = dcs->flags & ~(DC_SAVED | DC_DIRTY);
376     dc->hDevice          = dcs->hDevice;
377     dc->totalExtent      = dcs->totalExtent;
378     dc->ROPmode          = dcs->ROPmode;
379     dc->polyFillMode     = dcs->polyFillMode;
380     dc->stretchBltMode   = dcs->stretchBltMode;
381     dc->relAbsMode       = dcs->relAbsMode;
382     dc->backgroundMode   = dcs->backgroundMode;
383     dc->backgroundColor  = dcs->backgroundColor;
384     dc->textColor        = dcs->textColor;
385     dc->brushOrgX        = dcs->brushOrgX;
386     dc->brushOrgY        = dcs->brushOrgY;
387     dc->textAlign        = dcs->textAlign;
388     dc->charExtra        = dcs->charExtra;
389     dc->breakTotalExtra  = dcs->breakTotalExtra;
390     dc->breakCount       = dcs->breakCount;
391     dc->breakExtra       = dcs->breakExtra;
392     dc->breakRem         = dcs->breakRem;
393     dc->MapMode          = dcs->MapMode;
394     dc->GraphicsMode     = dcs->GraphicsMode;
395     dc->CursPosX         = dcs->CursPosX;
396     dc->CursPosY         = dcs->CursPosY;
397     dc->ArcDirection     = dcs->ArcDirection;
398     dc->xformWorld2Wnd   = dcs->xformWorld2Wnd;
399     dc->xformWorld2Vport = dcs->xformWorld2Vport;
400     dc->xformVport2World = dcs->xformVport2World;
401     dc->vport2WorldValid = dcs->vport2WorldValid;
402
403     dc->wndOrgX          = dcs->wndOrgX;
404     dc->wndOrgY          = dcs->wndOrgY;
405     dc->wndExtX          = dcs->wndExtX;
406     dc->wndExtY          = dcs->wndExtY;
407     dc->vportOrgX        = dcs->vportOrgX;
408     dc->vportOrgY        = dcs->vportOrgY;
409     dc->vportExtX        = dcs->vportExtX;
410     dc->vportExtY        = dcs->vportExtY;
411
412     if (!(dc->flags & DC_MEMORY)) dc->bitsPerPixel = dcs->bitsPerPixel;
413
414     if (dcs->hClipRgn)
415     {
416         if (!dc->hClipRgn) dc->hClipRgn = CreateRectRgn( 0, 0, 0, 0 );
417         CombineRgn( dc->hClipRgn, dcs->hClipRgn, 0, RGN_COPY );
418     }
419     else
420     {
421         if (dc->hClipRgn) DeleteObject( dc->hClipRgn );
422         dc->hClipRgn = 0;
423     }
424     CLIPPING_UpdateGCRegion( dc );
425
426     SelectObject( hdc, dcs->hBitmap );
427     SelectObject( hdc, dcs->hBrush );
428     SelectObject( hdc, dcs->hFont );
429     SelectObject( hdc, dcs->hPen );
430     SetBkColor( hdc, dcs->backgroundColor);
431     SetTextColor( hdc, dcs->textColor);
432     GDISelectPalette( hdc, dcs->hPalette, FALSE );
433     GDI_ReleaseObj( hdcs );
434     GDI_ReleaseObj( hdc );
435 }
436
437
438 /***********************************************************************
439  *           GetDCState   (GDI.179)
440  */
441 HDC16 WINAPI GetDCState16( HDC16 hdc )
442 {
443     return HDC_16( GetDCState( HDC_32(hdc) ));
444 }
445
446
447 /***********************************************************************
448  *           SetDCState   (GDI.180)
449  */
450 void WINAPI SetDCState16( HDC16 hdc, HDC16 hdcs )
451 {
452     SetDCState( HDC_32(hdc), HDC_32(hdcs) );
453 }
454
455
456 /***********************************************************************
457  *           SaveDC    (GDI32.@)
458  */
459 INT WINAPI SaveDC( HDC hdc )
460 {
461     HDC hdcs;
462     DC * dc, * dcs;
463     INT ret;
464
465     dc = DC_GetDCPtr( hdc );
466     if (!dc) return 0;
467
468     if(dc->funcs->pSaveDC)
469     {
470         ret = dc->funcs->pSaveDC( dc->physDev );
471         GDI_ReleaseObj( hdc );
472         return ret;
473     }
474
475     if (!(hdcs = GetDCState( hdc )))
476     {
477       GDI_ReleaseObj( hdc );
478       return 0;
479     }
480     dcs = DC_GetDCPtr( hdcs );
481
482     /* Copy path. The reason why path saving / restoring is in SaveDC/
483      * RestoreDC and not in GetDCState/SetDCState is that the ...DCState
484      * functions are only in Win16 (which doesn't have paths) and that
485      * SetDCState doesn't allow us to signal an error (which can happen
486      * when copying paths).
487      */
488     if (!PATH_AssignGdiPath( &dcs->path, &dc->path ))
489     {
490         GDI_ReleaseObj( hdc );
491         GDI_ReleaseObj( hdcs );
492         DeleteDC( hdcs );
493         return 0;
494     }
495
496     dcs->header.hNext = dc->header.hNext;
497     dc->header.hNext = HDC_16(hdcs);
498     TRACE("(%p): returning %d\n", hdc, dc->saveLevel+1 );
499     ret = ++dc->saveLevel;
500     GDI_ReleaseObj( hdcs );
501     GDI_ReleaseObj( hdc );
502     return ret;
503 }
504
505
506 /***********************************************************************
507  *           RestoreDC    (GDI32.@)
508  */
509 BOOL WINAPI RestoreDC( HDC hdc, INT level )
510 {
511     DC * dc, * dcs;
512     BOOL success;
513
514     TRACE("%p %d\n", hdc, level );
515     dc = DC_GetDCUpdate( hdc );
516     if(!dc) return FALSE;
517     if(dc->funcs->pRestoreDC)
518     {
519         success = dc->funcs->pRestoreDC( dc->physDev, level );
520         GDI_ReleaseObj( hdc );
521         return success;
522     }
523
524     if (level == -1) level = dc->saveLevel;
525     if ((level < 1)
526             /* This pair of checks disagrees with MSDN "Platform SDK:
527                Windows GDI" July 2000 which says all negative values
528                for level will be interpreted as an instance relative
529                to the current state.  Restricting it to just -1 does
530                not satisfy this */
531         || (level > dc->saveLevel))
532     {
533         GDI_ReleaseObj( hdc );
534         return FALSE;
535     }
536
537     success=TRUE;
538     while (dc->saveLevel >= level)
539     {
540         HDC hdcs = HDC_32(dc->header.hNext);
541         if (!(dcs = DC_GetDCPtr( hdcs )))
542         {
543           GDI_ReleaseObj( hdc );
544           return FALSE;
545         }
546         dc->header.hNext = dcs->header.hNext;
547         if (--dc->saveLevel < level)
548         {
549             SetDCState( hdc, hdcs );
550             if (!PATH_AssignGdiPath( &dc->path, &dcs->path ))
551                 /* FIXME: This might not be quite right, since we're
552                  * returning FALSE but still destroying the saved DC state */
553                 success=FALSE;
554         }
555         GDI_ReleaseObj( hdcs );
556         GDI_ReleaseObj( hdc );
557         DeleteDC( hdcs );
558         if (!(dc = DC_GetDCPtr( hdc ))) return FALSE;
559     }
560     GDI_ReleaseObj( hdc );
561     return success;
562 }
563
564
565 /***********************************************************************
566  *           CreateDCA    (GDI32.@)
567  */
568 HDC WINAPI CreateDCA( LPCSTR driver, LPCSTR device, LPCSTR output,
569                           const DEVMODEA *initData )
570 {
571     HDC hdc;
572     DC * dc;
573     const DC_FUNCTIONS *funcs;
574     char buf[300];
575
576     GDI_CheckNotLock();
577
578     if (!device || !DRIVER_GetDriverName( device, buf, sizeof(buf) ))
579     {
580         if (!driver) return 0;
581         strcpy(buf, driver);
582     }
583
584     if (!(funcs = DRIVER_load_driver( buf )))
585     {
586         ERR( "no driver found for %s\n", buf );
587         return 0;
588     }
589     if (!(dc = DC_AllocDC( funcs )))
590     {
591         DRIVER_release_driver( funcs );
592         return 0;
593     }
594
595     dc->flags   = 0;
596     dc->hBitmap = GetStockObject( DEFAULT_BITMAP );
597
598     TRACE("(driver=%s, device=%s, output=%s): returning %p\n",
599           debugstr_a(driver), debugstr_a(device), debugstr_a(output), dc->hSelf );
600
601     if (dc->funcs->pCreateDC &&
602         !dc->funcs->pCreateDC( dc, &dc->physDev, buf, device, output, initData ))
603     {
604         WARN("creation aborted by device\n" );
605         GDI_FreeObject( dc->hSelf, dc );
606         DRIVER_release_driver( funcs );
607         return 0;
608     }
609
610     dc->totalExtent.left   = 0;
611     dc->totalExtent.top    = 0;
612     dc->totalExtent.right  = GetDeviceCaps( dc->hSelf, HORZRES );
613     dc->totalExtent.bottom = GetDeviceCaps( dc->hSelf, VERTRES );
614     dc->hVisRgn = CreateRectRgnIndirect( &dc->totalExtent );
615
616     DC_InitDC( dc );
617     hdc = dc->hSelf;
618     GDI_ReleaseObj( hdc );
619     return hdc;
620 }
621
622
623 /***********************************************************************
624  *           CreateDCW    (GDI32.@)
625  */
626 HDC WINAPI CreateDCW( LPCWSTR driver, LPCWSTR device, LPCWSTR output,
627                           const DEVMODEW *initData )
628 {
629     LPSTR driverA = HEAP_strdupWtoA( GetProcessHeap(), 0, driver );
630     LPSTR deviceA = HEAP_strdupWtoA( GetProcessHeap(), 0, device );
631     LPSTR outputA = HEAP_strdupWtoA( GetProcessHeap(), 0, output );
632     HDC res = CreateDCA( driverA, deviceA, outputA,
633                             (const DEVMODEA *)initData /*FIXME*/ );
634     HeapFree( GetProcessHeap(), 0, driverA );
635     HeapFree( GetProcessHeap(), 0, deviceA );
636     HeapFree( GetProcessHeap(), 0, outputA );
637     return res;
638 }
639
640
641 /***********************************************************************
642  *           CreateICA    (GDI32.@)
643  */
644 HDC WINAPI CreateICA( LPCSTR driver, LPCSTR device, LPCSTR output,
645                           const DEVMODEA* initData )
646 {
647       /* Nothing special yet for ICs */
648     return CreateDCA( driver, device, output, initData );
649 }
650
651
652 /***********************************************************************
653  *           CreateICW    (GDI32.@)
654  */
655 HDC WINAPI CreateICW( LPCWSTR driver, LPCWSTR device, LPCWSTR output,
656                           const DEVMODEW* initData )
657 {
658       /* Nothing special yet for ICs */
659     return CreateDCW( driver, device, output, initData );
660 }
661
662
663 /***********************************************************************
664  *           CreateCompatibleDC   (GDI32.@)
665  */
666 HDC WINAPI CreateCompatibleDC( HDC hdc )
667 {
668     DC *dc, *origDC;
669     const DC_FUNCTIONS *funcs;
670
671     GDI_CheckNotLock();
672
673     if ((origDC = GDI_GetObjPtr( hdc, DC_MAGIC )))
674     {
675         funcs = origDC->funcs;
676         GDI_ReleaseObj( hdc ); /* can't hold the lock while loading the driver */
677         funcs = DRIVER_get_driver( funcs );
678     }
679     else funcs = DRIVER_load_driver( "DISPLAY" );
680
681     if (!funcs) return 0;
682
683     if (!(dc = DC_AllocDC( funcs )))
684     {
685         DRIVER_release_driver( funcs );
686         return 0;
687     }
688
689     TRACE("(%p): returning %p\n", hdc, dc->hSelf );
690
691     dc->flags        = DC_MEMORY;
692     dc->bitsPerPixel = 1;
693     dc->hBitmap      = GetStockObject( DEFAULT_BITMAP );
694
695     /* Copy the driver-specific physical device info into
696      * the new DC. The driver may use this read-only info
697      * while creating the compatible DC below. */
698     if ((origDC = GDI_GetObjPtr( hdc, DC_MAGIC ))) dc->physDev = origDC->physDev;
699
700     if (dc->funcs->pCreateDC &&
701         !dc->funcs->pCreateDC( dc, &dc->physDev, NULL, NULL, NULL, NULL ))
702     {
703         WARN("creation aborted by device\n");
704         GDI_FreeObject( dc->hSelf, dc );
705         if (origDC) GDI_ReleaseObj( hdc );
706         DRIVER_release_driver( funcs );
707         return 0;
708     }
709
710     dc->totalExtent.left   = 0;
711     dc->totalExtent.top    = 0;
712     dc->totalExtent.right  = 1;  /* default bitmap is 1x1 */
713     dc->totalExtent.bottom = 1;
714     dc->hVisRgn = CreateRectRgnIndirect( &dc->totalExtent );
715
716     DC_InitDC( dc );
717     GDI_ReleaseObj( dc->hSelf );
718     if (origDC) GDI_ReleaseObj( hdc );
719     return dc->hSelf;
720 }
721
722
723 /***********************************************************************
724  *           DeleteDC    (GDI32.@)
725  */
726 BOOL WINAPI DeleteDC( HDC hdc )
727 {
728     const DC_FUNCTIONS *funcs = NULL;
729     DC * dc;
730
731     TRACE("%p\n", hdc );
732
733     GDI_CheckNotLock();
734
735     if (!(dc = GDI_GetObjPtr( hdc, DC_MAGIC ))) return FALSE;
736
737     /* Call hook procedure to check whether is it OK to delete this DC */
738     if (dc->hookThunk && !(dc->flags & (DC_SAVED | DC_MEMORY)))
739     {
740         DCHOOKPROC proc = dc->hookThunk;
741         if (proc)
742         {
743             DWORD data = dc->dwHookData;
744             GDI_ReleaseObj( hdc );
745             if (!proc( HDC_16(hdc), DCHC_DELETEDC, data, 0 )) return FALSE;
746             if (!(dc = DC_GetDCPtr( hdc ))) return TRUE;  /* deleted by the hook */
747         }
748     }
749
750     while (dc->saveLevel)
751     {
752         DC * dcs;
753         HDC hdcs = HDC_32(dc->header.hNext);
754         if (!(dcs = DC_GetDCPtr( hdcs ))) break;
755         dc->header.hNext = dcs->header.hNext;
756         dc->saveLevel--;
757         if (dcs->hClipRgn) DeleteObject( dcs->hClipRgn );
758         if (dcs->hVisRgn) DeleteObject( dcs->hVisRgn );
759         if (dcs->hGCClipRgn) DeleteObject( dcs->hGCClipRgn );
760         PATH_DestroyGdiPath(&dcs->path);
761         GDI_FreeObject( hdcs, dcs );
762     }
763
764     if (!(dc->flags & DC_SAVED))
765     {
766         SelectObject( hdc, GetStockObject(BLACK_PEN) );
767         SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
768         SelectObject( hdc, GetStockObject(SYSTEM_FONT) );
769         SelectObject( hdc, GetStockObject(DEFAULT_BITMAP) );
770         funcs = dc->funcs;
771         if (dc->funcs->pDeleteDC) dc->funcs->pDeleteDC(dc->physDev);
772         dc->physDev = NULL;
773     }
774
775     if (dc->hClipRgn) DeleteObject( dc->hClipRgn );
776     if (dc->hVisRgn) DeleteObject( dc->hVisRgn );
777     if (dc->hGCClipRgn) DeleteObject( dc->hGCClipRgn );
778     PATH_DestroyGdiPath(&dc->path);
779
780     GDI_FreeObject( hdc, dc );
781     if (funcs) DRIVER_release_driver( funcs );  /* do that after releasing the GDI lock */
782     return TRUE;
783 }
784
785
786 /***********************************************************************
787  *           ResetDCA    (GDI32.@)
788  */
789 HDC WINAPI ResetDCA( HDC hdc, const DEVMODEA *devmode )
790 {
791     DC *dc;
792     HDC ret = hdc;
793
794     if ((dc = DC_GetDCPtr( hdc )))
795     {
796         if (dc->funcs->pResetDC) ret = dc->funcs->pResetDC( dc->physDev, devmode );
797         GDI_ReleaseObj( hdc );
798     }
799     return ret;
800 }
801
802
803 /***********************************************************************
804  *           ResetDCW    (GDI32.@)
805  */
806 HDC WINAPI ResetDCW( HDC hdc, const DEVMODEW *devmode )
807 {
808     return ResetDCA(hdc, (const DEVMODEA*)devmode); /* FIXME */
809 }
810
811
812 /***********************************************************************
813  *           GetDeviceCaps    (GDI32.@)
814  */
815 INT WINAPI GetDeviceCaps( HDC hdc, INT cap )
816 {
817     DC *dc;
818     INT ret = 0;
819
820     if ((dc = DC_GetDCPtr( hdc )))
821     {
822         if (dc->funcs->pGetDeviceCaps) ret = dc->funcs->pGetDeviceCaps( dc->physDev, cap );
823         GDI_ReleaseObj( hdc );
824     }
825     return ret;
826 }
827
828
829 /***********************************************************************
830  *           SetBkColor    (GDI32.@)
831  */
832 COLORREF WINAPI SetBkColor( HDC hdc, COLORREF color )
833 {
834     COLORREF oldColor;
835     DC * dc = DC_GetDCPtr( hdc );
836
837     if (!dc) return CLR_INVALID;
838     oldColor = dc->backgroundColor;
839     if (dc->funcs->pSetBkColor)
840     {
841         color = dc->funcs->pSetBkColor(dc->physDev, color);
842         if (color == CLR_INVALID)  /* don't change it */
843         {
844             color = oldColor;
845             oldColor = CLR_INVALID;
846         }
847     }
848     dc->backgroundColor = color;
849     GDI_ReleaseObj( hdc );
850     return oldColor;
851 }
852
853
854 /***********************************************************************
855  *           SetTextColor    (GDI32.@)
856  */
857 COLORREF WINAPI SetTextColor( HDC hdc, COLORREF color )
858 {
859     COLORREF oldColor;
860     DC * dc = DC_GetDCPtr( hdc );
861
862     if (!dc) return CLR_INVALID;
863     oldColor = dc->textColor;
864     if (dc->funcs->pSetTextColor)
865     {
866         color = dc->funcs->pSetTextColor(dc->physDev, color);
867         if (color == CLR_INVALID)  /* don't change it */
868         {
869             color = oldColor;
870             oldColor = CLR_INVALID;
871         }
872     }
873     dc->textColor = color;
874     GDI_ReleaseObj( hdc );
875     return oldColor;
876 }
877
878
879 /***********************************************************************
880  *           SetTextAlign    (GDI32.@)
881  */
882 UINT WINAPI SetTextAlign( HDC hdc, UINT align )
883 {
884     UINT prevAlign;
885     DC *dc = DC_GetDCPtr( hdc );
886     if (!dc) return 0x0;
887     if (dc->funcs->pSetTextAlign)
888         prevAlign = dc->funcs->pSetTextAlign(dc->physDev, align);
889     else {
890         prevAlign = dc->textAlign;
891         dc->textAlign = align;
892     }
893     GDI_ReleaseObj( hdc );
894     return prevAlign;
895 }
896
897 /***********************************************************************
898  *           GetDCOrgEx  (GDI32.@)
899  */
900 BOOL WINAPI GetDCOrgEx( HDC hDC, LPPOINT lpp )
901 {
902     DC * dc;
903
904     if (!lpp) return FALSE;
905     if (!(dc = DC_GetDCPtr( hDC ))) return FALSE;
906
907     lpp->x = lpp->y = 0;
908     if (dc->funcs->pGetDCOrgEx) dc->funcs->pGetDCOrgEx( dc->physDev, lpp );
909     GDI_ReleaseObj( hDC );
910     return TRUE;
911 }
912
913
914 /***********************************************************************
915  *           SetDCOrg   (GDI.117)
916  */
917 DWORD WINAPI SetDCOrg16( HDC16 hdc16, INT16 x, INT16 y )
918 {
919     DWORD prevOrg = 0;
920     HDC hdc = HDC_32( hdc16 );
921     DC *dc = DC_GetDCPtr( hdc );
922     if (!dc) return 0;
923     if (dc->funcs->pSetDCOrg) prevOrg = dc->funcs->pSetDCOrg( dc->physDev, x, y );
924     GDI_ReleaseObj( hdc );
925     return prevOrg;
926 }
927
928
929 /***********************************************************************
930  *           SetGraphicsMode    (GDI32.@)
931  */
932 INT WINAPI SetGraphicsMode( HDC hdc, INT mode )
933 {
934     INT ret = 0;
935     DC *dc = DC_GetDCPtr( hdc );
936
937     /* One would think that setting the graphics mode to GM_COMPATIBLE
938      * would also reset the world transformation matrix to the unity
939      * matrix. However, in Windows, this is not the case. This doesn't
940      * make a lot of sense to me, but that's the way it is.
941      */
942     if (!dc) return 0;
943     if ((mode > 0) && (mode <= GM_LAST))
944     {
945         ret = dc->GraphicsMode;
946         dc->GraphicsMode = mode;
947     }
948     GDI_ReleaseObj( hdc );
949     return ret;
950 }
951
952
953 /***********************************************************************
954  *           SetArcDirection    (GDI32.@)
955  */
956 INT WINAPI SetArcDirection( HDC hdc, INT nDirection )
957 {
958     DC * dc;
959     INT nOldDirection = 0;
960
961     if (nDirection!=AD_COUNTERCLOCKWISE && nDirection!=AD_CLOCKWISE)
962     {
963         SetLastError(ERROR_INVALID_PARAMETER);
964         return 0;
965     }
966
967     if ((dc = DC_GetDCPtr( hdc )))
968     {
969         nOldDirection = dc->ArcDirection;
970         dc->ArcDirection = nDirection;
971         GDI_ReleaseObj( hdc );
972     }
973     return nOldDirection;
974 }
975
976
977 /***********************************************************************
978  *           GetWorldTransform    (GDI32.@)
979  */
980 BOOL WINAPI GetWorldTransform( HDC hdc, LPXFORM xform )
981 {
982     DC * dc;
983     if (!xform) return FALSE;
984     if (!(dc = DC_GetDCPtr( hdc ))) return FALSE;
985     *xform = dc->xformWorld2Wnd;
986     GDI_ReleaseObj( hdc );
987     return TRUE;
988 }
989
990
991 /***********************************************************************
992  *           SetWorldTransform    (GDI32.@)
993  */
994 BOOL WINAPI SetWorldTransform( HDC hdc, const XFORM *xform )
995 {
996     BOOL ret = FALSE;
997     DC *dc = DC_GetDCPtr( hdc );
998
999     if (!dc) return FALSE;
1000     if (!xform) goto done;
1001
1002     /* Check that graphics mode is GM_ADVANCED */
1003     if (dc->GraphicsMode!=GM_ADVANCED) goto done;
1004
1005     dc->xformWorld2Wnd = *xform;
1006     DC_UpdateXforms( dc );
1007     ret = TRUE;
1008  done:
1009     GDI_ReleaseObj( hdc );
1010     return ret;
1011 }
1012
1013
1014 /****************************************************************************
1015  * ModifyWorldTransform [GDI32.@]
1016  * Modifies the world transformation for a device context.
1017  *
1018  * PARAMS
1019  *    hdc   [I] Handle to device context
1020  *    xform [I] XFORM structure that will be used to modify the world
1021  *              transformation
1022  *    iMode [I] Specifies in what way to modify the world transformation
1023  *              Possible values:
1024  *              MWT_IDENTITY
1025  *                 Resets the world transformation to the identity matrix.
1026  *                 The parameter xform is ignored.
1027  *              MWT_LEFTMULTIPLY
1028  *                 Multiplies xform into the world transformation matrix from
1029  *                 the left.
1030  *              MWT_RIGHTMULTIPLY
1031  *                 Multiplies xform into the world transformation matrix from
1032  *                 the right.
1033  *
1034  * RETURNS STD
1035  */
1036 BOOL WINAPI ModifyWorldTransform( HDC hdc, const XFORM *xform,
1037     DWORD iMode )
1038 {
1039     BOOL ret = FALSE;
1040     DC *dc = DC_GetDCPtr( hdc );
1041
1042     /* Check for illegal parameters */
1043     if (!dc) return FALSE;
1044     if (!xform) goto done;
1045
1046     /* Check that graphics mode is GM_ADVANCED */
1047     if (dc->GraphicsMode!=GM_ADVANCED) goto done;
1048
1049     switch (iMode)
1050     {
1051         case MWT_IDENTITY:
1052             dc->xformWorld2Wnd.eM11 = 1.0f;
1053             dc->xformWorld2Wnd.eM12 = 0.0f;
1054             dc->xformWorld2Wnd.eM21 = 0.0f;
1055             dc->xformWorld2Wnd.eM22 = 1.0f;
1056             dc->xformWorld2Wnd.eDx  = 0.0f;
1057             dc->xformWorld2Wnd.eDy  = 0.0f;
1058             break;
1059         case MWT_LEFTMULTIPLY:
1060             CombineTransform( &dc->xformWorld2Wnd, xform,
1061                 &dc->xformWorld2Wnd );
1062             break;
1063         case MWT_RIGHTMULTIPLY:
1064             CombineTransform( &dc->xformWorld2Wnd, &dc->xformWorld2Wnd,
1065                 xform );
1066             break;
1067         default:
1068             goto done;
1069     }
1070
1071     DC_UpdateXforms( dc );
1072     ret = TRUE;
1073  done:
1074     GDI_ReleaseObj( hdc );
1075     return ret;
1076 }
1077
1078
1079 /****************************************************************************
1080  * CombineTransform [GDI32.@]
1081  * Combines two transformation matrices.
1082  *
1083  * PARAMS
1084  *    xformResult [O] Stores the result of combining the two matrices
1085  *    xform1      [I] Specifies the first matrix to apply
1086  *    xform2      [I] Specifies the second matrix to apply
1087  *
1088  * REMARKS
1089  *    The same matrix can be passed in for more than one of the parameters.
1090  *
1091  * RETURNS STD
1092  */
1093 BOOL WINAPI CombineTransform( LPXFORM xformResult, const XFORM *xform1,
1094     const XFORM *xform2 )
1095 {
1096     XFORM xformTemp;
1097
1098     /* Check for illegal parameters */
1099     if (!xformResult || !xform1 || !xform2)
1100         return FALSE;
1101
1102     /* Create the result in a temporary XFORM, since xformResult may be
1103      * equal to xform1 or xform2 */
1104     xformTemp.eM11 = xform1->eM11 * xform2->eM11 +
1105                      xform1->eM12 * xform2->eM21;
1106     xformTemp.eM12 = xform1->eM11 * xform2->eM12 +
1107                      xform1->eM12 * xform2->eM22;
1108     xformTemp.eM21 = xform1->eM21 * xform2->eM11 +
1109                      xform1->eM22 * xform2->eM21;
1110     xformTemp.eM22 = xform1->eM21 * xform2->eM12 +
1111                      xform1->eM22 * xform2->eM22;
1112     xformTemp.eDx  = xform1->eDx  * xform2->eM11 +
1113                      xform1->eDy  * xform2->eM21 +
1114                      xform2->eDx;
1115     xformTemp.eDy  = xform1->eDx  * xform2->eM12 +
1116                      xform1->eDy  * xform2->eM22 +
1117                      xform2->eDy;
1118
1119     /* Copy the result to xformResult */
1120     *xformResult = xformTemp;
1121
1122     return TRUE;
1123 }
1124
1125
1126 /***********************************************************************
1127  *           SetDCHook   (GDI32.@)
1128  *
1129  * Note: this doesn't exist in Win32, we add it here because user32 needs it.
1130  */
1131 BOOL WINAPI SetDCHook( HDC hdc, DCHOOKPROC hookProc, DWORD dwHookData )
1132 {
1133     DC *dc = DC_GetDCPtr( hdc );
1134
1135     if (!dc) return FALSE;
1136     dc->dwHookData = dwHookData;
1137     dc->hookThunk = hookProc;
1138     GDI_ReleaseObj( hdc );
1139     return TRUE;
1140 }
1141
1142
1143 /* relay function to call the 16-bit DC hook proc */
1144 static BOOL16 WINAPI call_dc_hook16( HDC16 hdc16, WORD code, DWORD data, LPARAM lParam )
1145 {
1146     WORD args[6];
1147     DWORD ret;
1148     FARPROC16 proc = NULL;
1149     HDC hdc = HDC_32( hdc16 );
1150     DC *dc = DC_GetDCPtr( hdc );
1151
1152     if (!dc) return FALSE;
1153     proc = dc->hookProc;
1154     GDI_ReleaseObj( hdc );
1155     if (!proc) return FALSE;
1156     args[5] = hdc16;
1157     args[4] = code;
1158     args[3] = HIWORD(data);
1159     args[2] = LOWORD(data);
1160     args[1] = HIWORD(lParam);
1161     args[0] = LOWORD(lParam);
1162     WOWCallback16Ex( (DWORD)proc, WCB16_PASCAL, sizeof(args), args, &ret );
1163     return LOWORD(ret);
1164 }
1165
1166 /***********************************************************************
1167  *           SetDCHook   (GDI.190)
1168  */
1169 BOOL16 WINAPI SetDCHook16( HDC16 hdc16, FARPROC16 hookProc, DWORD dwHookData )
1170 {
1171     HDC hdc = HDC_32( hdc16 );
1172     DC *dc = DC_GetDCPtr( hdc );
1173     if (!dc) return FALSE;
1174
1175     dc->hookProc = hookProc;
1176     GDI_ReleaseObj( hdc );
1177     return SetDCHook( hdc, call_dc_hook16, dwHookData );
1178 }
1179
1180
1181 /***********************************************************************
1182  *           GetDCHook   (GDI.191)
1183  */
1184 DWORD WINAPI GetDCHook16( HDC16 hdc16, FARPROC16 *phookProc )
1185 {
1186     HDC hdc = HDC_32( hdc16 );
1187     DC *dc = DC_GetDCPtr( hdc );
1188     DWORD ret;
1189
1190     if (!dc) return 0;
1191     *phookProc = dc->hookProc;
1192     ret = dc->dwHookData;
1193     GDI_ReleaseObj( hdc );
1194     return ret;
1195 }
1196
1197
1198 /***********************************************************************
1199  *           SetHookFlags   (GDI.192)
1200  */
1201 WORD WINAPI SetHookFlags16(HDC16 hdc16, WORD flags)
1202 {
1203     HDC hdc = HDC_32( hdc16 );
1204     DC *dc = DC_GetDCPtr( hdc );
1205
1206     if( dc )
1207     {
1208         WORD wRet = dc->flags & DC_DIRTY;
1209
1210         /* "Undocumented Windows" info is slightly confusing.
1211          */
1212
1213         TRACE("hDC %p, flags %04x\n",hdc,flags);
1214
1215         if( flags & DCHF_INVALIDATEVISRGN )
1216             dc->flags |= DC_DIRTY;
1217         else if( flags & DCHF_VALIDATEVISRGN || !flags )
1218             dc->flags &= ~DC_DIRTY;
1219         GDI_ReleaseObj( hdc );
1220         return wRet;
1221     }
1222     return 0;
1223 }
1224
1225 /***********************************************************************
1226  *           SetICMMode    (GDI32.@)
1227  */
1228 INT WINAPI SetICMMode(HDC hdc, INT iEnableICM)
1229 {
1230 /*FIXME  Asuming that ICM is always off, and cannot be turned on */
1231     if (iEnableICM == ICM_OFF) return ICM_OFF;
1232     if (iEnableICM == ICM_ON) return 0;
1233     if (iEnableICM == ICM_QUERY) return ICM_OFF;
1234     return 0;
1235 }
1236
1237 /***********************************************************************
1238  *           GetDeviceGammaRamp    (GDI32.@)
1239  */
1240 BOOL WINAPI GetDeviceGammaRamp(HDC hDC, LPVOID ptr)
1241 {
1242     BOOL ret = FALSE;
1243     DC *dc = DC_GetDCPtr( hDC );
1244
1245     if( dc )
1246     {
1247         if (dc->funcs->pGetDeviceGammaRamp)
1248             ret = dc->funcs->pGetDeviceGammaRamp(dc->physDev, ptr);
1249         GDI_ReleaseObj( hDC );
1250     }
1251     return ret;
1252 }
1253
1254 /***********************************************************************
1255  *           SetDeviceGammaRamp    (GDI32.@)
1256  */
1257 BOOL WINAPI SetDeviceGammaRamp(HDC hDC, LPVOID ptr)
1258 {
1259     BOOL ret = FALSE;
1260     DC *dc = DC_GetDCPtr( hDC );
1261
1262     if( dc )
1263     {
1264         if (dc->funcs->pSetDeviceGammaRamp)
1265             ret = dc->funcs->pSetDeviceGammaRamp(dc->physDev, ptr);
1266         GDI_ReleaseObj( hDC );
1267     }
1268     return ret;
1269 }
1270
1271 /***********************************************************************
1272  *           GetColorSpace    (GDI32.@)
1273  */
1274 HCOLORSPACE WINAPI GetColorSpace(HDC hdc)
1275 {
1276 /*FIXME    Need to to whatever GetColorSpace actually does */
1277     return 0;
1278 }
1279
1280 /***********************************************************************
1281  *           CreateColorSpaceA    (GDI32.@)
1282  */
1283 HCOLORSPACE WINAPI CreateColorSpaceA( LPLOGCOLORSPACEA lpLogColorSpace )
1284 {
1285   FIXME( "stub\n" );
1286   return 0;
1287 }
1288
1289 /***********************************************************************
1290  *           CreateColorSpaceW    (GDI32.@)
1291  */
1292 HCOLORSPACE WINAPI CreateColorSpaceW( LPLOGCOLORSPACEW lpLogColorSpace )
1293 {
1294   FIXME( "stub\n" );
1295   return 0;
1296 }
1297
1298 /***********************************************************************
1299  *           DeleteColorSpace     (GDI32.@)
1300  */
1301 BOOL WINAPI DeleteColorSpace( HCOLORSPACE hColorSpace )
1302 {
1303   FIXME( "stub\n" );
1304
1305   return TRUE;
1306 }
1307
1308 /***********************************************************************
1309  *           SetColorSpace     (GDI32.@)
1310  */
1311 HCOLORSPACE WINAPI SetColorSpace( HDC hDC, HCOLORSPACE hColorSpace )
1312 {
1313   FIXME( "stub\n" );
1314
1315   return hColorSpace;
1316 }
1317
1318 /***********************************************************************
1319  *           GetBoundsRect    (GDI.194)
1320  */
1321 UINT16 WINAPI GetBoundsRect16(HDC16 hdc, LPRECT16 rect, UINT16 flags)
1322 {
1323     return DCB_RESET | DCB_DISABLE; /* bounding rectangle always empty and disabled*/
1324 }
1325
1326 /***********************************************************************
1327  *           GetBoundsRect    (GDI32.@)
1328  */
1329 UINT WINAPI GetBoundsRect(HDC hdc, LPRECT rect, UINT flags)
1330 {
1331     FIXME("(): stub\n");
1332     return DCB_RESET;   /* bounding rectangle always empty */
1333 }
1334
1335 /***********************************************************************
1336  *           SetBoundsRect    (GDI.193)
1337  */
1338 UINT16 WINAPI SetBoundsRect16(HDC16 hdc, const RECT16* rect, UINT16 flags)
1339 {
1340     if ( (flags & DCB_ACCUMULATE) || (flags & DCB_ENABLE) )
1341         FIXME("(%04x, %p, %04x): stub\n", hdc, rect, flags );
1342
1343     return DCB_RESET | DCB_DISABLE; /* bounding rectangle always empty and disabled*/
1344 }
1345
1346 /***********************************************************************
1347  *           SetBoundsRect    (GDI32.@)
1348  */
1349 UINT WINAPI SetBoundsRect(HDC hdc, const RECT* rect, UINT flags)
1350 {
1351     FIXME("(): stub\n");
1352     return DCB_DISABLE;   /* bounding rectangle always empty */
1353 }
1354
1355
1356 /***********************************************************************
1357  *              GetRelAbs               (GDI32.@)
1358  */
1359 INT WINAPI GetRelAbs( HDC hdc, DWORD dwIgnore )
1360 {
1361     INT ret = 0;
1362     DC *dc = DC_GetDCPtr( hdc );
1363     if (dc) ret = dc->relAbsMode;
1364     GDI_ReleaseObj( hdc );
1365     return ret;
1366 }
1367
1368 /***********************************************************************
1369  *           GetLayout    (GDI32.@)
1370  *
1371  * Gets left->right or right->left text layout flags of a dc.
1372  * win98 just returns 0 and sets ERROR_CALL_NOT_IMPLEMENTED so we do the same
1373  *
1374  */
1375 DWORD WINAPI GetLayout(HDC hdc)
1376 {
1377     FIXME("(%p): stub\n", hdc);
1378     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1379     return 0;
1380 }
1381
1382 /***********************************************************************
1383  *           SetLayout    (GDI32.@)
1384  *
1385  * Sets left->right or right->left text layout flags of a dc.
1386  * win98 just returns 0 and sets ERROR_CALL_NOT_IMPLEMENTED so we do the same
1387  *
1388  */
1389 DWORD WINAPI SetLayout(HDC hdc, DWORD layout)
1390 {
1391     FIXME("(%p,%08lx): stub\n", hdc, layout);
1392     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1393     return 0;
1394 }
1395
1396 /***********************************************************************
1397  *           SetDCBrushColor    (GDI32.@)
1398  *
1399  * Sets the current device context (DC) brush color to the specified
1400  * color value. If the device cannot represent the specified color
1401  * value, the color is set to the nearest physical color.
1402  *
1403  */
1404 COLORREF WINAPI SetDCBrushColor(HDC hdc, COLORREF crColor)
1405 {
1406     FIXME("(%p, %08lx): stub\n", hdc, crColor);
1407     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1408     return CLR_INVALID;
1409 }