GetSystemPaletteEntries returns palette size if entries==NULL.
[wine] / objects / dc.c
1 /*
2  * GDI Device Context functions
3  *
4  * Copyright 1993 Alexandre Julliard
5  *
6  */
7
8 #include <stdlib.h>
9 #include <string.h>
10 #include "dc.h"
11 #include "gdi.h"
12 #include "heap.h"
13 #include "metafile.h"
14 #include "debug.h"
15 #include "font.h"
16 #include "winerror.h"
17 #include "x11drv.h"
18
19 /***********************************************************************
20  *           DC_Init_DC_INFO
21  *
22  * Fill the WIN_DC_INFO structure.
23  */
24 static void DC_Init_DC_INFO( WIN_DC_INFO *win_dc_info )
25 {
26     win_dc_info->flags               = 0;
27     win_dc_info->devCaps             = NULL;
28     win_dc_info->hClipRgn            = 0;
29     win_dc_info->hVisRgn             = 0;
30     win_dc_info->hGCClipRgn          = 0;
31     win_dc_info->hPen                = STOCK_BLACK_PEN;
32     win_dc_info->hBrush              = STOCK_WHITE_BRUSH;
33     win_dc_info->hFont               = STOCK_SYSTEM_FONT;
34     win_dc_info->hBitmap             = 0;
35     win_dc_info->hFirstBitmap        = 0;
36     win_dc_info->hDevice             = 0;
37     win_dc_info->hPalette            = STOCK_DEFAULT_PALETTE;
38     win_dc_info->ROPmode             = R2_COPYPEN;
39     win_dc_info->polyFillMode        = ALTERNATE;
40     win_dc_info->stretchBltMode      = BLACKONWHITE;
41     win_dc_info->relAbsMode          = ABSOLUTE;
42     win_dc_info->backgroundMode      = OPAQUE;
43     win_dc_info->backgroundColor     = RGB( 255, 255, 255 );
44     win_dc_info->textColor           = RGB( 0, 0, 0 );
45     win_dc_info->brushOrgX           = 0;
46     win_dc_info->brushOrgY           = 0;
47     win_dc_info->textAlign           = TA_LEFT | TA_TOP | TA_NOUPDATECP;
48     win_dc_info->charExtra           = 0;
49     win_dc_info->breakTotalExtra     = 0;
50     win_dc_info->breakCount          = 0;
51     win_dc_info->breakExtra          = 0;
52     win_dc_info->breakRem            = 0;
53     win_dc_info->bitsPerPixel        = 1;
54     win_dc_info->MapMode             = MM_TEXT;
55     win_dc_info->GraphicsMode        = GM_COMPATIBLE;
56     win_dc_info->DCOrgX              = 0;
57     win_dc_info->DCOrgY              = 0;
58     win_dc_info->lpfnPrint           = NULL;
59     win_dc_info->CursPosX            = 0;
60     win_dc_info->CursPosY            = 0;
61     win_dc_info->ArcDirection        = AD_COUNTERCLOCKWISE;
62     win_dc_info->xformWorld2Wnd.eM11 = 1.0f;
63     win_dc_info->xformWorld2Wnd.eM12 = 0.0f;
64     win_dc_info->xformWorld2Wnd.eM21 = 0.0f;
65     win_dc_info->xformWorld2Wnd.eM22 = 1.0f;
66     win_dc_info->xformWorld2Wnd.eDx  = 0.0f;
67     win_dc_info->xformWorld2Wnd.eDy  = 0.0f;
68     win_dc_info->xformWorld2Vport    = win_dc_info->xformWorld2Wnd;
69     win_dc_info->xformVport2World    = win_dc_info->xformWorld2Wnd;
70     win_dc_info->vport2WorldValid    = TRUE;
71
72     PATH_InitGdiPath(&win_dc_info->path);
73 }
74
75
76 /***********************************************************************
77  *           DC_AllocDC
78  */
79 DC *DC_AllocDC( const DC_FUNCTIONS *funcs )
80 {
81     HDC16 hdc;
82     DC *dc;
83
84     if (!(hdc = GDI_AllocObject( sizeof(DC), DC_MAGIC ))) return NULL;
85     dc = (DC *) GDI_HEAP_LOCK( hdc );
86
87     dc->hSelf      = hdc;
88     dc->funcs      = funcs;
89     dc->physDev    = NULL;
90     dc->saveLevel  = 0;
91     dc->dwHookData = 0L;
92     dc->hookProc   = NULL;
93     dc->wndOrgX    = 0;
94     dc->wndOrgY    = 0;
95     dc->wndExtX    = 1;
96     dc->wndExtY    = 1;
97     dc->vportOrgX  = 0;
98     dc->vportOrgY  = 0;
99     dc->vportExtX  = 1;
100     dc->vportExtY  = 1;
101
102     DC_Init_DC_INFO( &dc->w );
103
104     return dc;
105 }
106
107
108
109 /***********************************************************************
110  *           DC_GetDCPtr
111  */
112 DC *DC_GetDCPtr( HDC32 hdc )
113 {
114     GDIOBJHDR *ptr = (GDIOBJHDR *)GDI_HEAP_LOCK( hdc );
115     if (!ptr) return NULL;
116     if ((ptr->wMagic == DC_MAGIC) || (ptr->wMagic == METAFILE_DC_MAGIC))
117         return (DC *)ptr;
118     GDI_HEAP_UNLOCK( hdc );
119     return NULL;
120 }
121
122
123 /***********************************************************************
124  *           DC_InitDC
125  *
126  * Setup device-specific DC values for a newly created DC.
127  */
128 void DC_InitDC( DC* dc )
129 {
130     RealizeDefaultPalette( dc->hSelf );
131     SetTextColor32( dc->hSelf, dc->w.textColor );
132     SetBkColor32( dc->hSelf, dc->w.backgroundColor );
133     SelectObject32( dc->hSelf, dc->w.hPen );
134     SelectObject32( dc->hSelf, dc->w.hBrush );
135     SelectObject32( dc->hSelf, dc->w.hFont );
136     CLIPPING_UpdateGCRegion( dc );
137 }
138
139
140 /***********************************************************************
141  *           DC_InvertXform
142  *
143  * Computes the inverse of the transformation xformSrc and stores it to
144  * xformDest. Returns TRUE if successful or FALSE if the xformSrc matrix
145  * is singular.
146  */
147 static BOOL32 DC_InvertXform( const XFORM *xformSrc, XFORM *xformDest )
148 {
149     FLOAT determinant;
150     
151     determinant = xformSrc->eM11*xformSrc->eM22 -
152         xformSrc->eM12*xformSrc->eM21;
153     if (determinant > -1e-12 && determinant < 1e-12)
154         return FALSE;
155
156     xformDest->eM11 =  xformSrc->eM22 / determinant;
157     xformDest->eM12 = -xformSrc->eM12 / determinant;
158     xformDest->eM21 = -xformSrc->eM21 / determinant;
159     xformDest->eM22 =  xformSrc->eM11 / determinant;
160     xformDest->eDx  = -xformSrc->eDx * xformDest->eM11 -
161                        xformSrc->eDy * xformDest->eM21;
162     xformDest->eDy  = -xformSrc->eDx * xformDest->eM12 -
163                        xformSrc->eDy * xformDest->eM22;
164
165     return TRUE;
166 }
167
168
169 /***********************************************************************
170  *           DC_UpdateXforms
171  *
172  * Updates the xformWorld2Vport, xformVport2World and vport2WorldValid
173  * fields of the specified DC by creating a transformation that
174  * represents the current mapping mode and combining it with the DC's
175  * world transform. This function should be called whenever the
176  * parameters associated with the mapping mode (window and viewport
177  * extents and origins) or the world transform change.
178  */
179 void DC_UpdateXforms( DC *dc )
180 {
181     XFORM xformWnd2Vport;
182     FLOAT scaleX, scaleY;
183     
184     /* Construct a transformation to do the window-to-viewport conversion */
185     scaleX = (FLOAT)dc->vportExtX / (FLOAT)dc->wndExtX;
186     scaleY = (FLOAT)dc->vportExtY / (FLOAT)dc->wndExtY;
187     xformWnd2Vport.eM11 = scaleX;
188     xformWnd2Vport.eM12 = 0.0;
189     xformWnd2Vport.eM21 = 0.0;
190     xformWnd2Vport.eM22 = scaleY;
191     xformWnd2Vport.eDx  = (FLOAT)dc->vportOrgX -
192         scaleX * (FLOAT)dc->wndOrgX;
193     xformWnd2Vport.eDy  = (FLOAT)dc->vportOrgY -
194         scaleY * (FLOAT)dc->wndOrgY;
195
196     /* Combine with the world transformation */
197     CombineTransform( &dc->w.xformWorld2Vport, &dc->w.xformWorld2Wnd,
198         &xformWnd2Vport );
199
200     /* Create inverse of world-to-viewport transformation */
201     dc->w.vport2WorldValid = DC_InvertXform( &dc->w.xformWorld2Vport,
202         &dc->w.xformVport2World );
203 }
204
205
206 /***********************************************************************
207  *           GetDCState    (GDI.179)
208  */
209 HDC16 WINAPI GetDCState( HDC16 hdc )
210 {
211     DC * newdc, * dc;
212     HGDIOBJ16 handle;
213     
214     if (!(dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ))) return 0;
215     if (!(handle = GDI_AllocObject( sizeof(DC), DC_MAGIC )))
216     {
217       GDI_HEAP_UNLOCK( hdc );
218       return 0;
219     }
220     newdc = (DC *) GDI_HEAP_LOCK( handle );
221
222     TRACE(dc, "(%04x): returning %04x\n", hdc, handle );
223
224     newdc->w.flags            = dc->w.flags | DC_SAVED;
225     newdc->w.devCaps          = dc->w.devCaps;
226     newdc->w.hPen             = dc->w.hPen;       
227     newdc->w.hBrush           = dc->w.hBrush;     
228     newdc->w.hFont            = dc->w.hFont;      
229     newdc->w.hBitmap          = dc->w.hBitmap;    
230     newdc->w.hFirstBitmap     = dc->w.hFirstBitmap;
231     newdc->w.hDevice          = dc->w.hDevice;
232     newdc->w.hPalette         = dc->w.hPalette;   
233     newdc->w.totalExtent      = dc->w.totalExtent;
234     newdc->w.bitsPerPixel     = dc->w.bitsPerPixel;
235     newdc->w.ROPmode          = dc->w.ROPmode;
236     newdc->w.polyFillMode     = dc->w.polyFillMode;
237     newdc->w.stretchBltMode   = dc->w.stretchBltMode;
238     newdc->w.relAbsMode       = dc->w.relAbsMode;
239     newdc->w.backgroundMode   = dc->w.backgroundMode;
240     newdc->w.backgroundColor  = dc->w.backgroundColor;
241     newdc->w.textColor        = dc->w.textColor;
242     newdc->w.brushOrgX        = dc->w.brushOrgX;
243     newdc->w.brushOrgY        = dc->w.brushOrgY;
244     newdc->w.textAlign        = dc->w.textAlign;
245     newdc->w.charExtra        = dc->w.charExtra;
246     newdc->w.breakTotalExtra  = dc->w.breakTotalExtra;
247     newdc->w.breakCount       = dc->w.breakCount;
248     newdc->w.breakExtra       = dc->w.breakExtra;
249     newdc->w.breakRem         = dc->w.breakRem;
250     newdc->w.MapMode          = dc->w.MapMode;
251     newdc->w.GraphicsMode     = dc->w.GraphicsMode;
252 #if 0
253     /* Apparently, the DC origin is not changed by [GS]etDCState */
254     newdc->w.DCOrgX           = dc->w.DCOrgX;
255     newdc->w.DCOrgY           = dc->w.DCOrgY;
256 #endif
257     newdc->w.CursPosX         = dc->w.CursPosX;
258     newdc->w.CursPosY         = dc->w.CursPosY;
259     newdc->w.ArcDirection     = dc->w.ArcDirection;
260     newdc->w.xformWorld2Wnd   = dc->w.xformWorld2Wnd;
261     newdc->w.xformWorld2Vport = dc->w.xformWorld2Vport;
262     newdc->w.xformVport2World = dc->w.xformVport2World;
263     newdc->w.vport2WorldValid = dc->w.vport2WorldValid;
264     newdc->wndOrgX            = dc->wndOrgX;
265     newdc->wndOrgY            = dc->wndOrgY;
266     newdc->wndExtX            = dc->wndExtX;
267     newdc->wndExtY            = dc->wndExtY;
268     newdc->vportOrgX          = dc->vportOrgX;
269     newdc->vportOrgY          = dc->vportOrgY;
270     newdc->vportExtX          = dc->vportExtX;
271     newdc->vportExtY          = dc->vportExtY;
272
273     newdc->hSelf = (HDC32)handle;
274     newdc->saveLevel = 0;
275
276     PATH_InitGdiPath( &newdc->w.path );
277     
278     /* Get/SetDCState() don't change hVisRgn field ("Undoc. Windows" p.559). */
279
280     newdc->w.hGCClipRgn = newdc->w.hVisRgn = 0;
281     if (dc->w.hClipRgn)
282     {
283         newdc->w.hClipRgn = CreateRectRgn32( 0, 0, 0, 0 );
284         CombineRgn32( newdc->w.hClipRgn, dc->w.hClipRgn, 0, RGN_COPY );
285     }
286     else
287         newdc->w.hClipRgn = 0;
288     GDI_HEAP_UNLOCK( handle );
289     GDI_HEAP_UNLOCK( hdc );
290     return handle;
291 }
292
293
294 /***********************************************************************
295  *           SetDCState    (GDI.180)
296  */
297 void WINAPI SetDCState( HDC16 hdc, HDC16 hdcs )
298 {
299     DC *dc, *dcs;
300     
301     if (!(dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ))) return;
302     if (!(dcs = (DC *) GDI_GetObjPtr( hdcs, DC_MAGIC )))
303     {
304       GDI_HEAP_UNLOCK( hdc );
305       return;
306     }
307     if (!dcs->w.flags & DC_SAVED)
308     {
309       GDI_HEAP_UNLOCK( hdc );
310       GDI_HEAP_UNLOCK( hdcs );
311       return;
312     }
313     TRACE(dc, "%04x %04x\n", hdc, hdcs );
314
315     dc->w.flags            = dcs->w.flags & ~DC_SAVED;
316     dc->w.devCaps          = dcs->w.devCaps;
317     dc->w.hFirstBitmap     = dcs->w.hFirstBitmap;
318     dc->w.hDevice          = dcs->w.hDevice;
319     dc->w.totalExtent      = dcs->w.totalExtent;
320     dc->w.ROPmode          = dcs->w.ROPmode;
321     dc->w.polyFillMode     = dcs->w.polyFillMode;
322     dc->w.stretchBltMode   = dcs->w.stretchBltMode;
323     dc->w.relAbsMode       = dcs->w.relAbsMode;
324     dc->w.backgroundMode   = dcs->w.backgroundMode;
325     dc->w.backgroundColor  = dcs->w.backgroundColor;
326     dc->w.textColor        = dcs->w.textColor;
327     dc->w.brushOrgX        = dcs->w.brushOrgX;
328     dc->w.brushOrgY        = dcs->w.brushOrgY;
329     dc->w.textAlign        = dcs->w.textAlign;
330     dc->w.charExtra        = dcs->w.charExtra;
331     dc->w.breakTotalExtra  = dcs->w.breakTotalExtra;
332     dc->w.breakCount       = dcs->w.breakCount;
333     dc->w.breakExtra       = dcs->w.breakExtra;
334     dc->w.breakRem         = dcs->w.breakRem;
335     dc->w.MapMode          = dcs->w.MapMode;
336     dc->w.GraphicsMode     = dcs->w.GraphicsMode;
337 #if 0
338     /* Apparently, the DC origin is not changed by [GS]etDCState */
339     dc->w.DCOrgX           = dcs->w.DCOrgX;
340     dc->w.DCOrgY           = dcs->w.DCOrgY;
341 #endif
342     dc->w.CursPosX         = dcs->w.CursPosX;
343     dc->w.CursPosY         = dcs->w.CursPosY;
344     dc->w.ArcDirection     = dcs->w.ArcDirection;
345     dc->w.xformWorld2Wnd   = dcs->w.xformWorld2Wnd;
346     dc->w.xformWorld2Vport = dcs->w.xformWorld2Vport;
347     dc->w.xformVport2World = dcs->w.xformVport2World;
348     dc->w.vport2WorldValid = dcs->w.vport2WorldValid;
349
350     dc->wndOrgX            = dcs->wndOrgX;
351     dc->wndOrgY            = dcs->wndOrgY;
352     dc->wndExtX            = dcs->wndExtX;
353     dc->wndExtY            = dcs->wndExtY;
354     dc->vportOrgX          = dcs->vportOrgX;
355     dc->vportOrgY          = dcs->vportOrgY;
356     dc->vportExtX          = dcs->vportExtX;
357     dc->vportExtY          = dcs->vportExtY;
358
359     if (!(dc->w.flags & DC_MEMORY)) dc->w.bitsPerPixel = dcs->w.bitsPerPixel;
360
361     if (dcs->w.hClipRgn)
362     {
363         if (!dc->w.hClipRgn) dc->w.hClipRgn = CreateRectRgn32( 0, 0, 0, 0 );
364         CombineRgn32( dc->w.hClipRgn, dcs->w.hClipRgn, 0, RGN_COPY );
365     }
366     else
367     {
368         if (dc->w.hClipRgn) DeleteObject16( dc->w.hClipRgn );
369         dc->w.hClipRgn = 0;
370     }
371     CLIPPING_UpdateGCRegion( dc );
372
373     SelectObject32( hdc, dcs->w.hBitmap );
374     SelectObject32( hdc, dcs->w.hBrush );
375     SelectObject32( hdc, dcs->w.hFont );
376     SelectObject32( hdc, dcs->w.hPen );
377     SetBkColor32( hdc, dcs->w.backgroundColor);
378     SetTextColor32( hdc, dcs->w.textColor);
379     GDISelectPalette( hdc, dcs->w.hPalette, FALSE );
380     GDI_HEAP_UNLOCK( hdc );
381     GDI_HEAP_UNLOCK( hdcs );
382 }
383
384
385 /***********************************************************************
386  *           SaveDC16    (GDI.30)
387  */
388 INT16 WINAPI SaveDC16( HDC16 hdc )
389 {
390     return (INT16)SaveDC32( hdc );
391 }
392
393
394 /***********************************************************************
395  *           SaveDC32    (GDI32.292)
396  */
397 INT32 WINAPI SaveDC32( HDC32 hdc )
398 {
399     HDC32 hdcs;
400     DC * dc, * dcs;
401     INT32 ret;
402
403     dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
404     if (!dc) 
405     {
406         dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
407         if (!dc) return 0;
408         MF_MetaParam0(dc, META_SAVEDC);
409         GDI_HEAP_UNLOCK( hdc );
410         return 1;  /* ?? */
411     }
412     if (!(hdcs = GetDCState( hdc )))
413     {
414       GDI_HEAP_UNLOCK( hdc );
415       return 0;
416     }
417     dcs = (DC *) GDI_HEAP_LOCK( hdcs );
418
419     /* Copy path. The reason why path saving / restoring is in SaveDC/
420      * RestoreDC and not in GetDCState/SetDCState is that the ...DCState
421      * functions are only in Win16 (which doesn't have paths) and that
422      * SetDCState doesn't allow us to signal an error (which can happen
423      * when copying paths).
424      */
425     if (!PATH_AssignGdiPath( &dcs->w.path, &dc->w.path ))
426     {
427         GDI_HEAP_UNLOCK( hdc );
428         GDI_HEAP_UNLOCK( hdcs );
429         DeleteDC32( hdcs );
430         return 0;
431     }
432     
433     dcs->header.hNext = dc->header.hNext;
434     dc->header.hNext = hdcs;
435     TRACE(dc, "(%04x): returning %d\n", hdc, dc->saveLevel+1 );
436     ret = ++dc->saveLevel;
437     GDI_HEAP_UNLOCK( hdcs );
438     GDI_HEAP_UNLOCK( hdc );
439     return ret;
440 }
441
442
443 /***********************************************************************
444  *           RestoreDC16    (GDI.39)
445  */
446 BOOL16 WINAPI RestoreDC16( HDC16 hdc, INT16 level )
447 {
448     return RestoreDC32( hdc, level );
449 }
450
451
452 /***********************************************************************
453  *           RestoreDC32    (GDI32.290)
454  */
455 BOOL32 WINAPI RestoreDC32( HDC32 hdc, INT32 level )
456 {
457     DC * dc, * dcs;
458     BOOL32 success;
459
460     TRACE(dc, "%04x %d\n", hdc, level );
461     dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
462     if (!dc) 
463     {
464         dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
465         if (!dc) return FALSE;
466         if (level != -1) 
467         {
468           GDI_HEAP_UNLOCK( hdc );
469           return FALSE;
470         }
471         MF_MetaParam1(dc, META_RESTOREDC, level);
472         GDI_HEAP_UNLOCK( hdc );
473         return TRUE;
474     }
475     if (level == -1) level = dc->saveLevel;
476     if ((level < 1) || (level > dc->saveLevel))
477     {
478       GDI_HEAP_UNLOCK( hdc );
479       return FALSE;
480     }
481     
482     success=TRUE;
483     while (dc->saveLevel >= level)
484     {
485         HDC16 hdcs = dc->header.hNext;
486         if (!(dcs = (DC *) GDI_GetObjPtr( hdcs, DC_MAGIC )))
487         {
488           GDI_HEAP_UNLOCK( hdc );
489           return FALSE;
490         }       
491         dc->header.hNext = dcs->header.hNext;
492         if (--dc->saveLevel < level)
493         {
494             SetDCState( hdc, hdcs );
495             if (!PATH_AssignGdiPath( &dc->w.path, &dcs->w.path ))
496                 /* FIXME: This might not be quite right, since we're
497                  * returning FALSE but still destroying the saved DC state */
498                 success=FALSE;
499         }
500         DeleteDC32( hdcs );
501     }
502     GDI_HEAP_UNLOCK( hdc );
503     return success;
504 }
505
506
507 /***********************************************************************
508  *           CreateDC16    (GDI.53)
509  */
510 HDC16 WINAPI CreateDC16( LPCSTR driver, LPCSTR device, LPCSTR output,
511                          const DEVMODE16 *initData )
512 {
513     DC * dc;
514     const DC_FUNCTIONS *funcs;
515
516     if (!(funcs = DRIVER_FindDriver( driver ))) return 0;
517     if (!(dc = DC_AllocDC( funcs ))) return 0;
518     dc->w.flags = 0;
519
520     TRACE(dc, "(driver=%s, device=%s, output=%s): returning %04x\n",
521                debugstr_a(driver), debugstr_a(device), debugstr_a(output), dc->hSelf );
522
523     if (dc->funcs->pCreateDC &&
524         !dc->funcs->pCreateDC( dc, driver, device, output, initData ))
525     {
526         WARN(dc, "creation aborted by device\n" );
527         GDI_HEAP_FREE( dc->hSelf );
528         return 0;
529     }
530
531     DC_InitDC( dc );
532     GDI_HEAP_UNLOCK( dc->hSelf );
533     return dc->hSelf;
534 }
535
536
537 /***********************************************************************
538  *           CreateDC32A    (GDI32.)
539  */
540 HDC32 WINAPI CreateDC32A( LPCSTR driver, LPCSTR device, LPCSTR output,
541                           const DEVMODE32A *initData )
542 {
543     return CreateDC16( driver, device, output, (const DEVMODE16 *)initData );
544 }
545
546
547 /***********************************************************************
548  *           CreateDC32W    (GDI32.)
549  */
550 HDC32 WINAPI CreateDC32W( LPCWSTR driver, LPCWSTR device, LPCWSTR output,
551                           const DEVMODE32W *initData )
552
553     LPSTR driverA = HEAP_strdupWtoA( GetProcessHeap(), 0, driver );
554     LPSTR deviceA = HEAP_strdupWtoA( GetProcessHeap(), 0, device );
555     LPSTR outputA = HEAP_strdupWtoA( GetProcessHeap(), 0, output );
556     HDC32 res = CreateDC16( driverA, deviceA, outputA,
557                             (const DEVMODE16 *)initData /*FIXME*/ );
558     HeapFree( GetProcessHeap(), 0, driverA );
559     HeapFree( GetProcessHeap(), 0, deviceA );
560     HeapFree( GetProcessHeap(), 0, outputA );
561     return res;
562 }
563
564
565 /***********************************************************************
566  *           CreateIC16    (GDI.153)
567  */
568 HDC16 WINAPI CreateIC16( LPCSTR driver, LPCSTR device, LPCSTR output,
569                          const DEVMODE16* initData )
570 {
571       /* Nothing special yet for ICs */
572     return CreateDC16( driver, device, output, initData );
573 }
574
575
576 /***********************************************************************
577  *           CreateIC32A    (GDI32.49)
578  */
579 HDC32 WINAPI CreateIC32A( LPCSTR driver, LPCSTR device, LPCSTR output,
580                           const DEVMODE32A* initData )
581 {
582       /* Nothing special yet for ICs */
583     return CreateDC32A( driver, device, output, initData );
584 }
585
586
587 /***********************************************************************
588  *           CreateIC32W    (GDI32.50)
589  */
590 HDC32 WINAPI CreateIC32W( LPCWSTR driver, LPCWSTR device, LPCWSTR output,
591                           const DEVMODE32W* initData )
592 {
593       /* Nothing special yet for ICs */
594     return CreateDC32W( driver, device, output, initData );
595 }
596
597
598 /***********************************************************************
599  *           CreateCompatibleDC16    (GDI.52)
600  */
601 HDC16 WINAPI CreateCompatibleDC16( HDC16 hdc )
602 {
603     return (HDC16)CreateCompatibleDC32( hdc );
604 }
605
606
607 /***********************************************************************
608  *           CreateCompatibleDC32   (GDI32.31)
609  */
610 HDC32 WINAPI CreateCompatibleDC32( HDC32 hdc )
611 {
612     DC *dc, *origDC;
613     HBITMAP32 hbitmap;
614     const DC_FUNCTIONS *funcs;
615
616     if ((origDC = (DC *)GDI_GetObjPtr( hdc, DC_MAGIC ))) funcs = origDC->funcs;
617     else funcs = DRIVER_FindDriver( "DISPLAY" );
618     if (!funcs) return 0;
619
620     if (!(dc = DC_AllocDC( funcs ))) return 0;
621
622     TRACE(dc, "(%04x): returning %04x\n",
623                hdc, dc->hSelf );
624
625       /* Create default bitmap */
626     if (!(hbitmap = CreateBitmap32( 1, 1, 1, 1, NULL )))
627     {
628         GDI_HEAP_FREE( dc->hSelf );
629         return 0;
630     }
631     dc->w.flags        = DC_MEMORY;
632     dc->w.bitsPerPixel = 1;
633     dc->w.hBitmap      = hbitmap;
634     dc->w.hFirstBitmap = hbitmap;
635
636     if (dc->funcs->pCreateDC &&
637         !dc->funcs->pCreateDC( dc, NULL, NULL, NULL, NULL ))
638     {
639         WARN(dc, "creation aborted by device\n");
640         DeleteObject32( hbitmap );
641         GDI_HEAP_FREE( dc->hSelf );
642         return 0;
643     }
644
645     DC_InitDC( dc );
646     GDI_HEAP_UNLOCK( dc->hSelf );
647     return dc->hSelf;
648 }
649
650
651 /***********************************************************************
652  *           DeleteDC16    (GDI.68)
653  */
654 BOOL16 WINAPI DeleteDC16( HDC16 hdc )
655 {
656     return DeleteDC32( hdc );
657 }
658
659
660 /***********************************************************************
661  *           DeleteDC32    (GDI32.67)
662  */
663 BOOL32 WINAPI DeleteDC32( HDC32 hdc )
664 {
665     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
666     if (!dc) return FALSE;
667
668     TRACE(dc, "%04x\n", hdc );
669
670     while (dc->saveLevel)
671     {
672         DC * dcs;
673         HDC16 hdcs = dc->header.hNext;
674         if (!(dcs = (DC *) GDI_GetObjPtr( hdcs, DC_MAGIC ))) break;
675         dc->header.hNext = dcs->header.hNext;
676         dc->saveLevel--;
677         DeleteDC32( hdcs );
678     }
679     
680     if (!(dc->w.flags & DC_SAVED))
681     {
682         SelectObject32( hdc, STOCK_BLACK_PEN );
683         SelectObject32( hdc, STOCK_WHITE_BRUSH );
684         SelectObject32( hdc, STOCK_SYSTEM_FONT );
685         if (dc->w.flags & DC_MEMORY) DeleteObject32( dc->w.hFirstBitmap );
686         if (dc->funcs->pDeleteDC) dc->funcs->pDeleteDC(dc);
687     }
688
689     if (dc->w.hClipRgn) DeleteObject32( dc->w.hClipRgn );
690     if (dc->w.hVisRgn) DeleteObject32( dc->w.hVisRgn );
691     if (dc->w.hGCClipRgn) DeleteObject32( dc->w.hGCClipRgn );
692     
693     PATH_DestroyGdiPath(&dc->w.path);
694     
695     return GDI_FreeObject( hdc );
696 }
697
698
699 /***********************************************************************
700  *           ResetDC16    (GDI.376)
701  */
702 HDC16 WINAPI ResetDC16( HDC16 hdc, const DEVMODE16 *devmode )
703 {
704     FIXME(dc, "stub\n" );
705     return hdc;
706 }
707
708
709 /***********************************************************************
710  *           ResetDC32A    (GDI32.287)
711  */
712 HDC32 WINAPI ResetDC32A( HDC32 hdc, const DEVMODE32A *devmode )
713 {
714     FIXME(dc, "stub\n" );
715     return hdc;
716 }
717
718
719 /***********************************************************************
720  *           ResetDC32W    (GDI32.288)
721  */
722 HDC32 WINAPI ResetDC32W( HDC32 hdc, const DEVMODE32W *devmode )
723 {
724     FIXME(dc, "stub\n" );
725     return hdc;
726 }
727
728
729 /***********************************************************************
730  *           GetDeviceCaps16    (GDI.80)
731  */
732 INT16 WINAPI GetDeviceCaps16( HDC16 hdc, INT16 cap )
733 {
734     return GetDeviceCaps32( hdc, cap );
735 }
736
737
738 /***********************************************************************
739  *           GetDeviceCaps32    (GDI32.171)
740  */
741 INT32 WINAPI GetDeviceCaps32( HDC32 hdc, INT32 cap )
742 {
743     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
744     INT32 ret;
745
746     if (!dc) return 0;
747
748     if ((cap < 0) || (cap > sizeof(DeviceCaps)-sizeof(WORD)))
749     {
750       GDI_HEAP_UNLOCK( hdc );
751       return 0;
752     }
753     
754     TRACE(dc, "(%04x,%d): returning %d\n",
755             hdc, cap, *(WORD *)(((char *)dc->w.devCaps) + cap) );
756     ret = *(WORD *)(((char *)dc->w.devCaps) + cap);
757     GDI_HEAP_UNLOCK( hdc );
758     return ret;
759 }
760
761
762 /***********************************************************************
763  *           SetBkColor16    (GDI.1)
764  */
765 COLORREF WINAPI SetBkColor16( HDC16 hdc, COLORREF color )
766 {
767     return SetBkColor32( hdc, color );
768 }
769
770
771 /***********************************************************************
772  *           SetBkColor32    (GDI32.305)
773  */
774 COLORREF WINAPI SetBkColor32( HDC32 hdc, COLORREF color )
775 {
776     COLORREF oldColor;
777     DC * dc = DC_GetDCPtr( hdc );
778   
779     if (!dc) return 0x80000000;
780     if (dc->funcs->pSetBkColor)
781         oldColor = dc->funcs->pSetBkColor(dc, color);
782     else {
783         oldColor = dc->w.backgroundColor;
784         dc->w.backgroundColor = color;
785     }
786     GDI_HEAP_UNLOCK( hdc );
787     return oldColor;
788 }
789
790
791 /***********************************************************************
792  *           SetTextColor16    (GDI.9)
793  */
794 COLORREF WINAPI SetTextColor16( HDC16 hdc, COLORREF color )
795 {
796     return SetTextColor32( hdc, color );
797 }
798
799
800 /***********************************************************************
801  *           SetTextColor32    (GDI32.338)
802  */
803 COLORREF WINAPI SetTextColor32( HDC32 hdc, COLORREF color )
804 {
805     COLORREF oldColor;
806     DC * dc = DC_GetDCPtr( hdc );
807   
808     if (!dc) return 0x80000000;
809     if (dc->funcs->pSetTextColor)
810         oldColor = dc->funcs->pSetTextColor(dc, color);
811     else {
812         oldColor = dc->w.textColor;
813         dc->w.textColor = color;
814     }
815     GDI_HEAP_UNLOCK( hdc );
816     return oldColor;
817 }
818
819
820 /***********************************************************************
821  *           SetTextAlign16    (GDI.346)
822  */
823 UINT16 WINAPI SetTextAlign16( HDC16 hdc, UINT16 textAlign )
824 {
825     return SetTextAlign32( hdc, textAlign );
826 }
827
828
829 /***********************************************************************
830  *           SetTextAlign32    (GDI32.336)
831  */
832 UINT32 WINAPI SetTextAlign32( HDC32 hdc, UINT32 textAlign )
833 {
834     UINT32 prevAlign;
835     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
836     if (!dc)
837     {
838         if (!(dc = (DC *)GDI_GetObjPtr( hdc, METAFILE_DC_MAGIC ))) return 0;
839         MF_MetaParam1( dc, META_SETTEXTALIGN, textAlign );
840         GDI_HEAP_UNLOCK( hdc );
841         return 1;
842     }
843     prevAlign = dc->w.textAlign;
844     dc->w.textAlign = textAlign;
845     GDI_HEAP_UNLOCK( hdc );
846     return prevAlign;
847 }
848
849
850 /***********************************************************************
851  *           GetDCOrgEx  (GDI32.168)
852  */
853 BOOL32 WINAPI GetDCOrgEx( HDC32 hDC, LPPOINT32 lpp )
854 {
855     DC * dc;
856     X11DRV_PDEVICE *physDev;
857
858     if (!lpp) return FALSE;
859     if (!(dc = (DC *) GDI_GetObjPtr( hDC, DC_MAGIC ))) return FALSE;
860     physDev = (X11DRV_PDEVICE *)dc->physDev;
861
862     if (!(dc->w.flags & DC_MEMORY))
863     {
864        Window root;
865        int w, h, border, depth;
866        /* FIXME: this is not correct for managed windows */
867        TSXGetGeometry( display, physDev->drawable, &root,
868                     &lpp->x, &lpp->y, &w, &h, &border, &depth );
869     }
870     else lpp->x = lpp->y = 0;
871     lpp->x += dc->w.DCOrgX; lpp->y += dc->w.DCOrgY;
872     GDI_HEAP_UNLOCK( hDC );
873     return TRUE;
874 }
875
876
877 /***********************************************************************
878  *           GetDCOrg    (GDI.79)
879  */
880 DWORD WINAPI GetDCOrg( HDC16 hdc )
881 {
882     POINT32     pt;
883     if( GetDCOrgEx( hdc, &pt) )
884         return MAKELONG( (WORD)pt.x, (WORD)pt.y );    
885     return 0;
886 }
887
888
889 /***********************************************************************
890  *           SetDCOrg    (GDI.117)
891  */
892 DWORD WINAPI SetDCOrg( HDC16 hdc, INT16 x, INT16 y )
893 {
894     DWORD prevOrg;
895     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
896     if (!dc) return 0;
897     prevOrg = dc->w.DCOrgX | (dc->w.DCOrgY << 16);
898     dc->w.DCOrgX = x;
899     dc->w.DCOrgY = y;
900     GDI_HEAP_UNLOCK( hdc );
901     return prevOrg;
902 }
903
904
905 /***********************************************************************
906  *           GetGraphicsMode    (GDI32.188)
907  */
908 INT32 WINAPI GetGraphicsMode( HDC32 hdc )
909 {
910     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
911     if (!dc) return 0;
912     return dc->w.GraphicsMode;
913 }
914
915
916 /***********************************************************************
917  *           SetGraphicsMode    (GDI32.317)
918  */
919 INT32 WINAPI SetGraphicsMode( HDC32 hdc, INT32 mode )
920 {
921     INT32 ret;
922     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
923
924     /* One would think that setting the graphics mode to GM_COMPATIBLE
925      * would also reset the world transformation matrix to the unity
926      * matrix. However, in Windows, this is not the case. This doesn't
927      * make a lot of sense to me, but that's the way it is.
928      */
929     
930     if (!dc) return 0;
931     if ((mode <= 0) || (mode > GM_LAST)) return 0;
932     ret = dc->w.GraphicsMode;
933     dc->w.GraphicsMode = mode;
934     return ret;
935 }
936
937
938 /***********************************************************************
939  *           GetArcDirection16    (GDI.524)
940  */
941 INT16 WINAPI GetArcDirection16( HDC16 hdc )
942 {
943     return GetArcDirection32( (HDC32)hdc );
944 }
945
946
947 /***********************************************************************
948  *           GetArcDirection32    (GDI32.141)
949  */
950 INT32 WINAPI GetArcDirection32( HDC32 hdc )
951 {
952     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
953     
954     if (!dc)
955         return 0;
956
957     return dc->w.ArcDirection;
958 }
959
960
961 /***********************************************************************
962  *           SetArcDirection16    (GDI.525)
963  */
964 INT16 WINAPI SetArcDirection16( HDC16 hdc, INT16 nDirection )
965 {
966     return SetArcDirection32( (HDC32)hdc, (INT32)nDirection );
967 }
968
969
970 /***********************************************************************
971  *           SetArcDirection32    (GDI32.302)
972  */
973 INT32 WINAPI SetArcDirection32( HDC32 hdc, INT32 nDirection )
974 {
975     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
976     INT32 nOldDirection;
977     
978     if (!dc)
979         return 0;
980
981     if (nDirection!=AD_COUNTERCLOCKWISE && nDirection!=AD_CLOCKWISE)
982     {
983         SetLastError(ERROR_INVALID_PARAMETER);
984         return 0;
985     }
986
987     nOldDirection = dc->w.ArcDirection;
988     dc->w.ArcDirection = nDirection;
989
990     return nOldDirection;
991 }
992
993
994 /***********************************************************************
995  *           GetWorldTransform    (GDI32.244)
996  */
997 BOOL32 WINAPI GetWorldTransform( HDC32 hdc, LPXFORM xform )
998 {
999     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
1000     
1001     if (!dc)
1002         return FALSE;
1003     if (!xform)
1004         return FALSE;
1005
1006     *xform = dc->w.xformWorld2Wnd;
1007     
1008     return TRUE;
1009 }
1010
1011
1012 /***********************************************************************
1013  *           SetWorldTransform    (GDI32.346)
1014  */
1015 BOOL32 WINAPI SetWorldTransform( HDC32 hdc, const XFORM *xform )
1016 {
1017     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
1018     
1019     if (!dc)
1020     {
1021         SetLastError( ERROR_INVALID_HANDLE );
1022         return FALSE;
1023     }
1024
1025     if (!xform)
1026         return FALSE;
1027     
1028     /* Check that graphics mode is GM_ADVANCED */
1029     if (dc->w.GraphicsMode!=GM_ADVANCED)
1030        return FALSE;
1031
1032     dc->w.xformWorld2Wnd = *xform;
1033     
1034     DC_UpdateXforms( dc );
1035
1036     return TRUE;
1037 }
1038
1039
1040 /****************************************************************************
1041  * ModifyWorldTransform [GDI32.253]
1042  * Modifies the world transformation for a device context.
1043  *
1044  * PARAMS
1045  *    hdc   [I] Handle to device context
1046  *    xform [I] XFORM structure that will be used to modify the world
1047  *              transformation
1048  *    iMode [I] Specifies in what way to modify the world transformation
1049  *              Possible values:
1050  *              MWT_IDENTITY
1051  *                 Resets the world transformation to the identity matrix.
1052  *                 The parameter xform is ignored.
1053  *              MWT_LEFTMULTIPLY
1054  *                 Multiplies xform into the world transformation matrix from
1055  *                 the left.
1056  *              MWT_RIGHTMULTIPLY
1057  *                 Multiplies xform into the world transformation matrix from
1058  *                 the right.
1059  *
1060  * RETURNS STD
1061  */
1062 BOOL32 WINAPI ModifyWorldTransform( HDC32 hdc, const XFORM *xform,
1063     DWORD iMode )
1064 {
1065     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
1066     
1067     /* Check for illegal parameters */
1068     if (!dc)
1069     {
1070         SetLastError( ERROR_INVALID_HANDLE );
1071         return FALSE;
1072     }
1073     if (!xform)
1074         return FALSE;
1075     
1076     /* Check that graphics mode is GM_ADVANCED */
1077     if (dc->w.GraphicsMode!=GM_ADVANCED)
1078        return FALSE;
1079        
1080     switch (iMode)
1081     {
1082         case MWT_IDENTITY:
1083             dc->w.xformWorld2Wnd.eM11 = 1.0f;
1084             dc->w.xformWorld2Wnd.eM12 = 0.0f;
1085             dc->w.xformWorld2Wnd.eM21 = 0.0f;
1086             dc->w.xformWorld2Wnd.eM22 = 1.0f;
1087             dc->w.xformWorld2Wnd.eDx  = 0.0f;
1088             dc->w.xformWorld2Wnd.eDy  = 0.0f;
1089             break;
1090         case MWT_LEFTMULTIPLY:
1091             CombineTransform( &dc->w.xformWorld2Wnd, xform,
1092                 &dc->w.xformWorld2Wnd );
1093             break;
1094         case MWT_RIGHTMULTIPLY:
1095             CombineTransform( &dc->w.xformWorld2Wnd, &dc->w.xformWorld2Wnd,
1096                 xform );
1097             break;
1098         default:
1099             return FALSE;
1100     }
1101
1102     DC_UpdateXforms( dc );
1103
1104     return TRUE;
1105 }
1106
1107
1108 /****************************************************************************
1109  * CombineTransform [GDI32.20]
1110  * Combines two transformation matrices.
1111  *
1112  * PARAMS
1113  *    xformResult [O] Stores the result of combining the two matrices
1114  *    xform1      [I] Specifies the first matrix to apply
1115  *    xform2      [I] Specifies the second matrix to apply
1116  *
1117  * REMARKS
1118  *    The same matrix can be passed in for more than one of the parameters.
1119  *
1120  * RETURNS STD
1121  */
1122 BOOL32 WINAPI CombineTransform( LPXFORM xformResult, const XFORM *xform1,
1123     const XFORM *xform2 )
1124 {
1125     XFORM xformTemp;
1126     
1127     /* Check for illegal parameters */
1128     if (!xformResult || !xform1 || !xform2)
1129         return FALSE;
1130
1131     /* Create the result in a temporary XFORM, since xformResult may be
1132      * equal to xform1 or xform2 */
1133     xformTemp.eM11 = xform1->eM11 * xform2->eM11 +
1134                      xform1->eM12 * xform2->eM21;
1135     xformTemp.eM12 = xform1->eM11 * xform2->eM12 +
1136                      xform1->eM12 * xform2->eM22;
1137     xformTemp.eM21 = xform1->eM21 * xform2->eM11 +
1138                      xform1->eM22 * xform2->eM21;
1139     xformTemp.eM22 = xform1->eM21 * xform2->eM12 +
1140                      xform1->eM22 * xform2->eM22;
1141     xformTemp.eDx  = xform1->eDx  * xform2->eM11 +
1142                      xform1->eDy  * xform2->eM21 +
1143                      xform2->eDx;
1144     xformTemp.eDy  = xform1->eDx  * xform2->eM12 +
1145                      xform1->eDy  * xform2->eM22 +
1146                      xform2->eDy;
1147
1148     /* Copy the result to xformResult */
1149     *xformResult = xformTemp;
1150
1151     return TRUE;
1152 }
1153
1154
1155 /***********************************************************************
1156  *           SetDCHook   (GDI.190)
1157  */
1158 BOOL16 WINAPI SetDCHook( HDC16 hdc, FARPROC16 hookProc, DWORD dwHookData )
1159 {
1160     DC *dc = (DC *)GDI_GetObjPtr( hdc, DC_MAGIC );
1161
1162     TRACE(dc, "hookProc %08x, default is %08x\n",
1163                 (UINT32)hookProc, (UINT32)DCHook );
1164
1165     if (!dc) return FALSE;
1166     dc->hookProc = hookProc;
1167     dc->dwHookData = dwHookData;
1168     GDI_HEAP_UNLOCK( hdc );
1169     return TRUE;
1170 }
1171
1172
1173 /***********************************************************************
1174  *           GetDCHook   (GDI.191)
1175  */
1176 DWORD WINAPI GetDCHook( HDC16 hdc, FARPROC16 *phookProc )
1177 {
1178     DC *dc = (DC *)GDI_GetObjPtr( hdc, DC_MAGIC );
1179     if (!dc) return 0;
1180     *phookProc = dc->hookProc;
1181     GDI_HEAP_UNLOCK( hdc );
1182     return dc->dwHookData;
1183 }
1184
1185
1186 /***********************************************************************
1187  *           SetHookFlags       (GDI.192)
1188  */
1189 WORD WINAPI SetHookFlags(HDC16 hDC, WORD flags)
1190 {
1191     DC* dc = (DC*)GDI_GetObjPtr( hDC, DC_MAGIC );
1192
1193     if( dc )
1194     {
1195         WORD wRet = dc->w.flags & DC_DIRTY;
1196
1197         /* "Undocumented Windows" info is slightly confusing.
1198          */
1199
1200         TRACE(dc,"hDC %04x, flags %04x\n",hDC,flags);
1201
1202         if( flags & DCHF_INVALIDATEVISRGN )
1203             dc->w.flags |= DC_DIRTY;
1204         else if( flags & DCHF_VALIDATEVISRGN || !flags )
1205             dc->w.flags &= ~DC_DIRTY;
1206         GDI_HEAP_UNLOCK( hDC );
1207         return wRet;
1208     }
1209     return 0;
1210 }
1211
1212 /***********************************************************************
1213  *           SetICMMode    (GDI32.318)
1214  */
1215 INT32 WINAPI SetICMMode(HDC32 hdc, INT32 iEnableICM)
1216 {
1217 /*FIXME  Asuming 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 /***********************************************************************
1226  *           GetColorSpace    (GDI32.165)
1227  */
1228 HCOLORSPACE32 WINAPI GetColorSpace(HDC32 hdc)
1229 {
1230 /*FIXME    Need to to whatever GetColorSpace actually does */
1231     return 0;
1232 }
1233
1234 /***********************************************************************
1235  *           GetBoundsRect16    (GDI.194)
1236  */
1237 UINT16 WINAPI GetBoundsRect16(HDC16 hdc, LPRECT16 rect, UINT16 flags)
1238 {
1239     return DCB_RESET | DCB_DISABLE; /* bounding rectangle always empty and disabled*/
1240 }
1241
1242 /***********************************************************************
1243  *           SetBoundsRect16    (GDI.193)
1244  */
1245 UINT16 WINAPI SetBoundsRect16(HDC16 hdc, const RECT16* rect, UINT16 flags)
1246 {
1247     if ( (flags & DCB_ACCUMULATE) || (flags & DCB_ENABLE) )
1248         FIXME( dc, "(%04x, %p, %04x): stub\n", hdc, rect, flags );
1249
1250     return DCB_RESET | DCB_DISABLE; /* bounding rectangle always empty and disabled*/
1251 }
1252