Fixed bug in DIB_SetImageBits_RLE8 (because 'color' var was WORD, all
[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 "color.h"
15 #include "debug.h"
16 #include "font.h"
17 #include "winerror.h"
18 #include "x11font.h"
19
20   /* ROP code to GC function conversion */
21 const int DC_XROPfunction[16] =
22 {
23     GXclear,        /* R2_BLACK */
24     GXnor,          /* R2_NOTMERGEPEN */
25     GXandInverted,  /* R2_MASKNOTPEN */
26     GXcopyInverted, /* R2_NOTCOPYPEN */
27     GXandReverse,   /* R2_MASKPENNOT */
28     GXinvert,       /* R2_NOT */
29     GXxor,          /* R2_XORPEN */
30     GXnand,         /* R2_NOTMASKPEN */
31     GXand,          /* R2_MASKPEN */
32     GXequiv,        /* R2_NOTXORPEN */
33     GXnoop,         /* R2_NOP */
34     GXorInverted,   /* R2_MERGENOTPEN */
35     GXcopy,         /* R2_COPYPEN */
36     GXorReverse,    /* R2_MERGEPENNOT */
37     GXor,           /* R2_MERGEPEN */
38     GXset           /* R2_WHITE */
39 };
40
41
42 /***********************************************************************
43  *           DC_FillDevCaps
44  *
45  * Fill the device caps structure.
46  */
47 void DC_FillDevCaps( DeviceCaps * caps )
48 {
49     caps->version       = 0x300; 
50     caps->technology    = DT_RASDISPLAY;
51     caps->horzSize      = WidthMMOfScreen(screen) * screenWidth / WidthOfScreen(screen);
52     caps->vertSize      = HeightMMOfScreen(screen) * screenHeight / HeightOfScreen(screen);
53     caps->horzRes       = screenWidth;
54     caps->vertRes       = screenHeight;
55     caps->bitsPixel     = screenDepth;
56     caps->planes        = 1;
57     caps->numBrushes    = 16+6;  /* 16 solid + 6 hatched brushes */
58     caps->numPens       = 16;    /* 16 solid pens */
59     caps->numMarkers    = 0;
60     caps->numFonts      = 0;
61     caps->numColors     = 100;
62     caps->pdeviceSize   = 0;
63     caps->curveCaps     = CC_CIRCLES | CC_PIE | CC_CHORD | CC_ELLIPSES |
64                           CC_WIDE | CC_STYLED | CC_WIDESTYLED | 
65                           CC_INTERIORS | CC_ROUNDRECT;
66     caps->lineCaps      = LC_POLYLINE | LC_MARKER | LC_POLYMARKER | LC_WIDE |
67                           LC_STYLED | LC_WIDESTYLED | LC_INTERIORS;
68     caps->polygonalCaps = PC_POLYGON | PC_RECTANGLE | PC_WINDPOLYGON |
69                           PC_SCANLINE | PC_WIDE | PC_STYLED | 
70                           PC_WIDESTYLED | PC_INTERIORS;
71     caps->textCaps      = TC_OP_CHARACTER | TC_OP_STROKE | TC_CP_STROKE |
72                           TC_IA_ABLE | TC_UA_ABLE | TC_SO_ABLE | TC_RA_ABLE;
73     caps->clipCaps      = CP_REGION;
74     caps->rasterCaps    = RC_BITBLT | RC_BANDING | RC_SCALING | RC_BITMAP64 |
75                           RC_DI_BITMAP | RC_DIBTODEV | RC_BIGFONT|
76                           RC_STRETCHBLT | RC_STRETCHDIB | RC_DEVBITS;
77
78     if( !(COLOR_GetSystemPaletteFlags() & COLOR_VIRTUAL) )
79         caps->rasterCaps |= RC_PALETTE;
80
81     caps->aspectX       = 36;  /* ?? */
82     caps->aspectY       = 36;  /* ?? */
83     caps->aspectXY      = 51;
84     caps->logPixelsX    = (int)(caps->horzRes * 25.4 / caps->horzSize);
85     caps->logPixelsY    = (int)(caps->vertRes * 25.4 / caps->vertSize);
86     caps->sizePalette   = (caps->rasterCaps & RC_PALETTE)
87                           ? DefaultVisual(display,DefaultScreen(display))->map_entries
88                           : 0;
89     caps->numReserved   = 0;
90     caps->colorRes      = 0;
91 }
92
93
94 /***********************************************************************
95  *           DC_Init_DC_INFO
96  *
97  * Fill the WIN_DC_INFO structure.
98  */
99 static void DC_Init_DC_INFO( WIN_DC_INFO *win_dc_info )
100 {
101     win_dc_info->flags               = 0;
102     win_dc_info->devCaps             = NULL;
103     win_dc_info->hClipRgn            = 0;
104     win_dc_info->hVisRgn             = 0;
105     win_dc_info->hGCClipRgn          = 0;
106     win_dc_info->hPen                = STOCK_BLACK_PEN;
107     win_dc_info->hBrush              = STOCK_WHITE_BRUSH;
108     win_dc_info->hFont               = STOCK_SYSTEM_FONT;
109     win_dc_info->hBitmap             = 0;
110     win_dc_info->hFirstBitmap        = 0;
111     win_dc_info->hDevice             = 0;
112     win_dc_info->hPalette            = STOCK_DEFAULT_PALETTE;
113     win_dc_info->ROPmode             = R2_COPYPEN;
114     win_dc_info->polyFillMode        = ALTERNATE;
115     win_dc_info->stretchBltMode      = BLACKONWHITE;
116     win_dc_info->relAbsMode          = ABSOLUTE;
117     win_dc_info->backgroundMode      = OPAQUE;
118     win_dc_info->backgroundColor     = RGB( 255, 255, 255 );
119     win_dc_info->textColor           = RGB( 0, 0, 0 );
120     win_dc_info->brushOrgX           = 0;
121     win_dc_info->brushOrgY           = 0;
122     win_dc_info->textAlign           = TA_LEFT | TA_TOP | TA_NOUPDATECP;
123     win_dc_info->charExtra           = 0;
124     win_dc_info->breakTotalExtra     = 0;
125     win_dc_info->breakCount          = 0;
126     win_dc_info->breakExtra          = 0;
127     win_dc_info->breakRem            = 0;
128     win_dc_info->bitsPerPixel        = 1;
129     win_dc_info->MapMode             = MM_TEXT;
130     win_dc_info->GraphicsMode        = GM_COMPATIBLE;
131     win_dc_info->DCOrgX              = 0;
132     win_dc_info->DCOrgY              = 0;
133     win_dc_info->lpfnPrint           = NULL;
134     win_dc_info->CursPosX            = 0;
135     win_dc_info->CursPosY            = 0;
136     win_dc_info->ArcDirection        = AD_COUNTERCLOCKWISE;
137     win_dc_info->xformWorld2Wnd.eM11 = 1.0f;
138     win_dc_info->xformWorld2Wnd.eM12 = 0.0f;
139     win_dc_info->xformWorld2Wnd.eM21 = 0.0f;
140     win_dc_info->xformWorld2Wnd.eM22 = 1.0f;
141     win_dc_info->xformWorld2Wnd.eDx  = 0.0f;
142     win_dc_info->xformWorld2Wnd.eDy  = 0.0f;
143     win_dc_info->xformWorld2Vport    = win_dc_info->xformWorld2Wnd;
144     win_dc_info->xformVport2World    = win_dc_info->xformWorld2Wnd;
145     win_dc_info->vport2WorldValid    = TRUE;
146
147     PATH_InitGdiPath(&win_dc_info->path);
148 }
149
150
151 /***********************************************************************
152  *           DC_AllocDC
153  */
154 DC *DC_AllocDC( const DC_FUNCTIONS *funcs )
155 {
156     HDC16 hdc;
157     DC *dc;
158
159     if (!(hdc = GDI_AllocObject( sizeof(DC), DC_MAGIC ))) return NULL;
160     dc = (DC *) GDI_HEAP_LOCK( hdc );
161
162     dc->hSelf      = hdc;
163     dc->funcs      = funcs;
164     dc->physDev    = NULL;
165     dc->saveLevel  = 0;
166     dc->dwHookData = 0L;
167     dc->hookProc   = NULL;
168     dc->wndOrgX    = 0;
169     dc->wndOrgY    = 0;
170     dc->wndExtX    = 1;
171     dc->wndExtY    = 1;
172     dc->vportOrgX  = 0;
173     dc->vportOrgY  = 0;
174     dc->vportExtX  = 1;
175     dc->vportExtY  = 1;
176
177     DC_Init_DC_INFO( &dc->w );
178
179     return dc;
180 }
181
182
183
184 /***********************************************************************
185  *           DC_GetDCPtr
186  */
187 DC *DC_GetDCPtr( HDC32 hdc )
188 {
189     GDIOBJHDR *ptr = (GDIOBJHDR *)GDI_HEAP_LOCK( hdc );
190     if (!ptr) return NULL;
191     if ((ptr->wMagic == DC_MAGIC) || (ptr->wMagic == METAFILE_DC_MAGIC))
192         return (DC *)ptr;
193     GDI_HEAP_UNLOCK( hdc );
194     return NULL;
195 }
196
197
198 /***********************************************************************
199  *           DC_InitDC
200  *
201  * Setup device-specific DC values for a newly created DC.
202  */
203 void DC_InitDC( DC* dc )
204 {
205     RealizeDefaultPalette( dc->hSelf );
206     SetTextColor32( dc->hSelf, dc->w.textColor );
207     SetBkColor32( dc->hSelf, dc->w.backgroundColor );
208     SelectObject32( dc->hSelf, dc->w.hPen );
209     SelectObject32( dc->hSelf, dc->w.hBrush );
210     SelectObject32( dc->hSelf, dc->w.hFont );
211     CLIPPING_UpdateGCRegion( dc );
212 }
213
214
215 /***********************************************************************
216  *           DC_SetupGCForPatBlt
217  *
218  * Setup the GC for a PatBlt operation using current brush.
219  * If fMapColors is TRUE, X pixels are mapped to Windows colors.
220  * Return FALSE if brush is BS_NULL, TRUE otherwise.
221  */
222 BOOL32 DC_SetupGCForPatBlt( DC * dc, GC gc, BOOL32 fMapColors )
223 {
224     XGCValues val;
225     unsigned long mask;
226     Pixmap pixmap = 0;
227
228     if (dc->u.x.brush.style == BS_NULL) return FALSE;
229     if (dc->u.x.brush.pixel == -1)
230     {
231         /* Special case used for monochrome pattern brushes.
232          * We need to swap foreground and background because
233          * Windows does it the wrong way...
234          */
235         val.foreground = dc->u.x.backgroundPixel;
236         val.background = dc->u.x.textPixel;
237     }
238     else
239     {
240         val.foreground = dc->u.x.brush.pixel;
241         val.background = dc->u.x.backgroundPixel;
242     }
243     if (fMapColors && COLOR_PixelToPalette)
244     {
245         val.foreground = COLOR_PixelToPalette[val.foreground];
246         val.background = COLOR_PixelToPalette[val.background];
247     }
248
249     if (dc->w.flags & DC_DIRTY) CLIPPING_UpdateGCRegion(dc);
250
251     val.function = DC_XROPfunction[dc->w.ROPmode-1];
252     /*
253     ** Let's replace GXinvert by GXxor with (black xor white)
254     ** This solves the selection color and leak problems in excel
255     ** FIXME : Let's do that only if we work with X-pixels, not with Win-pixels
256     */
257     if (val.function == GXinvert)
258         {
259         val.foreground = BlackPixelOfScreen(screen) ^ WhitePixelOfScreen(screen);
260         val.function = GXxor;
261         }
262     val.fill_style = dc->u.x.brush.fillStyle;
263     switch(val.fill_style)
264     {
265     case FillStippled:
266     case FillOpaqueStippled:
267         if (dc->w.backgroundMode==OPAQUE) val.fill_style = FillOpaqueStippled;
268         val.stipple = dc->u.x.brush.pixmap;
269         mask = GCStipple;
270         break;
271
272     case FillTiled:
273         if (fMapColors && COLOR_PixelToPalette)
274         {
275             register int x, y;
276             XImage *image;
277             EnterCriticalSection( &X11DRV_CritSection );
278             pixmap = XCreatePixmap( display, rootWindow, 8, 8, screenDepth );
279             image = XGetImage( display, dc->u.x.brush.pixmap, 0, 0, 8, 8,
280                                AllPlanes, ZPixmap );
281             for (y = 0; y < 8; y++)
282                 for (x = 0; x < 8; x++)
283                     XPutPixel( image, x, y,
284                                COLOR_PixelToPalette[XGetPixel( image, x, y)] );
285             XPutImage( display, pixmap, gc, image, 0, 0, 0, 0, 8, 8 );
286             XDestroyImage( image );
287             LeaveCriticalSection( &X11DRV_CritSection );
288             val.tile = pixmap;
289         }
290         else val.tile = dc->u.x.brush.pixmap;
291         mask = GCTile;
292         break;
293
294     default:
295         mask = 0;
296         break;
297     }
298     val.ts_x_origin = dc->w.DCOrgX + dc->w.brushOrgX;
299     val.ts_y_origin = dc->w.DCOrgY + dc->w.brushOrgY;
300     val.fill_rule = (dc->w.polyFillMode==WINDING) ? WindingRule : EvenOddRule;
301     TSXChangeGC( display, gc, 
302                GCFunction | GCForeground | GCBackground | GCFillStyle |
303                GCFillRule | GCTileStipXOrigin | GCTileStipYOrigin | mask,
304                &val );
305     if (pixmap) TSXFreePixmap( display, pixmap );
306     return TRUE;
307 }
308
309
310 /***********************************************************************
311  *           DC_SetupGCForBrush
312  *
313  * Setup dc->u.x.gc for drawing operations using current brush.
314  * Return FALSE if brush is BS_NULL, TRUE otherwise.
315  */
316 BOOL32 DC_SetupGCForBrush( DC * dc )
317 {
318     return DC_SetupGCForPatBlt( dc, dc->u.x.gc, FALSE );
319 }
320
321
322 /***********************************************************************
323  *           DC_SetupGCForPen
324  *
325  * Setup dc->u.x.gc for drawing operations using current pen.
326  * Return FALSE if pen is PS_NULL, TRUE otherwise.
327  */
328 BOOL32 DC_SetupGCForPen( DC * dc )
329 {
330     XGCValues val;
331
332     if (dc->u.x.pen.style == PS_NULL) return FALSE;
333
334     if (dc->w.flags & DC_DIRTY) CLIPPING_UpdateGCRegion(dc); 
335
336     switch (dc->w.ROPmode)
337     {
338     case R2_BLACK :
339         val.foreground = BlackPixelOfScreen( screen );
340         val.function = GXcopy;
341         break;
342     case R2_WHITE :
343         val.foreground = WhitePixelOfScreen( screen );
344         val.function = GXcopy;
345         break;
346     case R2_XORPEN :
347         val.foreground = dc->u.x.pen.pixel;
348         /* It is very unlikely someone wants to XOR with 0 */
349         /* This fixes the rubber-drawings in paintbrush */
350         if (val.foreground == 0)
351             val.foreground = BlackPixelOfScreen( screen )
352                             ^ WhitePixelOfScreen( screen );
353         val.function = GXxor;
354         break;
355     default :
356         val.foreground = dc->u.x.pen.pixel;
357         val.function   = DC_XROPfunction[dc->w.ROPmode-1];
358     }
359     val.background = dc->u.x.backgroundPixel;
360     val.fill_style = FillSolid;
361     if ((dc->u.x.pen.style!=PS_SOLID) && (dc->u.x.pen.style!=PS_INSIDEFRAME))
362     {
363         TSXSetDashes( display, dc->u.x.gc, 0,
364                     dc->u.x.pen.dashes, dc->u.x.pen.dash_len );
365         val.line_style = (dc->w.backgroundMode == OPAQUE) ?
366                               LineDoubleDash : LineOnOffDash;
367     }
368     else val.line_style = LineSolid;
369     val.line_width = dc->u.x.pen.width;
370     if (val.line_width <= 1) {
371         val.cap_style = CapNotLast;
372     } else {
373         switch (dc->u.x.pen.endcap)
374         {
375         case PS_ENDCAP_SQUARE:
376             val.cap_style = CapProjecting;
377             break;
378         case PS_ENDCAP_FLAT:
379             val.cap_style = CapButt;
380             break;
381         case PS_ENDCAP_ROUND:
382         default:
383             val.cap_style = CapRound;
384         }
385     }
386     switch (dc->u.x.pen.linejoin)
387     {
388     case PS_JOIN_BEVEL:
389         val.join_style = JoinBevel;
390         break;
391     case PS_JOIN_MITER:
392         val.join_style = JoinMiter;
393         break;
394     case PS_JOIN_ROUND:
395     default:
396         val.join_style = JoinRound;
397     }
398     TSXChangeGC( display, dc->u.x.gc, 
399                GCFunction | GCForeground | GCBackground | GCLineWidth |
400                GCLineStyle | GCCapStyle | GCJoinStyle | GCFillStyle, &val );
401     return TRUE;
402 }
403
404
405 /***********************************************************************
406  *           DC_SetupGCForText
407  *
408  * Setup dc->u.x.gc for text drawing operations.
409  * Return FALSE if the font is null, TRUE otherwise.
410  */
411 BOOL32 DC_SetupGCForText( DC * dc )
412 {
413     XFontStruct* xfs = XFONT_GetFontStruct( dc->u.x.font );
414
415     if( xfs )
416     {
417         XGCValues val;
418
419         if (dc->w.flags & DC_DIRTY) CLIPPING_UpdateGCRegion(dc);
420
421         val.function   = GXcopy;  /* Text is always GXcopy */
422         val.foreground = dc->u.x.textPixel;
423         val.background = dc->u.x.backgroundPixel;
424         val.fill_style = FillSolid;
425         val.font       = xfs->fid;
426
427         TSXChangeGC( display, dc->u.x.gc,
428                    GCFunction | GCForeground | GCBackground | GCFillStyle |
429                    GCFont, &val );
430         return TRUE;
431     } 
432     WARN(dc, "Physical font failure\n" );
433     return FALSE;
434 }
435
436
437 /***********************************************************************
438  *           DC_InvertXform
439  *
440  * Computes the inverse of the transformation xformSrc and stores it to
441  * xformDest. Returns TRUE if successful or FALSE if the xformSrc matrix
442  * is singular.
443  */
444 static BOOL32 DC_InvertXform( const XFORM *xformSrc, XFORM *xformDest )
445 {
446     FLOAT determinant;
447     
448     determinant = xformSrc->eM11*xformSrc->eM22 -
449         xformSrc->eM12*xformSrc->eM21;
450     if (determinant > -1e-12 && determinant < 1e-12)
451         return FALSE;
452
453     xformDest->eM11 =  xformSrc->eM22 / determinant;
454     xformDest->eM12 = -xformSrc->eM12 / determinant;
455     xformDest->eM21 = -xformSrc->eM21 / determinant;
456     xformDest->eM22 =  xformSrc->eM11 / determinant;
457     xformDest->eDx  = -xformSrc->eDx * xformDest->eM11 -
458                        xformSrc->eDy * xformDest->eM21;
459     xformDest->eDy  = -xformSrc->eDx * xformDest->eM12 -
460                        xformSrc->eDy * xformDest->eM22;
461
462     return TRUE;
463 }
464
465
466 /***********************************************************************
467  *           DC_UpdateXforms
468  *
469  * Updates the xformWorld2Vport, xformVport2World and vport2WorldValid
470  * fields of the specified DC by creating a transformation that
471  * represents the current mapping mode and combining it with the DC's
472  * world transform. This function should be called whenever the
473  * parameters associated with the mapping mode (window and viewport
474  * extents and origins) or the world transform change.
475  */
476 void DC_UpdateXforms( DC *dc )
477 {
478     XFORM xformWnd2Vport;
479     FLOAT scaleX, scaleY;
480     
481     /* Construct a transformation to do the window-to-viewport conversion */
482     scaleX = (FLOAT)dc->vportExtX / (FLOAT)dc->wndExtX;
483     scaleY = (FLOAT)dc->vportExtY / (FLOAT)dc->wndExtY;
484     xformWnd2Vport.eM11 = scaleX;
485     xformWnd2Vport.eM12 = 0.0;
486     xformWnd2Vport.eM21 = 0.0;
487     xformWnd2Vport.eM22 = scaleY;
488     xformWnd2Vport.eDx  = (FLOAT)dc->vportOrgX -
489         scaleX * (FLOAT)dc->wndOrgX;
490     xformWnd2Vport.eDy  = (FLOAT)dc->vportOrgY -
491         scaleY * (FLOAT)dc->wndOrgY;
492
493     /* Combine with the world transformation */
494     CombineTransform( &dc->w.xformWorld2Vport, &dc->w.xformWorld2Wnd,
495         &xformWnd2Vport );
496
497     /* Create inverse of world-to-viewport transformation */
498     dc->w.vport2WorldValid = DC_InvertXform( &dc->w.xformWorld2Vport,
499         &dc->w.xformVport2World );
500 }
501
502
503 /***********************************************************************
504  *           GetDCState    (GDI.179)
505  */
506 HDC16 WINAPI GetDCState( HDC16 hdc )
507 {
508     DC * newdc, * dc;
509     HGDIOBJ16 handle;
510     
511     if (!(dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ))) return 0;
512     if (!(handle = GDI_AllocObject( sizeof(DC), DC_MAGIC )))
513     {
514       GDI_HEAP_UNLOCK( hdc );
515       return 0;
516     }
517     newdc = (DC *) GDI_HEAP_LOCK( handle );
518
519     TRACE(dc, "(%04x): returning %04x\n", hdc, handle );
520
521     memset( &newdc->u.x, 0, sizeof(newdc->u.x) );
522     newdc->w.flags            = dc->w.flags | DC_SAVED;
523     newdc->w.devCaps          = dc->w.devCaps;
524     newdc->w.hPen             = dc->w.hPen;       
525     newdc->w.hBrush           = dc->w.hBrush;     
526     newdc->w.hFont            = dc->w.hFont;      
527     newdc->w.hBitmap          = dc->w.hBitmap;    
528     newdc->w.hFirstBitmap     = dc->w.hFirstBitmap;
529     newdc->w.hDevice          = dc->w.hDevice;
530     newdc->w.hPalette         = dc->w.hPalette;   
531     newdc->w.totalExtent      = dc->w.totalExtent;
532     newdc->w.bitsPerPixel     = dc->w.bitsPerPixel;
533     newdc->w.ROPmode          = dc->w.ROPmode;
534     newdc->w.polyFillMode     = dc->w.polyFillMode;
535     newdc->w.stretchBltMode   = dc->w.stretchBltMode;
536     newdc->w.relAbsMode       = dc->w.relAbsMode;
537     newdc->w.backgroundMode   = dc->w.backgroundMode;
538     newdc->w.backgroundColor  = dc->w.backgroundColor;
539     newdc->w.textColor        = dc->w.textColor;
540     newdc->w.brushOrgX        = dc->w.brushOrgX;
541     newdc->w.brushOrgY        = dc->w.brushOrgY;
542     newdc->w.textAlign        = dc->w.textAlign;
543     newdc->w.charExtra        = dc->w.charExtra;
544     newdc->w.breakTotalExtra  = dc->w.breakTotalExtra;
545     newdc->w.breakCount       = dc->w.breakCount;
546     newdc->w.breakExtra       = dc->w.breakExtra;
547     newdc->w.breakRem         = dc->w.breakRem;
548     newdc->w.MapMode          = dc->w.MapMode;
549     newdc->w.GraphicsMode     = dc->w.GraphicsMode;
550 #if 0
551     /* Apparently, the DC origin is not changed by [GS]etDCState */
552     newdc->w.DCOrgX           = dc->w.DCOrgX;
553     newdc->w.DCOrgY           = dc->w.DCOrgY;
554 #endif
555     newdc->w.CursPosX         = dc->w.CursPosX;
556     newdc->w.CursPosY         = dc->w.CursPosY;
557     newdc->w.ArcDirection     = dc->w.ArcDirection;
558     newdc->w.xformWorld2Wnd   = dc->w.xformWorld2Wnd;
559     newdc->w.xformWorld2Vport = dc->w.xformWorld2Vport;
560     newdc->w.xformVport2World = dc->w.xformVport2World;
561     newdc->w.vport2WorldValid = dc->w.vport2WorldValid;
562     newdc->wndOrgX            = dc->wndOrgX;
563     newdc->wndOrgY            = dc->wndOrgY;
564     newdc->wndExtX            = dc->wndExtX;
565     newdc->wndExtY            = dc->wndExtY;
566     newdc->vportOrgX          = dc->vportOrgX;
567     newdc->vportOrgY          = dc->vportOrgY;
568     newdc->vportExtX          = dc->vportExtX;
569     newdc->vportExtY          = dc->vportExtY;
570
571     newdc->hSelf = (HDC32)handle;
572     newdc->saveLevel = 0;
573
574     PATH_InitGdiPath( &newdc->w.path );
575     
576     /* Get/SetDCState() don't change hVisRgn field ("Undoc. Windows" p.559). */
577
578     newdc->w.hGCClipRgn = newdc->w.hVisRgn = 0;
579     if (dc->w.hClipRgn)
580     {
581         newdc->w.hClipRgn = CreateRectRgn32( 0, 0, 0, 0 );
582         CombineRgn32( newdc->w.hClipRgn, dc->w.hClipRgn, 0, RGN_COPY );
583     }
584     else
585         newdc->w.hClipRgn = 0;
586     GDI_HEAP_UNLOCK( handle );
587     GDI_HEAP_UNLOCK( hdc );
588     return handle;
589 }
590
591
592 /***********************************************************************
593  *           SetDCState    (GDI.180)
594  */
595 void WINAPI SetDCState( HDC16 hdc, HDC16 hdcs )
596 {
597     DC *dc, *dcs;
598     
599     if (!(dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ))) return;
600     if (!(dcs = (DC *) GDI_GetObjPtr( hdcs, DC_MAGIC )))
601     {
602       GDI_HEAP_UNLOCK( hdc );
603       return;
604     }
605     if (!dcs->w.flags & DC_SAVED)
606     {
607       GDI_HEAP_UNLOCK( hdc );
608       GDI_HEAP_UNLOCK( hdcs );
609       return;
610     }
611     TRACE(dc, "%04x %04x\n", hdc, hdcs );
612
613     dc->w.flags            = dcs->w.flags & ~DC_SAVED;
614     dc->w.devCaps          = dcs->w.devCaps;
615     dc->w.hFirstBitmap     = dcs->w.hFirstBitmap;
616     dc->w.hDevice          = dcs->w.hDevice;
617     dc->w.totalExtent      = dcs->w.totalExtent;
618     dc->w.ROPmode          = dcs->w.ROPmode;
619     dc->w.polyFillMode     = dcs->w.polyFillMode;
620     dc->w.stretchBltMode   = dcs->w.stretchBltMode;
621     dc->w.relAbsMode       = dcs->w.relAbsMode;
622     dc->w.backgroundMode   = dcs->w.backgroundMode;
623     dc->w.backgroundColor  = dcs->w.backgroundColor;
624     dc->w.textColor        = dcs->w.textColor;
625     dc->w.brushOrgX        = dcs->w.brushOrgX;
626     dc->w.brushOrgY        = dcs->w.brushOrgY;
627     dc->w.textAlign        = dcs->w.textAlign;
628     dc->w.charExtra        = dcs->w.charExtra;
629     dc->w.breakTotalExtra  = dcs->w.breakTotalExtra;
630     dc->w.breakCount       = dcs->w.breakCount;
631     dc->w.breakExtra       = dcs->w.breakExtra;
632     dc->w.breakRem         = dcs->w.breakRem;
633     dc->w.MapMode          = dcs->w.MapMode;
634     dc->w.GraphicsMode     = dcs->w.GraphicsMode;
635 #if 0
636     /* Apparently, the DC origin is not changed by [GS]etDCState */
637     dc->w.DCOrgX           = dcs->w.DCOrgX;
638     dc->w.DCOrgY           = dcs->w.DCOrgY;
639 #endif
640     dc->w.CursPosX         = dcs->w.CursPosX;
641     dc->w.CursPosY         = dcs->w.CursPosY;
642     dc->w.ArcDirection     = dcs->w.ArcDirection;
643     dc->w.xformWorld2Wnd   = dcs->w.xformWorld2Wnd;
644     dc->w.xformWorld2Vport = dcs->w.xformWorld2Vport;
645     dc->w.xformVport2World = dcs->w.xformVport2World;
646     dc->w.vport2WorldValid = dcs->w.vport2WorldValid;
647
648     dc->wndOrgX            = dcs->wndOrgX;
649     dc->wndOrgY            = dcs->wndOrgY;
650     dc->wndExtX            = dcs->wndExtX;
651     dc->wndExtY            = dcs->wndExtY;
652     dc->vportOrgX          = dcs->vportOrgX;
653     dc->vportOrgY          = dcs->vportOrgY;
654     dc->vportExtX          = dcs->vportExtX;
655     dc->vportExtY          = dcs->vportExtY;
656
657     if (!(dc->w.flags & DC_MEMORY)) dc->w.bitsPerPixel = dcs->w.bitsPerPixel;
658
659     if (dcs->w.hClipRgn)
660     {
661         if (!dc->w.hClipRgn) dc->w.hClipRgn = CreateRectRgn32( 0, 0, 0, 0 );
662         CombineRgn32( dc->w.hClipRgn, dcs->w.hClipRgn, 0, RGN_COPY );
663         CLIPPING_UpdateGCRegion( dc );
664     }
665     else
666         dc->w.hClipRgn = 0;
667
668     SelectObject32( hdc, dcs->w.hBitmap );
669     SelectObject32( hdc, dcs->w.hBrush );
670     SelectObject32( hdc, dcs->w.hFont );
671     SelectObject32( hdc, dcs->w.hPen );
672     SetBkColor32( hdc, dcs->w.backgroundColor);
673     SetTextColor32( hdc, dcs->w.textColor);
674     GDISelectPalette( hdc, dcs->w.hPalette, FALSE );
675     GDI_HEAP_UNLOCK( hdc );
676     GDI_HEAP_UNLOCK( hdcs );
677 }
678
679
680 /***********************************************************************
681  *           SaveDC16    (GDI.30)
682  */
683 INT16 WINAPI SaveDC16( HDC16 hdc )
684 {
685     return (INT16)SaveDC32( hdc );
686 }
687
688
689 /***********************************************************************
690  *           SaveDC32    (GDI32.292)
691  */
692 INT32 WINAPI SaveDC32( HDC32 hdc )
693 {
694     HDC32 hdcs;
695     DC * dc, * dcs;
696     INT32 ret;
697
698     dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
699     if (!dc) 
700     {
701         dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
702         if (!dc) return 0;
703         MF_MetaParam0(dc, META_SAVEDC);
704         GDI_HEAP_UNLOCK( hdc );
705         return 1;  /* ?? */
706     }
707     if (!(hdcs = GetDCState( hdc )))
708     {
709       GDI_HEAP_UNLOCK( hdc );
710       return 0;
711     }
712     dcs = (DC *) GDI_HEAP_LOCK( hdcs );
713
714     /* Copy path. The reason why path saving / restoring is in SaveDC/
715      * RestoreDC and not in GetDCState/SetDCState is that the ...DCState
716      * functions are only in Win16 (which doesn't have paths) and that
717      * SetDCState doesn't allow us to signal an error (which can happen
718      * when copying paths).
719      */
720     if (!PATH_AssignGdiPath( &dcs->w.path, &dc->w.path ))
721     {
722         GDI_HEAP_UNLOCK( hdc );
723         GDI_HEAP_UNLOCK( hdcs );
724         DeleteDC32( hdcs );
725         return 0;
726     }
727     
728     dcs->header.hNext = dc->header.hNext;
729     dc->header.hNext = hdcs;
730     TRACE(dc, "(%04x): returning %d\n", hdc, dc->saveLevel+1 );
731     ret = ++dc->saveLevel;
732     GDI_HEAP_UNLOCK( hdcs );
733     GDI_HEAP_UNLOCK( hdc );
734     return ret;
735 }
736
737
738 /***********************************************************************
739  *           RestoreDC16    (GDI.39)
740  */
741 BOOL16 WINAPI RestoreDC16( HDC16 hdc, INT16 level )
742 {
743     return RestoreDC32( hdc, level );
744 }
745
746
747 /***********************************************************************
748  *           RestoreDC32    (GDI32.290)
749  */
750 BOOL32 WINAPI RestoreDC32( HDC32 hdc, INT32 level )
751 {
752     DC * dc, * dcs;
753     BOOL32 success;
754
755     TRACE(dc, "%04x %d\n", hdc, level );
756     dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
757     if (!dc) 
758     {
759         dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
760         if (!dc) return FALSE;
761         if (level != -1) 
762         {
763           GDI_HEAP_UNLOCK( hdc );
764           return FALSE;
765         }
766         MF_MetaParam1(dc, META_RESTOREDC, level);
767         GDI_HEAP_UNLOCK( hdc );
768         return TRUE;
769     }
770     if (level == -1) level = dc->saveLevel;
771     if ((level < 1) || (level > dc->saveLevel))
772     {
773       GDI_HEAP_UNLOCK( hdc );
774       return FALSE;
775     }
776     
777     success=TRUE;
778     while (dc->saveLevel >= level)
779     {
780         HDC16 hdcs = dc->header.hNext;
781         if (!(dcs = (DC *) GDI_GetObjPtr( hdcs, DC_MAGIC )))
782         {
783           GDI_HEAP_UNLOCK( hdc );
784           return FALSE;
785         }       
786         dc->header.hNext = dcs->header.hNext;
787         if (--dc->saveLevel < level)
788         {
789             SetDCState( hdc, hdcs );
790             if (!PATH_AssignGdiPath( &dc->w.path, &dcs->w.path ))
791                 /* FIXME: This might not be quite right, since we're
792                  * returning FALSE but still destroying the saved DC state */
793                 success=FALSE;
794         }
795         DeleteDC32( hdcs );
796     }
797     GDI_HEAP_UNLOCK( hdc );
798     return success;
799 }
800
801
802 /***********************************************************************
803  *           CreateDC16    (GDI.53)
804  */
805 HDC16 WINAPI CreateDC16( LPCSTR driver, LPCSTR device, LPCSTR output,
806                          const DEVMODE16 *initData )
807 {
808     DC * dc;
809     const DC_FUNCTIONS *funcs;
810
811     if (!(funcs = DRIVER_FindDriver( driver ))) return 0;
812     if (!(dc = DC_AllocDC( funcs ))) return 0;
813     dc->w.flags = 0;
814
815     TRACE(dc, "(driver=%s, device=%s, output=%s): returning %04x\n",
816                debugstr_a(driver), debugstr_a(device), debugstr_a(output), dc->hSelf );
817
818     if (dc->funcs->pCreateDC &&
819         !dc->funcs->pCreateDC( dc, driver, device, output, initData ))
820     {
821         WARN(dc, "creation aborted by device\n" );
822         GDI_HEAP_FREE( dc->hSelf );
823         return 0;
824     }
825
826     DC_InitDC( dc );
827     GDI_HEAP_UNLOCK( dc->hSelf );
828     return dc->hSelf;
829 }
830
831
832 /***********************************************************************
833  *           CreateDC32A    (GDI32.)
834  */
835 HDC32 WINAPI CreateDC32A( LPCSTR driver, LPCSTR device, LPCSTR output,
836                           const DEVMODE32A *initData )
837 {
838     return CreateDC16( driver, device, output, (const DEVMODE16 *)initData );
839 }
840
841
842 /***********************************************************************
843  *           CreateDC32W    (GDI32.)
844  */
845 HDC32 WINAPI CreateDC32W( LPCWSTR driver, LPCWSTR device, LPCWSTR output,
846                           const DEVMODE32W *initData )
847
848     LPSTR driverA = HEAP_strdupWtoA( GetProcessHeap(), 0, driver );
849     LPSTR deviceA = HEAP_strdupWtoA( GetProcessHeap(), 0, device );
850     LPSTR outputA = HEAP_strdupWtoA( GetProcessHeap(), 0, output );
851     HDC32 res = CreateDC16( driverA, deviceA, outputA,
852                             (const DEVMODE16 *)initData /*FIXME*/ );
853     HeapFree( GetProcessHeap(), 0, driverA );
854     HeapFree( GetProcessHeap(), 0, deviceA );
855     HeapFree( GetProcessHeap(), 0, outputA );
856     return res;
857 }
858
859
860 /***********************************************************************
861  *           CreateIC16    (GDI.153)
862  */
863 HDC16 WINAPI CreateIC16( LPCSTR driver, LPCSTR device, LPCSTR output,
864                          const DEVMODE16* initData )
865 {
866       /* Nothing special yet for ICs */
867     return CreateDC16( driver, device, output, initData );
868 }
869
870
871 /***********************************************************************
872  *           CreateIC32A    (GDI32.49)
873  */
874 HDC32 WINAPI CreateIC32A( LPCSTR driver, LPCSTR device, LPCSTR output,
875                           const DEVMODE32A* initData )
876 {
877       /* Nothing special yet for ICs */
878     return CreateDC32A( driver, device, output, initData );
879 }
880
881
882 /***********************************************************************
883  *           CreateIC32W    (GDI32.50)
884  */
885 HDC32 WINAPI CreateIC32W( LPCWSTR driver, LPCWSTR device, LPCWSTR output,
886                           const DEVMODE32W* initData )
887 {
888       /* Nothing special yet for ICs */
889     return CreateDC32W( driver, device, output, initData );
890 }
891
892
893 /***********************************************************************
894  *           CreateCompatibleDC16    (GDI.52)
895  */
896 HDC16 WINAPI CreateCompatibleDC16( HDC16 hdc )
897 {
898     return (HDC16)CreateCompatibleDC32( hdc );
899 }
900
901
902 /***********************************************************************
903  *           CreateCompatibleDC32   (GDI32.31)
904  */
905 HDC32 WINAPI CreateCompatibleDC32( HDC32 hdc )
906 {
907     DC *dc, *origDC;
908     HBITMAP32 hbitmap;
909     const DC_FUNCTIONS *funcs;
910
911     if ((origDC = (DC *)GDI_GetObjPtr( hdc, DC_MAGIC ))) funcs = origDC->funcs;
912     else funcs = DRIVER_FindDriver( "DISPLAY" );
913     if (!funcs) return 0;
914
915     if (!(dc = DC_AllocDC( funcs ))) return 0;
916
917     TRACE(dc, "(%04x): returning %04x\n",
918                hdc, dc->hSelf );
919
920       /* Create default bitmap */
921     if (!(hbitmap = CreateBitmap32( 1, 1, 1, 1, NULL )))
922     {
923         GDI_HEAP_FREE( dc->hSelf );
924         return 0;
925     }
926     dc->w.flags        = DC_MEMORY;
927     dc->w.bitsPerPixel = 1;
928     dc->w.hBitmap      = hbitmap;
929     dc->w.hFirstBitmap = hbitmap;
930
931     if (dc->funcs->pCreateDC &&
932         !dc->funcs->pCreateDC( dc, NULL, NULL, NULL, NULL ))
933     {
934         WARN(dc, "creation aborted by device\n");
935         DeleteObject32( hbitmap );
936         GDI_HEAP_FREE( dc->hSelf );
937         return 0;
938     }
939
940     DC_InitDC( dc );
941     GDI_HEAP_UNLOCK( dc->hSelf );
942     return dc->hSelf;
943 }
944
945
946 /***********************************************************************
947  *           DeleteDC16    (GDI.68)
948  */
949 BOOL16 WINAPI DeleteDC16( HDC16 hdc )
950 {
951     return DeleteDC32( hdc );
952 }
953
954
955 /***********************************************************************
956  *           DeleteDC32    (GDI32.67)
957  */
958 BOOL32 WINAPI DeleteDC32( HDC32 hdc )
959 {
960     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
961     if (!dc) return FALSE;
962
963     TRACE(dc, "%04x\n", hdc );
964
965     while (dc->saveLevel)
966     {
967         DC * dcs;
968         HDC16 hdcs = dc->header.hNext;
969         if (!(dcs = (DC *) GDI_GetObjPtr( hdcs, DC_MAGIC ))) break;
970         dc->header.hNext = dcs->header.hNext;
971         dc->saveLevel--;
972         DeleteDC32( hdcs );
973     }
974     
975     if (!(dc->w.flags & DC_SAVED))
976     {
977         SelectObject32( hdc, STOCK_BLACK_PEN );
978         SelectObject32( hdc, STOCK_WHITE_BRUSH );
979         SelectObject32( hdc, STOCK_SYSTEM_FONT );
980         if (dc->w.flags & DC_MEMORY) DeleteObject32( dc->w.hFirstBitmap );
981         if (dc->funcs->pDeleteDC) dc->funcs->pDeleteDC(dc);
982     }
983
984     if (dc->w.hClipRgn) DeleteObject32( dc->w.hClipRgn );
985     if (dc->w.hVisRgn) DeleteObject32( dc->w.hVisRgn );
986     if (dc->w.hGCClipRgn) DeleteObject32( dc->w.hGCClipRgn );
987     
988     PATH_DestroyGdiPath(&dc->w.path);
989     
990     return GDI_FreeObject( hdc );
991 }
992
993
994 /***********************************************************************
995  *           ResetDC16    (GDI.376)
996  */
997 HDC16 WINAPI ResetDC16( HDC16 hdc, const DEVMODE16 *devmode )
998 {
999     FIXME(dc, "stub\n" );
1000     return hdc;
1001 }
1002
1003
1004 /***********************************************************************
1005  *           ResetDC32A    (GDI32.287)
1006  */
1007 HDC32 WINAPI ResetDC32A( HDC32 hdc, const DEVMODE32A *devmode )
1008 {
1009     FIXME(dc, "stub\n" );
1010     return hdc;
1011 }
1012
1013
1014 /***********************************************************************
1015  *           ResetDC32W    (GDI32.288)
1016  */
1017 HDC32 WINAPI ResetDC32W( HDC32 hdc, const DEVMODE32W *devmode )
1018 {
1019     FIXME(dc, "stub\n" );
1020     return hdc;
1021 }
1022
1023
1024 /***********************************************************************
1025  *           GetDeviceCaps16    (GDI.80)
1026  */
1027 INT16 WINAPI GetDeviceCaps16( HDC16 hdc, INT16 cap )
1028 {
1029     return GetDeviceCaps32( hdc, cap );
1030 }
1031
1032
1033 /***********************************************************************
1034  *           GetDeviceCaps32    (GDI32.171)
1035  */
1036 INT32 WINAPI GetDeviceCaps32( HDC32 hdc, INT32 cap )
1037 {
1038     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
1039     INT32 ret;
1040
1041     if (!dc) return 0;
1042
1043     if ((cap < 0) || (cap > sizeof(DeviceCaps)-sizeof(WORD)))
1044     {
1045       GDI_HEAP_UNLOCK( hdc );
1046       return 0;
1047     }
1048     
1049     TRACE(dc, "(%04x,%d): returning %d\n",
1050             hdc, cap, *(WORD *)(((char *)dc->w.devCaps) + cap) );
1051     ret = *(WORD *)(((char *)dc->w.devCaps) + cap);
1052     GDI_HEAP_UNLOCK( hdc );
1053     return ret;
1054 }
1055
1056
1057 /***********************************************************************
1058  *           SetBkColor16    (GDI.1)
1059  */
1060 COLORREF WINAPI SetBkColor16( HDC16 hdc, COLORREF color )
1061 {
1062     return SetBkColor32( hdc, color );
1063 }
1064
1065
1066 /***********************************************************************
1067  *           SetBkColor32    (GDI32.305)
1068  */
1069 COLORREF WINAPI SetBkColor32( HDC32 hdc, COLORREF color )
1070 {
1071     COLORREF oldColor;
1072     DC * dc = DC_GetDCPtr( hdc );
1073   
1074     if (!dc) return 0x80000000;
1075     if (dc->funcs->pSetBkColor)
1076         oldColor = dc->funcs->pSetBkColor(dc, color);
1077     else {
1078         oldColor = dc->w.backgroundColor;
1079         dc->w.backgroundColor = color;
1080     }
1081     GDI_HEAP_UNLOCK( hdc );
1082     return oldColor;
1083 }
1084
1085
1086 /***********************************************************************
1087  *           SetTextColor16    (GDI.9)
1088  */
1089 COLORREF WINAPI SetTextColor16( HDC16 hdc, COLORREF color )
1090 {
1091     return SetTextColor32( hdc, color );
1092 }
1093
1094
1095 /***********************************************************************
1096  *           SetTextColor32    (GDI32.338)
1097  */
1098 COLORREF WINAPI SetTextColor32( HDC32 hdc, COLORREF color )
1099 {
1100     COLORREF oldColor;
1101     DC * dc = DC_GetDCPtr( hdc );
1102   
1103     if (!dc) return 0x80000000;
1104     if (dc->funcs->pSetTextColor)
1105         oldColor = dc->funcs->pSetTextColor(dc, color);
1106     else {
1107         oldColor = dc->w.textColor;
1108         dc->w.textColor = color;
1109     }
1110     GDI_HEAP_UNLOCK( hdc );
1111     return oldColor;
1112 }
1113
1114
1115 /***********************************************************************
1116  *           SetTextAlign16    (GDI.346)
1117  */
1118 UINT16 WINAPI SetTextAlign16( HDC16 hdc, UINT16 textAlign )
1119 {
1120     return SetTextAlign32( hdc, textAlign );
1121 }
1122
1123
1124 /***********************************************************************
1125  *           SetTextAlign32    (GDI32.336)
1126  */
1127 UINT32 WINAPI SetTextAlign32( HDC32 hdc, UINT32 textAlign )
1128 {
1129     UINT32 prevAlign;
1130     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
1131     if (!dc)
1132     {
1133         if (!(dc = (DC *)GDI_GetObjPtr( hdc, METAFILE_DC_MAGIC ))) return 0;
1134         MF_MetaParam1( dc, META_SETTEXTALIGN, textAlign );
1135         GDI_HEAP_UNLOCK( hdc );
1136         return 1;
1137     }
1138     prevAlign = dc->w.textAlign;
1139     dc->w.textAlign = textAlign;
1140     GDI_HEAP_UNLOCK( hdc );
1141     return prevAlign;
1142 }
1143
1144
1145 /***********************************************************************
1146  *           GetDCOrgEx  (GDI32.168)
1147  */
1148 BOOL32 WINAPI GetDCOrgEx( HDC32 hDC, LPPOINT32 lpp )
1149 {
1150     DC * dc;
1151     if (!lpp) return FALSE;
1152     if (!(dc = (DC *) GDI_GetObjPtr( hDC, DC_MAGIC ))) return FALSE;
1153
1154     if (!(dc->w.flags & DC_MEMORY))
1155     {
1156        Window root;
1157        int w, h, border, depth;
1158        /* FIXME: this is not correct for managed windows */
1159        TSXGetGeometry( display, dc->u.x.drawable, &root,
1160                     &lpp->x, &lpp->y, &w, &h, &border, &depth );
1161     }
1162     else lpp->x = lpp->y = 0;
1163     lpp->x += dc->w.DCOrgX; lpp->y += dc->w.DCOrgY;
1164     GDI_HEAP_UNLOCK( hDC );
1165     return TRUE;
1166 }
1167
1168
1169 /***********************************************************************
1170  *           GetDCOrg    (GDI.79)
1171  */
1172 DWORD WINAPI GetDCOrg( HDC16 hdc )
1173 {
1174     POINT32     pt;
1175     if( GetDCOrgEx( hdc, &pt) )
1176         return MAKELONG( (WORD)pt.x, (WORD)pt.y );    
1177     return 0;
1178 }
1179
1180
1181 /***********************************************************************
1182  *           SetDCOrg    (GDI.117)
1183  */
1184 DWORD WINAPI SetDCOrg( HDC16 hdc, INT16 x, INT16 y )
1185 {
1186     DWORD prevOrg;
1187     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
1188     if (!dc) return 0;
1189     prevOrg = dc->w.DCOrgX | (dc->w.DCOrgY << 16);
1190     dc->w.DCOrgX = x;
1191     dc->w.DCOrgY = y;
1192     GDI_HEAP_UNLOCK( hdc );
1193     return prevOrg;
1194 }
1195
1196
1197 /***********************************************************************
1198  *           GetGraphicsMode    (GDI32.188)
1199  */
1200 INT32 WINAPI GetGraphicsMode( HDC32 hdc )
1201 {
1202     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
1203     if (!dc) return 0;
1204     return dc->w.GraphicsMode;
1205 }
1206
1207
1208 /***********************************************************************
1209  *           SetGraphicsMode    (GDI32.317)
1210  */
1211 INT32 WINAPI SetGraphicsMode( HDC32 hdc, INT32 mode )
1212 {
1213     INT32 ret;
1214     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
1215
1216     /* One would think that setting the graphics mode to GM_COMPATIBLE
1217      * would also reset the world transformation matrix to the unity
1218      * matrix. However, in Windows, this is not the case. This doesn't
1219      * make a lot of sense to me, but that's the way it is.
1220      */
1221     
1222     if (!dc) return 0;
1223     if ((mode <= 0) || (mode > GM_LAST)) return 0;
1224     ret = dc->w.GraphicsMode;
1225     dc->w.GraphicsMode = mode;
1226     return ret;
1227 }
1228
1229
1230 /***********************************************************************
1231  *           GetArcDirection16    (GDI.524)
1232  */
1233 INT16 WINAPI GetArcDirection16( HDC16 hdc )
1234 {
1235     return GetArcDirection32( (HDC32)hdc );
1236 }
1237
1238
1239 /***********************************************************************
1240  *           GetArcDirection32    (GDI32.141)
1241  */
1242 INT32 WINAPI GetArcDirection32( HDC32 hdc )
1243 {
1244     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
1245     
1246     if (!dc)
1247         return 0;
1248
1249     return dc->w.ArcDirection;
1250 }
1251
1252
1253 /***********************************************************************
1254  *           SetArcDirection16    (GDI.525)
1255  */
1256 INT16 WINAPI SetArcDirection16( HDC16 hdc, INT16 nDirection )
1257 {
1258     return SetArcDirection32( (HDC32)hdc, (INT32)nDirection );
1259 }
1260
1261
1262 /***********************************************************************
1263  *           SetArcDirection32    (GDI32.302)
1264  */
1265 INT32 WINAPI SetArcDirection32( HDC32 hdc, INT32 nDirection )
1266 {
1267     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
1268     INT32 nOldDirection;
1269     
1270     if (!dc)
1271         return 0;
1272
1273     if (nDirection!=AD_COUNTERCLOCKWISE && nDirection!=AD_CLOCKWISE)
1274     {
1275         SetLastError(ERROR_INVALID_PARAMETER);
1276         return 0;
1277     }
1278
1279     nOldDirection = dc->w.ArcDirection;
1280     dc->w.ArcDirection = nDirection;
1281
1282     return nOldDirection;
1283 }
1284
1285
1286 /***********************************************************************
1287  *           GetWorldTransform    (GDI32.244)
1288  */
1289 BOOL32 WINAPI GetWorldTransform( HDC32 hdc, LPXFORM xform )
1290 {
1291     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
1292     
1293     if (!dc)
1294         return FALSE;
1295     if (!xform)
1296         return FALSE;
1297
1298     *xform = dc->w.xformWorld2Wnd;
1299     
1300     return TRUE;
1301 }
1302
1303
1304 /***********************************************************************
1305  *           SetWorldTransform    (GDI32.346)
1306  */
1307 BOOL32 WINAPI SetWorldTransform( HDC32 hdc, const XFORM *xform )
1308 {
1309     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
1310     
1311     if (!dc)
1312     {
1313         SetLastError( ERROR_INVALID_HANDLE );
1314         return FALSE;
1315     }
1316
1317     if (!xform)
1318         return FALSE;
1319     
1320     /* Check that graphics mode is GM_ADVANCED */
1321     if (dc->w.GraphicsMode!=GM_ADVANCED)
1322        return FALSE;
1323
1324     dc->w.xformWorld2Wnd = *xform;
1325     
1326     DC_UpdateXforms( dc );
1327
1328     return TRUE;
1329 }
1330
1331
1332 /****************************************************************************
1333  * ModifyWorldTransform [GDI32.253]
1334  * Modifies the world transformation for a device context.
1335  *
1336  * PARAMS
1337  *    hdc   [I] Handle to device context
1338  *    xform [I] XFORM structure that will be used to modify the world
1339  *              transformation
1340  *    iMode [I] Specifies in what way to modify the world transformation
1341  *              Possible values:
1342  *              MWT_IDENTITY
1343  *                 Resets the world transformation to the identity matrix.
1344  *                 The parameter xform is ignored.
1345  *              MWT_LEFTMULTIPLY
1346  *                 Multiplies xform into the world transformation matrix from
1347  *                 the left.
1348  *              MWT_RIGHTMULTIPLY
1349  *                 Multiplies xform into the world transformation matrix from
1350  *                 the right.
1351  *
1352  * RETURNS STD
1353  */
1354 BOOL32 WINAPI ModifyWorldTransform( HDC32 hdc, const XFORM *xform,
1355     DWORD iMode )
1356 {
1357     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
1358     
1359     /* Check for illegal parameters */
1360     if (!dc)
1361     {
1362         SetLastError( ERROR_INVALID_HANDLE );
1363         return FALSE;
1364     }
1365     if (!xform)
1366         return FALSE;
1367     
1368     /* Check that graphics mode is GM_ADVANCED */
1369     if (dc->w.GraphicsMode!=GM_ADVANCED)
1370        return FALSE;
1371        
1372     switch (iMode)
1373     {
1374         case MWT_IDENTITY:
1375             dc->w.xformWorld2Wnd.eM11 = 1.0f;
1376             dc->w.xformWorld2Wnd.eM12 = 0.0f;
1377             dc->w.xformWorld2Wnd.eM21 = 0.0f;
1378             dc->w.xformWorld2Wnd.eM22 = 1.0f;
1379             dc->w.xformWorld2Wnd.eDx  = 0.0f;
1380             dc->w.xformWorld2Wnd.eDy  = 0.0f;
1381             break;
1382         case MWT_LEFTMULTIPLY:
1383             CombineTransform( &dc->w.xformWorld2Wnd, xform,
1384                 &dc->w.xformWorld2Wnd );
1385             break;
1386         case MWT_RIGHTMULTIPLY:
1387             CombineTransform( &dc->w.xformWorld2Wnd, &dc->w.xformWorld2Wnd,
1388                 xform );
1389             break;
1390         default:
1391             return FALSE;
1392     }
1393
1394     DC_UpdateXforms( dc );
1395
1396     return TRUE;
1397 }
1398
1399
1400 /****************************************************************************
1401  * CombineTransform [GDI32.20]
1402  * Combines two transformation matrices.
1403  *
1404  * PARAMS
1405  *    xformResult [O] Stores the result of combining the two matrices
1406  *    xform1      [I] Specifies the first matrix to apply
1407  *    xform2      [I] Specifies the second matrix to apply
1408  *
1409  * REMARKS
1410  *    The same matrix can be passed in for more than one of the parameters.
1411  *
1412  * RETURNS STD
1413  */
1414 BOOL32 WINAPI CombineTransform( LPXFORM xformResult, const XFORM *xform1,
1415     const XFORM *xform2 )
1416 {
1417     XFORM xformTemp;
1418     
1419     /* Check for illegal parameters */
1420     if (!xformResult || !xform1 || !xform2)
1421         return FALSE;
1422
1423     /* Create the result in a temporary XFORM, since xformResult may be
1424      * equal to xform1 or xform2 */
1425     xformTemp.eM11 = xform1->eM11 * xform2->eM11 +
1426                      xform1->eM12 * xform2->eM21;
1427     xformTemp.eM12 = xform1->eM11 * xform2->eM12 +
1428                      xform1->eM12 * xform2->eM22;
1429     xformTemp.eM21 = xform1->eM21 * xform2->eM11 +
1430                      xform1->eM22 * xform2->eM21;
1431     xformTemp.eM22 = xform1->eM21 * xform2->eM12 +
1432                      xform1->eM22 * xform2->eM22;
1433     xformTemp.eDx  = xform1->eDx  * xform2->eM11 +
1434                      xform1->eDy  * xform2->eM21 +
1435                      xform2->eDx;
1436     xformTemp.eDy  = xform1->eDx  * xform2->eM12 +
1437                      xform1->eDy  * xform2->eM22 +
1438                      xform2->eDy;
1439
1440     /* Copy the result to xformResult */
1441     *xformResult = xformTemp;
1442
1443     return TRUE;
1444 }
1445
1446
1447 /***********************************************************************
1448  *           SetDCHook   (GDI.190)
1449  */
1450 BOOL16 WINAPI SetDCHook( HDC16 hdc, FARPROC16 hookProc, DWORD dwHookData )
1451 {
1452     DC *dc = (DC *)GDI_GetObjPtr( hdc, DC_MAGIC );
1453
1454     TRACE(dc, "hookProc %08x, default is %08x\n",
1455                 (UINT32)hookProc, (UINT32)DCHook );
1456
1457     if (!dc) return FALSE;
1458     dc->hookProc = hookProc;
1459     dc->dwHookData = dwHookData;
1460     GDI_HEAP_UNLOCK( hdc );
1461     return TRUE;
1462 }
1463
1464
1465 /***********************************************************************
1466  *           GetDCHook   (GDI.191)
1467  */
1468 DWORD WINAPI GetDCHook( HDC16 hdc, FARPROC16 *phookProc )
1469 {
1470     DC *dc = (DC *)GDI_GetObjPtr( hdc, DC_MAGIC );
1471     if (!dc) return 0;
1472     *phookProc = dc->hookProc;
1473     GDI_HEAP_UNLOCK( hdc );
1474     return dc->dwHookData;
1475 }
1476
1477
1478 /***********************************************************************
1479  *           SetHookFlags       (GDI.192)
1480  */
1481 WORD WINAPI SetHookFlags(HDC16 hDC, WORD flags)
1482 {
1483     DC* dc = (DC*)GDI_GetObjPtr( hDC, DC_MAGIC );
1484
1485     if( dc )
1486     {
1487         WORD wRet = dc->w.flags & DC_DIRTY;
1488
1489         /* "Undocumented Windows" info is slightly confusing.
1490          */
1491
1492         TRACE(dc,"hDC %04x, flags %04x\n",hDC,flags);
1493
1494         if( flags & DCHF_INVALIDATEVISRGN )
1495             dc->w.flags |= DC_DIRTY;
1496         else if( flags & DCHF_VALIDATEVISRGN || !flags )
1497             dc->w.flags &= ~DC_DIRTY;
1498         GDI_HEAP_UNLOCK( hDC );
1499         return wRet;
1500     }
1501     return 0;
1502 }
1503
1504 /***********************************************************************
1505  *           SetICMMode    (GDI32.318)
1506  */
1507 INT32 WINAPI SetICMMode(HDC32 hdc, INT32 iEnableICM)
1508 {
1509 /*FIXME  Asuming that ICM is always off, and cannot be turned on */
1510     if (iEnableICM == ICM_OFF) return ICM_OFF;
1511     if (iEnableICM == ICM_ON) return 0;
1512     if (iEnableICM == ICM_QUERY) return ICM_OFF;
1513     return 0;
1514 }
1515
1516
1517 /***********************************************************************
1518  *           GetColorSpace    (GDI32.165)
1519  */
1520 HCOLORSPACE32 WINAPI GetColorSpace(HDC32 hdc)
1521 {
1522 /*FIXME    Need to to whatever GetColorSpace actually does */
1523     return 0;
1524 }
1525
1526 /***********************************************************************
1527  *           GetBoundsRect16    (GDI.194)
1528  */
1529 UINT16 WINAPI GetBoundsRect16(HDC16 hdc, LPRECT16 rect, UINT16 flags)
1530 {
1531     FIXME(dc, "(): stub\n");
1532     return DCB_RESET;   /* bounding rectangle always empty */
1533 }
1534
1535 /***********************************************************************
1536  *           SetBoundsRect16    (GDI.193)
1537  */
1538 UINT16 WINAPI SetBoundsRect16(HDC16 hdc, LPRECT16 rect, UINT16 flags)
1539 {
1540     FIXME(dc, "(): stub\n");
1541     return DCB_DISABLE;   /* bounding rectangle always empty */
1542 }
1543