Browse Source

feat: support dip <-> screen conversion on Linux

Shelley Vohr 1 month ago
parent
commit
88eb443ed7

+ 2 - 2
docs/api/screen.md

@@ -124,7 +124,7 @@ Returns [`Display`](structures/display.md) - The display nearest the specified p
 Returns [`Display`](structures/display.md) - The display that most closely
 intersects the provided bounds.
 
-### `screen.screenToDipPoint(point)` _Windows_
+### `screen.screenToDipPoint(point)` _Windows_ _Linux_
 
 * `point` [Point](structures/point.md)
 
@@ -133,7 +133,7 @@ Returns [`Point`](structures/point.md)
 Converts a screen physical point to a screen DIP point.
 The DPI scale is performed relative to the display containing the physical point.
 
-### `screen.dipToScreenPoint(point)` _Windows_
+### `screen.dipToScreenPoint(point)` _Windows_ _Linux_
 
 * `point` [Point](structures/point.md)
 

+ 35 - 2
shell/browser/api/electron_api_screen.cc

@@ -20,6 +20,8 @@
 #include "ui/display/display.h"
 #include "ui/display/screen.h"
 #include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/point_conversions.h"
+#include "ui/gfx/geometry/point_f.h"
 
 #if BUILDFLAG(IS_WIN)
 #include "ui/display/win/screen_win.h"
@@ -126,6 +128,37 @@ void Screen::OnDisplayMetricsChanged(const display::Display& display,
                                 MetricsToArray(changed_metrics)));
 }
 
+gfx::Point Screen::ScreenToDIPPoint(const gfx::PointF& point_px) {
+#if BUILDFLAG(IS_WIN)
+  return display::win::ScreenWin::ScreenToDIPPoint(point_px);
+#elif defined(IS_OZONE_X11)
+  display::Display display =
+      GetDisplayNearestPoint(gfx::ToFlooredPoint(point_px));
+  gfx::Vector2d delta_px = point_px - display.native_origin();
+  gfx::Vector2dF delta_dip =
+      gfx::ScaleVector2d(delta_px, 1.0 / display.device_scale_factor());
+  return display.bounds().origin() + delta_dip;
+#else  // Wayland
+  return gfx::ToFlooredPoint(point_px);
+#endif
+}
+
+gfx::Point Screen::DIPToScreenPoint(const gfx::Point& point_dip) {
+#if BUILDFLAG(IS_WIN)
+  return display::win::ScreenWin::DIPToScreenPoint(point_dip);
+#elif defined(IS_OZONE_X11)
+  display::Display display =
+      GetDisplayNearestPoint(gfx::ToFlooredPoint(point_dip));
+  gfx::Rect bounds_dip = display.bounds();
+  gfx::Vector2d delta_dip = point_dip - bounds_dip.origin();
+  gfx::Vector2dF delta_px =
+      gfx::ScaleVector2d(delta_dip, display.device_scale_factor());
+  return display.native_origin() + delta_px;
+#else  // Wayland
+  return point_dip;
+#endif
+}
+
 // static
 v8::Local<v8::Value> Screen::Create(gin_helper::ErrorThrower error_thrower) {
   if (!Browser::Get()->is_ready()) {
@@ -153,9 +186,9 @@ gin::ObjectTemplateBuilder Screen::GetObjectTemplateBuilder(
       .SetMethod("getPrimaryDisplay", &Screen::GetPrimaryDisplay)
       .SetMethod("getAllDisplays", &Screen::GetAllDisplays)
       .SetMethod("getDisplayNearestPoint", &Screen::GetDisplayNearestPoint)
+      .SetMethod("screenToDipPoint", &Screen::ScreenToDIPPoint)
+      .SetMethod("dipToScreenPoint", &Screen::DIPToScreenPoint)
 #if BUILDFLAG(IS_WIN)
-      .SetMethod("screenToDipPoint", &display::win::ScreenWin::ScreenToDIPPoint)
-      .SetMethod("dipToScreenPoint", &display::win::ScreenWin::DIPToScreenPoint)
       .SetMethod("screenToDipRect", &ScreenToDIPRect)
       .SetMethod("dipToScreenRect", &DIPToScreenRect)
 #endif

+ 4 - 0
shell/browser/api/electron_api_screen.h

@@ -15,6 +15,7 @@
 
 namespace gfx {
 class Point;
+class PointF;
 class Rect;
 class Screen;
 }  // namespace gfx
@@ -58,6 +59,9 @@ class Screen final : public gin::Wrappable<Screen>,
     return screen_->GetDisplayMatching(match_rect);
   }
 
+  gfx::Point ScreenToDIPPoint(const gfx::PointF& point_px);
+  gfx::Point DIPToScreenPoint(const gfx::Point& point_dip);
+
   // display::DisplayObserver:
   void OnDisplayAdded(const display::Display& new_display) override;
   void OnDisplaysRemoved(const display::Displays& removed_displays) override;