From 6cff589b5bd483b563fe465bde74ca94902aab41 Mon Sep 17 00:00:00 2001
From: Fabio Alessandrelli <fabio.alessandrelli@gmail.com>
Date: Fri, 12 Feb 2021 10:50:02 +0100
Subject: [HTML5] Detect screen scale and DPI.

`OS.get_screen_scale` will now return the `window.devicePixelRatio`
value, `OS.get_screen_dpi` uses CSS media queries to find approximate
DPI value for the current display.
`OS.get_screen_size` also return the actual screen size (not the CSS
pixel size).
---
 platform/javascript/display_server_javascript.cpp  |  9 ++++++--
 platform/javascript/display_server_javascript.h    |  1 +
 platform/javascript/godot_js.h                     |  1 +
 .../javascript/js/libs/library_godot_display.js    | 26 ++++++++++++++++++++++
 4 files changed, 35 insertions(+), 2 deletions(-)

(limited to 'platform/javascript')

diff --git a/platform/javascript/display_server_javascript.cpp b/platform/javascript/display_server_javascript.cpp
index b54ac5230a..5e2dddd8e7 100644
--- a/platform/javascript/display_server_javascript.cpp
+++ b/platform/javascript/display_server_javascript.cpp
@@ -845,7 +845,8 @@ Size2i DisplayServerJavaScript::screen_get_size(int p_screen) const {
 	EmscriptenFullscreenChangeEvent ev;
 	EMSCRIPTEN_RESULT result = emscripten_get_fullscreen_status(&ev);
 	ERR_FAIL_COND_V(result != EMSCRIPTEN_RESULT_SUCCESS, Size2i());
-	return Size2i(ev.screenWidth, ev.screenHeight);
+	double scale = godot_js_display_pixel_ratio_get();
+	return Size2i(ev.screenWidth * scale, ev.screenHeight * scale);
 }
 
 Rect2i DisplayServerJavaScript::screen_get_usable_rect(int p_screen) const {
@@ -855,7 +856,11 @@ Rect2i DisplayServerJavaScript::screen_get_usable_rect(int p_screen) const {
 }
 
 int DisplayServerJavaScript::screen_get_dpi(int p_screen) const {
-	return 96; // TODO maybe check pixel ratio via window.devicePixelRatio * 96? Inexact.
+	return godot_js_display_screen_dpi_get();
+}
+
+float DisplayServerJavaScript::screen_get_scale(int p_screen) const {
+	return godot_js_display_pixel_ratio_get();
 }
 
 Vector<DisplayServer::WindowID> DisplayServerJavaScript::get_window_list() const {
diff --git a/platform/javascript/display_server_javascript.h b/platform/javascript/display_server_javascript.h
index e28fbc56f3..e2fe731abf 100644
--- a/platform/javascript/display_server_javascript.h
+++ b/platform/javascript/display_server_javascript.h
@@ -136,6 +136,7 @@ public:
 	Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
 	Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
 	int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
+	float screen_get_scale(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
 
 	// windows
 	Vector<DisplayServer::WindowID> get_window_list() const override;
diff --git a/platform/javascript/godot_js.h b/platform/javascript/godot_js.h
index e8f41d4cae..d2a2fbd6db 100644
--- a/platform/javascript/godot_js.h
+++ b/platform/javascript/godot_js.h
@@ -51,6 +51,7 @@ extern int godot_js_os_execute(const char *p_json);
 extern void godot_js_os_shell_open(const char *p_uri);
 
 // Display
+extern int godot_js_display_screen_dpi_get();
 extern double godot_js_display_pixel_ratio_get();
 extern void godot_js_display_alert(const char *p_text);
 extern int godot_js_display_touchscreen_is_available();
diff --git a/platform/javascript/js/libs/library_godot_display.js b/platform/javascript/js/libs/library_godot_display.js
index 7b085aebc8..9ec295b39f 100644
--- a/platform/javascript/js/libs/library_godot_display.js
+++ b/platform/javascript/js/libs/library_godot_display.js
@@ -405,6 +405,27 @@ const GodotDisplay = {
 	$GodotDisplay__deps: ['$GodotConfig', '$GodotRuntime', '$GodotDisplayCursor', '$GodotDisplayListeners', '$GodotDisplayDragDrop', '$GodotDisplayGamepads'],
 	$GodotDisplay: {
 		window_icon: '',
+		findDPI: function () {
+			function testDPI(dpi) {
+				return window.matchMedia(`(max-resolution: ${dpi}dpi)`).matches;
+			}
+			function bisect(low, high, func) {
+				const mid = parseInt(((high - low) / 2) + low, 10);
+				if (high - low <= 1) {
+					return func(high) ? high : low;
+				}
+				if (func(mid)) {
+					return bisect(low, mid, func);
+				}
+				return bisect(mid, high, func);
+			}
+			try {
+				const dpi = bisect(0, 800, testDPI);
+				return dpi >= 96 ? dpi : 96;
+			} catch (e) {
+				return 96;
+			}
+		},
 	},
 
 	godot_js_display_is_swap_ok_cancel__sig: 'i',
@@ -422,6 +443,11 @@ const GodotDisplay = {
 		window.alert(GodotRuntime.parseString(p_text)); // eslint-disable-line no-alert
 	},
 
+	godot_js_display_screen_dpi_get__sig: 'i',
+	godot_js_display_screen_dpi_get: function () {
+		return GodotDisplay.findDPI();
+	},
+
 	godot_js_display_pixel_ratio_get__sig: 'f',
 	godot_js_display_pixel_ratio_get: function () {
 		return window.devicePixelRatio || 1;
-- 
cgit v1.2.3