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