:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / subsys / win32k / objects / dc.c
1 /* $Id$
2  *
3  * DC.C - Device context functions
4  *
5  */
6
7 #undef WIN32_LEAN_AND_MEAN
8 #include <windows.h>
9 #include <ddk/ntddk.h>
10
11 #include <win32k/bitmaps.h>
12 #include <win32k/coord.h>
13 #include <win32k/driver.h>
14 #include <win32k/dc.h>
15 #include <win32k/print.h>
16 #include <win32k/region.h>
17 #include <win32k/gdiobj.h>
18 #include <win32k/pen.h>
19 #include <win32k/text.h>
20 #include "../eng/handle.h"
21
22 //#define NDEBUG
23 #include <win32k/debug1.h>
24
25
26 /* FIXME: DCs should probably be thread safe  */
27
28 /*
29  * DC device-independent Get/SetXXX functions
30  * (RJJ) swiped from WINE
31  */
32
33 #define DC_GET_VAL( func_type, func_name, dc_field ) \
34 func_type STDCALL  func_name( HDC hdc ) \
35 {                                   \
36   func_type  ft;                    \
37   PDC  dc = DC_HandleToPtr( hdc );  \
38   if (!dc)                          \
39   {                                 \
40     return 0;                       \
41   }                                 \
42   ft = dc->dc_field;                \
43   DC_ReleasePtr( hdc );                         \
44   return ft;                        \
45 }
46
47 /* DC_GET_VAL_EX is used to define functions returning a POINT or a SIZE. It is
48  * important that the function has the right signature, for the implementation
49  * we can do whatever we want.
50  */
51 #define DC_GET_VAL_EX( func_name, ret_x, ret_y, type ) \
52 BOOL STDCALL  func_name( HDC hdc, LP##type pt ) \
53 {                                   \
54   PDC  dc = DC_HandleToPtr( hdc );  \
55   if (!dc)                          \
56   {                                 \
57     return FALSE;                   \
58   }                                 \
59   ((LPPOINT)pt)->x = dc->ret_x;     \
60   ((LPPOINT)pt)->y = dc->ret_y;     \
61   DC_ReleasePtr( hdc );                         \
62   return  TRUE;                     \
63 }
64
65 #define DC_SET_MODE( func_name, dc_field, min_val, max_val ) \
66 INT STDCALL  func_name( HDC hdc, INT mode ) \
67 {                                           \
68   INT  prevMode;                            \
69   PDC  dc = DC_HandleToPtr( hdc );          \
70   if(!dc)                                   \
71   {                                         \
72     return 0;                               \
73   }                                         \
74   if ((mode < min_val) || (mode > max_val)) \
75   {                                         \
76     return 0;                               \
77   }                                         \
78   prevMode = dc->dc_field;                  \
79   dc->dc_field = mode;                      \
80   DC_ReleasePtr( hdc );                                         \
81   return prevMode;                          \
82 }
83
84
85 VOID BitmapToSurf(HDC hdc, PSURFGDI SurfGDI, PSURFOBJ SurfObj, PBITMAPOBJ Bitmap);
86
87 //  ---------------------------------------------------------  File Statics
88
89 static void  W32kSetDCState16(HDC  hDC, HDC  hDCSave);
90
91 //  -----------------------------------------------------  Public Functions
92
93 BOOL STDCALL  W32kCancelDC(HDC  hDC)
94 {
95   UNIMPLEMENTED;
96 }
97
98 HDC STDCALL  W32kCreateCompatableDC(HDC  hDC)
99 {
100   PDC  NewDC, OrigDC = NULL;
101   HBITMAP  hBitmap;
102   SIZEL onebyone;
103   HDC hNewDC;
104
105   OrigDC = DC_HandleToPtr(hDC);
106   if (OrigDC == NULL)
107   {
108     hNewDC = DC_AllocDC(L"DISPLAY");
109         if( hNewDC )
110                 NewDC = DC_HandleToPtr( hNewDC );
111   }
112   else {
113     /*  Allocate a new DC based on the original DC's device  */
114     hNewDC = DC_AllocDC(OrigDC->DriverName);
115         if( hNewDC )
116                 NewDC = DC_HandleToPtr( hNewDC );
117   }
118
119   if (NewDC == NULL)
120   {
121     return  NULL;
122   }
123
124   /* Copy information from original DC to new DC  */
125   NewDC->hSelf = NewDC;
126
127   /* FIXME: Should this DC request its own PDEV?  */
128   if(OrigDC == NULL) {
129   } else {
130     NewDC->PDev = OrigDC->PDev;
131     NewDC->DMW = OrigDC->DMW;
132     memcpy(NewDC->FillPatternSurfaces,
133            OrigDC->FillPatternSurfaces,
134            sizeof OrigDC->FillPatternSurfaces);
135     NewDC->GDIInfo = OrigDC->GDIInfo;
136     NewDC->DevInfo = OrigDC->DevInfo;
137   }
138
139   // Create a 1x1 monochrome bitmap surface
140   onebyone.cx = 1;
141   onebyone.cy = 1;
142   NewDC->Surface = EngCreateBitmap(onebyone, 1, BMF_1BPP, 0, NULL);
143
144   /* DriverName is copied in the AllocDC routine  */
145   if(OrigDC == NULL) {
146     NewDC->DeviceDriver = DRIVER_FindMPDriver(NewDC->DriverName);
147   } else {
148     NewDC->DeviceDriver = OrigDC->DeviceDriver;
149     NewDC->wndOrgX = OrigDC->wndOrgX;
150     NewDC->wndOrgY = OrigDC->wndOrgY;
151     NewDC->wndExtX = OrigDC->wndExtX;
152     NewDC->wndExtY = OrigDC->wndExtY;
153     NewDC->vportOrgX = OrigDC->vportOrgX;
154     NewDC->vportOrgY = OrigDC->vportOrgY;
155     NewDC->vportExtX = OrigDC->vportExtX;
156     NewDC->vportExtY = OrigDC->vportExtY;
157   }
158
159   DC_InitDC(hNewDC);
160
161   /* Create default bitmap */
162   if (!(hBitmap = W32kCreateBitmap( 1, 1, 1, 1, NULL )))
163   {
164         DC_ReleasePtr( hNewDC );
165     DC_FreeDC( hNewDC );
166     return NULL;
167   }
168   NewDC->w.flags        = DC_MEMORY;
169   NewDC->w.bitsPerPixel = 1;
170   NewDC->w.hBitmap      = hBitmap;
171   NewDC->w.hFirstBitmap = hBitmap;
172
173   if(OrigDC != NULL)
174   {
175     NewDC->w.hPalette = OrigDC->w.hPalette;
176     NewDC->w.textColor = OrigDC->w.textColor;
177     NewDC->w.textAlign = OrigDC->w.textAlign;
178   }
179   DC_ReleasePtr( hDC );
180   DC_ReleasePtr( hNewDC );
181
182   return  hNewDC;
183 }
184
185 #include <ddk/ntddvid.h>
186
187 static GDIDEVICE PrimarySurface;
188 static BOOL PrimarySurfaceCreated = FALSE;
189
190 BOOL STDCALL W32kCreatePrimarySurface(LPCWSTR Driver,
191                                       LPCWSTR Device)
192 {
193   PGD_ENABLEDRIVER  GDEnableDriver;
194   HANDLE DeviceDriver;
195   DRVENABLEDATA  DED;
196   PSURFOBJ SurfObj;
197
198   /*  Open the miniport driver  */
199   if ((DeviceDriver = DRIVER_FindMPDriver(Driver)) == NULL)
200   {
201     DPRINT("FindMPDriver failed\n");
202     return(FALSE);
203   }
204
205   /*  Get the DDI driver's entry point  */
206   /*  FIXME: Retrieve DDI driver name from registry */
207   if ((GDEnableDriver = DRIVER_FindDDIDriver(L"\\SystemRoot\\system32\\drivers\\vgaddi.dll")) == NULL)
208   {
209     DPRINT("FindDDIDriver failed\n");
210     return(FALSE);
211   }
212
213   /*  Call DDI driver's EnableDriver function  */
214   RtlZeroMemory(&DED, sizeof(DED));
215
216   if (!GDEnableDriver(DDI_DRIVER_VERSION, sizeof(DED), &DED))
217   {
218     DPRINT("DrvEnableDriver failed\n");
219     return(FALSE);
220   }
221   DPRINT("Building DDI Functions\n");
222
223   /*  Construct DDI driver function dispatch table  */
224   if (!DRIVER_BuildDDIFunctions(&DED, &PrimarySurface.DriverFunctions))
225   {
226     DPRINT("BuildDDIFunctions failed\n");
227     return(FALSE);
228   }
229
230   /*  Allocate a phyical device handle from the driver  */
231   if (Device != NULL)
232   {
233     DPRINT("Device in u: %u\n", Device);
234 //    wcsncpy(NewDC->DMW.dmDeviceName, Device, DMMAXDEVICENAME); FIXME: this crashes everything?
235   }
236
237   DPRINT("Enabling PDev\n");
238
239   PrimarySurface.PDev =
240     PrimarySurface.DriverFunctions.EnablePDev(&PrimarySurface.DMW,
241                                              L"",
242                                              HS_DDI_MAX,
243                                              PrimarySurface.FillPatterns,
244                                              sizeof(PrimarySurface.GDIInfo),
245                                              (ULONG *) &PrimarySurface.GDIInfo,
246                                              sizeof(PrimarySurface.DevInfo),
247                                              &PrimarySurface.DevInfo,
248                                              NULL,
249                                              L"",
250                                              DeviceDriver);
251   if (PrimarySurface.PDev == NULL)
252   {
253     DPRINT("DrvEnablePDEV failed\n");
254     return(FALSE);
255   }
256
257   DPRINT("calling completePDev\n");
258
259   /*  Complete initialization of the physical device  */
260   PrimarySurface.DriverFunctions.CompletePDev(PrimarySurface.PDev,
261                                               &PrimarySurface);
262
263   DPRINT("calling DRIVER_ReferenceDriver\n");
264
265   DRIVER_ReferenceDriver (Driver);
266
267   DPRINT("calling EnableSurface\n");
268
269   /*  Enable the drawing surface  */
270   PrimarySurface.Handle =
271     PrimarySurface.DriverFunctions.EnableSurface(PrimarySurface.PDev);
272
273   SurfObj = (PSURFOBJ)AccessUserObject(PrimarySurface.Handle);
274   SurfObj->dhpdev = PrimarySurface.PDev;
275 }
276
277 HDC STDCALL  W32kCreateDC(LPCWSTR  Driver,
278                   LPCWSTR  Device,
279                   LPCWSTR  Output,
280                   CONST PDEVMODEW  InitData)
281 {
282   HDC  hNewDC;
283   PDC  NewDC;
284   HDC  hDC = NULL;
285
286   /*  Check for existing DC object  */
287   if ((hNewDC = DC_FindOpenDC(Driver)) != NULL)
288   {
289     hDC = hNewDC;
290     return  W32kCreateCompatableDC(hDC);
291   }
292
293   DPRINT("NAME: %S\n", Driver); // FIXME: Should not crash if NULL
294
295   /*  Allocate a DC object  */
296   if ((hNewDC = DC_AllocDC(Driver)) == NULL)
297   {
298     return  NULL;
299   }
300
301   NewDC = DC_HandleToPtr( hNewDC );
302   ASSERT( NewDC );
303
304   if (!PrimarySurfaceCreated)
305     {
306       if (!W32kCreatePrimarySurface(Driver, Device))
307         {
308           DC_ReleasePtr( hNewDC );
309           DC_FreeDC(hNewDC);
310           return  NULL;
311         }
312     }
313   PrimarySurfaceCreated = TRUE;
314   NewDC->DMW = PrimarySurface.DMW;
315   NewDC->DevInfo = PrimarySurface.DevInfo;
316   NewDC->GDIInfo = PrimarySurface.GDIInfo;
317   memcpy(NewDC->FillPatternSurfaces, PrimarySurface.FillPatterns,
318          sizeof(NewDC->FillPatternSurfaces));
319   NewDC->PDev = PrimarySurface.PDev;
320   NewDC->Surface = PrimarySurface.Handle;
321   NewDC->DriverFunctions = PrimarySurface.DriverFunctions;
322
323   NewDC->DMW.dmSize = sizeof(NewDC->DMW);
324   NewDC->DMW.dmFields = 0x000fc000;
325
326   /* FIXME: get mode selection information from somewhere  */
327
328   NewDC->DMW.dmLogPixels = 96;
329   NewDC->DMW.dmBitsPerPel = 4;
330   NewDC->DMW.dmPelsWidth = 640;
331   NewDC->DMW.dmPelsHeight = 480;
332   NewDC->DMW.dmDisplayFlags = 0;
333   NewDC->DMW.dmDisplayFrequency = 0;
334
335   NewDC->w.bitsPerPixel = 4; // FIXME: set this here??
336
337   NewDC->w.hPalette = NewDC->DevInfo.hpalDefault;
338
339   DPRINT("Bits per pel: %u\n", NewDC->w.bitsPerPixel);
340
341   /*  Initialize the DC state  */
342   DC_InitDC(hNewDC);
343
344   NewDC->w.hVisRgn = W32kCreateRectRgn(0, 0, 640, 480);
345   W32kSetTextColor(hNewDC, RGB(0, 0, 0));
346   W32kSetTextAlign(hNewDC, TA_TOP);
347   DC_ReleasePtr( hNewDC );
348
349   return hNewDC;
350 }
351
352 HDC STDCALL W32kCreateIC(LPCWSTR  Driver,
353                          LPCWSTR  Device,
354                          LPCWSTR  Output,
355                          CONST PDEVMODEW  DevMode)
356 {
357   /* FIXME: this should probably do something else...  */
358   return  W32kCreateDC(Driver, Device, Output, DevMode);
359 }
360
361 BOOL STDCALL W32kDeleteDC(HDC  DCHandle)
362 {
363   PDC  DCToDelete;
364
365   DCToDelete = DC_HandleToPtr(DCHandle);
366   if (DCToDelete == NULL)
367     {
368       return  FALSE;
369     }
370   DPRINT( "Deleting DC\n" );
371   if ((!(DCToDelete->w.flags & DC_MEMORY))) // Don't reset the display if its a memory DC
372   {
373     if (!DRIVER_UnreferenceDriver (DCToDelete->DriverName))
374     {
375       DPRINT( "No more references to driver, reseting display\n" );
376       DCToDelete->DriverFunctions.DisableSurface(DCToDelete->PDev);
377       CHECKPOINT;
378       DCToDelete->DriverFunctions.AssertMode( DCToDelete->PDev, FALSE );
379       CHECKPOINT;
380       DCToDelete->DriverFunctions.DisablePDev(DCToDelete->PDev);
381           PrimarySurfaceCreated = FALSE;
382         }
383   }
384   CHECKPOINT;
385   /*  First delete all saved DCs  */
386   while (DCToDelete->saveLevel)
387   {
388     PDC  savedDC;
389     HDC  savedHDC;
390
391     savedHDC = DC_GetNextDC (DCToDelete);
392     savedDC = DC_HandleToPtr (savedHDC);
393     if (savedDC == NULL)
394     {
395       break;
396     }
397     DC_SetNextDC (DCToDelete, DC_GetNextDC (savedDC));
398     DCToDelete->saveLevel--;
399         DC_ReleasePtr( savedHDC );
400     W32kDeleteDC (savedHDC);
401   }
402
403   /*  Free GDI resources allocated to this DC  */
404   if (!(DCToDelete->w.flags & DC_SAVED))
405   {
406     /*
407     W32kSelectObject (DCHandle, STOCK_BLACK_PEN);
408     W32kSelectObject (DCHandle, STOCK_WHITE_BRUSH);
409     W32kSelectObject (DCHandle, STOCK_SYSTEM_FONT);
410     DC_LockDC (DCHandle); W32kSelectObject does not recognize stock objects yet  */
411     if (DCToDelete->w.flags & DC_MEMORY)
412     {
413       W32kDeleteObject (DCToDelete->w.hFirstBitmap);
414     }
415   }
416   if (DCToDelete->w.hClipRgn)
417   {
418     W32kDeleteObject (DCToDelete->w.hClipRgn);
419   }
420   if (DCToDelete->w.hVisRgn)
421   {
422     W32kDeleteObject (DCToDelete->w.hVisRgn);
423   }
424   if (DCToDelete->w.hGCClipRgn)
425   {
426     W32kDeleteObject (DCToDelete->w.hGCClipRgn);
427   }
428 #if 0 /* FIXME */
429   PATH_DestroyGdiPath (&DCToDelete->w.path);
430 #endif
431   DC_ReleasePtr( DCToDelete );
432   DC_FreeDC (DCToDelete);
433
434   return TRUE;
435 }
436
437 INT STDCALL W32kDrawEscape(HDC  hDC,
438                     INT  nEscape,
439                     INT  cbInput,
440                     LPCSTR  lpszInData)
441 {
442   UNIMPLEMENTED;
443 }
444
445 INT STDCALL W32kEnumObjects(HDC  hDC,
446                      INT  ObjectType,
447                      GOBJENUMPROC  ObjectFunc,
448                      LPARAM  lParam)
449 {
450   UNIMPLEMENTED;
451 }
452
453 DC_GET_VAL( COLORREF, W32kGetBkColor, w.backgroundColor )
454 DC_GET_VAL( INT, W32kGetBkMode, w.backgroundMode )
455 DC_GET_VAL_EX( W32kGetBrushOrgEx, w.brushOrgX, w.brushOrgY, POINT )
456 DC_GET_VAL( HRGN, W32kGetClipRgn, w.hClipRgn )
457
458 HGDIOBJ STDCALL W32kGetCurrentObject(HDC  hDC,
459                               UINT  ObjectType)
460 {
461   UNIMPLEMENTED;
462 }
463
464 DC_GET_VAL_EX( W32kGetCurrentPositionEx, w.CursPosX, w.CursPosY, POINT )
465
466 BOOL STDCALL W32kGetDCOrgEx(HDC  hDC,
467                      LPPOINT  Point)
468 {
469   PDC dc;
470
471   if (!Point)
472   {
473     return FALSE;
474   }
475   dc = DC_HandleToPtr(hDC);
476   if (dc == NULL)
477   {
478     return FALSE;
479   }
480
481   Point->x = Point->y = 0;
482
483   Point->x += dc->w.DCOrgX;
484   Point->y += dc->w.DCOrgY;
485   DC_ReleasePtr( hDC );
486   return  TRUE;
487 }
488
489 HDC STDCALL W32kGetDCState16(HDC  hDC)
490 {
491   PDC  newdc, dc;
492   HDC hnewdc;
493
494   dc = DC_HandleToPtr(hDC);
495   if (dc == NULL)
496   {
497     return 0;
498   }
499
500   hnewdc = DC_AllocDC(NULL);
501   if (hnewdc == NULL)
502   {
503         DC_ReleasePtr( hDC );
504     return 0;
505   }
506   newdc = DC_HandleToPtr( hnewdc );
507   ASSERT( newdc );
508
509   newdc->w.flags            = dc->w.flags | DC_SAVED;
510 #if 0
511   newdc->w.devCaps          = dc->w.devCaps;
512 #endif
513   newdc->w.hPen             = dc->w.hPen;
514   newdc->w.hBrush           = dc->w.hBrush;
515   newdc->w.hFont            = dc->w.hFont;
516   newdc->w.hBitmap          = dc->w.hBitmap;
517   newdc->w.hFirstBitmap     = dc->w.hFirstBitmap;
518 #if 0
519   newdc->w.hDevice          = dc->w.hDevice;
520   newdc->w.hPalette         = dc->w.hPalette;
521 #endif
522   newdc->w.totalExtent      = dc->w.totalExtent;
523   newdc->w.bitsPerPixel     = dc->w.bitsPerPixel;
524   newdc->w.ROPmode          = dc->w.ROPmode;
525   newdc->w.polyFillMode     = dc->w.polyFillMode;
526   newdc->w.stretchBltMode   = dc->w.stretchBltMode;
527   newdc->w.relAbsMode       = dc->w.relAbsMode;
528   newdc->w.backgroundMode   = dc->w.backgroundMode;
529   newdc->w.backgroundColor  = dc->w.backgroundColor;
530   newdc->w.textColor        = dc->w.textColor;
531   newdc->w.brushOrgX        = dc->w.brushOrgX;
532   newdc->w.brushOrgY        = dc->w.brushOrgY;
533   newdc->w.textAlign        = dc->w.textAlign;
534   newdc->w.charExtra        = dc->w.charExtra;
535   newdc->w.breakTotalExtra  = dc->w.breakTotalExtra;
536   newdc->w.breakCount       = dc->w.breakCount;
537   newdc->w.breakExtra       = dc->w.breakExtra;
538   newdc->w.breakRem         = dc->w.breakRem;
539   newdc->w.MapMode          = dc->w.MapMode;
540   newdc->w.GraphicsMode     = dc->w.GraphicsMode;
541 #if 0
542   /* Apparently, the DC origin is not changed by [GS]etDCState */
543   newdc->w.DCOrgX           = dc->w.DCOrgX;
544   newdc->w.DCOrgY           = dc->w.DCOrgY;
545 #endif
546   newdc->w.CursPosX         = dc->w.CursPosX;
547   newdc->w.CursPosY         = dc->w.CursPosY;
548   newdc->w.ArcDirection     = dc->w.ArcDirection;
549 #if 0
550   newdc->w.xformWorld2Wnd   = dc->w.xformWorld2Wnd;
551   newdc->w.xformWorld2Vport = dc->w.xformWorld2Vport;
552   newdc->w.xformVport2World = dc->w.xformVport2World;
553   newdc->w.vport2WorldValid = dc->w.vport2WorldValid;
554 #endif
555   newdc->wndOrgX            = dc->wndOrgX;
556   newdc->wndOrgY            = dc->wndOrgY;
557   newdc->wndExtX            = dc->wndExtX;
558   newdc->wndExtY            = dc->wndExtY;
559   newdc->vportOrgX          = dc->vportOrgX;
560   newdc->vportOrgY          = dc->vportOrgY;
561   newdc->vportExtX          = dc->vportExtX;
562   newdc->vportExtY          = dc->vportExtY;
563
564   newdc->hSelf = hnewdc;
565   newdc->saveLevel = 0;
566
567 #if 0
568   PATH_InitGdiPath( &newdc->w.path );
569 #endif
570
571   /* Get/SetDCState() don't change hVisRgn field ("Undoc. Windows" p.559). */
572
573 #if 0
574   newdc->w.hGCClipRgn = newdc->w.hVisRgn = 0;
575 #endif
576   if (dc->w.hClipRgn)
577   {
578     newdc->w.hClipRgn = W32kCreateRectRgn( 0, 0, 0, 0 );
579     W32kCombineRgn( newdc->w.hClipRgn, dc->w.hClipRgn, 0, RGN_COPY );
580   }
581   else
582   {
583     newdc->w.hClipRgn = 0;
584   }
585   DC_ReleasePtr( hnewdc );
586   return  hnewdc;
587 }
588
589 INT STDCALL W32kGetDeviceCaps(HDC  hDC,
590                        INT  Index)
591 {
592   PDC  dc;
593   INT  ret;
594   POINT  pt;
595
596   dc = DC_HandleToPtr(hDC);
597   if (dc == NULL)
598   {
599     return 0;
600   }
601
602   /* Device capabilities for the printer */
603   switch (Index)
604   {
605     case PHYSICALWIDTH:
606       if(W32kEscape(hDC, GETPHYSPAGESIZE, 0, NULL, (LPVOID)&pt) > 0)
607       {
608         return pt.x;
609       }
610       break;
611
612     case PHYSICALHEIGHT:
613       if(W32kEscape(hDC, GETPHYSPAGESIZE, 0, NULL, (LPVOID)&pt) > 0)
614       {
615         return pt.y;
616       }
617       break;
618
619     case PHYSICALOFFSETX:
620       if(W32kEscape(hDC, GETPRINTINGOFFSET, 0, NULL, (LPVOID)&pt) > 0)
621       {
622         return pt.x;
623       }
624       break;
625
626     case PHYSICALOFFSETY:
627       if(W32kEscape(hDC, GETPRINTINGOFFSET, 0, NULL, (LPVOID)&pt) > 0)
628       {
629         return pt.y;
630       }
631       break;
632
633     case SCALINGFACTORX:
634       if(W32kEscape(hDC, GETSCALINGFACTOR, 0, NULL, (LPVOID)&pt) > 0)
635       {
636         return pt.x;
637       }
638       break;
639
640     case SCALINGFACTORY:
641       if(W32kEscape(hDC, GETSCALINGFACTOR, 0, NULL, (LPVOID)&pt) > 0)
642       {
643         return pt.y;
644       }
645       break;
646   }
647
648   if ((Index < 0) || (Index > sizeof(DEVICECAPS) - sizeof(WORD)))
649   {
650     return 0;
651   }
652
653   DPRINT("(%04x,%d): returning %d\n",
654          hDC, Index, *(WORD *)(((char *)dc->w.devCaps) + Index));
655   ret = *(WORD *)(((char *)dc->w.devCaps) + Index);
656
657   DC_ReleasePtr( hDC );
658   return ret;
659 }
660
661 DC_GET_VAL( INT, W32kGetMapMode, w.MapMode )
662 DC_GET_VAL( INT, W32kGetPolyFillMode, w.polyFillMode )
663
664 INT STDCALL W32kGetObjectA(HANDLE handle, INT count, LPVOID buffer)
665 {
666   PGDIOBJ  gdiObject;
667   INT  result = 0;
668   WORD  magic;
669
670   if (!count)
671     return  0;
672   gdiObject = GDIOBJ_LockObj (handle, GO_MAGIC_DONTCARE);
673   if (gdiObject == 0)
674     return  0;
675
676   magic = GDIOBJ_GetHandleMagic (handle);
677   switch(magic)
678   {
679 /*    case GO_PEN_MAGIC:
680       result = PEN_GetObject((PENOBJ *)gdiObject, count, buffer);
681       break;
682     case GO_BRUSH_MAGIC:
683       result = BRUSH_GetObject((BRUSHOBJ *)gdiObject, count, buffer);
684       break; */
685     case GO_BITMAP_MAGIC:
686       result = BITMAP_GetObject((BITMAPOBJ *)gdiObject, count, buffer);
687       break;
688 /*    case GO_FONT_MAGIC:
689       result = FONT_GetObjectA((FONTOBJ *)gdiObject, count, buffer);
690
691       // FIXME: Fix the LOGFONT structure for the stock fonts
692
693       if ( (handle >= FIRST_STOCK_HANDLE) && (handle <= LAST_STOCK_HANDLE) )
694         FixStockFontSizeA(handle, count, buffer);
695       break;
696     case GO_PALETTE_MAGIC:
697       result = PALETTE_GetObject((PALETTEOBJ *)gdiObject, count, buffer);
698       break; */
699
700     case GO_REGION_MAGIC:
701     case GO_DC_MAGIC:
702     case GO_DISABLED_DC_MAGIC:
703     case GO_META_DC_MAGIC:
704     case GO_METAFILE_MAGIC:
705     case GO_METAFILE_DC_MAGIC:
706     case GO_ENHMETAFILE_MAGIC:
707     case GO_ENHMETAFILE_DC_MAGIC:
708       // FIXME("Magic %04x not implemented\n", magic);
709       break;
710
711     default:
712       DbgPrint("Invalid GDI Magic %04x\n", magic);
713       break;
714   }
715   GDIOBJ_UnlockObj (handle, GO_MAGIC_DONTCARE);
716   return  result;
717 }
718
719 INT STDCALL W32kGetObjectW(HANDLE handle, INT count, LPVOID buffer)
720 {
721   PGDIOBJHDR  gdiObject;
722   INT  result = 0;
723   WORD  magic;
724
725   if (!count)
726     return 0;
727   gdiObject = GDIOBJ_LockObj(handle, GO_MAGIC_DONTCARE);
728   if (gdiObject == 0)
729     return 0;
730
731   magic = GDIOBJ_GetHandleMagic (handle);
732   switch(magic)
733   {
734 /*    case GO_PEN_MAGIC:
735       result = PEN_GetObject((PENOBJ *)gdiObject, count, buffer);
736       break;
737     case GO_BRUSH_MAGIC:
738       result = BRUSH_GetObject((BRUSHOBJ *)gdiObject, count, buffer);
739        break; */
740     case GO_BITMAP_MAGIC:
741       result = BITMAP_GetObject((BITMAPOBJ *)gdiObject, count, buffer);
742       break;
743 /*    case GO_FONT_MAGIC:
744       result = FONT_GetObjectW((FONTOBJ *)gdiObject, count, buffer);
745
746       // Fix the LOGFONT structure for the stock fonts
747
748       if ( (handle >= FIRST_STOCK_HANDLE) && (handle <= LAST_STOCK_HANDLE) )
749       FixStockFontSizeW(handle, count, buffer);
750     break;
751     case GO_PALETTE_MAGIC:
752       result = PALETTE_GetObject((PALETTEOBJ *)gdiObject, count, buffer);
753       break; */
754     default:
755       // FIXME("Magic %04x not implemented\n", gdiObject->magic);
756       break;
757   }
758   GDIOBJ_UnlockObj(handle, GO_MAGIC_DONTCARE);
759   return  result;
760 }
761
762 INT STDCALL W32kGetObject(HANDLE handle, INT count, LPVOID buffer)
763 {
764   return W32kGetObjectW(handle, count, buffer);
765 }
766
767 DWORD STDCALL W32kGetObjectType(HANDLE handle)
768 {
769   GDIOBJHDR * ptr;
770   INT result = 0;
771   WORD  magic;
772
773   ptr = GDIOBJ_LockObj(handle, GO_MAGIC_DONTCARE);
774   if (ptr == 0)
775     return 0;
776
777   magic = GDIOBJ_GetHandleMagic (handle);
778   switch(magic)
779   {
780     case GO_PEN_MAGIC:
781       result = OBJ_PEN;
782       break;
783     case GO_BRUSH_MAGIC:
784       result = OBJ_BRUSH;
785       break;
786     case GO_BITMAP_MAGIC:
787       result = OBJ_BITMAP;
788       break;
789     case GO_FONT_MAGIC:
790       result = OBJ_FONT;
791       break;
792     case GO_PALETTE_MAGIC:
793       result = OBJ_PAL;
794       break;
795     case GO_REGION_MAGIC:
796       result = OBJ_REGION;
797       break;
798     case GO_DC_MAGIC:
799       result = OBJ_DC;
800       break;
801     case GO_META_DC_MAGIC:
802       result = OBJ_METADC;
803       break;
804     case GO_METAFILE_MAGIC:
805       result = OBJ_METAFILE;
806       break;
807     case GO_METAFILE_DC_MAGIC:
808      result = OBJ_METADC;
809       break;
810     case GO_ENHMETAFILE_MAGIC:
811       result = OBJ_ENHMETAFILE;
812       break;
813     case GO_ENHMETAFILE_DC_MAGIC:
814       result = OBJ_ENHMETADC;
815       break;
816     default:
817       // FIXME("Magic %04x not implemented\n", magic);
818       break;
819   }
820   GDIOBJ_UnlockObj(handle, GO_MAGIC_DONTCARE);
821   return result;
822 }
823
824 DC_GET_VAL( INT, W32kGetRelAbs, w.relAbsMode )
825 DC_GET_VAL( INT, W32kGetROP2, w.ROPmode )
826 DC_GET_VAL( INT, W32kGetStretchBltMode, w.stretchBltMode )
827 DC_GET_VAL( UINT, W32kGetTextAlign, w.textAlign )
828 DC_GET_VAL( COLORREF, W32kGetTextColor, w.textColor )
829 DC_GET_VAL_EX( W32kGetViewportExtEx, vportExtX, vportExtY, SIZE )
830 DC_GET_VAL_EX( W32kGetViewportOrgEx, vportOrgX, vportOrgY, POINT )
831 DC_GET_VAL_EX( W32kGetWindowExtEx, wndExtX, wndExtY, SIZE )
832 DC_GET_VAL_EX( W32kGetWindowOrgEx, wndOrgX, wndOrgY, POINT )
833
834 HDC STDCALL W32kResetDC(HDC  hDC, CONST DEVMODEW *InitData)
835 {
836   UNIMPLEMENTED;
837 }
838
839 BOOL STDCALL W32kRestoreDC(HDC  hDC, INT  SaveLevel)
840 {
841   PDC  dc, dcs;
842   BOOL  success;
843
844   dc = DC_HandleToPtr(hDC);
845   if(!dc)
846   {
847     return FALSE;
848   }
849
850   if (SaveLevel == -1)
851   {
852     SaveLevel = dc->saveLevel;
853   }
854
855   if ((SaveLevel < 1) || (SaveLevel > dc->saveLevel))
856   {
857     return FALSE;
858   }
859
860   success = TRUE;
861   while (dc->saveLevel >= SaveLevel)
862   {
863     HDC hdcs = DC_GetNextDC (dc);
864
865     dcs = DC_HandleToPtr (hdcs);
866     if (dcs == NULL)
867     {
868       return FALSE;
869     }
870     DC_SetNextDC (dcs, DC_GetNextDC (dcs));
871     if (--dc->saveLevel < SaveLevel)
872       {
873         W32kSetDCState16 (hDC, hdcs);
874 #if 0
875         if (!PATH_AssignGdiPath( &dc->w.path, &dcs->w.path ))
876         {
877           /* FIXME: This might not be quite right, since we're
878            * returning FALSE but still destroying the saved DC state */
879           success = FALSE;
880         }
881 #endif
882       }
883           DC_ReleasePtr( hdcs );
884     W32kDeleteDC (hdcs);
885   }
886   DC_ReleasePtr( hDC );
887   return  success;
888 }
889
890 INT STDCALL W32kSaveDC(HDC  hDC)
891 {
892   HDC  hdcs;
893   PDC  dc, dcs;
894   INT  ret;
895
896   dc = DC_HandleToPtr (hDC);
897   if (dc == NULL)
898   {
899     return 0;
900   }
901
902   if (!(hdcs = W32kGetDCState16 (hDC)))
903   {
904     return 0;
905   }
906   dcs = DC_HandleToPtr (hdcs);
907
908 #if 0
909     /* Copy path. The reason why path saving / restoring is in SaveDC/
910      * RestoreDC and not in GetDCState/SetDCState is that the ...DCState
911      * functions are only in Win16 (which doesn't have paths) and that
912      * SetDCState doesn't allow us to signal an error (which can happen
913      * when copying paths).
914      */
915   if (!PATH_AssignGdiPath (&dcs->w.path, &dc->w.path))
916   {
917     W32kDeleteDC (hdcs);
918     return 0;
919   }
920 #endif
921
922   DC_SetNextDC (dcs, DC_GetNextDC (dc));
923   DC_SetNextDC (dc, hdcs);
924   ret = ++dc->saveLevel;
925   DC_ReleasePtr( hdcs );
926   DC_ReleasePtr( hDC );
927
928   return  ret;
929 }
930
931 HGDIOBJ STDCALL W32kSelectObject(HDC  hDC, HGDIOBJ  hGDIObj)
932 {
933   HGDIOBJ   objOrg;
934   BITMAPOBJ *pb;
935   PSURFOBJ  surfobj;
936   PSURFGDI  surfgdi;
937   PDC dc;
938   PPENOBJ pen;
939   PBRUSHOBJ brush;
940   PXLATEOBJ XlateObj;
941   PPALGDI PalGDI;
942   WORD  objectMagic;
943   ULONG NumColors;
944
945   if(!hDC || !hGDIObj) return NULL;
946
947   dc = DC_HandleToPtr(hDC);
948   objectMagic = GDIOBJ_GetHandleMagic (hGDIObj);
949 //  GdiObjHdr = hGDIObj;
950
951   // FIXME: Get object handle from GDIObj and use it instead of GDIObj below?
952
953   switch(objectMagic) {
954     case GO_PEN_MAGIC:
955       objOrg = (HGDIOBJ)dc->w.hPen;
956       dc->w.hPen = hGDIObj;
957
958       // Convert the color of the pen to the format of the DC
959       PalGDI = (PPALGDI)AccessInternalObject(dc->w.hPalette);
960           if( PalGDI ){
961         XlateObj = (PXLATEOBJ)EngCreateXlate(PalGDI->Mode, PAL_RGB, dc->w.hPalette, NULL);
962         pen = GDIOBJ_LockObj(dc->w.hPen, GO_PEN_MAGIC);
963         pen->logpen.lopnColor = XLATEOBJ_iXlate(XlateObj, pen->logpen.lopnColor);
964                 GDIOBJ_UnlockObj( dc->w.hPen, GO_PEN_MAGIC);
965           }
966       break;
967     case GO_BRUSH_MAGIC:
968       objOrg = (HGDIOBJ)dc->w.hBrush;
969       dc->w.hBrush = (HBRUSH) hGDIObj;
970
971       // Convert the color of the brush to the format of the DC
972       PalGDI = (PPALGDI)AccessInternalObject(dc->w.hPalette);
973           if( PalGDI ){
974         XlateObj = (PXLATEOBJ)EngCreateXlate(PalGDI->Mode, PAL_RGB, dc->w.hPalette, NULL);
975         brush = GDIOBJ_LockObj(dc->w.hBrush, GO_BRUSH_MAGIC);
976         brush->iSolidColor = XLATEOBJ_iXlate(XlateObj,
977                                              brush->logbrush.lbColor);
978                 GDIOBJ_UnlockObj( dc->w.hBrush, GO_BRUSH_MAGIC);
979           }
980       break;
981       case GO_FONT_MAGIC:
982       objOrg = (HGDIOBJ)dc->w.hFont;
983       dc->w.hFont = (HFONT) hGDIObj;
984       break;
985     case GO_BITMAP_MAGIC:
986       // must be memory dc to select bitmap
987       if (!(dc->w.flags & DC_MEMORY)) return NULL;
988       objOrg = (HGDIOBJ)dc->w.hBitmap;
989
990       // setup mem dc for drawing into bitmap
991       pb   = BITMAPOBJ_HandleToPtr (hGDIObj);
992       dc->w.hBitmap = CreateGDIHandle(sizeof( SURFGDI ), sizeof( SURFOBJ )); // Assign the DC's bitmap
993
994       surfobj = (PSURFOBJ) AccessUserObject( dc->w.hBitmap );
995       surfgdi = (PSURFGDI) AccessInternalObject( dc->w.hBitmap );
996       BitmapToSurf(hDC, surfgdi, surfobj, pb); // Put the bitmap in a surface
997
998       dc->Surface = dc->w.hBitmap;
999
1000       // if we're working with a DIB, get the palette [fixme: only create if the selected palette is null]
1001       if(pb->dib)
1002       {
1003         dc->w.bitsPerPixel = pb->dib->dsBmih.biBitCount;
1004
1005         if(pb->dib->dsBmih.biBitCount <= 8)
1006         {
1007           if(pb->dib->dsBmih.biBitCount == 1) { NumColors = 2; } else
1008           if(pb->dib->dsBmih.biBitCount == 4) { NumColors = 16; } else
1009           if(pb->dib->dsBmih.biBitCount == 8) { NumColors = 256; }
1010
1011           dc->w.hPalette = EngCreatePalette(PAL_INDEXED, NumColors, pb->ColorMap, 0, 0, 0);
1012         } else
1013         if((pb->dib->dsBmih.biBitCount > 8) && (pb->dib->dsBmih.biBitCount < 24))
1014         {
1015           dc->w.hPalette = EngCreatePalette(PAL_BITFIELDS, pb->dib->dsBmih.biClrUsed, NULL, 0, 0, 0);
1016         } else
1017         if(pb->dib->dsBmih.biBitCount >= 24)
1018         {
1019           dc->w.hPalette = EngCreatePalette(PAL_RGB, pb->dib->dsBmih.biClrUsed, NULL, 0, 0, 0);
1020         }
1021       } else {
1022         dc->w.bitsPerPixel = pb->bitmap.bmBitsPixel;
1023       }
1024       break;
1025 #if UPDATEREGIONS
1026     case GO_REGION_MAGIC:
1027       /* objOrg = (HGDIOBJ)hDC->region; */
1028       objOrg = NULL; /* FIXME? hDC->region is destroyed below */
1029       SelectClipRgn(hDC, (HRGN)hGDIObj);
1030       break;
1031 #endif
1032     default:
1033       return NULL;
1034   }
1035   DC_ReleasePtr( hDC );
1036   return objOrg;
1037 }
1038
1039 DC_SET_MODE( W32kSetBkMode, w.backgroundMode, TRANSPARENT, OPAQUE )
1040 DC_SET_MODE( W32kSetPolyFillMode, w.polyFillMode, ALTERNATE, WINDING )
1041 // DC_SET_MODE( W32kSetRelAbs, w.relAbsMode, ABSOLUTE, RELATIVE )
1042 DC_SET_MODE( W32kSetROP2, w.ROPmode, R2_BLACK, R2_WHITE )
1043 DC_SET_MODE( W32kSetStretchBltMode, w.stretchBltMode, BLACKONWHITE, HALFTONE )
1044
1045 COLORREF STDCALL W32kSetBkColor(HDC hDC, COLORREF color)
1046 {
1047   COLORREF  oldColor;
1048   PDC  dc = DC_HandleToPtr(hDC);
1049
1050   if (!dc)
1051   {
1052     return 0x80000000;
1053   }
1054
1055   oldColor = dc->w.backgroundColor;
1056   dc->w.backgroundColor = color;
1057   DC_ReleasePtr( hDC );
1058   return  oldColor;
1059 }
1060
1061 static void  W32kSetDCState16(HDC  hDC, HDC  hDCSave)
1062 {
1063   PDC  dc, dcs;
1064
1065   dc = DC_HandleToPtr(hDC);
1066   if (dc == NULL)
1067   {
1068     return;
1069   }
1070
1071   dcs = DC_HandleToPtr(hDCSave);
1072   if (dcs == NULL)
1073   {
1074         DC_ReleasePtr( hDC );
1075     return;
1076   }
1077   if (!dcs->w.flags & DC_SAVED)
1078   {
1079     return;
1080   }
1081
1082   dc->w.flags            = dcs->w.flags & ~DC_SAVED;
1083
1084 #if 0
1085   dc->w.devCaps          = dcs->w.devCaps;
1086 #endif
1087
1088   dc->w.hFirstBitmap     = dcs->w.hFirstBitmap;
1089
1090 #if 0
1091   dc->w.hDevice          = dcs->w.hDevice;
1092 #endif
1093
1094   dc->w.totalExtent      = dcs->w.totalExtent;
1095   dc->w.ROPmode          = dcs->w.ROPmode;
1096   dc->w.polyFillMode     = dcs->w.polyFillMode;
1097   dc->w.stretchBltMode   = dcs->w.stretchBltMode;
1098   dc->w.relAbsMode       = dcs->w.relAbsMode;
1099   dc->w.backgroundMode   = dcs->w.backgroundMode;
1100   dc->w.backgroundColor  = dcs->w.backgroundColor;
1101   dc->w.textColor        = dcs->w.textColor;
1102   dc->w.brushOrgX        = dcs->w.brushOrgX;
1103   dc->w.brushOrgY        = dcs->w.brushOrgY;
1104   dc->w.textAlign        = dcs->w.textAlign;
1105   dc->w.charExtra        = dcs->w.charExtra;
1106   dc->w.breakTotalExtra  = dcs->w.breakTotalExtra;
1107   dc->w.breakCount       = dcs->w.breakCount;
1108   dc->w.breakExtra       = dcs->w.breakExtra;
1109   dc->w.breakRem         = dcs->w.breakRem;
1110   dc->w.MapMode          = dcs->w.MapMode;
1111   dc->w.GraphicsMode     = dcs->w.GraphicsMode;
1112 #if 0
1113   /* Apparently, the DC origin is not changed by [GS]etDCState */
1114   dc->w.DCOrgX           = dcs->w.DCOrgX;
1115   dc->w.DCOrgY           = dcs->w.DCOrgY;
1116 #endif
1117   dc->w.CursPosX         = dcs->w.CursPosX;
1118   dc->w.CursPosY         = dcs->w.CursPosY;
1119   dc->w.ArcDirection     = dcs->w.ArcDirection;
1120
1121 #if 0
1122   dc->w.xformWorld2Wnd   = dcs->w.xformWorld2Wnd;
1123   dc->w.xformWorld2Vport = dcs->w.xformWorld2Vport;
1124   dc->w.xformVport2World = dcs->w.xformVport2World;
1125   dc->w.vport2WorldValid = dcs->w.vport2WorldValid;
1126 #endif
1127
1128   dc->wndOrgX            = dcs->wndOrgX;
1129   dc->wndOrgY            = dcs->wndOrgY;
1130   dc->wndExtX            = dcs->wndExtX;
1131   dc->wndExtY            = dcs->wndExtY;
1132   dc->vportOrgX          = dcs->vportOrgX;
1133   dc->vportOrgY          = dcs->vportOrgY;
1134   dc->vportExtX          = dcs->vportExtX;
1135   dc->vportExtY          = dcs->vportExtY;
1136
1137   if (!(dc->w.flags & DC_MEMORY))
1138   {
1139     dc->w.bitsPerPixel = dcs->w.bitsPerPixel;
1140   }
1141
1142 #if 0
1143   if (dcs->w.hClipRgn)
1144   {
1145     if (!dc->w.hClipRgn)
1146     {
1147       dc->w.hClipRgn = W32kCreateRectRgn( 0, 0, 0, 0 );
1148     }
1149     W32kCombineRgn( dc->w.hClipRgn, dcs->w.hClipRgn, 0, RGN_COPY );
1150   }
1151   else
1152   {
1153     if (dc->w.hClipRgn)
1154     {
1155       W32kDeleteObject( dc->w.hClipRgn );
1156     }
1157
1158     dc->w.hClipRgn = 0;
1159   }
1160   CLIPPING_UpdateGCRegion( dc );
1161 #endif
1162
1163   W32kSelectObject( hDC, dcs->w.hBitmap );
1164   W32kSelectObject( hDC, dcs->w.hBrush );
1165   W32kSelectObject( hDC, dcs->w.hFont );
1166   W32kSelectObject( hDC, dcs->w.hPen );
1167   W32kSetBkColor( hDC, dcs->w.backgroundColor);
1168   W32kSetTextColor( hDC, dcs->w.textColor);
1169
1170 #if 0
1171   GDISelectPalette16( hDC, dcs->w.hPalette, FALSE );
1172 #endif
1173
1174   DC_ReleasePtr( hDCSave );
1175   DC_ReleasePtr( hDC );
1176 }
1177
1178 //  ----------------------------------------------------  Private Interface
1179
1180 HDC  DC_AllocDC(LPCWSTR  Driver)
1181 {
1182         PDC  NewDC;
1183         HDC  hDC;
1184
1185         hDC = (HDC) GDIOBJ_AllocObj(sizeof(DC), GO_DC_MAGIC);
1186         if (hDC == NULL)
1187         {
1188           return  NULL;
1189         }
1190
1191         NewDC = (PDC) GDIOBJ_LockObj( hDC, GO_DC_MAGIC );
1192
1193         if (Driver != NULL)
1194         {
1195           NewDC->DriverName = ExAllocatePool(PagedPool, (wcslen(Driver) + 1) * sizeof(WCHAR));
1196           wcscpy(NewDC->DriverName, Driver);
1197         }
1198
1199         NewDC->w.xformWorld2Wnd.eM11 = 1.0f;
1200         NewDC->w.xformWorld2Wnd.eM12 = 0.0f;
1201         NewDC->w.xformWorld2Wnd.eM21 = 0.0f;
1202         NewDC->w.xformWorld2Wnd.eM22 = 1.0f;
1203         NewDC->w.xformWorld2Wnd.eDx = 0.0f;
1204         NewDC->w.xformWorld2Wnd.eDy = 0.0f;
1205         NewDC->w.xformWorld2Vport = NewDC->w.xformWorld2Wnd;
1206         NewDC->w.xformVport2World = NewDC->w.xformWorld2Wnd;
1207         NewDC->w.vport2WorldValid = TRUE;
1208
1209         NewDC->w.hFont = W32kGetStockObject(SYSTEM_FONT);
1210
1211         GDIOBJ_UnlockObj( hDC, GO_DC_MAGIC );
1212         return  hDC;
1213 }
1214
1215 HDC  DC_FindOpenDC(LPCWSTR  Driver)
1216 {
1217   return NULL;
1218 }
1219
1220 void  DC_InitDC(HDC  DCHandle)
1221 {
1222 //  W32kRealizeDefaultPalette(DCHandle);
1223   PDC DCToInit;
1224   if( (DCToInit = DC_HandleToPtr( DCHandle ) ) ){
1225           W32kSetTextColor(DCHandle, DCToInit->w.textColor);
1226           W32kSetBkColor(DCHandle, DCToInit->w.backgroundColor);
1227           W32kSelectObject(DCHandle, DCToInit->w.hPen);
1228           W32kSelectObject(DCHandle, W32kGetStockObject( GRAY_BRUSH )); //FIXME: default should be WHITE_BRUSH
1229           W32kSelectObject(DCHandle, DCToInit->w.hFont);
1230   }
1231   else
1232   DPRINT("DC_InitDC: can't get dc for handle %d\n", DCHandle );
1233 //  CLIPPING_UpdateGCRegion(DCToInit);
1234 }
1235
1236 void  DC_FreeDC(HDC  DCToFree)
1237 {
1238   if (!GDIOBJ_FreeObj(DCToFree, GO_DC_MAGIC, GDIOBJFLAG_DEFAULT))
1239   {
1240     DPRINT("DC_FreeDC failed\n");
1241   }
1242 }
1243
1244 BOOL DC_InternalDeleteDC( PDC DCToDelete )
1245 {
1246         if( DCToDelete->DriverName )
1247                 ExFreePool(DCToDelete->DriverName);
1248         return TRUE;
1249 }
1250
1251 HDC  DC_GetNextDC (PDC pDC)
1252 {
1253   return pDC->hNext;
1254 }
1255
1256 void  DC_SetNextDC (PDC pDC, HDC hNextDC)
1257 {
1258   pDC->hNext = hNextDC;
1259 }
1260
1261 void
1262 DC_UpdateXforms(PDC  dc)
1263 {
1264   XFORM  xformWnd2Vport;
1265   FLOAT  scaleX, scaleY;
1266
1267   /* Construct a transformation to do the window-to-viewport conversion */
1268   scaleX = (FLOAT)dc->vportExtX / (FLOAT)dc->wndExtX;
1269   scaleY = (FLOAT)dc->vportExtY / (FLOAT)dc->wndExtY;
1270   xformWnd2Vport.eM11 = scaleX;
1271   xformWnd2Vport.eM12 = 0.0;
1272   xformWnd2Vport.eM21 = 0.0;
1273   xformWnd2Vport.eM22 = scaleY;
1274   xformWnd2Vport.eDx  = (FLOAT)dc->vportOrgX - scaleX * (FLOAT)dc->wndOrgX;
1275   xformWnd2Vport.eDy  = (FLOAT)dc->vportOrgY - scaleY * (FLOAT)dc->wndOrgY;
1276
1277   /* Combine with the world transformation */
1278   W32kCombineTransform(&dc->w.xformWorld2Vport, &dc->w.xformWorld2Wnd, &xformWnd2Vport);
1279
1280   /* Create inverse of world-to-viewport transformation */
1281   dc->w.vport2WorldValid = DC_InvertXform(&dc->w.xformWorld2Vport, &dc->w.xformVport2World);
1282 }
1283
1284 BOOL
1285 DC_InvertXform(const XFORM *xformSrc,
1286                XFORM *xformDest)
1287 {
1288   FLOAT  determinant;
1289
1290   determinant = xformSrc->eM11*xformSrc->eM22 - xformSrc->eM12*xformSrc->eM21;
1291   if (determinant > -1e-12 && determinant < 1e-12)
1292   {
1293     return  FALSE;
1294   }
1295
1296   xformDest->eM11 =  xformSrc->eM22 / determinant;
1297   xformDest->eM12 = -xformSrc->eM12 / determinant;
1298   xformDest->eM21 = -xformSrc->eM21 / determinant;
1299   xformDest->eM22 =  xformSrc->eM11 / determinant;
1300   xformDest->eDx  = -xformSrc->eDx * xformDest->eM11 - xformSrc->eDy * xformDest->eM21;
1301   xformDest->eDy  = -xformSrc->eDx * xformDest->eM12 - xformSrc->eDy * xformDest->eM22;
1302
1303   return  TRUE;
1304 }