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