update for HEAD-2003091401
[reactos.git] / subsys / win32k / objects / dc.c
1 /*
2  *  ReactOS W32 Subsystem
3  *  Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 /* $Id$
20  *
21  * DC.C - Device context functions
22  *
23  */
24
25 #undef WIN32_LEAN_AND_MEAN
26 #include <windows.h>
27 #include <ddk/ntddk.h>
28 #include <ddk/ntddvid.h>
29
30 #include <win32k/bitmaps.h>
31 #include <win32k/brush.h>
32 #include <win32k/cliprgn.h>
33 #include <win32k/coord.h>
34 #include <win32k/driver.h>
35 #include <win32k/dc.h>
36 #include <win32k/misc.h>
37 #include <win32k/print.h>
38 #include <win32k/region.h>
39 #include <win32k/gdiobj.h>
40 #include <win32k/paint.h>
41 #include <win32k/pen.h>
42 #include <win32k/text.h>
43 #include "../eng/clip.h"
44 #include "../eng/handle.h"
45 #include <include/inteng.h>
46 #include <include/eng.h>
47 #include <include/palette.h>
48
49 #define NDEBUG
50 #include <win32k/debug1.h>
51
52 static GDIDEVICE PrimarySurface;
53 static BOOL PrimarySurfaceCreated = FALSE;
54
55 /* FIXME: DCs should probably be thread safe  */
56
57 /*
58  * DC device-independent Get/SetXXX functions
59  * (RJJ) swiped from WINE
60  */
61
62 #define DC_GET_VAL( func_type, func_name, dc_field ) \
63 func_type STDCALL  func_name( HDC hdc ) \
64 {                                   \
65   func_type  ft;                    \
66   PDC  dc = DC_LockDc( hdc );  \
67   if (!dc)                          \
68   {                                 \
69     return 0;                       \
70   }                                 \
71   ft = dc->dc_field;                \
72   DC_UnlockDc( hdc );                           \
73   return ft;                        \
74 }
75
76 /* DC_GET_VAL_EX is used to define functions returning a POINT or a SIZE. It is
77  * important that the function has the right signature, for the implementation
78  * we can do whatever we want.
79  */
80 #define DC_GET_VAL_EX( NtGdiFuncName, IntFuncName, ret_x, ret_y, type ) \
81 VOID FASTCALL IntFuncName ( PDC dc, LP##type pt )  \
82 {                                                  \
83   ASSERT ( dc );                                   \
84   ASSERT ( pt );                                   \
85   ((LPPOINT)pt)->x = dc->ret_x;                    \
86   ((LPPOINT)pt)->y = dc->ret_y;                    \
87 }                                                  \
88 BOOL STDCALL NtGdiFuncName ( HDC hdc, LP##type pt ) \
89 {                                                  \
90   PDC dc = DC_LockDc ( hdc );                 \
91   if ( !dc )                                       \
92     return FALSE;                                  \
93   IntFuncName ( dc, pt );                          \
94   DC_UnlockDc ( hdc );                           \
95   return TRUE;                                     \
96 }
97
98 #define DC_SET_MODE( func_name, dc_field, min_val, max_val ) \
99 INT STDCALL  func_name( HDC hdc, INT mode ) \
100 {                                           \
101   INT  prevMode;                            \
102   PDC  dc;                                  \
103   if ((mode < min_val) || (mode > max_val)) \
104     return 0;                               \
105   dc = DC_LockDc ( hdc );              \
106   if ( !dc )                                \
107     return 0;                               \
108   prevMode = dc->dc_field;                  \
109   dc->dc_field = mode;                      \
110   DC_UnlockDc ( hdc );                    \
111   return prevMode;                          \
112 }
113
114
115 //  ---------------------------------------------------------  File Statics
116
117 //  -----------------------------------------------------  Public Functions
118
119 BOOL STDCALL
120 NtGdiCancelDC(HDC  hDC)
121 {
122   UNIMPLEMENTED;
123 }
124
125 HDC STDCALL
126 NtGdiCreateCompatableDC(HDC  hDC)
127 {
128   PDC  NewDC, OrigDC;
129   HBITMAP  hBitmap;
130   HDC hNewDC;
131   HRGN hVisRgn;
132   BITMAPOBJ *pb;
133
134   if (hDC == NULL)
135   {
136     OrigDC = NULL;
137     hNewDC = DC_AllocDC(L"DISPLAY");
138   }
139   else
140   {
141     /*  Allocate a new DC based on the original DC's device  */
142     OrigDC = DC_LockDc(hDC);
143     if (NULL == OrigDC)
144     {
145       return NULL;
146     }
147     hNewDC = DC_AllocDC(OrigDC->DriverName);
148   }
149
150   if (NULL == hNewDC)
151   {
152     return  NULL;
153   }
154   NewDC = DC_LockDc( hNewDC );
155
156   /* Copy information from original DC to new DC  */
157   NewDC->hSelf = NewDC;
158
159   /* FIXME: Should this DC request its own PDEV?  */
160   if(OrigDC == NULL)
161   {
162     NewDC->PDev = PrimarySurface.PDev;
163     memcpy(NewDC->FillPatternSurfaces, PrimarySurface.FillPatterns,
164            sizeof(NewDC->FillPatternSurfaces));
165     NewDC->GDIInfo = &PrimarySurface.GDIInfo;
166     NewDC->DevInfo = &PrimarySurface.DevInfo;
167   }
168   else
169   {
170     NewDC->PDev = OrigDC->PDev;
171     NewDC->DMW = OrigDC->DMW;
172     memcpy(NewDC->FillPatternSurfaces,
173            OrigDC->FillPatternSurfaces,
174            sizeof OrigDC->FillPatternSurfaces);
175     NewDC->GDIInfo = OrigDC->GDIInfo;
176     NewDC->DevInfo = OrigDC->DevInfo;
177   }
178
179   /* DriverName is copied in the AllocDC routine  */
180   if(OrigDC == NULL)
181   {
182     NewDC->DeviceDriver = DRIVER_FindMPDriver(NewDC->DriverName);
183   }
184   else
185   {
186     NewDC->DeviceDriver = OrigDC->DeviceDriver;
187     NewDC->wndOrgX = OrigDC->wndOrgX;
188     NewDC->wndOrgY = OrigDC->wndOrgY;
189     NewDC->wndExtX = OrigDC->wndExtX;
190     NewDC->wndExtY = OrigDC->wndExtY;
191     NewDC->vportOrgX = OrigDC->vportOrgX;
192     NewDC->vportOrgY = OrigDC->vportOrgY;
193     NewDC->vportExtX = OrigDC->vportExtX;
194     NewDC->vportExtY = OrigDC->vportExtY;
195   }
196
197   /* Create default bitmap */
198   if (!(hBitmap = NtGdiCreateBitmap( 1, 1, 1, 1, NULL )))
199   {
200     DC_UnlockDc( hDC );
201     DC_UnlockDc( hNewDC );
202     DC_FreeDC( hNewDC );
203     return NULL;
204   }
205   NewDC->w.flags        = DC_MEMORY;
206   NewDC->w.bitsPerPixel = 1;
207   NewDC->w.hBitmap      = hBitmap;
208   NewDC->w.hFirstBitmap = hBitmap;
209   pb = BITMAPOBJ_LockBitmap(hBitmap);
210   NewDC->Surface = BitmapToSurf(pb);
211   BITMAPOBJ_UnlockBitmap(hBitmap);
212
213   if(OrigDC == NULL)
214   {
215     NewDC->w.hPalette = NewDC->DevInfo->hpalDefault;
216   }
217   else
218   {
219     NewDC->w.hPalette = OrigDC->w.hPalette;
220     NewDC->w.textColor = OrigDC->w.textColor;
221     NewDC->w.textAlign = OrigDC->w.textAlign;
222     NewDC->w.backgroundColor = OrigDC->w.backgroundColor;
223     NewDC->w.backgroundMode = OrigDC->w.backgroundMode;
224   }
225   if (NULL != hDC)
226   {
227     DC_UnlockDc( hDC );
228   }
229   DC_UnlockDc( hNewDC );
230
231   hVisRgn = NtGdiCreateRectRgn(0, 0, 1, 1);
232   NtGdiSelectVisRgn(hNewDC, hVisRgn);
233   NtGdiDeleteObject(hVisRgn);
234
235   DC_InitDC(hNewDC);
236
237   return  hNewDC;
238 }
239
240 static BOOL STDCALL
241 FindDriverFileNames(PUNICODE_STRING DriverFileNames)
242 {
243   RTL_QUERY_REGISTRY_TABLE QueryTable[2];
244   UNICODE_STRING RegistryPath;
245   NTSTATUS Status;
246
247   RtlInitUnicodeString(&RegistryPath, NULL);
248   RtlZeroMemory(QueryTable, sizeof(QueryTable));
249   QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT;
250   QueryTable[0].Name = L"\\Device\\Video0";
251   QueryTable[0].EntryContext = &RegistryPath;
252
253   Status = RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP,
254                                   L"VIDEO",
255                                   QueryTable,
256                                   NULL,
257                                   NULL);
258   if (! NT_SUCCESS(Status))
259   {
260     DPRINT1("No \\Device\\Video0 value in DEVICEMAP\\VIDEO found\n");
261     return FALSE;
262   }
263
264   DPRINT("RegistryPath %S\n", RegistryPath.Buffer);
265
266   QueryTable[0].Name = L"InstalledDisplayDrivers";
267   QueryTable[0].EntryContext = DriverFileNames;
268
269   Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
270                                   RegistryPath.Buffer,
271                                   QueryTable,
272                                   NULL,
273                                   NULL);
274   RtlFreeUnicodeString(&RegistryPath);
275   if (! NT_SUCCESS(Status))
276   {
277     DPRINT1("No InstalledDisplayDrivers value in service entry found\n");
278     return FALSE;
279   }
280
281   DPRINT("DriverFileNames %S\n", DriverFileNames->Buffer);
282
283   return TRUE;
284 }
285
286
287 BOOL STDCALL
288 NtGdiCreatePrimarySurface(LPCWSTR Driver,
289                                       LPCWSTR Device)
290 {
291   PGD_ENABLEDRIVER GDEnableDriver;
292   DRVENABLEDATA DED;
293   PSURFOBJ SurfObj;
294   PSURFGDI SurfGDI;
295   UNICODE_STRING DriverFileNames;
296   PWSTR CurrentName;
297   BOOL GotDriver;
298   extern void FASTCALL IntInitDesktopWindow(ULONG Width, ULONG Height);
299
300   /*  Open the miniport driver  */
301   if ((PrimarySurface.DisplayDevice = DRIVER_FindMPDriver(Driver)) == NULL)
302   {
303     DPRINT("FindMPDriver failed\n");
304     return(FALSE);
305   }
306
307   /*  Retrieve DDI driver names from registry */
308   RtlInitUnicodeString(&DriverFileNames, NULL);
309   if (! FindDriverFileNames(&DriverFileNames))
310   {
311     DPRINT("FindDriverFileNames failed\n");
312     return(FALSE);
313   }
314
315   /* DriverFileNames may be a list of drivers in REG_SZ_MULTI format, scan all of
316      them until a good one found */
317   CurrentName = DriverFileNames.Buffer;
318   GotDriver = FALSE;
319   while (! GotDriver && CurrentName < DriverFileNames.Buffer + DriverFileNames.Length)
320   {
321     /*  Get the DDI driver's entry point  */
322     GDEnableDriver = DRIVER_FindDDIDriver(CurrentName);
323     if (NULL == GDEnableDriver)
324     {
325       DPRINT("FindDDIDriver failed for %S\n", CurrentName);
326     }
327     else
328     {
329       /*  Call DDI driver's EnableDriver function  */
330       RtlZeroMemory(&DED, sizeof(DED));
331
332       if (!GDEnableDriver(DDI_DRIVER_VERSION, sizeof(DED), &DED))
333       {
334         DPRINT("DrvEnableDriver failed for %S\n", CurrentName);
335       }
336       else
337       {
338         GotDriver = TRUE;
339       }
340     }
341
342     if (! GotDriver)
343     {
344       /* Skip to the next name but never get past the Unicode string */
345       while (L'\0' != *CurrentName &&
346              CurrentName < DriverFileNames.Buffer + DriverFileNames.Length)
347       {
348         CurrentName++;
349       }
350       if (CurrentName < DriverFileNames.Buffer + DriverFileNames.Length)
351       {
352         CurrentName++;
353       }
354     }
355   }
356   RtlFreeUnicodeString(&DriverFileNames);
357   if (! GotDriver)
358   {
359     DPRINT("No suitable driver found\n");
360     return FALSE;
361   }
362
363   DPRINT("Display driver %S loaded\n", CurrentName);
364
365   DPRINT("Building DDI Functions\n");
366
367   /*  Construct DDI driver function dispatch table  */
368   if (!DRIVER_BuildDDIFunctions(&DED, &PrimarySurface.DriverFunctions))
369   {
370     DPRINT("BuildDDIFunctions failed\n");
371     return(FALSE);
372   }
373
374   /*  Allocate a phyical device handle from the driver  */
375   if (Device != NULL)
376   {
377     DPRINT("Device in u: %u\n", Device);
378 //    wcsncpy(NewDC->DMW.dmDeviceName, Device, DMMAXDEVICENAME); FIXME: this crashes everything?
379   }
380
381   DPRINT("Enabling PDev\n");
382
383   PrimarySurface.PDev =
384     PrimarySurface.DriverFunctions.EnablePDev(&PrimarySurface.DMW,
385                                              L"",
386                                              HS_DDI_MAX,
387                                              PrimarySurface.FillPatterns,
388                                              sizeof(PrimarySurface.GDIInfo),
389                                              (ULONG *) &PrimarySurface.GDIInfo,
390                                              sizeof(PrimarySurface.DevInfo),
391                                              &PrimarySurface.DevInfo,
392                                              NULL,
393                                              L"",
394                                              PrimarySurface.DisplayDevice);
395   if (PrimarySurface.PDev == NULL)
396   {
397     DPRINT("DrvEnablePDEV failed\n");
398     return(FALSE);
399   }
400
401   DPRINT("calling completePDev\n");
402
403   /*  Complete initialization of the physical device  */
404   PrimarySurface.DriverFunctions.CompletePDev(PrimarySurface.PDev,
405                                               &PrimarySurface);
406
407   DPRINT("calling DRIVER_ReferenceDriver\n");
408
409   DRIVER_ReferenceDriver (Driver);
410
411   DPRINT("calling EnableSurface\n");
412
413   /*  Enable the drawing surface  */
414   PrimarySurface.Handle =
415     PrimarySurface.DriverFunctions.EnableSurface(PrimarySurface.PDev);
416
417   SurfObj = (PSURFOBJ)AccessUserObject((ULONG) PrimarySurface.Handle);
418   SurfObj->dhpdev = PrimarySurface.PDev;
419   SurfGDI = (PSURFGDI)AccessInternalObject((ULONG) PrimarySurface.Handle);
420   IntInitDesktopWindow(SurfGDI->SurfObj.sizlBitmap.cx, SurfGDI->SurfObj.sizlBitmap.cy);
421
422   return TRUE;
423 }
424
425 HDC STDCALL
426 NtGdiCreateDC(LPCWSTR  Driver,
427              LPCWSTR  Device,
428              LPCWSTR  Output,
429              CONST PDEVMODEW  InitData)
430 {
431   HDC      hNewDC;
432   PDC      NewDC;
433   HDC      hDC = NULL;
434   PSURFGDI SurfGDI;
435   HRGN     hVisRgn;
436
437   /*  Check for existing DC object  */
438   if ((hNewDC = DC_FindOpenDC(Driver)) != NULL)
439   {
440     hDC = hNewDC;
441     return  NtGdiCreateCompatableDC(hDC);
442   }
443
444   DPRINT("NAME: %S\n", Driver); // FIXME: Should not crash if NULL
445
446   /*  Allocate a DC object  */
447   if ((hNewDC = DC_AllocDC(Driver)) == NULL)
448   {
449     return  NULL;
450   }
451
452   NewDC = DC_LockDc( hNewDC );
453   ASSERT( NewDC );
454
455   if (! PrimarySurfaceCreated)
456     {
457       PrimarySurfaceCreated = TRUE;
458       if (!NtGdiCreatePrimarySurface(Driver, Device))
459         {
460           PrimarySurfaceCreated = FALSE;
461           DC_UnlockDc( hNewDC );
462           DC_FreeDC(hNewDC);
463           return  NULL;
464         }
465     }
466   NewDC->DMW = PrimarySurface.DMW;
467   NewDC->DevInfo = &PrimarySurface.DevInfo;
468   NewDC->GDIInfo = &PrimarySurface.GDIInfo;
469   memcpy(NewDC->FillPatternSurfaces, PrimarySurface.FillPatterns,
470          sizeof(NewDC->FillPatternSurfaces));
471   NewDC->PDev = PrimarySurface.PDev;
472   NewDC->Surface = PrimarySurface.Handle;
473   NewDC->DriverFunctions = PrimarySurface.DriverFunctions;
474
475   NewDC->DMW.dmSize = sizeof(NewDC->DMW);
476   NewDC->DMW.dmFields = 0x000fc000;
477
478   /* FIXME: get mode selection information from somewhere  */
479
480   NewDC->DMW.dmLogPixels = 96;
481   SurfGDI = (PSURFGDI)AccessInternalObject((ULONG) PrimarySurface.Handle);
482   NewDC->DMW.dmBitsPerPel = SurfGDI->BitsPerPixel;
483   NewDC->DMW.dmPelsWidth = SurfGDI->SurfObj.sizlBitmap.cx;
484   NewDC->DMW.dmPelsHeight = SurfGDI->SurfObj.sizlBitmap.cy;
485   NewDC->DMW.dmDisplayFlags = 0;
486   NewDC->DMW.dmDisplayFrequency = 0;
487
488   NewDC->w.bitsPerPixel = SurfGDI->BitsPerPixel; // FIXME: set this here??
489
490   NewDC->w.hPalette = NewDC->DevInfo->hpalDefault;
491
492   DPRINT("Bits per pel: %u\n", NewDC->w.bitsPerPixel);
493   
494   DC_UnlockDc( hNewDC );
495
496   hVisRgn = NtGdiCreateRectRgn(0, 0, SurfGDI->SurfObj.sizlBitmap.cx,
497                               SurfGDI->SurfObj.sizlBitmap.cy);
498   NtGdiSelectVisRgn(hNewDC, hVisRgn);
499   NtGdiDeleteObject(hVisRgn);
500
501   /*  Initialize the DC state  */
502   DC_InitDC(hNewDC);
503   NtGdiSetTextColor(hNewDC, RGB(0, 0, 0));
504   NtGdiSetTextAlign(hNewDC, TA_TOP);
505   NtGdiSetBkColor(hNewDC, RGB(255, 255, 255));
506   NtGdiSetBkMode(hNewDC, OPAQUE);
507
508   return hNewDC;
509 }
510
511 HDC STDCALL
512 NtGdiCreateIC(LPCWSTR  Driver,
513              LPCWSTR  Device,
514              LPCWSTR  Output,
515              CONST PDEVMODEW  DevMode)
516 {
517   /* FIXME: this should probably do something else...  */
518   return  NtGdiCreateDC(Driver, Device, Output, DevMode);
519 }
520
521 BOOL STDCALL
522 NtGdiDeleteDC(HDC  DCHandle)
523 {
524   PDC  DCToDelete;
525
526   DCToDelete = DC_LockDc(DCHandle);
527   if (DCToDelete == NULL)
528     {
529       return  FALSE;
530     }
531   DPRINT( "Deleting DC\n" );
532   if ((!(DCToDelete->w.flags & DC_MEMORY))) // Don't reset the display if its a memory DC
533   {
534     if (!DRIVER_UnreferenceDriver (DCToDelete->DriverName))
535     {
536       PEPROCESS CurrentProcess;
537       DPRINT( "No more references to driver, reseting display\n" );
538       DCToDelete->DriverFunctions.AssertMode( DCToDelete->PDev, FALSE );
539       CHECKPOINT;
540       DCToDelete->DriverFunctions.DisableSurface(DCToDelete->PDev);
541       CHECKPOINT;
542       DCToDelete->DriverFunctions.DisablePDev(DCToDelete->PDev);
543
544       CurrentProcess = PsGetCurrentProcess();
545       if (CurrentProcess != Win32kDeviceProcess)
546         {
547           KeAttachProcess(Win32kDeviceProcess);
548         }
549       ZwClose(PrimarySurface.DisplayDevice);
550       if (CurrentProcess != Win32kDeviceProcess)
551         {
552           KeDetachProcess();
553         }
554
555       PrimarySurfaceCreated = FALSE;
556     }
557   }
558   CHECKPOINT;
559   /*  First delete all saved DCs  */
560   while (DCToDelete->saveLevel)
561   {
562     PDC  savedDC;
563     HDC  savedHDC;
564
565     savedHDC = DC_GetNextDC (DCToDelete);
566     savedDC = DC_LockDc (savedHDC);
567     if (savedDC == NULL)
568     {
569       break;
570     }
571     DC_SetNextDC (DCToDelete, DC_GetNextDC (savedDC));
572     DCToDelete->saveLevel--;
573         DC_UnlockDc( savedHDC );
574     NtGdiDeleteDC (savedHDC);
575   }
576
577   /*  Free GDI resources allocated to this DC  */
578   if (!(DCToDelete->w.flags & DC_SAVED))
579   {
580     /*
581     NtGdiSelectObject (DCHandle, STOCK_BLACK_PEN);
582     NtGdiSelectObject (DCHandle, STOCK_WHITE_BRUSH);
583     NtGdiSelectObject (DCHandle, STOCK_SYSTEM_FONT);
584     DC_LockDC (DCHandle); NtGdiSelectObject does not recognize stock objects yet  */
585     if (DCToDelete->w.flags & DC_MEMORY)
586     {
587       EngDeleteSurface (DCToDelete->Surface);
588       NtGdiDeleteObject (DCToDelete->w.hFirstBitmap);
589     }
590   }
591   if (DCToDelete->w.hClipRgn)
592   {
593     NtGdiDeleteObject (DCToDelete->w.hClipRgn);
594   }
595   if (DCToDelete->w.hVisRgn)
596   {
597     NtGdiDeleteObject (DCToDelete->w.hVisRgn);
598   }
599   if (NULL != DCToDelete->CombinedClip)
600     {
601       IntEngDeleteClipRegion(DCToDelete->CombinedClip);
602     }
603   if (DCToDelete->w.hGCClipRgn)
604   {
605     NtGdiDeleteObject (DCToDelete->w.hGCClipRgn);
606   }
607 #if 0 /* FIXME */
608   PATH_DestroyGdiPath (&DCToDelete->w.path);
609 #endif
610   DC_UnlockDc( DCHandle );
611   DC_FreeDC ( DCHandle );
612
613   return TRUE;
614 }
615
616 INT STDCALL
617 NtGdiDrawEscape(HDC  hDC,
618                INT  nEscape,
619                INT  cbInput,
620                LPCSTR  lpszInData)
621 {
622   UNIMPLEMENTED;
623 }
624
625 INT STDCALL
626 NtGdiEnumObjects(HDC  hDC,
627                 INT  ObjectType,
628                 GOBJENUMPROC  ObjectFunc,
629                 LPARAM  lParam)
630 {
631   UNIMPLEMENTED;
632 }
633
634 DC_GET_VAL( COLORREF, NtGdiGetBkColor, w.backgroundColor )
635 DC_GET_VAL( INT, NtGdiGetBkMode, w.backgroundMode )
636 DC_GET_VAL_EX( NtGdiGetBrushOrgEx, IntGetBrushOrgEx, w.brushOrgX, w.brushOrgY, POINT )
637 DC_GET_VAL( HRGN, NtGdiGetClipRgn, w.hClipRgn )
638
639 HGDIOBJ STDCALL
640 NtGdiGetCurrentObject(HDC  hDC, UINT  ObjectType)
641 {
642   UNIMPLEMENTED;
643 }
644
645 DC_GET_VAL_EX ( NtGdiGetCurrentPositionEx, IntGetCurrentPositionEx, w.CursPosX, w.CursPosY, POINT )
646
647 BOOL STDCALL
648 NtGdiGetDCOrgEx(HDC  hDC, LPPOINT  Point)
649 {
650   PDC dc;
651
652   if (!Point)
653   {
654     return FALSE;
655   }
656   dc = DC_LockDc(hDC);
657   if (dc == NULL)
658   {
659     return FALSE;
660   }
661
662   Point->x = Point->y = 0;
663
664   Point->x += dc->w.DCOrgX;
665   Point->y += dc->w.DCOrgY;
666   DC_UnlockDc( hDC );
667   return  TRUE;
668 }
669
670 COLORREF STDCALL
671 NtGdiSetBkColor(HDC hDC, COLORREF color)
672 {
673   COLORREF oldColor;
674   PDC  dc = DC_LockDc(hDC);
675
676   if ( !dc )
677     return 0x80000000;
678
679   oldColor = dc->w.backgroundColor;
680   dc->w.backgroundColor = color;
681   DC_UnlockDc ( hDC );
682   return oldColor;
683 }
684
685 static HDC STDCALL
686 NtGdiGetDCState(HDC  hDC)
687 {
688   PDC  newdc, dc;
689   HDC hnewdc;
690
691   dc = DC_LockDc(hDC);
692   if (dc == NULL)
693   {
694     return 0;
695   }
696
697   hnewdc = DC_AllocDC(NULL);
698   if (hnewdc == NULL)
699   {
700     DC_UnlockDc( hDC );
701     return 0;
702   }
703   newdc = DC_LockDc( hnewdc );
704   ASSERT( newdc );
705
706   newdc->w.flags            = dc->w.flags | DC_SAVED;
707   newdc->w.hPen             = dc->w.hPen;
708   newdc->w.hBrush           = dc->w.hBrush;
709   newdc->w.hFont            = dc->w.hFont;
710   newdc->w.hBitmap          = dc->w.hBitmap;
711   newdc->w.hFirstBitmap     = dc->w.hFirstBitmap;
712 #if 0
713   newdc->w.hDevice          = dc->w.hDevice;
714   newdc->w.hPalette         = dc->w.hPalette;
715 #endif
716   newdc->w.totalExtent      = dc->w.totalExtent;
717   newdc->w.bitsPerPixel     = dc->w.bitsPerPixel;
718   newdc->w.ROPmode          = dc->w.ROPmode;
719   newdc->w.polyFillMode     = dc->w.polyFillMode;
720   newdc->w.stretchBltMode   = dc->w.stretchBltMode;
721   newdc->w.relAbsMode       = dc->w.relAbsMode;
722   newdc->w.backgroundMode   = dc->w.backgroundMode;
723   newdc->w.backgroundColor  = dc->w.backgroundColor;
724   newdc->w.textColor        = dc->w.textColor;
725   newdc->w.brushOrgX        = dc->w.brushOrgX;
726   newdc->w.brushOrgY        = dc->w.brushOrgY;
727   newdc->w.textAlign        = dc->w.textAlign;
728   newdc->w.charExtra        = dc->w.charExtra;
729   newdc->w.breakTotalExtra  = dc->w.breakTotalExtra;
730   newdc->w.breakCount       = dc->w.breakCount;
731   newdc->w.breakExtra       = dc->w.breakExtra;
732   newdc->w.breakRem         = dc->w.breakRem;
733   newdc->w.MapMode          = dc->w.MapMode;
734   newdc->w.GraphicsMode     = dc->w.GraphicsMode;
735 #if 0
736   /* Apparently, the DC origin is not changed by [GS]etDCState */
737   newdc->w.DCOrgX           = dc->w.DCOrgX;
738   newdc->w.DCOrgY           = dc->w.DCOrgY;
739 #endif
740   newdc->w.CursPosX         = dc->w.CursPosX;
741   newdc->w.CursPosY         = dc->w.CursPosY;
742   newdc->w.ArcDirection     = dc->w.ArcDirection;
743 #if 0
744   newdc->w.xformWorld2Wnd   = dc->w.xformWorld2Wnd;
745   newdc->w.xformWorld2Vport = dc->w.xformWorld2Vport;
746   newdc->w.xformVport2World = dc->w.xformVport2World;
747   newdc->w.vport2WorldValid = dc->w.vport2WorldValid;
748 #endif
749   newdc->wndOrgX            = dc->wndOrgX;
750   newdc->wndOrgY            = dc->wndOrgY;
751   newdc->wndExtX            = dc->wndExtX;
752   newdc->wndExtY            = dc->wndExtY;
753   newdc->vportOrgX          = dc->vportOrgX;
754   newdc->vportOrgY          = dc->vportOrgY;
755   newdc->vportExtX          = dc->vportExtX;
756   newdc->vportExtY          = dc->vportExtY;
757
758   newdc->hSelf = hnewdc;
759   newdc->saveLevel = 0;
760
761 #if 0
762   PATH_InitGdiPath( &newdc->w.path );
763 #endif
764
765   /* Get/SetDCState() don't change hVisRgn field ("Undoc. Windows" p.559). */
766
767 #if 0
768   newdc->w.hGCClipRgn = newdc->w.hVisRgn = 0;
769 #endif
770   if (dc->w.hClipRgn)
771   {
772     newdc->w.hClipRgn = NtGdiCreateRectRgn( 0, 0, 0, 0 );
773     NtGdiCombineRgn( newdc->w.hClipRgn, dc->w.hClipRgn, 0, RGN_COPY );
774   }
775   else
776   {
777     newdc->w.hClipRgn = 0;
778   }
779   DC_UnlockDc( hnewdc );
780   DC_UnlockDc( hDC );
781   return  hnewdc;
782 }
783
784 STATIC
785 VOID
786 FASTCALL
787 NtGdiSetDCState ( HDC hDC, HDC hDCSave )
788 {
789   PDC  dc, dcs;
790
791   dc = DC_LockDc ( hDC );
792   if ( dc )
793   {
794     dcs = DC_LockDc ( hDCSave );
795     if ( dcs )
796     {
797       if ( dcs->w.flags & DC_SAVED )
798       {
799         dc->w.flags            = dcs->w.flags & ~DC_SAVED;
800
801         dc->w.hFirstBitmap     = dcs->w.hFirstBitmap;
802
803 #if 0
804         dc->w.hDevice          = dcs->w.hDevice;
805 #endif
806
807         dc->w.totalExtent      = dcs->w.totalExtent;
808         dc->w.ROPmode          = dcs->w.ROPmode;
809         dc->w.polyFillMode     = dcs->w.polyFillMode;
810         dc->w.stretchBltMode   = dcs->w.stretchBltMode;
811         dc->w.relAbsMode       = dcs->w.relAbsMode;
812         dc->w.backgroundMode   = dcs->w.backgroundMode;
813         dc->w.backgroundColor  = dcs->w.backgroundColor;
814         dc->w.textColor        = dcs->w.textColor;
815         dc->w.brushOrgX        = dcs->w.brushOrgX;
816         dc->w.brushOrgY        = dcs->w.brushOrgY;
817         dc->w.textAlign        = dcs->w.textAlign;
818         dc->w.charExtra        = dcs->w.charExtra;
819         dc->w.breakTotalExtra  = dcs->w.breakTotalExtra;
820         dc->w.breakCount       = dcs->w.breakCount;
821         dc->w.breakExtra       = dcs->w.breakExtra;
822         dc->w.breakRem         = dcs->w.breakRem;
823         dc->w.MapMode          = dcs->w.MapMode;
824         dc->w.GraphicsMode     = dcs->w.GraphicsMode;
825 #if 0
826         /* Apparently, the DC origin is not changed by [GS]etDCState */
827         dc->w.DCOrgX           = dcs->w.DCOrgX;
828         dc->w.DCOrgY           = dcs->w.DCOrgY;
829 #endif
830         dc->w.CursPosX         = dcs->w.CursPosX;
831         dc->w.CursPosY         = dcs->w.CursPosY;
832         dc->w.ArcDirection     = dcs->w.ArcDirection;
833
834 #if 0
835         dc->w.xformWorld2Wnd   = dcs->w.xformWorld2Wnd;
836         dc->w.xformWorld2Vport = dcs->w.xformWorld2Vport;
837         dc->w.xformVport2World = dcs->w.xformVport2World;
838         dc->w.vport2WorldValid = dcs->w.vport2WorldValid;
839 #endif
840
841         dc->wndOrgX            = dcs->wndOrgX;
842         dc->wndOrgY            = dcs->wndOrgY;
843         dc->wndExtX            = dcs->wndExtX;
844         dc->wndExtY            = dcs->wndExtY;
845         dc->vportOrgX          = dcs->vportOrgX;
846         dc->vportOrgY          = dcs->vportOrgY;
847         dc->vportExtX          = dcs->vportExtX;
848         dc->vportExtY          = dcs->vportExtY;
849
850         if (!(dc->w.flags & DC_MEMORY))
851         {
852           dc->w.bitsPerPixel = dcs->w.bitsPerPixel;
853         }
854
855 #if 0
856         if (dcs->w.hClipRgn)
857         {
858           if (!dc->w.hClipRgn)
859           {
860             dc->w.hClipRgn = NtGdiCreateRectRgn( 0, 0, 0, 0 );
861           }
862           NtGdiCombineRgn( dc->w.hClipRgn, dcs->w.hClipRgn, 0, RGN_COPY );
863         }
864         else
865         {
866           if (dc->w.hClipRgn)
867           {
868             NtGdiDeleteObject( dc->w.hClipRgn );
869           }
870
871           dc->w.hClipRgn = 0;
872         }
873         CLIPPING_UpdateGCRegion( dc );
874 #endif
875
876         NtGdiSelectObject( hDC, dcs->w.hBitmap );
877         NtGdiSelectObject( hDC, dcs->w.hBrush );
878         NtGdiSelectObject( hDC, dcs->w.hFont );
879         NtGdiSelectObject( hDC, dcs->w.hPen );
880         NtGdiSetBkColor( hDC, dcs->w.backgroundColor);
881         NtGdiSetTextColor( hDC, dcs->w.textColor);
882
883 #if 0
884         GDISelectPalette16( hDC, dcs->w.hPalette, FALSE );
885 #endif
886       }
887
888       DC_UnlockDc ( hDCSave );
889     }
890     DC_UnlockDc ( hDC );
891   }
892 }
893
894 INT STDCALL
895 NtGdiGetDeviceCaps(HDC  hDC,
896                   INT  Index)
897 {
898   PDC  dc;
899   INT  ret;
900   POINT  pt;
901
902   dc = DC_LockDc(hDC);
903   if (dc == NULL)
904   {
905     return 0;
906   }
907
908   /* Retrieve capability */
909   switch (Index)
910   {
911     case DRIVERVERSION:
912       ret = dc->GDIInfo->ulVersion;
913       break;
914
915     case TECHNOLOGY:
916       ret = dc->GDIInfo->ulTechnology;
917       break;
918
919     case HORZSIZE:
920       ret = dc->GDIInfo->ulHorzSize;
921       break;
922
923     case VERTSIZE:
924       ret = dc->GDIInfo->ulVertSize;
925       break;
926
927     case HORZRES:
928       ret = dc->GDIInfo->ulHorzRes;
929       break;
930
931     case VERTRES:
932       ret = dc->GDIInfo->ulVertRes;
933       break;
934
935     case LOGPIXELSX:
936       ret = dc->GDIInfo->ulLogPixelsX;
937       break;
938
939     case LOGPIXELSY:
940       ret = dc->GDIInfo->ulLogPixelsY;
941       break;
942
943     case BITSPIXEL:
944       ret = dc->GDIInfo->cBitsPixel;
945       break;
946
947     case PLANES:
948       ret = dc->GDIInfo->cPlanes;
949       break;
950
951     case NUMBRUSHES:
952       UNIMPLEMENTED; /* FIXME */
953       break;
954
955     case NUMPENS:
956       UNIMPLEMENTED; /* FIXME */
957       break;
958
959     case NUMFONTS:
960       UNIMPLEMENTED; /* FIXME */
961       break;
962
963     case NUMCOLORS:
964       ret = dc->GDIInfo->ulNumColors;
965       break;
966
967     case ASPECTX:
968       ret = dc->GDIInfo->ulAspectX;
969       break;
970
971     case ASPECTY:
972       ret = dc->GDIInfo->ulAspectY;
973       break;
974
975     case ASPECTXY:
976       ret = dc->GDIInfo->ulAspectXY;
977       break;
978
979     case PDEVICESIZE:
980       UNIMPLEMENTED; /* FIXME */
981       break;
982
983     case CLIPCAPS:
984       UNIMPLEMENTED; /* FIXME */
985       break;
986
987     case SIZEPALETTE:
988       ret = dc->GDIInfo->ulNumPalReg; /* FIXME not sure */
989       break;
990
991     case NUMRESERVED:
992       UNIMPLEMENTED; /* FIXME */
993       break;
994
995     case COLORRES:
996       UNIMPLEMENTED; /* FIXME */
997       break;
998
999     case PHYSICALWIDTH:
1000       if(NtGdiEscape(hDC, GETPHYSPAGESIZE, 0, NULL, (LPVOID)&pt) > 0)
1001       {
1002         ret = pt.x;
1003       }
1004       else
1005       {
1006         ret = 0;
1007       }
1008       break;
1009
1010     case PHYSICALHEIGHT:
1011       if(NtGdiEscape(hDC, GETPHYSPAGESIZE, 0, NULL, (LPVOID)&pt) > 0)
1012       {
1013         ret = pt.y;
1014       }
1015       else
1016       {
1017         ret = 0;
1018       }
1019       break;
1020
1021     case PHYSICALOFFSETX:
1022       if(NtGdiEscape(hDC, GETPRINTINGOFFSET, 0, NULL, (LPVOID)&pt) > 0)
1023       {
1024         ret = pt.x;
1025       }
1026       else
1027       {
1028         ret = 0;
1029       }
1030       break;
1031
1032     case PHYSICALOFFSETY:
1033       if(NtGdiEscape(hDC, GETPRINTINGOFFSET, 0, NULL, (LPVOID)&pt) > 0)
1034       {
1035         ret = pt.y;
1036       }
1037       else
1038       {
1039         ret = 0;
1040       }
1041       break;
1042
1043     case VREFRESH:
1044       UNIMPLEMENTED; /* FIXME */
1045       break;
1046
1047     case SCALINGFACTORX:
1048       if(NtGdiEscape(hDC, GETSCALINGFACTOR, 0, NULL, (LPVOID)&pt) > 0)
1049       {
1050         ret = pt.x;
1051       }
1052       else
1053       {
1054         ret = 0;
1055       }
1056       break;
1057
1058     case SCALINGFACTORY:
1059       if(NtGdiEscape(hDC, GETSCALINGFACTOR, 0, NULL, (LPVOID)&pt) > 0)
1060       {
1061         ret = pt.y;
1062       }
1063       else
1064       {
1065         ret = 0;
1066       }
1067       break;
1068
1069     case RASTERCAPS:
1070       UNIMPLEMENTED; /* FIXME */
1071       break;
1072
1073     case CURVECAPS:
1074       UNIMPLEMENTED; /* FIXME */
1075       break;
1076
1077     case LINECAPS:
1078       UNIMPLEMENTED; /* FIXME */
1079       break;
1080
1081     case POLYGONALCAPS:
1082       UNIMPLEMENTED; /* FIXME */
1083       break;
1084
1085     case TEXTCAPS:
1086       ret = dc->GDIInfo->flTextCaps;
1087       break;
1088
1089     default:
1090       ret = 0;
1091       break;
1092   }
1093
1094   DPRINT("(%04x,%d): returning %d\n", hDC, Index, ret);
1095
1096   DC_UnlockDc( hDC );
1097   return ret;
1098 }
1099
1100 DC_GET_VAL( INT, NtGdiGetMapMode, w.MapMode )
1101 DC_GET_VAL( INT, NtGdiGetPolyFillMode, w.polyFillMode )
1102
1103 INT STDCALL
1104 NtGdiGetObjectA(HANDLE handle, INT count, LPVOID buffer)
1105 {
1106   PGDIOBJ  gdiObject;
1107   INT  result = 0;
1108   DWORD objectType;
1109
1110   if (!count)
1111     return  0;
1112   gdiObject = GDIOBJ_LockObj (handle, GDI_OBJECT_TYPE_DONTCARE);
1113   if (gdiObject == 0)
1114     return  0;
1115
1116   objectType = GDIOBJ_GetObjectType(handle);
1117   switch(objectType)
1118   {
1119 /*    case GDI_OBJECT_TYPE_PEN:
1120       result = PEN_GetObject((PENOBJ *)gdiObject, count, buffer);
1121       break;
1122     case GDI_OBJECT_TYPE_BRUSH:
1123       result = BRUSH_GetObject((BRUSHOBJ *)gdiObject, count, buffer);
1124       break; */
1125     case GDI_OBJECT_TYPE_BITMAP:
1126       result = BITMAP_GetObject((BITMAPOBJ *)gdiObject, count, buffer);
1127       break;
1128 /*    case GDI_OBJECT_TYPE_FONT:
1129       result = FONT_GetObjectA((FONTOBJ *)gdiObject, count, buffer);
1130
1131       // FIXME: Fix the LOGFONT structure for the stock fonts
1132
1133       if ( (handle >= FIRST_STOCK_HANDLE) && (handle <= LAST_STOCK_HANDLE) )
1134         FixStockFontSizeA(handle, count, buffer);
1135       break;
1136     case GDI_OBJECT_TYPE_PALETTE:
1137       result = PALETTE_GetObject((PALETTEOBJ *)gdiObject, count, buffer);
1138       break; */
1139
1140     case GDI_OBJECT_TYPE_REGION:
1141     case GDI_OBJECT_TYPE_DC:
1142     case GDI_OBJECT_TYPE_METADC:
1143     case GDI_OBJECT_TYPE_METAFILE:
1144     case GDI_OBJECT_TYPE_ENHMETADC:
1145     case GDI_OBJECT_TYPE_EMF:
1146       DPRINT1("GDI object type 0x%08x not implemented\n", objectType);
1147       break;
1148
1149     default:
1150       DPRINT1("Invalid GDI object type 0x%08x\n", objectType);
1151       break;
1152   }
1153   GDIOBJ_UnlockObj(handle, GDI_OBJECT_TYPE_DONTCARE);
1154
1155   return result;
1156 }
1157
1158 INT STDCALL
1159 NtGdiGetObjectW(HANDLE handle, INT count, LPVOID buffer)
1160 {
1161   PGDIOBJHDR  gdiObject;
1162   INT  result = 0;
1163   DWORD objectType;
1164
1165   if (!count)
1166     return 0;
1167   gdiObject = GDIOBJ_LockObj(handle, GDI_OBJECT_TYPE_DONTCARE);
1168   if (gdiObject == 0)
1169     return 0;
1170
1171   objectType = GDIOBJ_GetObjectType(handle);
1172   switch(objectType)
1173   {
1174 /*    case GDI_OBJECT_TYPE_PEN:
1175       result = PEN_GetObject((PENOBJ *)gdiObject, count, buffer);
1176       break;
1177     case GDI_OBJECT_TYPE_BRUSH:
1178       result = BRUSH_GetObject((BRUSHOBJ *)gdiObject, count, buffer);
1179        break; */
1180     case GDI_OBJECT_TYPE_BITMAP:
1181       result = BITMAP_GetObject((BITMAPOBJ *)gdiObject, count, buffer);
1182       break;
1183 /*    case GDI_OBJECT_TYPE_FONT:
1184       result = FONT_GetObjectW((FONTOBJ *)gdiObject, count, buffer);
1185
1186       // Fix the LOGFONT structure for the stock fonts
1187
1188       if ( (handle >= FIRST_STOCK_HANDLE) && (handle <= LAST_STOCK_HANDLE) )
1189       FixStockFontSizeW(handle, count, buffer);
1190     break;
1191     case GDI_OBJECT_TYPE_PALETTE:
1192       result = PALETTE_GetObject((PALETTEOBJ *)gdiObject, count, buffer);
1193       break; */
1194     default:
1195       DPRINT1("GDI object type 0x%08x not implemented\n", objectType);
1196       break;
1197   }
1198
1199   GDIOBJ_UnlockObj(handle, GDI_OBJECT_TYPE_DONTCARE);
1200
1201   return result;
1202 }
1203
1204 INT STDCALL
1205 NtGdiGetObject(HANDLE handle, INT count, LPVOID buffer)
1206 {
1207   return NtGdiGetObjectW(handle, count, buffer);
1208 }
1209
1210 DWORD STDCALL
1211 NtGdiGetObjectType(HANDLE handle)
1212 {
1213   GDIOBJHDR * ptr;
1214   INT result = 0;
1215   DWORD objectType;
1216
1217   ptr = GDIOBJ_LockObj(handle, GDI_OBJECT_TYPE_DONTCARE);
1218   if (ptr == 0)
1219     return 0;
1220
1221   objectType = GDIOBJ_GetObjectType(handle);
1222   switch(objectType)
1223   {
1224     case GDI_OBJECT_TYPE_PEN:
1225       result = OBJ_PEN;
1226       break;
1227     case GDI_OBJECT_TYPE_BRUSH:
1228       result = OBJ_BRUSH;
1229       break;
1230     case GDI_OBJECT_TYPE_BITMAP:
1231       result = OBJ_BITMAP;
1232       break;
1233     case GDI_OBJECT_TYPE_FONT:
1234       result = OBJ_FONT;
1235       break;
1236     case GDI_OBJECT_TYPE_PALETTE:
1237       result = OBJ_PAL;
1238       break;
1239     case GDI_OBJECT_TYPE_REGION:
1240       result = OBJ_REGION;
1241       break;
1242     case GDI_OBJECT_TYPE_DC:
1243       result = OBJ_DC;
1244       break;
1245     case GDI_OBJECT_TYPE_METADC:
1246       result = OBJ_METADC;
1247       break;
1248     case GDI_OBJECT_TYPE_METAFILE:
1249       result = OBJ_METAFILE;
1250       break;
1251     case GDI_OBJECT_TYPE_ENHMETAFILE:
1252       result = OBJ_ENHMETAFILE;
1253       break;
1254     case GDI_OBJECT_TYPE_ENHMETADC:
1255       result = OBJ_ENHMETADC;
1256       break;
1257     case GDI_OBJECT_TYPE_EXTPEN:
1258       result = OBJ_EXTPEN;
1259       break;
1260     case GDI_OBJECT_TYPE_MEMDC:
1261       result = OBJ_MEMDC;
1262       break;
1263     default:
1264       DPRINT1("Magic 0x%08x not implemented\n", objectType);
1265       break;
1266   }
1267   GDIOBJ_UnlockObj(handle, GDI_OBJECT_TYPE_DONTCARE);
1268   return result;
1269 }
1270
1271 DC_GET_VAL( INT, NtGdiGetRelAbs, w.relAbsMode )
1272 DC_GET_VAL( INT, NtGdiGetROP2, w.ROPmode )
1273 DC_GET_VAL( INT, NtGdiGetStretchBltMode, w.stretchBltMode )
1274 DC_GET_VAL( UINT, NtGdiGetTextAlign, w.textAlign )
1275 DC_GET_VAL( COLORREF, NtGdiGetTextColor, w.textColor )
1276 DC_GET_VAL_EX( NtGdiGetViewportExtEx, IntGetViewportExtEx, vportExtX, vportExtY, SIZE )
1277 DC_GET_VAL_EX( NtGdiGetViewportOrgEx, IntGetViewportOrgEx, vportOrgX, vportOrgY, POINT )
1278 DC_GET_VAL_EX( NtGdiGetWindowExtEx, IntGetWindowExtEx, wndExtX, wndExtY, SIZE )
1279 DC_GET_VAL_EX( NtGdiGetWindowOrgEx, IntGetWindowOrgEx, wndOrgX, wndOrgY, POINT )
1280
1281 HDC STDCALL
1282 NtGdiResetDC(HDC  hDC, CONST DEVMODEW *InitData)
1283 {
1284   UNIMPLEMENTED;
1285 }
1286
1287 BOOL STDCALL
1288 NtGdiRestoreDC(HDC  hDC, INT  SaveLevel)
1289 {
1290   PDC  dc, dcs;
1291   BOOL  success;
1292
1293   dc = DC_LockDc(hDC);
1294   if(!dc)
1295   {
1296     return FALSE;
1297   }
1298
1299   if (SaveLevel == -1)
1300   {
1301     SaveLevel = dc->saveLevel;
1302   }
1303
1304   if ((SaveLevel < 1) || (SaveLevel > dc->saveLevel))
1305   {
1306     return FALSE;
1307   }
1308
1309   success = TRUE;
1310   while (dc->saveLevel >= SaveLevel)
1311   {
1312     HDC hdcs = DC_GetNextDC (dc);
1313
1314     dcs = DC_LockDc (hdcs);
1315     if (dcs == NULL)
1316     {
1317       return FALSE;
1318     }
1319     DC_SetNextDC (dcs, DC_GetNextDC (dcs));
1320     if (--dc->saveLevel < SaveLevel)
1321       {
1322         DC_UnlockDc( hDC );
1323         DC_UnlockDc( hdcs );
1324         NtGdiSetDCState(hDC, hdcs);
1325 #if 0
1326         if (!PATH_AssignGdiPath( &dc->w.path, &dcs->w.path ))
1327         {
1328           /* FIXME: This might not be quite right, since we're
1329            * returning FALSE but still destroying the saved DC state */
1330           success = FALSE;
1331         }
1332 #endif
1333         dc = DC_LockDc(hDC);
1334         if(!dc)
1335         {
1336           return FALSE;
1337         }
1338       }
1339     else
1340       {
1341       DC_UnlockDc( hdcs );
1342       }
1343     NtGdiDeleteDC (hdcs);
1344   }
1345   DC_UnlockDc( hDC );
1346   return  success;
1347 }
1348
1349 INT STDCALL
1350 NtGdiSaveDC(HDC  hDC)
1351 {
1352   HDC  hdcs;
1353   PDC  dc, dcs;
1354   INT  ret;
1355
1356   if (!(hdcs = NtGdiGetDCState(hDC)))
1357   {
1358     return 0;
1359   }
1360
1361   dcs = DC_LockDc (hdcs);
1362   if (dcs == NULL)
1363   {
1364     return 0;
1365   }
1366   dc = DC_LockDc (hDC);
1367   if (dc == NULL)
1368   {
1369     DC_UnlockDc(dc);
1370     return 0;
1371   }
1372
1373 #if 0
1374     /* Copy path. The reason why path saving / restoring is in SaveDC/
1375      * RestoreDC and not in GetDCState/SetDCState is that the ...DCState
1376      * functions are only in Win16 (which doesn't have paths) and that
1377      * SetDCState doesn't allow us to signal an error (which can happen
1378      * when copying paths).
1379      */
1380   if (!PATH_AssignGdiPath (&dcs->w.path, &dc->w.path))
1381   {
1382     NtGdiDeleteDC (hdcs);
1383     return 0;
1384   }
1385 #endif
1386
1387   DC_SetNextDC (dcs, DC_GetNextDC (dc));
1388   DC_SetNextDC (dc, hdcs);
1389   ret = ++dc->saveLevel;
1390   DC_UnlockDc( hdcs );
1391   DC_UnlockDc( hDC );
1392
1393   return  ret;
1394 }
1395
1396 HGDIOBJ
1397 STDCALL
1398 NtGdiSelectObject(HDC  hDC, HGDIOBJ  hGDIObj)
1399 {
1400   HGDIOBJ objOrg = NULL; // default to failure
1401   BITMAPOBJ *pb;
1402   PDC dc;
1403   PPENOBJ pen;
1404   PBRUSHOBJ brush;
1405   PXLATEOBJ XlateObj;
1406   PPALGDI PalGDI;
1407   DWORD objectType;
1408   COLORREF *ColorMap;
1409   ULONG NumColors, Index;
1410   HRGN hVisRgn;
1411   USHORT Mode;
1412
1413   if(!hDC || !hGDIObj) return NULL;
1414
1415   dc = DC_LockDc(hDC);
1416   ASSERT ( dc );
1417
1418   objectType = GDIOBJ_GetObjectType(hGDIObj);
1419 //  GdiObjHdr = hGDIObj;
1420
1421   // FIXME: Get object handle from GDIObj and use it instead of GDIObj below?
1422
1423   switch (objectType)
1424   {
1425     case GDI_OBJECT_TYPE_PEN:
1426       objOrg = (HGDIOBJ)dc->w.hPen;
1427       dc->w.hPen = hGDIObj;
1428
1429       /* Convert the color of the pen to the format of the DC */
1430       PalGDI = PALETTE_LockPalette(dc->w.hPalette);
1431       if (NULL != PalGDI)
1432       {
1433         Mode = PalGDI->Mode;
1434         PALETTE_UnlockPalette(dc->w.hPalette);
1435         XlateObj = (PXLATEOBJ)IntEngCreateXlate(Mode, PAL_RGB, dc->w.hPalette, NULL);
1436         ASSERT ( XlateObj );
1437         pen = PENOBJ_LockPen(dc->w.hPen);
1438         if( pen )
1439         {
1440           pen->logpen.lopnColor = XLATEOBJ_iXlate(XlateObj, pen->logpen.lopnColor);
1441           PENOBJ_UnlockPen(dc->w.hPen);
1442         }
1443         EngDeleteXlate(XlateObj);
1444       }
1445       break;
1446
1447     case GDI_OBJECT_TYPE_BRUSH:
1448       objOrg = (HGDIOBJ)dc->w.hBrush;
1449       dc->w.hBrush = (HBRUSH) hGDIObj;
1450
1451       /* Convert the color of the brush to the format of the DC */
1452       PalGDI = PALETTE_LockPalette(dc->w.hPalette);
1453       if (NULL != PalGDI)
1454       {
1455         Mode = PalGDI->Mode;
1456         PALETTE_UnlockPalette(dc->w.hPalette);
1457         XlateObj = (PXLATEOBJ)IntEngCreateXlate(Mode, PAL_RGB, dc->w.hPalette, NULL);
1458         ASSERT(XlateObj);
1459         brush = BRUSHOBJ_LockBrush(dc->w.hBrush);
1460         if( brush )
1461         {
1462           brush->iSolidColor = XLATEOBJ_iXlate(XlateObj, brush->logbrush.lbColor);
1463         }
1464         BRUSHOBJ_UnlockBrush(dc->w.hBrush);
1465         EngDeleteXlate(XlateObj);
1466       }
1467       break;
1468
1469     case GDI_OBJECT_TYPE_FONT:
1470       objOrg = (HGDIOBJ)dc->w.hFont;
1471       dc->w.hFont = (HFONT) hGDIObj;
1472       TextIntRealizeFont(dc->w.hFont);
1473       break;
1474
1475     case GDI_OBJECT_TYPE_BITMAP:
1476       // must be memory dc to select bitmap
1477       if (!(dc->w.flags & DC_MEMORY)) return NULL;
1478       objOrg = (HGDIOBJ)dc->w.hBitmap;
1479
1480       /* Release the old bitmap, lock the new one and convert it to a SURF */
1481       EngDeleteSurface(dc->Surface);
1482       dc->w.hBitmap = hGDIObj;
1483       pb = BITMAPOBJ_LockBitmap(hGDIObj);
1484       ASSERT(pb);
1485       dc->Surface = BitmapToSurf(pb);
1486
1487       // if we're working with a DIB, get the palette [fixme: only create if the selected palette is null]
1488       if(pb->dib)
1489       {
1490         dc->w.bitsPerPixel = pb->dib->dsBmih.biBitCount;
1491
1492         if(pb->dib->dsBmih.biBitCount <= 8)
1493         {
1494           if(pb->dib->dsBmih.biBitCount == 1) { NumColors = 2; } else
1495           if(pb->dib->dsBmih.biBitCount == 4) { NumColors = 16; } else
1496           if(pb->dib->dsBmih.biBitCount == 8) { NumColors = 256; }
1497
1498           ColorMap = ExAllocatePool(PagedPool, sizeof(COLORREF) * NumColors);
1499           ASSERT(ColorMap);
1500           for (Index = 0; Index < NumColors; Index++)
1501           {
1502             ColorMap[Index] = RGB(pb->ColorMap[Index].rgbRed,
1503                                   pb->ColorMap[Index].rgbGreen,
1504                                   pb->ColorMap[Index].rgbBlue);
1505           }
1506           dc->w.hPalette = PALETTE_AllocPalette(PAL_INDEXED, NumColors, (ULONG *) ColorMap, 0, 0, 0);
1507           ExFreePool(ColorMap);
1508         }
1509         else if ( 16 == pb->dib->dsBmih.biBitCount )
1510         {
1511           dc->w.hPalette = PALETTE_AllocPalette(PAL_BITFIELDS, pb->dib->dsBmih.biClrUsed, NULL, 0x7c00, 0x03e0, 0x001f);
1512         }
1513         else if(pb->dib->dsBmih.biBitCount >= 24)
1514         {
1515           dc->w.hPalette = PALETTE_AllocPalette(PAL_RGB, pb->dib->dsBmih.biClrUsed, NULL, 0, 0, 0);
1516         }
1517       }
1518       else
1519       {
1520         dc->w.bitsPerPixel = pb->bitmap.bmBitsPixel;
1521       }
1522
1523       DC_UnlockDc ( hDC );
1524       hVisRgn = NtGdiCreateRectRgn ( 0, 0, pb->size.cx, pb->size.cy );
1525       NtGdiSelectVisRgn ( hDC, hVisRgn );
1526       NtGdiDeleteObject ( hVisRgn );
1527       BITMAPOBJ_UnlockBitmap(hGDIObj);
1528
1529       return objOrg;
1530
1531 #if UPDATEREGIONS
1532     case GDI_OBJECT_TYPE_REGION:
1533       DC_UnlockDc ( hDC );
1534       SelectClipRgn(hDC, (HRGN)hGDIObj);
1535       return NULL;
1536 #endif
1537     default:
1538       break;
1539   }
1540   DC_UnlockDc( hDC );
1541   return objOrg;
1542 }
1543
1544 DC_SET_MODE( NtGdiSetBkMode, w.backgroundMode, TRANSPARENT, OPAQUE )
1545 DC_SET_MODE( NtGdiSetPolyFillMode, w.polyFillMode, ALTERNATE, WINDING )
1546 // DC_SET_MODE( NtGdiSetRelAbs, w.relAbsMode, ABSOLUTE, RELATIVE )
1547 DC_SET_MODE( NtGdiSetROP2, w.ROPmode, R2_BLACK, R2_WHITE )
1548 DC_SET_MODE( NtGdiSetStretchBltMode, w.stretchBltMode, BLACKONWHITE, HALFTONE )
1549
1550 //  ----------------------------------------------------  Private Interface
1551
1552 HDC FASTCALL
1553 DC_AllocDC(LPCWSTR Driver)
1554 {
1555   PDC  NewDC;
1556   HDC  hDC;
1557
1558   hDC = (HDC) GDIOBJ_AllocObj(sizeof(DC), GDI_OBJECT_TYPE_DC, (GDICLEANUPPROC) DC_InternalDeleteDC);
1559   if (hDC == NULL)
1560   {
1561     return  NULL;
1562   }
1563
1564   NewDC = DC_LockDc(hDC);
1565
1566   if (Driver != NULL)
1567   {
1568     NewDC->DriverName = ExAllocatePool(PagedPool, (wcslen(Driver) + 1) * sizeof(WCHAR));
1569     wcscpy(NewDC->DriverName, Driver);
1570   }
1571
1572   NewDC->w.xformWorld2Wnd.eM11 = 1.0f;
1573   NewDC->w.xformWorld2Wnd.eM12 = 0.0f;
1574   NewDC->w.xformWorld2Wnd.eM21 = 0.0f;
1575   NewDC->w.xformWorld2Wnd.eM22 = 1.0f;
1576   NewDC->w.xformWorld2Wnd.eDx = 0.0f;
1577   NewDC->w.xformWorld2Wnd.eDy = 0.0f;
1578   NewDC->w.xformWorld2Vport = NewDC->w.xformWorld2Wnd;
1579   NewDC->w.xformVport2World = NewDC->w.xformWorld2Wnd;
1580   NewDC->w.vport2WorldValid = TRUE;
1581
1582   NewDC->w.hFont = NtGdiGetStockObject(SYSTEM_FONT);
1583   TextIntRealizeFont(NewDC->w.hFont);
1584
1585   DC_UnlockDc(hDC);
1586
1587   return  hDC;
1588 }
1589
1590 HDC FASTCALL
1591 DC_FindOpenDC(LPCWSTR  Driver)
1592 {
1593   return NULL;
1594 }
1595
1596 /*!
1597  * Initialize some common fields in the Device Context structure.
1598 */
1599 VOID FASTCALL
1600 DC_InitDC(HDC  DCHandle)
1601 {
1602 //  NtGdiRealizeDefaultPalette(DCHandle);
1603
1604   NtGdiSelectObject(DCHandle, NtGdiGetStockObject( WHITE_BRUSH ));
1605   NtGdiSelectObject(DCHandle, NtGdiGetStockObject( BLACK_PEN ));
1606   //NtGdiSelectObject(DCHandle, hFont);
1607
1608 //  CLIPPING_UpdateGCRegion(DCToInit);
1609
1610 }
1611
1612 VOID FASTCALL
1613 DC_FreeDC(HDC  DCToFree)
1614 {
1615   if (!GDIOBJ_FreeObj(DCToFree, GDI_OBJECT_TYPE_DC, GDIOBJFLAG_DEFAULT))
1616   {
1617     DPRINT("DC_FreeDC failed\n");
1618   }
1619 }
1620
1621 BOOL FASTCALL
1622 DC_InternalDeleteDC( PDC DCToDelete )
1623 {
1624   if( DCToDelete->DriverName )
1625     {
1626       ExFreePool(DCToDelete->DriverName);
1627     }
1628
1629   return TRUE;
1630 }
1631
1632 HDC FASTCALL
1633 DC_GetNextDC (PDC pDC)
1634 {
1635   return pDC->hNext;
1636 }
1637
1638 VOID FASTCALL
1639 DC_SetNextDC (PDC pDC, HDC hNextDC)
1640 {
1641   pDC->hNext = hNextDC;
1642 }
1643
1644 VOID FASTCALL
1645 DC_UpdateXforms(PDC  dc)
1646 {
1647   XFORM  xformWnd2Vport;
1648   FLOAT  scaleX, scaleY;
1649
1650   /* Construct a transformation to do the window-to-viewport conversion */
1651   scaleX = (FLOAT)dc->vportExtX / (FLOAT)dc->wndExtX;
1652   scaleY = (FLOAT)dc->vportExtY / (FLOAT)dc->wndExtY;
1653   xformWnd2Vport.eM11 = scaleX;
1654   xformWnd2Vport.eM12 = 0.0;
1655   xformWnd2Vport.eM21 = 0.0;
1656   xformWnd2Vport.eM22 = scaleY;
1657   xformWnd2Vport.eDx  = (FLOAT)dc->vportOrgX - scaleX * (FLOAT)dc->wndOrgX;
1658   xformWnd2Vport.eDy  = (FLOAT)dc->vportOrgY - scaleY * (FLOAT)dc->wndOrgY;
1659
1660   /* Combine with the world transformation */
1661   NtGdiCombineTransform(&dc->w.xformWorld2Vport, &dc->w.xformWorld2Wnd, &xformWnd2Vport);
1662
1663   /* Create inverse of world-to-viewport transformation */
1664   dc->w.vport2WorldValid = DC_InvertXform(&dc->w.xformWorld2Vport, &dc->w.xformVport2World);
1665 }
1666
1667 BOOL FASTCALL
1668 DC_InvertXform(const XFORM *xformSrc,
1669                XFORM *xformDest)
1670 {
1671   FLOAT  determinant;
1672
1673   determinant = xformSrc->eM11*xformSrc->eM22 - xformSrc->eM12*xformSrc->eM21;
1674   if (determinant > -1e-12 && determinant < 1e-12)
1675   {
1676     return  FALSE;
1677   }
1678
1679   xformDest->eM11 =  xformSrc->eM22 / determinant;
1680   xformDest->eM12 = -xformSrc->eM12 / determinant;
1681   xformDest->eM21 = -xformSrc->eM21 / determinant;
1682   xformDest->eM22 =  xformSrc->eM11 / determinant;
1683   xformDest->eDx  = -xformSrc->eDx * xformDest->eM11 - xformSrc->eDy * xformDest->eM21;
1684   xformDest->eDy  = -xformSrc->eDx * xformDest->eM12 - xformSrc->eDy * xformDest->eM22;
1685
1686   return  TRUE;
1687 }
1688 /* EOF */