Jeffrey Morlan (mrnobo1024 at yahoo.com) - Fix ModifyWorldTransform multiplies. See...
[reactos.git] / reactos / subsystems / win32 / win32k / objects / coord.c
index 1b91251..55df78a 100644 (file)
@@ -16,7 +16,7 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-/* $Id$
+/*
  *
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS kernel
 void FASTCALL
 IntFixIsotropicMapping(PDC dc)
 {
-  ULONG xdim = EngMulDiv(dc->vportExtX, dc->GDIInfo->ulHorzSize, dc->GDIInfo->ulHorzRes) / dc->wndExtX;
-  ULONG ydim = EngMulDiv(dc->vportExtY, dc->GDIInfo->ulVertSize, dc->GDIInfo->ulVertRes) / dc->wndExtY;
+  ULONG xdim;
+  ULONG ydim;
+  PDC_ATTR Dc_Attr = dc->pDc_Attr;
+  if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
+
+  xdim = EngMulDiv(Dc_Attr->szlViewportExt.cx,
+               ((PGDIDEVICE)dc->pPDev)->GDIInfo.ulHorzSize,
+               ((PGDIDEVICE)dc->pPDev)->GDIInfo.ulHorzRes) /
+                                Dc_Attr->szlWindowExt.cx;
+  ydim = EngMulDiv(Dc_Attr->szlViewportExt.cy,
+               ((PGDIDEVICE)dc->pPDev)->GDIInfo.ulVertSize,
+               ((PGDIDEVICE)dc->pPDev)->GDIInfo.ulVertRes) /
+                                Dc_Attr->szlWindowExt.cy;
 
   if (xdim > ydim)
   {
-    dc->vportExtX = dc->vportExtX * abs(ydim / xdim);
-    if (!dc->vportExtX) dc->vportExtX = 1;
+    Dc_Attr->szlViewportExt.cx = Dc_Attr->szlViewportExt.cx * abs(ydim / xdim);
+    if (!Dc_Attr->szlViewportExt.cx) Dc_Attr->szlViewportExt.cx = 1;
   }
   else
   {
-    dc->vportExtY = dc->vportExtY * abs(xdim / ydim);
-    if (!dc->vportExtY) dc->vportExtY = 1;
+    Dc_Attr->szlViewportExt.cy = Dc_Attr->szlViewportExt.cy * abs(xdim / ydim);
+    if (!Dc_Attr->szlViewportExt.cy) Dc_Attr->szlViewportExt.cy = 1;
   }
 }
 
@@ -57,6 +68,7 @@ IntGdiCombineTransform(LPXFORM XFormResult,
                        LPXFORM xform1,
                        LPXFORM xform2)
 {
+  XFORM xformTemp;
   /* Check for illegal parameters */
   if (!XFormResult || !xform1 || !xform2)
   {
@@ -65,23 +77,21 @@ IntGdiCombineTransform(LPXFORM XFormResult,
 
   /* Create the result in a temporary XFORM, since xformResult may be
    * equal to xform1 or xform2 */
-  XFormResult->eM11 = xform1->eM11 * xform2->eM11 + xform1->eM12 * xform2->eM21;
-  XFormResult->eM12 = xform1->eM11 * xform2->eM12 + xform1->eM12 * xform2->eM22;
-  XFormResult->eM21 = xform1->eM21 * xform2->eM11 + xform1->eM22 * xform2->eM21;
-  XFormResult->eM22 = xform1->eM21 * xform2->eM12 + xform1->eM22 * xform2->eM22;
-  XFormResult->eDx  = xform1->eDx  * xform2->eM11 + xform1->eDy  * xform2->eM21 + xform2->eDx;
-  XFormResult->eDy  = xform1->eDx  * xform2->eM12 + xform1->eDy  * xform2->eM22 + xform2->eDy;
+  xformTemp.eM11 = xform1->eM11 * xform2->eM11 + xform1->eM12 * xform2->eM21;
+  xformTemp.eM12 = xform1->eM11 * xform2->eM12 + xform1->eM12 * xform2->eM22;
+  xformTemp.eM21 = xform1->eM21 * xform2->eM11 + xform1->eM22 * xform2->eM21;
+  xformTemp.eM22 = xform1->eM21 * xform2->eM12 + xform1->eM22 * xform2->eM22;
+  xformTemp.eDx  = xform1->eDx  * xform2->eM11 + xform1->eDy  * xform2->eM21 + xform2->eDx;
+  xformTemp.eDy  = xform1->eDx  * xform2->eM12 + xform1->eDy  * xform2->eM22 + xform2->eDy;
+  *XFormResult = xformTemp;
 
   return TRUE;
 }
 
 BOOL STDCALL NtGdiCombineTransform(LPXFORM  UnsafeXFormResult,
-                           CONST LPXFORM  Unsafexform1,
-                           CONST LPXFORM  Unsafexform2)
+                                   LPXFORM  Unsafexform1,
+                                   LPXFORM  Unsafexform2)
 {
-  XFORM  xformTemp;
-  XFORM  xform1 = {0}, xform2 = {0};
-  NTSTATUS Status = STATUS_SUCCESS;
   BOOL Ret;
 
   _SEH_TRY
@@ -95,41 +105,14 @@ BOOL STDCALL NtGdiCombineTransform(LPXFORM  UnsafeXFormResult,
     ProbeForRead(Unsafexform2,
                  sizeof(XFORM),
                  1);
-    xform1 = *Unsafexform1;
-    xform2 = *Unsafexform2;
-  }
-  _SEH_HANDLE
-  {
-    Status = _SEH_GetExceptionCode();
-  }
-  _SEH_END;
-
-  if(!NT_SUCCESS(Status))
-  {
-    SetLastNtError(Status);
-    return FALSE;
-  }
-
-  Ret = IntGdiCombineTransform(&xformTemp, &xform1, &xform2);
-
-  /* Copy the result to xformResult */
-  _SEH_TRY
-  {
-    /* pointer was already probed! */
-    *UnsafeXFormResult = xformTemp;
+    Ret = IntGdiCombineTransform(UnsafeXFormResult, Unsafexform1, Unsafexform2);
   }
   _SEH_HANDLE
   {
-    Status = _SEH_GetExceptionCode();
+    Ret = FALSE;
   }
   _SEH_END;
 
-  if(!NT_SUCCESS(Status))
-  {
-    SetLastNtError(Status);
-    return FALSE;
-  }
-
   return Ret;
 }
 
@@ -139,10 +122,10 @@ CoordDPtoLP(PDC Dc, LPPOINT Point)
 FLOAT x, y;
   x = (FLOAT)Point->x;
   y = (FLOAT)Point->y;
-  Point->x = x * Dc->w.xformVport2World.eM11 +
-    y * Dc->w.xformVport2World.eM21 + Dc->w.xformVport2World.eDx;
-  Point->y = x * Dc->w.xformVport2World.eM12 +
-    y * Dc->w.xformVport2World.eM22 + Dc->w.xformVport2World.eDy;
+  Point->x = x * Dc->DcLevel.xformVport2World.eM11 +
+    y * Dc->DcLevel.xformVport2World.eM21 + Dc->DcLevel.xformVport2World.eDx;
+  Point->y = x * Dc->DcLevel.xformVport2World.eM12 +
+    y * Dc->DcLevel.xformVport2World.eM22 + Dc->DcLevel.xformVport2World.eDy;
 }
 
 VOID
@@ -157,105 +140,15 @@ IntDPtoLP ( PDC dc, LPPOINT Points, INT Count )
     CoordDPtoLP ( dc, &Points[i] );
 }
 
-/*!
- * Converts points from device coordinates into logical coordinates. Conversion depends on the mapping mode,
- * world transfrom, viewport origin settings for the given device context.
- * \param      hDC             device context.
- * \param      Points  an array of POINT structures (in/out).
- * \param      Count   number of elements in the array of POINT structures.
- * \return  TRUE       if success.
-*/
-BOOL STDCALL
-NtGdiDPtoLP(HDC  hDC,
-          LPPOINT  UnsafePoints,
-          int  Count)
-{
-   PDC dc;
-   NTSTATUS Status = STATUS_SUCCESS;
-   LPPOINT Points;
-   ULONG Size;
-
-   dc = DC_LockDc(hDC);
-   if (!dc)
-   {
-     SetLastWin32Error(ERROR_INVALID_HANDLE);
-     return FALSE;
-   }
-
-   if (!UnsafePoints || Count <= 0)
-   {
-     DC_UnlockDc(dc);
-     SetLastWin32Error(ERROR_INVALID_PARAMETER);
-     return FALSE;
-   }
-
-   Size = Count * sizeof(POINT);
-
-   Points = (LPPOINT)ExAllocatePoolWithTag(PagedPool, Size, TAG_COORD);
-   if(!Points)
-   {
-     DC_UnlockDc(dc);
-     SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
-     return FALSE;
-   }
-
-   _SEH_TRY
-   {
-      ProbeForWrite(UnsafePoints,
-                    Size,
-                    1);
-      RtlCopyMemory(Points,
-                    UnsafePoints,
-                    Size);
-   }
-   _SEH_HANDLE
-   {
-      Status = _SEH_GetExceptionCode();
-   }
-   _SEH_END;
-   
-   if(!NT_SUCCESS(Status))
-   {
-     DC_UnlockDc(dc);
-     ExFreePool(Points);
-     SetLastNtError(Status);
-     return FALSE;
-   }
-
-   IntDPtoLP(dc, Points, Count);
-
-   _SEH_TRY
-   {
-      /* pointer was already probed! */
-      RtlCopyMemory(UnsafePoints,
-                    Points,
-                    Size);
-   }
-   _SEH_HANDLE
-   {
-      Status = _SEH_GetExceptionCode();
-   }
-   _SEH_END;
-
-   if(!NT_SUCCESS(Status))
-   {
-     DC_UnlockDc(dc);
-     ExFreePool(Points);
-     SetLastNtError(Status);
-     return FALSE;
-   }
-
-   DC_UnlockDc(dc);
-   ExFreePool(Points);
-   return TRUE;
-}
-
 int
 FASTCALL
 IntGetGraphicsMode ( PDC dc )
 {
+  PDC_ATTR Dc_Attr;
   ASSERT ( dc );
-  return dc->w.GraphicsMode;
+  Dc_Attr = dc->pDc_Attr;
+  if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
+  return Dc_Attr->iGraphicsMode;
 }
 
 BOOL
@@ -264,61 +157,43 @@ IntGdiModifyWorldTransform(PDC pDc,
                            CONST LPXFORM lpXForm,
                            DWORD Mode)
 {
-   ASSERT(pDc && lpXForm);
+   ASSERT(pDc);
 
    switch(Mode)
    {
      case MWT_IDENTITY:
-       pDc->w.xformWorld2Wnd.eM11 = 1.0f;
-       pDc->w.xformWorld2Wnd.eM12 = 0.0f;
-       pDc->w.xformWorld2Wnd.eM21 = 0.0f;
-       pDc->w.xformWorld2Wnd.eM22 = 1.0f;
-       pDc->w.xformWorld2Wnd.eDx  = 0.0f;
-       pDc->w.xformWorld2Wnd.eDy  = 0.0f;
+       pDc->DcLevel.xformWorld2Wnd.eM11 = 1.0f;
+       pDc->DcLevel.xformWorld2Wnd.eM12 = 0.0f;
+       pDc->DcLevel.xformWorld2Wnd.eM21 = 0.0f;
+       pDc->DcLevel.xformWorld2Wnd.eM22 = 1.0f;
+       pDc->DcLevel.xformWorld2Wnd.eDx  = 0.0f;
+       pDc->DcLevel.xformWorld2Wnd.eDy  = 0.0f;
        break;
 
      case MWT_LEFTMULTIPLY:
-       IntGdiCombineTransform(&pDc->w.xformWorld2Wnd, lpXForm, &pDc->w.xformWorld2Wnd );
+       IntGdiCombineTransform(&pDc->DcLevel.xformWorld2Wnd, lpXForm, &pDc->DcLevel.xformWorld2Wnd );
        break;
 
      case MWT_RIGHTMULTIPLY:
-       IntGdiCombineTransform(&pDc->w.xformWorld2Wnd, &pDc->w.xformWorld2Wnd, lpXForm);
+       IntGdiCombineTransform(&pDc->DcLevel.xformWorld2Wnd, &pDc->DcLevel.xformWorld2Wnd, lpXForm);
+       break;
+
+     case MWT_MAX+1: // Must be MWT_SET????
+       pDc->DcLevel.xformWorld2Wnd = *lpXForm; // Do it like Wine.
        break;
 
      default:
-       SetLastWin32Error(ERROR_INVALID_PARAMETER);
        return FALSE;
   }
-
   DC_UpdateXforms(pDc);
-  DC_UnlockDc(pDc);
   return TRUE;
 }
 
-int
-STDCALL
-NtGdiGetGraphicsMode ( HDC hDC )
-{
-  PDC dc;
-  int GraphicsMode; // default to failure
-
-  dc = DC_LockDc ( hDC );
-  if (!dc)
-  {
-    SetLastWin32Error(ERROR_INVALID_HANDLE);
-    return 0;
-  }
-
-  GraphicsMode = dc->w.GraphicsMode;
-
-  DC_UnlockDc(dc);
-  return GraphicsMode;
-}
-
 BOOL
 STDCALL
-NtGdiGetWorldTransform(HDC  hDC,
-                      LPXFORM  XForm)
+NtGdiGetTransform(HDC  hDC,
+               DWORD iXform,
+              LPXFORM  XForm)
 {
   PDC  dc;
   NTSTATUS Status = STATUS_SUCCESS;
@@ -341,7 +216,14 @@ NtGdiGetWorldTransform(HDC  hDC,
     ProbeForWrite(XForm,
                   sizeof(XFORM),
                   1);
-    *XForm = dc->w.xformWorld2Wnd;
+   switch(iXform)
+   {
+     case GdiWorldSpaceToPageSpace:
+        *XForm = dc->DcLevel.xformWorld2Wnd;
+     break;
+     default:
+     break;
+   }
   }
   _SEH_HANDLE
   {
@@ -364,10 +246,10 @@ CoordLPtoDP ( PDC Dc, LPPOINT Point )
 
   x = (FLOAT)Point->x;
   y = (FLOAT)Point->y;
-  Point->x = x * Dc->w.xformWorld2Vport.eM11 +
-    y * Dc->w.xformWorld2Vport.eM21 + Dc->w.xformWorld2Vport.eDx;
-  Point->y = x * Dc->w.xformWorld2Vport.eM12 +
-    y * Dc->w.xformWorld2Vport.eM22 + Dc->w.xformWorld2Vport.eDy;
+  Point->x = x * Dc->DcLevel.xformWorld2Vport.eM11 +
+    y * Dc->DcLevel.xformWorld2Vport.eM21 + Dc->DcLevel.xformWorld2Vport.eDx;
+  Point->y = x * Dc->DcLevel.xformWorld2Vport.eM12 +
+    y * Dc->DcLevel.xformWorld2Vport.eM22 + Dc->DcLevel.xformWorld2Vport.eDy;
 }
 
 VOID
@@ -390,8 +272,13 @@ IntLPtoDP ( PDC dc, LPPOINT Points, INT Count )
  * \param      Count   number of elements in the array of POINT structures.
  * \return  TRUE       if success.
 */
-BOOL STDCALL
-NtGdiLPtoDP ( HDC hDC, LPPOINT UnsafePoints, INT Count )
+BOOL
+APIENTRY
+NtGdiTransformPoints( HDC hDC,
+                      PPOINT UnsafePtsIn,
+                      PPOINT UnsafePtOut,
+                      INT Count,
+                      INT iMode )
 {
    PDC dc;
    NTSTATUS Status = STATUS_SUCCESS;
@@ -405,7 +292,7 @@ NtGdiLPtoDP ( HDC hDC, LPPOINT UnsafePoints, INT Count )
      return FALSE;
    }
 
-   if (!UnsafePoints || Count <= 0)
+   if (!UnsafePtsIn || !UnsafePtOut || Count <= 0)
    {
      DC_UnlockDc(dc);
      SetLastWin32Error(ERROR_INVALID_PARAMETER);
@@ -424,11 +311,14 @@ NtGdiLPtoDP ( HDC hDC, LPPOINT UnsafePoints, INT Count )
 
    _SEH_TRY
    {
-      ProbeForWrite(UnsafePoints,
+      ProbeForWrite(UnsafePtOut,
+                    Size,
+                    1);
+      ProbeForRead(UnsafePtsIn,
                     Size,
                     1);
       RtlCopyMemory(Points,
-                    UnsafePoints,
+                    UnsafePtsIn,
                     Size);
    }
    _SEH_HANDLE
@@ -445,12 +335,28 @@ NtGdiLPtoDP ( HDC hDC, LPPOINT UnsafePoints, INT Count )
      return FALSE;
    }
 
-   IntLPtoDP(dc, Points, Count);
+   switch (iMode)
+   {
+      case GdiDpToLp:
+        IntDPtoLP(dc, Points, Count);
+        break;
+      case GdiLpToDp:
+        IntLPtoDP(dc, Points, Count);
+        break;
+      case 2: // Not supported yet. Need testing.
+      default:
+      {
+        DC_UnlockDc(dc);
+        ExFreePool(Points);
+        SetLastWin32Error(ERROR_INVALID_PARAMETER);
+        return FALSE;
+      }
+   }
 
    _SEH_TRY
    {
       /* pointer was already probed! */
-      RtlCopyMemory(UnsafePoints,
+      RtlCopyMemory(UnsafePtOut,
                     Points,
                     Size);
    }
@@ -467,7 +373,9 @@ NtGdiLPtoDP ( HDC hDC, LPPOINT UnsafePoints, INT Count )
      SetLastNtError(Status);
      return FALSE;
    }
-
+//
+// If we are getting called that means User XForms is a mess!
+//
    DC_UnlockDc(dc);
    ExFreePool(Points);
    return TRUE;
@@ -476,19 +384,13 @@ NtGdiLPtoDP ( HDC hDC, LPPOINT UnsafePoints, INT Count )
 BOOL
 STDCALL
 NtGdiModifyWorldTransform(HDC hDC,
-                          CONST LPXFORM  UnsafeXForm,
+                          LPXFORM  UnsafeXForm,
                           DWORD Mode)
 {
    PDC dc;
    XFORM SafeXForm;
-   BOOL Ret = FALSE;
+   BOOL Ret = TRUE;
 
-   if (!UnsafeXForm)
-   {
-     SetLastWin32Error(ERROR_INVALID_PARAMETER);
-     return FALSE;
-   }
-   
    dc = DC_LockDc(hDC);
    if (!dc)
    {
@@ -496,19 +398,24 @@ NtGdiModifyWorldTransform(HDC hDC,
      return FALSE;
    }
 
-   _SEH_TRY
-   {
-      ProbeForRead(UnsafeXForm, sizeof(XFORM), 1);
-      RtlCopyMemory(&SafeXForm, UnsafeXForm, sizeof(XFORM));
-      
-      Ret = IntGdiModifyWorldTransform(dc, &SafeXForm, Mode);
-   }
-   _SEH_HANDLE
+   // The xform is permitted to be NULL for MWT_IDENTITY.
+   // However, if it is not NULL, then it must be valid even though it is not used.
+   if (UnsafeXForm != NULL || Mode != MWT_IDENTITY)
    {
-      SetLastNtError(_SEH_GetExceptionCode());
+      _SEH_TRY
+      {
+         ProbeForRead(UnsafeXForm, sizeof(XFORM), 1);
+         RtlCopyMemory(&SafeXForm, UnsafeXForm, sizeof(XFORM));
+      }
+      _SEH_HANDLE
+      {
+         Ret = FALSE;
+      }
+      _SEH_END;
    }
-   _SEH_END;
 
+   // Safe to handle kernel mode data.
+   if (Ret) Ret = IntGdiModifyWorldTransform(dc, &SafeXForm, Mode);
    DC_UnlockDc(dc);
    return Ret;
 }
@@ -521,6 +428,7 @@ NtGdiOffsetViewportOrgEx(HDC hDC,
                         LPPOINT UnsafePoint)
 {
   PDC      dc;
+  PDC_ATTR Dc_Attr;
   NTSTATUS Status = STATUS_SUCCESS;
 
   dc = DC_LockDc ( hDC );
@@ -529,7 +437,9 @@ NtGdiOffsetViewportOrgEx(HDC hDC,
     SetLastWin32Error(ERROR_INVALID_HANDLE);
     return FALSE;
   }
-
+  Dc_Attr = dc->pDc_Attr;
+  if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
+  
   if (UnsafePoint)
     {
         _SEH_TRY
@@ -537,8 +447,8 @@ NtGdiOffsetViewportOrgEx(HDC hDC,
             ProbeForWrite(UnsafePoint,
                           sizeof(POINT),
                           1);
-            UnsafePoint->x = dc->vportOrgX;
-            UnsafePoint->y = dc->vportOrgY;
+            UnsafePoint->x = Dc_Attr->ptlViewportOrg.x;
+            UnsafePoint->y = Dc_Attr->ptlViewportOrg.y;
         }
         _SEH_HANDLE
         {
@@ -554,10 +464,9 @@ NtGdiOffsetViewportOrgEx(HDC hDC,
          }
     }
 
-  dc->vportOrgX += XOffset;
-  dc->vportOrgY += YOffset;
+  Dc_Attr->ptlViewportOrg.x += XOffset;
+  Dc_Attr->ptlViewportOrg.y += YOffset;
   DC_UpdateXforms(dc);
-
   DC_UnlockDc(dc);
   return TRUE;
 }
@@ -570,25 +479,28 @@ NtGdiOffsetWindowOrgEx(HDC  hDC,
                       LPPOINT  Point)
 {
   PDC dc;
-
+  PDC_ATTR Dc_Attr;
+  
   dc = DC_LockDc(hDC);
   if (!dc)
     {
       SetLastWin32Error(ERROR_INVALID_HANDLE);
       return FALSE;
     }
+  Dc_Attr = dc->pDc_Attr;
+  if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
 
   if (Point)
     {
       NTSTATUS Status = STATUS_SUCCESS;
-      
+
       _SEH_TRY
       {
          ProbeForWrite(Point,
                        sizeof(POINT),
                        1);
-         Point->x = dc->wndOrgX;
-         Point->y = dc->wndOrgY;
+         Point->x = Dc_Attr->ptlWindowOrg.x;
+         Point->y = Dc_Attr->ptlWindowOrg.y;
       }
       _SEH_HANDLE
       {
@@ -604,8 +516,8 @@ NtGdiOffsetWindowOrgEx(HDC  hDC,
       }
     }
 
-  dc->wndOrgX += XOffset;
-  dc->wndOrgY += YOffset;
+  Dc_Attr->ptlWindowOrg.x += XOffset;
+  Dc_Attr->ptlWindowOrg.y += YOffset;
 
   DC_UpdateXforms(dc);
   DC_UnlockDc(dc);
@@ -616,127 +528,227 @@ NtGdiOffsetWindowOrgEx(HDC  hDC,
 BOOL
 STDCALL
 NtGdiScaleViewportExtEx(HDC  hDC,
-                             int  Xnum,
-                             int  Xdenom,
-                             int  Ynum,
-                             int  Ydenom,
-                             LPSIZE  Size)
+                       int  Xnum,
+                     int  Xdenom,
+                       int  Ynum,
+                     int  Ydenom,
+                    LPSIZE pSize)
 {
-   UNIMPLEMENTED;
-   return FALSE;
+  PDC pDC;
+  PDC_ATTR pDc_Attr;
+  BOOL Ret = FALSE;
+  LONG X, Y;
+  
+  pDC = DC_LockDc(hDC);
+  if (!pDC)
+  {
+      SetLastWin32Error(ERROR_INVALID_HANDLE);
+      return FALSE;
+  }
+  pDc_Attr = pDC->pDc_Attr;
+  if(!pDc_Attr) pDc_Attr = &pDC->Dc_Attr;
+
+  if ( pSize )
+  {
+     NTSTATUS Status = STATUS_SUCCESS;
+
+     _SEH_TRY
+     {
+       ProbeForWrite(pSize,
+            sizeof(LPSIZE),
+                         1);
+
+       pSize->cx = pDc_Attr->szlViewportExt.cx;
+       pSize->cy = pDc_Attr->szlViewportExt.cy;
+     }
+     _SEH_HANDLE
+     {
+         Status = _SEH_GetExceptionCode();
+     }
+     _SEH_END;
+
+     if(!NT_SUCCESS(Status))
+     {
+        SetLastNtError(Status);
+        DC_UnlockDc(pDC);
+        return FALSE;
+     }
+  }
+
+  if (pDc_Attr->iMapMode > MM_TWIPS)
+  { 
+     if ( ( Xdenom ) && ( Ydenom ) )
+     {
+        X = Xnum * pDc_Attr->szlViewportExt.cx / Xdenom;
+        if ( X )
+        {
+           Y = Ynum * pDc_Attr->szlViewportExt.cy / Ydenom;
+           if ( Y )
+           {
+              pDc_Attr->szlViewportExt.cx = X; 
+              pDc_Attr->szlViewportExt.cy = Y;
+
+              IntMirrorWindowOrg(pDC);
+              
+              pDc_Attr->flXform |= (PAGE_EXTENTS_CHANGED|INVALIDATE_ATTRIBUTES|DEVICE_TO_WORLD_INVALID);
+
+              if (pDc_Attr->iMapMode == MM_ISOTROPIC) IntFixIsotropicMapping(pDC);
+              DC_UpdateXforms(pDC);
+
+              Ret = TRUE;
+           }
+        }
+     }
+  }
+  else
+    Ret = TRUE;
+
+  DC_UnlockDc(pDC);
+  return Ret;
 }
 
 BOOL
 STDCALL
 NtGdiScaleWindowExtEx(HDC  hDC,
-                           int  Xnum,
-                           int  Xdenom,
-                           int  Ynum,
-                           int  Ydenom,
-                           LPSIZE  Size)
-{
-   UNIMPLEMENTED;
-   return FALSE;
-}
-
-int
-STDCALL
-NtGdiSetGraphicsMode(HDC  hDC,
-                    int  Mode)
+                     int  Xnum,
+                   int  Xdenom,
+                     int  Ynum,
+                   int  Ydenom,
+                  LPSIZE pSize)
 {
-  INT ret;
-  PDC dc;
+  PDC pDC;
+  PDC_ATTR pDc_Attr;
+  BOOL Ret = FALSE;
+  LONG X, Y;
+  
+  pDC = DC_LockDc(hDC);
+  if (!pDC)
+  {
+      SetLastWin32Error(ERROR_INVALID_HANDLE);
+      return FALSE;
+  }
+  pDc_Attr = pDC->pDc_Attr;
+  if(!pDc_Attr) pDc_Attr = &pDC->Dc_Attr;
 
-  dc = DC_LockDc (hDC);
-  if (!dc)
+  if ( pSize )
   {
-    SetLastWin32Error(ERROR_INVALID_HANDLE);
-    return 0;
+     NTSTATUS Status = STATUS_SUCCESS;
+
+     _SEH_TRY
+     {
+       ProbeForWrite(pSize,
+            sizeof(LPSIZE),
+                         1);
+
+       X = pDc_Attr->szlWindowExt.cx;
+       if (pDc_Attr->dwLayout & LAYOUT_RTL) X = -X;
+       pSize->cx = X;
+       pSize->cy = pDc_Attr->szlWindowExt.cy;
+     }
+     _SEH_HANDLE
+     {
+         Status = _SEH_GetExceptionCode();
+     }
+     _SEH_END;
+
+     if(!NT_SUCCESS(Status))
+     {
+        SetLastNtError(Status);
+        DC_UnlockDc(pDC);
+        return FALSE;
+     }
   }
 
-  /* One would think that setting the graphics mode to GM_COMPATIBLE
-   * would also reset the world transformation matrix to the unity
-   * matrix. However, in Windows, this is not the case. This doesn't
-   * make a lot of sense to me, but that's the way it is.
-   */
+  if (pDc_Attr->iMapMode > MM_TWIPS)
+  { 
+     if (( Xdenom ) && ( Ydenom ))
+     {
+        X = Xnum * pDc_Attr->szlWindowExt.cx / Xdenom;
+        if ( X )
+        {
+           Y = Ynum * pDc_Attr->szlWindowExt.cy / Ydenom;
+           if ( Y )
+           {
+              pDc_Attr->szlWindowExt.cx = X;
+              pDc_Attr->szlWindowExt.cy = Y;
 
-  if ((Mode != GM_COMPATIBLE) && (Mode != GM_ADVANCED))
-    {
-      DC_UnlockDc(dc);
-      SetLastWin32Error(ERROR_INVALID_PARAMETER);
-      return 0;
-    }
+              IntMirrorWindowOrg(pDC);
+              
+              pDc_Attr->flXform |= (PAGE_EXTENTS_CHANGED|INVALIDATE_ATTRIBUTES|DEVICE_TO_WORLD_INVALID);
 
-  ret = dc->w.GraphicsMode;
-  dc->w.GraphicsMode = Mode;
-  DC_UnlockDc(dc);
-  return  ret;
+              if (pDc_Attr->iMapMode == MM_ISOTROPIC) IntFixIsotropicMapping(pDC);
+              DC_UpdateXforms(pDC);
+
+              Ret = TRUE;
+           }
+        }
+     }
+  }
+  else
+    Ret = TRUE;
+
+  DC_UnlockDc(pDC);
+  return Ret;
 }
 
 int
 STDCALL
-NtGdiSetMapMode(HDC  hDC,
+IntGdiSetMapMode(PDC  dc,
                 int  MapMode)
 {
   int PrevMapMode;
-  PDC dc;
-
-  dc = DC_LockDc(hDC);
-  if (!dc)
-  {
-    SetLastWin32Error(ERROR_INVALID_HANDLE);
-    return 0;
-  }
+  PDC_ATTR Dc_Attr = dc->pDc_Attr;
+  if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
 
-  PrevMapMode = dc->w.MapMode;
+  PrevMapMode = Dc_Attr->iMapMode;
 
-  if (MapMode != dc->w.MapMode || (MapMode != MM_ISOTROPIC && MapMode != MM_ANISOTROPIC))
+  if (MapMode != Dc_Attr->iMapMode || (MapMode != MM_ISOTROPIC && MapMode != MM_ANISOTROPIC))
   {
-    dc->w.MapMode = MapMode;
+    Dc_Attr->iMapMode = MapMode;
 
     switch (MapMode)
     {
       case MM_TEXT:
-        dc->wndExtX = 1;
-        dc->wndExtY = 1;
-        dc->vportExtX = 1;
-        dc->vportExtY = 1;
+        Dc_Attr->szlWindowExt.cx = 1;
+        Dc_Attr->szlWindowExt.cy = 1;
+        Dc_Attr->szlViewportExt.cx = 1;
+        Dc_Attr->szlViewportExt.cy = 1;
         break;
 
       case MM_LOMETRIC:
       case MM_ISOTROPIC:
-        dc->wndExtX = dc->GDIInfo->ulHorzSize * 10;
-        dc->wndExtY = dc->GDIInfo->ulVertSize * 10;
-        dc->vportExtX = dc->GDIInfo->ulHorzRes;
-        dc->vportExtY = -dc->GDIInfo->ulVertRes;
+        Dc_Attr->szlWindowExt.cx = ((PGDIDEVICE)dc->pPDev)->GDIInfo.ulHorzSize * 10;
+        Dc_Attr->szlWindowExt.cy = ((PGDIDEVICE)dc->pPDev)->GDIInfo.ulVertSize * 10;
+        Dc_Attr->szlViewportExt.cx = ((PGDIDEVICE)dc->pPDev)->GDIInfo.ulHorzRes;
+        Dc_Attr->szlViewportExt.cy = -((PGDIDEVICE)dc->pPDev)->GDIInfo.ulVertRes;
         break;
 
       case MM_HIMETRIC:
-        dc->wndExtX = dc->GDIInfo->ulHorzSize * 100;
-        dc->wndExtY = dc->GDIInfo->ulVertSize * 100;
-        dc->vportExtX = dc->GDIInfo->ulHorzRes;
-        dc->vportExtY = -dc->GDIInfo->ulVertRes;
+        Dc_Attr->szlWindowExt.cx = ((PGDIDEVICE)dc->pPDev)->GDIInfo.ulHorzSize * 100;
+        Dc_Attr->szlWindowExt.cy = ((PGDIDEVICE)dc->pPDev)->GDIInfo.ulVertSize * 100;
+        Dc_Attr->szlViewportExt.cx = ((PGDIDEVICE)dc->pPDev)->GDIInfo.ulHorzRes;
+        Dc_Attr->szlViewportExt.cy = -((PGDIDEVICE)dc->pPDev)->GDIInfo.ulVertRes;
         break;
 
       case MM_LOENGLISH:
-        dc->wndExtX = EngMulDiv(1000, dc->GDIInfo->ulHorzSize, 254);
-        dc->wndExtY = EngMulDiv(1000, dc->GDIInfo->ulVertSize, 254);
-        dc->vportExtX = dc->GDIInfo->ulHorzRes;
-        dc->vportExtY = -dc->GDIInfo->ulVertRes;
+        Dc_Attr->szlWindowExt.cx = EngMulDiv(1000, ((PGDIDEVICE)dc->pPDev)->GDIInfo.ulHorzSize, 254);
+        Dc_Attr->szlWindowExt.cy = EngMulDiv(1000, ((PGDIDEVICE)dc->pPDev)->GDIInfo.ulVertSize, 254);
+        Dc_Attr->szlViewportExt.cx = ((PGDIDEVICE)dc->pPDev)->GDIInfo.ulHorzRes;
+        Dc_Attr->szlViewportExt.cy = -((PGDIDEVICE)dc->pPDev)->GDIInfo.ulVertRes;
         break;
 
       case MM_HIENGLISH:
-        dc->wndExtX = EngMulDiv(10000, dc->GDIInfo->ulHorzSize, 254);
-        dc->wndExtY = EngMulDiv(10000, dc->GDIInfo->ulVertSize, 254);
-        dc->vportExtX = dc->GDIInfo->ulHorzRes;
-        dc->vportExtY = -dc->GDIInfo->ulVertRes;
+        Dc_Attr->szlWindowExt.cx = EngMulDiv(10000, ((PGDIDEVICE)dc->pPDev)->GDIInfo.ulHorzSize, 254);
+        Dc_Attr->szlWindowExt.cy = EngMulDiv(10000, ((PGDIDEVICE)dc->pPDev)->GDIInfo.ulVertSize, 254);
+        Dc_Attr->szlViewportExt.cx = ((PGDIDEVICE)dc->pPDev)->GDIInfo.ulHorzRes;
+        Dc_Attr->szlViewportExt.cy = -((PGDIDEVICE)dc->pPDev)->GDIInfo.ulVertRes;
         break;
 
       case MM_TWIPS:
-        dc->wndExtX = EngMulDiv(14400, dc->GDIInfo->ulHorzSize, 254);
-        dc->wndExtY = EngMulDiv(14400, dc->GDIInfo->ulVertSize, 254);
-        dc->vportExtX = dc->GDIInfo->ulHorzRes;
-        dc->vportExtY = -dc->GDIInfo->ulVertRes;
+        Dc_Attr->szlWindowExt.cx = EngMulDiv(14400, ((PGDIDEVICE)dc->pPDev)->GDIInfo.ulHorzSize, 254);
+        Dc_Attr->szlWindowExt.cy = EngMulDiv(14400, ((PGDIDEVICE)dc->pPDev)->GDIInfo.ulVertSize, 254);
+        Dc_Attr->szlViewportExt.cx = ((PGDIDEVICE)dc->pPDev)->GDIInfo.ulHorzRes;
+        Dc_Attr->szlViewportExt.cy = -((PGDIDEVICE)dc->pPDev)->GDIInfo.ulVertRes;
         break;
 
       case MM_ANISOTROPIC:
@@ -746,8 +758,6 @@ NtGdiSetMapMode(HDC  hDC,
     DC_UpdateXforms(dc);
   }
 
-  DC_UnlockDc(dc);
-
   return PrevMapMode;
 }
 
@@ -759,6 +769,7 @@ NtGdiSetViewportExtEx(HDC  hDC,
                       LPSIZE  Size)
 {
   PDC dc;
+  PDC_ATTR Dc_Attr;
 
   dc = DC_LockDc(hDC);
   if ( !dc )
@@ -766,8 +777,10 @@ NtGdiSetViewportExtEx(HDC  hDC,
     SetLastWin32Error(ERROR_INVALID_HANDLE);
     return FALSE;
   }
+  Dc_Attr = dc->pDc_Attr;
+  if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
 
-  switch (dc->w.MapMode)
+  switch (Dc_Attr->iMapMode)
     {
       case MM_HIENGLISH:
       case MM_HIMETRIC:
@@ -793,13 +806,13 @@ NtGdiSetViewportExtEx(HDC  hDC,
          ProbeForWrite(Size,
                        sizeof(SIZE),
                        1);
-         Size->cx = dc->vportExtX;
-         Size->cy = dc->vportExtY;
+         Size->cx = Dc_Attr->szlViewportExt.cx;
+         Size->cy = Dc_Attr->szlViewportExt.cy;
 
-                dc->vportExtX = XExtent;
-         dc->vportExtY = YExtent;
+         Dc_Attr->szlViewportExt.cx = XExtent;
+         Dc_Attr->szlViewportExt.cy = YExtent;
 
-         if (dc->w.MapMode == MM_ISOTROPIC)
+         if (Dc_Attr->iMapMode == MM_ISOTROPIC)
              IntFixIsotropicMapping(dc);
       }
       _SEH_HANDLE
@@ -816,7 +829,7 @@ NtGdiSetViewportExtEx(HDC  hDC,
       }
     }
 
-  
+
   DC_UpdateXforms(dc);
   DC_UnlockDc(dc);
 
@@ -831,6 +844,7 @@ NtGdiSetViewportOrgEx(HDC  hDC,
                      LPPOINT  Point)
 {
   PDC dc;
+  PDC_ATTR Dc_Attr;
 
   dc = DC_LockDc(hDC);
   if (!dc)
@@ -838,18 +852,20 @@ NtGdiSetViewportOrgEx(HDC  hDC,
       SetLastWin32Error(ERROR_INVALID_HANDLE);
       return FALSE;
     }
+  Dc_Attr = dc->pDc_Attr;
+  if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
 
   if (Point)
     {
       NTSTATUS Status = STATUS_SUCCESS;
-      
+
       _SEH_TRY
       {
          ProbeForWrite(Point,
                        sizeof(POINT),
                        1);
-         Point->x = dc->vportOrgX;
-         Point->y = dc->vportOrgY;
+         Point->x = Dc_Attr->ptlViewportOrg.x;
+         Point->y = Dc_Attr->ptlViewportOrg.y;
       }
       _SEH_HANDLE
       {
@@ -865,8 +881,8 @@ NtGdiSetViewportOrgEx(HDC  hDC,
       }
     }
 
-  dc->vportOrgX = X;
-  dc->vportOrgY = Y;
+  Dc_Attr->ptlViewportOrg.x = X;
+  Dc_Attr->ptlViewportOrg.y = Y;
 
   DC_UpdateXforms(dc);
   DC_UnlockDc(dc);
@@ -882,6 +898,7 @@ NtGdiSetWindowExtEx(HDC  hDC,
                    LPSIZE  Size)
 {
   PDC dc;
+  PDC_ATTR Dc_Attr;
 
   dc = DC_LockDc(hDC);
   if (!dc)
@@ -889,8 +906,10 @@ NtGdiSetWindowExtEx(HDC  hDC,
       SetLastWin32Error(ERROR_INVALID_HANDLE);
       return FALSE;
     }
+  Dc_Attr = dc->pDc_Attr;
+  if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
 
-  switch (dc->w.MapMode)
+  switch (Dc_Attr->iMapMode)
     {
       case MM_HIENGLISH:
       case MM_HIMETRIC:
@@ -905,14 +924,14 @@ NtGdiSetWindowExtEx(HDC  hDC,
   if (Size)
     {
       NTSTATUS Status = STATUS_SUCCESS;
-      
+
       _SEH_TRY
       {
          ProbeForWrite(Size,
                        sizeof(SIZE),
                        1);
-         Size->cx = dc->wndExtX;
-         Size->cy = dc->wndExtY;
+         Size->cx = Dc_Attr->szlWindowExt.cx;
+         Size->cy = Dc_Attr->szlWindowExt.cy;
       }
       _SEH_HANDLE
       {
@@ -928,8 +947,8 @@ NtGdiSetWindowExtEx(HDC  hDC,
       }
     }
 
-  dc->wndExtX = XExtent;
-  dc->wndExtY = YExtent;
+  Dc_Attr->szlWindowExt.cx = XExtent;
+  Dc_Attr->szlWindowExt.cy = YExtent;
 
   DC_UpdateXforms(dc);
   DC_UnlockDc(dc);
@@ -945,6 +964,7 @@ NtGdiSetWindowOrgEx(HDC  hDC,
                    LPPOINT  Point)
 {
   PDC dc;
+  PDC_ATTR Dc_Attr;
 
   dc = DC_LockDc(hDC);
   if (!dc)
@@ -952,18 +972,20 @@ NtGdiSetWindowOrgEx(HDC  hDC,
       SetLastWin32Error(ERROR_INVALID_HANDLE);
       return FALSE;
     }
+  Dc_Attr = dc->pDc_Attr;
+  if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
 
   if (Point)
     {
       NTSTATUS Status = STATUS_SUCCESS;
-      
+
       _SEH_TRY
       {
          ProbeForWrite(Point,
                        sizeof(POINT),
                        1);
-         Point->x = dc->wndOrgX;
-         Point->y = dc->wndOrgY;
+         Point->x = Dc_Attr->ptlWindowOrg.x;
+         Point->y = Dc_Attr->ptlWindowOrg.y;
       }
       _SEH_HANDLE
       {
@@ -979,8 +1001,8 @@ NtGdiSetWindowOrgEx(HDC  hDC,
       }
     }
 
-  dc->wndOrgX = X;
-  dc->wndOrgY = Y;
+  Dc_Attr->ptlWindowOrg.x = X;
+  Dc_Attr->ptlWindowOrg.y = Y;
 
   DC_UpdateXforms(dc);
   DC_UnlockDc(dc);
@@ -988,57 +1010,201 @@ NtGdiSetWindowOrgEx(HDC  hDC,
   return TRUE;
 }
 
-BOOL
-STDCALL
-NtGdiSetWorldTransform(HDC  hDC,
-                      CONST LPXFORM  XForm)
+//
+// Mirror Window function.
+//
+VOID
+FASTCALL
+IntMirrorWindowOrg(PDC dc)
 {
-  PDC  dc;
-  NTSTATUS Status = STATUS_SUCCESS;
+  PDC_ATTR Dc_Attr;
+  LONG X;
+  
+  Dc_Attr = dc->pDc_Attr;
+  if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
 
-  dc = DC_LockDc (hDC);
-  if ( !dc )
+  if (!(Dc_Attr->dwLayout & LAYOUT_RTL))
   {
-    SetLastWin32Error(ERROR_INVALID_HANDLE);
-    return  FALSE;
+     Dc_Attr->ptlWindowOrg.x = Dc_Attr->lWindowOrgx; // Flip it back.
+     return;
   }
+  if (!Dc_Attr->szlViewportExt.cx) return;
+  // 
+  // WOrgx = wox - (Width - 1) * WExtx / VExtx
+  //
+  X = (dc->erclWindow.right - dc->erclWindow.left) - 1; // Get device width - 1
 
-  if (!XForm)
+  X = ( X * Dc_Attr->szlWindowExt.cx) / Dc_Attr->szlViewportExt.cx;
+
+  Dc_Attr->ptlWindowOrg.x = Dc_Attr->lWindowOrgx - X; // Now set the inverted win origion.
+
+  return;
+}
+
+// NtGdiSetLayout
+// 
+// The default is left to right. This function changes it to right to left, which
+// is the standard in Arabic and Hebrew cultures.
+//
+/*
+ * @implemented
+ */
+DWORD
+APIENTRY
+NtGdiSetLayout(
+    IN HDC hdc,
+    IN LONG wox,
+    IN DWORD dwLayout)
+{
+  PDC dc;
+  PDC_ATTR Dc_Attr;
+  DWORD oLayout;
+
+  dc = DC_LockDc(hdc);
+  if (!dc)
   {
-    DC_UnlockDc(dc);
-    /* Win doesn't set LastError */
-    return  FALSE;
+     SetLastWin32Error(ERROR_INVALID_HANDLE);
+     return GDI_ERROR;
   }
+  Dc_Attr = dc->pDc_Attr;
+  if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
+
+  Dc_Attr->dwLayout = dwLayout;
+  oLayout = Dc_Attr->dwLayout;
 
-  /* Check that graphics mode is GM_ADVANCED */
-  if ( dc->w.GraphicsMode != GM_ADVANCED )
+  if (!(dwLayout & LAYOUT_ORIENTATIONMASK))
   {
-    DC_UnlockDc(dc);
-    return  FALSE;
+     DC_UnlockDc(dc);
+     return oLayout;
   }
 
-  _SEH_TRY
+  if (dwLayout & LAYOUT_RTL) Dc_Attr->iMapMode = MM_ANISOTROPIC;
+
+  Dc_Attr->szlWindowExt.cy = -Dc_Attr->szlWindowExt.cy;
+  Dc_Attr->ptlWindowOrg.x  = -Dc_Attr->ptlWindowOrg.x;
+
+  if (wox == -1)
+     IntMirrorWindowOrg(dc);
+  else
+     Dc_Attr->ptlWindowOrg.x = wox - Dc_Attr->ptlWindowOrg.x;
+
+  if (!(Dc_Attr->flTextAlign & TA_CENTER)) Dc_Attr->flTextAlign |= TA_RIGHT;
+
+  if (dc->DcLevel.flPath & DCPATH_CLOCKWISE)
+      dc->DcLevel.flPath &= ~DCPATH_CLOCKWISE;
+  else
+      dc->DcLevel.flPath |= DCPATH_CLOCKWISE;
+
+  Dc_Attr->flXform |= (PAGE_EXTENTS_CHANGED|INVALIDATE_ATTRIBUTES|DEVICE_TO_WORLD_INVALID);
+
+//  DC_UpdateXforms(dc);
+  DC_UnlockDc(dc);
+  return oLayout;
+}
+
+/*
+ * @implemented
+ */
+LONG
+APIENTRY
+NtGdiGetDeviceWidth(
+    IN HDC hdc)
+{
+  PDC dc;
+  LONG Ret;
+  dc = DC_LockDc(hdc);
+  if (!dc)
   {
-    ProbeForRead(XForm,
-                 sizeof(XFORM),
-                 1);
-    dc->w.xformWorld2Wnd = *XForm;
+     SetLastWin32Error(ERROR_INVALID_HANDLE);
+     return 0;
   }
-  _SEH_HANDLE
+  Ret = dc->erclWindow.right - dc->erclWindow.left;
+  DC_UnlockDc(dc);
+  return Ret;
+}
+
+/*
+ * @implemented
+ */
+BOOL
+APIENTRY
+NtGdiMirrorWindowOrg(
+    IN HDC hdc)
+{
+  PDC dc;
+  dc = DC_LockDc(hdc);
+  if (!dc)
   {
-    Status = _SEH_GetExceptionCode();
+     SetLastWin32Error(ERROR_INVALID_HANDLE);
+     return FALSE;
   }
-  _SEH_END;
+  IntMirrorWindowOrg(dc);
+  DC_UnlockDc(dc);
+  return TRUE;
+}
 
-  if(!NT_SUCCESS(Status))
-  {
+/*
+ * @implemented
+ */
+BOOL
+APIENTRY
+NtGdiSetSizeDevice(
+    IN HDC hdc,
+    IN INT cxVirtualDevice,
+    IN INT cyVirtualDevice)
+{
+    PDC dc;
+    PDC_ATTR pDc_Attr;
+
+    if (!cxVirtualDevice ||
+        !cyVirtualDevice  ) return FALSE;
+
+    dc = DC_LockDc(hdc);
+    if (!dc) return FALSE;
+    
+    pDc_Attr = dc->pDc_Attr;
+    if(!pDc_Attr) pDc_Attr = &dc->Dc_Attr;
+
+    pDc_Attr->szlVirtualDeviceSize.cx = cxVirtualDevice;
+    pDc_Attr->szlVirtualDeviceSize.cy = cyVirtualDevice;
+
+//    DC_UpdateXforms(dc);    
     DC_UnlockDc(dc);
-    return FALSE;
-  }
 
-  DC_UpdateXforms(dc);
-  DC_UnlockDc(dc);
-  return  TRUE;
+    return TRUE;
+}
+
+/*
+ * @implemented
+ */
+BOOL
+APIENTRY
+NtGdiSetVirtualResolution(
+    IN HDC hdc,
+    IN INT cxVirtualDevicePixel,
+    IN INT cyVirtualDevicePixel,
+    IN INT cxVirtualDeviceMm,
+    IN INT cyVirtualDeviceMm)
+{
+    PDC dc;
+    PDC_ATTR pDc_Attr;
+
+    // Need test types for zeros and non zeros
+
+    dc = DC_LockDc(hdc);
+    if (!dc) return FALSE;
+    
+    pDc_Attr = dc->pDc_Attr;
+    if(!pDc_Attr) pDc_Attr = &dc->Dc_Attr;
+
+    pDc_Attr->szlVirtualDevicePixel.cx = cxVirtualDevicePixel;
+    pDc_Attr->szlVirtualDevicePixel.cy = cyVirtualDevicePixel;
+    pDc_Attr->szlVirtualDeviceMm.cx = cxVirtualDeviceMm;
+    pDc_Attr->szlVirtualDeviceMm.cy = cyVirtualDeviceMm;
+
+//    DC_UpdateXforms(dc);    
+    DC_UnlockDc(dc);
+    return TRUE;
 }
 
 /* EOF */