Fixes for the isotropic mapping mode (improved)

Michael Kaufmann hallo at michael-kaufmann.ch
Wed Jan 25 16:14:21 CST 2006


Changelog:
- Isotropic mapping mode: Adjust the viewport extension in 
SetWindowExtEx, handle negative extents
- Support the isotropic mapping mode in the enhanced metafile driver
- New tests
-------------- next part --------------
Index: dlls/gdi/enhmetafile.c
===================================================================
RCS file: /home/wine/wine/dlls/gdi/enhmetafile.c,v
retrieving revision 1.17
diff -u -r1.17 enhmetafile.c
--- dlls/gdi/enhmetafile.c	5 Nov 2005 10:45:02 -0000	1.17
+++ dlls/gdi/enhmetafile.c	25 Jan 2006 22:01:48 -0000
@@ -595,6 +595,33 @@
     }
 }
 
+/***********************************************************************
+ *           EMF_FixIsotropic
+ *
+ * Fix viewport extensions for isotropic mode.
+ */
+
+static void EMF_FixIsotropic(HDC hdc, enum_emh_data *info)
+{
+    double xdim = fabs((double)info->vportExtX * GetDeviceCaps( hdc, HORZSIZE ) /
+                  (GetDeviceCaps( hdc, HORZRES ) * info->wndExtX));
+    double ydim = fabs((double)info->vportExtY * GetDeviceCaps( hdc, VERTSIZE ) /
+                  (GetDeviceCaps( hdc, VERTRES ) * info->wndExtY));
+
+    if (xdim > ydim)
+    {
+        INT mincx = (info->vportExtX >= 0) ? 1 : -1;
+        info->vportExtX = floor(info->vportExtX * ydim / xdim + 0.5);
+        if (!info->vportExtX) info->vportExtX = mincx;
+    }
+    else
+    {
+        INT mincy = (info->vportExtY >= 0) ? 1 : -1;
+        info->vportExtY = floor(info->vportExtY * xdim / ydim + 0.5);
+        if (!info->vportExtY) info->vportExtY = mincy;
+    }
+}
+
 /*****************************************************************************
  *       emr_produces_output
  *
@@ -829,6 +856,8 @@
 	    break;
         info->wndExtX = pSetWindowExtEx->szlExtent.cx;
         info->wndExtY = pSetWindowExtEx->szlExtent.cy;
+        if (info->mode == MM_ISOTROPIC)
+            EMF_FixIsotropic(hdc, info);
 
         TRACE("SetWindowExtEx: %d,%d\n",info->wndExtX,info->wndExtY);
 	break;
@@ -852,6 +881,8 @@
 	    break;
         info->vportExtX = pSetViewportExtEx->szlExtent.cx;
         info->vportExtY = pSetViewportExtEx->szlExtent.cy;
+        if (info->mode == MM_ISOTROPIC)
+            EMF_FixIsotropic(hdc, info);
         TRACE("SetViewportExtEx: %d,%d\n",info->vportExtX,info->vportExtY);
 	break;
       }
@@ -1316,8 +1347,7 @@
         if (info->vportExtX == 0) info->vportExtX = 1;
         if (info->vportExtY == 0) info->vportExtY = 1;
         if (info->mode == MM_ISOTROPIC)
-            FIXME("EMRSCALEVIEWPORTEXTEX MM_ISOTROPIC mapping\n");
-            /* MAPPING_FixIsotropic( dc ); */
+            EMF_FixIsotropic(hdc, info);
 
         TRACE("EMRSCALEVIEWPORTEXTEX %ld/%ld %ld/%ld\n",
              lpScaleViewportExtEx->xNum,lpScaleViewportExtEx->xDenom,
@@ -1342,8 +1372,7 @@
         if (info->wndExtX == 0) info->wndExtX = 1;
         if (info->wndExtY == 0) info->wndExtY = 1;
         if (info->mode == MM_ISOTROPIC)
-            FIXME("EMRSCALEWINDOWEXTEX MM_ISOTROPIC mapping\n");
-            /* MAPPING_FixIsotropic( dc ); */
+            EMF_FixIsotropic(hdc, info);
 
         TRACE("EMRSCALEWINDOWEXTEX %ld/%ld %ld/%ld\n",
              lpScaleWindowExtEx->xNum,lpScaleWindowExtEx->xDenom,
Index: dlls/gdi/mapping.c
===================================================================
RCS file: /home/wine/wine/dlls/gdi/mapping.c,v
retrieving revision 1.1
diff -u -r1.1 mapping.c
--- dlls/gdi/mapping.c	12 Feb 2004 23:11:30 -0000	1.1
+++ dlls/gdi/mapping.c	25 Jan 2006 22:01:50 -0000
@@ -33,19 +33,22 @@
  */
 void MAPPING_FixIsotropic( DC * dc )
 {
-    double xdim = (double)dc->vportExtX * GetDeviceCaps( dc->hSelf, HORZSIZE ) /
-                  (GetDeviceCaps( dc->hSelf, HORZRES ) * dc->wndExtX);
-    double ydim = (double)dc->vportExtY * GetDeviceCaps( dc->hSelf, VERTSIZE ) /
-                  (GetDeviceCaps( dc->hSelf, VERTRES ) * dc->wndExtY);
+    double xdim = fabs((double)dc->vportExtX * GetDeviceCaps( dc->hSelf, HORZSIZE ) /
+                  (GetDeviceCaps( dc->hSelf, HORZRES ) * dc->wndExtX));
+    double ydim = fabs((double)dc->vportExtY * GetDeviceCaps( dc->hSelf, VERTSIZE ) /
+                  (GetDeviceCaps( dc->hSelf, VERTRES ) * dc->wndExtY));
+
     if (xdim > ydim)
     {
-	dc->vportExtX = floor(dc->vportExtX * fabs( ydim / xdim ) + 0.5);
-	if (!dc->vportExtX) dc->vportExtX = 1;
+        INT mincx = (dc->vportExtX >= 0) ? 1 : -1;
+        dc->vportExtX = floor(dc->vportExtX * ydim / xdim + 0.5);
+        if (!dc->vportExtX) dc->vportExtX = mincx;
     }
     else
     {
-	dc->vportExtY = floor(dc->vportExtY * fabs( xdim / ydim ) + 0.5);
-	if (!dc->vportExtY) dc->vportExtY = 1;
+        INT mincy = (dc->vportExtY >= 0) ? 1 : -1;
+        dc->vportExtY = floor(dc->vportExtY * xdim / ydim + 0.5);
+        if (!dc->vportExtY) dc->vportExtY = mincy;
     }
 }
 
@@ -326,7 +329,10 @@
     }
     dc->wndExtX = x;
     dc->wndExtY = y;
-    /* Windows fixes MM_ISOTROPIC mode only in SetViewportExtEx() */
+    /* The API docs say that you should call SetWindowExtEx before
+       SetViewportExtEx. This advice does not imply that Windows
+       doesn't ensure the isotropic mapping after SetWindowExtEx! */
+    if (dc->MapMode == MM_ISOTROPIC) MAPPING_FixIsotropic( dc );
     DC_UpdateXforms( dc );
  done:
     GDI_ReleaseObj( hdc );
Index: dlls/gdi/tests/mapping.c
===================================================================
RCS file: /home/wine/wine/dlls/gdi/tests/mapping.c,v
retrieving revision 1.1
diff -u -r1.1 mapping.c
--- dlls/gdi/tests/mapping.c	28 Oct 2005 16:41:25 -0000	1.1
+++ dlls/gdi/tests/mapping.c	25 Jan 2006 22:02:01 -0000
@@ -53,7 +53,108 @@
     ReleaseDC(0, hdc);
 }
 
+void test_SetWindowExt(HDC hdc, LONG cx, LONG cy, LONG expected_vp_cx, LONG expected_vp_cy)
+{
+    SIZE windowExt, viewportExt;
+    POINT windowOrg, windowOrgAfter, viewportOrg, viewportOrgAfter;
+
+    GetWindowOrgEx(hdc, &windowOrg);
+    GetViewportOrgEx(hdc, &viewportOrg);
+
+    SetWindowExtEx(hdc, cx, cy, NULL);
+    GetWindowExtEx(hdc, &windowExt);
+    ok(windowExt.cx == cx && windowExt.cy == cy,
+       "Window extension: Expected %ldx%ld, got %ldx%ld\n",
+       cx, cy, windowExt.cx, windowExt.cy);
+
+    GetViewportExtEx(hdc, &viewportExt);
+    ok(viewportExt.cx == expected_vp_cx && viewportExt.cy == expected_vp_cy,
+        "Viewport extents have not been properly adjusted: Expected %ldx%ld, got %ldx%ld\n",
+        expected_vp_cx, expected_vp_cy, viewportExt.cx, viewportExt.cy);
+
+    GetWindowOrgEx(hdc, &windowOrgAfter);
+    ok(windowOrg.x == windowOrgAfter.x && windowOrg.y == windowOrgAfter.y,
+        "Window origin changed from (%ld,%ld) to (%ld,%ld)\n",
+        windowOrg.x, windowOrg.y, windowOrgAfter.x, windowOrgAfter.y);
+
+    GetViewportOrgEx(hdc, &viewportOrgAfter);
+    ok(viewportOrg.x == viewportOrgAfter.x && viewportOrg.y == viewportOrgAfter.y,
+        "Viewport origin changed from (%ld,%ld) to (%ld,%ld)\n",
+        viewportOrg.x, viewportOrg.y, viewportOrgAfter.x, viewportOrgAfter.y);
+}
+
+void test_SetViewportExt(HDC hdc, LONG cx, LONG cy, LONG expected_vp_cx, LONG expected_vp_cy)
+{
+    SIZE windowExt, windowExtAfter, viewportExt;
+    POINT windowOrg, windowOrgAfter, viewportOrg, viewportOrgAfter;
+
+    GetWindowOrgEx(hdc, &windowOrg);
+    GetViewportOrgEx(hdc, &viewportOrg);
+    GetWindowExtEx(hdc, &windowExt);
+
+    SetViewportExtEx(hdc, cx, cy, NULL);
+    GetViewportExtEx(hdc, &viewportExt);
+    ok(viewportExt.cx == expected_vp_cx && viewportExt.cy == expected_vp_cy,
+        "Viewport extents have not been properly adjusted: Expected %ldx%ld, got %ldx%ld\n",
+        expected_vp_cx, expected_vp_cy, viewportExt.cx, viewportExt.cy);
+
+    GetWindowExtEx(hdc, &windowExtAfter);
+    ok(windowExt.cx == windowExtAfter.cx && windowExt.cy == windowExtAfter.cy,
+       "Window extension changed from %ldx%ld to %ldx%ld\n",
+       windowExt.cx, windowExt.cy, windowExtAfter.cx, windowExtAfter.cy);
+
+    GetWindowOrgEx(hdc, &windowOrgAfter);
+    ok(windowOrg.x == windowOrgAfter.x && windowOrg.y == windowOrgAfter.y,
+        "Window origin changed from (%ld,%ld) to (%ld,%ld)\n",
+        windowOrg.x, windowOrg.y, windowOrgAfter.x, windowOrgAfter.y);
+
+    GetViewportOrgEx(hdc, &viewportOrgAfter);
+    ok(viewportOrg.x == viewportOrgAfter.x && viewportOrg.y == viewportOrgAfter.y,
+        "Viewport origin changed from (%ld,%ld) to (%ld,%ld)\n",
+        viewportOrg.x, viewportOrg.y, viewportOrgAfter.x, viewportOrgAfter.y);
+}
+
+void test_isotropic_mapping(void)
+{
+    SIZE win, vp;
+    HDC hdc = GetDC(0);
+    
+    SetMapMode(hdc, MM_ISOTROPIC);
+    
+    /* MM_ISOTROPIC is set up like MM_LOMETRIC.
+       Initial values after SetMapMode():
+       (1 inch = 25.4 mm)
+       
+                       Windows 9x:               Windows NT:
+       Window Ext:     254 x -254                HORZSIZE*10 x VERTSIZE*10
+       Viewport Ext:   LOGPIXELSX x LOGPIXELSY   HORZRES x -VERTRES
+       
+       To test without rounding errors, we have to use multiples of
+       these values!
+     */
+    
+    GetWindowExtEx(hdc, &win);
+    GetViewportExtEx(hdc, &vp);
+    
+    test_SetViewportExt(hdc, 10 * vp.cx, 10 * vp.cy, 10 * vp.cx, 10 * vp.cy);
+    test_SetWindowExt(hdc, win.cx, win.cy, 10 * vp.cx, 10 * vp.cy);
+    test_SetWindowExt(hdc, 2 * win.cx, win.cy, 10 * vp.cx, 5 * vp.cy);
+    test_SetWindowExt(hdc, win.cx, win.cy, 5 * vp.cx, 5 * vp.cy);
+    test_SetViewportExt(hdc, 4 * vp.cx, 2 * vp.cy, 2 * vp.cx, 2 * vp.cy);
+    test_SetViewportExt(hdc, vp.cx, 2 * vp.cy, vp.cx, vp.cy);
+    test_SetViewportExt(hdc, 2 * vp.cx, 2 * vp.cy, 2 * vp.cx, 2 * vp.cy);
+    test_SetViewportExt(hdc, 4 * vp.cx, 2 * vp.cy, 2 * vp.cx, 2 * vp.cy);
+    test_SetWindowExt(hdc, 4 * win.cx, 2 * win.cy, 2 * vp.cx, vp.cy);
+    test_SetViewportExt(hdc, -2 * vp.cx, -4 * vp.cy, -2 * vp.cx, -vp.cy);
+    test_SetViewportExt(hdc, -2 * vp.cx, -1 * vp.cy, -2 * vp.cx, -vp.cy);    
+    test_SetWindowExt(hdc, -4 * win.cx, -2 * win.cy, -2 * vp.cx, -vp.cy);
+    test_SetWindowExt(hdc, 4 * win.cx, -4 * win.cy, -vp.cx, -vp.cy);
+    
+    ReleaseDC(0, hdc);
+}
+
 START_TEST(mapping)
 {
     test_modify_world_transform();
+    test_isotropic_mapping();
 }


More information about the wine-patches mailing list