Piotr Caban : gdiplus: Add more accurate algorithm for inverting scaling and translation matrices in GdipInvertMatrix.

Alexandre Julliard julliard at winehq.org
Sat Aug 12 07:19:31 CDT 2017


Module: wine
Branch: master
Commit: 595959c771691b46ea8521c3af37f7306a383068
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=595959c771691b46ea8521c3af37f7306a383068

Author: Piotr Caban <piotr at codeweavers.com>
Date:   Tue Aug  8 20:48:27 2017 +0200

gdiplus: Add more accurate algorithm for inverting scaling and translation matrices in GdipInvertMatrix.

Signed-off-by: Piotr Caban <piotr at codeweavers.com>
Signed-off-by: Vincent Povirk <vincent at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/gdiplus/matrix.c       | 16 +++++++++++++++-
 dlls/gdiplus/tests/matrix.c | 30 ++++++++++++++++++++++++++++++
 2 files changed, 45 insertions(+), 1 deletion(-)

diff --git a/dlls/gdiplus/matrix.c b/dlls/gdiplus/matrix.c
index 3cd8d82..2219d46 100644
--- a/dlls/gdiplus/matrix.c
+++ b/dlls/gdiplus/matrix.c
@@ -197,6 +197,17 @@ GpStatus WINGDIPAPI GdipInvertMatrix(GpMatrix *matrix)
     if(!invertible)
         return InvalidParameter;
 
+    /* optimize inverting simple scaling and translation matrices */
+    if(matrix->matrix[1] == 0 && matrix->matrix[2] == 0)
+    {
+        matrix->matrix[4] = -matrix->matrix[4] / matrix->matrix[0];
+        matrix->matrix[5] = -matrix->matrix[5] / matrix->matrix[3];
+        matrix->matrix[0] = 1 / matrix->matrix[0];
+        matrix->matrix[3] = 1 / matrix->matrix[3];
+
+        return Ok;
+    }
+
     det = matrix_det(matrix);
 
     copy = *matrix;
@@ -218,7 +229,10 @@ GpStatus WINGDIPAPI GdipIsMatrixInvertible(GDIPCONST GpMatrix *matrix, BOOL *res
     if(!matrix || !result)
         return InvalidParameter;
 
-    *result = (fabs(matrix_det(matrix)) >= 1e-5);
+    if(matrix->matrix[1] == 0 && matrix->matrix[2] == 0)
+        *result = matrix->matrix[0] != 0 && matrix->matrix[3] != 0;
+    else
+        *result = (fabs(matrix_det(matrix)) >= 1e-5);
 
     return Ok;
 }
diff --git a/dlls/gdiplus/tests/matrix.c b/dlls/gdiplus/tests/matrix.c
index 1e4f48d..3e655ce 100644
--- a/dlls/gdiplus/tests/matrix.c
+++ b/dlls/gdiplus/tests/matrix.c
@@ -19,6 +19,7 @@
  */
 
 #include <math.h>
+#include <limits.h>
 
 #include "objbase.h"
 #include "gdiplus.h"
@@ -27,6 +28,22 @@
 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
 #define expectf(expected, got) ok(fabs(expected - got) < 0.0001, "Expected %.2f, got %.2f\n", expected, got)
 
+static BOOL compare_float(float f, float g, unsigned int ulps)
+{
+    int x = *(int *)&f;
+    int y = *(int *)&g;
+
+    if (x < 0)
+        x = INT_MIN - x;
+    if (y < 0)
+        y = INT_MIN - y;
+
+    if (abs(x - y) > ulps)
+        return FALSE;
+
+    return TRUE;
+}
+
 static void test_constructor_destructor(void)
 {
     GpStatus status;
@@ -128,6 +145,7 @@ static void test_invert(void)
     GpMatrix *matrix = NULL;
     GpMatrix *inverted = NULL;
     BOOL equal = FALSE;
+    REAL elems[6];
 
     /* NULL */
     status = GdipInvertMatrix(NULL);
@@ -147,6 +165,18 @@ static void test_invert(void)
     GdipIsMatrixEqual(matrix, inverted, &equal);
     expect(TRUE, equal);
 
+    GdipCreateMatrix2(0.0006, 0, 0, 0.0006, 400, 400, &matrix);
+    status = GdipInvertMatrix(matrix);
+    expect(Ok, status);
+    status = GdipGetMatrixElements(matrix, elems);
+    expect(Ok, status);
+    ok(compare_float(elems[0], 1666.666504, 1), "elems[0] = %.10g\n", elems[0]);
+    ok(compare_float(elems[1], 0, 0), "elems[1] = %.10g\n", elems[1]);
+    ok(compare_float(elems[2], 0, 0), "elems[2] = %.10g\n", elems[2]);
+    ok(compare_float(elems[3], 1666.666504, 1), "elems[3] = %.10g\n", elems[3]);
+    ok(compare_float(elems[4], -666666.6875, 1), "elems[4] = %.10g\n", elems[4]);
+    ok(compare_float(elems[5], -666666.6875, 1), "elems[5] = %.10g\n", elems[5]);
+
     GdipDeleteMatrix(inverted);
     GdipDeleteMatrix(matrix);
 }




More information about the wine-cvs mailing list