1 package charactermanaj.ui.util;
3 import java.awt.Component;
4 import java.awt.Dimension;
5 import java.awt.GraphicsConfiguration;
6 import java.awt.GraphicsDevice;
7 import java.awt.GraphicsEnvironment;
8 import java.awt.Toolkit;
9 import java.awt.geom.AffineTransform;
10 import java.lang.reflect.Field;
11 import java.lang.reflect.Method;
13 import charactermanaj.util.JavaVersionUtils;
18 * Java8であれば自動スケールがかかっていないので、マニュアルでスケール倍して座標を補正する。
19 * Java11であれば自動スケールがかかっている。
21 public class ScaleSupport {
23 private static final int resolution;
25 private static final float computeScale;
27 private static final boolean noNeedCheckScaleByReflection;
29 private double scaleX;
31 private double scaleY;
33 private double manualScaleX;
35 private double manualScaleY;
37 private boolean retina;
40 // デフォルトのスクリーン解像度を取得する
41 Toolkit tk = Toolkit.getDefaultToolkit();
42 resolution = tk.getScreenResolution();
44 // スクリーン解像度と標準のDPIから必要とされるスケールを計算する。
45 // ただし、Windowsでない場合はスケール1の等倍にする。
46 // (Retinaの場合はシステム側でスケールされるのでアプリ側でスケールする必要はないため)
47 float dpi = System.getProperty("os.name").startsWith("Windows") ? 96f : resolution;
48 computeScale = resolution / dpi;
50 // Java9以降であればアフィン変換パラメータでスケールを確認できるので
51 // リフレクションを使ったスケールの確認は不要である。
52 noNeedCheckScaleByReflection = JavaVersionUtils.getJavaVersion() >= 9;
55 private ScaleSupport(double scaleX, double scaleY) {
58 if (scaleX > 1 || scaleY > 1 || Boolean.getBoolean("disableScaleCalibrate")) {
59 // システム側でスケールがかかっていれば、アプリ側ではスケールする必要はない。
60 // もしくはシステムプロパティでアプリによるスケールを無効にしている場合。
64 // システム側でスケールがかかっていない場合はアプリ側でスケールする
65 // スクリーン解像度とDPIから必要なスケールを求める
66 manualScaleX = computeScale;
67 manualScaleY = computeScale;
71 public static int getScreenResolution() {
75 public static float getScreenScale() {
79 private void setRetina(boolean retina) {
83 public boolean isRetina() {
88 * コンポーネントのグラフィクス設定からスケールを取得する。
89 * まだ画面に関連付けられていない場合はnullを返す。
93 public static ScaleSupport getInstance(Component comp) {
94 GraphicsConfiguration gconf = comp.getGraphicsConfiguration();
98 return getInstance(gconf);
101 public static ScaleSupport getDefault() {
102 GraphicsEnvironment genv = GraphicsEnvironment.getLocalGraphicsEnvironment();
103 GraphicsDevice gdev = genv.getDefaultScreenDevice();
104 return getInstance(gdev.getDefaultConfiguration());
107 public static ScaleSupport getInstance(GraphicsConfiguration gconf) {
108 // java9以降であれば、GraphicsConfigurationのデフォルトのアフィン変換に
109 // スクリーンのスケールがかけられている。
110 AffineTransform trans = gconf.getDefaultTransform();
111 double scaleX = trans.getScaleX();
112 double scaleY = trans.getScaleY();
114 boolean retina = false;
115 if (scaleX == 1 && scaleY == 1 && !noNeedCheckScaleByReflection) {
116 // Java8まではデフォルトのアフィン変換はスクリーンスケールは設定されていないので
117 // 等倍を返してきた場合は、グラフィクスデバイスがスケールメソッドをもっているかリフレクションで確かめる。
118 // Mac版のJava8であればスケーメメソッドをもっている。
119 // (Java9以降であれば確認は不要である。)
120 // http://hg.openjdk.java.net/jdk9/client/jdk/file/1089d8a8a6e1/src/java.desktop/macosx/classes/sun/awt/CGraphicsDevice.java
121 // https://www.programcreek.com/java-api-examples/?code=SensorsINI/jaer/jaer-master/src/net/sf/jaer/graphics/ChipCanvas.java
122 final GraphicsDevice device = gconf.getDevice();
123 Object scaleObj = null;
125 // public methodがあれば、そちらを試す。
126 Method methodGetScaleFactor = device.getClass().getMethod("getScaleFactor");
127 scaleObj = methodGetScaleFactor.invoke(device);
129 } catch (Exception ex) {
131 // sun.awt.CGraphicsDevice固有の内部フィールドを試す
132 Field field = device.getClass().getDeclaredField("scale");
133 field.setAccessible(true);
134 scaleObj = field.get(device);
135 } catch (Exception ex2) {
139 if (scaleObj instanceof Number) {
140 int scale = ((Number) scaleObj).intValue();
141 scaleX = scaleY = scale;
147 ScaleSupport inst = new ScaleSupport(scaleX, scaleY);
148 inst.setRetina(retina);
152 public double getDefaultScaleX() {
156 public double getDefaultScaleY() {
160 public double getManualScaleX() {
164 public double getManualScaleY() {
168 public Dimension manualScaled(Dimension dim) {
169 return new Dimension((int) (dim.getWidth() * manualScaleX), (int) (dim.getHeight() * manualScaleY));