Bug 1707533 - Make Wayland custom cursors behave like all other platforms. r=stransky
authorEmilio Cobos Álvarez <emilio@crisal.io>
Tue, 27 Apr 2021 10:50:45 +0000
changeset 577618 a19cf8b431ce85294abdcff91df6be63bcd26f0e
parent 577617 3d9daad425deccc2e8edd8db8eab4a908ef4749d
child 577619 bb1cf116c7a32af22326b150856e74008269f439
push id141961
push userealvarez@mozilla.com
push dateTue, 27 Apr 2021 10:54:41 +0000
treeherderautoland@a19cf8b431ce [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersstransky
bugs1707533
milestone90.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1707533 - Make Wayland custom cursors behave like all other platforms. r=stransky It seems GTK downscales the cursor if the resolution is less than the device scale, so this makes it consistent with X11 and all other desktop platforms. On the example on the bug it seems silly because the cursor is massive, but on legit examples like: https://downloads.scirra.com/labs/bugs/cursor-image-set/ This makes the cursor not abruptly change sizes when page zoom changes for example. Differential Revision: https://phabricator.services.mozilla.com/D113302
widget/gtk/nsWindow.cpp
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -2383,25 +2383,29 @@ gboolean nsWindow::OnPropertyNotifyEvent
 
   if (GetCurrentTimeGetter()->PropertyNotifyHandler(aWidget, aEvent)) {
     return TRUE;
   }
 
   return FALSE;
 }
 
-static GdkCursor* GetCursorForImage(const nsIWidget::Cursor& aCursor) {
+static GdkCursor* GetCursorForImage(const nsIWidget::Cursor& aCursor,
+                                    int32_t aWidgetScaleFactor) {
   if (!aCursor.IsCustom()) {
     return nullptr;
   }
   nsIntSize size = nsIWidget::CustomCursorSize(aCursor);
 
-  // NOTE: GTK only allows integer scale factors, so we ceil to the closest
-  // scale factor and then tell gtk to scale it down.
-  int32_t gtkScale = std::ceil(aCursor.mResolution);
+  // NOTE: GTK only allows integer scale factors, so we ceil to the larger scale
+  // factor and then tell gtk to scale it down. We ensure to scale at least to
+  // the GDK scale factor, so that cursors aren't downsized in HiDPI on wayland,
+  // see bug 1707533.
+  int32_t gtkScale =
+      std::max(aWidgetScaleFactor, int32_t(std::ceil(aCursor.mResolution)));
 
   // Reject cursors greater than 128 pixels in some direction, to prevent
   // spoofing.
   // XXX ideally we should rescale. Also, we could modify the API to
   // allow trusted content to set larger cursors.
   //
   // TODO(emilio, bug 1445844): Unify the solution for this with other
   // platforms.
@@ -2459,17 +2463,17 @@ void nsWindow::SetCursor(const Cursor& a
     return;
   }
 
   mUpdateCursor = false;
   mCursor = aCursor;
 
   // Try to set the cursor image first, and fall back to the numeric cursor.
   bool fromImage = true;
-  GdkCursor* newCursor = GetCursorForImage(aCursor);
+  GdkCursor* newCursor = GetCursorForImage(aCursor, GdkScaleFactor());
   if (!newCursor) {
     fromImage = false;
     newCursor = get_gtk_cursor(aCursor.mDefaultCursor);
   }
 
   auto CleanupCursor = mozilla::MakeScopeExit([&]() {
     // get_gtk_cursor returns a weak reference, which we shouldn't unref.
     if (fromImage) {
@@ -4251,16 +4255,21 @@ void nsWindow::OnScaleChanged(GtkAllocat
   }
 
 #ifdef MOZ_WAYLAND
   // We need to update scale when scale of egl window is changed.
   if (mContainer && moz_container_wayland_has_egl_window(mContainer)) {
     moz_container_wayland_set_scale_factor(mContainer);
   }
 #endif
+
+  if (mCursor.IsCustom()) {
+    mUpdateCursor = true;
+    SetCursor(Cursor{mCursor});
+  }
 }
 
 void nsWindow::DispatchDragEvent(EventMessage aMsg,
                                  const LayoutDeviceIntPoint& aRefPoint,
                                  guint aTime) {
   WidgetDragEvent event(true, aMsg, this);
 
   InitDragEvent(event);