[1/3] gdi32: fix for rotated Arc, ArcTo, Chord and Pie drawing, problem

Ralf Habacker ralf.habacker at freenet.de
Thu Jan 9 06:32:01 CST 2014


>From 07868ea6b93ff709f7629355fd66d6d8e91af8fd Mon Sep 17 00:00:00 2001
From: Daniel Wendt <daniel.wendt at linux.com>
Date: Fri, 15 Nov 2013 12:52:37 +0100
Subject: [1/3] gdi32: fix for rotated Arc, ArcTo, Chord and Pie drawing
 problem

Bug: http://bugs.winehq.org/show_bug.cgi?id=34579
---
 dlls/gdi32/dibdrv/graphics.c | 80
++++++++++++++++++++++++++++++++++++++++++++
 dlls/gdi32/gdi_private.h     |  3 ++
 2 files changed, 83 insertions(+)

diff --git a/dlls/gdi32/dibdrv/graphics.c b/dlls/gdi32/dibdrv/graphics.c
index 2c865c0..bc4f096 100644
--- a/dlls/gdi32/dibdrv/graphics.c
+++ b/dlls/gdi32/dibdrv/graphics.c
@@ -311,6 +311,60 @@ static int get_arc_points( PHYSDEV dev, const RECT
*rect, POINT start, POINT end
     return pos - count;
 }
 
+/*
+ Check if matrix has uniform scale and shear and contains a rotation.
+*/
+BOOL xform_has_rotate_and_uniform_scale_and_shear( const XFORM *xform )
+{
+    return xform->eM21 != 0 && xform->eM11 == xform->eM22 &&
-xform->eM21 == xform->eM12;
+}
+
+/*
+ Decompose rotation and translation from matrix xform.
+
+ If parameter rotation_and_translation is != NULL, save rotation and
translation into it.
+
+ Note: The current implementation only works on matrixes with uniform
scale and shear,
+       which has to be checked by a call to
xform_has_rotate_and_uniform_scale_and_shear().
+       Hints how to get *unique* values for non-uniform matrixes are
welcome.
+*/
+BOOL xform_decompose_rotation_and_translation( XFORM *xform, XFORM
*rotation_and_translation )
+{
+    XFORM inverse_matrix_scale;
+    XFORM origin_matrix = *xform;
+    double determinant = 0;
+
+    /* xform = xfrom-transposed * xform */
+    xform->eM11 = sqrt( xform->eM11 * xform->eM11 + xform->eM21 *
xform->eM21 );
+    xform->eM22 = sqrt( xform->eM12 * xform->eM12 + xform->eM22 *
xform->eM22 );
+    xform->eM12 = 0;
+    xform->eM21 = 0;
+    xform->eDx = 0;
+    xform->eDy = 0;
+
+    if ( rotation_and_translation == NULL )
+        return TRUE;
+
+    if ( xform->eM11 == 0 || xform->eM22 == 0 )
+        return FALSE;
+
+    determinant = xform->eM11 * xform->eM22;
+
+    inverse_matrix_scale.eM11 = xform->eM22 / determinant;
+    inverse_matrix_scale.eM12 = 0;
+    inverse_matrix_scale.eM21 = 0;
+    inverse_matrix_scale.eM22 = xform->eM11 / determinant;
+
+    /* calculate the rotation matrix */
+    rotation_and_translation->eM11 = inverse_matrix_scale.eM11 *
origin_matrix.eM11;
+    rotation_and_translation->eM12 = inverse_matrix_scale.eM11 *
origin_matrix.eM12;
+    rotation_and_translation->eM21 = inverse_matrix_scale.eM22 *
origin_matrix.eM12 * -1;
+    rotation_and_translation->eM22 = inverse_matrix_scale.eM22 *
origin_matrix.eM22;
+    rotation_and_translation->eDx = origin_matrix.eDx;
+    rotation_and_translation->eDy = origin_matrix.eDy;
+    return TRUE;
+}
+
 /* backend for arc functions; extra_lines is -1 for ArcTo, 0 for Arc, 1
for Chord, 2 for Pie */
 static BOOL draw_arc( PHYSDEV dev, INT left, INT top, INT right, INT
bottom,
                       INT start_x, INT start_y, INT end_x, INT end_y,
INT extra_lines )
@@ -322,6 +376,22 @@ static BOOL draw_arc( PHYSDEV dev, INT left, INT
top, INT right, INT bottom,
     BOOL ret = TRUE;
     HRGN outline = 0, interior = 0;
 
+    BOOL exclude_rotation = FALSE;
+    XFORM old;
+    XFORM rotation_and_translation;
+    if (GetGraphicsMode( pdev->dev.hdc ) == GM_ADVANCED)
+    {
+        XFORM xf;
+        GetWorldTransform( pdev->dev.hdc, &old );
+        xf = old;
+        if (xform_has_rotate_and_uniform_scale_and_shear( &xf ) &&
+            xform_decompose_rotation_and_translation( &xf,
&rotation_and_translation ))
+        {
+            SetWorldTransform( pdev->dev.hdc, &xf );
+            exclude_rotation = TRUE;
+        }
+    }
+
     if (!get_pen_device_rect( pdev, &rect, left, top, right, bottom ))
return TRUE;
 
     width = rect.right - rect.left;
@@ -355,6 +425,16 @@ static BOOL draw_arc( PHYSDEV dev, INT left, INT
top, INT right, INT bottom,
         points[count].y = rect.top + height / 2;
         count++;
     }
+
+    if (exclude_rotation == TRUE)
+    {
+        SetWorldTransform( pdev->dev.hdc, &rotation_and_translation );
+        /* apply rotation and translation to calculated points */
+        LPtoDP( dev->hdc, points, count );
+        /* restore origin matrix */
+        SetWorldTransform( pdev->dev.hdc, &old );
+    }
+
     if (count < 2)
     {
         HeapFree( GetProcessHeap(), 0, points );
diff --git a/dlls/gdi32/gdi_private.h b/dlls/gdi32/gdi_private.h
index 430e652..a3666c4 100644
--- a/dlls/gdi32/gdi_private.h
+++ b/dlls/gdi32/gdi_private.h
@@ -525,4 +525,7 @@ extern void free_heap_bits( struct gdi_image_bits
*bits ) DECLSPEC_HIDDEN;
 
 extern HMODULE gdi32_module DECLSPEC_HIDDEN;
 
+BOOL xform_has_rotate_and_uniform_scale_and_shear( const XFORM *xform );
+BOOL xform_decompose_rotation_and_translation( XFORM *xform, XFORM
*rotation_and_translation );
+
 #endif /* __WINE_GDI_PRIVATE_H */
-- 
1.8.4




More information about the wine-patches mailing list