[CMAKE]
[reactos.git] / dll / win32 / gdi32 / objects / coord.c
index 9f89ae1..c736ab7 100644 (file)
+/*
+ * COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         ReactOS System Libraries
+ * FILE:            dll/gdi32/objects/coord.c
+ * PURPOSE:         Functions for coordinate transformation
+ * PROGRAMMER:
+ */
 #include "precomp.h"
 
-/* the following deal with IEEE single-precision numbers */
-#define EXCESS          126L
-#define SIGNBIT         0x80000000L
-#define SIGN(fp)        ((fp) & SIGNBIT)
-#define EXP(fp)         (((fp) >> 23L) & 0xFF)
-#define MANT(fp)        ((fp) & 0x7FFFFFL)
-#define PACK(s,e,m)     ((s) | ((e) << 23L) | (m))
-
-// Sames as lrintf.
-#ifdef __GNUC__
-#define FLOAT_TO_INT(in,out)  \
-           __asm__ __volatile__ ("fistpl %0" : "=m" (out) : "t" (in) : "st");
-#else
-#define FLOAT_TO_INT(in,out) \
-          __asm fld in; \
-          __asm fistp out;
-#endif
-
-LONG
-FASTCALL
-EFtoF( EFLOAT_S * efp)
+/* Currently we use a MATRIX inside the DC_ATTR containing the
+   coordinate transformations, while we deal with XFORM structures
+   internally. If we move all coordinate transformation to gdi32,
+   we might as well have an XFORM structure in the DC_ATTR. */
+void
+MatrixToXForm(XFORM *pxform, const MATRIX *pmx)
 {
-    long Mant, Exp, Sign = 0;
-
-    if (!efp->lMant) return 0;
+    XFORML *pxforml = (XFORML*)pxform;
+    pxforml->eM11 = FOtoF(&pmx->efM11);
+    pxforml->eM12 = FOtoF(&pmx->efM12);
+    pxforml->eM21 = FOtoF(&pmx->efM21);
+    pxforml->eM22 = FOtoF(&pmx->efM22);
+    pxforml->eDx = FOtoF(&pmx->efDx);
+    pxforml->eDy = FOtoF(&pmx->efDy);
+}
 
-    Mant = efp->lMant;
-    Exp = efp->lExp;
-    Sign = SIGN(Mant);
+void
+GdiTransformPoints2(
+    XFORM *pxform,
+    PPOINT pptOut,
+    PPOINT pptIn,
+    ULONG nCount)
+{
+    ULONG i;
+    FLOAT x, y;
 
-//// M$ storage emulation
-    if( Sign ) Mant = -Mant;
-    Mant = ((Mant & 0x3fffffff) >> 7);
-    Exp += (EXCESS-1);
-////
-    Mant = MANT(Mant);
-    return PACK(Sign, Exp, Mant);
+    for (i = 0; i < nCount; i++)
+    {
+        x = pptIn[i].x * pxform->eM11 + pptIn[i].y * pxform->eM12 + pxform->eDx;
+        pptOut[i].x = _lrintf(x);
+        y = pptIn[i].x * pxform->eM21 + pptIn[i].y * pxform->eM22 + pxform->eDy;
+        pptOut[i].y = _lrintf(y);
+    }
 }
 
-VOID
-FASTCALL
-FtoEF( EFLOAT_S * efp, FLOATL f)
+FORCEINLINE
+void
+GdiTransformPoints(
+    MATRIX *pmx,
+    PPOINT pptOut,
+    PPOINT pptIn,
+    ULONG nCount)
 {
-    long Mant, Exp, Sign = 0;
-    gxf_long worker;
+    XFORM xform;
 
-#ifdef _X86_
-    worker.l = f; // It's a float stored in a long.
-#else
-    worker.f = f;
-#endif
-
-    Exp = EXP(worker.l);
-    Mant = MANT(worker.l);
-    if (SIGN(worker.l)) Sign = -1;
-//// M$ storage emulation
-    Mant = ((Mant << 7) | 0x40000000);
-    Mant ^= Sign;
-    Mant -= Sign;
-    Exp -= (EXCESS-1);
-////
-    efp->lMant = Mant;
-    efp->lExp = Exp;
+    MatrixToXForm(&xform, pmx);
+    GdiTransformPoints2(&xform, pptOut, pptIn, nCount);
 }
 
+#define MAX_OFFSET 4294967040.0
 
-VOID FASTCALL
-CoordCnvP(MATRIX_S * mx, LPPOINT Point)
+BOOL
+WINAPI
+CombineTransform(
+    LPXFORM pxfResult,
+    const XFORM *pxf1,
+    const XFORM *pxf2)
 {
-    FLOAT x, y;
-    gxf_long a, b, c;
+    XFORM xformTmp;
 
-    x = (FLOAT)Point->x;
-    y = (FLOAT)Point->y;
+    /* Check paramters */
+    if (!pxfResult || !pxf1 || !pxf2) return FALSE;
 
-    a.l = EFtoF( &mx->efM11 );
-    b.l = EFtoF( &mx->efM21 );
-    c.l = EFtoF( &mx->efDx  );
-    x = x * a.f + y * b.f + c.f;
+    /* Do matrix multiplication */
+    xformTmp.eM11 = pxf1->eM11 * pxf2->eM11 + pxf1->eM12 * pxf2->eM21;
+    xformTmp.eM12 = pxf1->eM11 * pxf2->eM12 + pxf1->eM12 * pxf2->eM22;
+    xformTmp.eM21 = pxf1->eM21 * pxf2->eM11 + pxf1->eM22 * pxf2->eM21;
+    xformTmp.eM22 = pxf1->eM21 * pxf2->eM12 + pxf1->eM22 * pxf2->eM22;
+    xformTmp.eDx = pxf1->eDx * pxf2->eM11 + pxf1->eDy * pxf2->eM21 + pxf2->eDx;
+    xformTmp.eDy = pxf1->eDx * pxf2->eM12 + pxf1->eDy * pxf2->eM22 + pxf2->eDy;
 
-    a.l = EFtoF( &mx->efM12 );
-    b.l = EFtoF( &mx->efM22 );
-    c.l = EFtoF( &mx->efDy  );
-    y = x * a.f + y * b.f + c.f;
+    *pxfResult = xformTmp;
+#if 0
+    /* windows compatibility fixups (needs more work) */
+    if (_isnan(xformTmp.eM12))
+    {
+        if (pxf1->eM11 == 0 || pxf2->eM12 == 0) pxfResult->eM12 = 0.;
+    }
+#endif
+    /* Check for invalid offset ranges */
+    if (xformTmp.eDx > MAX_OFFSET || xformTmp.eDx < -MAX_OFFSET ||
+        xformTmp.eDy > MAX_OFFSET || xformTmp.eDy < -MAX_OFFSET)
+    {
+        return FALSE;
+    }
 
-    FLOAT_TO_INT(x, Point->x );
-    FLOAT_TO_INT(y, Point->y );
+    return TRUE;
 }
 
-
 BOOL
 WINAPI
-DPtoLP ( HDC hDC, LPPOINT Points, INT Count )
+DPtoLP(HDC hdc, LPPOINT lpPoints, INT nCount)
 {
 #if 0
     INT i;
-    PDC_ATTR Dc_Attr;
+    PDC_ATTR pdcattr;
 
-    if (!GdiGetHandleUserData((HGDIOBJ) hDC, GDI_OBJECT_TYPE_DC, (PVOID) &Dc_Attr)) return FALSE;
+    pdcattr = GdiGetDcAttr(hdc);
+    if (!pdcattr)
+    {
+        SetLastError(ERROR_INVALID_HANDLE);
+        return FALSE;
+    }
 
-    if (Dc_Attr->flXform & ( DEVICE_TO_WORLD_INVALID | // Force a full recalibration!
-                             PAGE_XLATE_CHANGED      | // Changes or Updates have been made,
-                             PAGE_EXTENTS_CHANGED    | // do processing in kernel space.
-                             WORLD_XFORM_CHANGED ))
-#endif
-        return NtGdiTransformPoints( hDC, Points, Points, Count, GdiDpToLp); // DPtoLP mode.
-#if 0
-    else
+    if (pdcattr->flXform & ANY_XFORM_CHANGES)
     {
-        for ( i = 0; i < Count; i++ )
-            CoordCnvP ( &Dc_Attr->mxDeviceToWorld, &Points[i] );
+        GdiFixupTransforms(pdcattr);
     }
+
+    // FIXME: can this fail on Windows?
+    GdiTransformPoints(&pdcattr->mxDeviceToWorld, lpPoints, lpPoints, nCount);
+
     return TRUE;
 #endif
+    return NtGdiTransformPoints(hdc, lpPoints, lpPoints, nCount, GdiDpToLp);
 }
 
-
 BOOL
 WINAPI
-LPtoDP ( HDC hDC, LPPOINT Points, INT Count )
+LPtoDP(HDC hdc, LPPOINT lpPoints, INT nCount)
 {
 #if 0
     INT i;
-    PDC_ATTR Dc_Attr;
+    PDC_ATTR pdcattr;
 
-    if (!GdiGetHandleUserData((HGDIOBJ) hDC, GDI_OBJECT_TYPE_DC, (PVOID) &Dc_Attr)) return FALSE;
+    pdcattr = GdiGetDcAttr(hdc);
+    if (!pdcattr)
+    {
+        SetLastError(ERROR_INVALID_HANDLE);
+        return FALSE;
+    }
 
-    if (Dc_Attr->flXform & ( PAGE_XLATE_CHANGED   |  // Check for Changes and Updates
-                             PAGE_EXTENTS_CHANGED |
-                             WORLD_XFORM_CHANGED ))
-#endif
-        return NtGdiTransformPoints( hDC, Points, Points, Count, GdiLpToDp); // LPtoDP mode
-#if 0
-    else
+    if (pdcattr->flXform & ANY_XFORM_CHANGES)
     {
-        for ( i = 0; i < Count; i++ )
-            CoordCnvP ( &Dc_Attr->mxWorldToDevice, &Points[i] );
+        GdiFixupTransforms(pdcattr);
     }
+
+    // FIXME: can this fail on Windows?
+    GdiTransformPoints(&pdcattr->mxWorldToDevice, lpPoints, lpPoints, nCount);
+
     return TRUE;
 #endif
+    return NtGdiTransformPoints(hdc, lpPoints, lpPoints, nCount, GdiLpToDp);
 }
 
 /*
@@ -185,9 +195,26 @@ GetCurrentPositionEx(HDC hdc,
  */
 BOOL
 WINAPI
-GetWorldTransform( HDC hDC, LPXFORM lpXform )
+GetWorldTransform(HDC hDC, LPXFORM lpXform)
 {
-    return NtGdiGetTransform( hDC, GdiWorldSpaceToPageSpace, lpXform);
+#if 0
+    PDC_ATTR pdcattr;
+
+    pdcattr = GdiGetDcAttr(hdc);
+    if (!pdcattr)
+    {
+        SetLastError(ERROR_INVALID_HANDLE);
+        return FALSE;
+    }
+
+    if (pdcattr->flXform & ANY_XFORM_INVALID)
+    {
+        GdiFixupTransforms(pdcattr);
+    }
+
+    MatrixToXForm(lpXform, &pdcattr->mxWorldToDevice);
+#endif
+    return NtGdiGetTransform(hDC, GdiWorldSpaceToPageSpace, lpXform);
 }