Jeffrey Morlan (mrnobo1024 at yahoo.com) - Fix ModifyWorldTransform multiplies. See...
[reactos.git] / reactos / subsystems / win32 / win32k / objects / coord.c
index 8de7d49..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
@@ -68,6 +68,7 @@ IntGdiCombineTransform(LPXFORM XFormResult,
                        LPXFORM xform1,
                        LPXFORM xform2)
 {
+  XFORM xformTemp;
   /* Check for illegal parameters */
   if (!XFormResult || !xform1 || !xform2)
   {
@@ -76,12 +77,13 @@ 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;
 }
@@ -90,9 +92,6 @@ BOOL STDCALL NtGdiCombineTransform(LPXFORM  UnsafeXFormResult,
                                    LPXFORM  Unsafexform1,
                                    LPXFORM  Unsafexform2)
 {
-  XFORM  xformTemp;
-  XFORM  xform1 = {0}, xform2 = {0};
-  NTSTATUS Status = STATUS_SUCCESS;
   BOOL Ret;
 
   _SEH_TRY
@@ -106,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;
 }
 
@@ -150,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
@@ -185,33 +157,32 @@ 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->w.xformWorld2Wnd = *lpXForm; // Do it like Wine.
+       pDc->DcLevel.xformWorld2Wnd = *lpXForm; // Do it like Wine.
        break;
 
      default:
-       SetLastWin32Error(ERROR_INVALID_PARAMETER);
        return FALSE;
   }
   DC_UpdateXforms(pDc);
@@ -248,7 +219,7 @@ NtGdiGetTransform(HDC  hDC,
    switch(iXform)
    {
      case GdiWorldSpaceToPageSpace:
-        *XForm = dc->w.xformWorld2Wnd;
+        *XForm = dc->DcLevel.xformWorld2Wnd;
      break;
      default:
      break;
@@ -275,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
@@ -418,13 +389,7 @@ NtGdiModifyWorldTransform(HDC hDC,
 {
    PDC dc;
    XFORM SafeXForm;
-   BOOL Ret = FALSE;
-
-   if (!UnsafeXForm)
-   {
-     SetLastWin32Error(ERROR_INVALID_PARAMETER);
-     return FALSE;
-   }
+   BOOL Ret = TRUE;
 
    dc = DC_LockDc(hDC);
    if (!dc)
@@ -433,19 +398,24 @@ NtGdiModifyWorldTransform(HDC hDC,
      return FALSE;
    }
 
-   _SEH_TRY
-   {
-      ProbeForRead(UnsafeXForm, sizeof(XFORM), 1);
-      RtlCopyMemory(&SafeXForm, UnsafeXForm, sizeof(XFORM));
-   }
-   _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.
-   Ret = IntGdiModifyWorldTransform(dc, &SafeXForm, Mode);
+   if (Ret) Ret = IntGdiModifyWorldTransform(dc, &SafeXForm, Mode);
    DC_UnlockDc(dc);
    return Ret;
 }
@@ -558,27 +528,167 @@ 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)
+                     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);
+
+       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;
+     }
+  }
+
+  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;
+
+              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;
 }
 
 int
@@ -980,10 +1090,10 @@ NtGdiSetLayout(
 
   if (!(Dc_Attr->flTextAlign & TA_CENTER)) Dc_Attr->flTextAlign |= TA_RIGHT;
 
-  if (dc->w.ArcDirection == AD_CLOCKWISE)
-      dc->w.ArcDirection = AD_COUNTERCLOCKWISE;
+  if (dc->DcLevel.flPath & DCPATH_CLOCKWISE)
+      dc->DcLevel.flPath &= ~DCPATH_CLOCKWISE;
   else
-      dc->w.ArcDirection = AD_CLOCKWISE;
+      dc->DcLevel.flPath |= DCPATH_CLOCKWISE;
 
   Dc_Attr->flXform |= (PAGE_EXTENTS_CHANGED|INVALIDATE_ATTRIBUTES|DEVICE_TO_WORLD_INVALID);
 
@@ -1033,4 +1143,68 @@ NtGdiMirrorWindowOrg(
   return TRUE;
 }
 
+/*
+ * @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 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 */