diff --git a/dlls/gdiplus/matrix.c b/dlls/gdiplus/matrix.c index 3cd8d8287e5..2219d463694 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 1e4f48d8861..3e655cec8ed 100644 --- a/dlls/gdiplus/tests/matrix.c +++ b/dlls/gdiplus/tests/matrix.c @@ -19,6 +19,7 @@ */ #include +#include #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); }