]> git.saurik.com Git - wxWidgets.git/commitdiff
Avoid rounding errors in wxMSW wxDC scaling code.
authorVadim Zeitlin <vadim@wxwidgets.org>
Tue, 26 Apr 2011 22:57:42 +0000 (22:57 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Tue, 26 Apr 2011 22:57:42 +0000 (22:57 +0000)
Multiply by scale factor when it's > 1 and divide by it when it's < 1 to avoid
rounding errors. By choosing whether to increase the viewport or window
extents we increase precisions without any apparent negative effects (at least
under Windows NT where the coordinates in 2^27 range are supported, but even
under Windows 9x it's not clear if the old code was better as while we never
overflowed the viewport extents, we could overflow the window ones easily for
small zoom factors).

Closes #9554.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@67623 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

src/msw/dc.cpp

index 5079795653467c33fff3bb3246dde2d7e290cf1d..17ffaae9bf7d76020b7b1a5d02903059b231a532 100644 (file)
@@ -1967,11 +1967,39 @@ void wxMSWDCImpl::RealizeScaleAndOrigin()
 #ifndef __WXWINCE__
     ::SetMapMode(GetHdc(), MM_ANISOTROPIC);
 
-    int width = DeviceToLogicalXRel(VIEWPORT_EXTENT)*m_signX,
-        height = DeviceToLogicalYRel(VIEWPORT_EXTENT)*m_signY;
+    // wxWidgets API assumes that the coordinate space is "infinite" (i.e. only
+    // limited by 2^32 range of the integer coordinates) but in MSW API we must
+    // actually specify the extents that we use. So we more or less arbitrarily
+    // decide to use "base" VIEWPORT_EXTENT and adjust it depending on scale.
+    //
+    // To avoid rounding errors we prefer to multiply by the scale if it's > 1
+    // and to divide by it if it's < 1.
+    int devExtX, devExtY,   // Viewport, i.e. device space, extents.
+        logExtX, logExtY;   // Window, i.e. logical coordinate space, extents.
+    if ( m_scaleX >= 1 )
+    {
+        devExtX = VIEWPORT_EXTENT*m_scaleX;
+        logExtX = m_signX*VIEWPORT_EXTENT;
+    }
+    else
+    {
+        devExtX = VIEWPORT_EXTENT;
+        logExtX = m_signX*VIEWPORT_EXTENT/m_scaleX;
+    }
+
+    if ( m_scaleY >= 1 )
+    {
+        devExtY = VIEWPORT_EXTENT*m_scaleY;
+        logExtY = m_signY*VIEWPORT_EXTENT;
+    }
+    else
+    {
+        devExtY = VIEWPORT_EXTENT;
+        logExtY = m_signY*VIEWPORT_EXTENT/m_scaleY;
+    }
 
-    ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT, VIEWPORT_EXTENT, NULL);
-    ::SetWindowExtEx(GetHdc(), width, height, NULL);
+    ::SetViewportExtEx(GetHdc(), devExtX, devExtY, NULL);
+    ::SetWindowExtEx(GetHdc(), logExtX, logExtY, NULL);
 
     ::SetViewportOrgEx(GetHdc(), m_deviceOriginX, m_deviceOriginY, NULL);
     ::SetWindowOrgEx(GetHdc(), m_logicalOriginX, m_logicalOriginY, NULL);