8076545: Text size is twice bigger under Windows L&F on Win 8.1 with HiDPI display
authoralexsch
Tue, 15 Mar 2016 09:16:56 -0700
changeset 36884 1d4e53737869
parent 36883 0256b6d86efb
child 36885 75de89bc3d0d
8076545: Text size is twice bigger under Windows L&F on Win 8.1 with HiDPI display 8149453: [hidpi] JFileChooser does not scale properly on Windows with HiDPI display and Windows L&F 8149368: [hidpi] JLabel font is twice bigger than JTextArea font on Windows 7,HiDPI, Windows L&F Reviewed-by: flar, serb
jdk/src/java.desktop/windows/native/libawt/windows/ThemeReader.cpp
jdk/src/java.desktop/windows/native/libawt/windows/awt_DesktopProperties.cpp
jdk/src/java.desktop/windows/native/libawt/windows/awt_DesktopProperties.h
jdk/test/java/awt/font/FontScaling/FontScalingTest.java
--- a/jdk/src/java.desktop/windows/native/libawt/windows/ThemeReader.cpp	Tue Mar 15 09:22:48 2016 +0300
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/ThemeReader.cpp	Tue Mar 15 09:16:56 2016 -0700
@@ -31,6 +31,8 @@
 #include "awt_Object.h"
 #include "awt_Component.h"
 
+#include "math.h"
+
 // Important note about VC6 and VC7 (or XP Platform SDK)   !
 //
 // These type definitions have been imported from UxTheme.h
@@ -745,6 +747,23 @@
     return NULL;
 }
 
+void rescale(SIZE *size) {
+    HWND hWnd = ::GetDesktopWindow();
+    HDC hDC = ::GetDC(hWnd);
+    int dpiX = ::GetDeviceCaps(hDC, LOGPIXELSX);
+    int dpiY = ::GetDeviceCaps(hDC, LOGPIXELSY);
+
+    if (dpiX !=0 && dpiX != 96) {
+        float invScaleX = 96.0f / dpiX;
+        size->cx = (int)round(size->cx * invScaleX);
+    }
+    if (dpiY != 0 && dpiY != 96) {
+        float invScaleY = 96.0f / dpiY;
+        size->cy = (int)round(size->cy * invScaleY);
+    }
+    ::ReleaseDC(hWnd, hDC);
+}
+
 /*
  * Class:     sun_awt_windows_ThemeReader
  * Method:    getPartSize
@@ -770,6 +789,8 @@
                 dimMID = env->GetMethodID(dimClassID, "<init>", "(II)V");
                 CHECK_NULL_RETURN(dimMID, NULL);
             }
+
+            rescale(&size);
             jobject dimObj = env->NewObject(dimClassID, dimMID, size.cx, size.cy);
             if (safe_ExceptionOccurred(env)) {
                 env->ExceptionDescribe();
--- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_DesktopProperties.cpp	Tue Mar 15 09:22:48 2016 +0300
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_DesktopProperties.cpp	Tue Mar 15 09:16:56 2016 -0700
@@ -35,6 +35,8 @@
 #include <shellapi.h>
 #include <shlobj.h>
 
+#include "math.h"
+
 // WDesktopProperties fields
 jfieldID AwtDesktopProperties::pDataID = 0;
 jmethodID AwtDesktopProperties::setBooleanPropertyID = 0;
@@ -79,18 +81,35 @@
     }
 }
 
+void getInvScale(float &invScaleX, float &invScaleY) {
+    HWND hWnd = ::GetDesktopWindow();
+    HDC hDC = ::GetDC(hWnd);
+    int dpiX = ::GetDeviceCaps(hDC, LOGPIXELSX);
+    int dpiY = ::GetDeviceCaps(hDC, LOGPIXELSY);
+    ::ReleaseDC(hWnd, hDC);
+    invScaleX = (dpiX == 0.0f) ? 1.0f : 96.0f / dpiX;
+    invScaleY = (dpiY == 0.0f) ? 1.0f : 96.0f / dpiY;
+}
+
+int rescale(int value, float invScale){
+    return invScale == 1.0f ? value : (int)round(value * invScale);
+}
+
 void AwtDesktopProperties::GetSystemProperties() {
     HDC dc = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
 
     if (dc != NULL) {
         try {
-            SetFontProperty(dc, ANSI_FIXED_FONT, TEXT("win.ansiFixed.font"));
-            SetFontProperty(dc, ANSI_VAR_FONT, TEXT("win.ansiVar.font"));
-            SetFontProperty(dc, DEVICE_DEFAULT_FONT, TEXT("win.deviceDefault.font"));
-            SetFontProperty(dc, DEFAULT_GUI_FONT, TEXT("win.defaultGUI.font"));
-            SetFontProperty(dc, OEM_FIXED_FONT, TEXT("win.oemFixed.font"));
-            SetFontProperty(dc, SYSTEM_FONT, TEXT("win.system.font"));
-            SetFontProperty(dc, SYSTEM_FIXED_FONT, TEXT("win.systemFixed.font"));
+            float invScaleX;
+            float invScaleY;
+            getInvScale(invScaleX, invScaleY);
+            SetFontProperty(dc, ANSI_FIXED_FONT, TEXT("win.ansiFixed.font"), 1.0f);
+            SetFontProperty(dc, ANSI_VAR_FONT, TEXT("win.ansiVar.font"), 1.0f);
+            SetFontProperty(dc, DEVICE_DEFAULT_FONT, TEXT("win.deviceDefault.font"), 1.0f);
+            SetFontProperty(dc, DEFAULT_GUI_FONT, TEXT("win.defaultGUI.font"), invScaleY);
+            SetFontProperty(dc, OEM_FIXED_FONT, TEXT("win.oemFixed.font"), 1.0f);
+            SetFontProperty(dc, SYSTEM_FONT, TEXT("win.system.font"), 1.0f);
+            SetFontProperty(dc, SYSTEM_FIXED_FONT, TEXT("win.systemFixed.font"), 1.0f);
         }
         catch (std::bad_alloc&) {
             DeleteDC(dc);
@@ -266,31 +285,35 @@
     }
     VERIFY( SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncmetrics.cbSize, &ncmetrics, FALSE) );
 
-    SetFontProperty( TEXT("win.frame.captionFont"), ncmetrics.lfCaptionFont );
-    SetIntegerProperty( TEXT("win.frame.captionHeight"), ncmetrics.iCaptionHeight );
-    SetIntegerProperty( TEXT("win.frame.captionButtonWidth"), ncmetrics.iCaptionWidth );
-    SetIntegerProperty( TEXT("win.frame.captionButtonHeight"), ncmetrics.iCaptionHeight );
-    SetFontProperty( TEXT("win.frame.smallCaptionFont"), ncmetrics.lfSmCaptionFont );
-    SetIntegerProperty( TEXT("win.frame.smallCaptionHeight"), ncmetrics.iSmCaptionHeight );
-    SetIntegerProperty( TEXT("win.frame.smallCaptionButtonWidth"), ncmetrics.iSmCaptionWidth );
-    SetIntegerProperty( TEXT("win.frame.smallCaptionButtonHeight"), ncmetrics.iSmCaptionHeight );
-    SetIntegerProperty( TEXT("win.frame.sizingBorderWidth"), ncmetrics.iBorderWidth );
+    float invScaleX;
+    float invScaleY;
+    getInvScale(invScaleX, invScaleY);
+
+    SetFontProperty(TEXT("win.frame.captionFont"), ncmetrics.lfCaptionFont, invScaleY);
+    SetIntegerProperty(TEXT("win.frame.captionHeight"), rescale(ncmetrics.iCaptionHeight, invScaleY));
+    SetIntegerProperty(TEXT("win.frame.captionButtonWidth"), rescale(ncmetrics.iCaptionWidth, invScaleX));
+    SetIntegerProperty(TEXT("win.frame.captionButtonHeight"), rescale(ncmetrics.iCaptionHeight, invScaleY));
+    SetFontProperty(TEXT("win.frame.smallCaptionFont"), ncmetrics.lfSmCaptionFont, invScaleY);
+    SetIntegerProperty(TEXT("win.frame.smallCaptionHeight"), rescale(ncmetrics.iSmCaptionHeight, invScaleY));
+    SetIntegerProperty(TEXT("win.frame.smallCaptionButtonWidth"), rescale(ncmetrics.iSmCaptionWidth, invScaleX));
+    SetIntegerProperty(TEXT("win.frame.smallCaptionButtonHeight"), rescale(ncmetrics.iSmCaptionHeight, invScaleY));
+    SetIntegerProperty(TEXT("win.frame.sizingBorderWidth"), rescale(ncmetrics.iBorderWidth, invScaleX));
 
     // menu properties
-    SetFontProperty( TEXT("win.menu.font"), ncmetrics.lfMenuFont );
-    SetIntegerProperty( TEXT("win.menu.height"), ncmetrics.iMenuHeight );
-    SetIntegerProperty( TEXT("win.menu.buttonWidth"), ncmetrics.iMenuWidth );
+    SetFontProperty(TEXT("win.menu.font"), ncmetrics.lfMenuFont, invScaleY);
+    SetIntegerProperty(TEXT("win.menu.height"), rescale(ncmetrics.iMenuHeight, invScaleY));
+    SetIntegerProperty(TEXT("win.menu.buttonWidth"), rescale(ncmetrics.iMenuWidth, invScaleX));
 
     // scrollbar properties
-    SetIntegerProperty( TEXT("win.scrollbar.width"), ncmetrics.iScrollWidth );
-    SetIntegerProperty( TEXT("win.scrollbar.height"), ncmetrics.iScrollHeight );
+    SetIntegerProperty(TEXT("win.scrollbar.width"), rescale(ncmetrics.iScrollWidth, invScaleX));
+    SetIntegerProperty(TEXT("win.scrollbar.height"), rescale(ncmetrics.iScrollHeight, invScaleY));
 
     // status bar and tooltip properties
-    SetFontProperty( TEXT("win.status.font"), ncmetrics.lfStatusFont );
-    SetFontProperty( TEXT("win.tooltip.font"), ncmetrics.lfStatusFont );
+    SetFontProperty(TEXT("win.status.font"), ncmetrics.lfStatusFont, invScaleY);
+    SetFontProperty(TEXT("win.tooltip.font"), ncmetrics.lfStatusFont, invScaleY);
 
     // message box properties
-    SetFontProperty( TEXT("win.messagebox.font"), ncmetrics.lfMessageFont );
+    SetFontProperty(TEXT("win.messagebox.font"), ncmetrics.lfMessageFont, invScaleY);
 }
 
 void AwtDesktopProperties::GetIconParameters() {
@@ -302,10 +325,13 @@
     iconmetrics.cbSize = sizeof(iconmetrics);
     VERIFY( SystemParametersInfo(SPI_GETICONMETRICS, iconmetrics.cbSize, &iconmetrics, FALSE) );
 
-    SetIntegerProperty(TEXT("win.icon.hspacing"), iconmetrics.iHorzSpacing);
-    SetIntegerProperty(TEXT("win.icon.vspacing"), iconmetrics.iVertSpacing);
+    float invScaleX;
+    float invScaleY;
+    getInvScale(invScaleX, invScaleY);
+    SetIntegerProperty(TEXT("win.icon.hspacing"), rescale(iconmetrics.iHorzSpacing, invScaleX));
+    SetIntegerProperty(TEXT("win.icon.vspacing"), rescale(iconmetrics.iVertSpacing, invScaleY));
     SetBooleanProperty(TEXT("win.icon.titleWrappingOn"), iconmetrics.iTitleWrap != 0);
-    SetFontProperty(TEXT("win.icon.font"), iconmetrics.lfFont);
+    SetFontProperty(TEXT("win.icon.font"), iconmetrics.lfFont, invScaleY);
 }
 /*
  Windows settings for these are also in the registry
@@ -718,6 +744,7 @@
 }
 
 void AwtDesktopProperties::SetIntegerProperty(LPCTSTR propName, int value) {
+
     jstring key = JNU_NewStringPlatform(GetEnv(), propName);
     if (key == NULL) {
         throw std::bad_alloc();
@@ -752,8 +779,8 @@
 }
 
 void AwtDesktopProperties::SetFontProperty(HDC dc, int fontID,
-                                           LPCTSTR propName) {
-    HGDIOBJ font = GetStockObject(fontID);
+    LPCTSTR propName, float invScale) {
+        HGDIOBJ font = GetStockObject(fontID);
     if (font != NULL && SelectObject(dc, font) != NULL) {
         int length = GetTextFace(dc, 0, NULL);
 
@@ -789,8 +816,8 @@
                         throw std::bad_alloc();
                     }
 
-                    jint pointSize = metrics.tmHeight -
-                                     metrics.tmInternalLeading;
+                    jint pointSize = rescale(metrics.tmHeight -
+                                     metrics.tmInternalLeading, invScale);
                     jint style = java_awt_Font_PLAIN;
 
                     if (metrics.tmWeight >= FW_BOLD) {
@@ -818,7 +845,8 @@
     }
 }
 
-void AwtDesktopProperties::SetFontProperty(LPCTSTR propName, const LOGFONT & font) {
+void AwtDesktopProperties::SetFontProperty(LPCTSTR propName, const LOGFONT & font,
+    float invScale) {
     jstring fontName;
     jint pointSize;
     jint style;
@@ -836,7 +864,7 @@
     ReleaseDC(NULL, hdc);
 #endif
     // Java uses point sizes, but assumes 1 pixel = 1 point
-    pointSize = -font.lfHeight;
+    pointSize = rescale(-font.lfHeight, invScale);
 
     // convert Windows font style to Java style
     style = java_awt_Font_PLAIN;
--- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_DesktopProperties.h	Tue Mar 15 09:22:48 2016 +0300
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_DesktopProperties.h	Tue Mar 15 09:16:56 2016 -0700
@@ -73,8 +73,8 @@
         void SetIntegerProperty(LPCTSTR, int);
         void SetStringProperty(LPCTSTR, LPTSTR);
         void SetColorProperty(LPCTSTR, DWORD);
-        void SetFontProperty(HDC, int, LPCTSTR);
-        void SetFontProperty(LPCTSTR, const LOGFONT &);
+        void SetFontProperty(HDC, int, LPCTSTR, float invScale);
+        void SetFontProperty(LPCTSTR, const LOGFONT &, float invScale);
         void SetSoundProperty(LPCTSTR, LPCTSTR);
 
         JNIEnv * GetEnv() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/font/FontScaling/FontScalingTest.java	Tue Mar 15 09:16:56 2016 -0700
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import javax.swing.JButton;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.plaf.metal.MetalLookAndFeel;
+
+/*
+ * @test
+ * @bug 8076545
+ * @summary Text size is twice bigger under Windows L&F on Win 8.1 with
+ *          HiDPI display
+ */
+public class FontScalingTest {
+
+    public static void main(String[] args) throws Exception {
+        int metalFontSize = getFontSize(MetalLookAndFeel.class.getName());
+        int systemFontSize = getFontSize(UIManager.getSystemLookAndFeelClassName());
+
+        if (Math.abs(systemFontSize - metalFontSize) > 8) {
+            throw new RuntimeException("System L&F is too big!");
+        }
+    }
+
+    private static int getFontSize(String laf) throws Exception {
+
+        UIManager.setLookAndFeel(laf);
+        final int[] sizes = new int[1];
+
+        SwingUtilities.invokeAndWait(() -> {
+            JButton button = new JButton("Test");
+            sizes[0] = button.getFont().getSize();
+        });
+
+        return sizes[0];
+    }
+}
\ No newline at end of file