summaryrefslogtreecommitdiff
path: root/chromium/ui/ozone
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/ui/ozone')
-rw-r--r--chromium/ui/ozone/BUILD.gn3
-rw-r--r--chromium/ui/ozone/DIR_METADATA4
-rw-r--r--chromium/ui/ozone/OWNERS3
-rw-r--r--chromium/ui/ozone/common/egl_util.cc46
-rw-r--r--chromium/ui/ozone/common/features.cc2
-rw-r--r--chromium/ui/ozone/common/gl_surface_egl_readback.cc1
-rw-r--r--chromium/ui/ozone/demo/window_manager.cc11
-rw-r--r--chromium/ui/ozone/demo/window_manager.h2
-rw-r--r--chromium/ui/ozone/gl/gl_image_ozone_native_pixmap_unittest.cc6
-rw-r--r--chromium/ui/ozone/platform/cast/DIR_METADATA3
-rw-r--r--chromium/ui/ozone/platform/cast/OWNERS2
-rw-r--r--chromium/ui/ozone/platform/drm/BUILD.gn5
-rw-r--r--chromium/ui/ozone/platform/drm/DIR_METADATA3
-rw-r--r--chromium/ui/ozone/platform/drm/OWNERS2
-rw-r--r--chromium/ui/ozone/platform/drm/common/drm_util.cc114
-rw-r--r--chromium/ui/ozone/platform/drm/common/drm_util.h2
-rw-r--r--chromium/ui/ozone/platform/drm/common/drm_util_unittest.cc173
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/DEPS1
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/crtc_commit_request.cc10
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/crtc_commit_request.h5
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_device.cc47
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_device.h22
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_display.cc3
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_framebuffer.cc3
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_framebuffer.h8
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc42
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h2
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.cc13
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.h3
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager_gpu.cc8
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager_gpu.h4
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator.cc2
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator_unittest.cc11
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_thread.cc10
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc1
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_window.cc10
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_window.h5
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc7
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.h1
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc9
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.cc117
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.h31
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_controller_unittest.cc281
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.cc33
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.h3
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc10
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h4
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.cc30
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_unittest.cc72
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/mock_drm_device.cc88
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/mock_drm_device.h42
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/proxy_helpers.cc2
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/proxy_helpers.h31
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/screen_manager.cc350
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/screen_manager.h42
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc505
-rw-r--r--chromium/ui/ozone/platform/drm/host/drm_cursor.cc7
-rw-r--r--chromium/ui/ozone/platform/drm/host/drm_display_host_manager.cc12
-rw-r--r--chromium/ui/ozone/platform/drm/host/host_drm_device.cc7
-rw-r--r--chromium/ui/ozone/platform/drm/ozone_platform_drm.cc16
-rw-r--r--chromium/ui/ozone/platform/headless/ozone_platform_headless.cc4
-rw-r--r--chromium/ui/ozone/platform/scenic/overlay_manager_scenic.cc5
-rw-r--r--chromium/ui/ozone/platform/scenic/ozone_platform_scenic.cc3
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_overlay_view.cc3
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_surface_factory.cc1
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_surface_factory.h1
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_window.cc11
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_window.h8
-rw-r--r--chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.cc17
-rw-r--r--chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.h9
-rw-r--r--chromium/ui/ozone/platform/wayland/BUILD.gn35
-rw-r--r--chromium/ui/ozone/platform/wayland/DEPS2
-rw-r--r--chromium/ui/ozone/platform/wayland/common/data_util.cc2
-rw-r--r--chromium/ui/ozone/platform/wayland/common/wayland.cc24
-rw-r--r--chromium/ui/ozone/platform/wayland/common/wayland.h20
-rw-r--r--chromium/ui/ozone/platform/wayland/common/wayland_object.cc4
-rw-r--r--chromium/ui/ozone/platform/wayland/common/wayland_object.h10
-rw-r--r--chromium/ui/ozone/platform/wayland/common/wayland_util.cc28
-rw-r--r--chromium/ui/ozone/platform/wayland/common/wayland_util.h7
-rw-r--r--chromium/ui/ozone/platform/wayland/common/wayland_util_unittest.cc71
-rw-r--r--chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc63
-rw-r--r--chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h11
-rw-r--r--chromium/ui/ozone/platform/wayland/gpu/gl_surface_egl_readback_wayland.cc5
-rw-r--r--chromium/ui/ozone/platform/wayland/gpu/gl_surface_wayland.cc30
-rw-r--r--chromium/ui/ozone/platform/wayland/gpu/vulkan_implementation_wayland.cc25
-rw-r--r--chromium/ui/ozone/platform/wayland/gpu/vulkan_implementation_wayland.h4
-rw-r--r--chromium/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.cc32
-rw-r--r--chromium/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.h16
-rw-r--r--chromium/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.cc7
-rw-r--r--chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory.cc3
-rw-r--r--chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory.h1
-rw-r--r--chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc246
-rw-r--r--chromium/ui/ozone/platform/wayland/host/DEPS2
-rw-r--r--chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_device.cc17
-rw-r--r--chromium/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.cc27
-rw-r--r--chromium/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.h1
-rw-r--r--chromium/ui/ozone/platform/wayland/host/shell_object_factory.cc42
-rw-r--r--chromium/ui/ozone/platform/wayland/host/shell_object_factory.h8
-rw-r--r--chromium/ui/ozone/platform/wayland/host/shell_popup_wrapper.cc119
-rw-r--r--chromium/ui/ozone/platform/wayland/host/shell_popup_wrapper.h11
-rw-r--r--chromium/ui/ozone/platform/wayland/host/shell_surface_wrapper.h53
-rw-r--r--chromium/ui/ozone/platform/wayland/host/shell_toplevel_wrapper.cc (renamed from chromium/ui/ozone/platform/wayland/host/shell_surface_wrapper.cc)2
-rw-r--r--chromium/ui/ozone/platform/wayland/host/shell_toplevel_wrapper.h98
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_auxiliary_window.cc41
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_auxiliary_window.h3
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_connector.cc6
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc210
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h50
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_clipboard.cc175
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_clipboard.h28
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_clipboard_unittest.cc232
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_connection.cc70
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_connection.h11
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_connection_unittest.cc5
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_cursor.cc28
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_cursor.h30
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_cursor_factory.cc156
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_cursor_factory.h90
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_cursor_factory_unittest.cc134
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_device.cc24
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_device.h9
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_device_base.cc8
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_device_base.h27
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_device_unittest.cc203
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc232
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h61
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc446
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_offer.cc27
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_offer.h8
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_data_offer_base.cc2
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_event_source.cc60
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_event_source.h15
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_event_watcher.cc32
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_input_method_context.cc63
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_keyboard.cc20
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_keyboard.h27
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_pointer.cc11
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_pointer.h3
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc20
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_popup.cc21
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_popup.h9
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_screen.cc19
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc6
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_shm.h2
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_surface.cc110
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_surface.h23
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc398
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.h100
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_touch.cc5
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_touch.h2
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window.cc235
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window.h76
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.cc28
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.h15
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller_unittest.cc142
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window_factory.cc42
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_window_unittest.cc419
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_zaura_shell.cc13
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_zaura_shell.h14
-rw-r--r--chromium/ui/ozone/platform/wayland/host/wayland_zaura_shell_unittest.cc53
-rw-r--r--chromium/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc353
-rw-r--r--chromium/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h46
-rw-r--r--chromium/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.cc358
-rw-r--r--chromium/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h75
-rw-r--r--chromium/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.cc202
-rw-r--r--chromium/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.h88
-rw-r--r--chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_device.cc22
-rw-r--r--chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_device.h5
-rw-r--r--chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_device_manager.h3
-rw-r--r--chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_offer.cc2
-rw-r--r--chromium/ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1.cc14
-rw-r--r--chromium/ui/ozone/platform/wayland/host/zxdg_popup_v6_wrapper_impl.cc262
-rw-r--r--chromium/ui/ozone/platform/wayland/host/zxdg_popup_v6_wrapper_impl.h64
-rw-r--r--chromium/ui/ozone/platform/wayland/host/zxdg_surface_v6_wrapper_impl.cc74
-rw-r--r--chromium/ui/ozone/platform/wayland/host/zxdg_surface_v6_wrapper_impl.h56
-rw-r--r--chromium/ui/ozone/platform/wayland/host/zxdg_toplevel_v6_wrapper_impl.cc166
-rw-r--r--chromium/ui/ozone/platform/wayland/host/zxdg_toplevel_v6_wrapper_impl.h72
-rw-r--r--chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc11
-rw-r--r--chromium/ui/ozone/platform/wayland/test/mock_surface.cc35
-rw-r--r--chromium/ui/ozone/platform/wayland/test/mock_surface.h7
-rw-r--r--chromium/ui/ozone/platform/wayland/test/test_compositor.cc10
-rw-r--r--chromium/ui/ozone/platform/wayland/test/test_compositor.h2
-rw-r--r--chromium/ui/ozone/platform/wayland/test/test_data_offer.cc18
-rw-r--r--chromium/ui/ozone/platform/wayland/test/test_data_offer.h10
-rw-r--r--chromium/ui/ozone/platform/wayland/test/test_wayland_server_thread.cc7
-rw-r--r--chromium/ui/ozone/platform/wayland/test/wayland_drag_drop_test.cc127
-rw-r--r--chromium/ui/ozone/platform/wayland/test/wayland_drag_drop_test.h68
-rw-r--r--chromium/ui/ozone/platform/wayland/test/wayland_test.cc5
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc180
-rw-r--r--chromium/ui/ozone/platform/x11/BUILD.gn6
-rw-r--r--chromium/ui/ozone/platform/x11/client_native_pixmap_factory_x11.cc4
-rw-r--r--chromium/ui/ozone/platform/x11/gl_egl_utility_x11.cc13
-rw-r--r--chromium/ui/ozone/platform/x11/gl_egl_utility_x11.h4
-rw-r--r--chromium/ui/ozone/platform/x11/ozone_platform_x11.cc33
-rw-r--r--chromium/ui/ozone/platform/x11/x11_clipboard_ozone.cc83
-rw-r--r--chromium/ui/ozone/platform/x11/x11_clipboard_ozone.h14
-rw-r--r--chromium/ui/ozone/platform/x11/x11_os_exchange_data_provider_ozone.cc15
-rw-r--r--chromium/ui/ozone/platform/x11/x11_os_exchange_data_provider_ozone.h8
-rw-r--r--chromium/ui/ozone/platform/x11/x11_screen_ozone.cc16
-rw-r--r--chromium/ui/ozone/platform/x11/x11_screen_ozone.h7
-rw-r--r--chromium/ui/ozone/platform/x11/x11_surface_factory.cc41
-rw-r--r--chromium/ui/ozone/platform/x11/x11_surface_factory.h14
-rw-r--r--chromium/ui/ozone/platform/x11/x11_window_ozone_unittest.cc5
-rw-r--r--chromium/ui/ozone/public/input_controller.cc3
-rw-r--r--chromium/ui/ozone/public/input_controller.h11
-rw-r--r--chromium/ui/ozone/public/mojom/device_cursor.mojom3
-rw-r--r--chromium/ui/ozone/public/mojom/drm_device.mojom6
-rw-r--r--chromium/ui/ozone/public/mojom/wayland/wayland_buffer_manager.mojom18
-rw-r--r--chromium/ui/ozone/public/overlay_manager_ozone.h9
-rw-r--r--chromium/ui/ozone/public/overlay_surface_candidate.h2
-rw-r--r--chromium/ui/ozone/public/ozone_platform.cc2
-rw-r--r--chromium/ui/ozone/public/ozone_platform.h32
-rw-r--r--chromium/ui/ozone/public/ozone_switches.cc6
-rw-r--r--chromium/ui/ozone/public/ozone_switches.h4
-rw-r--r--chromium/ui/ozone/public/platform_gl_egl_utility.cc29
-rw-r--r--chromium/ui/ozone/public/platform_gl_egl_utility.h14
-rw-r--r--chromium/ui/ozone/public/surface_factory_ozone.cc3
-rw-r--r--chromium/ui/ozone/public/surface_factory_ozone.h3
218 files changed, 7249 insertions, 3180 deletions
diff --git a/chromium/ui/ozone/BUILD.gn b/chromium/ui/ozone/BUILD.gn
index 8416fb1f493..e788273148e 100644
--- a/chromium/ui/ozone/BUILD.gn
+++ b/chromium/ui/ozone/BUILD.gn
@@ -90,6 +90,7 @@ component("ozone_base") {
"public/ozone_switches.cc",
"public/ozone_switches.h",
"public/platform_clipboard.h",
+ "public/platform_gl_egl_utility.cc",
"public/platform_gl_egl_utility.h",
"public/platform_menu_utils.cc",
"public/platform_menu_utils.h",
@@ -372,7 +373,7 @@ if (ozone_platform_x11) {
buildflag_header("buildflags") {
header = "buildflags.h"
flags = [ "OZONE_PLATFORM_X11=$ozone_platform_x11" ]
- visibility += [ "//ui/gl:gl" ]
+ visibility += [ "*" ]
}
group("unittests") {
diff --git a/chromium/ui/ozone/DIR_METADATA b/chromium/ui/ozone/DIR_METADATA
new file mode 100644
index 00000000000..826e2a2ae84
--- /dev/null
+++ b/chromium/ui/ozone/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail: {
+ component: "Internals>Ozone"
+}
+team_email: "ozone-dev@chromium.org"
diff --git a/chromium/ui/ozone/OWNERS b/chromium/ui/ozone/OWNERS
index 7288821d96e..ec43a6d2a5d 100644
--- a/chromium/ui/ozone/OWNERS
+++ b/chromium/ui/ozone/OWNERS
@@ -1,6 +1,3 @@
rjkroege@chromium.org
spang@chromium.org
alexst@chromium.org
-
-# TEAM: ozone-dev@chromium.org
-# COMPONENT: Internals>Ozone
diff --git a/chromium/ui/ozone/common/egl_util.cc b/chromium/ui/ozone/common/egl_util.cc
index 56e5ebb152a..d23a6014601 100644
--- a/chromium/ui/ozone/common/egl_util.cc
+++ b/chromium/ui/ozone/common/egl_util.cc
@@ -12,6 +12,10 @@
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_implementation.h"
+#if BUILDFLAG(USE_OPENGL_APITRACE)
+#include <stdlib.h>
+#endif
+
namespace ui {
namespace {
@@ -93,6 +97,48 @@ bool LoadEGLGLES2Bindings(const base::FilePath& egl_library_path,
}
gl::SetGLGetProcAddressProc(get_proc_address);
+
+#if BUILDFLAG(USE_OPENGL_APITRACE)
+ constexpr char kTraceLibegl[] = "TRACE_LIBEGL";
+ constexpr char kTraceLibglesv2[] = "TRACE_LIBGLESV2";
+ constexpr char kTraceFile[] = "TRACE_FILE";
+
+ if (egl_library_path.BaseName().value() != kDefaultEglSoname) {
+ LOG(ERROR) << "Unsupported EGL library '"
+ << egl_library_path.BaseName().value()
+ << "'. egltrace may not work.";
+ }
+ if (gles_library_path.BaseName().value() != kDefaultGlesSoname) {
+ LOG(ERROR) << "Unsupported GLESv2 library '"
+ << gles_library_path.BaseName().value()
+ << "'. egltrace may not work.";
+ }
+
+ // Send correct library names to egttrace.
+ setenv(kTraceLibegl, egl_library_path.BaseName().value().c_str(),
+ /*overwrite=*/0);
+ setenv(kTraceLibglesv2, gles_library_path.BaseName().value().c_str(),
+ /*overwrite=*/0);
+#if defined(OS_CHROMEOS)
+ setenv(kTraceFile, "/tmp/gltrace.dat", /*overwrite=*/0);
+#else
+ if (!getenv(kTraceFile)) {
+ LOG(ERROR) << "egltrace requires valid TRACE_FILE environment variable but "
+ "none were found. Chrome will probably crash.";
+ }
+#endif
+
+ LOG(WARNING) << "Loading egltrace.so with TRACE_LIBEGL="
+ << getenv(kTraceLibegl)
+ << " TRACE_LIBGLESV2=" << getenv(kTraceLibglesv2)
+ << " TRACE_FILE=" << getenv(kTraceFile);
+ const base::FilePath::CharType kDefaultTraceSoname[] =
+ FILE_PATH_LITERAL("egltrace.so");
+ base::NativeLibrary trace_library =
+ base::LoadNativeLibrary(base::FilePath(kDefaultTraceSoname), &error);
+ gl::AddGLNativeLibrary(trace_library);
+#endif
+
gl::AddGLNativeLibrary(egl_library);
gl::AddGLNativeLibrary(gles_library);
diff --git a/chromium/ui/ozone/common/features.cc b/chromium/ui/ozone/common/features.cc
index e8f6809760a..02f03c4dc14 100644
--- a/chromium/ui/ozone/common/features.cc
+++ b/chromium/ui/ozone/common/features.cc
@@ -10,7 +10,7 @@ namespace ui {
const base::Feature kWaylandOverlayDelegation {
"WaylandOverlayDelegation",
-#if BUILDFLAG(IS_LACROS)
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
base::FEATURE_ENABLED_BY_DEFAULT
#else
base::FEATURE_DISABLED_BY_DEFAULT
diff --git a/chromium/ui/ozone/common/gl_surface_egl_readback.cc b/chromium/ui/ozone/common/gl_surface_egl_readback.cc
index 128d4f02273..1345001111d 100644
--- a/chromium/ui/ozone/common/gl_surface_egl_readback.cc
+++ b/chromium/ui/ozone/common/gl_surface_egl_readback.cc
@@ -8,6 +8,7 @@
#include "base/bind.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "ui/gl/gl_bindings.h"
#include "ui/ozone/common/egl_util.h"
namespace ui {
diff --git a/chromium/ui/ozone/demo/window_manager.cc b/chromium/ui/ozone/demo/window_manager.cc
index 611d6bff646..686f88da6ce 100644
--- a/chromium/ui/ozone/demo/window_manager.cc
+++ b/chromium/ui/ozone/demo/window_manager.cc
@@ -108,13 +108,10 @@ void WindowManager::OnDisplaysAcquired(
}
}
-void WindowManager::OnDisplayConfigured(
- const int64_t display_id,
- const gfx::Rect& bounds,
- const base::flat_map<int64_t, bool>& statuses) {
- DCHECK_EQ(statuses.size(), 1UL);
-
- if (statuses.at(display_id)) {
+void WindowManager::OnDisplayConfigured(const int64_t display_id,
+ const gfx::Rect& bounds,
+ bool config_success) {
+ if (config_success) {
std::unique_ptr<DemoWindow> window(
new DemoWindow(this, renderer_factory_.get(), bounds));
window->Start();
diff --git a/chromium/ui/ozone/demo/window_manager.h b/chromium/ui/ozone/demo/window_manager.h
index 0415b01bf39..db65a5b7b05 100644
--- a/chromium/ui/ozone/demo/window_manager.h
+++ b/chromium/ui/ozone/demo/window_manager.h
@@ -41,7 +41,7 @@ class WindowManager : public display::NativeDisplayObserver {
const std::vector<display::DisplaySnapshot*>& displays);
void OnDisplayConfigured(const int64_t display_id,
const gfx::Rect& bounds,
- const base::flat_map<int64_t, bool>& statuses);
+ bool config_success);
// display::NativeDisplayDelegate:
void OnConfigurationChanged() override;
diff --git a/chromium/ui/ozone/gl/gl_image_ozone_native_pixmap_unittest.cc b/chromium/ui/ozone/gl/gl_image_ozone_native_pixmap_unittest.cc
index 40087309e67..d9c19703f36 100644
--- a/chromium/ui/ozone/gl/gl_image_ozone_native_pixmap_unittest.cc
+++ b/chromium/ui/ozone/gl/gl_image_ozone_native_pixmap_unittest.cc
@@ -40,7 +40,7 @@ class GLImageNativePixmapTestDelegate : public GLImageTestDelegateBase {
DCHECK(pixmap) << "Offending format: " << gfx::BufferFormatToString(format);
if (usage == gfx::BufferUsage::GPU_READ_CPU_READ_WRITE ||
usage == gfx::BufferUsage::SCANOUT_CAMERA_READ_WRITE ||
- usage == gfx::BufferUsage::SCANOUT_VEA_READ_CAMERA_AND_CPU_READ_WRITE) {
+ usage == gfx::BufferUsage::VEA_READ_CAMERA_AND_CPU_READ_WRITE) {
auto client_pixmap = client_native_pixmap_factory_->ImportFromHandle(
pixmap->ExportHandle(), size, format, usage);
bool mapped = client_pixmap->Map();
@@ -120,14 +120,14 @@ using GLImageBindTestTypes = testing::Types<
GLImageNativePixmapTestDelegate<gfx::BufferUsage::GPU_READ_CPU_READ_WRITE,
gfx::BufferFormat::YVU_420>,
GLImageNativePixmapTestDelegate<
- gfx::BufferUsage::SCANOUT_VEA_READ_CAMERA_AND_CPU_READ_WRITE,
+ gfx::BufferUsage::VEA_READ_CAMERA_AND_CPU_READ_WRITE,
gfx::BufferFormat::YVU_420>,
GLImageNativePixmapTestDelegate<gfx::BufferUsage::GPU_READ_CPU_READ_WRITE,
gfx::BufferFormat::YUV_420_BIPLANAR>,
GLImageNativePixmapTestDelegate<gfx::BufferUsage::SCANOUT_CAMERA_READ_WRITE,
gfx::BufferFormat::YUV_420_BIPLANAR>,
GLImageNativePixmapTestDelegate<
- gfx::BufferUsage::SCANOUT_VEA_READ_CAMERA_AND_CPU_READ_WRITE,
+ gfx::BufferUsage::VEA_READ_CAMERA_AND_CPU_READ_WRITE,
gfx::BufferFormat::YUV_420_BIPLANAR>,
GLImageNativePixmapTestDelegate<gfx::BufferUsage::GPU_READ_CPU_READ_WRITE,
gfx::BufferFormat::P010>>;
diff --git a/chromium/ui/ozone/platform/cast/DIR_METADATA b/chromium/ui/ozone/platform/cast/DIR_METADATA
new file mode 100644
index 00000000000..774785b830c
--- /dev/null
+++ b/chromium/ui/ozone/platform/cast/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+ component: "Chromecast"
+}
diff --git a/chromium/ui/ozone/platform/cast/OWNERS b/chromium/ui/ozone/platform/cast/OWNERS
index 58f4b71ee3c..281daa82ed2 100644
--- a/chromium/ui/ozone/platform/cast/OWNERS
+++ b/chromium/ui/ozone/platform/cast/OWNERS
@@ -1,4 +1,2 @@
halliwell@chromium.org
lcwu@chromium.org
-
-# COMPONENT: Chromecast
diff --git a/chromium/ui/ozone/platform/drm/BUILD.gn b/chromium/ui/ozone/platform/drm/BUILD.gn
index 37a412b4422..5e5c1eb225c 100644
--- a/chromium/ui/ozone/platform/drm/BUILD.gn
+++ b/chromium/ui/ozone/platform/drm/BUILD.gn
@@ -3,6 +3,7 @@
# found in the LICENSE file.
import("//build/config/chromecast_build.gni")
+import("//build/config/chromeos/ui_mode.gni")
import("//build/config/linux/pkg_config.gni")
import("//build/config/ozone.gni")
import("//gpu/vulkan/features.gni")
@@ -119,9 +120,11 @@ source_set("gbm") {
deps = [
"//base",
+ "//build:chromeos_buildflags",
"//build/config/linux/libdrm",
"//gpu/vulkan:buildflags",
"//ipc",
+ "//media:media_buildflags",
"//mojo/public/cpp/system",
"//services/service_manager/public/cpp",
"//skia",
@@ -158,7 +161,7 @@ source_set("gbm") {
]
}
- if (is_chromeos) {
+ if (is_chromeos_ash) {
deps += [ "//ui/base/ime/chromeos" ]
}
diff --git a/chromium/ui/ozone/platform/drm/DIR_METADATA b/chromium/ui/ozone/platform/drm/DIR_METADATA
new file mode 100644
index 00000000000..91a288c1659
--- /dev/null
+++ b/chromium/ui/ozone/platform/drm/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+ component: "OS>Systems>Display"
+}
diff --git a/chromium/ui/ozone/platform/drm/OWNERS b/chromium/ui/ozone/platform/drm/OWNERS
index 5392283e6fe..363a93a5f95 100644
--- a/chromium/ui/ozone/platform/drm/OWNERS
+++ b/chromium/ui/ozone/platform/drm/OWNERS
@@ -1,4 +1,2 @@
dcastagna@chromium.org
dnicoara@chromium.org
-
-# COMPONENT: OS>Systems>Display
diff --git a/chromium/ui/ozone/platform/drm/common/drm_util.cc b/chromium/ui/ozone/platform/drm/common/drm_util.cc
index a03a4a94935..0c78e5fd8d5 100644
--- a/chromium/ui/ozone/platform/drm/common/drm_util.cc
+++ b/chromium/ui/ozone/platform/drm/common/drm_util.cc
@@ -13,16 +13,23 @@
#include <algorithm>
#include <memory>
+#include <string>
#include <utility>
+#include <vector>
#include "base/containers/flat_map.h"
#include "base/logging.h"
#include "base/metrics/histogram_functions.h"
#include "base/notreached.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
#include "ui/display/types/display_constants.h"
#include "ui/display/types/display_mode.h"
#include "ui/display/util/display_util.h"
#include "ui/display/util/edid_parser.h"
+#include "ui/ozone/platform/drm/common/scoped_drm_types.h"
namespace ui {
@@ -118,6 +125,8 @@ display::DisplayConnectionType GetDisplayType(drmModeConnector* connector) {
case DRM_MODE_CONNECTOR_DVID:
case DRM_MODE_CONNECTOR_DVIA:
return display::DISPLAY_CONNECTION_TYPE_DVI;
+ case DRM_MODE_CONNECTOR_VIRTUAL:
+ // A display on VM is treated as an internal display.
case DRM_MODE_CONNECTOR_LVDS:
case DRM_MODE_CONNECTOR_eDP:
case DRM_MODE_CONNECTOR_DSI:
@@ -195,6 +204,20 @@ display::PrivacyScreenState GetPrivacyScreenState(int fd,
connector->prop_values[index]);
}
+std::vector<uint64_t> GetPathTopology(int fd, drmModeConnector* connector) {
+ ScopedDrmPropertyBlobPtr path_blob =
+ GetDrmPropertyBlob(fd, connector, "PATH");
+
+ if (!path_blob) {
+ DCHECK_GT(connector->connector_id, 0u);
+
+ // The topology is consisted solely of the connector id.
+ return {base::strict_cast<uint64_t>(connector->connector_id)};
+ }
+
+ return ParsePathBlob(*path_blob);
+}
+
bool IsAspectPreserving(int fd, drmModeConnector* connector) {
ScopedDrmPropertyPtr property;
int index = GetDrmProperty(fd, connector, "scaling mode", &property);
@@ -437,6 +460,12 @@ std::unique_ptr<display::DisplaySnapshot> CreateDisplaySnapshot(
const gfx::Size physical_size =
gfx::Size(info->connector()->mmWidth, info->connector()->mmHeight);
const display::DisplayConnectionType type = GetDisplayType(info->connector());
+ uint64_t base_connector_id = 0u;
+ std::vector<uint64_t> path_topology = GetPathTopology(fd, info->connector());
+ if (!path_topology.empty()) {
+ base_connector_id = path_topology.front();
+ path_topology.erase(path_topology.begin());
+ }
const bool is_aspect_preserving_scaling =
IsAspectPreserving(fd, info->connector());
const display::PanelOrientation panel_orientation =
@@ -454,7 +483,8 @@ std::unique_ptr<display::DisplaySnapshot> CreateDisplaySnapshot(
const gfx::Size maximum_cursor_size = GetMaximumCursorSize(fd);
std::string display_name;
- int64_t display_id = display_index;
+ // Make sure the ID contains non index part.
+ int64_t display_id = display_index | 0x100;
int64_t product_code = display::DisplaySnapshot::kInvalidProductCode;
int32_t year_of_manufacture = display::kInvalidYearOfManufacture;
bool has_overscan = false;
@@ -497,21 +527,13 @@ std::unique_ptr<display::DisplaySnapshot> CreateDisplaySnapshot(
display::DisplaySnapshot::DisplayModeList modes =
ExtractDisplayModes(info, active_pixel_size, &current_mode, &native_mode);
- // TODO(https://crbug.com/1105919): Needed for investigating an issue where
- // non-supporting devices broadcast privacy screen support on certain
- // displays.
- VLOG(1) << "DisplaySnapshot created: display_id=" << display_id
- << " type=" << type << " current_mode="
- << (current_mode ? current_mode->ToString() : "nullptr")
- << " privacy_screen_state=" << privacy_screen_state;
-
return std::make_unique<display::DisplaySnapshot>(
- display_id, origin, physical_size, type, is_aspect_preserving_scaling,
- has_overscan, privacy_screen_state, has_color_correction_matrix,
- color_correction_in_linear_space, display_color_space, bits_per_channel,
- display_name, sys_path, std::move(modes), panel_orientation, edid,
- current_mode, native_mode, product_code, year_of_manufacture,
- maximum_cursor_size);
+ display_id, origin, physical_size, type, base_connector_id, path_topology,
+ is_aspect_preserving_scaling, has_overscan, privacy_screen_state,
+ has_color_correction_matrix, color_correction_in_linear_space,
+ display_color_space, bits_per_channel, display_name, sys_path,
+ std::move(modes), panel_orientation, edid, current_mode, native_mode,
+ product_code, year_of_manufacture, maximum_cursor_size);
}
int GetFourCCFormatForOpaqueFramebuffer(gfx::BufferFormat format) {
@@ -535,6 +557,8 @@ int GetFourCCFormatForOpaqueFramebuffer(gfx::BufferFormat format) {
return DRM_FORMAT_NV12;
case gfx::BufferFormat::YVU_420:
return DRM_FORMAT_YVU420;
+ case gfx::BufferFormat::P010:
+ return DRM_FORMAT_P010;
default:
NOTREACHED();
return 0;
@@ -552,4 +576,64 @@ uint64_t GetEnumValueForName(int fd, int property_id, const char* str) {
return 0;
}
+// Returns a vector that holds the path topology of the display. Returns an
+// empty vector upon failure.
+//
+// A path topology c-string is of the format:
+// mst:{DRM_BASE_CONNECTOR_ID#}-{BRANCH_1_PORT#}-...-{BRANCH_N_PORT#}\0
+//
+// For example, the display configuration:
+// Device <--conn6-- MST1 <--port2-- MST2 <--port1-- Display
+// may produce the following topology c-string:
+// "mst:6-2-1"
+//
+// To see how this string is constructed in the DRM:
+// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/gpu/drm/drm_dp_mst_topology.c?h=v5.10-rc3#n2229
+std::vector<uint64_t> ParsePathBlob(const drmModePropertyBlobRes& path_blob) {
+ if (!path_blob.length) {
+ LOG(ERROR) << "PATH property blob is empty.";
+ return {};
+ }
+
+ std::string path_str(
+ static_cast<char*>(path_blob.data),
+ base::strict_cast<std::string::size_type>(path_blob.length));
+ base::StringPiece path_string_piece(path_str);
+ path_string_piece = base::TrimString(path_string_piece, std::string("\0", 1u),
+ base::TRIM_TRAILING);
+
+ const std::string prefix("mst:");
+ if (!base::StartsWith(path_string_piece, prefix,
+ base::CompareCase::SENSITIVE)) {
+ LOG(ERROR) << "Invalid PATH string prefix. Does not contain '" << prefix
+ << "'. Input: '" << path_str << "'";
+ return {};
+ }
+ path_string_piece.remove_prefix(prefix.length());
+
+ std::vector<uint64_t> path;
+ for (const auto& string_port :
+ base::SplitStringPiece(path_string_piece, "-", base::KEEP_WHITESPACE,
+ base::SPLIT_WANT_ALL)) {
+ uint64_t int_port = 0;
+ if (base::StringToUint64(string_port, &int_port) && int_port > 0) {
+ path.push_back(int_port);
+ } else {
+ LOG(ERROR)
+ << "One or more port values in the PATH string are invalid. Input: '"
+ << path_str << "'";
+ return {};
+ }
+ }
+
+ if (path.size() < 2) {
+ LOG(ERROR)
+ << "Insufficient number of ports (should be at least 2 but found "
+ << path.size() << "). Input: '" << path_str << "'";
+ return {};
+ }
+
+ return path;
+}
+
} // namespace ui
diff --git a/chromium/ui/ozone/platform/drm/common/drm_util.h b/chromium/ui/ozone/platform/drm/common/drm_util.h
index c8fc1b71124..f86e91fdeda 100644
--- a/chromium/ui/ozone/platform/drm/common/drm_util.h
+++ b/chromium/ui/ozone/platform/drm/common/drm_util.h
@@ -100,6 +100,8 @@ bool ModeIsInterlaced(const drmModeModeInfo& mode);
uint64_t GetEnumValueForName(int fd, int property_id, const char* str);
+std::vector<uint64_t> ParsePathBlob(const drmModePropertyBlobRes& path_blob);
+
} // namespace ui
#endif // UI_OZONE_PLATFORM_DRM_COMMON_DRM_UTIL_H_
diff --git a/chromium/ui/ozone/platform/drm/common/drm_util_unittest.cc b/chromium/ui/ozone/platform/drm/common/drm_util_unittest.cc
index a0144bf0b10..3be4bc957f4 100644
--- a/chromium/ui/ozone/platform/drm/common/drm_util_unittest.cc
+++ b/chromium/ui/ozone/platform/drm/common/drm_util_unittest.cc
@@ -16,6 +16,7 @@
#include "ui/display/types/display_snapshot.h"
#include "ui/display/util/edid_parser.h"
#include "ui/gfx/geometry/size.h"
+#include "ui/ozone/platform/drm/common/scoped_drm_types.h"
namespace ui {
@@ -180,4 +181,176 @@ TEST_F(DrmUtilTest, TestDisplayModesExtraction) {
EXPECT_EQ(extracted_modes[1].get(), native_mode);
}
+TEST(PathBlobParser, InvalidBlob) {
+ char data[] = "this doesn't matter";
+ drmModePropertyBlobRes blob{1, 0, data};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+}
+
+TEST(PathBlobParser, EmptyOrNullString) {
+ {
+ char empty[] = "";
+ drmModePropertyBlobRes blob{1, sizeof(empty), empty};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+
+ {
+ char null[] = "\0";
+ drmModePropertyBlobRes blob{1, sizeof(null), null};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+}
+
+TEST(PathBlobParser, InvalidPathFormat) {
+ // Space(s)
+ {
+ char s[] = " ";
+ drmModePropertyBlobRes blob{1, sizeof(s), s};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+
+ {
+ char s[] = " ";
+ drmModePropertyBlobRes blob{1, sizeof(s), s};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+
+ // Missing colon
+ {
+ char s[] = "mst6-2-1";
+ drmModePropertyBlobRes blob{1, sizeof(s), s};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+
+ // Caps 'mst:'
+ {
+ char s[] = "MST:6-2-1";
+ drmModePropertyBlobRes blob{1, sizeof(s), s};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+
+ // Subset of "mst:"
+ {
+ char s[] = "ms";
+ drmModePropertyBlobRes blob{1, sizeof(s), s};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+
+ // No 'mst:'
+ {
+ char s[] = "6-2-1";
+ drmModePropertyBlobRes blob{1, sizeof(s), s};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+
+ // Other colon-delimited prefix
+ {
+ char s[] = "path:6-2-1";
+ drmModePropertyBlobRes blob{1, sizeof(s), s};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+
+ // Invalid port number or format
+ {
+ char s[] = "mst:";
+ drmModePropertyBlobRes blob{1, sizeof(s), s};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+
+ {
+ char s[] = "mst:6";
+ drmModePropertyBlobRes blob{1, sizeof(s), s};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+
+ {
+ char s[] = "mst::6-2-1";
+ drmModePropertyBlobRes blob{1, sizeof(s), s};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+
+ {
+ char s[] = "mst:-6-2-1";
+ drmModePropertyBlobRes blob{1, sizeof(s), s};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+
+ {
+ char s[] = "mst:6-2-1-";
+ drmModePropertyBlobRes blob{1, sizeof(s), s};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+
+ {
+ char s[] = "mst:c7";
+ drmModePropertyBlobRes blob{1, sizeof(s), s};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+
+ {
+ char s[] = "mst:6-b-1";
+ drmModePropertyBlobRes blob{1, sizeof(s), s};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+
+ {
+ char s[] = "mst:6--2";
+ drmModePropertyBlobRes blob{1, sizeof(s), s};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+
+ {
+ char s[] = "mst:---";
+ drmModePropertyBlobRes blob{1, sizeof(s), s};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+
+ {
+ char s[] = "mst:6- -2- -1";
+ drmModePropertyBlobRes blob{1, sizeof(s), s};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+
+ {
+ char s[] = "mst:6 -2-1";
+ drmModePropertyBlobRes blob{1, sizeof(s), s};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+
+ {
+ char s[] = "mst:6-'2'-1";
+ drmModePropertyBlobRes blob{1, sizeof(s), s};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+
+ // Null character
+ {
+ char s[] = "mst:6-\0-2-1";
+ drmModePropertyBlobRes blob{1, sizeof(s), s};
+ EXPECT_TRUE(ParsePathBlob(blob).empty());
+ }
+}
+
+TEST(PathBlobParser, ValidPathFormat) {
+ std::vector<uint64_t> expected = {6u, 2u, 1u};
+
+ {
+ char valid[] = "mst:6-2-1";
+ drmModePropertyBlobRes blob{1, sizeof(valid), valid};
+ EXPECT_EQ(expected, ParsePathBlob(blob));
+ }
+
+ {
+ char valid[] = "mst:6-2-1\0";
+ drmModePropertyBlobRes blob{1, sizeof(valid), valid};
+ EXPECT_EQ(expected, ParsePathBlob(blob));
+ }
+
+ {
+ char valid[] = {'m', 's', 't', ':', '6', '-', '2', '-', '1'};
+ drmModePropertyBlobRes blob{1, sizeof(valid), valid};
+ EXPECT_EQ(expected, ParsePathBlob(blob));
+ }
+}
+
} // namespace ui
diff --git a/chromium/ui/ozone/platform/drm/gpu/DEPS b/chromium/ui/ozone/platform/drm/gpu/DEPS
index 3fb5fa6f6a3..a4e9f0a5006 100644
--- a/chromium/ui/ozone/platform/drm/gpu/DEPS
+++ b/chromium/ui/ozone/platform/drm/gpu/DEPS
@@ -1,4 +1,5 @@
include_rules = [
+ "+media/media_buildflags.h",
"-ui/ozone/platform/drm",
"+ui/ozone/platform/drm/common",
"+ui/ozone/platform/drm/gpu",
diff --git a/chromium/ui/ozone/platform/drm/gpu/crtc_commit_request.cc b/chromium/ui/ozone/platform/drm/gpu/crtc_commit_request.cc
index 8127e1633f2..6f4c17b6fa9 100644
--- a/chromium/ui/ozone/platform/drm/gpu/crtc_commit_request.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/crtc_commit_request.cc
@@ -9,6 +9,7 @@ namespace ui {
CrtcCommitRequest::CrtcCommitRequest(uint32_t crtc_id,
uint32_t connector_id,
drmModeModeInfo mode,
+ gfx::Point origin,
HardwareDisplayPlaneList* plane_list,
DrmOverlayPlaneList overlays,
bool should_enable)
@@ -16,8 +17,11 @@ CrtcCommitRequest::CrtcCommitRequest(uint32_t crtc_id,
crtc_id_(crtc_id),
connector_id_(connector_id),
mode_(mode),
+ origin_(origin),
plane_list_(plane_list),
overlays_(std::move(overlays)) {
+ // Verify that at least one overlay plane is a primary plane if we're enabling
+ // a CRTC.
DCHECK(!should_enable || DrmOverlayPlane::GetPrimaryPlane(overlays_));
}
@@ -28,6 +32,7 @@ CrtcCommitRequest::CrtcCommitRequest(const CrtcCommitRequest& other)
crtc_id_(other.crtc_id_),
connector_id_(other.connector_id_),
mode_(other.mode_),
+ origin_(other.origin_),
plane_list_(other.plane_list_),
overlays_(DrmOverlayPlane::Clone(other.overlays_)) {}
@@ -36,11 +41,12 @@ CrtcCommitRequest CrtcCommitRequest::EnableCrtcRequest(
uint32_t crtc_id,
uint32_t connector_id,
drmModeModeInfo mode,
+ gfx::Point origin,
HardwareDisplayPlaneList* plane_list,
DrmOverlayPlaneList overlays) {
DCHECK(plane_list && !overlays.empty());
- return CrtcCommitRequest(crtc_id, connector_id, mode, plane_list,
+ return CrtcCommitRequest(crtc_id, connector_id, mode, origin, plane_list,
std::move(overlays), /*should_enable=*/true);
}
@@ -49,7 +55,7 @@ CrtcCommitRequest CrtcCommitRequest::DisableCrtcRequest(
uint32_t crtc_id,
uint32_t connector_id,
HardwareDisplayPlaneList* plane_list) {
- return CrtcCommitRequest(crtc_id, connector_id, {}, plane_list,
+ return CrtcCommitRequest(crtc_id, connector_id, {}, gfx::Point(), plane_list,
DrmOverlayPlaneList(), /*should_enable=*/false);
}
diff --git a/chromium/ui/ozone/platform/drm/gpu/crtc_commit_request.h b/chromium/ui/ozone/platform/drm/gpu/crtc_commit_request.h
index ad8eab84e7f..f3597f3bb31 100644
--- a/chromium/ui/ozone/platform/drm/gpu/crtc_commit_request.h
+++ b/chromium/ui/ozone/platform/drm/gpu/crtc_commit_request.h
@@ -9,6 +9,7 @@
#include <stdint.h>
#include <xf86drmMode.h>
+#include "ui/gfx/geometry/point.h"
#include "ui/ozone/platform/drm/gpu/drm_device.h"
#include "ui/ozone/platform/drm/gpu/drm_overlay_plane.h"
@@ -31,6 +32,7 @@ class CrtcCommitRequest {
uint32_t crtc_id,
uint32_t connector_id,
drmModeModeInfo mode,
+ gfx::Point origin,
HardwareDisplayPlaneList* plane_list,
DrmOverlayPlaneList overlays);
@@ -43,6 +45,7 @@ class CrtcCommitRequest {
uint32_t crtc_id() const { return crtc_id_; }
uint32_t connector_id() const { return connector_id_; }
const drmModeModeInfo& mode() const { return mode_; }
+ const gfx::Point& origin() const { return origin_; }
HardwareDisplayPlaneList* plane_list() const { return plane_list_; }
const DrmOverlayPlaneList& overlays() const { return overlays_; }
@@ -50,6 +53,7 @@ class CrtcCommitRequest {
CrtcCommitRequest(uint32_t crtc_id,
uint32_t connector_id,
drmModeModeInfo mode,
+ gfx::Point origin,
HardwareDisplayPlaneList* plane_list,
DrmOverlayPlaneList overlays,
bool should_enable);
@@ -58,6 +62,7 @@ class CrtcCommitRequest {
const uint32_t crtc_id_ = 0;
const uint32_t connector_id_ = 0;
const drmModeModeInfo mode_ = {};
+ const gfx::Point origin_;
HardwareDisplayPlaneList* plane_list_ = nullptr;
const DrmOverlayPlaneList overlays_;
};
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_device.cc b/chromium/ui/ozone/platform/drm/gpu/drm_device.cc
index cc5e8c5f213..6e262e27bbb 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_device.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_device.cc
@@ -308,9 +308,15 @@ bool DrmDevice::SetCrtc(uint32_t crtc_id,
TRACE_EVENT2("drm", "DrmDevice::SetCrtc", "crtc", crtc_id, "size",
gfx::Size(mode.hdisplay, mode.vdisplay).ToString());
- return !drmModeSetCrtc(file_.GetPlatformFile(), crtc_id, framebuffer, 0, 0,
- connectors.data(), connectors.size(),
- const_cast<drmModeModeInfo*>(&mode));
+
+ if (!drmModeSetCrtc(file_.GetPlatformFile(), crtc_id, framebuffer, 0, 0,
+ connectors.data(), connectors.size(),
+ const_cast<drmModeModeInfo*>(&mode))) {
+ ++modeset_sequence_id_;
+ return true;
+ }
+
+ return false;
}
bool DrmDevice::DisableCrtc(uint32_t crtc_id) {
@@ -540,14 +546,45 @@ bool DrmDevice::CommitProperties(
uint32_t flags,
uint32_t crtc_count,
scoped_refptr<PageFlipRequest> page_flip_request) {
+ bool success = CommitPropertiesInternal(properties, flags, crtc_count,
+ page_flip_request);
+
+ if (success && flags == DRM_MODE_ATOMIC_ALLOW_MODESET)
+ ++modeset_sequence_id_;
+
+ return success;
+}
+
+bool DrmDevice::CommitPropertiesInternal(
+ drmModeAtomicReq* properties,
+ uint32_t flags,
+ uint32_t crtc_count,
+ scoped_refptr<PageFlipRequest> page_flip_request) {
uint64_t id = 0;
+
if (page_flip_request) {
flags |= DRM_MODE_PAGE_FLIP_EVENT;
id = page_flip_manager_->GetNextId();
}
- if (!drmModeAtomicCommit(file_.GetPlatformFile(), properties, flags,
- reinterpret_cast<void*>(id))) {
+ int result = drmModeAtomicCommit(file_.GetPlatformFile(), properties, flags,
+ reinterpret_cast<void*>(id));
+ if (result && errno == EBUSY && (flags & DRM_MODE_ATOMIC_NONBLOCK)) {
+ VLOG(1) << "Nonblocking atomic commit failed with EBUSY, retry without "
+ "nonblock";
+ // There have been cases where we get back EBUSY when attempting a
+ // non-blocking atomic commit. If we return false from here, that will cause
+ // the GPU process to CHECK itself. These are likely due to kernel bugs,
+ // which should be fixed, but rather than crashing we should retry the
+ // commit without the non-blocking flag and then it should work. This will
+ // cause a slight delay, but that should be imperceptible and better than
+ // crashing. We still do want the underlying driver bugs fixed, but this
+ // provide a better user experience.
+ flags &= ~DRM_MODE_ATOMIC_NONBLOCK;
+ result = drmModeAtomicCommit(file_.GetPlatformFile(), properties, flags,
+ reinterpret_cast<void*>(id));
+ }
+ if (!result) {
if (page_flip_request) {
page_flip_manager_->RegisterCallback(id, crtc_count,
page_flip_request->AddPageFlip());
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_device.h b/chromium/ui/ozone/platform/drm/gpu/drm_device.h
index fdc7f2d0a38..400c9a80e66 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_device.h
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_device.h
@@ -215,11 +215,10 @@ class DrmDevice : public base::RefCountedThreadSafe<DrmDevice> {
// On success, true is returned and |page_flip_request| will receive a
// callback signalling completion of the flip, if provided.
- virtual bool CommitProperties(
- drmModeAtomicReq* properties,
- uint32_t flags,
- uint32_t crtc_count,
- scoped_refptr<PageFlipRequest> page_flip_request);
+ bool CommitProperties(drmModeAtomicReq* properties,
+ uint32_t flags,
+ uint32_t crtc_count,
+ scoped_refptr<PageFlipRequest> page_flip_request);
virtual bool SetCapability(uint64_t capability, uint64_t value);
@@ -230,6 +229,8 @@ class DrmDevice : public base::RefCountedThreadSafe<DrmDevice> {
virtual bool SetMaster();
virtual bool DropMaster();
+ int modeset_sequence_id() const { return modeset_sequence_id_; }
+
int get_fd() const { return file_.GetPlatformFile(); }
base::FilePath device_path() const { return device_path_; }
@@ -244,8 +245,19 @@ class DrmDevice : public base::RefCountedThreadSafe<DrmDevice> {
virtual ~DrmDevice();
+ virtual bool CommitPropertiesInternal(
+ drmModeAtomicReq* properties,
+ uint32_t flags,
+ uint32_t crtc_count,
+ scoped_refptr<PageFlipRequest> page_flip_request);
+
std::unique_ptr<HardwareDisplayPlaneManager> plane_manager_;
+ // Sequence ID incremented at each modeset.
+ // Currently used by DRM Framebuffer to indicate when was the fb initialized
+ // wrt the preceding modeset.
+ int modeset_sequence_id_ = 0;
+
private:
class IOWatcher;
class PageFlipManager;
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_display.cc b/chromium/ui/ozone/platform/drm/gpu/drm_display.cc
index 4f84ef488cf..b1ccd606e67 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_display.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_display.cc
@@ -10,6 +10,7 @@
#include "base/logging.h"
#include "base/stl_util.h"
#include "base/trace_event/trace_event.h"
+#include "build/chromeos_buildflags.h"
#include "ui/display/display_features.h"
#include "ui/display/types/display_snapshot.h"
#include "ui/display/types/gamma_ramp_rgb_entry.h"
@@ -156,7 +157,7 @@ std::unique_ptr<display::DisplaySnapshot> DrmDisplay::Update(
modes_ = GetDrmModeVector(info->connector());
is_hdr_capable_ =
params->bits_per_channel() > 8 && params->color_space().IsHDR();
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
is_hdr_capable_ =
is_hdr_capable_ &&
base::FeatureList::IsEnabled(display::features::kUseHDRTransferFunction);
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_framebuffer.cc b/chromium/ui/ozone/platform/drm/gpu/drm_framebuffer.cc
index bdf7db0ec19..4eb71a4d0f7 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_framebuffer.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_framebuffer.cc
@@ -113,7 +113,8 @@ DrmFramebuffer::DrmFramebuffer(scoped_refptr<DrmDevice> drm_device,
opaque_framebuffer_pixel_format_(opaque_framebuffer_pixel_format),
format_modifier_(format_modifier),
preferred_modifiers_(modifiers),
- size_(size) {}
+ size_(size),
+ modeset_sequence_id_at_allocation_(drm_device_->modeset_sequence_id()) {}
DrmFramebuffer::~DrmFramebuffer() {
if (!drm_device_->RemoveFramebuffer(framebuffer_id_))
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_framebuffer.h b/chromium/ui/ozone/platform/drm/gpu/drm_framebuffer.h
index 079297ac1a7..8dbfe7f2bd4 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_framebuffer.h
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_framebuffer.h
@@ -92,6 +92,10 @@ class DrmFramebuffer : public base::RefCountedThreadSafe<DrmFramebuffer> {
// Device on which the buffer was created.
const scoped_refptr<DrmDevice>& drm_device() const { return drm_device_; }
+ int modeset_sequence_id_at_allocation() const {
+ return modeset_sequence_id_at_allocation_;
+ }
+
private:
~DrmFramebuffer();
@@ -110,6 +114,10 @@ class DrmFramebuffer : public base::RefCountedThreadSafe<DrmFramebuffer> {
const std::vector<uint64_t> preferred_modifiers_;
const gfx::Size size_;
+ // The latest modeset sequence ID that was retrieved from DrmDevice when the
+ // buffer is initialized.
+ const int modeset_sequence_id_at_allocation_ = 0;
+
friend class base::RefCountedThreadSafe<DrmFramebuffer>;
};
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc b/chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc
index 8fdb11aba63..bd67bd3d60a 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc
@@ -166,9 +166,8 @@ void DrmGpuDisplayManager::RelinquishDisplayControl() {
drm->DropMaster();
}
-base::flat_map<int64_t, bool> DrmGpuDisplayManager::ConfigureDisplays(
+bool DrmGpuDisplayManager::ConfigureDisplays(
const std::vector<display::DisplayConfigurationParams>& config_requests) {
- base::flat_map<int64_t, bool> statuses;
ScreenManager::ControllerConfigsList controllers_to_configure;
for (const auto& config : config_requests) {
@@ -176,8 +175,7 @@ base::flat_map<int64_t, bool> DrmGpuDisplayManager::ConfigureDisplays(
DrmDisplay* display = FindDisplay(display_id);
if (!display) {
LOG(ERROR) << "There is no display with ID " << display_id;
- statuses.insert(std::make_pair(display_id, false));
- continue;
+ return false;
}
std::unique_ptr<drmModeModeInfo> mode_ptr =
@@ -185,8 +183,7 @@ base::flat_map<int64_t, bool> DrmGpuDisplayManager::ConfigureDisplays(
if (config.mode) {
if (!FindModeForDisplay(mode_ptr.get(), *config.mode.value(),
display->modes(), displays_)) {
- statuses.insert(std::make_pair(display_id, false));
- continue;
+ return false;
}
}
@@ -205,41 +202,30 @@ base::flat_map<int64_t, bool> DrmGpuDisplayManager::ConfigureDisplays(
controllers_to_configure.push_back(std::move(params));
}
- if (controllers_to_configure.empty())
- return statuses;
-
if (clear_overlay_cache_callback_)
clear_overlay_cache_callback_.Run();
- auto config_statuses =
+ bool config_success =
screen_manager_->ConfigureDisplayControllers(controllers_to_configure);
- for (const auto& status : config_statuses) {
- int64_t display_id = status.first;
- bool success = status.second;
- DrmDisplay* display = FindDisplay(display_id);
- auto config = std::find_if(
- config_requests.begin(), config_requests.end(),
- [display_id](const auto& request) { return request.id == display_id; });
- if (success) {
- display->SetOrigin(config->origin);
+ for (const auto& controller : controllers_to_configure) {
+ if (config_success) {
+ FindDisplay(controller.display_id)->SetOrigin(controller.origin);
} else {
- if (config->mode) {
+ if (controller.mode) {
VLOG(1) << "Failed to enable device="
- << display->drm()->device_path().value()
- << " crtc=" << display->crtc()
- << " connector=" << display->connector();
+ << controller.drm->device_path().value()
+ << " crtc=" << controller.crtc
+ << " connector=" << controller.connector;
} else {
VLOG(1) << "Failed to disable device="
- << display->drm()->device_path().value()
- << " crtc=" << display->crtc();
+ << controller.drm->device_path().value()
+ << " crtc=" << controller.crtc;
}
}
-
- statuses.insert(std::make_pair(display_id, success));
}
- return statuses;
+ return config_success;
}
bool DrmGpuDisplayManager::GetHDCPState(
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h b/chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h
index 2dbe2ba68a4..5bbdc84144e 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h
@@ -52,7 +52,7 @@ class DrmGpuDisplayManager {
bool TakeDisplayControl();
void RelinquishDisplayControl();
- base::flat_map<int64_t, bool> ConfigureDisplays(
+ bool ConfigureDisplays(
const std::vector<display::DisplayConfigurationParams>& config_requests);
bool GetHDCPState(int64_t display_id,
display::HDCPState* state,
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.cc b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.cc
index 231d1728494..928ad048588 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.cc
@@ -40,7 +40,10 @@ std::vector<OverlaySurfaceCandidate> ToCacheKey(
} // namespace
-DrmOverlayManager::DrmOverlayManager() {
+DrmOverlayManager::DrmOverlayManager(
+ bool allow_sync_and_real_buffer_page_flip_testing) {
+ allow_sync_and_real_buffer_page_flip_testing_ =
+ allow_sync_and_real_buffer_page_flip_testing;
DETACH_FROM_THREAD(thread_checker_);
}
@@ -79,7 +82,8 @@ void DrmOverlayManager::CheckOverlaySupport(
result_candidates.back().overlay_handled = can_handle;
}
- if (features::IsSynchronousPageFlipTestingEnabled()) {
+ if (allow_sync_and_real_buffer_page_flip_testing_ &&
+ features::IsSynchronousPageFlipTestingEnabled()) {
std::vector<OverlayStatus> status =
SendOverlayValidationRequestSync(result_candidates, widget);
size_t size = candidates->size();
@@ -145,6 +149,11 @@ bool DrmOverlayManager::CanHandleCandidate(
if (candidate.transform == gfx::OVERLAY_TRANSFORM_INVALID)
return false;
+ // The remaining checks are for ensuring consistency between GL compositing
+ // and overlays. If we must use an overlay, then skip the remaining checks.
+ if (candidate.requires_overlay)
+ return true;
+
// Reject candidates that don't fall on a pixel boundary.
if (!gfx::IsNearestRectWithinDistance(candidate.display_rect, 0.01f))
return false;
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.h b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.h
index 87173fa824a..56112a3f508 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.h
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.h
@@ -23,7 +23,8 @@ class OverlaySurfaceCandidate;
// of recent configurations.
class DrmOverlayManager : public OverlayManagerOzone {
public:
- DrmOverlayManager();
+ explicit DrmOverlayManager(
+ bool allow_sync_and_real_buffer_page_flip_testing = true);
~DrmOverlayManager() override;
// OverlayManagerOzone:
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager_gpu.cc b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager_gpu.cc
index 2137523fbd8..89c86a5f80e 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager_gpu.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager_gpu.cc
@@ -8,13 +8,17 @@
#include "base/bind.h"
#include "base/trace_event/trace_event.h"
+#include "ui/ozone/platform/drm/gpu/drm_overlay_manager.h"
#include "ui/ozone/platform/drm/gpu/drm_thread_proxy.h"
#include "ui/ozone/public/overlay_surface_candidate.h"
namespace ui {
-DrmOverlayManagerGpu::DrmOverlayManagerGpu(DrmThreadProxy* drm_thread_proxy)
- : drm_thread_proxy_(drm_thread_proxy) {}
+DrmOverlayManagerGpu::DrmOverlayManagerGpu(
+ DrmThreadProxy* drm_thread_proxy,
+ bool allow_sync_and_real_buffer_page_flip_testing)
+ : DrmOverlayManager(allow_sync_and_real_buffer_page_flip_testing),
+ drm_thread_proxy_(drm_thread_proxy) {}
DrmOverlayManagerGpu::~DrmOverlayManagerGpu() = default;
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager_gpu.h b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager_gpu.h
index 3931e02dac5..cb759538344 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager_gpu.h
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager_gpu.h
@@ -18,7 +18,9 @@ class DrmThreadProxy;
// overlay validations requests to the DRM thread.
class DrmOverlayManagerGpu : public DrmOverlayManager {
public:
- explicit DrmOverlayManagerGpu(DrmThreadProxy* drm_thread_proxy);
+ explicit DrmOverlayManagerGpu(
+ DrmThreadProxy* drm_thread_proxy,
+ bool allow_sync_and_real_buffer_page_flip_testing);
~DrmOverlayManagerGpu() override;
private:
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator.cc b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator.cc
index 4c496547411..348cba77ec8 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator.cc
@@ -46,7 +46,7 @@ scoped_refptr<DrmFramebuffer> GetBufferForPageFlipTest(
// flip commits.
std::vector<uint64_t> modifiers =
is_0th_plane
- ? drm_window->GetController()->GetFormatModifiers(fourcc_format)
+ ? drm_window->GetController()->GetSupportedModifiers(fourcc_format)
: std::vector<uint64_t>();
// Check if we can re-use existing buffers.
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator_unittest.cc b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator_unittest.cc
index 76577c6e485..f5938777c47 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator_unittest.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator_unittest.cc
@@ -81,15 +81,16 @@ class DrmOverlayValidatorTest : public testing::Test {
bool ModesetController(ui::HardwareDisplayController* controller) {
ui::CommitRequest commit_request;
- ui::DrmOverlayPlane plane(CreateBuffer(), nullptr);
+ ui::DrmOverlayPlaneList modeset_planes;
+ modeset_planes.emplace_back(CreateBuffer(), nullptr);
- controller->GetModesetProps(&commit_request, plane, kDefaultMode);
+ controller->GetModesetProps(&commit_request, modeset_planes, kDefaultMode);
ui::CommitRequest request_for_update = commit_request;
bool status = drm_->plane_manager()->Commit(std::move(commit_request),
DRM_MODE_ATOMIC_ALLOW_MODESET);
- controller->UpdateState(
- /*enable_requested=*/true,
- ui::DrmOverlayPlane::GetPrimaryPlane(request_for_update[0].overlays()));
+
+ for (const ui::CrtcCommitRequest& crtc_request : commit_request)
+ controller->UpdateState(crtc_request);
return status;
}
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_thread.cc b/chromium/ui/ozone/platform/drm/gpu/drm_thread.cc
index d77131c3dfc..115231c7d02 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_thread.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_thread.cc
@@ -142,7 +142,7 @@ void DrmThread::CreateBuffer(gfx::AcceleratedWidget widget,
std::vector<uint64_t> modifiers;
if (window && window->GetController() && !(flags & GBM_BO_USE_LINEAR) &&
!(client_flags & GbmPixmap::kFlagNoModifiers)) {
- modifiers = window->GetController()->GetFormatModifiers(fourcc_format);
+ modifiers = window->GetController()->GetSupportedModifiers(fourcc_format);
}
CreateBufferWithGbmFlags(drm, fourcc_format, size, framebuffer_size, flags,
@@ -328,13 +328,11 @@ void DrmThread::RefreshNativeDisplays(
void DrmThread::ConfigureNativeDisplays(
const std::vector<display::DisplayConfigurationParams>& config_requests,
- base::OnceCallback<void(const base::flat_map<int64_t, bool>&)> callback) {
+ base::OnceCallback<void(bool)> callback) {
TRACE_EVENT0("drm", "DrmThread::ConfigureNativeDisplays");
- base::flat_map<int64_t, bool> statuses =
- display_manager_->ConfigureDisplays(config_requests);
-
- std::move(callback).Run(statuses);
+ bool config_success = display_manager_->ConfigureDisplays(config_requests);
+ std::move(callback).Run(config_success);
}
void DrmThread::TakeDisplayControl(base::OnceCallback<void(bool)> callback) {
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc b/chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc
index fa04ef64c35..f2774c1e4aa 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc
@@ -8,6 +8,7 @@
#include <utility>
#include "base/bind.h"
+#include "base/threading/thread_restrictions.h"
#include "base/trace_event/trace_event.h"
#include "ui/gfx/linux/gbm_wrapper.h"
#include "ui/ozone/platform/drm/gpu/drm_device.h"
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_window.cc b/chromium/ui/ozone/platform/drm/gpu/drm_window.cc
index ec3aa6b951d..d83a4f53d8b 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_window.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_window.cc
@@ -31,11 +31,9 @@ DrmWindow::DrmWindow(gfx::AcceleratedWidget widget,
ScreenManager* screen_manager)
: widget_(widget),
device_manager_(device_manager),
- screen_manager_(screen_manager) {
-}
+ screen_manager_(screen_manager) {}
-DrmWindow::~DrmWindow() {
-}
+DrmWindow::~DrmWindow() {}
void DrmWindow::Initialize() {
TRACE_EVENT1("drm", "DrmWindow::Initialize", "widget", widget_);
@@ -133,10 +131,6 @@ OverlayStatusList DrmWindow::TestPageFlip(
last_submitted_planes_);
}
-const DrmOverlayPlane* DrmWindow::GetLastModesetBuffer() const {
- return DrmOverlayPlane::GetPrimaryPlane(last_submitted_planes_);
-}
-
void DrmWindow::UpdateCursorImage() {
if (!controller_)
return;
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_window.h b/chromium/ui/ozone/platform/drm/gpu/drm_window.h
index ea2a2721408..ea1ef54b324 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_window.h
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_window.h
@@ -84,8 +84,9 @@ class DrmWindow {
OverlayStatusList TestPageFlip(
const OverlaySurfaceCandidateList& overlay_params);
- // Returns the last buffer associated with this window.
- const DrmOverlayPlane* GetLastModesetBuffer() const;
+ const DrmOverlayPlaneList& last_submitted_planes() const {
+ return last_submitted_planes_;
+ }
private:
// Draw next frame in an animated cursor.
diff --git a/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc b/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc
index 163a89f699c..2fdc72f9a49 100644
--- a/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc
@@ -12,6 +12,7 @@
#include "base/files/file_path.h"
#include "base/strings/stringprintf.h"
+#include "base/threading/thread_restrictions.h"
#include "build/build_config.h"
#include "third_party/khronos/EGL/egl.h"
#include "ui/gfx/buffer_format_util.h"
@@ -20,6 +21,7 @@
#include "ui/gfx/linux/gbm_defines.h"
#include "ui/gfx/linux/scoped_gbm_device.h"
#include "ui/gfx/native_pixmap.h"
+#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_surface_egl.h"
#include "ui/ozone/common/egl_util.h"
#include "ui/ozone/common/gl_ozone_egl.h"
@@ -275,8 +277,11 @@ GLOzone* GbmSurfaceFactory::GetGLOzone(gl::GLImplementation implementation) {
#if BUILDFLAG(ENABLE_VULKAN)
std::unique_ptr<gpu::VulkanImplementation>
-GbmSurfaceFactory::CreateVulkanImplementation(bool allow_protected_memory,
+GbmSurfaceFactory::CreateVulkanImplementation(bool use_swiftshader,
+ bool allow_protected_memory,
bool enforce_protected_memory) {
+ DCHECK(!use_swiftshader)
+ << "Vulkan Swiftshader is not supported on this platform.";
return std::make_unique<ui::VulkanImplementationGbm>();
}
diff --git a/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.h b/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.h
index 4ac05739713..4aa40139d7d 100644
--- a/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.h
+++ b/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.h
@@ -39,6 +39,7 @@ class GbmSurfaceFactory : public SurfaceFactoryOzone {
#if BUILDFLAG(ENABLE_VULKAN)
std::unique_ptr<gpu::VulkanImplementation> CreateVulkanImplementation(
+ bool use_swiftshader,
bool allow_protected_memory,
bool enforce_protected_memory) override;
scoped_refptr<gfx::NativePixmap> CreateNativePixmapForVulkan(
diff --git a/chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc b/chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
index 664381d52a2..67cb75493b6 100644
--- a/chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
@@ -15,12 +15,17 @@
#include "base/trace_event/trace_event.h"
#include "ui/gfx/gpu_fence.h"
#include "ui/gfx/presentation_feedback.h"
+#include "ui/gl/gl_bindings.h"
#include "ui/ozone/common/egl_util.h"
#include "ui/ozone/platform/drm/gpu/drm_device.h"
#include "ui/ozone/platform/drm/gpu/drm_framebuffer.h"
#include "ui/ozone/platform/drm/gpu/drm_window_proxy.h"
#include "ui/ozone/platform/drm/gpu/gbm_surface_factory.h"
+#if BUILDFLAG(USE_OPENGL_APITRACE)
+#include "ui/gl/gl_implementation.h"
+#endif
+
namespace ui {
namespace {
@@ -133,6 +138,10 @@ void GbmSurfaceless::SwapBuffersAsync(
glFlush();
}
+#if BUILDFLAG(USE_OPENGL_APITRACE)
+ gl::TerminateFrame(); // Notify end of frame at buffer swap request.
+#endif
+
unsubmitted_frames_.back()->Flush();
PendingFrame* frame = unsubmitted_frames_.back().get();
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.cc b/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.cc
index 47a684e7d22..ed387cbc7dc 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.cc
@@ -16,9 +16,11 @@
#include "base/trace_event/trace_event.h"
#include "third_party/libdrm/src/include/drm/drm_fourcc.h"
#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkImage.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/gpu_fence.h"
+#include "ui/gfx/linux/drm_util_linux.h"
#include "ui/gfx/native_pixmap.h"
#include "ui/gfx/presentation_feedback.h"
#include "ui/gfx/swap_result.h"
@@ -58,7 +60,7 @@ void DrawCursor(DrmDumbBuffer* cursor, const SkBitmap& image) {
// Clear to transparent in case |image| is smaller than the canvas.
SkCanvas* canvas = cursor->GetCanvas();
canvas->clear(SK_ColorTRANSPARENT);
- canvas->drawBitmapRect(image, damage, nullptr);
+ canvas->drawImageRect(image.asImage(), damage, SkSamplingOptions());
}
} // namespace
@@ -73,26 +75,26 @@ HardwareDisplayController::HardwareDisplayController(
HardwareDisplayController::~HardwareDisplayController() = default;
-void HardwareDisplayController::GetModesetProps(CommitRequest* commit_request,
- const DrmOverlayPlane& primary,
- const drmModeModeInfo& mode) {
- TRACE_EVENT0("drm", "HDC::GetModesetProps");
- GetModesetPropsForCrtcs(commit_request, primary,
+void HardwareDisplayController::GetModesetProps(
+ CommitRequest* commit_request,
+ const DrmOverlayPlaneList& modeset_planes,
+ const drmModeModeInfo& mode) {
+ GetModesetPropsForCrtcs(commit_request, modeset_planes,
/*use_current_crtc_mode=*/false, mode);
}
-void HardwareDisplayController::GetEnableProps(CommitRequest* commit_request,
- const DrmOverlayPlane& primary) {
- TRACE_EVENT0("drm", "HDC::GetEnableProps");
+void HardwareDisplayController::GetEnableProps(
+ CommitRequest* commit_request,
+ const DrmOverlayPlaneList& modeset_planes) {
// TODO(markyacoub): Simplify and remove the use of empty_mode.
drmModeModeInfo empty_mode = {};
- GetModesetPropsForCrtcs(commit_request, primary,
+ GetModesetPropsForCrtcs(commit_request, modeset_planes,
/*use_current_crtc_mode=*/true, empty_mode);
}
void HardwareDisplayController::GetModesetPropsForCrtcs(
CommitRequest* commit_request,
- const DrmOverlayPlane& primary,
+ const DrmOverlayPlaneList& modeset_planes,
bool use_current_crtc_mode,
const drmModeModeInfo& mode) {
DCHECK(commit_request);
@@ -103,19 +105,16 @@ void HardwareDisplayController::GetModesetPropsForCrtcs(
drmModeModeInfo modeset_mode =
use_current_crtc_mode ? controller->mode() : mode;
- DrmOverlayPlaneList overlays;
- overlays.push_back(primary.Clone());
+ DrmOverlayPlaneList overlays = DrmOverlayPlane::Clone(modeset_planes);
CrtcCommitRequest request = CrtcCommitRequest::EnableCrtcRequest(
- controller->crtc(), controller->connector(), modeset_mode,
+ controller->crtc(), controller->connector(), modeset_mode, origin_,
&owned_hardware_planes_, std::move(overlays));
commit_request->push_back(std::move(request));
}
}
void HardwareDisplayController::GetDisableProps(CommitRequest* commit_request) {
- TRACE_EVENT0("drm", "HDC::GetDisableProps");
-
for (const auto& controller : crtc_controllers_) {
CrtcCommitRequest request = CrtcCommitRequest::DisableCrtcRequest(
controller->crtc(), controller->connector(), &owned_hardware_planes_);
@@ -124,14 +123,13 @@ void HardwareDisplayController::GetDisableProps(CommitRequest* commit_request) {
}
void HardwareDisplayController::UpdateState(
- bool enable_requested,
- const DrmOverlayPlane* primary_plane) {
+ const CrtcCommitRequest& crtc_request) {
// Verify that the current state matches the requested state.
- if (enable_requested && IsEnabled()) {
- DCHECK(primary_plane);
+ if (crtc_request.should_enable() && IsEnabled()) {
+ DCHECK(!crtc_request.overlays().empty());
// TODO(markyacoub): This should be absorbed in the commit request.
ResetCursor();
- OnModesetComplete(*primary_plane);
+ OnModesetComplete(crtc_request.overlays());
}
}
@@ -146,6 +144,24 @@ void HardwareDisplayController::SchedulePageFlip(
bool status =
ScheduleOrTestPageFlip(plane_list, page_flip_request, &out_fence);
+ if (!status) {
+ for (const auto& plane : plane_list) {
+ // If the page flip failed and we see that the buffer has been allocated
+ // before the latest modeset, it could mean it was an in-flight buffer
+ // carrying an obsolete configuration.
+ // Request a buffer reallocation to reflect the new change.
+ if (plane.buffer &&
+ plane.buffer->modeset_sequence_id_at_allocation() <
+ plane.buffer->drm_device()->modeset_sequence_id()) {
+ std::move(submission_callback)
+ .Run(gfx::SwapResult::SWAP_NAK_RECREATE_BUFFERS, nullptr);
+ std::move(presentation_callback)
+ .Run(gfx::PresentationFeedback::Failure());
+ return;
+ }
+ }
+ }
+
CHECK(status) << "SchedulePageFlip failed";
if (page_flip_request->page_flip_count() == 0) {
@@ -204,17 +220,16 @@ bool HardwareDisplayController::ScheduleOrTestPageFlip(
}
std::vector<uint64_t> HardwareDisplayController::GetFormatModifiers(
- uint32_t format) const {
- std::vector<uint64_t> modifiers;
-
+ uint32_t fourcc_format) const {
if (crtc_controllers_.empty())
- return modifiers;
+ return std::vector<uint64_t>();
- modifiers = crtc_controllers_[0]->GetFormatModifiers(format);
+ std::vector<uint64_t> modifiers =
+ crtc_controllers_[0]->GetFormatModifiers(fourcc_format);
for (size_t i = 1; i < crtc_controllers_.size(); ++i) {
std::vector<uint64_t> other =
- crtc_controllers_[i]->GetFormatModifiers(format);
+ crtc_controllers_[i]->GetFormatModifiers(fourcc_format);
std::vector<uint64_t> intersection;
std::set_intersection(modifiers.begin(), modifiers.end(), other.begin(),
@@ -225,11 +240,26 @@ std::vector<uint64_t> HardwareDisplayController::GetFormatModifiers(
return modifiers;
}
-std::vector<uint64_t>
-HardwareDisplayController::GetFormatModifiersForModesetting(
+std::vector<uint64_t> HardwareDisplayController::GetSupportedModifiers(
uint32_t fourcc_format) const {
- const auto& modifiers = GetFormatModifiers(fourcc_format);
+ if (preferred_format_modifier_.empty())
+ return std::vector<uint64_t>();
+
+ auto it = preferred_format_modifier_.find(fourcc_format);
+ if (it != preferred_format_modifier_.end())
+ return std::vector<uint64_t>{it->second};
+
+ return GetFormatModifiers(fourcc_format);
+}
+
+std::vector<uint64_t>
+HardwareDisplayController::GetFormatModifiersForTestModeset(
+ uint32_t fourcc_format) {
+ // If we're about to test, clear the current preferred modifier.
+ preferred_format_modifier_.clear();
+
std::vector<uint64_t> filtered_modifiers;
+ const auto& modifiers = GetFormatModifiers(fourcc_format);
for (auto modifier : modifiers) {
// AFBC for modeset buffers doesn't work correctly, as we can't fill it with
// a valid AFBC buffer. For now, don't use AFBC for modeset buffers.
@@ -242,6 +272,18 @@ HardwareDisplayController::GetFormatModifiersForModesetting(
return filtered_modifiers;
}
+void HardwareDisplayController::UpdatePreferredModiferForFormat(
+ gfx::BufferFormat buffer_format,
+ uint64_t modifier) {
+ uint32_t fourcc_format = GetFourCCFormatFromBufferFormat(buffer_format);
+ base::InsertOrAssign(preferred_format_modifier_, fourcc_format, modifier);
+
+ uint32_t opaque_fourcc_format =
+ GetFourCCFormatForOpaqueFramebuffer(buffer_format);
+ base::InsertOrAssign(preferred_format_modifier_, opaque_fourcc_format,
+ modifier);
+}
+
void HardwareDisplayController::MoveCursor(const gfx::Point& location) {
cursor_location_ = location;
UpdateCursorLocation();
@@ -368,22 +410,21 @@ void HardwareDisplayController::OnPageFlipComplete(
time_of_last_flip_ = presentation_feedback.timestamp;
current_planes_ = std::move(pending_planes);
for (const auto& controller : crtc_controllers_) {
- GetDrmDevice()->plane_manager()->ResetModesetBufferOfCrtc(
+ GetDrmDevice()->plane_manager()->ResetModesetStateForCrtc(
controller->crtc());
}
page_flip_request_ = nullptr;
}
void HardwareDisplayController::OnModesetComplete(
- const DrmOverlayPlane& primary) {
- // drmModeSetCrtc has an immediate effect, so we can assume that the current
- // planes have been updated. However if a page flip is still pending, set the
- // pending planes to the same values so that the callback keeps the correct
- // state.
+ const DrmOverlayPlaneList& modeset_planes) {
+ // Modesetting is blocking so it has an immediate effect. We can assume that
+ // the current planes have been updated. However, if a page flip is still
+ // pending, set the pending planes to the same values so that the callback
+ // keeps the correct state.
page_flip_request_ = nullptr;
owned_hardware_planes_.legacy_page_flips.clear();
- current_planes_.clear();
- current_planes_.push_back(primary.Clone());
+ current_planes_ = DrmOverlayPlane::Clone(modeset_planes);
time_of_last_flip_ = base::TimeTicks::Now();
}
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.h b/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.h
index 17a917183ae..27e4dd4bcbf 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.h
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.h
@@ -14,9 +14,11 @@
#include <vector>
#include "base/callback.h"
+#include "base/containers/flat_map.h"
#include "base/macros.h"
#include "base/time/time.h"
#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/buffer_types.h"
#include "ui/gfx/swap_result.h"
#include "ui/ozone/platform/drm/gpu/drm_overlay_plane.h"
#include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h"
@@ -96,15 +98,15 @@ class HardwareDisplayController {
// Gets the props required to modeset a CRTC with a |mode| onto
// |commit_request|.
void GetModesetProps(CommitRequest* commit_request,
- const DrmOverlayPlane& primary,
+ const DrmOverlayPlaneList& modeset_planes,
const drmModeModeInfo& mode);
// Gets the props required to enable/disable a CRTC onto |commit_request|.
void GetEnableProps(CommitRequest* commit_request,
- const DrmOverlayPlane& primary);
+ const DrmOverlayPlaneList& modeset_planes);
void GetDisableProps(CommitRequest* commit_request);
// Updates state of the controller after modeset/enable/disable is performed.
- void UpdateState(bool enable_requested, const DrmOverlayPlane* primary_plane);
+ void UpdateState(const CrtcCommitRequest& crtc_request);
// Schedules the |overlays|' framebuffers to be displayed on the next vsync
// event. The event will be posted on the graphics card file descriptor |fd_|
@@ -128,17 +130,19 @@ class HardwareDisplayController {
// doesn't change any state.
bool TestPageFlip(const DrmOverlayPlaneList& plane_list);
- // Return the supported modifiers for |fourcc_format| for this
- // controller.
- std::vector<uint64_t> GetFormatModifiers(uint32_t fourcc_format) const;
+ // Return the supported modifiers for |fourcc_format| for this controller.
+ std::vector<uint64_t> GetSupportedModifiers(uint32_t fourcc_format) const;
// Return the supported modifiers for |fourcc_format| for this
// controller to be used for modeset buffers. Currently, this only exists
// because we can't provide valid AFBC buffers during modeset.
// See https://crbug.com/852675
// TODO: Remove this.
- std::vector<uint64_t> GetFormatModifiersForModesetting(
- uint32_t fourcc_format) const;
+ std::vector<uint64_t> GetFormatModifiersForTestModeset(
+ uint32_t fourcc_format);
+
+ void UpdatePreferredModiferForFormat(gfx::BufferFormat buffer_format,
+ uint64_t modifier);
// Moves the hardware cursor to |location|.
void MoveCursor(const gfx::Point& location);
@@ -175,10 +179,10 @@ class HardwareDisplayController {
// Loops over |crtc_controllers_| and save their props into |commit_request|
// to be enabled/modeset.
void GetModesetPropsForCrtcs(CommitRequest* commit_request,
- const DrmOverlayPlane& primary,
+ const DrmOverlayPlaneList& modeset_planes,
bool use_current_crtc_mode,
const drmModeModeInfo& mode);
- void OnModesetComplete(const DrmOverlayPlane& primary);
+ void OnModesetComplete(const DrmOverlayPlaneList& modeset_planes);
bool ScheduleOrTestPageFlip(const DrmOverlayPlaneList& plane_list,
scoped_refptr<PageFlipRequest> page_flip_request,
std::unique_ptr<gfx::GpuFence>* out_fence);
@@ -189,6 +193,8 @@ class HardwareDisplayController {
void ResetCursor();
void DisableCursor();
+ std::vector<uint64_t> GetFormatModifiers(uint32_t fourcc_format) const;
+
HardwareDisplayPlaneList owned_hardware_planes_;
// Stores the CRTC configuration. This is used to identify monitors and
@@ -207,6 +213,11 @@ class HardwareDisplayController {
int cursor_frontbuffer_ = 0;
DrmDumbBuffer* current_cursor_ = nullptr;
+ // Maps each fourcc_format to its preferred modifier which was generated
+ // through modeset-test and updated in UpdatePreferredModifierForFormat().
+ base::flat_map<uint32_t /*fourcc_format*/, uint64_t /*preferred_modifier*/>
+ preferred_format_modifier_;
+
base::WeakPtrFactory<HardwareDisplayController> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(HardwareDisplayController);
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller_unittest.cc b/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller_unittest.cc
index 739c8dd5d62..7cc0dddf155 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller_unittest.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller_unittest.cc
@@ -9,6 +9,7 @@
#include <utility>
#include "base/bind.h"
+#include "base/containers/contains.h"
#include "base/files/file_util.h"
#include "base/macros.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -123,7 +124,7 @@ class HardwareDisplayControllerTest : public testing::Test {
}
protected:
- bool ModesetWithPlane(const ui::DrmOverlayPlane& plane);
+ bool ModesetWithPlanes(const ui::DrmOverlayPlaneList& modeset_planes);
bool DisableController();
std::unique_ptr<ui::HardwareDisplayController> controller_;
@@ -242,16 +243,15 @@ void HardwareDisplayControllerTest::InitializeDrmDevice(bool use_atomic) {
gfx::Point());
}
-bool HardwareDisplayControllerTest::ModesetWithPlane(
- const ui::DrmOverlayPlane& plane) {
+bool HardwareDisplayControllerTest::ModesetWithPlanes(
+ const ui::DrmOverlayPlaneList& modeset_planes) {
ui::CommitRequest commit_request;
- controller_->GetModesetProps(&commit_request, plane, kDefaultMode);
+ controller_->GetModesetProps(&commit_request, modeset_planes, kDefaultMode);
ui::CommitRequest request_for_update = commit_request;
bool status = drm_->plane_manager()->Commit(std::move(commit_request),
DRM_MODE_ATOMIC_ALLOW_MODESET);
- controller_->UpdateState(
- /*enable_requested=*/true,
- ui::DrmOverlayPlane::GetPrimaryPlane(request_for_update[0].overlays()));
+ for (const ui::CrtcCommitRequest& crtc_request : commit_request)
+ controller_->UpdateState(crtc_request);
return status;
}
@@ -262,7 +262,8 @@ bool HardwareDisplayControllerTest::DisableController() {
ui::CommitRequest request_for_update = commit_request;
bool status = drm_->plane_manager()->Commit(std::move(commit_request),
DRM_MODE_ATOMIC_ALLOW_MODESET);
- controller_->UpdateState(/*enable_requested=*/false, nullptr);
+ for (const ui::CrtcCommitRequest& crtc_request : commit_request)
+ controller_->UpdateState(crtc_request);
return status;
}
@@ -301,15 +302,18 @@ uint64_t HardwareDisplayControllerTest::GetPlanePropertyValue(
}
TEST_F(HardwareDisplayControllerTest, CheckModesettingResult) {
- ui::DrmOverlayPlane plane(CreateBuffer(), nullptr);
+ ui::DrmOverlayPlaneList modeset_planes;
+ modeset_planes.emplace_back(CreateBuffer(), nullptr);
- EXPECT_TRUE(ModesetWithPlane(plane));
- EXPECT_FALSE(plane.buffer->HasOneRef());
+ EXPECT_TRUE(ModesetWithPlanes(modeset_planes));
+ EXPECT_FALSE(ui::DrmOverlayPlane::GetPrimaryPlane(modeset_planes)
+ ->buffer->HasOneRef());
}
TEST_F(HardwareDisplayControllerTest, CrtcPropsAfterModeset) {
- ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- EXPECT_TRUE(ModesetWithPlane(plane1));
+ ui::DrmOverlayPlaneList modeset_planes;
+ modeset_planes.emplace_back(CreateBuffer(), nullptr);
+ EXPECT_TRUE(ModesetWithPlanes(modeset_planes));
ui::ScopedDrmObjectPropertyPtr crtc_props =
drm_->GetObjectProperties(kPrimaryCrtc, DRM_MODE_OBJECT_CRTC);
@@ -328,8 +332,9 @@ TEST_F(HardwareDisplayControllerTest, CrtcPropsAfterModeset) {
}
TEST_F(HardwareDisplayControllerTest, ConnectorPropsAfterModeset) {
- ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- EXPECT_TRUE(ModesetWithPlane(plane1));
+ ui::DrmOverlayPlaneList modeset_planes;
+ modeset_planes.emplace_back(CreateBuffer(), nullptr);
+ EXPECT_TRUE(ModesetWithPlanes(modeset_planes));
ui::ScopedDrmObjectPropertyPtr connector_props =
drm_->GetObjectProperties(kConnectorIdBase, DRM_MODE_OBJECT_CONNECTOR);
@@ -343,11 +348,15 @@ TEST_F(HardwareDisplayControllerTest, ConnectorPropsAfterModeset) {
TEST_F(HardwareDisplayControllerTest, PlanePropsAfterModeset) {
const FakeFenceFD fake_fence_fd;
- ui::DrmOverlayPlane plane1(CreateBuffer(), fake_fence_fd.GetGpuFence());
- EXPECT_TRUE(ModesetWithPlane(plane1));
+ ui::DrmOverlayPlaneList modeset_planes;
+ modeset_planes.emplace_back(CreateBuffer(), fake_fence_fd.GetGpuFence());
+ EXPECT_TRUE(ModesetWithPlanes(modeset_planes));
ui::ScopedDrmObjectPropertyPtr plane_props =
drm_->GetObjectProperties(kPlaneOffset, DRM_MODE_OBJECT_PLANE);
+ const ui::DrmOverlayPlane* primary_plane =
+ ui::DrmOverlayPlane::GetPrimaryPlane(modeset_planes);
+
{
ui::DrmDevice::Property prop = {};
ui::GetDrmPropertyForName(drm_.get(), plane_props.get(), "CRTC_ID", &prop);
@@ -358,13 +367,13 @@ TEST_F(HardwareDisplayControllerTest, PlanePropsAfterModeset) {
ui::DrmDevice::Property prop = {};
ui::GetDrmPropertyForName(drm_.get(), plane_props.get(), "CRTC_X", &prop);
EXPECT_EQ(kCrtcX, prop.id);
- EXPECT_EQ(plane1.display_bounds.x(), static_cast<int>(prop.value));
+ EXPECT_EQ(primary_plane->display_bounds.x(), static_cast<int>(prop.value));
}
{
ui::DrmDevice::Property prop = {};
ui::GetDrmPropertyForName(drm_.get(), plane_props.get(), "CRTC_Y", &prop);
EXPECT_EQ(kCrtcY, prop.id);
- EXPECT_EQ(plane1.display_bounds.y(), static_cast<int>(prop.value));
+ EXPECT_EQ(primary_plane->display_bounds.y(), static_cast<int>(prop.value));
}
{
ui::DrmDevice::Property prop = {};
@@ -382,13 +391,13 @@ TEST_F(HardwareDisplayControllerTest, PlanePropsAfterModeset) {
ui::DrmDevice::Property prop = {};
ui::GetDrmPropertyForName(drm_.get(), plane_props.get(), "FB_ID", &prop);
EXPECT_EQ(kPlaneFbId, prop.id);
- EXPECT_EQ(plane1.buffer->opaque_framebuffer_id(),
+ EXPECT_EQ(primary_plane->buffer->opaque_framebuffer_id(),
static_cast<uint32_t>(prop.value));
}
- gfx::RectF crop_rectf = plane1.crop_rect;
- crop_rectf.Scale(plane1.buffer->size().width(),
- plane1.buffer->size().height());
+ gfx::RectF crop_rectf = primary_plane->crop_rect;
+ crop_rectf.Scale(primary_plane->buffer->size().width(),
+ primary_plane->buffer->size().height());
gfx::Rect crop_rect = gfx::ToNearestRect(crop_rectf);
gfx::Rect fixed_point_rect =
gfx::Rect(crop_rect.x() << 16, crop_rect.y() << 16,
@@ -427,8 +436,10 @@ TEST_F(HardwareDisplayControllerTest, PlanePropsAfterModeset) {
}
TEST_F(HardwareDisplayControllerTest, FenceFdValueChange) {
- ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- EXPECT_TRUE(ModesetWithPlane(plane1));
+ ui::DrmOverlayPlaneList modeset_planes;
+ ui::DrmOverlayPlane plane(CreateBuffer(), nullptr);
+ modeset_planes.push_back(plane.Clone());
+ EXPECT_TRUE(ModesetWithPlanes(modeset_planes));
// Test invalid fence fd
{
@@ -443,9 +454,9 @@ TEST_F(HardwareDisplayControllerTest, FenceFdValueChange) {
}
const FakeFenceFD fake_fence_fd;
- plane1.gpu_fence = fake_fence_fd.GetGpuFence();
+ plane.gpu_fence = fake_fence_fd.GetGpuFence();
std::vector<ui::DrmOverlayPlane> planes = {};
- planes.push_back(plane1.Clone());
+ planes.push_back(plane.Clone());
SchedulePageFlip(std::move(planes));
// Verify fence FD after a GPU Fence is added to the plane.
@@ -460,8 +471,10 @@ TEST_F(HardwareDisplayControllerTest, FenceFdValueChange) {
static_cast<int>(fence_fd_prop.value));
}
- plane1.gpu_fence = nullptr;
- EXPECT_TRUE(ModesetWithPlane(plane1));
+ plane.gpu_fence = nullptr;
+ modeset_planes.clear();
+ modeset_planes.push_back(plane.Clone());
+ EXPECT_TRUE(ModesetWithPlanes(modeset_planes));
// Test an invalid FD again after the fence is removed.
{
@@ -477,9 +490,9 @@ TEST_F(HardwareDisplayControllerTest, FenceFdValueChange) {
}
TEST_F(HardwareDisplayControllerTest, CheckDisableResetsProps) {
- ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
-
- EXPECT_TRUE(ModesetWithPlane(plane1));
+ ui::DrmOverlayPlaneList modeset_planes;
+ modeset_planes.emplace_back(CreateBuffer(), nullptr);
+ EXPECT_TRUE(ModesetWithPlanes(modeset_planes));
// Test props values after disabling.
DisableController();
@@ -581,20 +594,21 @@ TEST_F(HardwareDisplayControllerTest, CheckDisableResetsProps) {
}
TEST_F(HardwareDisplayControllerTest, CheckStateAfterPageFlip) {
- ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
-
- EXPECT_TRUE(ModesetWithPlane(plane1));
+ ui::DrmOverlayPlaneList modeset_planes;
+ modeset_planes.emplace_back(CreateBuffer(), nullptr);
+ EXPECT_TRUE(ModesetWithPlanes(modeset_planes));
EXPECT_EQ(1, drm_->get_commit_count());
- ui::DrmOverlayPlane plane2(CreateBuffer(), nullptr);
- std::vector<ui::DrmOverlayPlane> planes;
- planes.push_back(plane2.Clone());
+ ui::DrmOverlayPlane page_flip_plane(CreateBuffer(), nullptr);
+ std::vector<ui::DrmOverlayPlane> page_flip_planes;
+ page_flip_planes.push_back(page_flip_plane.Clone());
- SchedulePageFlip(std::move(planes));
+ SchedulePageFlip(std::move(page_flip_planes));
drm_->RunCallbacks();
- EXPECT_TRUE(plane1.buffer->HasOneRef());
- EXPECT_FALSE(plane2.buffer->HasOneRef());
+ EXPECT_TRUE(ui::DrmOverlayPlane::GetPrimaryPlane(modeset_planes)
+ ->buffer->HasOneRef());
+ EXPECT_FALSE(page_flip_plane.buffer->HasOneRef());
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
EXPECT_EQ(1, page_flips_);
@@ -608,24 +622,21 @@ TEST_F(HardwareDisplayControllerTest, CheckStateIfModesetFails) {
InitializeDrmDevice(/* use_atomic */ false);
drm_->set_set_crtc_expectation(false);
- ui::DrmOverlayPlane plane(CreateBuffer(), nullptr);
-
- EXPECT_FALSE(ModesetWithPlane(plane));
+ ui::DrmOverlayPlaneList modeset_planes;
+ modeset_planes.emplace_back(CreateBuffer(), nullptr);
+ EXPECT_FALSE(ModesetWithPlanes(modeset_planes));
}
TEST_F(HardwareDisplayControllerTest, CheckOverlayPresent) {
- ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- ui::DrmOverlayPlane plane2(
- CreateOverlayBuffer(), 1, gfx::OVERLAY_TRANSFORM_NONE,
- gfx::Rect(kOverlaySize), gfx::RectF(kDefaultModeSizeF), true, nullptr);
+ ui::DrmOverlayPlaneList planes;
+ planes.emplace_back(CreateBuffer(), nullptr);
+ planes.emplace_back(CreateOverlayBuffer(), 1, gfx::OVERLAY_TRANSFORM_NONE,
+ gfx::Rect(kOverlaySize), gfx::RectF(kDefaultModeSizeF),
+ true, nullptr);
- EXPECT_TRUE(ModesetWithPlane(plane1));
+ EXPECT_TRUE(ModesetWithPlanes(planes));
EXPECT_EQ(1, drm_->get_commit_count());
- std::vector<ui::DrmOverlayPlane> planes;
- planes.push_back(plane1.Clone());
- planes.push_back(plane2.Clone());
-
SchedulePageFlip(std::move(planes));
drm_->RunCallbacks();
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
@@ -637,18 +648,15 @@ TEST_F(HardwareDisplayControllerTest, CheckOverlayPresent) {
}
TEST_F(HardwareDisplayControllerTest, CheckOverlayTestMode) {
- ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- ui::DrmOverlayPlane plane2(
- CreateOverlayBuffer(), 1, gfx::OVERLAY_TRANSFORM_NONE,
- gfx::Rect(kOverlaySize), gfx::RectF(kDefaultModeSizeF), true, nullptr);
+ ui::DrmOverlayPlaneList planes;
+ planes.emplace_back(CreateBuffer(), nullptr);
+ planes.emplace_back(CreateOverlayBuffer(), 1, gfx::OVERLAY_TRANSFORM_NONE,
+ gfx::Rect(kOverlaySize), gfx::RectF(kDefaultModeSizeF),
+ true, nullptr);
- EXPECT_TRUE(ModesetWithPlane(plane1));
+ EXPECT_TRUE(ModesetWithPlanes(planes));
EXPECT_EQ(1, drm_->get_commit_count());
- std::vector<ui::DrmOverlayPlane> planes;
- planes.push_back(plane1.Clone());
- planes.push_back(plane2.Clone());
-
SchedulePageFlip(ui::DrmOverlayPlane::Clone(planes));
EXPECT_EQ(2, drm_->get_commit_count());
// Verify both planes on the primary display have a valid framebuffer.
@@ -674,16 +682,13 @@ TEST_F(HardwareDisplayControllerTest, CheckOverlayTestMode) {
}
TEST_F(HardwareDisplayControllerTest, AcceptUnderlays) {
- ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- ui::DrmOverlayPlane plane2(CreateBuffer(), -1, gfx::OVERLAY_TRANSFORM_NONE,
- gfx::Rect(kDefaultModeSize),
- gfx::RectF(kDefaultModeSizeF), true, nullptr);
+ ui::DrmOverlayPlaneList planes;
+ planes.emplace_back(CreateBuffer(), nullptr);
+ planes.emplace_back(CreateBuffer(), -1, gfx::OVERLAY_TRANSFORM_NONE,
+ gfx::Rect(kDefaultModeSize),
+ gfx::RectF(kDefaultModeSizeF), true, nullptr);
- EXPECT_TRUE(ModesetWithPlane(plane1));
-
- std::vector<ui::DrmOverlayPlane> planes;
- planes.push_back(plane1.Clone());
- planes.push_back(plane2.Clone());
+ EXPECT_TRUE(ModesetWithPlanes(planes));
SchedulePageFlip(std::move(planes));
drm_->RunCallbacks();
@@ -695,13 +700,12 @@ TEST_F(HardwareDisplayControllerTest, PageflipMirroredControllers) {
controller_->AddCrtc(std::make_unique<ui::CrtcController>(
drm_.get(), kSecondaryCrtc, kConnectorIdBase + 1));
- ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- EXPECT_TRUE(ModesetWithPlane(plane1));
+ ui::DrmOverlayPlaneList planes;
+ planes.emplace_back(CreateBuffer(), nullptr);
+
+ EXPECT_TRUE(ModesetWithPlanes(planes));
EXPECT_EQ(1, drm_->get_commit_count());
- ui::DrmOverlayPlane plane2(CreateBuffer(), nullptr);
- std::vector<ui::DrmOverlayPlane> planes;
- planes.push_back(plane2.Clone());
SchedulePageFlip(std::move(planes));
drm_->RunCallbacks();
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
@@ -720,10 +724,10 @@ TEST_F(HardwareDisplayControllerTest, PlaneStateAfterRemoveCrtc) {
controller_->AddCrtc(std::make_unique<ui::CrtcController>(
drm_.get(), kSecondaryCrtc, kConnectorIdBase + 1));
- ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- EXPECT_TRUE(ModesetWithPlane(plane1));
- std::vector<ui::DrmOverlayPlane> planes;
- planes.push_back(plane1.Clone());
+ ui::DrmOverlayPlaneList planes;
+ planes.emplace_back(CreateBuffer(), nullptr);
+ EXPECT_TRUE(ModesetWithPlanes(planes));
+
SchedulePageFlip(ui::DrmOverlayPlane::Clone(planes));
drm_->RunCallbacks();
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
@@ -762,10 +766,10 @@ TEST_F(HardwareDisplayControllerTest, PlaneStateAfterRemoveCrtc) {
}
TEST_F(HardwareDisplayControllerTest, PlaneStateAfterDestroyingCrtc) {
- ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- EXPECT_TRUE(ModesetWithPlane(plane1));
- std::vector<ui::DrmOverlayPlane> planes;
- planes.push_back(plane1.Clone());
+ ui::DrmOverlayPlaneList planes;
+ planes.emplace_back(CreateBuffer(), nullptr);
+ EXPECT_TRUE(ModesetWithPlanes(planes));
+
SchedulePageFlip(std::move(planes));
drm_->RunCallbacks();
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
@@ -790,10 +794,10 @@ TEST_F(HardwareDisplayControllerTest, PlaneStateAfterAddCrtc) {
controller_->AddCrtc(std::make_unique<ui::CrtcController>(
drm_.get(), kSecondaryCrtc, kConnectorIdBase + 1));
- ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- EXPECT_TRUE(ModesetWithPlane(plane1));
- std::vector<ui::DrmOverlayPlane> planes;
- planes.push_back(plane1.Clone());
+ ui::DrmOverlayPlaneList planes;
+ planes.emplace_back(CreateBuffer(), nullptr);
+ EXPECT_TRUE(ModesetWithPlanes(planes));
+
SchedulePageFlip(ui::DrmOverlayPlane::Clone(planes));
drm_->RunCallbacks();
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
@@ -835,39 +839,52 @@ TEST_F(HardwareDisplayControllerTest, PlaneStateAfterAddCrtc) {
}
TEST_F(HardwareDisplayControllerTest, ModesetWhilePageFlipping) {
- ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- EXPECT_TRUE(ModesetWithPlane(plane1));
- std::vector<ui::DrmOverlayPlane> planes;
- planes.push_back(plane1.Clone());
- SchedulePageFlip(std::move(planes));
+ ui::DrmOverlayPlaneList planes;
+ planes.emplace_back(CreateBuffer(), nullptr);
+ EXPECT_TRUE(ModesetWithPlanes(planes));
- EXPECT_TRUE(ModesetWithPlane(plane1));
+ SchedulePageFlip(ui::DrmOverlayPlane::Clone(planes));
+
+ EXPECT_TRUE(ModesetWithPlanes(planes));
drm_->RunCallbacks();
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
EXPECT_EQ(1, page_flips_);
}
TEST_F(HardwareDisplayControllerTest, FailPageFlipping) {
- ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- EXPECT_TRUE(ModesetWithPlane(plane1));
+ ui::DrmOverlayPlaneList modeset_planes;
+ modeset_planes.emplace_back(CreateBuffer(), nullptr);
+ ASSERT_TRUE(ModesetWithPlanes(modeset_planes));
+
+ std::vector<ui::DrmOverlayPlane> page_flip_planes;
+ page_flip_planes.emplace_back(CreateBuffer(), nullptr);
drm_->set_commit_expectation(false);
- std::vector<ui::DrmOverlayPlane> planes;
- planes.push_back(plane1.Clone());
- EXPECT_DEATH_IF_SUPPORTED(SchedulePageFlip(std::move(planes)),
+ EXPECT_DEATH_IF_SUPPORTED(SchedulePageFlip(std::move(page_flip_planes)),
"SchedulePageFlip failed");
}
-TEST_F(HardwareDisplayControllerTest, CheckNoPrimaryPlaneOnFlip) {
- ui::DrmOverlayPlane modeset_primary_plane(CreateBuffer(), nullptr);
- EXPECT_TRUE(ModesetWithPlane(modeset_primary_plane));
-
- ui::DrmOverlayPlane plane1(CreateBuffer(), 1, gfx::OVERLAY_TRANSFORM_NONE,
- gfx::Rect(kDefaultModeSize),
- gfx::RectF(0, 0, 1, 1), true, nullptr);
- std::vector<ui::DrmOverlayPlane> planes;
- planes.push_back(plane1.Clone());
+TEST_F(HardwareDisplayControllerTest,
+ RecreateBuffersOnOldPlanesPageFlipFailure) {
+ ui::DrmOverlayPlaneList planes;
+ planes.emplace_back(CreateBuffer(), nullptr);
+ ASSERT_TRUE(ModesetWithPlanes(planes));
+
+ drm_->set_commit_expectation(false);
SchedulePageFlip(std::move(planes));
+ EXPECT_EQ(gfx::SwapResult::SWAP_NAK_RECREATE_BUFFERS, last_swap_result_);
+}
+
+TEST_F(HardwareDisplayControllerTest, CheckNoPrimaryPlaneOnFlip) {
+ ui::DrmOverlayPlaneList modeset_planes;
+ modeset_planes.emplace_back(CreateBuffer(), nullptr);
+ EXPECT_TRUE(ModesetWithPlanes(modeset_planes));
+
+ std::vector<ui::DrmOverlayPlane> page_flip_planes;
+ page_flip_planes.emplace_back(CreateBuffer(), 1, gfx::OVERLAY_TRANSFORM_NONE,
+ gfx::Rect(kDefaultModeSize),
+ gfx::RectF(0, 0, 1, 1), true, nullptr);
+ SchedulePageFlip(std::move(page_flip_planes));
drm_->RunCallbacks();
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
@@ -875,10 +892,10 @@ TEST_F(HardwareDisplayControllerTest, CheckNoPrimaryPlaneOnFlip) {
}
TEST_F(HardwareDisplayControllerTest, AddCrtcMidPageFlip) {
- ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- EXPECT_TRUE(ModesetWithPlane(plane1));
- std::vector<ui::DrmOverlayPlane> planes;
- planes.push_back(plane1.Clone());
+ ui::DrmOverlayPlaneList planes;
+ planes.emplace_back(CreateBuffer(), nullptr);
+ EXPECT_TRUE(ModesetWithPlanes(planes));
+
SchedulePageFlip(std::move(planes));
controller_->AddCrtc(std::make_unique<ui::CrtcController>(
@@ -890,10 +907,10 @@ TEST_F(HardwareDisplayControllerTest, AddCrtcMidPageFlip) {
}
TEST_F(HardwareDisplayControllerTest, RemoveCrtcMidPageFlip) {
- ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- EXPECT_TRUE(ModesetWithPlane(plane1));
- std::vector<ui::DrmOverlayPlane> planes;
- planes.push_back(plane1.Clone());
+ ui::DrmOverlayPlaneList planes;
+ planes.emplace_back(CreateBuffer(), nullptr);
+ EXPECT_TRUE(ModesetWithPlanes(planes));
+
SchedulePageFlip(std::move(planes));
controller_->RemoveCrtc(drm_, kPrimaryCrtc);
@@ -907,16 +924,13 @@ TEST_F(HardwareDisplayControllerTest, Disable) {
// Page flipping overlays is only supported on atomic configurations.
InitializeDrmDevice(/* use_atomic= */ true);
- ui::DrmOverlayPlane plane1(CreateBuffer(), nullptr);
- EXPECT_TRUE(ModesetWithPlane(plane1));
-
- ui::DrmOverlayPlane plane2(
- CreateOverlayBuffer(), 1, gfx::OVERLAY_TRANSFORM_NONE,
- gfx::Rect(kOverlaySize), gfx::RectF(kDefaultModeSizeF), true, nullptr);
- std::vector<ui::DrmOverlayPlane> planes;
- planes.push_back(plane1.Clone());
- planes.push_back(plane2.Clone());
+ ui::DrmOverlayPlaneList planes;
+ planes.emplace_back(CreateBuffer(), nullptr);
+ EXPECT_TRUE(ModesetWithPlanes(planes));
+ planes.emplace_back(CreateOverlayBuffer(), 1, gfx::OVERLAY_TRANSFORM_NONE,
+ gfx::Rect(kOverlaySize), gfx::RectF(kDefaultModeSizeF),
+ true, nullptr);
SchedulePageFlip(std::move(planes));
drm_->RunCallbacks();
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
@@ -931,3 +945,20 @@ TEST_F(HardwareDisplayControllerTest, Disable) {
// No plane should be in use.
ASSERT_EQ(0, planes_in_use);
}
+
+TEST_F(HardwareDisplayControllerTest, MultiplePlanesModeset) {
+ ui::DrmOverlayPlaneList modeset_planes;
+ modeset_planes.emplace_back(CreateBuffer(), nullptr);
+ modeset_planes.emplace_back(CreateBuffer(), nullptr);
+ ASSERT_TRUE(ModesetWithPlanes(modeset_planes));
+ EXPECT_EQ(drm_->plane_manager()
+ ->GetCrtcStateForCrtcId(kPrimaryCrtc)
+ .modeset_framebuffers.size(),
+ 2UL);
+ for (const auto& plane : modeset_planes) {
+ EXPECT_TRUE(base::Contains(drm_->plane_manager()
+ ->GetCrtcStateForCrtcId(kPrimaryCrtc)
+ .modeset_framebuffers,
+ plane.buffer));
+ }
+}
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.cc b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.cc
index acff6ed2116..a24b5b83e70 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.cc
@@ -4,7 +4,10 @@
#include "ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.h"
+#include <drm_fourcc.h>
+
#include "base/logging.h"
+#include "media/media_buildflags.h"
#include "ui/ozone/platform/drm/gpu/drm_device.h"
#include "ui/ozone/platform/drm/gpu/drm_gpu_util.h"
@@ -20,12 +23,15 @@ uint32_t OverlayTransformToDrmRotationPropertyValue(
return DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_0;
case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL:
return DRM_MODE_REFLECT_Y | DRM_MODE_ROTATE_0;
+ // Driver code swaps 90 and 270 to be compliant with how xrandr uses these
+ // values, so we need to invert them here as well to get them back to the
+ // proper value.
case gfx::OVERLAY_TRANSFORM_ROTATE_90:
- return DRM_MODE_ROTATE_90;
+ return DRM_MODE_ROTATE_270;
case gfx::OVERLAY_TRANSFORM_ROTATE_180:
return DRM_MODE_ROTATE_180;
case gfx::OVERLAY_TRANSFORM_ROTATE_270:
- return DRM_MODE_ROTATE_270;
+ return DRM_MODE_ROTATE_90;
default:
NOTREACHED();
}
@@ -35,8 +41,22 @@ uint32_t OverlayTransformToDrmRotationPropertyValue(
// Rotations are dependent on modifiers. Tiled formats can be rotated,
// linear formats cannot. Atomic tests currently ignore modifiers, so there
// isn't a way of determining if the rotation is supported.
-// TODO(https://crbug/880464): Remove this.
-bool IsRotationTransformSupported(gfx::OverlayTransform transform) {
+// TODO(https://b/172210707): Atomic tests should work if we are using
+// kUseRealBuffersForPageFlipTest, so this should be revisited and tested more
+// broadly with a condition on that.
+// NOTE: This is enabled for TGL+ and NV12/P010 formats for 90/270 rotation
+// currently since we always allocate those formats as Y-tiled and 90/270
+// rotation is supported by the HW in that case. This is needed for protected
+// content that requires overlays.
+bool IsRotationTransformSupported(gfx::OverlayTransform transform,
+ uint32_t format_fourcc) {
+#if BUILDFLAG(USE_CHROMEOS_PROTECTED_MEDIA)
+ if ((format_fourcc == DRM_FORMAT_NV12 || format_fourcc == DRM_FORMAT_P010) &&
+ (transform == gfx::OVERLAY_TRANSFORM_ROTATE_90 ||
+ transform == gfx::OVERLAY_TRANSFORM_ROTATE_270)) {
+ return true;
+ }
+#endif
if ((transform == gfx::OVERLAY_TRANSFORM_ROTATE_90) ||
(transform == gfx::OVERLAY_TRANSFORM_ROTATE_270) ||
(transform == gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL)) {
@@ -80,11 +100,12 @@ bool HardwareDisplayPlaneAtomic::AssignPlaneProps(
const gfx::Rect& crtc_rect,
const gfx::Rect& src_rect,
const gfx::OverlayTransform transform,
- int in_fence_fd) {
+ int in_fence_fd,
+ uint32_t format_fourcc) {
if (transform != gfx::OVERLAY_TRANSFORM_NONE && !properties_.rotation.id)
return false;
- if (!IsRotationTransformSupported(transform))
+ if (!IsRotationTransformSupported(transform, format_fourcc))
return false;
// Make a copy of properties to get the props IDs for the new intermediate
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.h b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.h
index 5043b987468..ae8d07997ec 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.h
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.h
@@ -31,7 +31,8 @@ class HardwareDisplayPlaneAtomic : public HardwareDisplayPlane {
const gfx::Rect& crtc_rect,
const gfx::Rect& src_rect,
const gfx::OverlayTransform transform,
- int in_fence_fd);
+ int in_fence_fd,
+ uint32_t format_fourcc);
// Sets the props on |property_set| for commit.
bool SetPlaneProps(drmModeAtomicReq* property_set);
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc
index 634fb042481..448cfa9a14b 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc
@@ -459,8 +459,10 @@ void HardwareDisplayPlaneManager::UpdateCrtcAndPlaneStatesAfterModeset(
if (is_enabled) {
crtc_state.mode = crtc_request.mode();
- crtc_state.modeset_framebuffer =
- DrmOverlayPlane::GetPrimaryPlane(crtc_request.overlays())->buffer;
+ crtc_state.modeset_framebuffers.clear();
+ for (const auto& overlay : crtc_request.overlays())
+ crtc_state.modeset_framebuffers.push_back(overlay.buffer);
+
} else {
if (crtc_request.plane_list())
disable_planes_lists.insert(crtc_request.plane_list());
@@ -483,9 +485,9 @@ void HardwareDisplayPlaneManager::UpdateCrtcAndPlaneStatesAfterModeset(
}
}
-void HardwareDisplayPlaneManager::ResetModesetBufferOfCrtc(uint32_t crtc_id) {
+void HardwareDisplayPlaneManager::ResetModesetStateForCrtc(uint32_t crtc_id) {
CrtcState& crtc_state = CrtcStateForCrtcId(crtc_id);
- crtc_state.modeset_framebuffer = nullptr;
+ crtc_state.modeset_framebuffers.clear();
}
} // namespace ui
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h
index a4593292e8d..0cd18997ce8 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h
@@ -82,7 +82,7 @@ class HardwareDisplayPlaneManager {
CrtcState(CrtcState&&);
drmModeModeInfo mode = {};
- scoped_refptr<DrmFramebuffer> modeset_framebuffer;
+ std::vector<scoped_refptr<DrmFramebuffer>> modeset_framebuffers;
CrtcProperties properties = {};
@@ -187,7 +187,7 @@ class HardwareDisplayPlaneManager {
// which resources needed to be tracked internally in
// HardwareDisplayPlaneManager and which should be taken care of by the
// caller.
- void ResetModesetBufferOfCrtc(uint32_t crtc_id);
+ void ResetModesetStateForCrtc(uint32_t crtc_id);
protected:
struct ConnectorProperties {
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.cc b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.cc
index db7e3cad473..2fae9fcc8ff 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.cc
@@ -11,10 +11,10 @@
#include <utility>
#include "base/bind.h"
+#include "base/containers/contains.h"
#include "base/containers/flat_set.h"
#include "base/files/platform_file.h"
#include "base/logging.h"
-#include "base/stl_util.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "ui/gfx/gpu_fence.h"
#include "ui/gfx/gpu_fence_handle.h"
@@ -142,8 +142,11 @@ bool HardwareDisplayPlaneManagerAtomic::Commit(CommitRequest commit_request,
if (crtc_request.should_enable()) {
DCHECK(crtc_request.plane_list());
- status &= AssignOverlayPlanes(crtc_request.plane_list(),
- crtc_request.overlays(), crtc_id);
+ if (!AssignOverlayPlanes(crtc_request.plane_list(),
+ crtc_request.overlays(), crtc_id)) {
+ LOG_IF(ERROR, !is_testing) << "Failed to Assign Overlay Planes";
+ status = false;
+ }
enable_planes_lists.insert(crtc_request.plane_list());
}
}
@@ -204,9 +207,9 @@ void HardwareDisplayPlaneManagerAtomic::SetAtomicPropsForCommit(
plane->set_in_use(false);
HardwareDisplayPlaneAtomic* atomic_plane =
static_cast<HardwareDisplayPlaneAtomic*>(plane);
- atomic_plane->AssignPlaneProps(0, 0, gfx::Rect(), gfx::Rect(),
- gfx::OVERLAY_TRANSFORM_NONE,
- base::kInvalidPlatformFile);
+ atomic_plane->AssignPlaneProps(
+ 0, 0, gfx::Rect(), gfx::Rect(), gfx::OVERLAY_TRANSFORM_NONE,
+ base::kInvalidPlatformFile, DRM_FORMAT_INVALID);
atomic_plane->SetPlaneProps(atomic_request);
}
}
@@ -307,9 +310,9 @@ bool HardwareDisplayPlaneManagerAtomic::DisableOverlayPlanes(
HardwareDisplayPlaneAtomic* atomic_plane =
static_cast<HardwareDisplayPlaneAtomic*>(plane);
- atomic_plane->AssignPlaneProps(0, 0, gfx::Rect(), gfx::Rect(),
- gfx::OVERLAY_TRANSFORM_NONE,
- base::kInvalidPlatformFile);
+ atomic_plane->AssignPlaneProps(
+ 0, 0, gfx::Rect(), gfx::Rect(), gfx::OVERLAY_TRANSFORM_NONE,
+ base::kInvalidPlatformFile, DRM_FORMAT_INVALID);
atomic_plane->SetPlaneProps(plane_list->atomic_property_set.get());
}
ret = drm_->CommitProperties(plane_list->atomic_property_set.get(),
@@ -365,7 +368,7 @@ void HardwareDisplayPlaneManagerAtomic::RequestPlanesReadyCallback(
}
bool HardwareDisplayPlaneManagerAtomic::SetPlaneData(
- HardwareDisplayPlaneList* plane_list,
+ HardwareDisplayPlaneList*,
HardwareDisplayPlane* hw_plane,
const DrmOverlayPlane& overlay,
uint32_t crtc_id,
@@ -382,9 +385,10 @@ bool HardwareDisplayPlaneManagerAtomic::SetPlaneData(
fence_fd = gpu_fence_handle.owned_fd.get();
}
- if (!atomic_plane->AssignPlaneProps(crtc_id, framebuffer_id,
- overlay.display_bounds, src_rect,
- overlay.plane_transform, fence_fd)) {
+ if (!atomic_plane->AssignPlaneProps(
+ crtc_id, framebuffer_id, overlay.display_bounds, src_rect,
+ overlay.plane_transform, fence_fd,
+ overlay.buffer->framebuffer_pixel_format())) {
return false;
}
return true;
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_unittest.cc b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_unittest.cc
index 6f73d1747a0..1f23be53932 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_unittest.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_unittest.cc
@@ -288,7 +288,7 @@ TEST_P(HardwareDisplayPlaneManagerTest, ResettingConnectorCache) {
ui::CrtcCommitRequest request = ui::CrtcCommitRequest::EnableCrtcRequest(
crtc_properties_[i].id, connector_properties[i].id, kDefaultMode,
- &state, std::move(overlays));
+ gfx::Point(), &state, std::move(overlays));
commit_request.push_back(std::move(request));
}
@@ -309,22 +309,22 @@ TEST_P(HardwareDisplayPlaneManagerTest, ResettingConnectorCache) {
ui::DrmOverlayPlaneList overlays;
overlays.push_back(ui::DrmOverlayPlane(fake_buffer_, nullptr));
commit_request.push_back(ui::CrtcCommitRequest::EnableCrtcRequest(
- crtc_properties_[0].id, kConnectorIdBase, kDefaultMode, &state,
- std::move(overlays)));
+ crtc_properties_[0].id, kConnectorIdBase, kDefaultMode, gfx::Point(),
+ &state, std::move(overlays)));
}
{
ui::DrmOverlayPlaneList overlays;
overlays.push_back(ui::DrmOverlayPlane(fake_buffer_, nullptr));
commit_request.push_back(ui::CrtcCommitRequest::EnableCrtcRequest(
- crtc_properties_[1].id, kConnectorIdBase + 1, kDefaultMode, &state,
- std::move(overlays)));
+ crtc_properties_[1].id, kConnectorIdBase + 1, kDefaultMode,
+ gfx::Point(), &state, std::move(overlays)));
}
{
ui::DrmOverlayPlaneList overlays;
overlays.push_back(ui::DrmOverlayPlane(fake_buffer_, nullptr));
commit_request.push_back(ui::CrtcCommitRequest::EnableCrtcRequest(
- crtc_properties_[2].id, kConnectorIdBase + 3, kDefaultMode, &state,
- std::move(overlays)));
+ crtc_properties_[2].id, kConnectorIdBase + 3, kDefaultMode,
+ gfx::Point(), &state, std::move(overlays)));
}
EXPECT_TRUE(fake_drm_->plane_manager()->Commit(
@@ -332,6 +332,47 @@ TEST_P(HardwareDisplayPlaneManagerTest, ResettingConnectorCache) {
}
}
+TEST_P(HardwareDisplayPlaneManagerTest, SequenceIncrementOnModesetOnly) {
+ fake_drm_->InitializeState(crtc_properties_, connector_properties_,
+ plane_properties_, property_names_,
+ /*use_atomic=*/true);
+
+ // Modeset Test
+ {
+ int pre_test_sequence_id = fake_drm_->modeset_sequence_id();
+ ASSERT_TRUE(fake_drm_->plane_manager()->Commit(
+ ui::CommitRequest(),
+ DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_ALLOW_MODESET));
+ EXPECT_EQ(pre_test_sequence_id, fake_drm_->modeset_sequence_id());
+ }
+
+ // Successful Modeset
+ {
+ int pre_modeset_sequence_id = fake_drm_->modeset_sequence_id();
+ ASSERT_TRUE(fake_drm_->plane_manager()->Commit(
+ ui::CommitRequest(), DRM_MODE_ATOMIC_ALLOW_MODESET));
+ EXPECT_EQ(pre_modeset_sequence_id + 1, fake_drm_->modeset_sequence_id());
+ }
+
+ // Failed Modeset
+ {
+ int pre_modeset_sequence_id = fake_drm_->modeset_sequence_id();
+ fake_drm_->set_set_crtc_expectation(false);
+ ASSERT_FALSE(fake_drm_->plane_manager()->Commit(
+ ui::CommitRequest(), DRM_MODE_ATOMIC_ALLOW_MODESET));
+ fake_drm_->set_set_crtc_expectation(true);
+ EXPECT_EQ(pre_modeset_sequence_id, fake_drm_->modeset_sequence_id());
+ }
+
+ // Page Flip
+ {
+ int pre_flip_sequence_id = fake_drm_->modeset_sequence_id();
+ ASSERT_TRUE(fake_drm_->plane_manager()->Commit(ui::CommitRequest(),
+ DRM_MODE_ATOMIC_NONBLOCK));
+ EXPECT_EQ(pre_flip_sequence_id, fake_drm_->modeset_sequence_id());
+ }
+}
+
TEST_P(HardwareDisplayPlaneManagerLegacyTest, Modeset) {
InitializeDrmState(/*crtc_count=*/1, /*planes_per_crtc=*/1);
fake_drm_->InitializeState(crtc_properties_, connector_properties_,
@@ -346,8 +387,8 @@ TEST_P(HardwareDisplayPlaneManagerLegacyTest, Modeset) {
ui::DrmOverlayPlaneList overlays;
overlays.push_back(plane.Clone());
commit_request.push_back(ui::CrtcCommitRequest::EnableCrtcRequest(
- crtc_properties_[0].id, connector_properties_[0].id, kDefaultMode, &state,
- std::move(overlays)));
+ crtc_properties_[0].id, connector_properties_[0].id, kDefaultMode,
+ gfx::Point(), &state, std::move(overlays)));
EXPECT_FALSE(fake_drm_->plane_manager()->Commit(
std::move(commit_request), DRM_MODE_ATOMIC_ALLOW_MODESET));
@@ -495,8 +536,8 @@ TEST_P(HardwareDisplayPlaneManagerAtomicTest, Modeset) {
overlays.push_back(ui::DrmOverlayPlane(fake_buffer_, nullptr));
commit_request.push_back(ui::CrtcCommitRequest::EnableCrtcRequest(
- crtc_properties_[0].id, connector_properties_[0].id, kDefaultMode, &state,
- std::move(overlays)));
+ crtc_properties_[0].id, connector_properties_[0].id, kDefaultMode,
+ gfx::Point(), &state, std::move(overlays)));
EXPECT_TRUE(fake_drm_->plane_manager()->Commit(
std::move(commit_request), DRM_MODE_ATOMIC_ALLOW_MODESET));
@@ -530,8 +571,8 @@ TEST_P(HardwareDisplayPlaneManagerAtomicTest, CheckPropsAfterModeset) {
ui::DrmOverlayPlaneList overlays;
overlays.push_back(ui::DrmOverlayPlane(fake_buffer_, nullptr));
commit_request.push_back(ui::CrtcCommitRequest::EnableCrtcRequest(
- crtc_properties_[0].id, connector_properties_[0].id, kDefaultMode, &state,
- std::move(overlays)));
+ crtc_properties_[0].id, connector_properties_[0].id, kDefaultMode,
+ gfx::Point(), &state, std::move(overlays)));
EXPECT_TRUE(fake_drm_->plane_manager()->Commit(
std::move(commit_request), DRM_MODE_ATOMIC_ALLOW_MODESET));
@@ -570,7 +611,7 @@ TEST_P(HardwareDisplayPlaneManagerAtomicTest, CheckPropsAfterDisable) {
overlays.push_back(ui::DrmOverlayPlane(fake_buffer_, nullptr));
commit_request.push_back(ui::CrtcCommitRequest::EnableCrtcRequest(
crtc_properties_[0].id, connector_properties_[0].id, kDefaultMode,
- &state, std::move(overlays)));
+ gfx::Point(), &state, std::move(overlays)));
EXPECT_TRUE(fake_drm_->plane_manager()->Commit(
std::move(commit_request), DRM_MODE_ATOMIC_ALLOW_MODESET));
}
@@ -1379,7 +1420,8 @@ class HardwareDisplayPlaneAtomicMock : public ui::HardwareDisplayPlaneAtomic {
const gfx::Rect& crtc_rect,
const gfx::Rect& src_rect,
const gfx::OverlayTransform transform,
- int in_fence_fd) override {
+ int in_fence_fd,
+ uint32_t format_fourcc) override {
framebuffer_ = framebuffer;
return true;
}
diff --git a/chromium/ui/ozone/platform/drm/gpu/mock_drm_device.cc b/chromium/ui/ozone/platform/drm/gpu/mock_drm_device.cc
index bf00ae93cfe..1ef0fe9f11f 100644
--- a/chromium/ui/ozone/platform/drm/gpu/mock_drm_device.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/mock_drm_device.cc
@@ -9,7 +9,9 @@
#include <utility>
#include "base/check.h"
-#include "base/stl_util.h"
+#include "base/containers/contains.h"
+#include "base/containers/flat_map.h"
+#include "base/logging.h"
#include "skia/ext/legacy_display_globals.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkCanvas.h"
@@ -70,6 +72,13 @@ Type* FindObjectById(uint32_t id, std::vector<Type>& properties) {
return it != properties.end() ? &(*it) : nullptr;
}
+// TODO(dnicoara): Generate all IDs internal to MockDrmDevice.
+// For now generate something with a high enough ID to be unique in tests.
+uint32_t GetUniqueNumber() {
+ static uint32_t value_generator = 0xff000000;
+ return ++value_generator;
+}
+
} // namespace
MockDrmDevice::CrtcProperties::CrtcProperties() = default;
@@ -173,6 +182,34 @@ void MockDrmDevice::UpdateState(
connector_properties_ = connector_properties;
plane_properties_ = plane_properties;
property_names_ = property_names;
+
+ // Props IDs shouldn't change throughout a DRM state. Grab it once at
+ // UpdateState.
+ plane_crtc_id_prop_id_ = 0;
+ for (const PlaneProperties& plane_props : plane_properties) {
+ const std::vector<DrmDevice::Property>& props = plane_props.properties;
+ auto it = std::find_if(
+ props.begin(), props.end(),
+ [&names = property_names_](const DrmDevice::Property& prop) {
+ return names.at(prop.id) == "CRTC_ID";
+ });
+ if (it != props.end()) {
+ plane_crtc_id_prop_id_ = it->id;
+ // all planes should have the same prop ID for the name. Break right after
+ // the first one is found.
+ break;
+ }
+ }
+}
+
+void MockDrmDevice::SetModifiersOverhead(
+ base::flat_map<uint64_t /*modifier*/, int /*overhead*/>
+ modifiers_overhead) {
+ modifiers_overhead_ = modifiers_overhead;
+}
+
+void MockDrmDevice::SetSystemLimitOfModifiers(uint64_t limit) {
+ system_watermark_limitations_ = limit;
}
ScopedDrmResourcesPtr MockDrmDevice::GetResources() {
@@ -258,8 +295,9 @@ bool MockDrmDevice::AddFramebuffer2(uint32_t width,
uint32_t* framebuffer,
uint32_t flags) {
add_framebuffer_call_count_++;
- *framebuffer = add_framebuffer_call_count_;
+ *framebuffer = GetUniqueNumber();
framebuffer_ids_.insert(*framebuffer);
+ fb_props_[*framebuffer] = {width, height, modifiers[0]};
return add_framebuffer_expectation_;
}
@@ -269,6 +307,11 @@ bool MockDrmDevice::RemoveFramebuffer(uint32_t framebuffer) {
CHECK(it != framebuffer_ids_.end());
framebuffer_ids_.erase(it);
}
+ {
+ auto it = fb_props_.find(framebuffer);
+ CHECK(it != fb_props_.end());
+ fb_props_.erase(it);
+ }
remove_framebuffer_call_count_++;
std::vector<uint32_t> crtcs_to_clear;
for (auto crtc_fb : crtc_fb_) {
@@ -330,7 +373,7 @@ bool MockDrmDevice::SetProperty(uint32_t connector_id,
ScopedDrmPropertyBlob MockDrmDevice::CreatePropertyBlob(const void* blob,
size_t size) {
- uint32_t id = ++property_id_generator_;
+ uint32_t id = GetUniqueNumber();
allocated_property_blobs_.insert(id);
return std::make_unique<DrmPropertyBlobMetadata>(this, id);
}
@@ -427,25 +470,46 @@ bool MockDrmDevice::CloseBufferHandle(uint32_t handle) {
return true;
}
-bool MockDrmDevice::CommitProperties(
+bool MockDrmDevice::CommitPropertiesInternal(
drmModeAtomicReq* request,
uint32_t flags,
uint32_t crtc_count,
scoped_refptr<PageFlipRequest> page_flip_request) {
+ commit_count_++;
if (flags == kTestModesetFlags)
++test_modeset_count_;
else if (flags == kCommitModesetFlags)
++commit_modeset_count_;
- commit_count_++;
- if (!commit_expectation_)
+ if ((flags & kCommitModesetFlags && !set_crtc_expectation_) ||
+ (flags & DRM_MODE_ATOMIC_NONBLOCK && !commit_expectation_)) {
return false;
+ }
+
+ uint64_t requested_resources = 0;
+ base::flat_map<uint64_t, int> crtc_planes_counter;
for (uint32_t i = 0; i < request->cursor; ++i) {
- bool res = ValidatePropertyValue(request->items[i].property_id,
- request->items[i].value);
- if (!res)
+ const drmModeAtomicReqItem& item = request->items[i];
+ if (!ValidatePropertyValue(item.property_id, item.value))
return false;
+
+ if (fb_props_.find(item.value) != fb_props_.end()) {
+ const FramebufferProps& props = fb_props_[item.value];
+ requested_resources += modifiers_overhead_[props.modifier];
+ }
+
+ if (item.property_id == plane_crtc_id_prop_id_) {
+ if (++crtc_planes_counter[item.value] > 1 &&
+ !modeset_with_overlays_expectation_)
+ return false;
+ }
+ }
+
+ if (requested_resources > system_watermark_limitations_) {
+ LOG(ERROR) << "Requested display configuration exceeds system watermark "
+ "limitations";
+ return false;
}
if (page_flip_request)
@@ -463,6 +527,12 @@ bool MockDrmDevice::CommitProperties(
return false;
}
+ // Count all committed planes at the end just before returning true to reflect
+ // the number of planes that have successfully been committed.
+ last_planes_committed_count_ = 0;
+ for (const auto& planes_counter : crtc_planes_counter)
+ last_planes_committed_count_ += planes_counter.second;
+
return true;
}
diff --git a/chromium/ui/ozone/platform/drm/gpu/mock_drm_device.h b/chromium/ui/ozone/platform/drm/gpu/mock_drm_device.h
index 922d402147c..0c2d823f12a 100644
--- a/chromium/ui/ozone/platform/drm/gpu/mock_drm_device.h
+++ b/chromium/ui/ozone/platform/drm/gpu/mock_drm_device.h
@@ -8,11 +8,13 @@
#include <drm_mode.h>
#include <stddef.h>
#include <stdint.h>
+#include <limits>
#include <map>
#include <memory>
#include <set>
#include <vector>
+#include "base/containers/flat_map.h"
#include "base/containers/queue.h"
#include "base/macros.h"
#include "third_party/skia/include/core/SkRefCnt.h"
@@ -90,11 +92,18 @@ class MockDrmDevice : public DrmDevice {
legacy_gamma_ramp_expectation_ = state;
}
void set_commit_expectation(bool state) { commit_expectation_ = state; }
+ void set_overlay_modeset_expecation(bool state) {
+ modeset_with_overlays_expectation_ = state;
+ }
uint32_t current_framebuffer() const { return current_framebuffer_; }
const std::vector<sk_sp<SkSurface>> buffers() const { return buffers_; }
+ int last_planes_committed_count() const {
+ return last_planes_committed_count_;
+ }
+
uint32_t get_cursor_handle_for_crtc(uint32_t crtc) const {
const auto it = crtc_cursor_map_.find(crtc);
return it != crtc_cursor_map_.end() ? it->second : 0;
@@ -122,6 +131,9 @@ class MockDrmDevice : public DrmDevice {
void SetPropertyBlob(ScopedDrmPropertyBlobPtr blob);
+ void SetModifiersOverhead(base::flat_map<uint64_t, int> modifiers_overhead);
+ void SetSystemLimitOfModifiers(uint64_t limit);
+
// DrmDevice:
ScopedDrmResourcesPtr GetResources() override;
ScopedDrmPlaneResPtr GetPlaneResources() override;
@@ -177,10 +189,6 @@ class MockDrmDevice : public DrmDevice {
bool MapDumbBuffer(uint32_t handle, size_t size, void** pixels) override;
bool UnmapDumbBuffer(void* pixels, size_t size) override;
bool CloseBufferHandle(uint32_t handle) override;
- bool CommitProperties(drmModeAtomicReq* request,
- uint32_t flags,
- uint32_t crtc_count,
- scoped_refptr<PageFlipRequest> callback) override;
bool SetGammaRamp(
uint32_t crtc_id,
const std::vector<display::GammaRampRGBEntry>& lut) override;
@@ -188,8 +196,21 @@ class MockDrmDevice : public DrmDevice {
uint32_t GetFramebufferForCrtc(uint32_t crtc_id) const;
private:
+ // Properties of the plane associated with a fb.
+ struct FramebufferProps {
+ uint32_t width = 0;
+ uint32_t height = 0;
+ uint64_t modifier = 0;
+ };
+
~MockDrmDevice() override;
+ bool CommitPropertiesInternal(
+ drmModeAtomicReq* request,
+ uint32_t flags,
+ uint32_t crtc_count,
+ scoped_refptr<PageFlipRequest> callback) override;
+
bool UpdateProperty(uint32_t id,
uint64_t value,
std::vector<DrmDevice::Property>* properties);
@@ -210,6 +231,7 @@ class MockDrmDevice : public DrmDevice {
int commit_count_ = 0;
int set_object_property_count_ = 0;
int set_gamma_ramp_count_ = 0;
+ int last_planes_committed_count_ = 0;
bool set_crtc_expectation_;
bool add_framebuffer_expectation_;
@@ -217,8 +239,10 @@ class MockDrmDevice : public DrmDevice {
bool create_dumb_buffer_expectation_;
bool legacy_gamma_ramp_expectation_ = false;
bool commit_expectation_ = true;
+ bool modeset_with_overlays_expectation_ = true;
uint32_t current_framebuffer_;
+ uint32_t plane_crtc_id_prop_id_ = 0;
std::vector<sk_sp<SkSurface>> buffers_;
@@ -237,12 +261,14 @@ class MockDrmDevice : public DrmDevice {
std::map<uint32_t, std::string> property_names_;
- // TODO(dnicoara): Generate all IDs internal to MockDrmDevice.
- // For now generate something with a high enough ID to be unique in tests.
- uint32_t property_id_generator_ = 0xff000000;
-
std::set<uint32_t> allocated_property_blobs_;
+ // Props of the plane associated with the generated fb_id.
+ base::flat_map<uint32_t /*fb_id*/, FramebufferProps> fb_props_;
+
+ uint64_t system_watermark_limitations_ = std::numeric_limits<uint64_t>::max();
+ base::flat_map<uint64_t /*modifier*/, int /*overhead*/> modifiers_overhead_;
+
DISALLOW_COPY_AND_ASSIGN(MockDrmDevice);
};
diff --git a/chromium/ui/ozone/platform/drm/gpu/proxy_helpers.cc b/chromium/ui/ozone/platform/drm/gpu/proxy_helpers.cc
index c65c5f6825c..af364e9c0e4 100644
--- a/chromium/ui/ozone/platform/drm/gpu/proxy_helpers.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/proxy_helpers.cc
@@ -6,6 +6,8 @@
#include <utility>
+#include "base/bind.h"
+
namespace ui {
void PostSyncTask(
diff --git a/chromium/ui/ozone/platform/drm/gpu/proxy_helpers.h b/chromium/ui/ozone/platform/drm/gpu/proxy_helpers.h
index d5be9bd74e3..c488aea5a1d 100644
--- a/chromium/ui/ozone/platform/drm/gpu/proxy_helpers.h
+++ b/chromium/ui/ozone/platform/drm/gpu/proxy_helpers.h
@@ -7,7 +7,7 @@
#include <utility>
-#include "base/bind.h"
+#include "base/bind_post_task.h"
#include "base/location.h"
#include "base/memory/ref_counted.h"
#include "base/synchronization/waitable_event.h"
@@ -15,19 +15,6 @@
namespace ui {
-namespace internal {
-
-template <typename... Args>
-void PostAsyncTask(
- const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
- base::OnceCallback<void(Args...)> callback,
- Args... args) {
- auto closure = base::BindOnce(std::move(callback), std::move(args)...);
- task_runner->PostTask(FROM_HERE, std::move(closure));
-}
-
-} // namespace internal
-
// Posts a task to a different thread and blocks waiting for the task to finish
// executing.
void PostSyncTask(
@@ -40,10 +27,10 @@ void PostSyncTask(
// thread).
template <typename... Args>
base::RepeatingCallback<void(Args...)> CreateSafeRepeatingCallback(
- base::RepeatingCallback<void(Args...)> callback) {
- return base::BindRepeating(&internal::PostAsyncTask<Args...>,
- base::ThreadTaskRunnerHandle::Get(),
- std::move(callback));
+ base::RepeatingCallback<void(Args...)> callback,
+ const base::Location& location = FROM_HERE) {
+ return base::BindPostTask(base::ThreadTaskRunnerHandle::Get(),
+ std::move(callback), location);
}
// Creates a OnceCallback that will run |callback| on the calling thread. Useful
@@ -51,10 +38,10 @@ base::RepeatingCallback<void(Args...)> CreateSafeRepeatingCallback(
// task finished (and the callback needs to run on the original thread).
template <typename... Args>
base::OnceCallback<void(Args...)> CreateSafeOnceCallback(
- base::OnceCallback<void(Args...)> callback) {
- return base::BindOnce(&internal::PostAsyncTask<Args...>,
- base::ThreadTaskRunnerHandle::Get(),
- std::move(callback));
+ base::OnceCallback<void(Args...)> callback,
+ const base::Location& location = FROM_HERE) {
+ return base::BindPostTask(base::ThreadTaskRunnerHandle::Get(),
+ std::move(callback), location);
}
} // namespace ui
diff --git a/chromium/ui/ozone/platform/drm/gpu/screen_manager.cc b/chromium/ui/ozone/platform/drm/gpu/screen_manager.cc
index 5a8319fe9cd..127f4d87257 100644
--- a/chromium/ui/ozone/platform/drm/gpu/screen_manager.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/screen_manager.cc
@@ -10,6 +10,7 @@
#include "base/files/platform_file.h"
#include "base/logging.h"
+#include "base/trace_event/trace_event.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "ui/display/types/display_snapshot.h"
@@ -36,7 +37,7 @@ namespace {
bool FillModesetBuffer(const scoped_refptr<DrmDevice>& drm,
HardwareDisplayController* controller,
SkSurface* surface,
- uint32_t fourcc_format) {
+ const std::vector<uint64_t>& modifiers) {
DCHECK(!controller->crtc_controllers().empty());
CrtcController* first_crtc = controller->crtc_controllers()[0].get();
ScopedDrmCrtcPtr saved_crtc(drm->GetCrtc(first_crtc->crtc()));
@@ -45,7 +46,6 @@ bool FillModesetBuffer(const scoped_refptr<DrmDevice>& drm,
return false;
}
- const auto& modifiers = controller->GetFormatModifiers(fourcc_format);
for (const uint64_t modifier : modifiers) {
// A value of 0 means DRM_FORMAT_MOD_NONE. If the CRTC has any other
// modifier (tiling, compression, etc.) we can't read the fb and assume it's
@@ -77,7 +77,7 @@ bool FillModesetBuffer(const scoped_refptr<DrmDevice>& drm,
// Copy the source buffer. Do not perform any blending.
paint.setBlendMode(SkBlendMode::kSrc);
surface->getCanvas()->drawImage(saved_buffer.surface()->makeImageSnapshot(),
- 0, 0, &paint);
+ 0, 0, SkSamplingOptions(), &paint);
return true;
}
@@ -93,19 +93,6 @@ CrtcController* GetCrtcController(HardwareDisplayController* controller,
return nullptr;
}
-std::vector<uint64_t> GetModifiersForPrimaryFormat(
- HardwareDisplayController* controller) {
- gfx::BufferFormat format = display::DisplaySnapshot::PrimaryFormat();
- uint32_t fourcc_format = ui::GetFourCCFormatForOpaqueFramebuffer(format);
- return controller->GetFormatModifiersForModesetting(fourcc_format);
-}
-
-bool AreAllStatusesTrue(base::flat_map<int64_t, bool>& display_statuses) {
- auto it = find_if(display_statuses.begin(), display_statuses.end(),
- [](const auto status) { return status.second == false; });
- return (it == display_statuses.end());
-}
-
} // namespace
ScreenManager::ScreenManager() = default;
@@ -175,6 +162,9 @@ void ScreenManager::AddDisplayController(const scoped_refptr<DrmDevice>& drm,
void ScreenManager::RemoveDisplayControllers(
const CrtcsWithDrmList& controllers_to_remove) {
+ TRACE_EVENT1("drm", "ScreenManager::RemoveDisplayControllers",
+ "display_count", controllers_to_remove.size());
+
// Split them to different lists unique to each DRM Device.
base::flat_map<scoped_refptr<DrmDevice>, CrtcsWithDrmList>
controllers_for_drm_devices;
@@ -223,8 +213,10 @@ void ScreenManager::RemoveDisplayControllers(
UpdateControllerToWindowMapping();
}
-base::flat_map<int64_t, bool> ScreenManager::ConfigureDisplayControllers(
+bool ScreenManager::ConfigureDisplayControllers(
const ControllerConfigsList& controllers_params) {
+ TRACE_EVENT0("drm", "ScreenManager::ConfigureDisplayControllers");
+
// Split them to different lists unique to each DRM Device.
base::flat_map<scoped_refptr<DrmDevice>, ControllerConfigsList>
displays_for_drm_devices;
@@ -238,33 +230,81 @@ base::flat_map<int64_t, bool> ScreenManager::ConfigureDisplayControllers(
displays_for_drm_devices[params.drm].emplace_back(params);
}
- base::flat_map<int64_t, bool> statuses;
+ bool config_success = true;
// Perform display configurations together for the same DRM only.
for (const auto& configs_on_drm : displays_for_drm_devices) {
- auto display_statuses = TestAndModeset(configs_on_drm.second);
- statuses.insert(display_statuses.begin(), display_statuses.end());
+ const ControllerConfigsList& controllers_params = configs_on_drm.second;
+ bool test_modeset = TestAndSetPreferredModifiers(controllers_params) ||
+ TestAndSetLinearModifier(controllers_params);
+ config_success &= test_modeset;
+ if (!test_modeset)
+ continue;
+ bool can_modeset_with_overlays =
+ TestModesetWithOverlays(controllers_params);
+ config_success &= Modeset(controllers_params, can_modeset_with_overlays);
}
- if (AreAllStatusesTrue(statuses))
+ if (config_success)
UpdateControllerToWindowMapping();
- return statuses;
+ return config_success;
}
-base::flat_map<int64_t, bool> ScreenManager::TestAndModeset(
+bool ScreenManager::TestAndSetPreferredModifiers(
const ControllerConfigsList& controllers_params) {
- if (!TestModeset(controllers_params)) {
- base::flat_map<int64_t, bool> statuses;
- for (const auto& params : controllers_params)
- statuses.insert(std::make_pair(params.display_id, false));
- return statuses;
+ TRACE_EVENT1("drm", "ScreenManager::TestAndSetPreferredModifiers",
+ "display_count", controllers_params.size());
+
+ CrtcPreferredModifierMap crtcs_preferred_modifier;
+ CommitRequest commit_request;
+ auto drm = controllers_params[0].drm;
+
+ for (const auto& params : controllers_params) {
+ auto it = FindDisplayController(params.drm, params.crtc);
+ DCHECK(controllers_.end() != it);
+ HardwareDisplayController* controller = it->get();
+
+ if (params.mode) {
+ uint32_t fourcc_format = ui::GetFourCCFormatForOpaqueFramebuffer(
+ display::DisplaySnapshot::PrimaryFormat());
+ std::vector<uint64_t> modifiers =
+ controller->GetFormatModifiersForTestModeset(fourcc_format);
+ // Test with no overlays to go for a lower bandwidth usage.
+ DrmOverlayPlaneList modeset_planes = GetModesetPlanes(
+ controller, gfx::Rect(params.origin, ModeSize(*params.mode)),
+ modifiers, /*include_overlays=*/false, /*is_testing=*/true);
+ if (modeset_planes.empty())
+ return false;
+
+ uint64_t primary_modifier =
+ DrmOverlayPlane::GetPrimaryPlane(modeset_planes)
+ ->buffer->format_modifier();
+ crtcs_preferred_modifier[params.crtc] =
+ std::make_pair(modifiers.empty(), primary_modifier);
+
+ GetModesetControllerProps(&commit_request, controller, params.origin,
+ *params.mode, modeset_planes);
+ } else {
+ controller->GetDisableProps(&commit_request);
+ }
+ }
+
+ if (!drm->plane_manager()->Commit(
+ std::move(commit_request),
+ DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_ALLOW_MODESET)) {
+ return false;
}
- return Modeset(controllers_params);
+ SetPreferredModifiers(controllers_params, crtcs_preferred_modifier);
+ return true;
}
-bool ScreenManager::TestModeset(
+bool ScreenManager::TestAndSetLinearModifier(
const ControllerConfigsList& controllers_params) {
+ TRACE_EVENT1("drm", "ScreenManager::TestAndSetLinearModifier",
+ "display_count", controllers_params.size());
+
+ CrtcPreferredModifierMap crtcs_preferred_modifier;
CommitRequest commit_request;
auto drm = controllers_params[0].drm;
@@ -273,65 +313,151 @@ bool ScreenManager::TestModeset(
DCHECK(controllers_.end() != it);
HardwareDisplayController* controller = it->get();
+ uint32_t fourcc_format = ui::GetFourCCFormatForOpaqueFramebuffer(
+ display::DisplaySnapshot::PrimaryFormat());
+ std::vector<uint64_t> modifiers =
+ controller->GetFormatModifiersForTestModeset(fourcc_format);
+ // Test with an empty list if no preferred modifiers are advertised.
+ // Platforms might not support gbm_bo_create_with_modifiers(). If the
+ // platform doesn't expose modifiers, do not attempt to explicitly request
+ // LINEAR otherwise we might CHECK() when trying to allocate buffers.
+ if (!modifiers.empty())
+ modifiers = std::vector<uint64_t>{DRM_FORMAT_MOD_LINEAR};
+ crtcs_preferred_modifier[params.crtc] =
+ std::make_pair(modifiers.empty(), DRM_FORMAT_MOD_LINEAR);
+
if (params.mode) {
- DrmOverlayPlane primary_plane = GetModesetBuffer(
+ // Test with no overlays to go for a lower bandwidth usage.
+ DrmOverlayPlaneList modeset_planes = GetModesetPlanes(
controller, gfx::Rect(params.origin, ModeSize(*params.mode)),
- GetModifiersForPrimaryFormat(controller));
- if (!primary_plane.buffer)
+ modifiers, /*include_overlays=*/false, /*is_testing=*/true);
+ if (modeset_planes.empty())
return false;
GetModesetControllerProps(&commit_request, controller, params.origin,
- *params.mode, primary_plane);
+ *params.mode, modeset_planes);
+ } else {
+ controller->GetDisableProps(&commit_request);
+ }
+ }
+
+ if (!drm->plane_manager()->Commit(
+ std::move(commit_request),
+ DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_ALLOW_MODESET)) {
+ return false;
+ }
+
+ SetPreferredModifiers(controllers_params, crtcs_preferred_modifier);
+ return true;
+}
+
+void ScreenManager::SetPreferredModifiers(
+ const ControllerConfigsList& controllers_params,
+ const CrtcPreferredModifierMap& crtcs_preferred_modifier) {
+ for (const auto& params : controllers_params) {
+ if (params.mode) {
+ bool was_modifiers_list_empty =
+ crtcs_preferred_modifier.at(params.crtc).first;
+ // No preferred modifiers should be saved as some platforms might not have
+ // bo_create_with_modifiers implemented, this will send the preferred
+ // modifiers list as an empty list.
+ if (!was_modifiers_list_empty) {
+ uint64_t picked_modifier =
+ crtcs_preferred_modifier.at(params.crtc).second;
+ auto it = FindDisplayController(params.drm, params.crtc);
+ DCHECK(*it);
+ it->get()->UpdatePreferredModiferForFormat(
+ display::DisplaySnapshot::PrimaryFormat(), picked_modifier);
+ }
+ }
+ }
+}
+
+bool ScreenManager::TestModesetWithOverlays(
+ const ControllerConfigsList& controllers_params) {
+ TRACE_EVENT1("drm", "ScreenManager::TestModesetWithOverlays", "display_count",
+ controllers_params.size());
+
+ bool does_an_overlay_exist = false;
+
+ CommitRequest commit_request;
+ auto drm = controllers_params[0].drm;
+ for (const auto& params : controllers_params) {
+ auto it = FindDisplayController(params.drm, params.crtc);
+ DCHECK(controllers_.end() != it);
+ HardwareDisplayController* controller = it->get();
+
+ if (params.mode) {
+ uint32_t fourcc_format = GetFourCCFormatForOpaqueFramebuffer(
+ display::DisplaySnapshot::PrimaryFormat());
+ std::vector<uint64_t> modifiers =
+ controller->GetSupportedModifiers(fourcc_format);
+
+ DrmOverlayPlaneList modeset_planes = GetModesetPlanes(
+ controller, gfx::Rect(params.origin, ModeSize(*params.mode)),
+ modifiers, /*include_overlays=*/true, /*is_testing=*/true);
+ DCHECK(!modeset_planes.empty());
+ does_an_overlay_exist |= modeset_planes.size() > 1;
+
+ GetModesetControllerProps(&commit_request, controller, params.origin,
+ *params.mode, modeset_planes);
} else {
controller->GetDisableProps(&commit_request);
}
}
+ // If we have no overlays, report not modesetting with overlays as we haven't
+ // tested with overlays.
+ if (!does_an_overlay_exist)
+ return false;
return drm->plane_manager()->Commit(
std::move(commit_request),
DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_ALLOW_MODESET);
}
-base::flat_map<int64_t, bool> ScreenManager::Modeset(
- const ControllerConfigsList& controllers_params) {
- base::flat_map<int64_t, bool> statuses;
+bool ScreenManager::Modeset(const ControllerConfigsList& controllers_params,
+ bool can_modeset_with_overlays) {
+ TRACE_EVENT2("drm", "ScreenManager::Modeset", "display_count",
+ controllers_params.size(), "modeset_with_overlays",
+ can_modeset_with_overlays);
+
+ CommitRequest commit_request;
+ auto drm = controllers_params[0].drm;
for (const auto& params : controllers_params) {
- // Commit one controller at a time.
- CommitRequest commit_request;
- bool status = true;
if (params.mode) {
auto it = FindDisplayController(params.drm, params.crtc);
DCHECK(controllers_.end() != it);
HardwareDisplayController* controller = it->get();
- DrmOverlayPlane primary_plane = GetModesetBuffer(
- controller, gfx::Rect(params.origin, ModeSize(*params.mode)),
- GetModifiersForPrimaryFormat(controller));
- if (primary_plane.buffer) {
- SetDisplayControllerForEnableAndGetProps(
- &commit_request, params.drm, params.crtc, params.connector,
- params.origin, *params.mode, primary_plane);
- } else {
- status = false;
- }
+ uint32_t fourcc_format = GetFourCCFormatForOpaqueFramebuffer(
+ display::DisplaySnapshot::PrimaryFormat());
+ std::vector<uint64_t> modifiers =
+ controller->GetSupportedModifiers(fourcc_format);
+
+ gfx::Rect bounds = gfx::Rect(params.origin, ModeSize(*params.mode));
+ DrmOverlayPlaneList modeset_planes =
+ GetModesetPlanes(controller, bounds, modifiers,
+ can_modeset_with_overlays, /*is_testing=*/false);
+
+ SetDisplayControllerForEnableAndGetProps(
+ &commit_request, params.drm, params.crtc, params.connector,
+ params.origin, *params.mode, modeset_planes);
} else {
- status = SetDisableDisplayControllerForDisableAndGetProps(
+ bool disable_set = SetDisableDisplayControllerForDisableAndGetProps(
&commit_request, params.drm, params.crtc);
+ if (!disable_set)
+ return false;
}
+ }
- CommitRequest request_for_update = commit_request;
- if (status) {
- status &= params.drm->plane_manager()->Commit(
- std::move(commit_request), DRM_MODE_ATOMIC_ALLOW_MODESET);
- UpdateControllerStateAfterModeset(params, request_for_update, status);
- }
+ bool commit_status = drm->plane_manager()->Commit(
+ commit_request, DRM_MODE_ATOMIC_ALLOW_MODESET);
- statuses.insert(std::make_pair(params.display_id, status));
- }
+ UpdateControllerStateAfterModeset(drm, commit_request, commit_status);
- return statuses;
+ return commit_status;
}
void ScreenManager::SetDisplayControllerForEnableAndGetProps(
@@ -341,7 +467,7 @@ void ScreenManager::SetDisplayControllerForEnableAndGetProps(
uint32_t connector,
const gfx::Point& origin,
const drmModeModeInfo& mode,
- const DrmOverlayPlane& primary) {
+ const DrmOverlayPlaneList& modeset_planes) {
HardwareDisplayControllers::iterator it = FindDisplayController(drm, crtc);
DCHECK(controllers_.end() != it)
<< "Display controller (crtc=" << crtc << ") doesn't exist.";
@@ -358,10 +484,10 @@ void ScreenManager::SetDisplayControllerForEnableAndGetProps(
// Otherwise it could apply a mode with the same resolution and refresh
// rate but with different timings to the other CRTC.
GetModesetControllerProps(commit_request, controller,
- controller->origin(), mode, primary);
+ controller->origin(), mode, modeset_planes);
} else {
// Just get props to re-enable the controller re-using the current state.
- GetEnableControllerProps(commit_request, controller, primary);
+ GetEnableControllerProps(commit_request, controller, modeset_planes);
}
return;
}
@@ -377,7 +503,8 @@ void ScreenManager::SetDisplayControllerForEnableAndGetProps(
controller = it->get();
}
- GetModesetControllerProps(commit_request, controller, origin, mode, primary);
+ GetModesetControllerProps(commit_request, controller, origin, mode,
+ modeset_planes);
}
bool ScreenManager::SetDisableDisplayControllerForDisableAndGetProps(
@@ -402,31 +529,32 @@ bool ScreenManager::SetDisableDisplayControllerForDisableAndGetProps(
}
void ScreenManager::UpdateControllerStateAfterModeset(
- const ControllerConfigParams& config,
+ const scoped_refptr<DrmDevice>& drm,
const CommitRequest& commit_request,
bool did_succeed) {
- for (auto& crtc_request : commit_request) {
+ for (const CrtcCommitRequest& crtc_request : commit_request) {
bool was_enabled = (crtc_request.should_enable());
HardwareDisplayControllers::iterator it =
- FindDisplayController(config.drm, crtc_request.crtc_id());
+ FindDisplayController(drm, crtc_request.crtc_id());
if (it != controllers_.end()) {
- it->get()->UpdateState(was_enabled, DrmOverlayPlane::GetPrimaryPlane(
- crtc_request.overlays()));
+ it->get()->UpdateState(crtc_request);
// If the CRTC is mirrored, move it to the mirror controller.
if (did_succeed && was_enabled)
- HandleMirrorIfExists(config, it);
+ HandleMirrorIfExists(drm, crtc_request, it);
}
}
}
void ScreenManager::HandleMirrorIfExists(
- const ControllerConfigParams& config,
+ const scoped_refptr<DrmDevice>& drm,
+ const CrtcCommitRequest& crtc_request,
const HardwareDisplayControllers::iterator& controller) {
- gfx::Rect modeset_bounds(config.origin, ModeSize(*config.mode));
+ gfx::Rect modeset_bounds(crtc_request.origin(),
+ ModeSize(crtc_request.mode()));
HardwareDisplayControllers::iterator mirror =
- FindActiveDisplayControllerByLocation(config.drm, modeset_bounds);
+ FindActiveDisplayControllerByLocation(drm, modeset_bounds);
// TODO(dnicoara): This is hacky, instead the DrmDisplay and
// CrtcController should be merged and picking the mode should be done
// properly within HardwareDisplayController.
@@ -434,7 +562,7 @@ void ScreenManager::HandleMirrorIfExists(
// TODO(markyacoub): RemoveCrtc makes a blocking commit to
// DisableOverlayPlanes. This should be redesigned and included as part of
// the Modeset commit.
- (*mirror)->AddCrtc((*controller)->RemoveCrtc(config.drm, config.crtc));
+ (*mirror)->AddCrtc((*controller)->RemoveCrtc(drm, crtc_request.crtc_id()));
controllers_.erase(controller);
}
}
@@ -541,24 +669,30 @@ void ScreenManager::UpdateControllerToWindowMapping() {
// otherwise the controller may be waiting for a page flip while the window
// tries to schedule another buffer.
if (should_enable) {
- DrmOverlayPlane primary_plane = GetModesetBuffer(
+ uint32_t fourcc_format = ui::GetFourCCFormatForOpaqueFramebuffer(
+ display::DisplaySnapshot::PrimaryFormat());
+ std::vector<uint64_t> modifiers =
+ controller->GetSupportedModifiers(fourcc_format);
+ DrmOverlayPlaneList modeset_planes = GetModesetPlanes(
controller,
- gfx::Rect(controller->origin(), controller->GetModeSize()),
- GetModifiersForPrimaryFormat(controller));
- DCHECK(primary_plane.buffer);
+ gfx::Rect(controller->origin(), controller->GetModeSize()), modifiers,
+ /*include_overlays=*/true, /*is_testing=*/false);
+ DCHECK(!modeset_planes.empty());
CommitRequest commit_request;
- GetEnableControllerProps(&commit_request, controller, primary_plane);
+ GetEnableControllerProps(&commit_request, controller, modeset_planes);
controller->GetDrmDevice()->plane_manager()->Commit(
std::move(commit_request), DRM_MODE_ATOMIC_ALLOW_MODESET);
}
}
}
-DrmOverlayPlane ScreenManager::GetModesetBuffer(
+DrmOverlayPlaneList ScreenManager::GetModesetPlanes(
HardwareDisplayController* controller,
const gfx::Rect& bounds,
- const std::vector<uint64_t>& modifiers) {
+ const std::vector<uint64_t>& modifiers,
+ bool include_overlays,
+ bool is_testing) {
scoped_refptr<DrmDevice> drm = controller->GetDrmDevice();
uint32_t fourcc_format = ui::GetFourCCFormatForOpaqueFramebuffer(
display::DisplaySnapshot::PrimaryFormat());
@@ -569,19 +703,27 @@ DrmOverlayPlane ScreenManager::GetModesetBuffer(
fourcc_format, bounds.size(), GBM_BO_USE_SCANOUT, modifiers);
if (!buffer) {
LOG(ERROR) << "Failed to create scanout buffer";
- return DrmOverlayPlane::Error();
+ return DrmOverlayPlaneList();
}
// If the current primary plane matches what we need for the next page flip,
- // we can clone it.
+ // clone all last_submitted_planes (matching primary + overlays).
DrmWindow* window = FindWindowAt(bounds);
if (window) {
- const DrmOverlayPlane* primary = window->GetLastModesetBuffer();
- const DrmDevice* drm = controller->GetDrmDevice().get();
+ const DrmOverlayPlaneList& last_submitted_planes =
+ window->last_submitted_planes();
+ const DrmOverlayPlane* primary =
+ DrmOverlayPlane::GetPrimaryPlane(last_submitted_planes);
if (primary && primary->buffer->size() == bounds.size() &&
- primary->buffer->drm_device() == drm) {
- if (primary->buffer->format_modifier() == buffer->GetFormatModifier())
- return primary->Clone();
+ primary->buffer->drm_device() == controller->GetDrmDevice().get() &&
+ primary->buffer->format_modifier() == buffer->GetFormatModifier()) {
+ if (include_overlays) {
+ return DrmOverlayPlane::Clone(last_submitted_planes);
+ } else {
+ DrmOverlayPlaneList modeset_plane;
+ modeset_plane.push_back(primary->Clone());
+ return modeset_plane;
+ }
}
}
@@ -589,28 +731,32 @@ DrmOverlayPlane ScreenManager::GetModesetBuffer(
drm, buffer.get(), buffer->GetSize(), modifiers);
if (!framebuffer) {
LOG(ERROR) << "Failed to add framebuffer for scanout buffer";
- return DrmOverlayPlane::Error();
+ return DrmOverlayPlaneList();
}
- sk_sp<SkSurface> surface = buffer->GetSurface();
- if (!surface) {
- VLOG(2) << "Can't get a SkSurface from the modeset gbm buffer.";
- } else if (!FillModesetBuffer(drm, controller, surface.get(),
- buffer->GetFormat())) {
- // If we fail to fill the modeset buffer, clear it black to avoid displaying
- // an uninitialized framebuffer.
- surface->getCanvas()->clear(SK_ColorBLACK);
+ if (!is_testing) {
+ sk_sp<SkSurface> surface = buffer->GetSurface();
+ if (!surface) {
+ VLOG(2) << "Can't get a SkSurface from the modeset gbm buffer.";
+ } else if (!FillModesetBuffer(drm, controller, surface.get(), modifiers)) {
+ // If we fail to fill the modeset buffer, clear it black to avoid
+ // displaying an uninitialized framebuffer.
+ surface->getCanvas()->clear(SK_ColorBLACK);
+ }
}
- return DrmOverlayPlane(framebuffer, nullptr);
+
+ DrmOverlayPlaneList modeset_planes;
+ modeset_planes.emplace_back(framebuffer, nullptr);
+ return modeset_planes;
}
void ScreenManager::GetEnableControllerProps(
CommitRequest* commit_request,
HardwareDisplayController* controller,
- const DrmOverlayPlane& primary) {
+ const DrmOverlayPlaneList& modeset_planes) {
DCHECK(!controller->crtc_controllers().empty());
- controller->GetEnableProps(commit_request, primary);
+ controller->GetEnableProps(commit_request, modeset_planes);
}
void ScreenManager::GetModesetControllerProps(
@@ -618,11 +764,11 @@ void ScreenManager::GetModesetControllerProps(
HardwareDisplayController* controller,
const gfx::Point& origin,
const drmModeModeInfo& mode,
- const DrmOverlayPlane& primary) {
+ const DrmOverlayPlaneList& modeset_planes) {
DCHECK(!controller->crtc_controllers().empty());
controller->set_origin(origin);
- controller->GetModesetProps(commit_request, primary, mode);
+ controller->GetModesetProps(commit_request, modeset_planes, mode);
}
DrmWindow* ScreenManager::FindWindowAt(const gfx::Rect& bounds) const {
diff --git a/chromium/ui/ozone/platform/drm/gpu/screen_manager.h b/chromium/ui/ozone/platform/drm/gpu/screen_manager.h
index d7ac2810b53..c102c52525d 100644
--- a/chromium/ui/ozone/platform/drm/gpu/screen_manager.h
+++ b/chromium/ui/ozone/platform/drm/gpu/screen_manager.h
@@ -68,7 +68,7 @@ class ScreenManager {
void RemoveDisplayControllers(const CrtcsWithDrmList& controllers_to_remove);
// Enables/Disables the display controller based on if a mode exists.
- base::flat_map<int64_t, bool> ConfigureDisplayControllers(
+ bool ConfigureDisplayControllers(
const ControllerConfigsList& controllers_params);
// Returns a reference to the display controller configured to display within
@@ -98,6 +98,9 @@ class ScreenManager {
std::vector<std::unique_ptr<HardwareDisplayController>>;
using WidgetToWindowMap =
std::unordered_map<gfx::AcceleratedWidget, std::unique_ptr<DrmWindow>>;
+ using CrtcPreferredModifierMap = base::flat_map<
+ uint32_t /*crtc_is*/,
+ std::pair<bool /*modifiers_list.empty()*/, uint64_t /*picked_modifier*/>>;
// Returns an iterator into |controllers_| for the controller identified by
// (|crtc|, |connector|).
@@ -105,13 +108,21 @@ class ScreenManager {
const scoped_refptr<DrmDevice>& drm,
uint32_t crtc);
- base::flat_map<int64_t, bool> TestAndModeset(
+ bool TestAndSetPreferredModifiers(
const ControllerConfigsList& controllers_params);
-
- bool TestModeset(const ControllerConfigsList& controllers_params);
-
- base::flat_map<int64_t, bool> Modeset(
+ bool TestAndSetLinearModifier(
const ControllerConfigsList& controllers_params);
+ // Setting the Preferred modifiers that passed from one of the Modeset Test
+ // functions. The preferred modifiers are used in Modeset.
+ void SetPreferredModifiers(
+ const ControllerConfigsList& controllers_params,
+ const CrtcPreferredModifierMap& crtcs_preferred_modifier);
+ // The planes used for modesetting can have overlays beside the primary, test
+ // if we can modeset with them. If not, return false to indicate that we must
+ // only use the primary plane.
+ bool TestModesetWithOverlays(const ControllerConfigsList& controllers_params);
+ bool Modeset(const ControllerConfigsList& controllers_params,
+ bool can_modeset_with_overlays);
// Configures a display controller to be enabled. The display controller is
// identified by (|crtc|, |connector|) and the controller is to be modeset
@@ -123,7 +134,7 @@ class ScreenManager {
uint32_t connector,
const gfx::Point& origin,
const drmModeModeInfo& mode,
- const DrmOverlayPlane& primary);
+ const DrmOverlayPlaneList& modeset_planes);
// Configures a display controller to be disabled. The display controller is
// identified by |crtc|. Controller modeset props are added into
@@ -135,12 +146,13 @@ class ScreenManager {
const scoped_refptr<DrmDevice>& drm,
uint32_t crtc);
- void UpdateControllerStateAfterModeset(const ControllerConfigParams& config,
+ void UpdateControllerStateAfterModeset(const scoped_refptr<DrmDevice>& drm,
const CommitRequest& commit_request,
bool did_succeed);
void HandleMirrorIfExists(
- const ControllerConfigParams& config,
+ const scoped_refptr<DrmDevice>& drm,
+ const CrtcCommitRequest& crtc_request,
const HardwareDisplayControllers::iterator& controller);
// Returns an iterator into |controllers_| for the controller located at
@@ -154,19 +166,21 @@ class ScreenManager {
const scoped_refptr<DrmDevice>& drm,
const gfx::Rect& bounds);
- DrmOverlayPlane GetModesetBuffer(HardwareDisplayController* controller,
- const gfx::Rect& bounds,
- const std::vector<uint64_t>& modifiers);
+ DrmOverlayPlaneList GetModesetPlanes(HardwareDisplayController* controller,
+ const gfx::Rect& bounds,
+ const std::vector<uint64_t>& modifiers,
+ bool include_overlays,
+ bool is_testing);
// Gets props for modesetting the |controller| using |origin| and |mode|.
void GetModesetControllerProps(CommitRequest* commit_request,
HardwareDisplayController* controller,
const gfx::Point& origin,
const drmModeModeInfo& mode,
- const DrmOverlayPlane& primary);
+ const DrmOverlayPlaneList& modeset_planes);
void GetEnableControllerProps(CommitRequest* commit_request,
HardwareDisplayController* controller,
- const DrmOverlayPlane& primary);
+ const DrmOverlayPlaneList& modeset_planes);
DrmWindow* FindWindowAt(const gfx::Rect& bounds) const;
diff --git a/chromium/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc b/chromium/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc
index d4a1a691a1e..a98d358da52 100644
--- a/chromium/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc
@@ -47,6 +47,7 @@ constexpr uint32_t kSecondaryConnector = kConnectorIdBase + 1;
constexpr uint32_t kPlaneIdBase = 300;
constexpr uint32_t kInFormatsBlobPropIdBase = 400;
+constexpr uint32_t kFbIdPropId = 3005;
constexpr uint32_t kTypePropId = 3010;
constexpr uint32_t kInFormatsPropId = 3011;
@@ -81,7 +82,8 @@ class ScreenManagerTest : public testing::Test {
void InitializeDrmState(ui::MockDrmDevice* drm,
const std::vector<CrtcState>& crtc_states,
- bool is_atomic = true) {
+ bool is_atomic,
+ bool use_modifiers_list = false) {
std::vector<ui::MockDrmDevice::CrtcProperties> crtc_properties(
crtc_states.size());
std::map<uint32_t, std::string> crtc_property_names = {
@@ -109,7 +111,7 @@ class ScreenManagerTest : public testing::Test {
{3002, "CRTC_Y"},
{3003, "CRTC_W"},
{3004, "CRTC_H"},
- {3005, "FB_ID"},
+ {kFbIdPropId, "FB_ID"},
{3006, "SRC_X"},
{3007, "SRC_Y"},
{3008, "SRC_W"},
@@ -143,9 +145,17 @@ class ScreenManagerTest : public testing::Test {
: DRM_PLANE_TYPE_OVERLAY;
} else if (pair.first == kInFormatsPropId) {
value = property_id++;
+ std::vector<drm_format_modifier> drm_format_modifiers;
+ if (use_modifiers_list) {
+ for (const auto modifier : supported_modifiers_) {
+ drm_format_modifiers.push_back(
+ {/*formats=*/1, /*offset=*/0, /*pad=*/0, modifier});
+ }
+ }
+
drm->SetPropertyBlob(ui::MockDrmDevice::AllocateInFormatsBlob(
value, crtc_states[crtc_idx].planes[plane_idx].formats,
- std::vector<drm_format_modifier>()));
+ std::move(drm_format_modifiers)));
}
crtc_plane_properties[plane_idx].properties.push_back(
@@ -165,12 +175,15 @@ class ScreenManagerTest : public testing::Test {
connector_property_names.end());
property_names.insert(plane_property_names.begin(),
plane_property_names.end());
+
+ drm->SetModifiersOverhead(modifiers_overhead_);
drm->InitializeState(crtc_properties, connector_properties,
plane_properties, property_names, is_atomic);
}
void InitializeDrmStateWithDefault(ui::MockDrmDevice* drm,
- bool is_atomic = true) {
+ bool is_atomic,
+ bool use_modifiers_list = false) {
// A Sample of CRTC states.
std::vector<CrtcState> crtc_states = {
{/* .planes = */
@@ -182,11 +195,12 @@ class ScreenManagerTest : public testing::Test {
{/* .formats = */ {DRM_FORMAT_XRGB8888}},
}},
};
- InitializeDrmState(drm, crtc_states, is_atomic);
+ InitializeDrmState(drm, crtc_states, is_atomic, use_modifiers_list);
}
void SetUp() override {
auto gbm = std::make_unique<ui::MockGbmDevice>();
+ supported_modifiers_ = gbm->GetSupportedModifiers();
drm_ = new ui::MockDrmDevice(std::move(gbm));
device_manager_ = std::make_unique<ui::DrmDeviceManager>(nullptr);
screen_manager_ = std::make_unique<ui::ScreenManager>();
@@ -218,6 +232,10 @@ class ScreenManagerTest : public testing::Test {
scoped_refptr<ui::MockDrmDevice> drm_;
std::unique_ptr<ui::DrmDeviceManager> device_manager_;
std::unique_ptr<ui::ScreenManager> screen_manager_;
+ std::vector<uint64_t> supported_modifiers_;
+ base::flat_map<uint64_t /*modifier*/, int /*overhead*/> modifiers_overhead_{
+ {DRM_FORMAT_MOD_LINEAR, 1},
+ {I915_FORMAT_MOD_Yf_TILED_CCS, 100}};
private:
DISALLOW_COPY_AND_ASSIGN(ScreenManagerTest);
@@ -231,7 +249,7 @@ TEST_F(ScreenManagerTest, CheckWithNoControllers) {
}
TEST_F(ScreenManagerTest, CheckWithValidController) {
- InitializeDrmStateWithDefault(drm_.get());
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
@@ -252,7 +270,7 @@ TEST_F(ScreenManagerTest, CheckWithValidController) {
}
TEST_F(ScreenManagerTest, CheckWithInvalidBounds) {
- InitializeDrmStateWithDefault(drm_.get());
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
@@ -268,7 +286,7 @@ TEST_F(ScreenManagerTest, CheckWithInvalidBounds) {
}
TEST_F(ScreenManagerTest, CheckForSecondValidController) {
- InitializeDrmStateWithDefault(drm_.get());
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
@@ -287,14 +305,104 @@ TEST_F(ScreenManagerTest, CheckForSecondValidController) {
screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
EXPECT_EQ(drm_->get_test_modeset_count(), 1);
- EXPECT_EQ(drm_->get_commit_modeset_count(), 2);
+ EXPECT_EQ(drm_->get_commit_modeset_count(), 1);
EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
EXPECT_TRUE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
}
+TEST_F(ScreenManagerTest, CheckMultipleDisplaysWithinModifiersLimit) {
+ int max_supported_displays_with_modifier = 2;
+ drm_->SetSystemLimitOfModifiers(
+ modifiers_overhead_[I915_FORMAT_MOD_Yf_TILED_CCS] *
+ max_supported_displays_with_modifier);
+
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true,
+ /*use_modifiers_list=*/true);
+
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+ screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
+ kSecondaryConnector);
+
+ ScreenManager::ControllerConfigsList controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ drmModeModeInfo secondary_mode = kDefaultMode;
+ controllers_to_enable.emplace_back(
+ kSecondaryDisplayId, drm_, kSecondaryCrtc, kSecondaryConnector,
+ GetSecondaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(secondary_mode));
+ EXPECT_TRUE(
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable));
+
+ EXPECT_EQ(drm_->get_test_modeset_count(), 1);
+ EXPECT_EQ(drm_->get_commit_modeset_count(), 1);
+}
+
+TEST_F(ScreenManagerTest, CheckMultipleDisplaysOutsideModifiersLimit) {
+ int max_supported_displays_with_modifier = 2;
+ drm_->SetSystemLimitOfModifiers(modifiers_overhead_[DRM_FORMAT_MOD_LINEAR] *
+ max_supported_displays_with_modifier);
+
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true,
+ /*use_modifiers_list=*/true);
+
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+ screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
+ kSecondaryConnector);
+
+ ScreenManager::ControllerConfigsList controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ drmModeModeInfo secondary_mode = kDefaultMode;
+ controllers_to_enable.emplace_back(
+ kSecondaryDisplayId, drm_, kSecondaryCrtc, kSecondaryConnector,
+ GetSecondaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(secondary_mode));
+ EXPECT_TRUE(
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable));
+
+ // Testing for a failed test-modeset with modifiers + a fallback to Linear
+ // Modifier and a modeset commit.
+ EXPECT_EQ(drm_->get_test_modeset_count(), 2);
+ EXPECT_EQ(drm_->get_commit_modeset_count(), 1);
+}
+
+TEST_F(ScreenManagerTest, CheckDisplaysWith0Limit) {
+ drm_->SetSystemLimitOfModifiers(0);
+
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true,
+ /*use_modifiers_list=*/true);
+
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+ screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
+ kSecondaryConnector);
+
+ ScreenManager::ControllerConfigsList controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ drmModeModeInfo secondary_mode = kDefaultMode;
+ controllers_to_enable.emplace_back(
+ kSecondaryDisplayId, drm_, kSecondaryCrtc, kSecondaryConnector,
+ GetSecondaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(secondary_mode));
+ EXPECT_FALSE(
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable));
+
+ // Testing for a failed test-modeset with modifiers + failed test-modeset with
+ // Linear Modifier and no modeset due to failed tests.
+ EXPECT_EQ(drm_->get_test_modeset_count(), 2);
+ EXPECT_EQ(drm_->get_commit_modeset_count(), 0);
+}
+
TEST_F(ScreenManagerTest, CheckControllerAfterItIsRemoved) {
- InitializeDrmStateWithDefault(drm_.get());
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
@@ -314,7 +422,7 @@ TEST_F(ScreenManagerTest, CheckControllerAfterItIsRemoved) {
}
TEST_F(ScreenManagerTest, CheckControllerAfterDisabled) {
- InitializeDrmStateWithDefault(drm_.get());
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
// Enable
@@ -344,7 +452,7 @@ TEST_F(ScreenManagerTest, CheckControllerAfterDisabled) {
}
TEST_F(ScreenManagerTest, CheckMultipleControllersAfterBeingRemoved) {
- InitializeDrmStateWithDefault(drm_.get());
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
@@ -375,7 +483,7 @@ TEST_F(ScreenManagerTest, CheckMultipleControllersAfterBeingRemoved) {
}
TEST_F(ScreenManagerTest, CheckMultipleControllersAfterBeingDisabled) {
- InitializeDrmStateWithDefault(drm_.get());
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
kSecondaryConnector);
@@ -407,7 +515,7 @@ TEST_F(ScreenManagerTest, CheckMultipleControllersAfterBeingDisabled) {
EXPECT_EQ(drm_->get_test_modeset_count(),
test_modeset_count_before_disable + 1);
EXPECT_EQ(drm_->get_commit_modeset_count(),
- commit_modeset_count_before_disable + 2);
+ commit_modeset_count_before_disable + 1);
EXPECT_FALSE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
EXPECT_FALSE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
@@ -442,7 +550,7 @@ TEST_F(ScreenManagerTest, CheckDuplicateConfiguration) {
}
TEST_F(ScreenManagerTest, CheckChangingMode) {
- InitializeDrmStateWithDefault(drm_.get());
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
@@ -478,7 +586,7 @@ TEST_F(ScreenManagerTest, CheckChangingMode) {
}
TEST_F(ScreenManagerTest, CheckForControllersInMirroredMode) {
- InitializeDrmStateWithDefault(drm_.get());
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
@@ -517,7 +625,7 @@ TEST_F(ScreenManagerTest, CheckMirrorModeTransitions) {
},
},
};
- InitializeDrmState(drm_.get(), crtc_states);
+ InitializeDrmState(drm_.get(), crtc_states, /*is_atomic=*/true);
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
@@ -574,7 +682,7 @@ TEST_F(ScreenManagerTest, CheckMirrorModeTransitions) {
// Make sure we're using each display's mode when doing mirror mode otherwise
// the timings may be off.
TEST_F(ScreenManagerTest, CheckMirrorModeModesettingWithDisplaysMode) {
- InitializeDrmStateWithDefault(drm_.get());
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
@@ -609,7 +717,7 @@ TEST_F(ScreenManagerTest, CheckMirrorModeModesettingWithDisplaysMode) {
}
TEST_F(ScreenManagerTest, MonitorGoneInMirrorMode) {
- InitializeDrmStateWithDefault(drm_.get());
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
@@ -641,23 +749,29 @@ TEST_F(ScreenManagerTest, MonitorGoneInMirrorMode) {
}
TEST_F(ScreenManagerTest, MonitorDisabledInMirrorMode) {
- InitializeDrmStateWithDefault(drm_.get());
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
kSecondaryConnector);
- ScreenManager::ControllerConfigsList controllers_to_enable;
- controllers_to_enable.emplace_back(
- kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
- GetPrimaryBounds().origin(),
- std::make_unique<drmModeModeInfo>(kDefaultMode));
- drmModeModeInfo secondary_mode = kDefaultMode;
- controllers_to_enable.emplace_back(
- kSecondaryDisplayId, drm_, kSecondaryCrtc, kSecondaryConnector,
- GetPrimaryBounds().origin(),
- std::make_unique<drmModeModeInfo>(secondary_mode));
+ // Enable in Mirror Mode.
+ {
+ ScreenManager::ControllerConfigsList controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ drmModeModeInfo secondary_mode = kDefaultMode;
+ controllers_to_enable.emplace_back(
+ kSecondaryDisplayId, drm_, kSecondaryCrtc, kSecondaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(secondary_mode));
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
+ }
+
// Disable display Controller.
+ ScreenManager::ControllerConfigsList controllers_to_enable;
controllers_to_enable.emplace_back(0, drm_, kSecondaryCrtc, 0, gfx::Point(),
nullptr);
screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
@@ -672,7 +786,7 @@ TEST_F(ScreenManagerTest, MonitorDisabledInMirrorMode) {
}
TEST_F(ScreenManagerTest, DoNotEnterMirrorModeUnlessSameBounds) {
- InitializeDrmStateWithDefault(drm_.get());
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
@@ -741,7 +855,7 @@ TEST_F(ScreenManagerTest, ReuseFramebufferIfDisabledThenReEnabled) {
}
TEST_F(ScreenManagerTest, CheckMirrorModeAfterBeginReEnabled) {
- InitializeDrmStateWithDefault(drm_.get());
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
@@ -839,8 +953,8 @@ TEST_F(ScreenManagerTest,
scoped_refptr<ui::MockDrmDevice> drm2 =
new ui::MockDrmDevice(std::move(gbm_device));
- InitializeDrmStateWithDefault(drm_.get());
- InitializeDrmStateWithDefault(drm2.get());
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
+ InitializeDrmStateWithDefault(drm2.get(), /*is_atomic=*/true);
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
screen_manager_->AddDisplayController(drm2, kPrimaryCrtc, kPrimaryConnector);
@@ -868,7 +982,7 @@ TEST_F(ScreenManagerTest,
}
TEST_F(ScreenManagerTest, CheckControllerToWindowMappingWithSameBounds) {
- InitializeDrmStateWithDefault(drm_.get());
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
std::unique_ptr<ui::DrmWindow> window(
new ui::DrmWindow(1, device_manager_.get(), screen_manager_.get()));
@@ -891,7 +1005,7 @@ TEST_F(ScreenManagerTest, CheckControllerToWindowMappingWithSameBounds) {
}
TEST_F(ScreenManagerTest, CheckControllerToWindowMappingWithDifferentBounds) {
- InitializeDrmStateWithDefault(drm_.get());
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
std::unique_ptr<ui::DrmWindow> window(
new ui::DrmWindow(1, device_manager_.get(), screen_manager_.get()));
@@ -917,7 +1031,7 @@ TEST_F(ScreenManagerTest, CheckControllerToWindowMappingWithDifferentBounds) {
TEST_F(ScreenManagerTest,
CheckControllerToWindowMappingWithOverlappingWindows) {
- InitializeDrmStateWithDefault(drm_.get());
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
const size_t kWindowCount = 2;
for (size_t i = 1; i < kWindowCount + 1; ++i) {
@@ -948,7 +1062,7 @@ TEST_F(ScreenManagerTest,
}
TEST_F(ScreenManagerTest, ShouldDissociateWindowOnControllerRemoval) {
- InitializeDrmStateWithDefault(drm_.get());
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
gfx::AcceleratedWidget window_id = 1;
std::unique_ptr<ui::DrmWindow> window(new ui::DrmWindow(
@@ -1105,12 +1219,12 @@ TEST_F(ScreenManagerTest, ShouldNotHardwareMirrorDifferentDrmDevices) {
auto gbm_device1 = std::make_unique<MockGbmDevice>();
auto drm_device1 =
base::MakeRefCounted<MockDrmDevice>(std::move(gbm_device1));
- InitializeDrmStateWithDefault(drm_device1.get());
+ InitializeDrmStateWithDefault(drm_device1.get(), /*is_atomic=*/true);
auto gbm_device2 = std::make_unique<MockGbmDevice>();
auto drm_device2 =
base::MakeRefCounted<MockDrmDevice>(std::move(gbm_device2));
- InitializeDrmStateWithDefault(drm_device2.get());
+ InitializeDrmStateWithDefault(drm_device2.get(), /*is_atomic=*/true);
DrmDeviceManager drm_device_manager(nullptr);
ScreenManager screen_manager;
@@ -1310,4 +1424,315 @@ TEST_F(ScreenManagerTest, ShouldNotUnbindFramebufferOnJoiningMirror) {
screen_manager.RemoveWindow(1)->Shutdown();
}
+TEST_F(ScreenManagerTest, DrmFramebufferSequenceIdIncrementingAtModeset) {
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
+
+ scoped_refptr<DrmFramebuffer> pre_modeset_buffer =
+ CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size());
+ CHECK_EQ(pre_modeset_buffer->modeset_sequence_id_at_allocation(), 0);
+
+ // Successful modeset
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+ {
+ ScreenManager::ControllerConfigsList controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ ASSERT_TRUE(
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable));
+ }
+
+ scoped_refptr<DrmFramebuffer> first_post_modeset_buffer =
+ CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size());
+ CHECK_EQ(first_post_modeset_buffer->modeset_sequence_id_at_allocation(), 1);
+ CHECK_EQ(pre_modeset_buffer->modeset_sequence_id_at_allocation(), 0);
+
+ // Unsuccessful modeset
+ {
+ drm_->set_set_crtc_expectation(false);
+ ScreenManager::ControllerConfigsList controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetSecondaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ ASSERT_FALSE(
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable));
+ }
+
+ scoped_refptr<DrmFramebuffer> second_post_modeset_buffer =
+ CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size());
+ CHECK_EQ(second_post_modeset_buffer->modeset_sequence_id_at_allocation(), 1);
+ CHECK_EQ(first_post_modeset_buffer->modeset_sequence_id_at_allocation(), 1);
+ CHECK_EQ(pre_modeset_buffer->modeset_sequence_id_at_allocation(), 0);
+}
+
+TEST_F(ScreenManagerTest, CloningPlanesOnModeset) {
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
+
+ std::unique_ptr<ui::DrmWindow> window(
+ new ui::DrmWindow(1, device_manager_.get(), screen_manager_.get()));
+ window->Initialize();
+ window->SetBounds(GetPrimaryBounds());
+ scoped_refptr<DrmFramebuffer> buffer =
+ CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size());
+ ui::DrmOverlayPlaneList planes;
+ planes.push_back(ui::DrmOverlayPlane(buffer, nullptr));
+ window->SchedulePageFlip(std::move(planes), base::DoNothing(),
+ base::DoNothing());
+ screen_manager_->AddWindow(1, std::move(window));
+
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+ ScreenManager::ControllerConfigsList controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ ASSERT_TRUE(
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable));
+
+ EXPECT_TRUE(base::Contains(drm_->plane_manager()
+ ->GetCrtcStateForCrtcId(kPrimaryCrtc)
+ .modeset_framebuffers,
+ buffer));
+
+ window = screen_manager_->RemoveWindow(1);
+ window->Shutdown();
+}
+
+TEST_F(ScreenManagerTest, CloningMultiplePlanesOnModeset) {
+ std::vector<CrtcState> crtc_states = {{
+ /* .planes = */
+ {
+ {/* .formats = */ {DRM_FORMAT_XRGB8888}},
+ {/* .formats = */ {DRM_FORMAT_XRGB8888}},
+ },
+ }};
+ InitializeDrmState(drm_.get(), crtc_states, /*is_atomic=*/true);
+
+ std::unique_ptr<ui::DrmWindow> window(
+ new ui::DrmWindow(1, device_manager_.get(), screen_manager_.get()));
+ window->Initialize();
+ window->SetBounds(GetPrimaryBounds());
+ scoped_refptr<DrmFramebuffer> primary =
+ CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size());
+ scoped_refptr<DrmFramebuffer> overlay =
+ CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size());
+ ui::DrmOverlayPlaneList planes;
+ planes.push_back(ui::DrmOverlayPlane(primary, nullptr));
+ planes.push_back(ui::DrmOverlayPlane(overlay, nullptr));
+ window->SchedulePageFlip(std::move(planes), base::DoNothing(),
+ base::DoNothing());
+ screen_manager_->AddWindow(1, std::move(window));
+
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+ ScreenManager::ControllerConfigsList controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ ASSERT_TRUE(
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable));
+
+ EXPECT_TRUE(base::Contains(drm_->plane_manager()
+ ->GetCrtcStateForCrtcId(kPrimaryCrtc)
+ .modeset_framebuffers,
+ primary));
+ EXPECT_TRUE(base::Contains(drm_->plane_manager()
+ ->GetCrtcStateForCrtcId(kPrimaryCrtc)
+ .modeset_framebuffers,
+ overlay));
+
+ window = screen_manager_->RemoveWindow(1);
+ window->Shutdown();
+}
+
+TEST_F(ScreenManagerTest, ModesetWithClonedPlanesNoOverlays) {
+ InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
+
+ std::unique_ptr<ui::DrmWindow> window(
+ new ui::DrmWindow(1, device_manager_.get(), screen_manager_.get()));
+ window->Initialize();
+ window->SetBounds(GetPrimaryBounds());
+ scoped_refptr<DrmFramebuffer> buffer =
+ CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size());
+ ui::DrmOverlayPlaneList planes;
+ planes.push_back(ui::DrmOverlayPlane(buffer, nullptr));
+ window->SchedulePageFlip(std::move(planes), base::DoNothing(),
+ base::DoNothing());
+ screen_manager_->AddWindow(1, std::move(window));
+
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+ ScreenManager::ControllerConfigsList controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ ASSERT_TRUE(
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable));
+ ASSERT_TRUE(base::Contains(drm_->plane_manager()
+ ->GetCrtcStateForCrtcId(kPrimaryCrtc)
+ .modeset_framebuffers,
+ buffer));
+
+ EXPECT_EQ(drm_->get_test_modeset_count(), 1);
+ EXPECT_EQ(drm_->last_planes_committed_count(), 1);
+
+ window = screen_manager_->RemoveWindow(1);
+ window->Shutdown();
+}
+
+TEST_F(ScreenManagerTest, ModesetWithClonedPlanesWithOverlaySucceeding) {
+ std::vector<CrtcState> crtc_states = {{
+ /* .planes = */
+ {
+ {/* .formats = */ {DRM_FORMAT_XRGB8888}},
+ {/* .formats = */ {DRM_FORMAT_XRGB8888}},
+ },
+ }};
+ InitializeDrmState(drm_.get(), crtc_states, /*is_atomic=*/true);
+
+ std::unique_ptr<ui::DrmWindow> window(
+ new ui::DrmWindow(1, device_manager_.get(), screen_manager_.get()));
+ window->Initialize();
+ window->SetBounds(GetPrimaryBounds());
+ scoped_refptr<DrmFramebuffer> primary =
+ CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size());
+ scoped_refptr<DrmFramebuffer> overlay =
+ CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size());
+ ui::DrmOverlayPlaneList planes;
+ planes.push_back(ui::DrmOverlayPlane(primary, nullptr));
+ planes.push_back(ui::DrmOverlayPlane(overlay, nullptr));
+ window->SchedulePageFlip(std::move(planes), base::DoNothing(),
+ base::DoNothing());
+ screen_manager_->AddWindow(1, std::move(window));
+
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+ ScreenManager::ControllerConfigsList controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ ASSERT_TRUE(
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable));
+
+ EXPECT_TRUE(base::Contains(drm_->plane_manager()
+ ->GetCrtcStateForCrtcId(kPrimaryCrtc)
+ .modeset_framebuffers,
+ primary));
+ EXPECT_TRUE(base::Contains(drm_->plane_manager()
+ ->GetCrtcStateForCrtcId(kPrimaryCrtc)
+ .modeset_framebuffers,
+ overlay));
+
+ EXPECT_EQ(drm_->get_test_modeset_count(), 2);
+ EXPECT_EQ(drm_->last_planes_committed_count(), 2);
+
+ window = screen_manager_->RemoveWindow(1);
+ window->Shutdown();
+}
+
+TEST_F(ScreenManagerTest, ModesetWithClonedPlanesWithOverlayFailing) {
+ std::vector<CrtcState> crtc_states = {{
+ /* .planes = */
+ {
+ {/* .formats = */ {DRM_FORMAT_XRGB8888}},
+ {/* .formats = */ {DRM_FORMAT_XRGB8888}},
+ },
+ }};
+ InitializeDrmState(drm_.get(), crtc_states, /*is_atomic=*/true);
+
+ std::unique_ptr<ui::DrmWindow> window(
+ new ui::DrmWindow(1, device_manager_.get(), screen_manager_.get()));
+ window->Initialize();
+ window->SetBounds(GetPrimaryBounds());
+ scoped_refptr<DrmFramebuffer> primary =
+ CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size());
+ scoped_refptr<DrmFramebuffer> overlay =
+ CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size());
+ ui::DrmOverlayPlaneList planes;
+ planes.push_back(ui::DrmOverlayPlane(primary, nullptr));
+ planes.push_back(ui::DrmOverlayPlane(overlay, nullptr));
+ window->SchedulePageFlip(std::move(planes), base::DoNothing(),
+ base::DoNothing());
+ screen_manager_->AddWindow(1, std::move(window));
+
+ drm_->set_overlay_modeset_expecation(false);
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+ ScreenManager::ControllerConfigsList controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ EXPECT_TRUE(
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable));
+
+ EXPECT_TRUE(base::Contains(drm_->plane_manager()
+ ->GetCrtcStateForCrtcId(kPrimaryCrtc)
+ .modeset_framebuffers,
+ primary));
+ EXPECT_FALSE(base::Contains(drm_->plane_manager()
+ ->GetCrtcStateForCrtcId(kPrimaryCrtc)
+ .modeset_framebuffers,
+ overlay));
+
+ EXPECT_EQ(drm_->get_test_modeset_count(), 2);
+ EXPECT_EQ(drm_->last_planes_committed_count(), 1);
+
+ window = screen_manager_->RemoveWindow(1);
+ window->Shutdown();
+}
+
+TEST_F(ScreenManagerTest, ModesetWithNewBuffersOnModifiersChange) {
+ std::vector<CrtcState> crtc_states = {{
+ /* .planes = */
+ {
+ {/* .formats = */ {DRM_FORMAT_XRGB8888}},
+ {/* .formats = */ {DRM_FORMAT_XRGB8888}},
+ },
+ }};
+ InitializeDrmState(drm_.get(), crtc_states, /*is_atomic=*/true,
+ /*use_modifiers_list=*/true);
+ std::unique_ptr<ui::DrmWindow> window(
+ new ui::DrmWindow(1, device_manager_.get(), screen_manager_.get()));
+ window->Initialize();
+ window->SetBounds(GetPrimaryBounds());
+
+ scoped_refptr<DrmFramebuffer> primary =
+ CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size());
+ scoped_refptr<DrmFramebuffer> overlay =
+ CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size());
+ ui::DrmOverlayPlaneList planes;
+ planes.push_back(ui::DrmOverlayPlane(primary, nullptr));
+ planes.push_back(ui::DrmOverlayPlane(overlay, nullptr));
+ window->SchedulePageFlip(std::move(planes), base::DoNothing(),
+ base::DoNothing());
+ screen_manager_->AddWindow(1, std::move(window));
+
+ screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+ ScreenManager::ControllerConfigsList controllers_to_enable;
+ controllers_to_enable.emplace_back(
+ kPrimaryDisplayId, drm_, kPrimaryCrtc, kPrimaryConnector,
+ GetPrimaryBounds().origin(),
+ std::make_unique<drmModeModeInfo>(kDefaultMode));
+ ASSERT_TRUE(
+ screen_manager_->ConfigureDisplayControllers(controllers_to_enable));
+
+ EXPECT_FALSE(base::Contains(drm_->plane_manager()
+ ->GetCrtcStateForCrtcId(kPrimaryCrtc)
+ .modeset_framebuffers,
+ primary));
+ EXPECT_FALSE(base::Contains(drm_->plane_manager()
+ ->GetCrtcStateForCrtcId(kPrimaryCrtc)
+ .modeset_framebuffers,
+ overlay));
+
+ // Testing test modifiers only, no linear or overlays test.
+ EXPECT_EQ(drm_->get_test_modeset_count(), 1);
+ EXPECT_EQ(drm_->last_planes_committed_count(), 1);
+
+ window = screen_manager_->RemoveWindow(1);
+ window->Shutdown();
+}
+
} // namespace ui
diff --git a/chromium/ui/ozone/platform/drm/host/drm_cursor.cc b/chromium/ui/ozone/platform/drm/host/drm_cursor.cc
index afed5c26d24..5b433602330 100644
--- a/chromium/ui/ozone/platform/drm/host/drm_cursor.cc
+++ b/chromium/ui/ozone/platform/drm/host/drm_cursor.cc
@@ -8,11 +8,12 @@
#include <utility>
#include "base/trace_event/trace_event.h"
+#include "build/chromeos_buildflags.h"
#include "ui/gfx/geometry/point_conversions.h"
#include "ui/ozone/platform/drm/host/drm_window_host.h"
#include "ui/ozone/platform/drm/host/drm_window_host_manager.h"
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ui/events/ozone/chromeos/cursor_controller.h"
#endif
@@ -192,7 +193,7 @@ void DrmCursor::MoveCursor(const gfx::Vector2dF& delta) {
if (window_ == gfx::kNullAcceleratedWidget)
return;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
gfx::Vector2dF transformed_delta = delta;
ui::CursorController::GetInstance()->ApplyCursorConfigForWindow(
window_, &transformed_delta);
@@ -232,7 +233,7 @@ void DrmCursor::SetCursorLocationLocked(const gfx::PointF& location) {
gfx::PointF(confined_bounds_.right() - 1, confined_bounds_.bottom() - 1));
location_ = clamped_location;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
ui::CursorController::GetInstance()->SetCursorLocation(location_);
#endif
}
diff --git a/chromium/ui/ozone/platform/drm/host/drm_display_host_manager.cc b/chromium/ui/ozone/platform/drm/host/drm_display_host_manager.cc
index 975da5c6ab3..32818432bd4 100644
--- a/chromium/ui/ozone/platform/drm/host/drm_display_host_manager.cc
+++ b/chromium/ui/ozone/platform/drm/host/drm_display_host_manager.cc
@@ -237,15 +237,11 @@ void DrmDisplayHostManager::UpdateDisplays(
void DrmDisplayHostManager::ConfigureDisplays(
const std::vector<display::DisplayConfigurationParams>& config_requests,
display::ConfigureCallback callback) {
- base::flat_map<int64_t, bool> dummy_statuses;
- bool is_any_dummy = false;
for (auto& config : config_requests) {
- is_any_dummy |= GetDisplay(config.id)->is_dummy();
- dummy_statuses.insert(std::make_pair(config.id, true));
- }
- if (is_any_dummy) {
- std::move(callback).Run(dummy_statuses);
- return;
+ if (GetDisplay(config.id)->is_dummy()) {
+ std::move(callback).Run(true);
+ return;
+ }
}
proxy_->GpuConfigureNativeDisplays(config_requests, std::move(callback));
diff --git a/chromium/ui/ozone/platform/drm/host/host_drm_device.cc b/chromium/ui/ozone/platform/drm/host/host_drm_device.cc
index 1c6c2b9ac58..9cd757ceeb6 100644
--- a/chromium/ui/ozone/platform/drm/host/host_drm_device.cc
+++ b/chromium/ui/ozone/platform/drm/host/host_drm_device.cc
@@ -136,16 +136,11 @@ void HostDrmDevice::GpuConfigureNativeDisplays(
if (IsConnected()) {
drm_device_->ConfigureNativeDisplays(config_requests, std::move(callback));
} else {
- // If not connected, report failure to config.
- base::flat_map<int64_t, bool> dummy_statuses;
- for (const auto& config : config_requests)
- dummy_statuses.insert(std::make_pair(config.id, false));
-
// Post this task to protect the callstack from accumulating too many
// recursive calls to ConfigureDisplaysTask::Run() in cases in which the GPU
// process crashes repeatedly.
base::SequencedTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(std::move(callback), dummy_statuses));
+ FROM_HERE, base::BindOnce(std::move(callback), false));
}
}
diff --git a/chromium/ui/ozone/platform/drm/ozone_platform_drm.cc b/chromium/ui/ozone/platform/drm/ozone_platform_drm.cc
index 8a6442257df..aceccb83583 100644
--- a/chromium/ui/ozone/platform/drm/ozone_platform_drm.cc
+++ b/chromium/ui/ozone/platform/drm/ozone_platform_drm.cc
@@ -18,6 +18,7 @@
#include "base/notreached.h"
#include "base/threading/platform_thread.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "build/chromeos_buildflags.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "ui/base/buildflags.h"
@@ -58,7 +59,7 @@
#include "ui/events/ozone/layout/stub/stub_keyboard_layout_engine.h"
#endif
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ui/base/ime/chromeos/input_method_chromeos.h"
#else
#include "ui/base/ime/input_method_minimal.h"
@@ -174,7 +175,7 @@ class OzonePlatformDrm : public OzonePlatform {
std::unique_ptr<InputMethod> CreateInputMethod(
internal::InputMethodDelegate* delegate,
gfx::AcceleratedWidget) override {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
return std::make_unique<InputMethodChromeOS>(delegate);
#else
return std::make_unique<InputMethodMinimal>(delegate);
@@ -230,6 +231,12 @@ class OzonePlatformDrm : public OzonePlatform {
}
void InitializeGPU(const InitParams& args) override {
+ // Check if buffer bandwidth compression is disabled
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableBufferBWCompression)) {
+ setenv("MINIGBM_DEBUG", "nocompression", 1);
+ }
+
gpu_task_runner_ = base::ThreadTaskRunnerHandle::Get();
// NOTE: Can't start the thread here since this is called before sandbox
@@ -239,8 +246,9 @@ class OzonePlatformDrm : public OzonePlatform {
surface_factory_ =
std::make_unique<GbmSurfaceFactory>(drm_thread_proxy_.get());
- overlay_manager_ =
- std::make_unique<DrmOverlayManagerGpu>(drm_thread_proxy_.get());
+ overlay_manager_ = std::make_unique<DrmOverlayManagerGpu>(
+ drm_thread_proxy_.get(),
+ args.allow_sync_and_real_buffer_page_flip_testing);
// If gpu is in a separate process, rest of the initialization happens after
// entering the sandbox.
diff --git a/chromium/ui/ozone/platform/headless/ozone_platform_headless.cc b/chromium/ui/ozone/platform/headless/ozone_platform_headless.cc
index 01107a50f94..f6e70bb27fa 100644
--- a/chromium/ui/ozone/platform/headless/ozone_platform_headless.cc
+++ b/chromium/ui/ozone/platform/headless/ozone_platform_headless.cc
@@ -89,11 +89,7 @@ class OzonePlatformHeadless : public OzonePlatform {
std::unique_ptr<InputMethod> CreateInputMethod(
internal::InputMethodDelegate* delegate,
gfx::AcceleratedWidget widget) override {
-#if defined(OS_FUCHSIA)
- return std::make_unique<InputMethodFuchsia>(delegate, widget);
-#else
return std::make_unique<InputMethodMinimal>(delegate);
-#endif
}
void InitializeUI(const InitParams& params) override {
diff --git a/chromium/ui/ozone/platform/scenic/overlay_manager_scenic.cc b/chromium/ui/ozone/platform/scenic/overlay_manager_scenic.cc
index e8e4b816710..7ec96d5e05a 100644
--- a/chromium/ui/ozone/platform/scenic/overlay_manager_scenic.cc
+++ b/chromium/ui/ozone/platform/scenic/overlay_manager_scenic.cc
@@ -32,7 +32,10 @@ class OverlayCandidatesScenic : public OverlayCandidatesOzone {
} // namespace
-OverlayManagerScenic::OverlayManagerScenic() {}
+OverlayManagerScenic::OverlayManagerScenic() {
+ // Fuchsia overlays rely on ShouldUseRealBuffersForPageFlipTest.
+ allow_sync_and_real_buffer_page_flip_testing_ = true;
+}
OverlayManagerScenic::~OverlayManagerScenic() = default;
diff --git a/chromium/ui/ozone/platform/scenic/ozone_platform_scenic.cc b/chromium/ui/ozone/platform/scenic/ozone_platform_scenic.cc
index 35827691a17..5769845402e 100644
--- a/chromium/ui/ozone/platform/scenic/ozone_platform_scenic.cc
+++ b/chromium/ui/ozone/platform/scenic/ozone_platform_scenic.cc
@@ -131,7 +131,8 @@ class OzonePlatformScenic : public OzonePlatform,
std::unique_ptr<InputMethod> CreateInputMethod(
internal::InputMethodDelegate* delegate,
gfx::AcceleratedWidget widget) override {
- return std::make_unique<InputMethodFuchsia>(delegate, widget);
+ return std::make_unique<InputMethodFuchsia>(
+ delegate, window_manager_->GetWindow(widget)->CloneViewRef());
}
void InitializeUI(const InitParams& params) override {
diff --git a/chromium/ui/ozone/platform/scenic/scenic_overlay_view.cc b/chromium/ui/ozone/platform/scenic/scenic_overlay_view.cc
index a9709908586..f7e30451b70 100644
--- a/chromium/ui/ozone/platform/scenic/scenic_overlay_view.cc
+++ b/chromium/ui/ozone/platform/scenic/scenic_overlay_view.cc
@@ -50,6 +50,9 @@ ScenicOverlayView::~ScenicOverlayView() {
surface->AssertBelongsToCurrentThread();
surface->RemoveOverlayView(buffer_collection_id_);
}
+
+ // Releasing |image_pipe_| implicitly also enforces cleanup.
+ image_pipe_->RemoveBufferCollection(kImagePipeBufferCollectionId);
}
void ScenicOverlayView::Initialize(
diff --git a/chromium/ui/ozone/platform/scenic/scenic_surface_factory.cc b/chromium/ui/ozone/platform/scenic/scenic_surface_factory.cc
index d1e03bbb990..f9066115081 100644
--- a/chromium/ui/ozone/platform/scenic/scenic_surface_factory.cc
+++ b/chromium/ui/ozone/platform/scenic/scenic_surface_factory.cc
@@ -243,6 +243,7 @@ void ScenicSurfaceFactory::CreateNativePixmapAsync(
#if BUILDFLAG(ENABLE_VULKAN)
std::unique_ptr<gpu::VulkanImplementation>
ScenicSurfaceFactory::CreateVulkanImplementation(
+ bool use_swiftshader,
bool allow_protected_memory,
bool enforce_protected_memory) {
return std::make_unique<ui::VulkanImplementationScenic>(
diff --git a/chromium/ui/ozone/platform/scenic/scenic_surface_factory.h b/chromium/ui/ozone/platform/scenic/scenic_surface_factory.h
index b0454ac45cb..20f7dca7608 100644
--- a/chromium/ui/ozone/platform/scenic/scenic_surface_factory.h
+++ b/chromium/ui/ozone/platform/scenic/scenic_surface_factory.h
@@ -63,6 +63,7 @@ class ScenicSurfaceFactory : public SurfaceFactoryOzone {
NativePixmapCallback callback) override;
#if BUILDFLAG(ENABLE_VULKAN)
std::unique_ptr<gpu::VulkanImplementation> CreateVulkanImplementation(
+ bool use_swiftshader,
bool allow_protected_memory,
bool enforce_protected_memory) override;
#endif
diff --git a/chromium/ui/ozone/platform/scenic/scenic_window.cc b/chromium/ui/ozone/platform/scenic/scenic_window.cc
index 330fe7de65f..b25ec452a2b 100644
--- a/chromium/ui/ozone/platform/scenic/scenic_window.cc
+++ b/chromium/ui/ozone/platform/scenic/scenic_window.cc
@@ -29,10 +29,11 @@ ScenicWindow::ScenicWindow(ScenicWindowManager* window_manager,
window_id_(manager_->AddWindow(this)),
event_dispatcher_(this),
scenic_session_(manager_->GetScenic()),
+ view_ref_(std::move(properties.view_ref_pair.view_ref)),
view_(&scenic_session_,
std::move(std::move(properties.view_token)),
std::move(properties.view_ref_pair.control_ref),
- std::move(properties.view_ref_pair.view_ref),
+ CloneViewRef(),
"chromium window"),
node_(&scenic_session_),
input_node_(&scenic_session_),
@@ -245,6 +246,14 @@ void ScenicWindow::UpdateSize() {
delegate_->OnBoundsChanged(bounds_);
}
+fuchsia::ui::views::ViewRef ScenicWindow::CloneViewRef() {
+ fuchsia::ui::views::ViewRef dup;
+ zx_status_t status =
+ view_ref_.reference.duplicate(ZX_RIGHT_SAME_RIGHTS, &dup.reference);
+ ZX_CHECK(status == ZX_OK, status) << "zx_object_duplicate";
+ return dup;
+}
+
void ScenicWindow::OnScenicError(zx_status_t status) {
LOG(ERROR) << "scenic::Session failed with code " << status << ".";
delegate_->OnClosed();
diff --git a/chromium/ui/ozone/platform/scenic/scenic_window.h b/chromium/ui/ozone/platform/scenic/scenic_window.h
index 2981db6cde8..3bf566cdca0 100644
--- a/chromium/ui/ozone/platform/scenic/scenic_window.h
+++ b/chromium/ui/ozone/platform/scenic/scenic_window.h
@@ -49,6 +49,9 @@ class COMPONENT_EXPORT(OZONE) ScenicWindow
// causing its contents to be displayed in this window.
void AttachSurfaceView(fuchsia::ui::views::ViewHolderToken token);
+ // Returns a ViewRef associated with this window.
+ fuchsia::ui::views::ViewRef CloneViewRef();
+
// PlatformWindow implementation.
gfx::Rect GetBounds() const override;
void SetBounds(const gfx::Rect& bounds) override;
@@ -107,6 +110,11 @@ class COMPONENT_EXPORT(OZONE) ScenicWindow
// Scenic session used for all drawing operations in this View.
scenic::Session scenic_session_;
+ // Handle to a kernel object which identifies this window's View
+ // across the system. ViewRef consumers can access the handle by
+ // calling CloneViewRef().
+ fuchsia::ui::views::ViewRef view_ref_;
+
// The view resource in |scenic_session_|.
scenic::View view_;
diff --git a/chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.cc b/chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.cc
index 9487bcaea42..6a3dee239f9 100644
--- a/chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.cc
+++ b/chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.cc
@@ -140,8 +140,9 @@ bool SysmemBufferCollection::Initialize(
is_protected_ = force_protected;
if (register_with_image_pipe) {
- scenic_overlay_view_.emplace(scenic_surface_factory->CreateScenicSession(),
- scenic_surface_factory);
+ overlay_view_task_runner_ = base::ThreadTaskRunnerHandle::Get();
+ scenic_overlay_view_ = std::make_unique<ScenicOverlayView>(
+ scenic_surface_factory->CreateScenicSession(), scenic_surface_factory);
surface_factory_ = scenic_surface_factory;
}
@@ -335,6 +336,12 @@ SysmemBufferCollection::~SysmemBufferCollection() {
if (on_deleted_)
std::move(on_deleted_).Run();
+
+ if (scenic_overlay_view_ &&
+ !overlay_view_task_runner_->BelongsToCurrentThread()) {
+ overlay_view_task_runner_->DeleteSoon(FROM_HERE,
+ std::move(scenic_overlay_view_));
+ }
}
bool SysmemBufferCollection::InitializeInternal(
@@ -350,7 +357,7 @@ bool SysmemBufferCollection::InitializeInternal(
// overlay.
fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken>
collection_token_for_scenic;
- if (scenic_overlay_view_.has_value()) {
+ if (scenic_overlay_view_) {
collection_token->Duplicate(ZX_RIGHT_SAME_RIGHTS,
collection_token_for_scenic.NewRequest());
}
@@ -361,7 +368,7 @@ bool SysmemBufferCollection::InitializeInternal(
return false;
}
- if (scenic_overlay_view_.has_value()) {
+ if (scenic_overlay_view_) {
scenic_overlay_view_->Initialize(std::move(collection_token_for_scenic));
}
@@ -450,7 +457,7 @@ bool SysmemBufferCollection::InitializeInternal(
is_protected_ = buffers_info_.settings.buffer_settings.is_secure;
// Add all images to Image pipe for presentation later.
- if (scenic_overlay_view_.has_value()) {
+ if (scenic_overlay_view_) {
scenic_overlay_view_->AddImages(buffers_info_.buffer_count, image_size_);
}
diff --git a/chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.h b/chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.h
index 873ddbeccce..6a3ce46bd6b 100644
--- a/chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.h
+++ b/chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.h
@@ -13,6 +13,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/optional.h"
+#include "base/single_thread_task_runner.h"
#include "base/threading/thread_checker.h"
#include "gpu/ipc/common/vulkan_ycbcr_info.h"
#include "gpu/vulkan/fuchsia/vulkan_fuchsia_ext.h"
@@ -88,8 +89,7 @@ class SysmemBufferCollection
return buffers_info_.settings.buffer_settings.size_bytes;
}
ScenicOverlayView* scenic_overlay_view() {
- return scenic_overlay_view_.has_value() ? &scenic_overlay_view_.value()
- : nullptr;
+ return scenic_overlay_view_ ? scenic_overlay_view_.get() : nullptr;
}
ScenicSurfaceFactory* surface_factory() { return surface_factory_; }
@@ -131,10 +131,13 @@ class SysmemBufferCollection
// that is referenced by |collection_|.
VkBufferCollectionFUCHSIA vk_buffer_collection_ = VK_NULL_HANDLE;
+ // |scenic_overlay_view_| view should be used and deleted on the same thread
+ // as creation.
+ scoped_refptr<base::SingleThreadTaskRunner> overlay_view_task_runner_;
// If ScenicOverlayView is created and its ImagePipe is added as a participant
// in buffer allocation negotiations, the associated images can be displayed
// as overlays.
- base::Optional<ScenicOverlayView> scenic_overlay_view_;
+ std::unique_ptr<ScenicOverlayView> scenic_overlay_view_;
ScenicSurfaceFactory* surface_factory_ = nullptr;
// Thread checker used to verify that CreateVkImage() is always called from
diff --git a/chromium/ui/ozone/platform/wayland/BUILD.gn b/chromium/ui/ozone/platform/wayland/BUILD.gn
index 46447f33e84..d1aab09a3a6 100644
--- a/chromium/ui/ozone/platform/wayland/BUILD.gn
+++ b/chromium/ui/ozone/platform/wayland/BUILD.gn
@@ -18,7 +18,6 @@ source_set("wayland") {
"client_native_pixmap_factory_wayland.h",
"common/data_util.cc",
"common/data_util.h",
- "common/wayland.cc",
"common/wayland.h",
"common/wayland_object.cc",
"common/wayland_object.h",
@@ -51,8 +50,9 @@ source_set("wayland") {
"host/shell_object_factory.h",
"host/shell_popup_wrapper.cc",
"host/shell_popup_wrapper.h",
- "host/shell_surface_wrapper.cc",
"host/shell_surface_wrapper.h",
+ "host/shell_toplevel_wrapper.cc",
+ "host/shell_toplevel_wrapper.h",
"host/wayland_auxiliary_window.cc",
"host/wayland_auxiliary_window.h",
"host/wayland_buffer_manager_connector.cc",
@@ -65,6 +65,8 @@ source_set("wayland") {
"host/wayland_connection.h",
"host/wayland_cursor.cc",
"host/wayland_cursor.h",
+ "host/wayland_cursor_factory.cc",
+ "host/wayland_cursor_factory.h",
"host/wayland_cursor_position.cc",
"host/wayland_cursor_position.h",
"host/wayland_data_device.cc",
@@ -138,6 +140,8 @@ source_set("wayland") {
"host/xdg_popup_wrapper_impl.h",
"host/xdg_surface_wrapper_impl.cc",
"host/xdg_surface_wrapper_impl.h",
+ "host/xdg_toplevel_wrapper_impl.cc",
+ "host/xdg_toplevel_wrapper_impl.h",
"host/zwp_primary_selection_device.cc",
"host/zwp_primary_selection_device.h",
"host/zwp_primary_selection_device_manager.cc",
@@ -147,6 +151,12 @@ source_set("wayland") {
"host/zwp_text_input_wrapper.h",
"host/zwp_text_input_wrapper_v1.cc",
"host/zwp_text_input_wrapper_v1.h",
+ "host/zxdg_popup_v6_wrapper_impl.cc",
+ "host/zxdg_popup_v6_wrapper_impl.h",
+ "host/zxdg_surface_v6_wrapper_impl.cc",
+ "host/zxdg_surface_v6_wrapper_impl.h",
+ "host/zxdg_toplevel_v6_wrapper_impl.cc",
+ "host/zxdg_toplevel_v6_wrapper_impl.h",
"ozone_platform_wayland.cc",
"ozone_platform_wayland.h",
]
@@ -182,6 +192,7 @@ source_set("wayland") {
"//ui/base:buildflags",
"//ui/base/cursor",
"//ui/base/cursor:cursor_base",
+ "//ui/base/cursor:theme_manager",
"//ui/base/cursor/mojom:cursor_type",
"//ui/base/ime/linux",
"//ui/events",
@@ -202,7 +213,7 @@ source_set("wayland") {
"//ui/platform_window/wm",
]
- if (is_linux && !is_chromeos) {
+ if (is_linux || is_chromeos_lacros) {
deps += [ "//ui/base/ime/linux" ]
}
@@ -217,9 +228,12 @@ source_set("wayland") {
]
}
- # TODO(crbug.com/1052397): Rename chromeos_is_browser_only to is_lacros.
- if (chromeos_is_browser_only) {
- deps += [ "//chromeos/crosapi/cpp" ]
+ if (is_chromeos_lacros) {
+ deps += [
+ "//chromeos/crosapi/cpp",
+ "//chromeos/crosapi/mojom",
+ "//chromeos/lacros",
+ ]
}
defines = [ "OZONE_IMPLEMENTATION" ]
@@ -230,6 +244,7 @@ source_set("wayland") {
} else {
deps += [
"//third_party/wayland:wayland_client",
+ "//third_party/wayland:wayland_cursor",
"//third_party/wayland:wayland_egl",
]
}
@@ -357,9 +372,11 @@ source_set("wayland_unittests") {
testonly = true
sources = [
+ "common/wayland_util_unittest.cc",
"gpu/wayland_overlay_manager_unittest.cc",
+ "host/wayland_clipboard_unittest.cc",
"host/wayland_connection_unittest.cc",
- "host/wayland_data_device_unittest.cc",
+ "host/wayland_cursor_factory_unittest.cc",
"host/wayland_data_drag_controller_unittest.cc",
"host/wayland_event_source_unittest.cc",
"host/wayland_input_method_context_unittest.cc",
@@ -370,6 +387,9 @@ source_set("wayland_unittests") {
"host/wayland_window_drag_controller_unittest.cc",
"host/wayland_window_manager_unittests.cc",
"host/wayland_window_unittest.cc",
+ "host/wayland_zaura_shell_unittest.cc",
+ "test/wayland_drag_drop_test.cc",
+ "test/wayland_drag_drop_test.h",
"test/wayland_test.cc",
"test/wayland_test.h",
]
@@ -377,6 +397,7 @@ source_set("wayland_unittests") {
deps = [
":test_support",
":wayland",
+ "//components/exo/wayland/protocol:aura_shell_protocol",
"//testing/gmock",
"//testing/gtest",
"//third_party/wayland:wayland_server",
diff --git a/chromium/ui/ozone/platform/wayland/DEPS b/chromium/ui/ozone/platform/wayland/DEPS
index 1eeae79d79e..b7393cb1394 100644
--- a/chromium/ui/ozone/platform/wayland/DEPS
+++ b/chromium/ui/ozone/platform/wayland/DEPS
@@ -7,7 +7,7 @@ include_rules = [
"+third_party/wayland",
"+ui/base/clipboard/clipboard_constants.h",
"+ui/base/dragdrop/drag_drop_types.h",
- "+ui/base/dragdrop/file_info/file_info.h",
+ "+ui/base/clipboard/file_info.h",
"+ui/base/dragdrop/os_exchange_data.h",
"+ui/base/dragdrop/os_exchange_data_provider_non_backed.h",
]
diff --git a/chromium/ui/ozone/platform/wayland/common/data_util.cc b/chromium/ui/ozone/platform/wayland/common/data_util.cc
index 90773668cde..94c84236a2c 100644
--- a/chromium/ui/ozone/platform/wayland/common/data_util.cc
+++ b/chromium/ui/ozone/platform/wayland/common/data_util.cc
@@ -12,7 +12,7 @@
#include "base/strings/string_split.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/base/clipboard/clipboard_constants.h"
-#include "ui/base/dragdrop/file_info/file_info.h"
+#include "ui/base/clipboard/file_info.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/base/dragdrop/os_exchange_data_provider_non_backed.h"
#include "ui/ozone/public/platform_clipboard.h"
diff --git a/chromium/ui/ozone/platform/wayland/common/wayland.cc b/chromium/ui/ozone/platform/wayland/common/wayland.cc
deleted file mode 100644
index 8a20e3a7be3..00000000000
--- a/chromium/ui/ozone/platform/wayland/common/wayland.cc
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/ozone/platform/wayland/common/wayland.h"
-
-namespace wl {
-
-void* bind_registry(struct wl_registry* registry,
- uint32_t name,
- const struct wl_interface* interface,
- uint32_t version) {
- if (dlsym(RTLD_DEFAULT, "wl_proxy_marshal_constructor_versioned")) {
- return wl_registry_bind(registry, name, interface, version);
- } else {
- return wl_proxy_marshal_constructor(reinterpret_cast<wl_proxy*>(registry),
- WL_REGISTRY_BIND, interface, name,
- interface->name, version, nullptr);
- }
- NOTREACHED();
- return nullptr;
-}
-
-} // namespace wl
diff --git a/chromium/ui/ozone/platform/wayland/common/wayland.h b/chromium/ui/ozone/platform/wayland/common/wayland.h
index c645346ddcb..fd8ff58bf7d 100644
--- a/chromium/ui/ozone/platform/wayland/common/wayland.h
+++ b/chromium/ui/ozone/platform/wayland/common/wayland.h
@@ -5,26 +5,22 @@
#ifndef UI_OZONE_PLATFORM_WAYLAND_COMMON_WAYLAND_H_
#define UI_OZONE_PLATFORM_WAYLAND_COMMON_WAYLAND_H_
-#include <dlfcn.h>
-// This header includes wayland-client-core.h and wayland-client-protocol.h
#include <wayland-client.h>
-#include "base/notreached.h"
-
namespace wl {
template <typename T>
uint32_t get_version_of_object(T* obj) {
- if (dlsym(RTLD_DEFAULT, "wl_proxy_get_version"))
- return wl_proxy_get_version(reinterpret_cast<wl_proxy*>(obj));
- // Older version of the libwayland-client didn't support version of objects.
- return 0;
+ return wl_proxy_get_version(reinterpret_cast<wl_proxy*>(obj));
}
-void* bind_registry(struct wl_registry* registry,
- uint32_t name,
- const struct wl_interface* interface,
- uint32_t version);
+template <typename T>
+T* bind_registry(struct wl_registry* registry,
+ uint32_t name,
+ const struct wl_interface* interface,
+ uint32_t version) {
+ return static_cast<T*>(wl_registry_bind(registry, name, interface, version));
+}
} // namespace wl
diff --git a/chromium/ui/ozone/platform/wayland/common/wayland_object.cc b/chromium/ui/ozone/platform/wayland/common/wayland_object.cc
index 7a6c5e7b849..8827a5e9f49 100644
--- a/chromium/ui/ozone/platform/wayland/common/wayland_object.cc
+++ b/chromium/ui/ozone/platform/wayland/common/wayland_object.cc
@@ -15,6 +15,7 @@
#include <primary-selection-unstable-v1-client-protocol.h>
#include <text-input-unstable-v1-client-protocol.h>
#include <viewporter-client-protocol.h>
+#include <wayland-cursor.h>
#include <wayland-drm-client-protocol.h>
#include <xdg-decoration-unstable-v1-client-protocol.h>
#include <xdg-foreign-unstable-v1-client-protocol.h>
@@ -131,6 +132,9 @@ const wl_interface* ObjectTraits<wl_compositor>::interface =
void (*ObjectTraits<wl_compositor>::deleter)(wl_compositor*) =
&wl_compositor_destroy;
+void (*ObjectTraits<wl_cursor_theme>::deleter)(wl_cursor_theme*) =
+ &wl_cursor_theme_destroy;
+
const wl_interface* ObjectTraits<wl_data_device_manager>::interface =
&wl_data_device_manager_interface;
void (*ObjectTraits<wl_data_device_manager>::deleter)(wl_data_device_manager*) =
diff --git a/chromium/ui/ozone/platform/wayland/common/wayland_object.h b/chromium/ui/ozone/platform/wayland/common/wayland_object.h
index b06cf876f91..d609c6150fa 100644
--- a/chromium/ui/ozone/platform/wayland/common/wayland_object.h
+++ b/chromium/ui/ozone/platform/wayland/common/wayland_object.h
@@ -20,6 +20,7 @@ struct zwp_primary_selection_source_v1;
struct wl_buffer;
struct wl_callback;
struct wl_compositor;
+struct wl_cursor_theme;
struct wl_data_device_manager;
struct wl_data_device;
struct wl_data_offer;
@@ -154,6 +155,11 @@ struct ObjectTraits<wl_compositor> {
};
template <>
+struct ObjectTraits<wl_cursor_theme> {
+ static void (*deleter)(wl_cursor_theme*);
+};
+
+template <>
struct ObjectTraits<wl_data_device_manager> {
static const wl_interface* interface;
static void (*deleter)(wl_data_device_manager*);
@@ -462,8 +468,8 @@ class Object : public std::unique_ptr<T, Deleter> {
template <typename T>
wl::Object<T> Bind(wl_registry* registry, uint32_t name, uint32_t version) {
- return wl::Object<T>(static_cast<T*>(
- wl::bind_registry(registry, name, ObjectTraits<T>::interface, version)));
+ return wl::Object<T>(wl::bind_registry<T>(
+ registry, name, ObjectTraits<T>::interface, version));
}
} // namespace wl
diff --git a/chromium/ui/ozone/platform/wayland/common/wayland_util.cc b/chromium/ui/ozone/platform/wayland/common/wayland_util.cc
index 042cfc8e96b..6d7b05906af 100644
--- a/chromium/ui/ozone/platform/wayland/common/wayland_util.cc
+++ b/chromium/ui/ozone/platform/wayland/common/wayland_util.cc
@@ -7,7 +7,11 @@
#include <xdg-shell-client-protocol.h>
#include <xdg-shell-unstable-v6-client-protocol.h>
+#include "third_party/skia/include/core/SkPath.h"
+#include "third_party/skia/include/core/SkRegion.h"
#include "ui/base/hit_test.h"
+#include "ui/gfx/skia_util.h"
+#include "ui/gfx/transform.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
#include "ui/ozone/platform/wayland/host/wayland_shm_buffer.h"
#include "ui/ozone/platform/wayland/host/wayland_surface.h"
@@ -131,7 +135,7 @@ bool DrawBitmap(const SkBitmap& bitmap, ui::WaylandShmBuffer* out_buffer) {
// Clear to transparent in case |bitmap| is smaller than the canvas.
auto* canvas = sk_surface->getCanvas();
canvas->clear(SK_ColorTRANSPARENT);
- canvas->drawBitmapRect(bitmap, damage, nullptr);
+ canvas->drawImageRect(bitmap.asImage(), damage, SkSamplingOptions());
return true;
}
@@ -276,4 +280,26 @@ gfx::Rect TranslateWindowBoundsToParentDIP(ui::WaylandWindow* window,
1.0 / window->buffer_scale());
}
+std::vector<gfx::Rect> CreateRectsFromSkPath(const SkPath& path) {
+ SkRegion clip_region;
+ clip_region.setRect(path.getBounds().round());
+ SkRegion region;
+ region.setPath(path, clip_region);
+
+ std::vector<gfx::Rect> rects;
+ for (SkRegion::Iterator it(region); !it.done(); it.next())
+ rects.push_back(gfx::SkIRectToRect(it.rect()));
+
+ return rects;
+}
+
+SkPath ConvertPathToDIP(const SkPath& path_in_pixels, const int32_t scale) {
+ SkScalar sk_scale = SkFloatToScalar(1.0f / scale);
+ gfx::Transform transform;
+ transform.Scale(sk_scale, sk_scale);
+ SkPath path_in_dips;
+ path_in_pixels.transform(SkMatrix(transform.matrix()), &path_in_dips);
+ return path_in_dips;
+}
+
} // namespace wl
diff --git a/chromium/ui/ozone/platform/wayland/common/wayland_util.h b/chromium/ui/ozone/platform/wayland/common/wayland_util.h
index d755de9e0ba..8d8b12f9cc1 100644
--- a/chromium/ui/ozone/platform/wayland/common/wayland_util.h
+++ b/chromium/ui/ozone/platform/wayland/common/wayland_util.h
@@ -17,6 +17,7 @@
#include "ui/platform_window/platform_window_init_properties.h"
class SkBitmap;
+class SkPath;
namespace ui {
class WaylandConnection;
@@ -87,6 +88,12 @@ ui::WaylandWindow* RootWindowFromWlSurface(wl_surface* surface);
gfx::Rect TranslateWindowBoundsToParentDIP(ui::WaylandWindow* window,
ui::WaylandWindow* parent_window);
+// Returns rectangles dictated by SkPath.
+std::vector<gfx::Rect> CreateRectsFromSkPath(const SkPath& path);
+
+// Returns converted SkPath in DIPs from the one in pixels.
+SkPath ConvertPathToDIP(const SkPath& path_in_pixels, const int32_t scale);
+
} // namespace wl
#endif // UI_OZONE_PLATFORM_WAYLAND_COMMON_WAYLAND_UTIL_H_
diff --git a/chromium/ui/ozone/platform/wayland/common/wayland_util_unittest.cc b/chromium/ui/ozone/platform/wayland/common/wayland_util_unittest.cc
new file mode 100644
index 00000000000..57a3669cb30
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/common/wayland_util_unittest.cc
@@ -0,0 +1,71 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/ozone/platform/wayland/common/wayland_util.h"
+
+#include <memory>
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkPath.h"
+#include "third_party/skia/include/core/SkRect.h"
+
+namespace ui {
+
+class WaylandUtilTest : public testing::Test {};
+
+TEST_F(WaylandUtilTest, TestCreateRectsFromSkPath) {
+ constexpr int width = 100;
+ constexpr int height = 100;
+
+ // Test1 consists of 2 rectangles from SkPath.
+ std::vector<gfx::Rect> expectedFor2Rects = {gfx::Rect(1, 0, 98, 1),
+ gfx::Rect(0, 1, 100, 99)};
+ SkPath pathFor2Rects;
+ const SkRect rect = SkRect::MakeIWH(width, height);
+ constexpr SkScalar corner_radius_scalar = 2.0;
+ constexpr SkScalar radii[8] = {corner_radius_scalar,
+ corner_radius_scalar, // top-left
+ corner_radius_scalar,
+ corner_radius_scalar, // top-right
+ 0,
+ 0, // bottom-right
+ 0,
+ 0}; // bottom-left
+ pathFor2Rects.addRoundRect(rect, radii, SkPathDirection::kCW);
+ EXPECT_EQ(expectedFor2Rects, wl::CreateRectsFromSkPath(pathFor2Rects));
+
+ // Test2 consists of 5 rectangles from SkPath.
+ std::vector<gfx::Rect> expectedFor5Rects = {
+ gfx::Rect(3, 0, 94, 1), gfx::Rect(1, 1, 98, 2), gfx::Rect(0, 3, 100, 94),
+ gfx::Rect(1, 97, 98, 2), gfx::Rect(3, 99, 94, 1)};
+ SkPath pathFor5Rects;
+ pathFor5Rects.moveTo(0, 3);
+ pathFor5Rects.lineTo(1, 3);
+ pathFor5Rects.lineTo(1, 1);
+ pathFor5Rects.lineTo(3, 1);
+ pathFor5Rects.lineTo(3, 0);
+
+ pathFor5Rects.lineTo(width - 3, 0);
+ pathFor5Rects.lineTo(width - 3, 1);
+ pathFor5Rects.lineTo(width - 1, 1);
+ pathFor5Rects.lineTo(width - 1, 3);
+ pathFor5Rects.lineTo(width, 3);
+
+ pathFor5Rects.lineTo(width, height - 3);
+ pathFor5Rects.lineTo(width - 1, height - 3);
+ pathFor5Rects.lineTo(width - 1, height - 1);
+ pathFor5Rects.lineTo(width - 3, height - 1);
+ pathFor5Rects.lineTo(width - 3, height);
+
+ pathFor5Rects.lineTo(3, height);
+ pathFor5Rects.lineTo(3, height - 1);
+ pathFor5Rects.lineTo(1, height - 1);
+ pathFor5Rects.lineTo(1, height - 3);
+ pathFor5Rects.lineTo(0, height - 3);
+ pathFor5Rects.close();
+
+ EXPECT_EQ(expectedFor5Rects, wl::CreateRectsFromSkPath(pathFor5Rects));
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc b/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc
index 1b15b1c27f7..827cd1c9b7d 100644
--- a/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc
+++ b/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc
@@ -11,6 +11,8 @@
#include "base/task/thread_pool.h"
#include "base/trace_event/trace_event.h"
#include "ui/gfx/gpu_fence.h"
+#include "ui/gfx/gpu_fence_handle.h"
+#include "ui/gl/gl_bindings.h"
#include "ui/ozone/common/egl_util.h"
#include "ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.h"
#include "ui/ozone/public/mojom/wayland/wayland_overlay_config.mojom.h"
@@ -19,12 +21,6 @@ namespace ui {
namespace {
-void WaitForEGLFence(EGLDisplay display, EGLSyncKHR fence) {
- eglClientWaitSyncKHR(display, fence, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
- EGL_FOREVER_KHR);
- eglDestroySyncKHR(display, fence);
-}
-
void WaitForGpuFences(std::vector<std::unique_ptr<gfx::GpuFence>> fences) {
for (auto& fence : fences)
fence->Wait();
@@ -60,9 +56,9 @@ bool GbmSurfacelessWayland::ScheduleOverlayPlane(
const gfx::RectF& crop_rect,
bool enable_blend,
std::unique_ptr<gfx::GpuFence> gpu_fence) {
- unsubmitted_frames_.back()->overlays.push_back(
- gl::GLSurfaceOverlay(z_order, transform, image, bounds_rect, crop_rect,
- enable_blend, std::move(gpu_fence)));
+ unsubmitted_frames_.back()->overlays.emplace_back(
+ z_order, transform, image, bounds_rect, crop_rect, enable_blend,
+ std::move(gpu_fence));
return true;
}
@@ -115,31 +111,23 @@ void GbmSurfacelessWayland::SwapBuffersAsync(
unsubmitted_frames_.push_back(std::make_unique<PendingFrame>());
- if (!use_egl_fence_sync_ || !frame->schedule_planes_succeeded) {
+ // If Wayland server supports linux_explicit_synchronization_protocol, fences
+ // should be shipped with buffers. Otherwise, we will wait for fences.
+ if (buffer_manager_->supports_acquire_fence() || !use_egl_fence_sync_ ||
+ !frame->schedule_planes_succeeded) {
frame->ready = true;
MaybeSubmitFrames();
return;
}
+ base::OnceClosure fence_wait_task;
std::vector<std::unique_ptr<gfx::GpuFence>> fences;
- // Uset in-fences provided in the overlays. If there are none, we insert our
- // own fence and wait.
for (auto& plane : frame->planes) {
if (plane.second.gpu_fence)
fences.push_back(std::move(plane.second.gpu_fence));
}
- base::OnceClosure fence_wait_task;
- if (!fences.empty()) {
- fence_wait_task = base::BindOnce(&WaitForGpuFences, std::move(fences));
- } else {
- // TODO(fangzhoug): the following should be replaced by a per surface flush
- // as it gets implemented in GL drivers.
- EGLSyncKHR fence = InsertFence(has_implicit_external_sync_);
- CHECK_NE(fence, EGL_NO_SYNC_KHR) << "eglCreateSyncKHR failed";
-
- fence_wait_task = base::BindOnce(&WaitForEGLFence, GetDisplay(), fence);
- }
+ fence_wait_task = base::BindOnce(&WaitForGpuFences, std::move(fences));
base::OnceClosure fence_retired_callback = base::BindOnce(
&GbmSurfacelessWayland::FenceRetired, weak_factory_.GetWeakPtr(), frame);
@@ -190,6 +178,14 @@ void GbmSurfacelessWayland::SetRelyOnImplicitSync() {
use_egl_fence_sync_ = false;
}
+bool GbmSurfacelessWayland::SupportsPlaneGpuFences() const {
+ return true;
+}
+
+bool GbmSurfacelessWayland::SupportsOverridePlatformSize() const {
+ return true;
+}
+
gfx::SurfaceOrigin GbmSurfacelessWayland::GetOrigin() const {
// GbmSurfacelessWayland's y-axis is flipped compare to GL - (0,0) is at top
// left corner.
@@ -200,9 +196,9 @@ GbmSurfacelessWayland::~GbmSurfacelessWayland() {
buffer_manager_->UnregisterSurface(widget_);
}
-GbmSurfacelessWayland::PendingFrame::PendingFrame() {}
+GbmSurfacelessWayland::PendingFrame::PendingFrame() = default;
-GbmSurfacelessWayland::PendingFrame::~PendingFrame() {}
+GbmSurfacelessWayland::PendingFrame::~PendingFrame() = default;
void GbmSurfacelessWayland::PendingFrame::ScheduleOverlayPlanes(
gfx::AcceleratedWidget widget) {
@@ -238,15 +234,19 @@ void GbmSurfacelessWayland::MaybeSubmitFrames() {
}
std::vector<ui::ozone::mojom::WaylandOverlayConfigPtr> overlay_configs;
- for (const auto& plane : submitted_frame->planes) {
+ for (auto& plane : submitted_frame->planes) {
overlay_configs.push_back(
ui::ozone::mojom::WaylandOverlayConfig::From(plane.second));
overlay_configs.back()->buffer_id = plane.first;
- if (plane.second.z_order == 0) {
+ if (plane.second.z_order == 0)
overlay_configs.back()->damage_region = submitted_frame->damage_region_;
- submitted_frame->buffer_id = plane.first;
- }
+#if DCHECK_IS_ON()
+ if (plane.second.z_order == INT32_MIN)
+ background_buffer_id_ = plane.first;
+#endif
+ plane.second.gpu_fence.reset();
}
+
buffer_manager_->CommitOverlays(widget_, std::move(overlay_configs));
submitted_frames_.push_back(std::move(submitted_frame));
}
@@ -273,7 +273,7 @@ void GbmSurfacelessWayland::OnSubmission(BufferId buffer_id,
const gfx::SwapResult& swap_result) {
// submitted_frames_ may temporarily have more than one buffer in it if
// buffers are released out of order by the Wayland server.
- DCHECK(!submitted_frames_.empty());
+ DCHECK(!submitted_frames_.empty() || background_buffer_id_ == buffer_id);
size_t erased = 0;
for (auto& submitted_frame : submitted_frames_) {
@@ -320,7 +320,8 @@ void GbmSurfacelessWayland::OnSubmission(BufferId buffer_id,
void GbmSurfacelessWayland::OnPresentation(
BufferId buffer_id,
const gfx::PresentationFeedback& feedback) {
- DCHECK(!submitted_frames_.empty() || !pending_presentation_frames_.empty());
+ DCHECK(!submitted_frames_.empty() || !pending_presentation_frames_.empty() ||
+ background_buffer_id_ == buffer_id);
size_t erased = 0;
for (auto& frame : pending_presentation_frames_) {
diff --git a/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h b/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h
index 910b9a7056e..8be5c32391f 100644
--- a/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h
+++ b/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h
@@ -60,6 +60,8 @@ class GbmSurfacelessWayland : public gl::SurfacelessEGL,
PresentationCallback presentation_callback) override;
EGLConfig GetConfig() override;
void SetRelyOnImplicitSync() override;
+ bool SupportsPlaneGpuFences() const override;
+ bool SupportsOverridePlatformSize() const override;
gfx::SurfaceOrigin GetOrigin() const override;
private:
@@ -88,9 +90,6 @@ class GbmSurfacelessWayland : public gl::SurfacelessEGL,
bool ready = false;
- // The id of the buffer, which represents this frame.
- BufferId buffer_id = 0;
-
// A region of the updated content in a corresponding frame. It's used to
// advice Wayland which part of a buffer is going to be updated. Passing {0,
// 0, 0, 0} results in a whole buffer update on the Wayland compositor side.
@@ -120,6 +119,12 @@ class GbmSurfacelessWayland : public gl::SurfacelessEGL,
WaylandBufferManagerGpu* const buffer_manager_;
+ // |background_buffer_id| is sent to WaylandBufferManagerHost once per
+ // background_buffer allocation. However WaylandBufferManagerHost may commit
+ // this buffer more often b/c buffers needs to be re-attached when wl_surface
+ // is reshown.
+ BufferId background_buffer_id_;
+
// The native surface. Deleting this is allowed to free the EGLNativeWindow.
gfx::AcceleratedWidget widget_;
std::vector<std::unique_ptr<PendingFrame>> unsubmitted_frames_;
diff --git a/chromium/ui/ozone/platform/wayland/gpu/gl_surface_egl_readback_wayland.cc b/chromium/ui/ozone/platform/wayland/gpu/gl_surface_egl_readback_wayland.cc
index 195d061926c..5383fb8209c 100644
--- a/chromium/ui/ozone/platform/wayland/gpu/gl_surface_egl_readback_wayland.cc
+++ b/chromium/ui/ozone/platform/wayland/gpu/gl_surface_egl_readback_wayland.cc
@@ -116,8 +116,9 @@ void GLSurfaceEglReadbackWayland::SwapBuffersAsync(
CHECK(next_buffer->shm_mapping_.memory());
ReadPixels(next_buffer->shm_mapping_.memory());
- buffer_manager_->CommitBuffer(widget_, next_buffer->buffer_id_,
- {{0, 0}, GetSize()});
+ const auto bounds = gfx::Rect(GetSize());
+ buffer_manager_->CommitBuffer(widget_, next_buffer->buffer_id_, bounds,
+ bounds);
}
gfx::SurfaceOrigin GLSurfaceEglReadbackWayland::GetOrigin() const {
diff --git a/chromium/ui/ozone/platform/wayland/gpu/gl_surface_wayland.cc b/chromium/ui/ozone/platform/wayland/gpu/gl_surface_wayland.cc
index e5cdaf12895..b430a061c26 100644
--- a/chromium/ui/ozone/platform/wayland/gpu/gl_surface_wayland.cc
+++ b/chromium/ui/ozone/platform/wayland/gpu/gl_surface_wayland.cc
@@ -46,21 +46,21 @@ bool GLSurfaceWayland::Resize(const gfx::Size& size,
EGLConfig GLSurfaceWayland::GetConfig() {
if (!config_) {
- GLint config_attribs[] = {EGL_BUFFER_SIZE,
- 32,
- EGL_ALPHA_SIZE,
- 8,
- EGL_BLUE_SIZE,
- 8,
- EGL_GREEN_SIZE,
- 8,
- EGL_RED_SIZE,
- 8,
- EGL_RENDERABLE_TYPE,
- EGL_OPENGL_ES2_BIT,
- EGL_SURFACE_TYPE,
- EGL_WINDOW_BIT,
- EGL_NONE};
+ EGLint config_attribs[] = {EGL_BUFFER_SIZE,
+ 32,
+ EGL_ALPHA_SIZE,
+ 8,
+ EGL_BLUE_SIZE,
+ 8,
+ EGL_GREEN_SIZE,
+ 8,
+ EGL_RED_SIZE,
+ 8,
+ EGL_RENDERABLE_TYPE,
+ EGL_OPENGL_ES2_BIT,
+ EGL_SURFACE_TYPE,
+ EGL_WINDOW_BIT,
+ EGL_NONE};
config_ = ChooseEGLConfig(GetDisplay(), config_attribs);
}
return config_;
diff --git a/chromium/ui/ozone/platform/wayland/gpu/vulkan_implementation_wayland.cc b/chromium/ui/ozone/platform/wayland/gpu/vulkan_implementation_wayland.cc
index 3a2be4275ef..1a3335da4e2 100644
--- a/chromium/ui/ozone/platform/wayland/gpu/vulkan_implementation_wayland.cc
+++ b/chromium/ui/ozone/platform/wayland/gpu/vulkan_implementation_wayland.cc
@@ -34,8 +34,8 @@ bool InitializeVulkanFunctionPointers(
} // namespace
-VulkanImplementationWayland::VulkanImplementationWayland()
- : gpu::VulkanImplementation(false /* use_swiftshader */) {}
+VulkanImplementationWayland::VulkanImplementationWayland(bool use_swiftshader)
+ : gpu::VulkanImplementation(use_swiftshader) {}
VulkanImplementationWayland::~VulkanImplementationWayland() {}
@@ -47,14 +47,20 @@ bool VulkanImplementationWayland::InitializeVulkanInstance(bool using_surface) {
auto* vulkan_function_pointers = gpu::GetVulkanFunctionPointers();
- base::FilePath path("libvulkan.so.1");
+ base::FilePath path;
+ if (use_swiftshader()) {
+ if (!base::PathService::Get(base::DIR_MODULE, &path))
+ return false;
+
+ path = path.Append("libvk_swiftshader.so");
+ } else {
+ path = base::FilePath("libvulkan.so.1");
+ }
if (!InitializeVulkanFunctionPointers(path, vulkan_function_pointers))
return false;
- if (!vulkan_instance_.Initialize(required_extensions, {}))
- return false;
- return true;
+ return vulkan_instance_.Initialize(required_extensions, {});
}
gpu::VulkanInstance* VulkanImplementationWayland::GetVulkanInstance() {
@@ -77,13 +83,16 @@ bool VulkanImplementationWayland::GetPhysicalDevicePresentationSupport(
std::vector<const char*>
VulkanImplementationWayland::GetRequiredDeviceExtensions() {
- return {
- VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME,
+ std::vector<const char*> result{
VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME,
VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME,
VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME,
VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME,
};
+
+ if (!use_swiftshader())
+ result.push_back(VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME);
+ return result;
}
std::vector<const char*>
diff --git a/chromium/ui/ozone/platform/wayland/gpu/vulkan_implementation_wayland.h b/chromium/ui/ozone/platform/wayland/gpu/vulkan_implementation_wayland.h
index e504ac313ef..5acd1e07945 100644
--- a/chromium/ui/ozone/platform/wayland/gpu/vulkan_implementation_wayland.h
+++ b/chromium/ui/ozone/platform/wayland/gpu/vulkan_implementation_wayland.h
@@ -14,7 +14,7 @@ namespace ui {
class VulkanImplementationWayland : public gpu::VulkanImplementation {
public:
- VulkanImplementationWayland();
+ explicit VulkanImplementationWayland(bool use_swiftshader = false);
~VulkanImplementationWayland() override;
VulkanImplementationWayland(const VulkanImplementationWayland&) = delete;
@@ -56,4 +56,4 @@ class VulkanImplementationWayland : public gpu::VulkanImplementation {
} // namespace ui
-#endif // UI_OZONE_PLATFORM_WAYLAND_GPU_VULKAN_IMPLEMENTATION_WAYLAND_H_ \ No newline at end of file
+#endif // UI_OZONE_PLATFORM_WAYLAND_GPU_VULKAN_IMPLEMENTATION_WAYLAND_H_
diff --git a/chromium/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.cc b/chromium/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.cc
index 5c14a1c918f..da7ce23565e 100644
--- a/chromium/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.cc
+++ b/chromium/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.cc
@@ -44,7 +44,8 @@ void WaylandBufferManagerGpu::Initialize(
mojo::PendingRemote<ozone::mojom::WaylandBufferManagerHost> remote_host,
const base::flat_map<::gfx::BufferFormat, std::vector<uint64_t>>&
buffer_formats_with_modifiers,
- bool supports_dma_buf) {
+ bool supports_dma_buf,
+ bool supports_acquire_fence) {
DCHECK(supported_buffer_formats_with_modifiers_.empty());
supported_buffer_formats_with_modifiers_ = buffer_formats_with_modifiers;
@@ -52,6 +53,7 @@ void WaylandBufferManagerGpu::Initialize(
if (!supports_dma_buf)
set_gbm_device(nullptr);
#endif
+ supports_acquire_fence_ = supports_acquire_fence;
BindHostInterface(std::move(remote_host));
@@ -182,18 +184,16 @@ void WaylandBufferManagerGpu::CreateShmBasedBuffer(
void WaylandBufferManagerGpu::CommitBuffer(gfx::AcceleratedWidget widget,
uint32_t buffer_id,
+ const gfx::Rect& bounds_rect,
const gfx::Rect& damage_region) {
- if (!remote_host_) {
- LOG(ERROR) << "Interface is not bound. Can't request "
- "WaylandBufferManagerHost to create/commit/destroy buffers.";
- return;
- }
-
- // Do the mojo call on the IO child thread.
- io_thread_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(&WaylandBufferManagerGpu::CommitBufferInternal,
- base::Unretained(this), widget, buffer_id, damage_region));
+ std::vector<ui::ozone::mojom::WaylandOverlayConfigPtr> overlay_configs;
+ // This surface only commits one buffer per frame, use INT32_MIN to attach
+ // the buffer to root_surface of wayland window.
+ overlay_configs.push_back(ui::ozone::mojom::WaylandOverlayConfig::New(
+ INT32_MIN, gfx::OverlayTransform::OVERLAY_TRANSFORM_NONE, buffer_id,
+ bounds_rect, gfx::RectF(), damage_region, false, gfx::GpuFenceHandle()));
+
+ CommitOverlays(widget, std::move(overlay_configs));
}
void WaylandBufferManagerGpu::CommitOverlays(
@@ -271,14 +271,6 @@ void WaylandBufferManagerGpu::CreateShmBasedBufferInternal(
length, size, buffer_id);
}
-void WaylandBufferManagerGpu::CommitBufferInternal(
- gfx::AcceleratedWidget widget,
- uint32_t buffer_id,
- const gfx::Rect& damage_region) {
- DCHECK(io_thread_runner_->BelongsToCurrentThread());
- remote_host_->CommitBuffer(widget, buffer_id, damage_region);
-}
-
void WaylandBufferManagerGpu::CommitOverlaysInternal(
gfx::AcceleratedWidget widget,
std::vector<ozone::mojom::WaylandOverlayConfigPtr> overlays) {
diff --git a/chromium/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.h b/chromium/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.h
index 1f451202652..8123ade0306 100644
--- a/chromium/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.h
+++ b/chromium/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.h
@@ -26,7 +26,6 @@
namespace gfx {
enum class SwapResult;
-class Rect;
} // namespace gfx
namespace ui {
@@ -51,7 +50,8 @@ class WaylandBufferManagerGpu : public ozone::mojom::WaylandBufferManagerGpu {
mojo::PendingRemote<ozone::mojom::WaylandBufferManagerHost> remote_host,
const base::flat_map<::gfx::BufferFormat, std::vector<uint64_t>>&
buffer_formats_with_modifiers,
- bool supports_dma_buf) override;
+ bool supports_dma_buf,
+ bool supports_acquire_fence) override;
// These two calls get the surface, which backs the |widget| and notifies it
// about the submission and the presentation. After the surface receives the
@@ -103,10 +103,13 @@ class WaylandBufferManagerGpu : public ozone::mojom::WaylandBufferManagerGpu {
// logic as well. This call must not be done twice for the same |widget| until
// the OnSubmission is called (which actually means the client can continue
// sending buffer swap requests).
+ //
+ // CommitBuffer() calls CommitOverlays() to commit only a primary plane
+ // buffer.
void CommitBuffer(gfx::AcceleratedWidget widget,
uint32_t buffer_id,
+ const gfx::Rect& bounds_rect,
const gfx::Rect& damage_region);
-
// Send overlay configurations for a frame to a WaylandWindow identified by
// |widget|.
void CommitOverlays(
@@ -124,6 +127,8 @@ class WaylandBufferManagerGpu : public ozone::mojom::WaylandBufferManagerGpu {
}
#endif
+ bool supports_acquire_fence() const { return supports_acquire_fence_; }
+
// Adds a WaylandBufferManagerGpu binding.
void AddBindingWaylandBufferManagerGpu(
mojo::PendingReceiver<ozone::mojom::WaylandBufferManagerGpu> receiver);
@@ -148,9 +153,6 @@ class WaylandBufferManagerGpu : public ozone::mojom::WaylandBufferManagerGpu {
size_t length,
gfx::Size size,
uint32_t buffer_id);
- void CommitBufferInternal(gfx::AcceleratedWidget widget,
- uint32_t buffer_id,
- const gfx::Rect& damage_region);
void CommitOverlaysInternal(
gfx::AcceleratedWidget widget,
std::vector<ozone::mojom::WaylandOverlayConfigPtr> overlays);
@@ -178,6 +180,8 @@ class WaylandBufferManagerGpu : public ozone::mojom::WaylandBufferManagerGpu {
// A DRM render node based gbm device.
std::unique_ptr<GbmDevice> gbm_device_;
#endif
+ // Whether Wayland server allows buffer submission with acquire fence.
+ bool supports_acquire_fence_ = false;
mojo::Receiver<ozone::mojom::WaylandBufferManagerGpu> receiver_{this};
diff --git a/chromium/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.cc b/chromium/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.cc
index deb43b013e4..bb7029b7d29 100644
--- a/chromium/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.cc
+++ b/chromium/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.cc
@@ -58,6 +58,7 @@ class WaylandCanvasSurface::SharedMemoryBuffer {
// based wl_buffer, which can be attached to a surface and have its contents
// shown on a screen.
bool Initialize(const gfx::Size& size) {
+ size_ = size;
base::CheckedNumeric<size_t> checked_length(size.width());
checked_length *= size.height();
checked_length *= 4;
@@ -92,7 +93,8 @@ class WaylandCanvasSurface::SharedMemoryBuffer {
}
void CommitBuffer(const gfx::Rect& damage) {
- buffer_manager_->CommitBuffer(widget_, buffer_id_, damage);
+ buffer_manager_->CommitBuffer(widget_, buffer_id_, gfx::Rect(size_),
+ damage);
}
void OnUse() {
@@ -134,6 +136,9 @@ class WaylandCanvasSurface::SharedMemoryBuffer {
}
private:
+ // The size of the buffer.
+ gfx::Size size_;
+
// The id of the buffer this surface is backed.
const uint32_t buffer_id_;
diff --git a/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory.cc b/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory.cc
index 0f20a7c0c39..18f555b2076 100644
--- a/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory.cc
+++ b/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory.cc
@@ -164,9 +164,10 @@ GLOzone* WaylandSurfaceFactory::GetGLOzone(
#if BUILDFLAG(ENABLE_VULKAN)
std::unique_ptr<gpu::VulkanImplementation>
WaylandSurfaceFactory::CreateVulkanImplementation(
+ bool use_swiftshader,
bool allow_protected_memory,
bool enforce_protected_memory) {
- return std::make_unique<VulkanImplementationWayland>();
+ return std::make_unique<VulkanImplementationWayland>(use_swiftshader);
}
#endif
diff --git a/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory.h b/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory.h
index 1de11ed0104..18a0319c1d9 100644
--- a/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory.h
+++ b/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory.h
@@ -31,6 +31,7 @@ class WaylandSurfaceFactory : public SurfaceFactoryOzone {
GLOzone* GetGLOzone(gl::GLImplementation implementation) override;
#if BUILDFLAG(ENABLE_VULKAN)
std::unique_ptr<gpu::VulkanImplementation> CreateVulkanImplementation(
+ bool use_swiftshader,
bool allow_protected_memory,
bool enforce_protected_memory) override;
#endif
diff --git a/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc b/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc
index cc71dc65c2b..310d4a9be16 100644
--- a/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc
+++ b/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc
@@ -178,7 +178,7 @@ class WaylandSurfaceFactoryTest : public WaylandTest {
WaylandTest::SetUp();
auto manager_ptr = connection_->buffer_manager_host()->BindInterface();
- buffer_manager_gpu_->Initialize(std::move(manager_ptr), {}, false);
+ buffer_manager_gpu_->Initialize(std::move(manager_ptr), {}, false, false);
// Wait until initialization and mojo calls go through.
base::RunLoop().RunUntilIdle();
@@ -204,221 +204,10 @@ class WaylandSurfaceFactoryTest : public WaylandTest {
};
TEST_P(WaylandSurfaceFactoryTest,
- GbmSurfacelessWaylandCheckOrderOfCallbacksTest) {
- gl::SetGLImplementation(gl::kGLImplementationEGLGLES2);
-
- buffer_manager_gpu_->set_gbm_device(std::make_unique<MockGbmDevice>());
-
- auto* gl_ozone = surface_factory_->GetGLOzone(gl::kGLImplementationEGLGLES2);
- auto gl_surface = gl_ozone->CreateSurfacelessViewGLSurface(widget_);
- EXPECT_TRUE(gl_surface);
- gl_surface->SetRelyOnImplicitSync();
- static_cast<ui::GbmSurfacelessWayland*>(gl_surface.get())
- ->SetNoGLFlushForTests();
-
- // Expect to create 3 buffers.
- EXPECT_CALL(*server_.zwp_linux_dmabuf_v1(), CreateParams(_, _, _)).Times(3);
-
- // Create buffers and FakeGlImageNativePixmap.
- std::vector<scoped_refptr<FakeGLImageNativePixmap>> fake_gl_image;
- for (int i = 0; i < 3; ++i) {
- auto native_pixmap = surface_factory_->CreateNativePixmap(
- widget_, nullptr, window_->GetBounds().size(),
- gfx::BufferFormat::BGRA_8888, gfx::BufferUsage::SCANOUT);
- fake_gl_image.push_back(base::MakeRefCounted<FakeGLImageNativePixmap>(
- native_pixmap, window_->GetBounds().size()));
-
- Sync();
-
- // Create one buffer at a time.
- auto params_vector = server_.zwp_linux_dmabuf_v1()->buffer_params();
- DCHECK_EQ(params_vector.size(), 1u);
- zwp_linux_buffer_params_v1_send_created(
- params_vector.front()->resource(),
- params_vector.front()->buffer_resource());
-
- Sync();
- }
-
- // Now, schedule 3 buffers for swap.
- auto* mock_surface = server_.GetObject<wl::MockSurface>(
- window_->root_surface()->GetSurfaceId());
-
- CallbacksHelper cbs_helper;
- // Submit all the available buffers.
- for (const auto& gl_image : fake_gl_image) {
- // Associate each image with swap id so that we could track released
- // buffers.
- auto swap_id = cbs_helper.GetNextLocalSwapId();
- // Associate the image with the next swap id so that we can easily track if
- // it became free to reuse.
- gl_image->AssociateWithSwapId(swap_id);
- // And set it to be busy...
- gl_image->SetBusy(true);
-
- // Prepare overlay plane.
- gl_surface->ScheduleOverlayPlane(
- INT32_MIN, gfx::OverlayTransform::OVERLAY_TRANSFORM_FLIP_VERTICAL,
- gl_image.get(), window_->GetBounds(), {}, false, nullptr);
-
- std::vector<scoped_refptr<FakeGLImageNativePixmap>> gl_images;
- gl_images.push_back(gl_image);
-
- // And submit each image. They will be executed in FIFO manner.
- gl_surface->SwapBuffersAsync(
- base::BindOnce(&CallbacksHelper::FinishSwapBuffersAsync,
- base::Unretained(&cbs_helper), swap_id, gl_images),
- base::BindOnce(&CallbacksHelper::BufferPresented,
- base::Unretained(&cbs_helper), swap_id));
- }
-
- // Let's sync so that 1) GbmSurfacelessWayland submits the buffer according to
- // internal queue and fake server processes the request.
-
- // Also, we expect only one buffer to be committed.
- EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(1);
- EXPECT_CALL(*mock_surface, Frame(_)).Times(1);
- EXPECT_CALL(*mock_surface, DamageBuffer(_, _, _, _)).Times(1);
- EXPECT_CALL(*mock_surface, Commit()).Times(1);
-
- Sync();
-
- testing::Mock::VerifyAndClearExpectations(&mock_surface);
-
- // Give mojo the chance to pass the callbacks.
- base::RunLoop().RunUntilIdle();
-
- // We have just received Attach/DamageBuffer/Commit for buffer with swap
- // id=0u. The SwapCompletionCallback must be executed automatically as long as
- // we didn't have any buffers attached to the surface before.
- EXPECT_EQ(cbs_helper.GetLastFinishedSwapId(), 0u);
-
- cbs_helper.ResetLastFinishedSwapId();
-
- for (const auto& gl_image : fake_gl_image) {
- // All the images except the first one, which was associated with swap
- // id=0u, must be busy and not displayed. The first one must be displayed.
- if (gl_image->GetAssociateWithSwapId() == 0u) {
- EXPECT_FALSE(gl_image->busy());
- EXPECT_TRUE(gl_image->displayed());
- } else {
- EXPECT_TRUE(gl_image->busy());
- EXPECT_FALSE(gl_image->displayed());
- }
- }
-
- // Expect buffer for swap with id=1u to be committed.
- EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(1);
- EXPECT_CALL(*mock_surface, Frame(_)).Times(1);
- EXPECT_CALL(*mock_surface, DamageBuffer(_, _, _, _)).Times(1);
- EXPECT_CALL(*mock_surface, Commit()).Times(1);
-
- // Send the frame callback so that pending buffer for swap id=1u is processed
- // and swapped.
- mock_surface->SendFrameCallback();
-
- Sync();
-
- // Give mojo the chance to pass the callbacks.
- base::RunLoop().RunUntilIdle();
-
- // Even though the second buffer was submitted, we mustn't receive
- // SwapCompletionCallback until the previous buffer is released.
- EXPECT_EQ(cbs_helper.GetLastFinishedSwapId(),
- std::numeric_limits<uint32_t>::max());
-
- // This will result in Wayland server releasing previously attached buffer for
- // swap id=0u and calling OnSubmission for buffer with swap id=1u.
- mock_surface->ReleaseBuffer(mock_surface->prev_attached_buffer());
-
- Sync();
-
- // Give mojo the chance to pass the callbacks.
- base::RunLoop().RunUntilIdle();
-
- // We expect only one buffer to be released. Thus, the last swap id must be
- // 0 as we waited until next buffer was attached to the surface.
- EXPECT_EQ(cbs_helper.GetLastFinishedSwapId(), 1u);
-
- // Reset to test further swap ids.
- cbs_helper.ResetLastFinishedSwapId();
-
- for (const auto& gl_image : fake_gl_image) {
- // The first image is not displayed and not busy, the second is displayed
- // and not busy. And others are not display and busy.
- if (gl_image->GetAssociateWithSwapId() == 0u) {
- EXPECT_FALSE(gl_image->busy());
- EXPECT_FALSE(gl_image->displayed());
- } else if (gl_image->GetAssociateWithSwapId() == 1u) {
- EXPECT_FALSE(gl_image->busy());
- EXPECT_TRUE(gl_image->displayed());
- } else {
- EXPECT_TRUE(gl_image->busy());
- EXPECT_FALSE(gl_image->displayed());
- }
- }
-
- EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(1);
- EXPECT_CALL(*mock_surface, Frame(_)).Times(1);
- EXPECT_CALL(*mock_surface, DamageBuffer(_, _, _, _)).Times(1);
- EXPECT_CALL(*mock_surface, Commit()).Times(1);
-
- // Send the frame callback, so that the pending buffer with swap id=2u can
- // be processed.
- mock_surface->SendFrameCallback();
-
- Sync();
-
- // Give mojo the chance to pass the callbacks.
- base::RunLoop().RunUntilIdle();
-
- // Even though the second buffer was submitted, we mustn't receive
- // SwapCompletionCallback until the previous buffer is released.
- EXPECT_EQ(cbs_helper.GetLastFinishedSwapId(),
- std::numeric_limits<uint32_t>::max());
-
- // This will result in Wayland server releasing previously attached buffer for
- // swap id=1u and calling OnSubmission for buffer with swap id=2u.
- mock_surface->ReleaseBuffer(mock_surface->prev_attached_buffer());
-
- Sync();
-
- // Give mojo the chance to pass the callbacks.
- base::RunLoop().RunUntilIdle();
-
- // We should receive next callbacks for the next swap id.
- EXPECT_EQ(cbs_helper.GetLastFinishedSwapId(), 2u);
-
- cbs_helper.ResetLastFinishedSwapId();
-
- // All images must be free now and the last one is displayed.
- for (const auto& gl_image : fake_gl_image) {
- if (gl_image->GetAssociateWithSwapId() == 2u) {
- EXPECT_TRUE(gl_image->displayed());
- EXPECT_FALSE(gl_image->busy());
- } else {
- EXPECT_FALSE(gl_image->displayed());
- EXPECT_FALSE(gl_image->busy());
- }
- }
-
- // There are no buffers left. Send last frame callback and verify that.
- EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(0);
- EXPECT_CALL(*mock_surface, Frame(_)).Times(0);
- EXPECT_CALL(*mock_surface, DamageBuffer(_, _, _, _)).Times(0);
- EXPECT_CALL(*mock_surface, Commit()).Times(0);
-
- // Send a frame callback so that the WaylandBufferManagerHost processes the
- // pending buffers if any exist.
- mock_surface->SendFrameCallback();
-}
-
-TEST_P(WaylandSurfaceFactoryTest,
GbmSurfacelessWaylandCommitOverlaysCallbacksTest) {
- // GbmSurfacelessWaylandCheckOrderOfCallbacksTest tests with one buffer per
- // frame. This tests multiple buffers per-frame and order of
- // SwapCompletionCallbacks. Even when all OnSubmission from later frames are
- // called, their SwapCompletionCallbacks should not run until previous frames'
+ // This tests multiple buffers per-frame and order of SwapCompletionCallbacks.
+ // Even when all OnSubmission from later frames are called, their
+ // SwapCompletionCallbacks should not run until previous frames'
// SwapCompletionCallbacks run.
gl::SetGLImplementation(gl::kGLImplementationEGLGLES2);
@@ -493,10 +282,10 @@ TEST_P(WaylandSurfaceFactoryTest,
// Also, we expect only one buffer to be committed.
EXPECT_CALL(*mock_primary_surface, Attach(_, _, _)).Times(1);
- EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(0);
+ EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(1);
EXPECT_CALL(*mock_primary_surface, DamageBuffer(_, _, _, _)).Times(1);
EXPECT_CALL(*mock_primary_surface, Commit()).Times(1);
- EXPECT_CALL(*root_surface, Frame(_)).Times(1);
+ EXPECT_CALL(*root_surface, Frame(_)).Times(0);
EXPECT_CALL(*root_surface, Commit()).Times(1);
Sync();
@@ -553,15 +342,15 @@ TEST_P(WaylandSurfaceFactoryTest,
// Expect one buffer to be committed.
EXPECT_CALL(*mock_primary_surface, Attach(_, _, _)).Times(1);
- EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(0);
+ EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(1);
EXPECT_CALL(*mock_primary_surface, DamageBuffer(_, _, _, _)).Times(1);
EXPECT_CALL(*mock_primary_surface, Commit()).Times(1);
- EXPECT_CALL(*root_surface, Frame(_)).Times(1);
+ EXPECT_CALL(*root_surface, Frame(_)).Times(0);
EXPECT_CALL(*root_surface, Commit()).Times(1);
// Send the frame callback so that pending buffer for swap id=1u is processed
// and swapped.
- root_surface->SendFrameCallback();
+ mock_primary_surface->SendFrameCallback();
Sync();
@@ -620,12 +409,12 @@ TEST_P(WaylandSurfaceFactoryTest,
EXPECT_CALL(*mock_primary_surface, DamageBuffer(_, _, _, _)).Times(0);
EXPECT_CALL(*mock_primary_surface, Commit()).Times(0);
// Expect root surface to be committed.
- EXPECT_CALL(*root_surface, Frame(_)).Times(1);
+ EXPECT_CALL(*root_surface, Frame(_)).Times(0);
EXPECT_CALL(*root_surface, Commit()).Times(1);
// Send the frame callback so that pending buffer for swap id=2u is processed
// and swapped.
- root_surface->SendFrameCallback();
+ mock_primary_surface->SendFrameCallback();
Sync();
@@ -754,10 +543,10 @@ TEST_P(WaylandSurfaceFactoryTest,
// Also, we expect primary buffer to be committed.
EXPECT_CALL(*mock_primary_surface, Attach(_, _, _)).Times(1);
- EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(0);
+ EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(1);
EXPECT_CALL(*mock_primary_surface, DamageBuffer(_, _, _, _)).Times(1);
EXPECT_CALL(*mock_primary_surface, Commit()).Times(1);
- EXPECT_CALL(*root_surface, Frame(_)).Times(1);
+ EXPECT_CALL(*root_surface, Frame(_)).Times(0);
EXPECT_CALL(*root_surface, Commit()).Times(1);
Sync();
@@ -829,23 +618,24 @@ TEST_P(WaylandSurfaceFactoryTest,
// Expect primary buffer to be committed.
EXPECT_CALL(*mock_primary_surface, Attach(_, _, _)).Times(1);
- EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(0);
+ EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(1);
EXPECT_CALL(*mock_primary_surface, DamageBuffer(_, _, _, _)).Times(1);
EXPECT_CALL(*mock_primary_surface, Commit()).Times(1);
// Expect overlay buffer to be committed.
EXPECT_CALL(*mock_overlay_surface, Attach(_, _, _)).Times(1);
- EXPECT_CALL(*mock_overlay_surface, Frame(_)).Times(0);
+ EXPECT_CALL(*mock_overlay_surface, Frame(_)).Times(1);
EXPECT_CALL(*mock_overlay_surface, DamageBuffer(_, _, _, _)).Times(1);
EXPECT_CALL(*mock_overlay_surface, Commit()).Times(1);
// Expect root surface to be committed without buffer.
- EXPECT_CALL(*root_surface, Frame(_)).Times(1);
+ EXPECT_CALL(*root_surface, Frame(_)).Times(0);
EXPECT_CALL(*root_surface, Commit()).Times(1);
// Send the frame callback so that pending buffer for swap id=1u is processed
// and swapped.
- root_surface->SendFrameCallback();
+ mock_overlay_surface->SendFrameCallback();
+ mock_primary_surface->SendFrameCallback();
Sync();
diff --git a/chromium/ui/ozone/platform/wayland/host/DEPS b/chromium/ui/ozone/platform/wayland/host/DEPS
index 3ed58be77cd..b9371fab272 100644
--- a/chromium/ui/ozone/platform/wayland/host/DEPS
+++ b/chromium/ui/ozone/platform/wayland/host/DEPS
@@ -1,5 +1,7 @@
include_rules = [
# For Lacros.
+ "+chromeos/crosapi/mojom",
"+chromeos/crosapi/cpp/crosapi_constants.h",
+ "+chromeos/lacros/lacros_chrome_service_impl.h",
"+chromeos/ui/base",
]
diff --git a/chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_device.cc b/chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_device.cc
index 45540640759..ed4dc91240c 100644
--- a/chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_device.cc
+++ b/chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_device.cc
@@ -41,10 +41,6 @@ void GtkPrimarySelectionDevice::OnDataOffer(
gtk_primary_selection_offer* offer) {
auto* self = static_cast<GtkPrimarySelectionDevice*>(data);
DCHECK(self);
-
- self->connection()->clipboard()->UpdateSequenceNumber(
- ClipboardBuffer::kSelection);
-
self->set_data_offer(std::make_unique<GtkPrimarySelectionOffer>(offer));
}
@@ -57,17 +53,16 @@ void GtkPrimarySelectionDevice::OnSelection(
DCHECK(self);
// 'offer' will be null to indicate that the selection is no longer valid,
- // i.e. there is no longer clipboard data available to paste.
+ // i.e. there is no longer selection data available to be fetched.
if (!offer) {
self->ResetDataOffer();
-
- // Clear Clipboard cache.
- self->connection()->clipboard()->SetData({}, {});
- return;
+ } else {
+ DCHECK(self->data_offer());
+ self->data_offer()->EnsureTextMimeTypeIfNeeded();
}
- DCHECK(self->data_offer());
- self->data_offer()->EnsureTextMimeTypeIfNeeded();
+ if (self->selection_delegate())
+ self->selection_delegate()->OnSelectionOffer(self->data_offer());
}
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.cc b/chromium/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.cc
index 0a0e4712910..cb501cbd8f0 100644
--- a/chromium/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.cc
+++ b/chromium/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.cc
@@ -4,24 +4,31 @@
#include "ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.h"
-#include <gdk/gdkwayland.h>
#include <gtk/gtk.h>
#include <memory>
#include "base/bind.h"
+#include "base/environment.h"
#include "base/logging.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_event_source.h"
#include "ui/ozone/platform/wayland/host/wayland_surface.h"
#include "ui/ozone/platform/wayland/host/wayland_window.h"
#include "ui/ozone/platform/wayland/host/wayland_window_manager.h"
#include "ui/ozone/platform/wayland/host/xdg_foreign_wrapper.h"
#include "ui/platform_window/platform_window_init_properties.h"
+#if GTK_CHECK_VERSION(3, 90, 0)
+#include <gdk/wayland/gdkwayland.h>
+#else
+#include <gdk/gdkwayland.h>
+
#define WEAK_GTK_FN(x) extern "C" __attribute__((weak)) decltype(x) x
WEAK_GTK_FN(gdk_wayland_window_set_transient_for_exported);
+#endif
namespace ui {
@@ -29,6 +36,9 @@ GtkUiDelegateWayland::GtkUiDelegateWayland(WaylandConnection* connection)
: connection_(connection) {
DCHECK(connection_);
gdk_set_allowed_backends("wayland");
+ // GDK_BACKEND takes precedence over gdk_set_allowed_backends(), so override
+ // it to ensure we get the wayland backend.
+ base::Environment::Create()->SetVar("GDK_BACKEND", "wayland");
}
GtkUiDelegateWayland::~GtkUiDelegateWayland() = default;
@@ -51,12 +61,14 @@ GdkWindow* GtkUiDelegateWayland::GetGdkWindow(
bool GtkUiDelegateWayland::SetGdkWindowTransientFor(
GdkWindow* window,
gfx::AcceleratedWidget parent) {
+#if !GTK_CHECK_VERSION(3, 90, 0)
if (!gdk_wayland_window_set_transient_for_exported) {
LOG(WARNING) << "set_transient_for_exported not supported in GTK version "
<< GTK_MAJOR_VERSION << '.' << GTK_MINOR_VERSION << '.'
<< GTK_MICRO_VERSION;
return false;
}
+#endif
auto* parent_window =
connection_->wayland_window_manager()->GetWindow(parent);
@@ -82,10 +94,19 @@ void GtkUiDelegateWayland::ShowGtkWindow(GtkWindow* window) {
gtk_window_present(window);
}
+int GtkUiDelegateWayland::GetGdkKeyState() {
+ // TODO(crbug/1159460): Test fcitx unikey IME on ozone/wayland.
+ return connection_->event_source()->keyboard_modifiers();
+}
+
void GtkUiDelegateWayland::OnHandle(GdkWindow* window,
const std::string& handle) {
- gdk_wayland_window_set_transient_for_exported(
- window, const_cast<char*>(handle.c_str()));
+ char* parent = const_cast<char*>(handle.c_str());
+#if GTK_CHECK_VERSION(3, 90, 0)
+ gdk_wayland_toplevel_set_transient_for_exported(GDK_TOPLEVEL(window), parent);
+#else
+ gdk_wayland_window_set_transient_for_exported(window, parent);
+#endif
}
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.h b/chromium/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.h
index e5e23aeddac..d198057b8ca 100644
--- a/chromium/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.h
+++ b/chromium/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.h
@@ -30,6 +30,7 @@ class GtkUiDelegateWayland : public GtkUiDelegate {
gfx::AcceleratedWidget parent) override;
void ClearTransientFor(gfx::AcceleratedWidget parent) override;
void ShowGtkWindow(GtkWindow* window) override;
+ int GetGdkKeyState() override;
private:
// Called when xdg-foreign exports a parent window passed in
diff --git a/chromium/ui/ozone/platform/wayland/host/shell_object_factory.cc b/chromium/ui/ozone/platform/wayland/host/shell_object_factory.cc
index dea71480eb6..ed7842b76c2 100644
--- a/chromium/ui/ozone/platform/wayland/host/shell_object_factory.cc
+++ b/chromium/ui/ozone/platform/wayland/host/shell_object_factory.cc
@@ -8,20 +8,37 @@
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
#include "ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h"
#include "ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h"
+#include "ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.h"
+#include "ui/ozone/platform/wayland/host/zxdg_popup_v6_wrapper_impl.h"
+#include "ui/ozone/platform/wayland/host/zxdg_surface_v6_wrapper_impl.h"
+#include "ui/ozone/platform/wayland/host/zxdg_toplevel_v6_wrapper_impl.h"
namespace ui {
ShellObjectFactory::ShellObjectFactory() = default;
ShellObjectFactory::~ShellObjectFactory() = default;
-std::unique_ptr<ShellSurfaceWrapper>
-ShellObjectFactory::CreateShellSurfaceWrapper(WaylandConnection* connection,
- WaylandWindow* wayland_window) {
- if (connection->shell() || connection->shell_v6()) {
+std::unique_ptr<ShellToplevelWrapper>
+ShellObjectFactory::CreateShellToplevelWrapper(WaylandConnection* connection,
+ WaylandWindow* wayland_window) {
+ if (connection->shell()) {
auto surface =
std::make_unique<XDGSurfaceWrapperImpl>(wayland_window, connection);
- return surface->Initialize(true /* with_top_level */) ? std::move(surface)
- : nullptr;
+ if (!surface->Initialize())
+ return nullptr;
+
+ auto toplevel = std::make_unique<XDGToplevelWrapperImpl>(
+ std::move(surface), wayland_window, connection);
+ return toplevel->Initialize() ? std::move(toplevel) : nullptr;
+ } else if (connection->shell_v6()) {
+ auto surface =
+ std::make_unique<ZXDGSurfaceV6WrapperImpl>(wayland_window, connection);
+ if (!surface->Initialize())
+ return nullptr;
+
+ auto toplevel = std::make_unique<ZXDGToplevelV6WrapperImpl>(
+ std::move(surface), wayland_window, connection);
+ return toplevel->Initialize() ? std::move(toplevel) : nullptr;
}
LOG(WARNING) << "Shell protocol is not available.";
return nullptr;
@@ -31,15 +48,24 @@ std::unique_ptr<ShellPopupWrapper> ShellObjectFactory::CreateShellPopupWrapper(
WaylandConnection* connection,
WaylandWindow* wayland_window,
const gfx::Rect& bounds) {
- if (connection->shell() || connection->shell_v6()) {
+ if (connection->shell()) {
auto surface =
std::make_unique<XDGSurfaceWrapperImpl>(wayland_window, connection);
- if (!surface->Initialize(false /* with_top_level */))
+ if (!surface->Initialize())
return nullptr;
auto popup = std::make_unique<XDGPopupWrapperImpl>(std::move(surface),
wayland_window);
return popup->Initialize(connection, bounds) ? std::move(popup) : nullptr;
+ } else if (connection->shell_v6()) {
+ auto surface =
+ std::make_unique<ZXDGSurfaceV6WrapperImpl>(wayland_window, connection);
+ if (!surface->Initialize())
+ return nullptr;
+
+ auto popup = std::make_unique<ZXDGPopupV6WrapperImpl>(std::move(surface),
+ wayland_window);
+ return popup->Initialize(connection, bounds) ? std::move(popup) : nullptr;
}
LOG(WARNING) << "Shell protocol is not available.";
return nullptr;
diff --git a/chromium/ui/ozone/platform/wayland/host/shell_object_factory.h b/chromium/ui/ozone/platform/wayland/host/shell_object_factory.h
index a915326c23f..da3472a5018 100644
--- a/chromium/ui/ozone/platform/wayland/host/shell_object_factory.h
+++ b/chromium/ui/ozone/platform/wayland/host/shell_object_factory.h
@@ -13,7 +13,7 @@ class Rect;
namespace ui {
-class ShellSurfaceWrapper;
+class ShellToplevelWrapper;
class ShellPopupWrapper;
class WaylandConnection;
class WaylandWindow;
@@ -27,8 +27,8 @@ class ShellObjectFactory {
ShellObjectFactory();
~ShellObjectFactory();
- // Creates and initializes a ShellSurfaceWrapper.
- std::unique_ptr<ShellSurfaceWrapper> CreateShellSurfaceWrapper(
+ // Creates and initializes a ShellToplevelWrapper.
+ std::unique_ptr<ShellToplevelWrapper> CreateShellToplevelWrapper(
WaylandConnection* connection,
WaylandWindow* wayland_window);
@@ -41,4 +41,4 @@ class ShellObjectFactory {
} // namespace ui
-#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_SHELL_OBJECT_FACTORY_H_ \ No newline at end of file
+#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_SHELL_OBJECT_FACTORY_H_
diff --git a/chromium/ui/ozone/platform/wayland/host/shell_popup_wrapper.cc b/chromium/ui/ozone/platform/wayland/host/shell_popup_wrapper.cc
index f9f5aaa0825..bcf8fc25847 100644
--- a/chromium/ui/ozone/platform/wayland/host/shell_popup_wrapper.cc
+++ b/chromium/ui/ozone/platform/wayland/host/shell_popup_wrapper.cc
@@ -6,6 +6,10 @@
#include "base/check_op.h"
#include "base/notreached.h"
+#include "ui/ozone/platform/wayland/common/wayland_util.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_event_source.h"
+#include "ui/ozone/platform/wayland/host/wayland_toplevel_window.h"
namespace ui {
@@ -79,4 +83,119 @@ gfx::Rect GetAnchorRect(MenuType menu_type,
return anchor_rect;
}
+WlAnchor GetAnchor(MenuType menu_type, const gfx::Rect& bounds) {
+ WlAnchor anchor = WlAnchor::None;
+ switch (menu_type) {
+ case MenuType::TYPE_RIGHT_CLICK:
+ anchor = WlAnchor::TopLeft;
+ break;
+ case MenuType::TYPE_3DOT_PARENT_MENU:
+ anchor = WlAnchor::BottomRight;
+ break;
+ case MenuType::TYPE_3DOT_CHILD_MENU:
+ // Chromium may want to manually position a child menu on the left side of
+ // its parent menu. Thus, react accordingly. Positive x means the child is
+ // located on the right side of the parent and negative - on the left
+ // side.
+ if (bounds.x() >= 0)
+ anchor = WlAnchor::TopRight;
+ else
+ anchor = WlAnchor::TopLeft;
+ break;
+ case MenuType::TYPE_UNKNOWN:
+ NOTREACHED() << "Unsupported menu type";
+ break;
+ }
+
+ return anchor;
+}
+
+WlGravity GetGravity(MenuType menu_type, const gfx::Rect& bounds) {
+ WlGravity gravity = WlGravity::None;
+ switch (menu_type) {
+ case MenuType::TYPE_RIGHT_CLICK:
+ gravity = WlGravity::BottomRight;
+ break;
+ case MenuType::TYPE_3DOT_PARENT_MENU:
+ gravity = WlGravity::BottomRight;
+ break;
+ case MenuType::TYPE_3DOT_CHILD_MENU:
+ // Chromium may want to manually position a child menu on the left side of
+ // its parent menu. Thus, react accordingly. Positive x means the child is
+ // located on the right side of the parent and negative - on the left
+ // side.
+ if (bounds.x() >= 0)
+ gravity = WlGravity::BottomRight;
+ else
+ gravity = WlGravity::BottomLeft;
+ break;
+ case MenuType::TYPE_UNKNOWN:
+ NOTREACHED() << "Unsupported menu type";
+ break;
+ }
+
+ return gravity;
+}
+
+WlConstraintAdjustment GetConstraintAdjustment(MenuType menu_type) {
+ WlConstraintAdjustment constraint = WlConstraintAdjustment::None;
+
+ switch (menu_type) {
+ case MenuType::TYPE_RIGHT_CLICK:
+ constraint =
+ WlConstraintAdjustment::SlideX | WlConstraintAdjustment::SlideY |
+ WlConstraintAdjustment::FlipY | WlConstraintAdjustment::ResizeY;
+ break;
+ case MenuType::TYPE_3DOT_PARENT_MENU:
+ constraint = WlConstraintAdjustment::SlideX |
+ WlConstraintAdjustment::FlipY |
+ WlConstraintAdjustment::ResizeY;
+ break;
+ case MenuType::TYPE_3DOT_CHILD_MENU:
+ constraint = WlConstraintAdjustment::SlideY |
+ WlConstraintAdjustment::FlipX |
+ WlConstraintAdjustment::ResizeY;
+ break;
+ case MenuType::TYPE_UNKNOWN:
+ NOTREACHED() << "Unsupported menu type";
+ break;
+ }
+
+ return constraint;
+}
+
+MenuType ShellPopupWrapper::GetMenuTypeForPositioner(
+ WaylandConnection* connection,
+ WaylandWindow* parent_window) const {
+ bool is_right_click_menu =
+ connection->event_source()->last_pointer_button_pressed() &
+ EF_RIGHT_MOUSE_BUTTON;
+
+ // Different types of menu require different anchors, constraint adjustments,
+ // gravity and etc.
+ if (is_right_click_menu)
+ return MenuType::TYPE_RIGHT_CLICK;
+ else if (!wl::IsMenuType(parent_window->type()))
+ return MenuType::TYPE_3DOT_PARENT_MENU;
+ else
+ return MenuType::TYPE_3DOT_CHILD_MENU;
+}
+
+bool ShellPopupWrapper::CanGrabPopup(WaylandConnection* connection) const {
+ // When drag process starts, as described the protocol -
+ // https://goo.gl/1Mskq3, the client must have an active implicit grab. If
+ // we try to create a popup and grab it, it will be immediately dismissed.
+ // Thus, do not take explicit grab during drag process.
+ if (connection->IsDragInProgress() || !connection->seat())
+ return false;
+
+ // According to the definition of the xdg protocol, the grab request must be
+ // used in response to some sort of user action like a button press, key
+ // press, or touch down event.
+ EventType last_event_type = connection->event_serial().event_type;
+ return last_event_type == ET_TOUCH_PRESSED ||
+ last_event_type == ET_KEY_PRESSED ||
+ last_event_type == ET_MOUSE_PRESSED;
+}
+
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/shell_popup_wrapper.h b/chromium/ui/ozone/platform/wayland/host/shell_popup_wrapper.h
index 2970549dd09..77eaa71794d 100644
--- a/chromium/ui/ozone/platform/wayland/host/shell_popup_wrapper.h
+++ b/chromium/ui/ozone/platform/wayland/host/shell_popup_wrapper.h
@@ -11,6 +11,7 @@
namespace ui {
class WaylandConnection;
+class WaylandWindow;
enum class MenuType {
TYPE_RIGHT_CLICK,
@@ -73,11 +74,21 @@ class ShellPopupWrapper {
// Initializes the popup surface.
virtual bool Initialize(WaylandConnection* connection,
const gfx::Rect& bounds) = 0;
+
+ // Sends acknowledge configure event back to wayland.
+ virtual void AckConfigure(uint32_t serial) = 0;
+
+ MenuType GetMenuTypeForPositioner(WaylandConnection* connection,
+ WaylandWindow* parent_window) const;
+ bool CanGrabPopup(WaylandConnection* connection) const;
};
gfx::Rect GetAnchorRect(MenuType menu_type,
const gfx::Rect& menu_bounds,
const gfx::Rect& parent_window_bounds);
+WlAnchor GetAnchor(MenuType menu_type, const gfx::Rect& bounds);
+WlGravity GetGravity(MenuType menu_type, const gfx::Rect& bounds);
+WlConstraintAdjustment GetConstraintAdjustment(MenuType menu_type);
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/shell_surface_wrapper.h b/chromium/ui/ozone/platform/wayland/host/shell_surface_wrapper.h
index c75e87a627b..d89aacbb46f 100644
--- a/chromium/ui/ozone/platform/wayland/host/shell_surface_wrapper.h
+++ b/chromium/ui/ozone/platform/wayland/host/shell_surface_wrapper.h
@@ -5,8 +5,7 @@
#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_SHELL_SURFACE_WRAPPER_H_
#define UI_OZONE_PLATFORM_WAYLAND_HOST_SHELL_SURFACE_WRAPPER_H_
-#include "base/strings/string16.h"
-#include "ui/ozone/platform/wayland/common/wayland_object.h"
+#include <cstdint>
namespace gfx {
class Rect;
@@ -14,63 +13,21 @@ class Rect;
namespace ui {
-class WaylandConnection;
-
-// Wrapper interface for different wayland shells shell versions.
+// Wrapper interface for different wayland xdg-shell surface versions.
class ShellSurfaceWrapper {
public:
virtual ~ShellSurfaceWrapper() {}
- // Initializes the ShellSurface. Some protocols may require to create shell
- // surface without toplevel role and assign a popup role to it later.
- virtual bool Initialize(bool with_toplevel) = 0;
-
- // Sets a native window to maximized state.
- virtual void SetMaximized() = 0;
-
- // Unsets a native window from maximized state.
- virtual void UnSetMaximized() = 0;
-
- // Sets a native window to fullscreen state.
- virtual void SetFullscreen() = 0;
-
- // Unsets a native window from fullscreen state.
- virtual void UnSetFullscreen() = 0;
-
- // Sets a native window to minimized state.
- virtual void SetMinimized() = 0;
-
- // Tells wayland to start interactive window drag.
- virtual void SurfaceMove(WaylandConnection* connection) = 0;
-
- // Tells wayland to start interactive window resize.
- virtual void SurfaceResize(WaylandConnection* connection,
- uint32_t hittest) = 0;
-
- // Sets a title of a native window.
- virtual void SetTitle(const base::string16& title) = 0;
+ // Initializes the ShellSurface.
+ virtual bool Initialize() = 0;
// Sends acknowledge configure event back to wayland.
- virtual void AckConfigure() = 0;
+ virtual void AckConfigure(uint32_t serial) = 0;
// Sets a desired window geometry once wayland requests client to do so.
virtual void SetWindowGeometry(const gfx::Rect& bounds) = 0;
-
- // Sets the minimum size for the top level.
- virtual void SetMinSize(int32_t width, int32_t height) = 0;
-
- // Sets the maximum size for the top level.
- virtual void SetMaxSize(int32_t width, int32_t height) = 0;
-
- // Sets an app id of the native window that is shown as an application name
- // and hints the compositor that it can group application surfaces together by
- // their app id. This also helps the compositor to identify application's
- // .desktop file and use the icon set there.
- virtual void SetAppId(const std::string& app_id) = 0;
};
-bool CheckIfWlArrayHasValue(struct wl_array* wl_array, uint32_t value);
-
} // namespace ui
#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_SHELL_SURFACE_WRAPPER_H_
diff --git a/chromium/ui/ozone/platform/wayland/host/shell_surface_wrapper.cc b/chromium/ui/ozone/platform/wayland/host/shell_toplevel_wrapper.cc
index ea7d3ca8c94..e84d7ca63bb 100644
--- a/chromium/ui/ozone/platform/wayland/host/shell_surface_wrapper.cc
+++ b/chromium/ui/ozone/platform/wayland/host/shell_toplevel_wrapper.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/ozone/platform/wayland/host/shell_surface_wrapper.h"
+#include "ui/ozone/platform/wayland/host/shell_toplevel_wrapper.h"
namespace ui {
diff --git a/chromium/ui/ozone/platform/wayland/host/shell_toplevel_wrapper.h b/chromium/ui/ozone/platform/wayland/host/shell_toplevel_wrapper.h
new file mode 100644
index 00000000000..8767166a13d
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/host/shell_toplevel_wrapper.h
@@ -0,0 +1,98 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_SHELL_TOPLEVEL_WRAPPER_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_SHELL_TOPLEVEL_WRAPPER_H_
+
+#include "base/strings/string16.h"
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
+
+namespace gfx {
+class Rect;
+}
+
+namespace ui {
+
+class WaylandConnection;
+
+// A wrapper around different versions of xdg toplevels. Allows
+// WaylandToplevelWindow to set window-like properties such as maximize,
+// fullscreen, and minimize, set application-specific metadata like title and
+// id, as well as trigger user interactive operations such as interactive resize
+// and move.
+class ShellToplevelWrapper {
+ public:
+ enum class DecorationMode {
+ // Client-side decoration for a window.
+ // In this case, the client is responsible for drawing decorations
+ // for a window (e.g. caption bar, close button). This is suitable for
+ // windows using custom frame.
+ kClientSide = 1,
+ // Server-side decoration for a window.
+ // In this case, the ash window manager is responsible for drawing
+ // decorations. This is suitable for windows using native frame.
+ // e.g. taskmanager.
+ kServerSide
+ };
+
+ virtual ~ShellToplevelWrapper() = default;
+
+ // Initializes the ShellToplevel.
+ virtual bool Initialize() = 0;
+
+ // Sets a native window to maximized state.
+ virtual void SetMaximized() = 0;
+
+ // Unsets a native window from maximized state.
+ virtual void UnSetMaximized() = 0;
+
+ // Sets a native window to fullscreen state.
+ virtual void SetFullscreen() = 0;
+
+ // Unsets a native window from fullscreen state.
+ virtual void UnSetFullscreen() = 0;
+
+ // Sets a native window to minimized state.
+ virtual void SetMinimized() = 0;
+
+ // Tells wayland to start interactive window drag.
+ virtual void SurfaceMove(WaylandConnection* connection) = 0;
+
+ // Tells wayland to start interactive window resize.
+ virtual void SurfaceResize(WaylandConnection* connection,
+ uint32_t hittest) = 0;
+
+ // Sets a title of a native window.
+ virtual void SetTitle(const base::string16& title) = 0;
+
+ // Sends acknowledge configure event back to wayland.
+ virtual void AckConfigure(uint32_t serial) = 0;
+
+ // Sets a desired window geometry once wayland requests client to do so.
+ virtual void SetWindowGeometry(const gfx::Rect& bounds) = 0;
+
+ // Sets the minimum size for the top level.
+ virtual void SetMinSize(int32_t width, int32_t height) = 0;
+
+ // Sets the maximum size for the top level.
+ virtual void SetMaxSize(int32_t width, int32_t height) = 0;
+
+ // Sets an app id of the native window that is shown as an application name
+ // and hints the compositor that it can group application surfaces together by
+ // their app id. This also helps the compositor to identify application's
+ // .desktop file and use the icon set there.
+ virtual void SetAppId(const std::string& app_id) = 0;
+
+ // In case of kClientSide or kServerSide, this function sends a request to the
+ // wayland compositor to update the decoration mode for a surface associated
+ // with this top level window.
+ virtual void SetDecoration(DecorationMode decoration) = 0;
+};
+
+// Look for |value| in |wl_array| in C++ style.
+bool CheckIfWlArrayHasValue(struct wl_array* wl_array, uint32_t value);
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_SHELL_TOPLEVEL_WRAPPER_H_
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_auxiliary_window.cc b/chromium/ui/ozone/platform/wayland/host/wayland_auxiliary_window.cc
index 5139572e51b..7d8cb1086f5 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_auxiliary_window.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_auxiliary_window.cc
@@ -46,7 +46,7 @@ void WaylandAuxiliaryWindow::SetBounds(const gfx::Rect& bounds) {
auto old_bounds = GetBounds();
WaylandWindow::SetBounds(bounds);
- if (old_bounds == bounds || !parent_window())
+ if (old_bounds == bounds || !parent_window() || !subsurface_)
return;
auto subsurface_bounds_dip =
@@ -58,22 +58,11 @@ void WaylandAuxiliaryWindow::SetBounds(const gfx::Rect& bounds) {
}
void WaylandAuxiliaryWindow::CreateSubsurface() {
- auto* parent = parent_window();
- if (!parent) {
- // wl_subsurface can be used for several purposes: tooltips and drag arrow
- // windows. If we are in a drag process, use the entered window. Otherwise,
- // it must be a tooltip.
- if (connection()->IsDragInProgress()) {
- parent = connection()->data_drag_controller()->entered_window();
- set_parent_window(parent);
- } else {
- // If Aura does not not provide a reference parent window, needed by
- // Wayland, we get the current focused window to place and show the
- // tooltips.
- parent =
- connection()->wayland_window_manager()->GetCurrentFocusedWindow();
- }
- }
+ auto* parent = FindParentWindow();
+ set_parent_window(parent);
+
+ // We need to make sure that buffer scale matches the parent window.
+ UpdateBufferScale(true);
// Tooltip and drag arrow creation is an async operation. By the time Aura
// actually creates them, it is possible that the user has already moved the
@@ -101,14 +90,30 @@ void WaylandAuxiliaryWindow::CreateSubsurface() {
connection()->wayland_window_manager()->NotifyWindowConfigured(this);
}
+WaylandWindow* WaylandAuxiliaryWindow::FindParentWindow() {
+ // wl_subsurface can be used for several purposes: tooltips and drag arrow
+ // windows. If we are in a drag process, use the entered window. Otherwise,
+ // it must be a tooltip.
+ if (connection()->IsDragInProgress())
+ return connection()->data_drag_controller()->entered_window();
+
+ // We get the current focused window to place and show the
+ // tooltips.
+ return connection()->wayland_window_manager()->GetCurrentFocusedWindow();
+}
+
bool WaylandAuxiliaryWindow::OnInitialize(
PlatformWindowInitProperties properties) {
DCHECK(!parent_window());
// If we do not have parent window provided, we must always use a focused
// window or a window that entered drag whenever the subsurface is created.
- if (properties.parent_widget == gfx::kNullAcceleratedWidget)
+ if (properties.parent_widget == gfx::kNullAcceleratedWidget) {
+ // Need to set the possible parent window here, so the initial scale will be
+ // calculated correctly.
+ set_parent_window(FindParentWindow());
return true;
+ }
set_parent_window(
connection()->wayland_window_manager()->FindParentForNewWindow(
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_auxiliary_window.h b/chromium/ui/ozone/platform/wayland/host/wayland_auxiliary_window.h
index 0db19755696..0fb87289e10 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_auxiliary_window.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_auxiliary_window.h
@@ -31,6 +31,9 @@ class WaylandAuxiliaryWindow : public WaylandWindow {
// Creates (if necessary) and shows a subsurface window.
void CreateSubsurface();
+ // Finds an appropriate parent window.
+ WaylandWindow* FindParentWindow();
+
wl::Object<wl_subsurface> subsurface_;
};
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_connector.cc b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_connector.cc
index da4fdd5fa93..0a6e6d5b9d6 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_connector.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_connector.cc
@@ -84,9 +84,9 @@ void WaylandBufferManagerConnector::OnBufferManagerHostPtrBinded(
#if defined(WAYLAND_GBM)
supports_dma_buf = buffer_manager_host_->SupportsDmabuf();
#endif
- buffer_manager_gpu_remote->Initialize(std::move(buffer_manager_host),
- buffer_formats_with_modifiers,
- supports_dma_buf);
+ buffer_manager_gpu_remote->Initialize(
+ std::move(buffer_manager_host), buffer_formats_with_modifiers,
+ supports_dma_buf, buffer_manager_host_->SupportsAcquireFence());
}
void WaylandBufferManagerConnector::OnTerminateGpuProcess(std::string message) {
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc
index fc9e374dc63..831babb51b4 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc
@@ -7,11 +7,14 @@
#include <presentation-time-client-protocol.h>
#include <memory>
+#include "base/bind.h"
#include "base/i18n/number_formatting.h"
+#include "base/stl_util.h"
#include "base/strings/strcat.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/current_thread.h"
#include "base/trace_event/trace_event.h"
+#include "ui/gfx/gpu_fence.h"
#include "ui/gfx/linux/drm_util_linux.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
#include "ui/ozone/platform/wayland/host/wayland_drm.h"
@@ -58,6 +61,46 @@ std::string NumberToString(uint32_t number) {
} // namespace
+struct WaylandBufferManagerHost::Frame {
+ explicit Frame(WaylandSurface* root_surface,
+ WaylandBufferManagerHost* manager)
+ : root_surface(root_surface),
+ buffer_manager_(manager),
+ weak_factory(this) {}
+ void IncrementPendingActions() { ++pending_actions; }
+ void PendingActionComplete() {
+ DCHECK(base::CurrentUIThread::IsSet());
+ CHECK_GT(pending_actions, 0u);
+ if (!--pending_actions)
+ if (!std::move(frame_commit_cb).Run()) {
+ buffer_manager_->error_message_ =
+ base::StrCat({"Buffer with ", NumberToString(buffer_id),
+ " id does not exist or failed to be created."});
+ buffer_manager_->TerminateGpuProcess();
+ }
+ }
+
+ // |root_surface| and |buffer_id| are saved so this Frame can be destroyed to
+ // prevent running |frame_commit_cb| in case the corresponding surface/buffer
+ // is removed.
+ WaylandSurface* root_surface;
+ uint32_t buffer_id = 0u;
+
+ // Calls TerminateGpuProcess() if buffer does not exist.
+ WaylandBufferManagerHost* const buffer_manager_;
+
+ // Number of actions to be completed before |frame_commit_cb| is run
+ // automatically. Such actions include:
+ // 1) End Frame;
+ // 2) Commit of a subsurface in this frame;
+ size_t pending_actions = 0u;
+
+ // This runs WaylandBufferManagerHost::Surface::CommitBuffer() of
+ // |root_surface| with |buffer_id|.
+ base::OnceCallback<bool()> frame_commit_cb;
+ base::WeakPtrFactory<WaylandBufferManagerHost::Frame> weak_factory;
+};
+
class WaylandBufferManagerHost::Surface {
public:
Surface(WaylandSurface* wayland_surface,
@@ -68,16 +111,22 @@ class WaylandBufferManagerHost::Surface {
buffer_manager_(buffer_manager) {}
~Surface() = default;
- bool CommitBuffer(uint32_t buffer_id,
- const gfx::Rect& damage_region,
- bool wait_for_frame_callback) {
+ bool CommitBuffer(
+ uint32_t buffer_id,
+ const gfx::Rect& damage_region,
+ bool wait_for_frame_callback,
+ base::OnceClosure post_commit_cb,
+ gfx::GpuFenceHandle access_fence_handle = gfx::GpuFenceHandle()) {
+ DCHECK(!post_commit_cb.is_null());
// The window has already been destroyed.
if (!wayland_surface_)
return true;
// This is a buffer-less commit, do not lookup buffers.
if (buffer_id == kInvalidBufferId) {
- pending_commits_.push_back({nullptr, wait_for_frame_callback});
+ DCHECK(access_fence_handle.is_null());
+ pending_commits_.push_back({nullptr, wait_for_frame_callback, nullptr,
+ std::move(post_commit_cb)});
MaybeProcessPendingBuffer();
return true;
}
@@ -107,7 +156,10 @@ class WaylandBufferManagerHost::Surface {
if (buffer->attached && !buffer->wl_buffer)
return false;
- pending_commits_.push_back({buffer, wait_for_frame_callback});
+ pending_commits_.push_back(
+ {buffer, wait_for_frame_callback,
+ std::make_unique<gfx::GpuFence>(std::move(access_fence_handle)),
+ std::move(post_commit_cb)});
MaybeProcessPendingBuffer();
return true;
}
@@ -122,8 +174,10 @@ class WaylandBufferManagerHost::Surface {
MaybeProcessSubmittedBuffers();
for (auto it = pending_commits_.begin(); it != pending_commits_.end();
++it) {
- if (it->buffer == buffer)
+ if (it->buffer == buffer) {
+ std::move(it->post_commit_cb).Run();
pending_commits_.erase(it++);
+ }
}
}
@@ -155,6 +209,8 @@ class WaylandBufferManagerHost::Surface {
ResetSurfaceContents();
submitted_buffers_.clear();
+ for (auto& pending_commit : pending_commits_)
+ std::move(pending_commit.post_commit_cb).Run();
pending_commits_.clear();
connection_->ScheduleFlush();
@@ -227,9 +283,16 @@ class WaylandBufferManagerHost::Surface {
// Whether this commit must wait for a wl_frame_callback and setup another
// wl_frame_callback.
bool wait_for_callback = false;
+ // Fence to wait on before the |buffer| content is available to read by
+ // Wayland host.
+ std::unique_ptr<gfx::GpuFence> access_fence;
+ // Callback to run once this commit is applied.
+ base::OnceClosure post_commit_cb;
};
- bool CommitBufferInternal(WaylandBuffer* buffer, bool wait_for_callback) {
+ bool CommitBufferInternal(WaylandBuffer* buffer,
+ bool wait_for_callback,
+ const gfx::GpuFenceHandle& access_fence_handle) {
DCHECK(buffer && wayland_surface_);
// If the same buffer has been submitted again right after the client
@@ -242,7 +305,7 @@ class WaylandBufferManagerHost::Surface {
// Once the BufferRelease is called, the buffer will be released.
DCHECK(buffer->released);
buffer->released = false;
- AttachBuffer(buffer);
+ AttachBuffer(buffer, access_fence_handle);
}
// If the client submits the same buffer twice, we need to store it twice,
@@ -278,8 +341,11 @@ class WaylandBufferManagerHost::Surface {
buffer->size);
}
- void AttachBuffer(WaylandBuffer* buffer) {
+ void AttachBuffer(WaylandBuffer* buffer,
+ const gfx::GpuFenceHandle& access_fence_handle) {
DCHECK(wayland_surface_ && configured_);
+ if (!access_fence_handle.is_null())
+ wayland_surface_->SetAcquireFence(access_fence_handle);
wayland_surface_->AttachBuffer(buffer->wl_buffer.get());
}
@@ -552,27 +618,30 @@ class WaylandBufferManagerHost::Surface {
//
// The third case happens if the window hasn't been configured until a
// request to attach a buffer to its surface is sent.
- auto pending_commit = std::move(pending_commits_.front());
+ const auto& pending_commit = pending_commits_.front();
if ((pending_commit.buffer && !pending_commit.buffer->wl_buffer) ||
(wl_frame_callback_ && pending_commit.wait_for_callback) ||
!configured_) {
return;
}
+ auto commit = std::move(pending_commits_.front());
+ pending_commits_.erase(pending_commits_.begin());
+
// A Commit without attaching buffers only needs to setup wl_frame_callback.
- if (!pending_commit.buffer) {
- pending_commits_.erase(pending_commits_.begin());
- if (pending_commit.wait_for_callback)
+ if (!commit.buffer) {
+ if (commit.wait_for_callback)
SetupFrameCallback();
CommitSurface();
+ std::move(commit.post_commit_cb).Run();
connection_->ScheduleFlush();
MaybeProcessSubmittedBuffers();
return;
}
- pending_commits_.erase(pending_commits_.begin());
- CommitBufferInternal(pending_commit.buffer,
- pending_commit.wait_for_callback);
+ CommitBufferInternal(commit.buffer, commit.wait_for_callback,
+ commit.access_fence->GetGpuFenceHandle());
+ std::move(commit.post_commit_cb).Run();
}
// Widget this helper surface backs and has 1:1 relationship with the
@@ -645,6 +714,8 @@ void WaylandBufferManagerHost::OnWindowRemoved(WaylandWindow* window) {
surface_graveyard_.emplace_back(std::move(it->second));
}
surfaces_.erase(it);
+
+ RemovePendingFrames(window->root_surface(), 0u);
}
void WaylandBufferManagerHost::OnWindowConfigured(WaylandWindow* window) {
@@ -675,6 +746,8 @@ void WaylandBufferManagerHost::OnSubsurfaceRemoved(
surface_graveyard_.emplace_back(std::move(it->second));
}
surfaces_.erase(it);
+
+ RemovePendingFrames(subsurface->wayland_surface(), 0u);
}
void WaylandBufferManagerHost::SetSurfaceConfigured(WaylandSurface* surface) {
@@ -709,6 +782,7 @@ void WaylandBufferManagerHost::OnChannelDestroyed() {
surface_pair.second->ClearState();
anonymous_buffers_.clear();
+ pending_frames_.clear();
}
wl::BufferFormatsWithModifiersMap
@@ -727,6 +801,10 @@ bool WaylandBufferManagerHost::SupportsDmabuf() const {
(connection_->drm() && connection_->drm()->SupportsDrmPrime());
}
+bool WaylandBufferManagerHost::SupportsAcquireFence() const {
+ return !!connection_->linux_explicit_synchronization_v1();
+}
+
void WaylandBufferManagerHost::SetWaylandBufferManagerGpu(
mojo::PendingAssociatedRemote<ozone::mojom::WaylandBufferManagerGpu>
buffer_manager_gpu_associated) {
@@ -803,19 +881,72 @@ void WaylandBufferManagerHost::CreateShmBasedBuffer(mojo::PlatformHandle shm_fd,
connection_->ScheduleFlush();
}
+void WaylandBufferManagerHost::StartFrame(WaylandSurface* root_surface) {
+ RemovePendingFrames(nullptr, 0u);
+ DCHECK_LE(pending_frames_.size(), 10u);
+ pending_frames_.push_back(
+ std::make_unique<WaylandBufferManagerHost::Frame>(root_surface, this));
+ pending_frames_.back()->IncrementPendingActions();
+}
+
+void WaylandBufferManagerHost::EndFrame(uint32_t buffer_id,
+ const gfx::Rect& damage_region) {
+ DCHECK(base::CurrentUIThread::IsSet());
+
+ // If TerminateGpuProcess() is called, pending_frames_ would be cleared.
+ if (pending_frames_.empty())
+ return;
+
+ pending_frames_.back()->buffer_id = buffer_id;
+ Surface* surface = GetSurface(pending_frames_.back()->root_surface);
+ if (!surface) {
+ pending_frames_.erase(--pending_frames_.end());
+ return;
+ }
+
+ base::OnceClosure post_commit_cb = base::DoNothing();
+ pending_frames_.back()->frame_commit_cb = base::BindOnce(
+ &WaylandBufferManagerHost::Surface::CommitBuffer,
+ base::Unretained(surface), buffer_id, damage_region, !!buffer_id,
+ std::move(post_commit_cb), gfx::GpuFenceHandle());
+
+ pending_frames_.back()->PendingActionComplete();
+}
+
+void WaylandBufferManagerHost::RemovePendingFrames(WaylandSurface* root_surface,
+ uint32_t buffer_id) {
+ base::EraseIf(pending_frames_,
+ [buffer_id, root_surface](const std::unique_ptr<Frame>& frame) {
+ return !frame->pending_actions ||
+ (frame->buffer_id == buffer_id && buffer_id) ||
+ (frame->root_surface == root_surface && root_surface);
+ });
+}
+
bool WaylandBufferManagerHost::CommitBufferInternal(
WaylandSurface* wayland_surface,
uint32_t buffer_id,
const gfx::Rect& damage_region,
- bool wait_for_frame_callback) {
+ bool wait_for_frame_callback,
+ bool commit_synced_subsurface,
+ gfx::GpuFenceHandle access_fence_handle) {
DCHECK(base::CurrentUIThread::IsSet());
Surface* surface = GetSurface(wayland_surface);
if (!surface || !ValidateBufferIdFromGpu(buffer_id))
return false;
- if (!surface->CommitBuffer(buffer_id, damage_region,
- wait_for_frame_callback)) {
+ base::OnceClosure subsurface_committed_cb = base::DoNothing();
+ if (!pending_frames_.empty() && commit_synced_subsurface) {
+ pending_frames_.back()->IncrementPendingActions();
+ subsurface_committed_cb.Reset();
+ subsurface_committed_cb =
+ base::BindOnce(&WaylandBufferManagerHost::Frame::PendingActionComplete,
+ pending_frames_.back()->weak_factory.GetWeakPtr());
+ }
+ if (!surface->CommitBuffer(buffer_id, damage_region, wait_for_frame_callback,
+ std::move(subsurface_committed_cb),
+ std::move(access_fence_handle))) {
error_message_ =
base::StrCat({"Buffer with ", NumberToString(buffer_id),
" id does not exist or failed to be created."});
@@ -826,45 +957,6 @@ bool WaylandBufferManagerHost::CommitBufferInternal(
return true;
}
-bool WaylandBufferManagerHost::CommitWithoutBufferInternal(
- WaylandSurface* wayland_surface,
- bool wait_for_frame_callback) {
- DCHECK(base::CurrentUIThread::IsSet());
-
- Surface* surface = GetSurface(wayland_surface);
- if (!surface)
- return false;
-
- bool result = surface->CommitBuffer(kInvalidBufferId, gfx::Rect(),
- wait_for_frame_callback);
- DCHECK(result);
-
- if (!error_message_.empty())
- TerminateGpuProcess();
- return true;
-}
-
-void WaylandBufferManagerHost::CommitBuffer(gfx::AcceleratedWidget widget,
- uint32_t buffer_id,
- const gfx::Rect& damage_region) {
- DCHECK(base::CurrentUIThread::IsSet());
-
- TRACE_EVENT1("wayland", "WaylandBufferManagerHost::CommitBuffer", "Buffer id",
- buffer_id);
-
- DCHECK(error_message_.empty());
-
- if (widget == gfx::kNullAcceleratedWidget) {
- error_message_ = "Invalid widget.";
- TerminateGpuProcess();
- } else {
- auto* window = connection_->wayland_window_manager()->GetWindow(widget);
- if (!window)
- return;
- CommitBufferInternal(window->root_surface(), buffer_id, damage_region);
- }
-}
-
void WaylandBufferManagerHost::CommitOverlays(
gfx::AcceleratedWidget widget,
std::vector<ui::ozone::mojom::WaylandOverlayConfigPtr> overlays) {
@@ -954,6 +1046,8 @@ void WaylandBufferManagerHost::DestroyBuffer(gfx::AcceleratedWidget widget,
}
}
+ RemovePendingFrames(nullptr, buffer_id);
+
// Ensure that we can't destroy more than 1 buffer. This can be 0 as well
// if no buffers are destroyed.
DCHECK_LE(destroyed_count, 1u);
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h
index 28dc77dc8d0..8137f562f07 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h
@@ -5,7 +5,6 @@
#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_BUFFER_MANAGER_HOST_H_
#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_BUFFER_MANAGER_HOST_H_
-#include <map>
#include <memory>
#include <vector>
@@ -18,6 +17,7 @@
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/gpu_fence_handle.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/presentation_feedback.h"
#include "ui/gfx/swap_result.h"
@@ -109,6 +109,7 @@ class WaylandBufferManagerHost : public ozone::mojom::WaylandBufferManagerHost,
wl::BufferFormatsWithModifiersMap GetSupportedBufferFormats() const;
bool SupportsDmabuf() const;
+ bool SupportsAcquireFence() const;
// ozone::mojom::WaylandBufferManagerHost overrides:
//
@@ -139,13 +140,6 @@ class WaylandBufferManagerHost : public ozone::mojom::WaylandBufferManagerHost,
// Called by the GPU to destroy the imported wl_buffer with a |buffer_id|.
void DestroyBuffer(gfx::AcceleratedWidget widget,
uint32_t buffer_id) override;
- // Called by the GPU and asks to attach a wl_buffer with a |buffer_id| to a
- // WaylandWindow with the specified |widget|.
- // Calls OnSubmission and OnPresentation on successful swap and pixels
- // presented.
- void CommitBuffer(gfx::AcceleratedWidget widget,
- uint32_t buffer_id,
- const gfx::Rect& damage_region) override;
// Called by the GPU and asks to configure the surface/subsurfaces and attach
// wl_buffers to WaylandWindow with the specified |widget|. Calls OnSubmission
// and OnPresentation on successful swap and pixels presented.
@@ -153,6 +147,15 @@ class WaylandBufferManagerHost : public ozone::mojom::WaylandBufferManagerHost,
gfx::AcceleratedWidget widget,
std::vector<ui::ozone::mojom::WaylandOverlayConfigPtr> overlays) override;
+ // Called by WaylandWindow to start recording a frame. This helps record the
+ // number of subsurface commits needed to finish for this frame before
+ // |root_surface| can be committed.
+ // This pairs with an EndCommitFrame(). Every CommitBufferInternal() in
+ // between increases the number of needed pending commits by 1.
+ void StartFrame(WaylandSurface* root_surface);
+ void EndFrame(uint32_t buffer_id = 0u,
+ const gfx::Rect& damage_region = gfx::Rect());
+
// Called by the WaylandWindow and asks to attach a wl_buffer with a
// |buffer_id| to a WaylandSurface.
// Calls OnSubmission and OnPresentation on successful swap and pixels
@@ -163,16 +166,16 @@ class WaylandBufferManagerHost : public ozone::mojom::WaylandBufferManagerHost,
// commit will move an entire wl_surface tree from pending state to ready
// state. This root_surface commit must wait for wl_frame_callback, such that
// in effect all other surface updates wait for this wl_frame_callback, too.
- bool CommitBufferInternal(WaylandSurface* wayland_surface,
- uint32_t buffer_id,
- const gfx::Rect& damage_region,
- bool wait_for_frame_callback = true);
-
- // Does a wl_surface commit without attaching any buffers. This commit will
- // still wait for previous wl_frame_callback. Similar to above but for
- // commits that do not change the root_surface.
- bool CommitWithoutBufferInternal(WaylandSurface* wayland_surface,
- bool wait_for_frame_callback = true);
+ // |access_fence_handle| specifies a gpu fence created by the gpu process.
+ // It's to be waited on before content of the buffer is ready to be read by
+ // Wayland host.
+ bool CommitBufferInternal(
+ WaylandSurface* wayland_surface,
+ uint32_t buffer_id,
+ const gfx::Rect& damage_region,
+ bool wait_for_frame_callback = true,
+ bool commit_synced_subsurface = false,
+ gfx::GpuFenceHandle access_fence_handle = gfx::GpuFenceHandle());
// When a surface is hidden, the client may want to detach the buffer attached
// to the surface to ensure Wayland does not present those contents and do not
@@ -189,10 +192,17 @@ class WaylandBufferManagerHost : public ozone::mojom::WaylandBufferManagerHost,
// presentation callbacks for that surface.
class Surface;
+ // This represents a frame that consists of state changes to multiple
+ // synchronized wl_surfaces that are in the same hierarchy. It defers
+ // committing the root surface until all child surfaces' states are ready.
+ struct Frame;
+
bool CreateBuffer(const gfx::Size& size, uint32_t buffer_id);
Surface* GetSurface(WaylandSurface* wayland_surface) const;
+ void RemovePendingFrames(WaylandSurface* root_surface, uint32_t buffer_id);
+
// Validates data sent from GPU. If invalid, returns false and sets an error
// message to |error_message_|.
bool ValidateDataFromGpu(const base::ScopedFD& file,
@@ -230,6 +240,10 @@ class WaylandBufferManagerHost : public ozone::mojom::WaylandBufferManagerHost,
base::flat_map<WaylandSurface*, std::unique_ptr<Surface>> surfaces_;
+ // When StartCommitFrame() is called, a Frame is pushed to
+ // |pending_frames_|. See StartCommitFrame().
+ std::vector<std::unique_ptr<Frame>> pending_frames_;
+
// When a WaylandWindow/WaylandSubsurface is removed, its corresponding
// Surface may still have an un-released buffer and un-acked presentation.
// Thus, we keep removed surfaces in the graveyard. It's safe to delete them
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.cc b/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.cc
index 43d14126367..f6984d4ff54 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.cc
@@ -8,18 +8,22 @@
#include <string>
#include "base/check.h"
+#include "base/memory/scoped_refptr.h"
#include "base/notreached.h"
+#include "base/optional.h"
#include "ui/base/clipboard/clipboard_buffer.h"
#include "ui/base/clipboard/clipboard_constants.h"
#include "ui/ozone/platform/wayland/common/wayland_object.h"
#include "ui/ozone/platform/wayland/host/gtk_primary_selection_device.h"
#include "ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.h"
-#include "ui/ozone/platform/wayland/host/zwp_primary_selection_device.h"
-#include "ui/ozone/platform/wayland/host/zwp_primary_selection_device_manager.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
#include "ui/ozone/platform/wayland/host/wayland_data_device.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_device_base.h"
#include "ui/ozone/platform/wayland/host/wayland_data_device_manager.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_offer_base.h"
#include "ui/ozone/platform/wayland/host/wayland_data_source.h"
+#include "ui/ozone/platform/wayland/host/zwp_primary_selection_device.h"
+#include "ui/ozone/platform/wayland/host/zwp_primary_selection_device_manager.h"
#include "ui/ozone/public/platform_clipboard.h"
namespace wl {
@@ -36,15 +40,20 @@ class Clipboard {
virtual std::vector<std::string> ReadMimeTypes() = 0;
// Asynchronously reads clipboard content with |mime_type| format. The result
- // data is expected to arrive through WaylandClipboard::SetData().
- // TODO(nickdiego): Decouple DataDevice impls from WaylandClipboard.
- virtual bool Read(const std::string& mime_type) = 0;
+ // data is expected to arrive through OnSelectionDataReceived() callback.
+ virtual bool Read(const std::string& mime_type,
+ ui::PlatformClipboard::DataMap* data_map,
+ ui::PlatformClipboard::RequestDataClosure callback) = 0;
// Synchronously stores and announces |data| as available from this clipboard.
virtual void Write(const ui::PlatformClipboard::DataMap* data) = 0;
// Tells if this clipboard instance is the current selection owner.
virtual bool IsSelectionOwner() const = 0;
+
+ // Sets the callback in charge of updating the clipboard sequence number.
+ virtual void SetSequenceNumberUpdateCb(
+ ui::PlatformClipboard::SequenceNumberUpdateCb callback) = 0;
};
// Templated wl::Clipboard implementation. Whereas DataSource is the data source
@@ -55,41 +64,70 @@ class Clipboard {
template <typename Manager,
typename DataSource = typename Manager::DataSource,
typename DataDevice = typename Manager::DataDevice>
-class ClipboardImpl final : public Clipboard, public DataSource::Delegate {
+class ClipboardImpl final : public Clipboard,
+ public DataSource::Delegate,
+ public DataDevice::SelectionDelegate {
public:
- explicit ClipboardImpl(Manager* manager) : manager_(manager) {}
+ explicit ClipboardImpl(Manager* manager, ui::ClipboardBuffer buffer)
+ : manager_(manager), buffer_(buffer) {
+ GetDevice()->set_selection_delegate(this);
+ }
+ ~ClipboardImpl() final { GetDevice()->set_selection_delegate(nullptr); }
+
ClipboardImpl(const ClipboardImpl&) = delete;
ClipboardImpl& operator=(const ClipboardImpl&) = delete;
- virtual ~ClipboardImpl() = default;
- virtual bool Read(const std::string& mime_type) override {
- return GetDevice()->RequestSelectionData(mime_type);
+ // TODO(crbug.com/1165466): Support nested clipboard requests.
+ bool Read(const std::string& mime_type,
+ ui::PlatformClipboard::DataMap* data_map,
+ ui::PlatformClipboard::RequestDataClosure callback) final {
+ DCHECK(data_map);
+ received_data_ = data_map;
+ read_clipboard_closure_ = std::move(callback);
+
+ if (GetDevice()->RequestSelectionData(mime_type))
+ return true;
+ SetData(base::MakeRefCounted<base::RefCountedBytes>(), mime_type);
+ return false;
}
- std::vector<std::string> ReadMimeTypes() override {
+ std::vector<std::string> ReadMimeTypes() final {
return GetDevice()->GetAvailableMimeTypes();
}
- virtual void Write(const ui::PlatformClipboard::DataMap* data) override {
+ // Once this client sends wl_data_source::offer, it is responsible for holding
+ // onto its clipboard contents. At future points in time, the wayland server
+ // may send a wl_data_source::send event, in which case this client is
+ // responsible for writing the clipboard contents into the supplied fd. This
+ // client can only drop the clipboard contents when it receives a
+ // wl_data_source::cancelled event.
+ void Write(const ui::PlatformClipboard::DataMap* data) final {
if (!data || data->empty()) {
- data_.clear();
+ offered_data_.clear();
source_.reset();
} else {
- data_ = *data;
+ offered_data_ = *data;
source_ = manager_->CreateSource(this);
source_->Offer(GetMimeTypes());
GetDevice()->SetSelectionSource(source_.get());
}
}
- bool IsSelectionOwner() const override { return !!source_; }
+ bool IsSelectionOwner() const final { return !!source_; }
+
+ void SetSequenceNumberUpdateCb(
+ ui::PlatformClipboard::SequenceNumberUpdateCb callback) final {
+ CHECK(update_sequence_cb_.is_null())
+ << "The callback can be installed only once.";
+ update_sequence_cb_ = callback;
+ }
private:
DataDevice* GetDevice() { return manager_->GetDevice(); }
std::vector<std::string> GetMimeTypes() {
std::vector<std::string> mime_types;
- for (const auto& data : data_) {
+ for (const auto& data : offered_data_) {
mime_types.push_back(data.first);
if (data.first == ui::kMimeTypeText)
mime_types.push_back(ui::kMimeTypeTextUtf8);
@@ -97,6 +135,36 @@ class ClipboardImpl final : public Clipboard, public DataSource::Delegate {
return mime_types;
}
+ void SetData(ui::PlatformClipboard::Data contents,
+ const std::string& mime_type) {
+ if (!received_data_)
+ return;
+
+ DCHECK(contents);
+ (*received_data_)[mime_type] = contents;
+
+ if (!read_clipboard_closure_.is_null()) {
+ auto it = received_data_->find(mime_type);
+ DCHECK(it != received_data_->end());
+ std::move(read_clipboard_closure_).Run(it->second);
+ }
+ received_data_ = nullptr;
+ }
+
+ // WaylandDataDeviceBase::SelectionDelegate:
+ void OnSelectionOffer(ui::WaylandDataOfferBase* offer) final {
+ if (!update_sequence_cb_.is_null())
+ update_sequence_cb_.Run(buffer_);
+
+ if (!offer)
+ SetData({}, {});
+ }
+
+ void OnSelectionDataReceived(const std::string& mime_type,
+ ui::PlatformClipboard::Data contents) final {
+ SetData(contents, mime_type);
+ }
+
// WaylandDataSource::Delegate:
void OnDataSourceFinish(bool completed) override {
if (!completed)
@@ -106,21 +174,34 @@ class ClipboardImpl final : public Clipboard, public DataSource::Delegate {
void OnDataSourceSend(const std::string& mime_type,
std::string* contents) override {
DCHECK(contents);
- auto it = data_.find(mime_type);
- if (it == data_.end() && mime_type == ui::kMimeTypeTextUtf8)
- it = data_.find(ui::kMimeTypeText);
- if (it != data_.end())
+ auto it = offered_data_.find(mime_type);
+ if (it == offered_data_.end() && mime_type == ui::kMimeTypeTextUtf8)
+ it = offered_data_.find(ui::kMimeTypeText);
+ if (it != offered_data_.end())
contents->assign(it->second->data().begin(), it->second->data().end());
}
// The device manager used to access data device and create data sources.
Manager* const manager_;
+ // The clipboard buffer managed by this |this|.
+ const ui::ClipboardBuffer buffer_;
+
// The current data source used to offer clipboard data.
std::unique_ptr<DataSource> source_;
// The data currently stored in a given clipboard buffer.
- ui::PlatformClipboard::DataMap data_;
+ ui::PlatformClipboard::DataMap offered_data_;
+
+ // Holds a temporary instance of the client's clipboard content
+ // so that we can asynchronously write to it.
+ ui::PlatformClipboard::DataMap* received_data_ = nullptr;
+
+ // Stores the callback to be invoked upon data reading from clipboard.
+ ui::PlatformClipboard::RequestDataClosure read_clipboard_closure_;
+
+ // Notifies when clipboard sequence must change. Can be empty if not set.
+ ui::PlatformClipboard::SequenceNumberUpdateCb update_sequence_cb_;
};
} // namespace wl
@@ -132,7 +213,8 @@ WaylandClipboard::WaylandClipboard(WaylandConnection* connection,
: connection_(connection),
copypaste_clipboard_(
std::make_unique<wl::ClipboardImpl<WaylandDataDeviceManager>>(
- manager)) {
+ manager,
+ ClipboardBuffer::kCopyPaste)) {
DCHECK(manager);
DCHECK(connection_);
DCHECK(copypaste_clipboard_);
@@ -149,19 +231,16 @@ void WaylandClipboard::OfferClipboardData(
std::move(callback).Run();
}
+// TODO(crbug.com/1165466): Support nested clipboard requests.
void WaylandClipboard::RequestClipboardData(
ClipboardBuffer buffer,
const std::string& mime_type,
PlatformClipboard::DataMap* data_map,
PlatformClipboard::RequestDataClosure callback) {
- DCHECK(data_map);
- data_map_ = data_map;
- read_clipboard_closure_ = std::move(callback);
- auto* clipboard = GetClipboard(buffer);
- if (!clipboard || !clipboard->Read(mime_type)) {
- SetData(scoped_refptr<base::RefCountedBytes>(new base::RefCountedBytes()),
- mime_type);
- }
+ if (auto* clipboard = GetClipboard(buffer))
+ clipboard->Read(mime_type, data_map, std::move(callback));
+ else
+ std::move(callback).Run(base::nullopt);
}
bool WaylandClipboard::IsSelectionOwner(ClipboardBuffer buffer) {
@@ -172,9 +251,9 @@ bool WaylandClipboard::IsSelectionOwner(ClipboardBuffer buffer) {
void WaylandClipboard::SetSequenceNumberUpdateCb(
PlatformClipboard::SequenceNumberUpdateCb cb) {
- CHECK(update_sequence_cb_.is_null())
- << " The callback can be installed only once.";
- update_sequence_cb_ = std::move(cb);
+ copypaste_clipboard_->SetSequenceNumberUpdateCb(cb);
+ if (auto* selection_clipboard = GetClipboard(ClipboardBuffer::kSelection))
+ selection_clipboard->SetSequenceNumberUpdateCb(cb);
}
void WaylandClipboard::GetAvailableMimeTypes(
@@ -191,27 +270,6 @@ bool WaylandClipboard::IsSelectionBufferAvailable() const {
(connection_->gtk_primary_selection_device_manager() != nullptr);
}
-void WaylandClipboard::SetData(PlatformClipboard::Data contents,
- const std::string& mime_type) {
- if (!data_map_)
- return;
-
- DCHECK(contents);
- (*data_map_)[mime_type] = contents;
-
- if (!read_clipboard_closure_.is_null()) {
- auto it = data_map_->find(mime_type);
- DCHECK(it != data_map_->end());
- std::move(read_clipboard_closure_).Run(it->second);
- }
- data_map_ = nullptr;
-}
-
-void WaylandClipboard::UpdateSequenceNumber(ClipboardBuffer buffer) {
- if (!update_sequence_cb_.is_null())
- update_sequence_cb_.Run(buffer);
-}
-
wl::Clipboard* WaylandClipboard::GetClipboard(ClipboardBuffer buffer) {
if (buffer == ClipboardBuffer::kCopyPaste)
return copypaste_clipboard_.get();
@@ -219,16 +277,17 @@ wl::Clipboard* WaylandClipboard::GetClipboard(ClipboardBuffer buffer) {
if (buffer == ClipboardBuffer::kSelection) {
if (auto* manager = connection_->zwp_primary_selection_device_manager()) {
if (!primary_selection_clipboard_) {
- primary_selection_clipboard_ =
- std::make_unique<wl::ClipboardImpl<ZwpPrimarySelectionDeviceManager>>(
- manager);
+ primary_selection_clipboard_ = std::make_unique<
+ wl::ClipboardImpl<ZwpPrimarySelectionDeviceManager>>(
+ manager, ClipboardBuffer::kSelection);
}
return primary_selection_clipboard_.get();
} else if (auto* manager =
connection_->gtk_primary_selection_device_manager()) {
if (!primary_selection_clipboard_) {
primary_selection_clipboard_ = std::make_unique<
- wl::ClipboardImpl<GtkPrimarySelectionDeviceManager>>(manager);
+ wl::ClipboardImpl<GtkPrimarySelectionDeviceManager>>(
+ manager, ClipboardBuffer::kSelection);
}
return primary_selection_clipboard_.get();
}
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.h b/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.h
index 515c85ca6c3..1b15f4f488e 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.h
@@ -7,13 +7,10 @@
#include <memory>
#include <string>
-#include <vector>
#include "base/callback.h"
-#include "base/containers/flat_map.h"
-#include "base/macros.h"
-#include "base/optional.h"
#include "ui/base/clipboard/clipboard_buffer.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_device.h"
#include "ui/ozone/public/platform_clipboard.h"
namespace wl {
@@ -25,7 +22,12 @@ namespace ui {
class WaylandConnection;
class WaylandDataDeviceManager;
-// Handles clipboard operations.
+// This class is a wrapper around Wayland data_device protocols that simulates
+// typical clipboard operations. Unlike some other platforms, data-transfer is
+// an async, lazy operation. This means that even after "writing" data to the
+// system clipboard, this class must still hold on to a local cache of the
+// clipboard contents, since it may be read (repeatedly) by other Wayland
+// clients.
//
// WaylandDataDeviceManager singleton is required to be up and running for
// WaylandClipboard to be minimally functional.
@@ -55,11 +57,6 @@ class WaylandClipboard : public PlatformClipboard {
PlatformClipboard::SequenceNumberUpdateCb cb) override;
bool IsSelectionBufferAvailable() const override;
- // TODO(nickdiego): Get rid of these methods once DataDevice implementations
- // are decoupled from WaylandClipboard.
- void SetData(PlatformClipboard::Data contents, const std::string& mime_type);
- void UpdateSequenceNumber(ClipboardBuffer buffer);
-
private:
// Get the wl::Clipboard instance owning a given |buffer|. Can return null in
// case |buffer| is unsupported. E.g: primary selection is not available.
@@ -69,17 +66,6 @@ class WaylandClipboard : public PlatformClipboard {
// primary selection.
WaylandConnection* const connection_;
- // Holds a temporary instance of the client's clipboard content
- // so that we can asynchronously write to it.
- PlatformClipboard::DataMap* data_map_ = nullptr;
-
- // Notifies whenever clipboard sequence number is changed. Can be empty if
- // not set.
- PlatformClipboard::SequenceNumberUpdateCb update_sequence_cb_;
-
- // Stores the callback to be invoked upon data reading from clipboard.
- PlatformClipboard::RequestDataClosure read_clipboard_closure_;
-
const std::unique_ptr<wl::Clipboard> copypaste_clipboard_;
std::unique_ptr<wl::Clipboard> primary_selection_clipboard_;
};
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_clipboard_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_clipboard_unittest.cc
new file mode 100644
index 00000000000..9318149af79
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_clipboard_unittest.cc
@@ -0,0 +1,232 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <wayland-server.h>
+
+#include <cstring>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/callback_forward.h"
+#include "base/containers/contains.h"
+#include "base/containers/flat_set.h"
+#include "base/location.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/mock_callback.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/clipboard/clipboard_buffer.h"
+#include "ui/base/clipboard/clipboard_constants.h"
+#include "ui/events/base_event_utils.h"
+#include "ui/ozone/platform/wayland/test/mock_surface.h"
+#include "ui/ozone/platform/wayland/test/test_data_device.h"
+#include "ui/ozone/platform/wayland/test/test_data_device_manager.h"
+#include "ui/ozone/platform/wayland/test/test_data_offer.h"
+#include "ui/ozone/platform/wayland/test/test_data_source.h"
+#include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h"
+#include "ui/ozone/platform/wayland/test/wayland_test.h"
+#include "ui/ozone/public/platform_clipboard.h"
+
+using testing::_;
+using testing::Mock;
+
+namespace ui {
+
+namespace {
+
+constexpr char kSampleClipboardText[] = "This is a sample text for clipboard.";
+
+template <typename StringType>
+ui::PlatformClipboard::Data ToClipboardData(const StringType& data_string) {
+ std::vector<uint8_t> data_vector;
+ data_vector.assign(data_string.begin(), data_string.end());
+ return base::RefCountedBytes::TakeVector(&data_vector);
+}
+
+} // namespace
+
+class WaylandClipboardTest : public WaylandTest {
+ public:
+ WaylandClipboardTest() = default;
+
+ void SetUp() override {
+ WaylandTest::SetUp();
+
+ Sync();
+
+ data_device_manager_ = server_.data_device_manager();
+ ASSERT_TRUE(data_device_manager_);
+
+ clipboard_ = connection_->clipboard();
+ ASSERT_TRUE(clipboard_);
+
+ offered_data_.clear();
+ }
+
+ protected:
+ // Fill the clipboard backing store with sample data.
+ void OfferData(ClipboardBuffer buffer,
+ const char* data,
+ const std::string& mime_type) {
+ std::vector<uint8_t> data_vector(data, data + std::strlen(data));
+ offered_data_[mime_type] = base::RefCountedBytes::TakeVector(&data_vector);
+
+ base::MockCallback<PlatformClipboard::OfferDataClosure> offer_callback;
+ EXPECT_CALL(offer_callback, Run()).Times(1);
+ clipboard_->OfferClipboardData(buffer, offered_data_, offer_callback.Get());
+ }
+
+ wl::TestDataDeviceManager* data_device_manager_;
+ PlatformClipboard* clipboard_;
+ PlatformClipboard::DataMap offered_data_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(WaylandClipboardTest);
+};
+
+TEST_P(WaylandClipboardTest, WriteToClipboard) {
+ // The client writes data to the clipboard ...
+ OfferData(ClipboardBuffer::kCopyPaste, kSampleClipboardText,
+ {kMimeTypeTextUtf8});
+ Sync();
+
+ // ... and the server reads it.
+ base::RunLoop run_loop;
+ auto callback = base::BindOnce(
+ [](base::RunLoop* loop, std::vector<uint8_t>&& data) {
+ std::string string_data(data.begin(), data.end());
+ EXPECT_EQ(kSampleClipboardText, string_data);
+ loop->Quit();
+ },
+ &run_loop);
+
+ data_device_manager_->data_source()->ReadData(kMimeTypeTextUtf8,
+ std::move(callback));
+ run_loop.Run();
+}
+
+TEST_P(WaylandClipboardTest, ReadFromClipboard) {
+ auto* data_offer = data_device_manager_->data_device()->OnDataOffer();
+ data_offer->OnOffer(kMimeTypeTextUtf8,
+ ToClipboardData(std::string(kSampleClipboardText)));
+ data_device_manager_->data_device()->OnSelection(data_offer);
+ Sync();
+
+ // The client requests to read the clipboard data from the server. The Server
+ // writes in some sample data, and we check it matches expectation.
+ base::RunLoop run_loop;
+ auto callback = base::BindOnce(
+ [](base::OnceClosure quit_closure,
+ const base::Optional<PlatformClipboard::Data>& data) {
+ auto& bytes = data->get()->data();
+ std::string string_data = std::string(bytes.begin(), bytes.end());
+ EXPECT_EQ(kSampleClipboardText, string_data);
+ std::move(quit_closure).Run();
+ },
+ run_loop.QuitClosure());
+
+ PlatformClipboard::DataMap read_data_;
+ clipboard_->RequestClipboardData(ClipboardBuffer::kCopyPaste,
+ kMimeTypeTextUtf8, &read_data_,
+ std::move(callback));
+ Sync();
+ run_loop.Run();
+}
+
+TEST_P(WaylandClipboardTest, ReadFromClipboardWithoutOffer) {
+ // When no data offer is advertised and client requests clipboard data
+ // from the server, the response callback should be gracefully called with
+ // an empty string.
+ auto callback =
+ base::BindOnce([](const base::Optional<PlatformClipboard::Data>& data) {
+ auto& bytes = data->get()->data();
+ std::string string_data = std::string(bytes.begin(), bytes.end());
+ EXPECT_EQ("", string_data);
+ });
+ PlatformClipboard::DataMap read_data_;
+ clipboard_->RequestClipboardData(ClipboardBuffer::kCopyPaste,
+ kMimeTypeTextUtf8, &read_data_,
+ std::move(callback));
+}
+
+TEST_P(WaylandClipboardTest, IsSelectionOwner) {
+ OfferData(ClipboardBuffer::kCopyPaste, kSampleClipboardText,
+ {kMimeTypeTextUtf8});
+ Sync();
+ ASSERT_TRUE(clipboard_->IsSelectionOwner(ClipboardBuffer::kCopyPaste));
+
+ // The compositor sends OnCancelled whenever another application
+ // on the system sets a new selection. It means we are not the application
+ // that owns the current selection data.
+ data_device_manager_->data_source()->OnCancelled();
+ Sync();
+
+ ASSERT_FALSE(clipboard_->IsSelectionOwner(ClipboardBuffer::kCopyPaste));
+}
+
+// Ensures WaylandClipboard correctly handles overlapping read requests for
+// different clipboard buffers.
+TEST_P(WaylandClipboardTest, OverlapReadingFromDifferentBuffers) {
+ // Offer a piece of text in kCopyPaste clipboard buffer.
+ auto* data_offer = data_device_manager_->data_device()->OnDataOffer();
+ data_offer->OnOffer(kMimeTypeTextUtf8,
+ ToClipboardData(std::string(kSampleClipboardText)));
+ data_device_manager_->data_device()->OnSelection(data_offer);
+ Sync();
+
+ // Post a read request for kSelection buffer, which will start its execution
+ // after kCopyPaste request (below) starts.
+ PlatformClipboard::DataMap selection_data_;
+ base::MockCallback<PlatformClipboard::RequestDataClosure> selection_callback;
+ EXPECT_CALL(selection_callback, Run(_)).Times(1);
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::BindOnce(&PlatformClipboard::RequestClipboardData,
+ base::Unretained(clipboard_), ClipboardBuffer::kSelection,
+ kMimeTypeTextUtf8, base::Unretained(&selection_data_),
+ selection_callback.Get()));
+
+ // Instantly start a clipboard read request for kCopyPaste buffer (the actual
+ // data transfer will take place asynchronously. See WaylandDataDevice impl)
+ // and ensure read callback is called and |copy_paste_data_| is filled as
+ // expected, regardless any other request that may arrive in the meantime.
+ PlatformClipboard::DataMap copy_paste_data_;
+ base::RunLoop run_loop;
+ clipboard_->RequestClipboardData(
+ ClipboardBuffer::kCopyPaste, kMimeTypeTextUtf8, &copy_paste_data_,
+ base::BindOnce(
+ [](base::OnceClosure quit_closure,
+ const base::Optional<PlatformClipboard::Data>& data) {
+ ASSERT_TRUE(data.has_value());
+ EXPECT_EQ(kSampleClipboardText,
+ std::string(data->get()->front_as<const char>(),
+ data->get()->size()));
+ std::move(quit_closure).Run();
+ },
+ run_loop.QuitClosure()));
+
+ Sync();
+ run_loop.Run();
+
+ EXPECT_TRUE(selection_data_.empty());
+
+ EXPECT_EQ(1u, copy_paste_data_.size());
+ EXPECT_TRUE(base::Contains(copy_paste_data_, kMimeTypeTextUtf8));
+ auto contents = copy_paste_data_[kMimeTypeTextUtf8];
+ EXPECT_EQ(kSampleClipboardText,
+ std::string(contents->front_as<const char>(), contents->size()));
+}
+
+INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
+ WaylandClipboardTest,
+ ::testing::Values(kXdgShellStable));
+
+INSTANTIATE_TEST_SUITE_P(XdgVersionV6Test,
+ WaylandClipboardTest,
+ ::testing::Values(kXdgShellV6));
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_connection.cc b/chromium/ui/ozone/platform/wayland/host/wayland_connection.cc
index 73b76474df1..702328d0e9f 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_connection.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_connection.cc
@@ -53,7 +53,10 @@
namespace ui {
namespace {
-constexpr uint32_t kMaxAuraShellVersion = 11;
+// The maximum supported versions for a given interface.
+// The version bound will be the minimum of the value and the version
+// advertised by the server.
+constexpr uint32_t kMaxAuraShellVersion = 16;
constexpr uint32_t kMaxCompositorVersion = 4;
constexpr uint32_t kMaxCursorShapesVersion = 1;
constexpr uint32_t kMaxGtkPrimarySelectionDeviceManagerVersion = 1;
@@ -67,10 +70,13 @@ constexpr uint32_t kMaxWpPresentationVersion = 1;
constexpr uint32_t kMaxWpViewporterVersion = 1;
constexpr uint32_t kMaxTextInputManagerVersion = 1;
constexpr uint32_t kMaxExplicitSyncVersion = 2;
-constexpr uint32_t kMinWlDrmVersion = 2;
-constexpr uint32_t kMinWlOutputVersion = 2;
constexpr uint32_t kMaxXdgDecorationVersion = 1;
constexpr uint32_t kMaxExtendedDragVersion = 1;
+// The minimum required version for a given interface.
+// Ensures that the version bound (advertised by server) is higher than this
+// value.
+constexpr uint32_t kMinWlDrmVersion = 2;
+constexpr uint32_t kMinWlOutputVersion = 2;
} // namespace
WaylandConnection::WaylandConnection() = default;
@@ -89,8 +95,22 @@ bool WaylandConnection::Initialize() {
LOG(ERROR) << "Failed to load wayland client libraries.";
return false;
}
+
if (void* libwayland_egl = dlopen("libwayland-egl.so.1", dlopen_flags))
third_party_wayland::InitializeLibwaylandegl(libwayland_egl);
+
+ // TODO(crbug.com/1081784): consider handling this in more flexible way.
+ // libwayland-cursor is said to be part of the standard shipment of Wayland,
+ // and it seems unlikely (although possible) that it would be unavailable
+ // while libwayland-client was present. To handle that gracefully, chrome can
+ // fall back to the generic Ozone behaviour.
+ if (void* libwayland_cursor =
+ dlopen("libwayland-cursor.so.0", dlopen_flags)) {
+ third_party_wayland::InitializeLibwaylandcursor(libwayland_cursor);
+ } else {
+ LOG(ERROR) << "Failed to load libwayland-cursor.so.0.";
+ return false;
+ }
#endif
static const wl_registry_listener registry_listener = {
@@ -163,6 +183,21 @@ void WaylandConnection::SetShutdownCb(base::OnceCallback<void()> shutdown_cb) {
event_source()->SetShutdownCb(std::move(shutdown_cb));
}
+void WaylandConnection::SetPlatformCursor(wl_cursor* cursor_data,
+ int buffer_scale) {
+ if (!cursor_)
+ return;
+ cursor_->SetPlatformShape(cursor_data, serial(), buffer_scale);
+}
+
+void WaylandConnection::SetCursorBufferListener(
+ WaylandCursorBufferListener* listener) {
+ listener_ = listener;
+ if (!cursor_)
+ return;
+ cursor_->set_listener(listener_);
+}
+
void WaylandConnection::SetCursorBitmap(const std::vector<SkBitmap>& bitmaps,
const gfx::Point& hotspot_in_dips,
int buffer_scale) {
@@ -205,6 +240,7 @@ void WaylandConnection::UpdateInputDevices(wl_seat* seat,
pointer_ =
std::make_unique<WaylandPointer>(pointer, this, event_source());
cursor_ = std::make_unique<WaylandCursor>(pointer_.get(), this);
+ cursor_->set_listener(listener_);
wayland_cursor_position_ = std::make_unique<WaylandCursorPosition>();
} else {
LOG(ERROR) << "Failed to get wl_pointer from seat";
@@ -362,7 +398,8 @@ void WaylandConnection::Global(void* data,
strcmp(interface, "gtk_primary_selection_device_manager") == 0) {
wl::Object<::gtk_primary_selection_device_manager> manager =
wl::Bind<::gtk_primary_selection_device_manager>(
- registry, name, kMaxGtkPrimarySelectionDeviceManagerVersion);
+ registry, name,
+ std::min(version, kMaxGtkPrimarySelectionDeviceManagerVersion));
connection->gtk_primary_selection_device_manager_ =
std::make_unique<GtkPrimarySelectionDeviceManager>(manager.release(),
connection);
@@ -371,7 +408,8 @@ void WaylandConnection::Global(void* data,
0) {
wl::Object<zwp_primary_selection_device_manager_v1> manager =
wl::Bind<zwp_primary_selection_device_manager_v1>(
- registry, name, kMaxGtkPrimarySelectionDeviceManagerVersion);
+ registry, name,
+ std::min(version, kMaxGtkPrimarySelectionDeviceManagerVersion));
connection->zwp_primary_selection_device_manager_ =
std::make_unique<ZwpPrimarySelectionDeviceManager>(manager.release(),
connection);
@@ -390,16 +428,16 @@ void WaylandConnection::Global(void* data,
zwp_linux_dmabuf.release(), connection);
} else if (!connection->presentation_ &&
(strcmp(interface, "wp_presentation") == 0)) {
- connection->presentation_ =
- wl::Bind<wp_presentation>(registry, name, kMaxWpPresentationVersion);
+ connection->presentation_ = wl::Bind<wp_presentation>(
+ registry, name, std::min(version, kMaxWpPresentationVersion));
} else if (!connection->viewporter_ &&
(strcmp(interface, "wp_viewporter") == 0)) {
- connection->viewporter_ =
- wl::Bind<wp_viewporter>(registry, name, kMaxWpViewporterVersion);
+ connection->viewporter_ = wl::Bind<wp_viewporter>(
+ registry, name, std::min(version, kMaxWpViewporterVersion));
} else if (!connection->zcr_cursor_shapes_ &&
strcmp(interface, "zcr_cursor_shapes_v1") == 0) {
- auto zcr_cursor_shapes =
- wl::Bind<zcr_cursor_shapes_v1>(registry, name, kMaxCursorShapesVersion);
+ auto zcr_cursor_shapes = wl::Bind<zcr_cursor_shapes_v1>(
+ registry, name, std::min(version, kMaxCursorShapesVersion));
if (!zcr_cursor_shapes) {
LOG(ERROR) << "Failed to bind zcr_cursor_shapes_v1";
return;
@@ -409,7 +447,7 @@ void WaylandConnection::Global(void* data,
} else if (!connection->keyboard_extension_v1_ &&
strcmp(interface, "zcr_keyboard_extension_v1") == 0) {
connection->keyboard_extension_v1_ = wl::Bind<zcr_keyboard_extension_v1>(
- registry, name, kMaxKeyboardExtensionVersion);
+ registry, name, std::min(version, kMaxKeyboardExtensionVersion));
if (!connection->keyboard_extension_v1_) {
LOG(ERROR) << "Failed to bind zcr_keyboard_extension_v1";
return;
@@ -447,12 +485,12 @@ void WaylandConnection::Global(void* data,
} else if (!connection->xdg_decoration_manager_ &&
strcmp(interface, "zxdg_decoration_manager_v1") == 0) {
connection->xdg_decoration_manager_ =
- wl::Bind<struct zxdg_decoration_manager_v1>(registry, name,
- kMaxXdgDecorationVersion);
+ wl::Bind<struct zxdg_decoration_manager_v1>(
+ registry, name, std::min(version, kMaxXdgDecorationVersion));
} else if (!connection->extended_drag_v1_ &&
strcmp(interface, "zcr_extended_drag_v1") == 0) {
- connection->extended_drag_v1_ =
- wl::Bind<zcr_extended_drag_v1>(registry, name, kMaxExtendedDragVersion);
+ connection->extended_drag_v1_ = wl::Bind<zcr_extended_drag_v1>(
+ registry, name, std::min(version, kMaxExtendedDragVersion));
if (!connection->extended_drag_v1_) {
LOG(ERROR) << "Failed to bind to zcr_extended_drag_v1 global";
return;
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_connection.h b/chromium/ui/ozone/platform/wayland/host/wayland_connection.h
index b7f2981a074..7624abc23d6 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_connection.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_connection.h
@@ -16,6 +16,8 @@
#include "ui/ozone/platform/wayland/host/wayland_data_source.h"
#include "ui/ozone/platform/wayland/host/wayland_window_manager.h"
+struct wl_cursor;
+
namespace gfx {
class Point;
}
@@ -24,6 +26,7 @@ namespace ui {
class WaylandBufferManagerHost;
class WaylandCursor;
+class WaylandCursorBufferListener;
class WaylandDrm;
class WaylandEventSource;
class WaylandKeyboard;
@@ -65,6 +68,8 @@ class WaylandConnection {
wl_display* display() const { return display_.get(); }
wl_compositor* compositor() const { return compositor_.get(); }
+ // The server version of the compositor interface (might be higher than the
+ // version binded).
uint32_t compositor_version() const { return compositor_version_; }
wl_subcompositor* subcompositor() const { return subcompositor_.get(); }
wp_viewporter* viewporter() const { return viewporter_.get(); }
@@ -92,6 +97,10 @@ class WaylandConnection {
uint32_t serial() const { return serial_.serial; }
EventSerial event_serial() const { return serial_; }
+ void SetPlatformCursor(wl_cursor* cursor_data, int buffer_scale);
+
+ void SetCursorBufferListener(WaylandCursorBufferListener* listener);
+
void SetCursorBitmap(const std::vector<SkBitmap>& bitmaps,
const gfx::Point& hotspot_in_dips,
int buffer_scale);
@@ -250,6 +259,8 @@ class WaylandConnection {
// Manages Wayland windows.
WaylandWindowManager wayland_window_manager_;
+ WaylandCursorBufferListener* listener_ = nullptr;
+
bool scheduled_flush_ = false;
EventSerial serial_;
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_connection_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_connection_unittest.cc
index cfce7dba945..4d6cabb6a2e 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_connection_unittest.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_connection_unittest.cc
@@ -8,8 +8,10 @@
#include "base/run_loop.h"
#include "base/test/task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/ozone/platform/wayland/common/wayland.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
#include "ui/ozone/platform/wayland/host/wayland_event_source.h"
+#include "ui/ozone/platform/wayland/test/test_compositor.h"
#include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h"
namespace ui {
@@ -30,6 +32,9 @@ TEST(WaylandConnectionTest, Ping) {
base::RunLoop().RunUntilIdle();
server.Pause();
+ EXPECT_EQ(wl::TestCompositor::kVersion,
+ wl::get_version_of_object(connection.compositor()));
+
xdg_wm_base_send_ping(server.xdg_shell()->resource(), 1234);
EXPECT_CALL(*server.xdg_shell(), Pong(1234));
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_cursor.cc b/chromium/ui/ozone/platform/wayland/host/wayland_cursor.cc
index 44218ecc612..bd32821c243 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_cursor.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_cursor.cc
@@ -4,6 +4,7 @@
#include "ui/ozone/platform/wayland/host/wayland_cursor.h"
+#include <wayland-cursor.h>
#include <memory>
#include <vector>
@@ -74,6 +75,30 @@ void WaylandCursor::UpdateBitmap(const std::vector<SkBitmap>& cursor_image,
auto* address = buffer.get();
buffers_.emplace(address, std::move(buffer));
+
+ if (listener_)
+ listener_->OnCursorBufferAttached(nullptr);
+}
+
+void WaylandCursor::SetPlatformShape(wl_cursor* cursor_data,
+ uint32_t serial,
+ int buffer_scale) {
+ if (!pointer_)
+ return;
+
+ wl_cursor_image* cursor_image = cursor_data->images[0];
+ wl_buffer* cursor_buffer = wl_cursor_image_get_buffer(cursor_image);
+
+ wl_pointer_set_cursor(pointer_->wl_object(), serial, pointer_surface_.get(),
+ cursor_image->hotspot_x, cursor_image->hotspot_y);
+ wl_surface_set_buffer_scale(pointer_surface_.get(), buffer_scale);
+ wl_surface_damage(pointer_surface_.get(), 0, 0, cursor_image->width,
+ cursor_image->height);
+ wl_surface_attach(pointer_surface_.get(), cursor_buffer, 0, 0);
+ wl_surface_commit(pointer_surface_.get());
+
+ if (listener_)
+ listener_->OnCursorBufferAttached(cursor_data);
}
void WaylandCursor::HideCursor(uint32_t serial) {
@@ -84,6 +109,9 @@ void WaylandCursor::HideCursor(uint32_t serial) {
wl_surface_commit(pointer_surface_.get());
connection_->ScheduleFlush();
+
+ if (listener_)
+ listener_->OnCursorBufferAttached(nullptr);
}
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_cursor.h b/chromium/ui/ozone/platform/wayland/host/wayland_cursor.h
index e60191eced4..16af372b4c0 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_cursor.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_cursor.h
@@ -15,6 +15,8 @@
class SkBitmap;
+struct wl_cursor;
+
namespace gfx {
class Point;
}
@@ -24,12 +26,23 @@ namespace ui {
class WaylandConnection;
class WaylandPointer;
+// Interface through which WaylandCursor notifies the listener that it has
+// attached another buffer to the pointer surface. The listener may free the
+// previous buffer if it was holding it.
+class WaylandCursorBufferListener {
+ public:
+ // Tells the listener that a new buffer is attached. |cursor_data| may be
+ // non-nullptr if the platform shape is used, or nullptr if the cursor has
+ // been hidden, or a custom bitmap has been set.
+ virtual void OnCursorBufferAttached(wl_cursor* cursor_data) = 0;
+
+ protected:
+ virtual ~WaylandCursorBufferListener() = default;
+};
+
// Manages the actual visual representation (what users see drawn) of the
// 'pointer' (which is the Wayland term for mouse/mice).
//
-// An instance of this class is aggregated by an instance of WaylandPointer
-// and is exposed for updating the pointer bitmap with the single method call.
-//
// Encapsulates the low-level job such as surface and buffer management and
// Wayland protocol calls.
class WaylandCursor {
@@ -48,6 +61,15 @@ class WaylandCursor {
uint32_t serial,
int buffer_scale);
+ // Takes data managed by the platform (without taking ownership).
+ void SetPlatformShape(wl_cursor* cursor_data,
+ uint32_t serial,
+ int buffer_scale);
+
+ void set_listener(WaylandCursorBufferListener* listener) {
+ listener_ = listener;
+ }
+
private:
// wl_buffer_listener:
static void OnBufferRelease(void* data, wl_buffer* wl_buffer);
@@ -57,6 +79,8 @@ class WaylandCursor {
WaylandPointer* const pointer_;
WaylandConnection* const connection_;
+ WaylandCursorBufferListener* listener_ = nullptr;
+
// Holds the buffers and their memory until the compositor releases them.
base::flat_map<wl_buffer*, WaylandShmBuffer> buffers_;
const wl::Object<wl_surface> pointer_surface_;
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_cursor_factory.cc b/chromium/ui/ozone/platform/wayland/host/wayland_cursor_factory.cc
new file mode 100644
index 00000000000..5c0a72ebe2a
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_cursor_factory.cc
@@ -0,0 +1,156 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/ozone/platform/wayland/host/wayland_cursor_factory.h"
+
+#include <wayland-cursor.h>
+
+#include "base/task/post_task.h"
+#include "base/task/task_traits.h"
+#include "base/task/thread_pool.h"
+#include "base/task/thread_pool/thread_pool_instance.h"
+#include "base/task_runner_util.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_shm.h"
+
+namespace ui {
+
+namespace {
+
+wl_cursor_theme* LoadCursorTheme(const std::string& name,
+ int size,
+ wl_shm* shm) {
+ // wl_cursor_theme_load() can return nullptr. We don't check that here but
+ // have to be cautious when we actually load the shape.
+ return wl_cursor_theme_load((name.empty() ? nullptr : name.c_str()), size,
+ shm);
+}
+
+} // namespace
+
+WaylandCursorFactory::ThemeData::ThemeData() = default;
+
+WaylandCursorFactory::ThemeData::~ThemeData() = default;
+
+WaylandCursorFactory::WaylandCursorFactory(WaylandConnection* connection)
+ : connection_(connection) {
+ connection_->SetCursorBufferListener(this);
+ ReloadThemeCursors();
+}
+
+WaylandCursorFactory::~WaylandCursorFactory() = default;
+
+void WaylandCursorFactory::ObserveThemeChanges() {
+ auto* cursor_theme_manager = CursorThemeManager::GetInstance();
+ DCHECK(cursor_theme_manager);
+ cursor_theme_observer_.Observe(cursor_theme_manager);
+}
+
+base::Optional<PlatformCursor> WaylandCursorFactory::GetDefaultCursor(
+ mojom::CursorType type) {
+ if (type == mojom::CursorType::kNone)
+ return nullptr; // nullptr is used for the hidden cursor.
+
+ if (current_theme_->cache.count(type) == 0) {
+ for (const std::string& name : CursorNamesFromType(type)) {
+ wl_cursor* cursor = GetCursorFromTheme(name);
+ if (!cursor)
+ continue;
+
+ current_theme_->cache[type] =
+ base::MakeRefCounted<BitmapCursorOzone>(type, cursor);
+ break;
+ }
+ }
+ if (current_theme_->cache.count(type) == 0)
+ current_theme_->cache[type] = nullptr;
+
+ // Fall back to the base class implementation if the theme has't provided
+ // a shape for the requested type.
+ if (current_theme_->cache[type].get() == nullptr)
+ return BitmapCursorFactoryOzone::GetDefaultCursor(type);
+
+ return static_cast<PlatformCursor>(current_theme_->cache[type].get());
+}
+
+wl_cursor* WaylandCursorFactory::GetCursorFromTheme(const std::string& name) {
+ // Possible if the theme could not be loaded.
+ if (!current_theme_->theme)
+ return nullptr;
+
+ return wl_cursor_theme_get_cursor(current_theme_->theme.get(), name.c_str());
+}
+
+void WaylandCursorFactory::OnCursorThemeNameChanged(
+ const std::string& cursor_theme_name) {
+ if (name_ == cursor_theme_name)
+ return;
+
+ name_ = cursor_theme_name;
+ ReloadThemeCursors();
+}
+
+void WaylandCursorFactory::OnCursorThemeSizeChanged(int cursor_theme_size) {
+ if (size_ == cursor_theme_size)
+ return;
+
+ size_ = cursor_theme_size;
+ ReloadThemeCursors();
+}
+
+void WaylandCursorFactory::OnCursorBufferAttached(wl_cursor* cursor_data) {
+ if (!unloaded_theme_)
+ return;
+ if (!cursor_data) {
+ unloaded_theme_.reset();
+ return;
+ }
+ for (auto& item : current_theme_->cache) {
+ if (item.second->platform_data() == cursor_data) {
+ // The cursor that has been just attached is from the current theme. That
+ // means that the theme that has been unloaded earlier can now be deleted.
+ unloaded_theme_.reset();
+ return;
+ }
+ }
+}
+
+void WaylandCursorFactory::ReloadThemeCursors() {
+ // If we use any cursor when the theme is reloaded, the one can be only from
+ // the theme that is currently used. As soon as we take the next cursor from
+ // the next theme, we will destroy it (see OnCursorBufferAttached() above).
+ // If more than one theme has been changed but we didn't take any cursors from
+ // them (which is possible if the user played with settings but didn't switch
+ // into Chromium), we don't need to track them all.
+ if (!unloaded_theme_ && current_theme_ && current_theme_->cache.size() > 0)
+ unloaded_theme_ = std::move(current_theme_);
+
+ current_theme_ = std::make_unique<ThemeData>();
+
+ // The task environment is normally not created in tests. As this factory is
+ // part of the platform that is created always and early, posting a task to
+ // the pool would fail in many many tests.
+ if (!base::ThreadPoolInstance::Get())
+ return;
+
+ base::PostTaskAndReplyWithResult(
+ FROM_HERE,
+ {base::ThreadPool(), base::MayBlock(),
+ base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
+ base::BindOnce(LoadCursorTheme, name_, size_, connection_->shm()->get()),
+ base::BindOnce(&WaylandCursorFactory::OnThemeLoaded,
+ weak_factory_.GetWeakPtr(), name_, size_));
+}
+
+void WaylandCursorFactory::OnThemeLoaded(const std::string& loaded_theme_name,
+ int loaded_theme_size,
+ wl_cursor_theme* loaded_theme) {
+ if (loaded_theme_name == name_ && loaded_theme_size == size_) {
+ // wl_cursor_theme_load() can return nullptr. We don't check that here but
+ // have to be cautious when we actually load the shape.
+ current_theme_->theme.reset(loaded_theme);
+ }
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_cursor_factory.h b/chromium/ui/ozone/platform/wayland/host/wayland_cursor_factory.h
new file mode 100644
index 00000000000..0be03bc1b43
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_cursor_factory.h
@@ -0,0 +1,90 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_CURSOR_FACTORY_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_CURSOR_FACTORY_H_
+
+#include <string>
+
+#include "base/containers/flat_map.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
+#include "base/scoped_observation.h"
+#include "ui/base/cursor/cursor_theme_manager.h"
+#include "ui/base/cursor/cursor_theme_manager_observer.h"
+#include "ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h"
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
+#include "ui/ozone/platform/wayland/host/wayland_cursor.h"
+
+struct wl_cursor_theme;
+
+namespace ui {
+
+class WaylandConnection;
+
+// CursorFactory implementation for Wayland.
+class WaylandCursorFactory : public BitmapCursorFactoryOzone,
+ public CursorThemeManagerObserver,
+ public WaylandCursorBufferListener {
+ public:
+ explicit WaylandCursorFactory(WaylandConnection* connection);
+ WaylandCursorFactory(const WaylandCursorFactory&) = delete;
+ WaylandCursorFactory& operator=(const WaylandCursorFactory&) = delete;
+ ~WaylandCursorFactory() override;
+
+ // CursorFactory:
+ void ObserveThemeChanges() override;
+
+ // CursorFactoryOzone:
+ base::Optional<PlatformCursor> GetDefaultCursor(
+ mojom::CursorType type) override;
+
+ protected:
+ // Returns the actual wl_cursor record from the currently loaded theme.
+ // Virtual for tests where themes can be empty.
+ virtual wl_cursor* GetCursorFromTheme(const std::string& name);
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(WaylandCursorFactoryTest,
+ RetainOldThemeUntilNewBufferIsAttached);
+
+ struct ThemeData {
+ ThemeData();
+ ~ThemeData();
+ wl::Object<wl_cursor_theme> theme;
+ base::flat_map<mojom::CursorType, scoped_refptr<BitmapCursorOzone>> cache;
+ };
+
+ // CusorThemeManagerObserver:
+ void OnCursorThemeNameChanged(const std::string& cursor_theme_name) override;
+ void OnCursorThemeSizeChanged(int cursor_theme_size) override;
+
+ // WaylandCursorBufferListener:
+ void OnCursorBufferAttached(wl_cursor* cursor_data) override;
+
+ void ReloadThemeCursors();
+ void OnThemeLoaded(const std::string& loaded_theme_name,
+ int loaded_theme_size,
+ wl_cursor_theme* loaded_theme);
+
+ WaylandConnection* const connection_;
+
+ base::ScopedObservation<CursorThemeManager, CursorThemeManagerObserver>
+ cursor_theme_observer_{this};
+
+ // Name of the current theme.
+ std::string name_;
+ // Current size of cursors
+ int size_ = 24;
+
+ std::unique_ptr<ThemeData> current_theme_;
+ // Holds the reference on the unloaded theme until the cursor is released.
+ std::unique_ptr<ThemeData> unloaded_theme_;
+
+ base::WeakPtrFactory<WaylandCursorFactory> weak_factory_{this};
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_CURSOR_FACTORY_H_
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_cursor_factory_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_cursor_factory_unittest.cc
new file mode 100644
index 00000000000..1ea0e04b6cc
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_cursor_factory_unittest.cc
@@ -0,0 +1,134 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/ozone/platform/wayland/host/wayland_cursor_factory.h"
+
+#include <wayland-cursor.h>
+
+#include "base/containers/flat_map.h"
+#include "base/gtest_prod_util.h"
+#include "ui/ozone/platform/wayland/test/wayland_test.h"
+
+namespace ui {
+
+namespace {
+
+// Overrides WaylandCursorFactory::GetCursorFromTheme() to pretend that cursors
+// are really loaded.
+class DryRunningWaylandCursorFactory : public WaylandCursorFactory {
+ public:
+ explicit DryRunningWaylandCursorFactory(WaylandConnection* connection)
+ : WaylandCursorFactory(connection) {}
+ DryRunningWaylandCursorFactory(const DryRunningWaylandCursorFactory&) =
+ delete;
+ DryRunningWaylandCursorFactory& operator=(
+ const DryRunningWaylandCursorFactory&) = delete;
+ ~DryRunningWaylandCursorFactory() override = default;
+
+ protected:
+ // Pretends to load a cursor by creating an empty wl_cursor.
+ wl_cursor* GetCursorFromTheme(const std::string& name) override {
+ if (cursors_.count(name) == 0) {
+ cursors_[name] = std::make_unique<wl_cursor>();
+ cursors_[name]->image_count = 0;
+ cursors_[name]->images = nullptr;
+ cursors_[name]->name = nullptr;
+ }
+ return cursors_[name].get();
+ }
+
+ private:
+ base::flat_map<std::string, std::unique_ptr<wl_cursor>> cursors_;
+};
+
+} // namespace
+
+class WaylandCursorFactoryTest : public WaylandTest {
+ public:
+ WaylandCursorFactoryTest() = default;
+
+ void SetUp() override {
+ WaylandTest::SetUp();
+
+ cursor_factory_ =
+ std::make_unique<DryRunningWaylandCursorFactory>(connection_.get());
+ }
+
+ protected:
+ std::unique_ptr<WaylandCursorFactory> cursor_factory_;
+};
+
+// Tests that the factory holds the cursor theme until a buffer taken from it
+// released.
+TEST_P(WaylandCursorFactoryTest, RetainOldThemeUntilNewBufferIsAttached) {
+ // The default theme should be loaded right away. The unloaded theme should
+ // not be set.
+ EXPECT_NE(cursor_factory_->current_theme_, nullptr);
+ EXPECT_EQ(cursor_factory_->unloaded_theme_, nullptr);
+
+ // Trigger theme reload and ensure that the theme instance has changed.
+ // As we didn't request any buffers, the unloaded theme should not be held.
+ {
+ auto* const current_theme = cursor_factory_->current_theme_.get();
+ cursor_factory_->OnCursorThemeNameChanged("Theme1");
+ EXPECT_NE(cursor_factory_->current_theme_, nullptr);
+ EXPECT_NE(cursor_factory_->current_theme_.get(), current_theme);
+ EXPECT_EQ(cursor_factory_->unloaded_theme_, nullptr);
+ }
+
+ // Now request some buffer, and while "holding" it (i.e., not notifying the
+ // factory about attaching any other buffer), reload the theme a couple times.
+ // This time the unloaded theme should be set and survive these reloads.
+ // In the end, tell the factory that we have attached a buffer belonging to
+ // the cursor from the "unloaded" theme. This must not trigger unloading of
+ // that theme.
+ {
+ auto* const current_theme = cursor_factory_->current_theme_.get();
+ auto const cursor =
+ cursor_factory_->GetDefaultCursor(mojom::CursorType::kPointer);
+ EXPECT_NE(cursor, nullptr);
+ EXPECT_GT(cursor_factory_->current_theme_->cache.size(), 0U);
+
+ cursor_factory_->OnCursorThemeNameChanged("Theme2");
+
+ EXPECT_EQ(cursor_factory_->current_theme_->cache.size(), 0U);
+ EXPECT_NE(cursor_factory_->current_theme_, nullptr);
+ EXPECT_NE(cursor_factory_->current_theme_.get(), current_theme);
+ EXPECT_EQ(cursor_factory_->unloaded_theme_.get(), current_theme);
+
+ cursor_factory_->OnCursorThemeNameChanged("Theme3");
+
+ EXPECT_EQ(cursor_factory_->current_theme_->cache.size(), 0U);
+ EXPECT_NE(cursor_factory_->current_theme_, nullptr);
+ EXPECT_NE(cursor_factory_->current_theme_.get(), current_theme);
+ EXPECT_EQ(cursor_factory_->unloaded_theme_.get(), current_theme);
+
+ cursor_factory_->OnCursorBufferAttached(reinterpret_cast<wl_cursor*>(
+ reinterpret_cast<BitmapCursorOzone*>(*cursor)->platform_data()));
+ EXPECT_EQ(cursor_factory_->unloaded_theme_.get(), current_theme);
+ }
+
+ // Finally, tell the factory that we have attached a buffer from the current
+ // theme. This time the old theme held since a while ago should be freed.
+ {
+ auto const cursor =
+ cursor_factory_->GetDefaultCursor(mojom::CursorType::kPointer);
+ EXPECT_NE(cursor, nullptr);
+
+ cursor_factory_->OnCursorBufferAttached(reinterpret_cast<wl_cursor*>(
+ reinterpret_cast<BitmapCursorOzone*>(*cursor)->platform_data()));
+
+ EXPECT_EQ(cursor_factory_->unloaded_theme_.get(), nullptr);
+ }
+}
+
+INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
+ WaylandCursorFactoryTest,
+ ::testing::Values(kXdgShellStable));
+
+INSTANTIATE_TEST_SUITE_P(XdgVersionV6Test,
+ WaylandCursorFactoryTest,
+ ::testing::Values(kXdgShellV6));
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_device.cc b/chromium/ui/ozone/platform/wayland/host/wayland_data_device.cc
index 8f4b62fa68e..01f32113363 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_device.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_device.cc
@@ -10,7 +10,6 @@
#include "base/bind.h"
#include "base/files/scoped_file.h"
-#include "ui/base/clipboard/clipboard_buffer.h"
#include "ui/gfx/geometry/point_f.h"
#include "ui/ozone/platform/wayland/common/data_util.h"
#include "ui/ozone/platform/wayland/common/wayland_object.h"
@@ -94,10 +93,7 @@ void WaylandDataDevice::OnOffer(void* data,
wl_data_device* data_device,
wl_data_offer* offer) {
auto* self = static_cast<WaylandDataDevice*>(data);
-
- self->connection()->clipboard()->UpdateSequenceNumber(
- ClipboardBuffer::kCopyPaste);
-
+ DCHECK(self);
DCHECK(!self->new_offer_);
self->new_offer_ = std::make_unique<WaylandDataOffer>(offer);
}
@@ -163,7 +159,7 @@ void WaylandDataDevice::OnLeave(void* data, wl_data_device* data_device) {
// potential use-after-free. Above call to OnDragLeave() may result in
// |drag_delegate_| being reset, so it must be checked here as well.
if (self->drag_delegate_ && !self->drag_delegate_->IsDragSource())
- self->drag_delegate_ = nullptr;
+ self->ResetDragDelegate();
}
void WaylandDataDevice::OnSelection(void* data,
@@ -173,19 +169,17 @@ void WaylandDataDevice::OnSelection(void* data,
DCHECK(self);
// 'offer' will be null to indicate that the selection is no longer valid,
- // i.e. there is no longer clipboard data available to paste.
+ // i.e. there is no longer selection data available to fetch.
if (!offer) {
self->ResetDataOffer();
-
- // Clear Clipboard cache.
- self->connection()->clipboard()->SetData({}, {});
- return;
+ } else {
+ DCHECK(self->new_offer_);
+ self->set_data_offer(std::move(self->new_offer_));
+ self->data_offer()->EnsureTextMimeTypeIfNeeded();
}
- DCHECK(self->new_offer_);
- self->set_data_offer(std::move(self->new_offer_));
-
- self->data_offer()->EnsureTextMimeTypeIfNeeded();
+ if (self->selection_delegate())
+ self->selection_delegate()->OnSelectionOffer(self->data_offer());
}
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_device.h b/chromium/ui/ozone/platform/wayland/host/wayland_data_device.h
index f43ba2e8dfa..b13551eaf66 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_device.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_device.h
@@ -74,6 +74,15 @@ class WaylandDataDevice : public WaylandDataDeviceBase {
// Returns the underlying wl_data_device singleton object.
wl_data_device* data_device() const { return data_device_.get(); }
+ // wl_data_device::set_selection makes the corresponding wl_data_source the
+ // target of future wl_data_device::data_offer events. In non-Wayland terms,
+ // this is equivalent to "writing" to the clipboard or DnD, although the
+ // actual transfer of data happens asynchronously, on-demand-only.
+ //
+ // The API relies on the assumption that the Wayland client is responding to a
+ // keyboard or mouse event with a serial number. This is cached in
+ // WaylandConnection. However, this may not exist or be set properly in tests,
+ // resulting in the Wayland server ignoring the set_selection() request.
void SetSelectionSource(WaylandDataSource* source);
private:
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_device_base.cc b/chromium/ui/ozone/platform/wayland/host/wayland_data_device_base.cc
index 7df5d9ec709..50be3ad35bc 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_device_base.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_device_base.cc
@@ -56,10 +56,10 @@ void WaylandDataDeviceBase::ReadClipboardDataFromFD(
const std::string& mime_type) {
std::vector<uint8_t> contents;
wl::ReadDataFromFD(std::move(fd), &contents);
- connection_->clipboard()->SetData(
- scoped_refptr<base::RefCountedBytes>(
- base::RefCountedBytes::TakeVector(&contents)),
- mime_type);
+ if (!selection_delegate_)
+ return;
+ selection_delegate_->OnSelectionDataReceived(
+ mime_type, base::RefCountedBytes::TakeVector(&contents));
}
void WaylandDataDeviceBase::RegisterDeferredReadCallback() {
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_device_base.h b/chromium/ui/ozone/platform/wayland/host/wayland_data_device_base.h
index e331243fc5e..1775790bef2 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_device_base.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_device_base.h
@@ -12,6 +12,7 @@
#include "base/macros.h"
#include "ui/ozone/platform/wayland/common/wayland_object.h"
#include "ui/ozone/platform/wayland/host/wayland_data_offer_base.h"
+#include "ui/ozone/public/platform_clipboard.h"
namespace ui {
@@ -20,9 +21,25 @@ class WaylandConnection;
// Implements high level (protocol-agnostic) interface to a Wayland data device.
class WaylandDataDeviceBase {
public:
+ class SelectionDelegate {
+ public:
+ virtual void OnSelectionOffer(WaylandDataOfferBase* offer) = 0;
+ virtual void OnSelectionDataReceived(const std::string& mime_type,
+ PlatformClipboard::Data contents) = 0;
+
+ protected:
+ virtual ~SelectionDelegate() = default;
+ };
+
explicit WaylandDataDeviceBase(WaylandConnection* connection);
virtual ~WaylandDataDeviceBase();
+ // Sets the delegate instance responsible for handling section events.
+ void set_selection_delegate(SelectionDelegate* selection_delegate) {
+ DCHECK(!selection_delegate_ || !selection_delegate);
+ selection_delegate_ = selection_delegate;
+ }
+
// Returns MIME types given by the current data offer.
const std::vector<std::string>& GetAvailableMimeTypes() const;
@@ -50,6 +67,8 @@ class WaylandDataDeviceBase {
void RegisterDeferredReadClosure(base::OnceClosure closure);
+ SelectionDelegate* selection_delegate() { return selection_delegate_; }
+
private:
// wl_callback_listener callback
static void DeferredReadCallback(void* data,
@@ -58,9 +77,11 @@ class WaylandDataDeviceBase {
void DeferredReadCallbackInternal(struct wl_callback* cb, uint32_t time);
- // Used to call out to WaylandConnection once clipboard data
- // has been successfully read.
- WaylandConnection* const connection_ = nullptr;
+ SelectionDelegate* selection_delegate_ = nullptr;
+
+ // Used to call out to WaylandConnection once clipboard data has been
+ // successfully read.
+ WaylandConnection* const connection_;
// Offer that holds the most-recent clipboard selection, or null if no
// clipboard data is available.
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_device_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_data_device_unittest.cc
deleted file mode 100644
index 855982cf567..00000000000
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_device_unittest.cc
+++ /dev/null
@@ -1,203 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <wayland-server.h>
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/containers/flat_set.h"
-#include "base/strings/string16.h"
-#include "base/strings/utf_string_conversions.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/base/clipboard/clipboard_constants.h"
-#include "ui/events/base_event_utils.h"
-#include "ui/ozone/platform/wayland/test/mock_surface.h"
-#include "ui/ozone/platform/wayland/test/test_data_device.h"
-#include "ui/ozone/platform/wayland/test/test_data_device_manager.h"
-#include "ui/ozone/platform/wayland/test/test_data_offer.h"
-#include "ui/ozone/platform/wayland/test/test_data_source.h"
-#include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h"
-#include "ui/ozone/platform/wayland/test/wayland_test.h"
-#include "ui/ozone/public/platform_clipboard.h"
-
-using testing::_;
-using testing::Mock;
-
-namespace ui {
-
-namespace {
-
-constexpr char kSampleClipboardText[] = "This is a sample text for clipboard.";
-
-template <typename StringType>
-ui::PlatformClipboard::Data ToClipboardData(const StringType& data_string) {
- std::vector<uint8_t> data_vector;
- data_vector.assign(data_string.begin(), data_string.end());
- return scoped_refptr<base::RefCountedBytes>(
- base::RefCountedBytes::TakeVector(&data_vector));
-}
-
-} // namespace
-
-// This class mocks how a real clipboard/ozone client would
-// hook to PlatformClipboard, with one difference: real clients
-// have no access to the WaylandConnection instance like this
-// MockClipboardClient impl does. Instead, clients and ozone gets
-// plumbbed up by calling the appropriated Ozone API,
-// OzonePlatform::GetPlatformClipboard.
-class MockClipboardClient {
- public:
- explicit MockClipboardClient(WaylandConnection* connection) {
- DCHECK(connection);
- // See comment above for reasoning to access the WaylandConnection
- // directly from here.
- delegate_ = connection->clipboard();
-
- DCHECK(delegate_);
- }
- ~MockClipboardClient() = default;
-
- // Fill the clipboard backing store with sample data.
- void SetData(PlatformClipboard::Data data,
- const std::string& mime_type,
- PlatformClipboard::OfferDataClosure callback) {
- data_types_[mime_type] = data;
- delegate_->OfferClipboardData(ClipboardBuffer::kCopyPaste, data_types_,
- std::move(callback));
- }
-
- void ReadData(const std::string& mime_type,
- PlatformClipboard::RequestDataClosure callback) {
- delegate_->RequestClipboardData(ClipboardBuffer::kCopyPaste, mime_type,
- &data_types_, std::move(callback));
- }
-
- bool IsSelectionOwner() {
- return delegate_->IsSelectionOwner(ClipboardBuffer::kCopyPaste);
- }
-
- private:
- PlatformClipboard* delegate_ = nullptr;
- PlatformClipboard::DataMap data_types_;
-
- DISALLOW_COPY_AND_ASSIGN(MockClipboardClient);
-};
-
-class WaylandDataDeviceManagerTest : public WaylandTest {
- public:
- WaylandDataDeviceManagerTest() {}
-
- void SetUp() override {
- WaylandTest::SetUp();
-
- Sync();
-
- data_device_manager_ = server_.data_device_manager();
- DCHECK(data_device_manager_);
-
- clipboard_client_ =
- std::make_unique<MockClipboardClient>(connection_.get());
- }
-
- protected:
- wl::TestDataDeviceManager* data_device_manager_;
- std::unique_ptr<MockClipboardClient> clipboard_client_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(WaylandDataDeviceManagerTest);
-};
-
-TEST_P(WaylandDataDeviceManagerTest, WriteToClipboard) {
- // The client writes data to the clipboard ...
- std::vector<uint8_t> data_vector(
- kSampleClipboardText,
- kSampleClipboardText + strlen(kSampleClipboardText));
- clipboard_client_->SetData(
- scoped_refptr<base::RefCountedBytes>(
- base::RefCountedBytes::TakeVector(&data_vector)),
- {kMimeTypeTextUtf8}, base::BindOnce([]() {}));
- Sync();
-
- // ... and the server reads it.
- base::RunLoop run_loop;
- auto callback = base::BindOnce(
- [](base::RunLoop* loop, std::vector<uint8_t>&& data) {
- std::string string_data(data.begin(), data.end());
- EXPECT_EQ(kSampleClipboardText, string_data);
- loop->Quit();
- },
- &run_loop);
- data_device_manager_->data_source()->ReadData(kMimeTypeTextUtf8,
- std::move(callback));
- run_loop.Run();
-}
-
-TEST_P(WaylandDataDeviceManagerTest, ReadFromClipboard) {
- // TODO(nickdiego): implement this in terms of an actual wl_surface that
- // gets focused and compositor sends data_device data to it.
- auto* data_offer = data_device_manager_->data_device()->OnDataOffer();
- data_offer->OnOffer(kMimeTypeTextUtf8,
- ToClipboardData(std::string(kSampleClipboardText)));
- data_device_manager_->data_device()->OnSelection(data_offer);
- Sync();
-
- // The client requests to reading clipboard data from the server.
- // The Server writes in some sample data, and we check it matches
- // expectation.
- auto callback =
- base::BindOnce([](const base::Optional<PlatformClipboard::Data>& data) {
- auto& bytes = data->get()->data();
- std::string string_data = std::string(bytes.begin(), bytes.end());
- EXPECT_EQ(kSampleClipboardText, string_data);
- });
- clipboard_client_->ReadData(kMimeTypeTextUtf8, std::move(callback));
- Sync();
-}
-
-TEST_P(WaylandDataDeviceManagerTest, ReadFromClipboardWithoutOffer) {
- // When no data offer is advertised and client requests clipboard data
- // from the server, the response callback should be gracefully called with
- // an empty string.
- auto callback =
- base::BindOnce([](const base::Optional<PlatformClipboard::Data>& data) {
- auto& bytes = data->get()->data();
- std::string string_data = std::string(bytes.begin(), bytes.end());
- EXPECT_EQ("", string_data);
- });
- clipboard_client_->ReadData(kMimeTypeTextUtf8, std::move(callback));
-}
-
-TEST_P(WaylandDataDeviceManagerTest, IsSelectionOwner) {
- auto callback = base::BindOnce([]() {});
- std::vector<uint8_t> data_vector(
- kSampleClipboardText,
- kSampleClipboardText + strlen(kSampleClipboardText));
- clipboard_client_->SetData(
- scoped_refptr<base::RefCountedBytes>(
- base::RefCountedBytes::TakeVector(&data_vector)),
- {kMimeTypeTextUtf8}, std::move(callback));
- Sync();
- ASSERT_TRUE(clipboard_client_->IsSelectionOwner());
-
- // The compositor sends OnCancelled whenever another application
- // on the system sets a new selection. It means we are not the application
- // that owns the current selection data.
- data_device_manager_->data_source()->OnCancelled();
- Sync();
-
- ASSERT_FALSE(clipboard_client_->IsSelectionOwner());
-}
-
-INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
- WaylandDataDeviceManagerTest,
- ::testing::Values(kXdgShellStable));
-
-INSTANTIATE_TEST_SUITE_P(XdgVersionV6Test,
- WaylandDataDeviceManagerTest,
- ::testing::Values(kXdgShellV6));
-
-} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc b/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc
index 736c40d3cbe..d81ce6155af 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc
@@ -7,13 +7,13 @@
#include <cstdint>
#include "base/check.h"
+#include "base/metrics/histogram_macros.h"
#include "base/notreached.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/clipboard/clipboard_constants.h"
#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/base/dragdrop/os_exchange_data_provider_non_backed.h"
-#include "ui/gfx/geometry/point_f.h"
#include "ui/ozone/platform/wayland/common/data_util.h"
#include "ui/ozone/platform/wayland/common/wayland_util.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
@@ -28,31 +28,22 @@ namespace ui {
namespace {
-// Returns actions possible with the given source and drag'n'drop actions.
-// Also converts enums: input params are wl_data_device_manager_dnd_action but
-// the result is ui::DragDropTypes.
-int GetPossibleActions(uint32_t source_actions, uint32_t dnd_action) {
- // If drag'n'drop action is set, use it but check for ASK action (see below).
- uint32_t action = dnd_action != WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE
- ? dnd_action
- : source_actions;
-
- // We accept any action except ASK (see below).
- int operation = DragDropTypes::DRAG_NONE;
- if (action & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY)
- operation |= DragDropTypes::DRAG_COPY;
- if (action & WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE)
- operation |= DragDropTypes::DRAG_MOVE;
- if (action & WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK) {
- // This is very rare and non-standard. Chromium doesn't set this when
- // anything is dragged from it, neither it provides any UI for asking
- // the user about the desired drag'n'drop action when data is dragged
- // from an external source.
- // We are safe with not adding anything here. However, keep NOTIMPLEMENTED
- // for an (unlikely) event of this being hit in distant future.
- NOTIMPLEMENTED_LOG_ONCE();
- }
- return operation;
+int DndActionsToDragOperations(uint32_t actions) {
+ int operations = DragDropTypes::DRAG_NONE;
+ if (actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY)
+ operations |= DragDropTypes::DRAG_COPY;
+ if (actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE)
+ operations |= DragDropTypes::DRAG_MOVE;
+ return operations;
+}
+
+uint32_t DragOperationsToDndActions(int operations) {
+ uint32_t dnd_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
+ if (operations & DragDropTypes::DRAG_COPY)
+ dnd_actions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
+ if (operations & DragDropTypes::DRAG_MOVE)
+ dnd_actions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
+ return dnd_actions;
}
const SkBitmap* GetDragImage(const OSExchangeData& data) {
@@ -94,21 +85,27 @@ void WaylandDataDragController::StartSession(const OSExchangeData& data,
Offer(data, operation);
// Create drag icon surface (if any) and store the data to be exchanged.
- CreateIconSurfaceIfNeeded(data);
+ icon_bitmap_ = GetDragImage(data);
+ if (icon_bitmap_) {
+ icon_surface_ = connection_->CreateSurface();
+ wl_surface_set_buffer_scale(icon_surface_.get(),
+ origin_window_->buffer_scale());
+ }
data_ = std::make_unique<OSExchangeData>(data.provider().Clone());
// Starts the wayland drag session setting |this| object as delegate.
state_ = State::kStarted;
data_device_->StartDrag(*data_source_, *origin_window_, icon_surface_.get(),
this);
+
+ window_manager_->AddObserver(this);
}
-// Sessions initiated from Chromium, will have |origin_window_| pointing to the
-// window where the drag started in. In such cases, |data_| is expected to be
-// non-null, which can be used to save some IO cycles.
+// Sessions initiated from Chromium, will have |data_source_| set. In which
+// case, |data_| is expected to be non-null as well.
bool WaylandDataDragController::IsDragSource() const {
- DCHECK(!origin_window_ || data_);
- return !!origin_window_;
+ DCHECK(!data_source_ || data_);
+ return !!data_source_;
}
void WaylandDataDragController::DrawIcon() {
@@ -125,7 +122,6 @@ void WaylandDataDragController::DrawIcon() {
return;
}
}
- // TODO(crbug.com/1085418): Fix drag icon scaling
wl::DrawBitmap(*icon_bitmap_, shm_buffer_.get());
wl_surface_attach(icon_surface_.get(), shm_buffer_->get(), 0, 0);
wl_surface_damage(icon_surface_.get(), 0, 0, size.width(), size.height());
@@ -142,6 +138,7 @@ void WaylandDataDragController::OnDragEnter(WaylandWindow* window,
const gfx::PointF& location,
uint32_t serial) {
DCHECK(window);
+ DCHECK(data_offer_);
window_ = window;
// TODO(crbug.com/1004715): Set mime type the client can accept. Now it sets
@@ -153,39 +150,53 @@ void WaylandDataDragController::OnDragEnter(WaylandWindow* window,
data_offer_->Accept(serial, mime);
}
- std::unique_ptr<OSExchangeData> dragged_data;
- // If the DND session was initiated from a Chromium window, |data_| already
- // holds the data to be exchanged, so no needed to read it through Wayland,
- // thus just copy it here.
- if (IsDragSource())
- dragged_data = std::make_unique<OSExchangeData>(data_->provider().Clone());
- window_->OnDragEnter(location, std::move(dragged_data),
- GetPossibleActions(data_offer_->source_actions(),
- data_offer_->dnd_action()));
+ if (IsDragSource()) {
+ // If the DND session was initiated from a Chromium window, |data_| already
+ // holds the data to be exchanged, so we don't need to read it through
+ // Wayland and can just copy it here.
+ DCHECK(data_);
+ PropagateOnDragEnter(
+ location, std::make_unique<OSExchangeData>(data_->provider().Clone()));
+ } else {
+ // Otherwise, we are about to accept data dragged from another application.
+ // Reading the data may take some time so set |state_| to |kTrasferring|,
+ // which will defer sending OnDragEnter to the client until the data
+ // is ready.
+ state_ = State::kTransferring;
+ received_data_ = std::make_unique<OSExchangeData>(
+ std::make_unique<OSExchangeDataProviderNonBacked>());
+ last_drag_location_ = location;
+ HandleUnprocessedMimeTypes(base::TimeTicks::Now());
+ }
}
void WaylandDataDragController::OnDragMotion(const gfx::PointF& location) {
if (!window_)
return;
- int client_operation = window_->OnDragMotion(
- location, GetPossibleActions(data_offer_->source_actions(),
- data_offer_->dnd_action()));
- SetOperation(client_operation);
+ if (state_ == State::kTransferring) {
+ last_drag_location_ = location;
+ return;
+ }
+
+ DCHECK(data_offer_);
+ int available_operations =
+ DndActionsToDragOperations(data_offer_->source_actions());
+ int client_operations = window_->OnDragMotion(location, available_operations);
+
+ data_offer_->SetActions(DragOperationsToDndActions(client_operations));
}
void WaylandDataDragController::OnDragLeave() {
- if (!window_)
- return;
-
- // Leave event can arrive while data is being transferred. As it cannot be
- // handled right away, just mark it to be processed when the data is ready.
if (state_ == State::kTransferring) {
+ // We cannot leave until the transfer is finished. Postponing.
is_leave_pending_ = true;
return;
}
- window_->OnDragLeave();
+ if (window_)
+ window_->OnDragLeave();
+
window_ = nullptr;
data_offer_.reset();
is_leave_pending_ = false;
@@ -195,40 +206,32 @@ void WaylandDataDragController::OnDragDrop() {
if (!window_)
return;
- if (IsDragSource()) {
- // This means the data is being exchanged between Chromium windows. In this
- // case, data is supposed to have already been sent to the drop handler
- // before (see OnDragEnter()), expecting to receive null at this stage.
- OnDataTransferFinished(nullptr);
- return;
- }
+ window_->OnDragDrop();
- // Otherwise, we are about to accept data dragged from another application.
- // Reading the data may take some time so set |state_| to |kTrasfering|, which
- // will make final "leave" event handling to be postponed until data is ready.
- state_ = State::kTransferring;
- received_data_ = std::make_unique<OSExchangeData>(
- std::make_unique<OSExchangeDataProviderNonBacked>());
- HandleUnprocessedMimeTypes();
+ // Offer must be finished and destroyed here as some compositors may delay to
+ // send wl_data_source::finished|cancelled until owning client destroys the
+ // drag offer. e.g: Exosphere.
+ data_offer_->FinishOffer();
+ data_offer_.reset();
}
void WaylandDataDragController::OnDataSourceFinish(bool completed) {
DCHECK(data_source_);
- DCHECK(origin_window_);
-
- origin_window_->OnDragSessionClose(data_source_->dnd_action());
- // DnD handlers expect DragLeave to be sent for drag sessions that end up
- // with no data transfer (wl_data_source::cancelled event).
- if (!completed)
- origin_window_->OnDragLeave();
+ if (origin_window_) {
+ origin_window_->OnDragSessionClose(data_source_->dnd_action());
+ // DnD handlers expect DragLeave to be sent for drag sessions that end up
+ // with no data transfer (wl_data_source::cancelled event).
+ if (!completed)
+ origin_window_->OnDragLeave();
+ origin_window_ = nullptr;
+ }
- origin_window_ = nullptr;
+ window_manager_->RemoveObserver(this);
data_source_.reset();
data_offer_.reset();
data_.reset();
data_device_->ResetDragDelegate();
-
state_ = State::kIdle;
}
@@ -243,6 +246,14 @@ void WaylandDataDragController::OnDataSourceSend(const std::string& mime_type,
}
}
+void WaylandDataDragController::OnWindowRemoved(WaylandWindow* window) {
+ if (window == window_)
+ window_ = nullptr;
+
+ if (window == origin_window_)
+ origin_window_ = nullptr;
+}
+
void WaylandDataDragController::Offer(const OSExchangeData& data,
int operation) {
DCHECK(data_source_);
@@ -271,36 +282,29 @@ void WaylandDataDragController::Offer(const OSExchangeData& data,
data_source_->SetAction(operation);
}
-void WaylandDataDragController::CreateIconSurfaceIfNeeded(
- const OSExchangeData& data) {
- icon_bitmap_ = GetDragImage(data);
- if (icon_bitmap_)
- icon_surface_ = connection_->CreateSurface();
-}
-
// Asynchronously requests and reads data for every negotiated/supported mime
// type, one after another, OnMimeTypeDataTransferred calls back into this
// function once it finishes reading data for each mime type, until there is no
// more unprocessed mime types on the |unprocessed_mime_types_| queue. Once this
// process is finished, OnDataTransferFinished is called to deliver the
// |received_data_| to the drop handler.
-void WaylandDataDragController::HandleUnprocessedMimeTypes() {
- DCHECK_EQ(state_, State::kTransferring);
+void WaylandDataDragController::HandleUnprocessedMimeTypes(
+ base::TimeTicks start_time) {
std::string mime_type = GetNextUnprocessedMimeType();
- if (mime_type.empty()) {
- OnDataTransferFinished(std::move(received_data_));
+ if (mime_type.empty() || is_leave_pending_ || state_ == State::kIdle) {
+ OnDataTransferFinished(start_time, std::move(received_data_));
} else {
DCHECK(data_offer_);
data_device_->RequestData(
data_offer_.get(), mime_type,
base::BindOnce(&WaylandDataDragController::OnMimeTypeDataTransferred,
- weak_factory_.GetWeakPtr()));
+ weak_factory_.GetWeakPtr(), start_time));
}
}
void WaylandDataDragController::OnMimeTypeDataTransferred(
+ base::TimeTicks start_time,
PlatformClipboard::Data contents) {
- DCHECK_EQ(state_, State::kTransferring);
DCHECK(contents);
if (!contents->data().empty()) {
std::string mime_type = unprocessed_mime_types_.front();
@@ -309,21 +313,37 @@ void WaylandDataDragController::OnMimeTypeDataTransferred(
unprocessed_mime_types_.pop_front();
// Continue reading data for other negotiated mime types.
- HandleUnprocessedMimeTypes();
+ HandleUnprocessedMimeTypes(start_time);
}
void WaylandDataDragController::OnDataTransferFinished(
+ base::TimeTicks start_time,
std::unique_ptr<OSExchangeData> received_data) {
- data_offer_->FinishOffer();
- window_->OnDragDrop(std::move(received_data));
-
unprocessed_mime_types_.clear();
+ if (state_ == State::kIdle)
+ return;
+
state_ = State::kIdle;
// If |is_leave_pending_| is set, it means a 'leave' event was fired while
- // data was on transit, so process it here (See OnDragLeave for more context).
- if (is_leave_pending_)
- OnDragLeave();
+ // data was on transit (see OnDragLeave for more context). Sending
+ // OnDragEnter to the window makes no sense anymore because the drag is no
+ // longer over it. Reset and exit.
+ if (is_leave_pending_) {
+ if (data_offer_) {
+ data_offer_->FinishOffer();
+ data_offer_.reset();
+ }
+ data_.reset();
+ data_device_->ResetDragDelegate();
+ is_leave_pending_ = false;
+ return;
+ }
+
+ UMA_HISTOGRAM_TIMES("Event.WaylandDragDrop.IncomingDataTransferTime",
+ base::TimeTicks::Now() - start_time);
+
+ PropagateOnDragEnter(last_drag_location_, std::move(received_data));
}
// Returns the next MIME type to be received from the source process, or an
@@ -342,21 +362,15 @@ std::string WaylandDataDragController::GetNextUnprocessedMimeType() {
return {};
}
-void WaylandDataDragController::SetOperation(const int operation) {
- uint32_t dnd_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
- uint32_t preferred_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
-
- if (operation & DragDropTypes::DRAG_COPY) {
- dnd_actions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
- preferred_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
- }
+void WaylandDataDragController::PropagateOnDragEnter(
+ const gfx::PointF& location,
+ std::unique_ptr<OSExchangeData> data) {
+ DCHECK(window_);
- if (operation & DragDropTypes::DRAG_MOVE) {
- dnd_actions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
- if (preferred_action == WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE)
- preferred_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
- }
- data_offer_->SetAction(dnd_actions, preferred_action);
+ window_->OnDragEnter(
+ location, std::move(data),
+ DndActionsToDragOperations(data_offer_->source_actions()));
+ OnDragMotion(location);
}
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h b/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h
index 5e4c15dd08b..e4a7efbe2ab 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h
@@ -11,9 +11,11 @@
#include "base/gtest_prod_util.h"
#include "base/memory/weak_ptr.h"
+#include "ui/gfx/geometry/point_f.h"
#include "ui/ozone/platform/wayland/common/wayland_object.h"
#include "ui/ozone/platform/wayland/host/wayland_data_device.h"
#include "ui/ozone/platform/wayland/host/wayland_data_source.h"
+#include "ui/ozone/platform/wayland/host/wayland_window_observer.h"
struct wl_surface;
class SkBitmap;
@@ -28,15 +30,41 @@ class WaylandWindow;
class WaylandWindowManager;
class WaylandShmBuffer;
-// WaylandDataDragController implements regular data exchanging between Chromium
-// and other client applications on top of the Wayland Drag and Drop protocol.
-// By implementing both DataDevice::DragDelegate and DataSource::Delegate,
-// it is responsible for handling both DND sessions initiated from Chromium
-// windows as well as those triggered by other clients.
+// WaylandDataDragController implements regular data exchange on top of the
+// Wayland Drag and Drop protocol. The data can be dragged within the Chromium
+// window, or between Chromium and other application in both directions.
+//
+// The outgoing drag starts via the StartSession() method. For more context,
+// see WaylandTopLevelWindow::StartDrag().
+//
+// The incoming drag starts with the call to OnDragEnter() from the Wayland side
+// (the data device), and ends up in call to WaylandWindow::OnDragEnter(), but
+// two ways of coming there are possible:
+//
+// 1. The drag has been initiated by a Chromium window. In this case, the data
+// that is being dragged is available right away, and therefore the controller
+// can forward the data to the window immediately.
+//
+// 2. The data is being dragged from another application. Before notifying the
+// window, the controller requests the data from the source side, which results
+// in a number of requests to Wayland and data transfers from it. Only after
+// data records of all supported MIME types have been received, the window will
+// be notified.
+//
+// It is possible that further drag events come while the data is still being
+// transferred. The drag motion event is ignored; the window will first receive
+// OnDragEnter, and any OnDragMotion that comes after that. The drag leave
+// event stops the transfer and cancels the operation; the window will not
+// receive anything at all.
class WaylandDataDragController : public WaylandDataDevice::DragDelegate,
- public WaylandDataSource::Delegate {
+ public WaylandDataSource::Delegate,
+ public WaylandWindowObserver {
public:
- enum class State { kIdle, kStarted, kTransferring };
+ enum class State {
+ kIdle, // Doing nothing special
+ kStarted, // The outgoing drag is in progress.
+ kTransferring, // The incoming data is transferred from the source.
+ };
WaylandDataDragController(WaylandConnection* connection,
WaylandDataDeviceManager* data_device_manager);
@@ -77,14 +105,21 @@ class WaylandDataDragController : public WaylandDataDevice::DragDelegate,
void OnDataSourceSend(const std::string& mime_type,
std::string* contents) override;
+ // WaylandWindowObserver:
+ void OnWindowRemoved(WaylandWindow* window) override;
+
void Offer(const OSExchangeData& data, int operation);
- void CreateIconSurfaceIfNeeded(const OSExchangeData& data);
- void HandleUnprocessedMimeTypes();
- void OnMimeTypeDataTransferred(PlatformClipboard::Data contents);
+ void HandleUnprocessedMimeTypes(base::TimeTicks start_time);
+ void OnMimeTypeDataTransferred(base::TimeTicks start_time,
+ PlatformClipboard::Data contents);
void OnDataTransferFinished(
+ base::TimeTicks start_time,
std::unique_ptr<ui::OSExchangeData> received_data);
std::string GetNextUnprocessedMimeType();
- void SetOperation(const int operation);
+ // Calls the window's OnDragEnter with the given location and data,
+ // then immediately calls OnDragMotion to get the actual operation.
+ void PropagateOnDragEnter(const gfx::PointF& location,
+ std::unique_ptr<OSExchangeData> data);
WaylandConnection* const connection_;
WaylandDataDeviceManager* const data_device_manager_;
@@ -93,6 +128,7 @@ class WaylandDataDragController : public WaylandDataDevice::DragDelegate,
State state_ = State::kIdle;
+ // Data offered by us to the other side.
std::unique_ptr<WaylandDataSource> data_source_;
// When dragging is started from Chromium, |data_| holds the data to be sent
@@ -117,6 +153,9 @@ class WaylandDataDragController : public WaylandDataDevice::DragDelegate,
// Current window under pointer.
WaylandWindow* window_ = nullptr;
+ // The most recent location received while dragging the data.
+ gfx::PointF last_drag_location_;
+
// The data delivered from Wayland
std::unique_ptr<ui::OSExchangeData> received_data_;
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc
index 8bd11603863..3e827a00928 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc
@@ -14,24 +14,26 @@
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/clipboard/clipboard_constants.h"
+#include "ui/base/clipboard/file_info.h"
#include "ui/base/cursor/cursor.h"
#include "ui/base/dragdrop/drag_drop_types.h"
-#include "ui/base/dragdrop/file_info/file_info.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/events/base_event_utils.h"
#include "ui/gfx/geometry/point.h"
#include "ui/ozone/platform/wayland/common/data_util.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
#include "ui/ozone/platform/wayland/host/wayland_data_device.h"
#include "ui/ozone/platform/wayland/host/wayland_data_device_manager.h"
#include "ui/ozone/platform/wayland/host/wayland_data_drag_controller.h"
#include "ui/ozone/platform/wayland/host/wayland_data_source.h"
-#include "ui/ozone/platform/wayland/host/wayland_toplevel_window.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
#include "ui/ozone/platform/wayland/test/mock_surface.h"
#include "ui/ozone/platform/wayland/test/test_data_device.h"
#include "ui/ozone/platform/wayland/test/test_data_device_manager.h"
#include "ui/ozone/platform/wayland/test/test_data_offer.h"
#include "ui/ozone/platform/wayland/test/test_data_source.h"
#include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h"
+#include "ui/ozone/platform/wayland/test/wayland_drag_drop_test.h"
#include "ui/ozone/platform/wayland/test/wayland_test.h"
#include "ui/ozone/public/platform_clipboard.h"
#include "ui/platform_window/platform_window_init_properties.h"
@@ -78,12 +80,8 @@ class MockDropHandler : public WmDropHandler {
MockDropHandler() = default;
~MockDropHandler() override = default;
- MOCK_METHOD4(OnDragEnter,
- void(const gfx::PointF& point,
- std::unique_ptr<OSExchangeData> data,
- int operation,
- int modifiers));
- MOCK_METHOD3(OnDragMotion,
+ MOCK_METHOD0(MockOnDragEnter, void());
+ MOCK_METHOD3(MockDragMotion,
int(const gfx::PointF& point, int operation, int modifiers));
MOCK_METHOD0(MockOnDragDrop, void());
MOCK_METHOD0(OnDragLeave, void());
@@ -92,34 +90,52 @@ class MockDropHandler : public WmDropHandler {
on_drop_closure_ = closure;
}
+ void SetPreferredOperations(int preferred_operations) {
+ preferred_operations_ = preferred_operations;
+ }
+
OSExchangeData* dropped_data() { return dropped_data_.get(); }
+ int available_operations() const { return available_operations_; }
+
protected:
+ void OnDragEnter(const gfx::PointF& point,
+ std::unique_ptr<ui::OSExchangeData> data,
+ int operation,
+ int modifiers) override {
+ dropped_data_ = std::move(data);
+ MockOnDragEnter();
+ }
void OnDragDrop(std::unique_ptr<OSExchangeData> data,
int modifiers) override {
- dropped_data_ = std::move(data);
MockOnDragDrop();
on_drop_closure_.Run();
on_drop_closure_.Reset();
}
+ int OnDragMotion(const gfx::PointF& point,
+ int operation,
+ int modifiers) override {
+ available_operations_ = operation;
+ MockDragMotion(point, operation, modifiers);
+ return preferred_operations_;
+ }
+
private:
base::RepeatingClosure on_drop_closure_;
std::unique_ptr<OSExchangeData> dropped_data_;
+ int preferred_operations_ = ui::DragDropTypes::DRAG_COPY;
+ int available_operations_ = ui::DragDropTypes::DRAG_NONE;
};
-class WaylandDataDragControllerTest : public WaylandTest {
+class WaylandDataDragControllerTest : public WaylandDragDropTest {
public:
WaylandDataDragControllerTest() = default;
+ ~WaylandDataDragControllerTest() override = default;
void SetUp() override {
- WaylandTest::SetUp();
-
- Sync();
-
- data_device_manager_ = server_.data_device_manager();
- DCHECK(data_device_manager_);
+ WaylandDragDropTest::SetUp();
drag_handler_delegate_ = std::make_unique<MockDragHandlerDelegate>();
drop_handler_ = std::make_unique<MockDropHandler>();
@@ -134,63 +150,68 @@ class WaylandDataDragControllerTest : public WaylandTest {
return connection_->data_device_manager()->GetDevice();
}
+ MockDropHandler* drop_handler() { return drop_handler_.get(); }
+
+ MockDragHandlerDelegate* drag_handler() {
+ return drag_handler_delegate_.get();
+ }
+
+ wl::MockSurface* GetMockSurface(uint32_t id) {
+ return server_.GetObject<wl::MockSurface>(id);
+ }
+
+ WaylandConnection* connection() { return connection_.get(); }
+
+ WaylandWindow* window() { return window_.get(); }
+
base::string16 sample_text_for_dnd() const {
static auto text = base::ASCIIToUTF16(kSampleTextForDragAndDrop);
return text;
}
- void ReadDataWhenSourceIsReady() {
+ void RunDragLoopWithSampleData(WaylandWindow* origin_window, int operations) {
+ ASSERT_TRUE(origin_window);
+ OSExchangeData os_exchange_data;
+ os_exchange_data.SetString(sample_text_for_dnd());
+ origin_window->StartDrag(os_exchange_data, operations, /*cursor=*/{},
+ /*can_grab_pointer=*/true,
+ drag_handler_delegate_.get());
Sync();
+ }
- if (!data_device_manager_->data_source()) {
- // The data source is created asynchronously via the window's data drag
- // controller. If it is null now, it means that the task for that has not
- // yet executed, and we have to come later.
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(
- &WaylandDataDragControllerTest::ReadDataWhenSourceIsReady,
- base::Unretained(this)));
- return;
- }
-
- // Now the server can read the data and give it to our callback.
- base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
- auto callback = base::BindOnce(
- [](base::RunLoop* loop, std::vector<uint8_t>&& data) {
- std::string result(data.begin(), data.end());
- EXPECT_EQ(kSampleTextForDragAndDrop, result);
- loop->Quit();
- },
- &run_loop);
- data_device_manager_->data_source()->ReadData(kMimeTypeTextUtf8,
- std::move(callback));
- run_loop.Run();
-
- data_device_manager_->data_source()->OnCancelled();
+ std::unique_ptr<WaylandWindow> CreateTestWindow(
+ PlatformWindowType type,
+ const gfx::Size& size,
+ MockPlatformWindowDelegate* delegate) {
+ DCHECK(delegate);
+ PlatformWindowInitProperties properties{gfx::Rect(size)};
+ properties.type = type;
+ EXPECT_CALL(*delegate, OnAcceleratedWidgetAvailable(_)).Times(1);
+ auto window = WaylandWindow::Create(delegate, connection_.get(),
+ std::move(properties));
+ SetWmDropHandler(window.get(), drop_handler_.get());
+ EXPECT_NE(gfx::kNullAcceleratedWidget, window->GetWidget());
Sync();
+ return window;
}
void ScheduleDragCancel() {
- Sync();
+ ScheduleTestTask(base::BindOnce(
+ [](WaylandDataDragControllerTest* self) {
+ self->SendDndCancelled();
- if (!data_device_manager_->data_source()) {
- // The data source is created asynchronously by the data drag controller.
- // If it is null at this point, it means that the task for that has not
- // yet executed, and we have to try again a bit later.
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(&WaylandDataDragControllerTest::ScheduleDragCancel,
- base::Unretained(this)));
- return;
- }
+ // DnD handlers expect DragLeave to be sent before DragFinished when
+ // drag sessions end up with no data transfer (cancelled). Otherwise,
+ // it might lead to issues like https://crbug.com/1109324.
+ EXPECT_CALL(*self->drop_handler(), OnDragLeave).Times(1);
+ EXPECT_CALL(*self->drag_handler(), OnDragFinished).Times(1);
- data_device_manager_->data_source()->OnCancelled();
- Sync();
+ self->Sync();
+ },
+ base::Unretained(this)));
}
protected:
- wl::TestDataDeviceManager* data_device_manager_;
std::unique_ptr<MockDropHandler> drop_handler_;
std::unique_ptr<MockDragHandlerDelegate> drag_handler_delegate_;
};
@@ -199,22 +220,31 @@ TEST_P(WaylandDataDragControllerTest, StartDrag) {
const bool restored_focus = window_->has_pointer_focus();
window_->SetPointerFocus(true);
- // The client starts dragging.
- ASSERT_EQ(PlatformWindowType::kWindow, window_->type());
- OSExchangeData os_exchange_data;
- os_exchange_data.SetString(sample_text_for_dnd());
+ auto test = [](WaylandDataDragControllerTest* self) {
+ // Now the server can read the data and give it to our callback.
+ base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
+ auto read_callback = base::BindOnce(
+ [](base::RunLoop* loop, std::vector<uint8_t>&& data) {
+ std::string result(data.begin(), data.end());
+ EXPECT_EQ(kSampleTextForDragAndDrop, result);
+ loop->Quit();
+ },
+ &run_loop);
+ self->ReadData(kMimeTypeTextUtf8, std::move(read_callback));
+ run_loop.Run();
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(&WaylandDataDragControllerTest::ReadDataWhenSourceIsReady,
- base::Unretained(this)));
+ self->SendDndCancelled();
+ self->Sync();
+ };
- static_cast<WaylandToplevelWindow*>(window_.get())
- ->StartDrag(os_exchange_data,
- DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_MOVE, {}, true,
- drag_handler_delegate_.get());
- Sync();
+ // Post test task to be performed asynchronously once the dnd-related protocol
+ // objects are ready.
+ ScheduleTestTask(base::BindOnce(test, base::Unretained(this)));
+ RunDragLoopWithSampleData(
+ window_.get(), DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_MOVE);
+
+ // Ensure drag delegate it properly reset when the drag loop quits.
EXPECT_FALSE(data_device()->drag_delegate_);
window_->SetPointerFocus(restored_focus);
@@ -286,6 +316,8 @@ TEST_P(WaylandDataDragControllerTest, ReceiveDrag) {
1002, surface_->resource(), wl_fixed_from_int(entered_point.x()),
wl_fixed_from_int(entered_point.y()), data_offer);
+ Sync();
+
int64_t time =
(EventTimeForNow() - base::TimeTicks()).InMilliseconds() & UINT32_MAX;
gfx::Point motion_point(11, 11);
@@ -323,27 +355,27 @@ TEST_P(WaylandDataDragControllerTest, DropSeveralMimeTypes) {
kMimeTypeURIList,
ToClipboardData(std::string("file:///home/user/file\r\n")));
- EXPECT_CALL(*drop_handler_, OnDragEnter(_, _, _, _)).Times(1);
+ EXPECT_CALL(*drop_handler_, MockOnDragEnter()).Times(1);
gfx::Point entered_point(10, 10);
data_device_manager_->data_device()->OnEnter(
1002, surface_->resource(), wl_fixed_from_int(entered_point.x()),
wl_fixed_from_int(entered_point.y()), data_offer);
+ // Here we are expecting three data items, so there will be three roundtrips
+ // to the Wayland and back. Hence Sync() three times.
+ Sync();
+ Sync();
Sync();
- Mock::VerifyAndClearExpectations(drop_handler_.get());
EXPECT_CALL(*drop_handler_, MockOnDragDrop()).Times(1);
base::RunLoop loop;
drop_handler_->SetOnDropClosure(loop.QuitClosure());
data_device_manager_->data_device()->OnDrop();
- // Here we are expecting three data items, so there will be three roundtrips
- // to the Wayland and back. Hence Sync() three times.
- Sync();
- Sync();
Sync();
loop.Run();
Mock::VerifyAndClearExpectations(drop_handler_.get());
+ ASSERT_NE(drop_handler_->dropped_data(), nullptr);
EXPECT_TRUE(drop_handler_->dropped_data()->HasString());
EXPECT_TRUE(drop_handler_->dropped_data()->HasFile());
EXPECT_TRUE(drop_handler_->dropped_data()->HasURL(kFilenameToURLPolicy));
@@ -370,13 +402,12 @@ TEST_P(WaylandDataDragControllerTest, ValidateDroppedUriList) {
auto* data_offer = data_device_manager_->data_device()->OnDataOffer();
data_offer->OnOffer(kMimeTypeURIList, ToClipboardData(kCase.content));
- EXPECT_CALL(*drop_handler_, OnDragEnter(_, _, _, _)).Times(1);
+ EXPECT_CALL(*drop_handler_, MockOnDragEnter()).Times(1);
gfx::Point entered_point(10, 10);
data_device_manager_->data_device()->OnEnter(
1002, surface_->resource(), wl_fixed_from_int(entered_point.x()),
wl_fixed_from_int(entered_point.y()), data_offer);
Sync();
- Mock::VerifyAndClearExpectations(drop_handler_.get());
EXPECT_CALL(*drop_handler_, MockOnDragDrop()).Times(1);
base::RunLoop loop;
@@ -425,13 +456,12 @@ TEST_P(WaylandDataDragControllerTest, ValidateDroppedXMozUrl) {
data_offer->OnOffer(kMimeTypeMozillaURL,
ToClipboardData(base::UTF8ToUTF16(kCase.content)));
- EXPECT_CALL(*drop_handler_, OnDragEnter(_, _, _, _)).Times(1);
+ EXPECT_CALL(*drop_handler_, MockOnDragEnter()).Times(1);
gfx::Point entered_point(10, 10);
data_device_manager_->data_device()->OnEnter(
1002, surface_->resource(), wl_fixed_from_int(entered_point.x()),
wl_fixed_from_int(entered_point.y()), data_offer);
Sync();
- Mock::VerifyAndClearExpectations(drop_handler_.get());
EXPECT_CALL(*drop_handler_, MockOnDragDrop()).Times(1);
base::RunLoop loop;
@@ -468,27 +498,253 @@ TEST_P(WaylandDataDragControllerTest, StartAndCancel) {
const bool restored_focus = window_->has_pointer_focus();
window_->SetPointerFocus(true);
- ASSERT_EQ(PlatformWindowType::kWindow, window_->type());
+ // Schedule a wl_data_source::cancelled event to be sent asynchronously
+ // once the drag session gets started.
+ ScheduleDragCancel();
+
+ RunDragLoopWithSampleData(window_.get(), DragDropTypes::DRAG_COPY);
+
+ window_->SetPointerFocus(restored_focus);
+}
+
+TEST_P(WaylandDataDragControllerTest, ForeignDragHandleAskAction) {
+ auto* data_offer = data_device_manager_->data_device()->OnDataOffer();
+ data_offer->OnOffer(kMimeTypeText,
+ ToClipboardData(std::string(kSampleTextForDragAndDrop)));
+ data_offer->OnSourceActions(WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE |
+ WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY);
+ data_offer->OnAction(WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK);
+
+ gfx::Point entered_point(10, 10);
+ // The server sends an enter event.
+ data_device_manager_->data_device()->OnEnter(
+ 1002, surface_->resource(), wl_fixed_from_int(entered_point.x()),
+ wl_fixed_from_int(entered_point.y()), data_offer);
+ Sync();
+
+ int64_t time = 1;
+ gfx::Point motion_point(11, 11);
+
+ // Verify ask handling with drop handler preferring "copy" operation.
+ drop_handler_->SetPreferredOperations(ui::DragDropTypes::DRAG_COPY);
+ data_device_manager_->data_device()->OnMotion(
+ time, wl_fixed_from_int(motion_point.x()),
+ wl_fixed_from_int(motion_point.y()));
+ Sync();
+
+ EXPECT_EQ(WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY,
+ data_offer->preferred_action());
+ EXPECT_EQ(WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY,
+ data_offer->supported_actions());
+
+ data_device_manager_->data_device()->OnLeave();
+}
+
+// Verifies entered surface destruction is properly handled.
+// Regression test for https://crbug.com/1143707.
+TEST_P(WaylandDataDragControllerTest, DestroyEnteredSurface) {
+ auto* window_1 = window_.get();
+ const bool restored_focus = window_1->has_pointer_focus();
+ window_1->SetPointerFocus(true);
+ ASSERT_EQ(PlatformWindowType::kWindow, window_1->type());
+
+ auto test = [](WaylandDataDragControllerTest* self) {
+ // Init and open |target_window|.
+ MockPlatformWindowDelegate delegate_2;
+ auto window_2 = self->CreateTestWindow(PlatformWindowType::kWindow,
+ gfx::Size(80, 80), &delegate_2);
+
+ // Leave |window_1| and enter |window_2|.
+ self->SendDndLeave();
+ self->SendDndEnter(window_2.get(), gfx::Point(20, 20));
+ self->Sync();
+
+ // Destroy the entered window at client side and emulates a
+ // wl_data_device::leave to ensure no UAF happens.
+ window_2->PrepareForShutdown();
+ window_2.reset();
+ self->SendDndLeave();
+ self->Sync();
+
+ // Emulate server sending an wl_data_source::cancelled event so the drag
+ // loop is finished.
+ self->SendDndCancelled();
+ self->Sync();
+ };
+
+ // Post test task to be performed asynchronously once the drag session gets
+ // started.
+ ScheduleTestTask(base::BindOnce(test, base::Unretained(this)));
+
+ RunDragLoopWithSampleData(window_.get(), DragDropTypes::DRAG_COPY);
+
+ window_1->SetPointerFocus(restored_focus);
+}
+
+// Verifies that early origin surface destruction is properly handled.
+// Regression test for https://crbug.com/1143707.
+TEST_P(WaylandDataDragControllerTest, DestroyOriginSurface) {
+ auto* window_1 = window_.get();
+ const bool restored_focus = window_1->has_pointer_focus();
+ window_1->SetPointerFocus(false);
+ ASSERT_EQ(PlatformWindowType::kWindow, window_1->type());
+
+ auto test = [](WaylandDataDragControllerTest* self,
+ std::unique_ptr<WaylandWindow>* origin) {
+ // Leave origin surface and enter |window_|.
+ self->SendDndLeave();
+ self->SendDndEnter(self->window(), gfx::Point(20, 20));
+ self->Sync();
+
+ // Shutdown and destroy the popup window where the drag session was
+ // initiated, which leads to the drag loop to finish.
+ (*origin)->PrepareForShutdown();
+ origin->reset();
+ };
+
+ // Init and open |target_window|.
+ MockPlatformWindowDelegate delegate_2;
+ auto window_2 = CreateTestWindow(PlatformWindowType::kPopup,
+ gfx::Size(80, 80), &delegate_2);
+ window_2->SetPointerFocus(true);
+ Sync();
+
+ // Post test task to be performed asynchronously once the drag session gets
+ // started.
+ ScheduleTestTask(base::BindOnce(test, base::Unretained(this),
+ base::Unretained(&window_2)));
+
+ // Request to start the drag session, which spins a nested run loop.
OSExchangeData os_exchange_data;
os_exchange_data.SetString(sample_text_for_dnd());
+ window_2->StartDrag(os_exchange_data, DragDropTypes::DRAG_COPY, {}, true,
+ drag_handler_delegate_.get());
+ Sync();
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(&WaylandDataDragControllerTest::ScheduleDragCancel,
- base::Unretained(this)));
+ // Send wl_data_source::cancelled event. The drag controller is then
+ // expected to gracefully reset its internal state.
+ SendDndLeave();
+ SendDndCancelled();
+ Sync();
- // DnD handlers expect DragLeave to be sent before DragFinished when drag
- // sessions end up with no data transfer (cancelled). Otherwise, it might lead
- // to issues like https://crbug.com/1109324.
- EXPECT_CALL(*drop_handler_, OnDragLeave()).Times(1);
- EXPECT_CALL(*drag_handler_delegate_, OnDragFinished(_)).Times(1);
+ window_1->SetPointerFocus(restored_focus);
+}
- static_cast<WaylandToplevelWindow*>(window_.get())
- ->StartDrag(os_exchange_data, DragDropTypes::DRAG_COPY, {}, true,
- drag_handler_delegate_.get());
- Sync();
+// Ensures drag/drop events are properly propagated to non-toplevel windows.
+TEST_P(WaylandDataDragControllerTest, DragToNonToplevelWindows) {
+ auto* origin_window = window_.get();
+ const bool restored_focus = origin_window->has_pointer_focus();
+ origin_window->SetPointerFocus(true);
+
+ auto test = [](WaylandDataDragControllerTest* self,
+ PlatformWindowType window_type) {
+ // Init and open |target_window|.
+ MockPlatformWindowDelegate aux_window_delegate;
+ auto aux_window = self->CreateTestWindow(window_type, gfx::Size(100, 40),
+ &aux_window_delegate);
+
+ // Leave |origin_window| and enter non-toplevel |aux_window|.
+ self->SendDndLeave();
+ EXPECT_CALL(*self->drop_handler(), OnDragLeave).Times(1);
+ self->Sync();
+
+ self->SendDndEnter(aux_window.get(), {});
+ EXPECT_CALL(*self->drop_handler(), MockOnDragEnter()).Times(1);
+ EXPECT_CALL(*self->drop_handler(), MockDragMotion(_, _, _)).Times(1);
+ self->Sync();
+
+ // Goes back to |origin_window|, as |aux_window| is going to get destroyed
+ // once this test task finishes.
+ self->SendDndLeave();
+ EXPECT_CALL(*self->drop_handler(), OnDragLeave).Times(1);
+ self->Sync();
+
+ self->SendDndEnter(self->window(), {});
+ EXPECT_CALL(*self->drop_handler(), MockOnDragEnter()).Times(1);
+ EXPECT_CALL(*self->drop_handler(), MockDragMotion(_, _, _)).Times(1);
+ self->Sync();
+ };
+
+ // Post test tasks, for each non-toplevel window type, to be performed
+ // asynchronously once the dnd-related protocol objects are ready.
+ constexpr PlatformWindowType kNonToplevelWindowTypes[]{
+ PlatformWindowType::kPopup, PlatformWindowType::kMenu,
+ PlatformWindowType::kTooltip, PlatformWindowType::kBubble};
+ for (auto window_type : kNonToplevelWindowTypes)
+ ScheduleTestTask(base::BindOnce(test, base::Unretained(this), window_type));
+
+ // Post a wl_data_source::cancelled notifying the client to tear down the drag
+ // session.
+ ScheduleDragCancel();
+
+ // Request to start the drag session, which spins a nested run loop.
+ RunDragLoopWithSampleData(origin_window, DragDropTypes::DRAG_COPY);
+
+ origin_window->SetPointerFocus(restored_focus);
+}
- window_->SetPointerFocus(restored_focus);
+// Ensures that requests to create a |PlatformWindowType::kPopup| during drag
+// sessions return wl_subsurface-backed windows.
+TEST_P(WaylandDataDragControllerTest, PopupRequestCreatesAuxiliaryWindow) {
+ auto* origin_window = window_.get();
+ const bool restored_focus = origin_window->has_pointer_focus();
+ origin_window->SetPointerFocus(true);
+
+ auto test = [](WaylandDataDragControllerTest* self) {
+ MockPlatformWindowDelegate delegate;
+ auto popup_window = self->CreateTestWindow(PlatformWindowType::kPopup,
+ gfx::Size(100, 40), &delegate);
+ popup_window->Show(false);
+ self->Sync();
+
+ auto* surface =
+ self->GetMockSurface(popup_window->root_surface()->GetSurfaceId());
+ ASSERT_TRUE(surface);
+ EXPECT_NE(nullptr, surface->sub_surface());
+ };
+
+ ScheduleTestTask(base::BindOnce(test, base::Unretained(this)));
+
+ // Post a wl_data_source::cancelled notifying the client to tear down the drag
+ // session.
+ ScheduleDragCancel();
+
+ // Request to start the drag session, which spins a nested run loop.
+ RunDragLoopWithSampleData(origin_window, DragDropTypes::DRAG_COPY);
+
+ origin_window->SetPointerFocus(restored_focus);
+}
+
+// Ensures that requests to create a |PlatformWindowType::kMenu| during drag
+// sessions return xdg_popup-backed windows.
+TEST_P(WaylandDataDragControllerTest, MenuRequestCreatesPopupWindow) {
+ auto* origin_window = window_.get();
+ const bool restored_focus = origin_window->has_pointer_focus();
+ origin_window->SetPointerFocus(true);
+
+ auto test = [](WaylandDataDragControllerTest* self) {
+ MockPlatformWindowDelegate delegate;
+ auto menu_window = self->CreateTestWindow(PlatformWindowType::kMenu,
+ gfx::Size(100, 40), &delegate);
+ menu_window->Show(false);
+ self->Sync();
+
+ auto* surface =
+ self->GetMockSurface(menu_window->root_surface()->GetSurfaceId());
+ ASSERT_TRUE(surface);
+ EXPECT_EQ(nullptr, surface->sub_surface());
+ };
+
+ ScheduleTestTask(base::BindOnce(test, base::Unretained(this)));
+
+ // Post a wl_data_source::cancelled notifying the client to tear down the drag
+ // session.
+ ScheduleDragCancel();
+
+ // Request to start the drag session, which spins a nested run loop.
+ RunDragLoopWithSampleData(origin_window, DragDropTypes::DRAG_COPY);
+
+ origin_window->SetPointerFocus(restored_focus);
}
INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_offer.cc b/chromium/ui/ozone/platform/wayland/host/wayland_data_offer.cc
index 84d29d32b60..7e2a7143fd7 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_offer.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_offer.cc
@@ -24,14 +24,6 @@ WaylandDataOffer::~WaylandDataOffer() {
data_offer_.reset();
}
-void WaylandDataOffer::SetAction(uint32_t dnd_actions,
- uint32_t preferred_action) {
- if (wl::get_version_of_object(data_offer_.get()) >=
- WL_DATA_OFFER_SET_ACTIONS_SINCE_VERSION) {
- wl_data_offer_set_actions(data_offer_.get(), dnd_actions, preferred_action);
- }
-}
-
void WaylandDataOffer::Accept(uint32_t serial, const std::string& mime_type) {
wl_data_offer_accept(data_offer_.get(), serial, mime_type.c_str());
}
@@ -68,12 +60,21 @@ void WaylandDataOffer::FinishOffer() {
}
}
-uint32_t WaylandDataOffer::source_actions() const {
- return source_actions_;
-}
+void WaylandDataOffer::SetActions(uint32_t dnd_actions) {
+ if (wl::get_version_of_object(data_offer_.get()) <
+ WL_DATA_OFFER_SET_ACTIONS_SINCE_VERSION) {
+ return;
+ }
+
+ // Determine preferred action based on the given |dnd_actions|, prioritizing
+ // "copy" over "move", if both are set.
+ uint32_t preferred_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
+ if (dnd_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY)
+ preferred_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
+ else if (dnd_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE)
+ preferred_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
-uint32_t WaylandDataOffer::dnd_action() const {
- return dnd_action_;
+ wl_data_offer_set_actions(data_offer_.get(), dnd_actions, preferred_action);
}
// static
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_offer.h b/chromium/ui/ozone/platform/wayland/host/wayland_data_offer.h
index a724709c9c1..467e4c48d4c 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_offer.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_offer.h
@@ -27,16 +27,16 @@ class WaylandDataOffer : public WaylandDataOfferBase {
explicit WaylandDataOffer(wl_data_offer* data_offer);
~WaylandDataOffer() override;
- void SetAction(uint32_t dnd_actions, uint32_t preferred_action);
void Accept(uint32_t serial, const std::string& mime_type);
void Reject(uint32_t serial);
+ void FinishOffer();
// WaylandDataOfferBase overrides:
base::ScopedFD Receive(const std::string& mime_type) override;
- void FinishOffer();
- uint32_t source_actions() const;
- uint32_t dnd_action() const;
+ uint32_t source_actions() const { return source_actions_; }
+ uint32_t dnd_action() const { return dnd_action_; }
+ void SetActions(uint32_t dnd_actions);
private:
// wl_data_offer_listener callbacks.
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_offer_base.cc b/chromium/ui/ozone/platform/wayland/host/wayland_data_offer_base.cc
index cbdd82a25d0..bf4393a9a17 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_data_offer_base.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_offer_base.cc
@@ -4,7 +4,7 @@
#include "ui/ozone/platform/wayland/host/wayland_data_offer_base.h"
-#include "base/stl_util.h"
+#include "base/containers/contains.h"
#include "ui/base/clipboard/clipboard_constants.h"
namespace ui {
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_event_source.cc b/chromium/ui/ozone/platform/wayland/host/wayland_event_source.cc
index 15eb6b6e2c2..28f5892a0e9 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_event_source.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_event_source.cc
@@ -17,6 +17,8 @@
#include "ui/events/keycodes/dom/dom_key.h"
#include "ui/events/keycodes/keyboard_code_conversion.h"
#include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/events/ozone/layout/keyboard_layout_engine.h"
+#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
#include "ui/events/pointer_details.h"
#include "ui/events/types/event_type.h"
#include "ui/gfx/geometry/point_f.h"
@@ -85,17 +87,6 @@ bool WaylandEventSource::StopProcessingEvents() {
return event_watcher_->StopProcessingEvents();
}
-void WaylandEventSource::OnKeyboardCreated(WaylandKeyboard* keyboard) {
- DCHECK(keyboard);
- keyboard_ = keyboard;
-}
-
-void WaylandEventSource::OnKeyboardDestroyed(WaylandKeyboard* keyboard) {
- DCHECK_EQ(keyboard_, keyboard);
- keyboard_modifiers_ = 0;
- keyboard_ = nullptr;
-}
-
void WaylandEventSource::OnKeyboardFocusChanged(WaylandWindow* window,
bool focused) {
DCHECK(window);
@@ -109,14 +100,15 @@ void WaylandEventSource::OnKeyboardModifiersChanged(int modifiers) {
uint32_t WaylandEventSource::OnKeyboardKeyEvent(EventType type,
DomCode dom_code,
bool repeat,
- base::TimeTicks timestamp) {
+ base::TimeTicks timestamp,
+ int device_id) {
DCHECK(type == ET_KEY_PRESSED || type == ET_KEY_RELEASED);
- if (!keyboard_)
- return POST_DISPATCH_NONE;
DomKey dom_key;
KeyboardCode key_code;
- if (!keyboard_->Decode(dom_code, keyboard_modifiers_, &dom_key, &key_code)) {
+ auto* layout_engine = KeyboardLayoutEngineManager::GetKeyboardLayoutEngine();
+ if (!layout_engine || !layout_engine->Lookup(dom_code, keyboard_modifiers_,
+ &dom_key, &key_code)) {
LOG(ERROR) << "Failed to decode key event.";
return POST_DISPATCH_NONE;
}
@@ -128,30 +120,12 @@ uint32_t WaylandEventSource::OnKeyboardKeyEvent(EventType type,
KeyEvent event(type, key_code, dom_code, keyboard_modifiers_, dom_key,
timestamp);
- event.set_source_device_id(keyboard_->device_id());
+ event.set_source_device_id(device_id);
return DispatchEvent(&event);
}
-void WaylandEventSource::OnPointerCreated(WaylandPointer* pointer) {
- DCHECK(pointer);
- pointer_ = pointer;
-}
-
-void WaylandEventSource::OnPointerDestroyed(WaylandPointer* pointer) {
- DCHECK_EQ(pointer_, pointer);
-
- // Clear focused window, if any.
- HandlePointerFocusChange(nullptr);
-
- ResetPointerFlags();
- pointer_ = nullptr;
-}
-
void WaylandEventSource::OnPointerFocusChanged(WaylandWindow* window,
const gfx::PointF& location) {
- if (!pointer_)
- return;
-
// Save new pointer location.
pointer_location_ = location;
@@ -174,9 +148,6 @@ void WaylandEventSource::OnPointerButtonEvent(EventType type,
DCHECK(type == ET_MOUSE_PRESSED || type == ET_MOUSE_RELEASED);
DCHECK(HasAnyPointerButtonFlag(changed_button));
- if (!pointer_)
- return;
-
auto* prev_focused_window = window_with_pointer_focus_;
if (window)
HandlePointerFocusChange(window);
@@ -212,6 +183,10 @@ void WaylandEventSource::OnPointerAxisEvent(const gfx::Vector2d& offset) {
current_pointer_frame_.dy += offset.y();
}
+void WaylandEventSource::OnResetPointerFlags() {
+ ResetPointerFlags();
+}
+
void WaylandEventSource::OnPointerFrameEvent() {
base::TimeTicks now = EventTimeForNow();
current_pointer_frame_.dt = now - last_pointer_frame_time_;
@@ -255,17 +230,6 @@ void WaylandEventSource::OnPointerAxisStopEvent(uint32_t axis) {
current_pointer_frame_.is_axis_stop = true;
}
-void WaylandEventSource::OnTouchCreated(WaylandTouch* touch) {
- DCHECK(touch);
- touch_ = touch;
-}
-
-void WaylandEventSource::OnTouchDestroyed(WaylandTouch* touch) {
- DCHECK_EQ(touch_, touch);
- touch_points_.clear();
- touch_ = nullptr;
-}
-
void WaylandEventSource::OnTouchPressEvent(WaylandWindow* window,
const gfx::PointF& location,
base::TimeTicks timestamp,
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_event_source.h b/chromium/ui/ozone/platform/wayland/host/wayland_event_source.h
index dfda62810e5..ed0a6f85250 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_event_source.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_event_source.h
@@ -81,18 +81,15 @@ class WaylandEventSource : public PlatformEventSource,
protected:
// WaylandKeyboard::Delegate
- void OnKeyboardCreated(WaylandKeyboard* keyboard) override;
- void OnKeyboardDestroyed(WaylandKeyboard* keyboard) override;
void OnKeyboardFocusChanged(WaylandWindow* window, bool focused) override;
void OnKeyboardModifiersChanged(int modifiers) override;
uint32_t OnKeyboardKeyEvent(EventType type,
DomCode dom_code,
bool repeat,
- base::TimeTicks timestamp) override;
+ base::TimeTicks timestamp,
+ int device_id) override;
// WaylandPointer::Delegate
- void OnPointerCreated(WaylandPointer* pointer) override;
- void OnPointerDestroyed(WaylandPointer* pointer) override;
void OnPointerFocusChanged(WaylandWindow* window,
const gfx::PointF& location) override;
void OnPointerButtonEvent(EventType evtype,
@@ -103,10 +100,9 @@ class WaylandEventSource : public PlatformEventSource,
void OnPointerFrameEvent() override;
void OnPointerAxisSourceEvent(uint32_t axis_source) override;
void OnPointerAxisStopEvent(uint32_t axis) override;
+ void OnResetPointerFlags() override;
// WaylandTouch::Delegate
- void OnTouchCreated(WaylandTouch* touch) override;
- void OnTouchDestroyed(WaylandTouch* touch) override;
void OnTouchPressEvent(WaylandWindow* window,
const gfx::PointF& location,
base::TimeTicks timestamp,
@@ -146,11 +142,6 @@ class WaylandEventSource : public PlatformEventSource,
WaylandWindowManager* const window_manager_;
- // Input device objects. Owned by WaylandConnection.
- WaylandKeyboard* keyboard_ = nullptr;
- WaylandPointer* pointer_ = nullptr;
- WaylandTouch* touch_ = nullptr;
-
// Bitmask of EventFlags used to keep track of the the pointer state.
int pointer_flags_ = 0;
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_event_watcher.cc b/chromium/ui/ozone/platform/wayland/host/wayland_event_watcher.cc
index 9fd65bd9afa..c97a0e31bd3 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_event_watcher.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_event_watcher.cc
@@ -4,8 +4,11 @@
#include "ui/ozone/platform/wayland/host/wayland_event_watcher.h"
+#include <cstring>
+
#include "base/bind.h"
#include "base/check.h"
+#include "base/logging.h"
#include "base/task/current_thread.h"
#include "ui/events/event.h"
#include "ui/ozone/platform/wayland/common/wayland.h"
@@ -55,6 +58,8 @@ void WaylandEventWatcher::OnFileCanReadWithoutBlocking(int fd) {
if (prepared_) {
prepared_ = false;
+ // Errors will be checked the next time OnFileCanReadWithoutBlocking calls
+ // CheckForErrors.
if (wl_display_read_events(display_) == -1)
return;
wl_display_dispatch_pending(display_);
@@ -114,13 +119,38 @@ void WaylandEventWatcher::MaybePrepareReadQueue() {
}
bool WaylandEventWatcher::CheckForErrors() {
+ // Errors are fatal. If this function returns non-zero the display can no
+ // longer be used.
int err = wl_display_get_error(display_);
- if (err == EPROTO) {
+
+ // TODO(crbug.com/1172305): Wayland display_error message should be printed
+ // automatically by wl_log(). However, wl_log() does not print anything. Needs
+ // investigation.
+ if (err) {
+ // When |err| is EPROTO, we can still use the |display_| to retrieve the
+ // protocol error. Otherwise, get the error string from strerror and
+ // shutdown the browser.
+ if (err == EPROTO) {
+ uint32_t ec, id;
+ const struct wl_interface* intf;
+ ec = wl_display_get_protocol_error(display_, &intf, &id);
+ if (intf) {
+ LOG(ERROR) << "Fatal Wayland protocol error " << ec << " on interface "
+ << intf->name << " (object " << id << "). Shutting down..";
+ } else {
+ LOG(ERROR) << "Fatal Wayland protocol error " << ec
+ << ". Shutting down..";
+ }
+ } else {
+ LOG(ERROR) << "Fatal Wayland communication error: " << std::strerror(err);
+ }
+
// This can be null in tests.
if (!shutdown_cb_.is_null())
std::move(shutdown_cb_).Run();
return false;
}
+
return true;
}
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_input_method_context.cc b/chromium/ui/ozone/platform/wayland/host/wayland_input_method_context.cc
index a7bd5baba4f..b7e3c6b3238 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_input_method_context.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_input_method_context.cc
@@ -12,6 +12,7 @@
#include "base/optional.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "build/chromeos_buildflags.h"
#include "ui/base/ime/composition_text.h"
#include "ui/base/ime/ime_text_span.h"
#include "ui/events/base_event_utils.h"
@@ -24,9 +25,16 @@
#include "ui/ozone/public/ozone_switches.h"
#if BUILDFLAG(USE_XKBCOMMON)
+#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
#include "ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.h"
#endif
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+#include "base/check.h"
+#include "chromeos/crosapi/mojom/crosapi.mojom.h"
+#include "chromeos/lacros/lacros_chrome_service_impl.h"
+#endif
+
namespace ui {
namespace {
@@ -42,6 +50,41 @@ base::Optional<size_t> OffsetFromUTF8Offset(const base::StringPiece& text,
return converted.size();
}
+bool IsImeEnabled() {
+ base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
+ // We do not expect both switches are set at the same time.
+ DCHECK(!cmd_line->HasSwitch(switches::kEnableWaylandIme) ||
+ !cmd_line->HasSwitch(switches::kDisableWaylandIme));
+ // Force enable/disable wayland IMEs, when explictly specified via commandline
+ // arguments.
+ if (cmd_line->HasSwitch(switches::kEnableWaylandIme))
+ return true;
+ if (cmd_line->HasSwitch(switches::kDisableWaylandIme))
+ return false;
+
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+ // On Lacros chrome, we check whether ash-chrome supports IME, then
+ // enable IME if so. This allows us to control IME enabling state in
+ // Lacros-chrome side, which helps us on releasing.
+ // TODO(crbug.com/1159237): In the future, we may want to unify the behavior
+ // of ozone/wayland across platforms.
+ const auto* lacros_chrome_service = chromeos::LacrosChromeServiceImpl::Get();
+
+ // Note: |init_params| may be null, if ash-chrome is too old.
+ // TODO(crbug.com/1156033): Clean up the condition, after ash-chrome in the
+ // world becomes new enough.
+ const crosapi::mojom::BrowserInitParams* init_params =
+ lacros_chrome_service->init_params();
+ if (init_params && init_params->exo_ime_support !=
+ crosapi::mojom::ExoImeSupport::kUnsupported) {
+ return true;
+ }
+#endif
+
+ // Do not enable wayland IME by default.
+ return false;
+}
+
} // namespace
WaylandInputMethodContext::WaylandInputMethodContext(
@@ -65,10 +108,8 @@ WaylandInputMethodContext::~WaylandInputMethodContext() {
}
void WaylandInputMethodContext::Init(bool initialize_for_testing) {
- bool use_ozone_wayland_vkb =
- initialize_for_testing ||
- base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableWaylandIme);
+ bool use_ozone_wayland_vkb = initialize_for_testing || IsImeEnabled();
+
// If text input instance is not created then all ime context operations
// are noop. This option is because in some environments someone might not
// want to enable ime/virtual keyboard even if it's available.
@@ -215,16 +256,24 @@ void WaylandInputMethodContext::OnKeysym(uint32_t keysym,
uint32_t state,
uint32_t modifiers) {
#if BUILDFLAG(USE_XKBCOMMON)
+ auto* layout_engine = KeyboardLayoutEngineManager::GetKeyboardLayoutEngine();
+ if (!layout_engine)
+ return;
+
// TODO(crbug.com/1079353): Handle modifiers.
- DomCode dom_code =
- connection_->keyboard()->layout_engine()->GetDomCodeByKeysym(keysym);
+ DomCode dom_code = static_cast<XkbKeyboardLayoutEngine*>(layout_engine)
+ ->GetDomCodeByKeysym(keysym);
if (dom_code == DomCode::NONE)
return;
+ // Keyboard might not exist.
+ int device_id =
+ connection_->keyboard() ? connection_->keyboard()->device_id() : 0;
+
EventType type =
state == WL_KEYBOARD_KEY_STATE_PRESSED ? ET_KEY_PRESSED : ET_KEY_RELEASED;
key_delegate_->OnKeyboardKeyEvent(type, dom_code, /*repeat=*/false,
- EventTimeForNow());
+ EventTimeForNow(), device_id);
#else
NOTIMPLEMENTED();
#endif
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.cc b/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.cc
index 7b1e06e7ad5..812bdfcaf5a 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.cc
@@ -51,9 +51,6 @@ WaylandKeyboard::WaylandKeyboard(
&WaylandKeyboard::Modifiers, &WaylandKeyboard::RepeatInfo,
};
- DCHECK(delegate_);
- delegate_->OnKeyboardCreated(this);
-
wl_keyboard_add_listener(obj_.get(), &listener, this);
// TODO(tonikitoo): Default auto-repeat to ON here?
@@ -63,7 +60,8 @@ WaylandKeyboard::WaylandKeyboard(
}
WaylandKeyboard::~WaylandKeyboard() {
- delegate_->OnKeyboardDestroyed(this);
+ // Reset keyboard modifiers on destruction.
+ delegate_->OnKeyboardModifiersChanged(0);
}
void WaylandKeyboard::Keymap(void* data,
@@ -194,8 +192,9 @@ void WaylandKeyboard::DispatchKey(uint32_t key,
// Pass empty DomKey and KeyboardCode here so the delegate can pre-process
// and decode it when needed.
- uint32_t result = delegate_->OnKeyboardKeyEvent(
- down ? ET_KEY_PRESSED : ET_KEY_RELEASED, dom_code, repeat, timestamp);
+ uint32_t result =
+ delegate_->OnKeyboardKeyEvent(down ? ET_KEY_PRESSED : ET_KEY_RELEASED,
+ dom_code, repeat, timestamp, device_id);
if (extended_keyboard_v1_) {
bool handled = result & POST_DISPATCH_STOP_PROPAGATION;
@@ -204,15 +203,6 @@ void WaylandKeyboard::DispatchKey(uint32_t key,
}
}
-bool WaylandKeyboard::Decode(DomCode dom_code,
- int modifiers,
- DomKey* out_dom_key,
- KeyboardCode* out_key_code) {
- DCHECK(out_dom_key);
- DCHECK(out_key_code);
- return layout_engine_->Lookup(dom_code, modifiers, out_dom_key, out_key_code);
-}
-
void WaylandKeyboard::SyncCallback(void* data,
struct wl_callback* cb,
uint32_t time) {
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.h b/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.h
index d655dc09cc3..d6f0b0bb025 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.h
@@ -17,7 +17,6 @@
namespace ui {
-class DomKey;
class KeyboardLayoutEngine;
class WaylandConnection;
class WaylandWindow;
@@ -29,14 +28,6 @@ class WaylandKeyboard : public EventAutoRepeatHandler::Delegate {
public:
class Delegate;
- using LayoutEngine =
-#if BUILDFLAG(USE_XKBCOMMON)
- XkbKeyboardLayoutEngine
-#else
- KeyboardLayoutEngine
-#endif
- ;
-
WaylandKeyboard(wl_keyboard* keyboard,
zcr_keyboard_extension_v1* keyboard_extension_v1,
WaylandConnection* connection,
@@ -45,13 +36,16 @@ class WaylandKeyboard : public EventAutoRepeatHandler::Delegate {
virtual ~WaylandKeyboard();
int device_id() const { return obj_.id(); }
- bool Decode(DomCode dom_code,
- int modifiers,
- DomKey* out_dom_key,
- KeyboardCode* out_key_code);
- LayoutEngine* layout_engine() const { return layout_engine_; }
private:
+ using LayoutEngine =
+#if BUILDFLAG(USE_XKBCOMMON)
+ XkbKeyboardLayoutEngine
+#else
+ KeyboardLayoutEngine
+#endif
+ ;
+
// wl_keyboard_listener
static void Keymap(void* data,
wl_keyboard* obj,
@@ -113,8 +107,6 @@ class WaylandKeyboard : public EventAutoRepeatHandler::Delegate {
class WaylandKeyboard::Delegate {
public:
- virtual void OnKeyboardCreated(WaylandKeyboard* keyboard) = 0;
- virtual void OnKeyboardDestroyed(WaylandKeyboard* keyboard) = 0;
virtual void OnKeyboardFocusChanged(WaylandWindow* window, bool focused) = 0;
virtual void OnKeyboardModifiersChanged(int modifiers) = 0;
// Returns a mask of ui::PostDispatchAction indicating how the event was
@@ -122,7 +114,8 @@ class WaylandKeyboard::Delegate {
virtual uint32_t OnKeyboardKeyEvent(EventType type,
DomCode dom_code,
bool repeat,
- base::TimeTicks timestamp) = 0;
+ base::TimeTicks timestamp,
+ int device_id) = 0;
protected:
// Prevent deletion through a WaylandKeyboard::Delegate pointer.
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_pointer.cc b/chromium/ui/ozone/platform/wayland/host/wayland_pointer.cc
index b4fb4f09c5c..50d55f66b5c 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_pointer.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_pointer.cc
@@ -27,14 +27,15 @@ WaylandPointer::WaylandPointer(wl_pointer* pointer,
&WaylandPointer::AxisSource, &WaylandPointer::AxisStop,
&WaylandPointer::AxisDiscrete};
- DCHECK(delegate_);
- delegate_->OnPointerCreated(this);
-
wl_pointer_add_listener(obj_.get(), &listener, this);
}
WaylandPointer::~WaylandPointer() {
- delegate_->OnPointerDestroyed(this);
+ // Even though, WaylandPointer::Leave is always called when Wayland destroys
+ // wl_pointer, it's better to be explicit as some Wayland compositors may have
+ // bugs.
+ delegate_->OnPointerFocusChanged(nullptr, {});
+ delegate_->OnResetPointerFlags();
}
// static
@@ -130,7 +131,7 @@ void WaylandPointer::Axis(void* data,
offset.set_y(-wl_fixed_to_double(value) / kAxisValueScale *
MouseWheelEvent::kWheelDelta);
} else if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) {
- offset.set_x(wl_fixed_to_double(value) / kAxisValueScale *
+ offset.set_x(-wl_fixed_to_double(value) / kAxisValueScale *
MouseWheelEvent::kWheelDelta);
} else {
return;
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_pointer.h b/chromium/ui/ozone/platform/wayland/host/wayland_pointer.h
index 2ebb8419769..f9ad83b385a 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_pointer.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_pointer.h
@@ -80,8 +80,6 @@ class WaylandPointer {
class WaylandPointer::Delegate {
public:
- virtual void OnPointerCreated(WaylandPointer* pointer) = 0;
- virtual void OnPointerDestroyed(WaylandPointer* pointer) = 0;
virtual void OnPointerFocusChanged(WaylandWindow* window,
const gfx::PointF& location) = 0;
virtual void OnPointerButtonEvent(EventType evtype,
@@ -92,6 +90,7 @@ class WaylandPointer::Delegate {
virtual void OnPointerFrameEvent() = 0;
virtual void OnPointerAxisSourceEvent(uint32_t axis_source) = 0;
virtual void OnPointerAxisStopEvent(uint32_t axis) = 0;
+ virtual void OnResetPointerFlags() = 0;
};
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc
index 91e9b9707c6..94d56df903a 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc
@@ -234,7 +234,7 @@ TEST_P(WaylandPointerTest, AxisHorizontal) {
ASSERT_TRUE(event);
ASSERT_TRUE(event->IsMouseWheelEvent());
auto* mouse_wheel_event = event->AsMouseWheelEvent();
- EXPECT_EQ(gfx::Vector2d(MouseWheelEvent::kWheelDelta, 0),
+ EXPECT_EQ(gfx::Vector2d(-MouseWheelEvent::kWheelDelta, 0),
mouse_wheel_event->offset());
EXPECT_EQ(EF_LEFT_MOUSE_BUTTON, mouse_wheel_event->button_flags());
EXPECT_EQ(0, mouse_wheel_event->changed_button_flags());
@@ -340,11 +340,11 @@ TEST_P(WaylandPointerTest, FlingVertical) {
EXPECT_EQ(ET_SCROLL_FLING_START, scroll_event->type());
EXPECT_EQ(gfx::PointF(50, 75), scroll_event->location_f());
EXPECT_EQ(0.0f, scroll_event->x_offset());
+ EXPECT_EQ(0.0f, scroll_event->x_offset_ordinal());
// Initial vertical velocity depends on the implementation outside of
// WaylandPointer, but it should be negative value based on the direction of
// recent two axis events.
EXPECT_GT(0.0f, scroll_event->y_offset());
- EXPECT_EQ(0.0f, scroll_event->x_offset_ordinal());
EXPECT_GT(0.0f, scroll_event->y_offset_ordinal());
}
@@ -393,13 +393,13 @@ TEST_P(WaylandPointerTest, FlingHorizontal) {
auto* scroll_event = event3->AsScrollEvent();
EXPECT_EQ(ET_SCROLL_FLING_START, scroll_event->type());
EXPECT_EQ(gfx::PointF(50, 75), scroll_event->location_f());
- // Initial horizontal velocity depends on the implementation outside of
- // WaylandPointer, but it should be positive value based on the direction of
- // recent two axis events.
- EXPECT_LT(0.0f, scroll_event->x_offset());
EXPECT_EQ(0.0f, scroll_event->y_offset());
- EXPECT_LT(0.0f, scroll_event->x_offset_ordinal());
EXPECT_EQ(0.0f, scroll_event->y_offset_ordinal());
+ // Initial horizontal velocity depends on the implementation outside of
+ // WaylandPointer, but it should be negative value based on the direction of
+ // recent two axis events.
+ EXPECT_GT(0.0f, scroll_event->x_offset());
+ EXPECT_GT(0.0f, scroll_event->x_offset_ordinal());
}
TEST_P(WaylandPointerTest, FlingCancel) {
@@ -518,10 +518,10 @@ TEST_P(WaylandPointerTest, FlingDiagonal) {
auto* scroll_event = event5->AsScrollEvent();
EXPECT_EQ(ET_SCROLL_FLING_START, scroll_event->type());
EXPECT_EQ(gfx::PointF(50, 75), scroll_event->location_f());
- // Check the offset direction. It should non-zero in both directions.
- EXPECT_LT(0.0f, scroll_event->x_offset());
+ // Check the offset direction. It should non-zero in both axes.
+ EXPECT_GT(0.0f, scroll_event->x_offset());
EXPECT_GT(0.0f, scroll_event->y_offset());
- EXPECT_LT(0.0f, scroll_event->x_offset_ordinal());
+ EXPECT_GT(0.0f, scroll_event->x_offset_ordinal());
EXPECT_GT(0.0f, scroll_event->y_offset_ordinal());
// Horizontal offset should be larger than vertical one, given the scroll
// offset in each direction.
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_popup.cc b/chromium/ui/ozone/platform/wayland/host/wayland_popup.cc
index 62601c3dde5..736b2388374 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_popup.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_popup.cc
@@ -4,11 +4,14 @@
#include "ui/ozone/platform/wayland/host/wayland_popup.h"
+#include <aura-shell-client-protocol.h>
+
#include "ui/ozone/platform/wayland/common/wayland_util.h"
#include "ui/ozone/platform/wayland/host/shell_object_factory.h"
#include "ui/ozone/platform/wayland/host/shell_popup_wrapper.h"
#include "ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_zaura_shell.h"
namespace ui {
@@ -33,9 +36,22 @@ bool WaylandPopup::CreateShellPopup() {
}
parent_window()->set_child_window(this);
+ InitializeAuraShellSurface();
return true;
}
+void WaylandPopup::InitializeAuraShellSurface() {
+ DCHECK(shell_popup_);
+ if (!connection()->zaura_shell() || aura_surface_)
+ return;
+ aura_surface_.reset(zaura_shell_get_aura_surface(
+ connection()->zaura_shell()->wl_object(), root_surface()->surface()));
+ if (shadow_type_ == PlatformWindowShadowType::kDrop) {
+ zaura_surface_set_frame(aura_surface_.get(),
+ ZAURA_SURFACE_FRAME_TYPE_SHADOW);
+ }
+}
+
void WaylandPopup::Show(bool inactive) {
if (shell_popup_)
return;
@@ -121,6 +137,10 @@ void WaylandPopup::HandlePopupConfigure(const gfx::Rect& bounds_dip) {
SetBoundsDip(new_bounds_dip);
}
+void WaylandPopup::HandleSurfaceConfigure(uint32_t serial) {
+ shell_popup()->AckConfigure(serial);
+}
+
void WaylandPopup::OnCloseRequest() {
// Before calling OnCloseRequest, the |shell_popup_| must become hidden and
// only then call OnCloseRequest().
@@ -133,6 +153,7 @@ bool WaylandPopup::OnInitialize(PlatformWindowInitProperties properties) {
DCHECK(parent_window());
root_surface()->SetBufferScale(parent_window()->buffer_scale(), false);
set_ui_scale(parent_window()->ui_scale());
+ shadow_type_ = properties.shadow_type;
return true;
}
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_popup.h b/chromium/ui/ozone/platform/wayland/host/wayland_popup.h
index a5810317d86..38af4fa80b4 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_popup.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_popup.h
@@ -27,12 +27,17 @@ class WaylandPopup : public WaylandWindow {
private:
// WaylandWindow overrides:
void HandlePopupConfigure(const gfx::Rect& bounds) override;
+ void HandleSurfaceConfigure(uint32_t serial) override;
void OnCloseRequest() override;
bool OnInitialize(PlatformWindowInitProperties properties) override;
// Creates a popup window, which is visible as a menu window.
bool CreateShellPopup();
+ // Initializes the aura-shell surface, in the case aura-shell EXO extension
+ // is available.
+ void InitializeAuraShellSurface();
+
// Returns bounds with origin relative to parent window's origin.
gfx::Rect AdjustPopupWindowPosition();
@@ -40,6 +45,10 @@ class WaylandPopup : public WaylandWindow {
// know anything about the version.
std::unique_ptr<ShellPopupWrapper> shell_popup_;
+ wl::Object<zaura_surface> aura_surface_;
+
+ PlatformWindowShadowType shadow_type_ = PlatformWindowShadowType::kNone;
+
DISALLOW_COPY_AND_ASSIGN(WaylandPopup);
};
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_screen.cc b/chromium/ui/ozone/platform/wayland/host/wayland_screen.cc
index 07e4c2864ec..42c13a25090 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_screen.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_screen.cc
@@ -7,7 +7,7 @@
#include <set>
#include <vector>
-#include "base/stl_util.h"
+#include "base/containers/contains.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "ui/display/display.h"
@@ -40,7 +40,7 @@ WaylandScreen::WaylandScreen(WaylandConnection* connection)
auto format = buffer_format.first;
// TODO(crbug.com/1127822): Investigate a better fix for this.
-#if !BUILDFLAG(IS_LACROS)
+#if !BUILDFLAG(IS_CHROMEOS_LACROS)
// RGBA_8888 is the preferred format, except when running on ChromiumOS. See
// crbug.com/1127558.
if (format == gfx::BufferFormat::RGBA_8888)
@@ -50,7 +50,7 @@ WaylandScreen::WaylandScreen(WaylandConnection* connection)
// available, but for some reason Chromium gets broken when it's used.
// Though, we can import RGBX_8888 dma buffer to EGLImage successfully.
// Enable that back when the issue is resolved.
-#endif // !BUILDFLAG(IS_LACROS)
+#endif // !BUILDFLAG(IS_CHROMEOS_LACROS)
if (!image_format_alpha_ && format == gfx::BufferFormat::BGRA_8888)
image_format_alpha_ = gfx::BufferFormat::BGRA_8888;
@@ -99,10 +99,12 @@ void WaylandScreen::AddOrUpdateDisplay(uint32_t output_id,
const gfx::Rect& new_bounds,
int32_t scale_factor) {
display::Display changed_display(output_id);
- if (!display::Display::HasForceDeviceScaleFactor())
- changed_display.set_device_scale_factor(scale_factor);
- changed_display.set_bounds(new_bounds);
- changed_display.set_work_area(new_bounds);
+ if (!display::Display::HasForceDeviceScaleFactor()) {
+ changed_display.SetScaleAndBounds(scale_factor, new_bounds);
+ } else {
+ changed_display.set_bounds(new_bounds);
+ changed_display.set_work_area(new_bounds);
+ }
gfx::DisplayColorSpaces color_spaces;
color_spaces.SetOutputBufferFormats(image_format_no_alpha_.value(),
@@ -235,6 +237,9 @@ gfx::AcceleratedWidget WaylandScreen::GetLocalProcessWidgetAtPoint(
display::Display WaylandScreen::GetDisplayNearestPoint(
const gfx::Point& point) const {
+ auto displays = GetAllDisplays();
+ if (displays.size() <= 1)
+ return GetPrimaryDisplay();
return *FindDisplayNearestPoint(display_list_.displays(), point);
}
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc
index 46b30f43b54..865ebbe730b 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc
@@ -232,9 +232,13 @@ TEST_P(WaylandScreenTest, OutputPropertyChanges) {
Sync();
- changed_values = display::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR;
+ changed_values =
+ display::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR |
+ display::DisplayObserver::DISPLAY_METRIC_WORK_AREA |
+ display::DisplayObserver::DISPLAY_METRIC_BOUNDS;
EXPECT_EQ(observer.GetAndClearChangedMetrics(), changed_values);
EXPECT_EQ(observer.GetDisplay().device_scale_factor(), new_scale_value);
+ EXPECT_EQ(observer.GetDisplay().bounds(), gfx::Rect(50, 50));
platform_screen_->RemoveObserver(&observer);
}
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_shm.h b/chromium/ui/ozone/platform/wayland/host/wayland_shm.h
index 4f7f13ea8bf..0b484ed6e87 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_shm.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_shm.h
@@ -24,6 +24,8 @@ class WaylandShm {
WaylandShm(wl_shm* shm, WaylandConnection* connection);
~WaylandShm();
+ wl_shm* get() const { return shm_.get(); }
+
// Creates a wl_buffer based on shared memory handle for the specified
// |widget|.
wl::Object<struct wl_buffer> CreateBuffer(base::ScopedFD fd,
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_surface.cc b/chromium/ui/ozone/platform/wayland/host/wayland_surface.cc
index f3092c43e31..99906d1c6dd 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_surface.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_surface.cc
@@ -4,8 +4,10 @@
#include "ui/ozone/platform/wayland/host/wayland_surface.h"
+#include <linux-explicit-synchronization-unstable-v1-client-protocol.h>
#include <viewporter-client-protocol.h>
+#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/native_widget_types.h"
@@ -50,7 +52,19 @@ bool WaylandSurface::Initialize() {
LOG(ERROR) << "Failed to create wp_viewport";
return false;
}
+ } else {
+ LOG(WARNING) << "Server doesn't support wp_viewporter.";
+ }
+
+ // The server needs to support the linux_explicit_synchronization protocol.
+ if (!connection_->linux_explicit_synchronization_v1()) {
+ LOG(WARNING)
+ << "Server doesn't support zwp_linux_explicit_synchronization_v1.";
+ return true;
}
+ surface_sync_.reset(zwp_linux_explicit_synchronization_v1_get_synchronization(
+ connection_->linux_explicit_synchronization_v1(), surface_.get()));
+ DCHECK(surface_sync());
return true;
}
@@ -60,6 +74,11 @@ void WaylandSurface::UnsetRootWindow() {
root_window_ = nullptr;
}
+void WaylandSurface::SetAcquireFence(const gfx::GpuFenceHandle& acquire_fence) {
+ zwp_linux_surface_synchronization_v1_set_acquire_fence(
+ surface_sync(), acquire_fence.owned_fd.get());
+}
+
void WaylandSurface::AttachBuffer(wl_buffer* buffer) {
// The logic in DamageBuffer currently relies on attachment coordinates of
// (0, 0). If this changes, then the calculation in DamageBuffer will also
@@ -87,10 +106,12 @@ void WaylandSurface::UpdateBufferDamageRegion(
if (!crop_rect_.IsEmpty()) {
viewport_src = gfx::ToEnclosedRect(
gfx::ScaleRect(crop_rect_, bounds.width(), bounds.height()));
- wp_viewport_set_source(viewport(), wl_fixed_from_int(viewport_src.x()),
- wl_fixed_from_int(viewport_src.y()),
- wl_fixed_from_int(viewport_src.width()),
- wl_fixed_from_int(viewport_src.height()));
+ if (viewport()) {
+ wp_viewport_set_source(viewport(), wl_fixed_from_int(viewport_src.x()),
+ wl_fixed_from_int(viewport_src.y()),
+ wl_fixed_from_int(viewport_src.width()),
+ wl_fixed_from_int(viewport_src.height()));
+ }
}
// Apply viewport scale (wp_viewport.set_destination).
gfx::Size viewport_dst = bounds;
@@ -162,8 +183,10 @@ void WaylandSurface::SetBufferScale(int32_t new_scale, bool update_bounds) {
if (!display_size_px_.IsEmpty()) {
gfx::Size viewport_dst =
gfx::ScaleToCeiledSize(display_size_px_, 1.f / buffer_scale_);
- wp_viewport_set_destination(viewport(), viewport_dst.width(),
- viewport_dst.height());
+ if (viewport()) {
+ wp_viewport_set_destination(viewport(), viewport_dst.width(),
+ viewport_dst.height());
+ }
}
connection_->ScheduleFlush();
@@ -175,42 +198,83 @@ void WaylandSurface::SetOpaqueRegion(const gfx::Rect& region_px) {
if (!root_window_ || !root_window_->IsOpaqueWindow())
return;
- wl::Object<wl_region> region(
- wl_compositor_create_region(connection_->compositor()));
- gfx::Rect region_dip =
- gfx::ScaleToEnclosingRect(region_px, 1.f / buffer_scale_);
- wl_region_add(region.get(), region_dip.x(), region_dip.y(),
- region_dip.width(), region_dip.height());
+ wl_surface_set_opaque_region(surface_.get(),
+ CreateAndAddRegion(region_px).get());
+
+ connection_->ScheduleFlush();
+}
+
+void WaylandSurface::SetInputRegion(const gfx::Rect& region_px) {
+ // Don't set input region when use_native_frame is enabled.
+ if (!root_window_ || root_window_->ShouldUseNativeFrame())
+ return;
- wl_surface_set_opaque_region(surface_.get(), region.get());
+ // Sets input region for input events to allow go through and
+ // for the compositor to ignore the parts of the input region that fall
+ // outside of the surface.
+ wl_surface_set_input_region(surface_.get(),
+ CreateAndAddRegion(region_px).get());
connection_->ScheduleFlush();
}
+wl::Object<wl_region> WaylandSurface::CreateAndAddRegion(
+ const gfx::Rect& region_px) {
+ DCHECK(root_window_);
+
+ wl::Object<wl_region> region(
+ wl_compositor_create_region(connection_->compositor()));
+
+ auto window_shape_in_dips = root_window_->GetWindowShape();
+ if (window_shape_in_dips.has_value()) {
+ for (const auto& rect : window_shape_in_dips.value())
+ wl_region_add(region.get(), rect.x(), rect.y(), rect.width(),
+ rect.height());
+ } else {
+ gfx::Rect region_dip =
+ gfx::ScaleToEnclosingRect(region_px, 1.f / buffer_scale_);
+ wl_region_add(region.get(), region_dip.x(), region_dip.y(),
+ region_dip.width(), region_dip.height());
+ }
+ return region;
+}
+
void WaylandSurface::SetViewportSource(const gfx::RectF& src_rect) {
- if (src_rect == crop_rect_) {
+ if (src_rect == crop_rect_)
return;
- } else if (src_rect.IsEmpty() || src_rect == gfx::RectF{0.f, 0.f, 1.f, 1.f}) {
- wp_viewport_set_source(viewport(), wl_fixed_from_int(-1),
- wl_fixed_from_int(-1), wl_fixed_from_int(-1),
- wl_fixed_from_int(-1));
+ // |src_rect| {1.f, 1.f} does not apply cropping so set it to empty.
+ if (src_rect.IsEmpty() || src_rect == gfx::RectF{1.f, 1.f}) {
+ crop_rect_ = gfx::RectF();
+ if (viewport()) {
+ wp_viewport_set_source(viewport(), wl_fixed_from_int(-1),
+ wl_fixed_from_int(-1), wl_fixed_from_int(-1),
+ wl_fixed_from_int(-1));
+ }
return;
}
+ // wp_viewport_set_source() needs pixel inputs. Store |src_rect| and calculate
+ // in UpdateBufferDamageRegion().
crop_rect_ = src_rect;
}
void WaylandSurface::SetViewportDestination(const gfx::Size& dest_size_px) {
- if (dest_size_px == display_size_px_) {
+ if (dest_size_px == display_size_px_)
+ return;
+ if (dest_size_px.IsEmpty()) {
+ display_size_px_ = gfx::Size();
+ if (viewport()) {
+ wp_viewport_set_destination(viewport(), -1, -1);
+ }
return;
- } else if (dest_size_px.IsEmpty()) {
- wp_viewport_set_destination(viewport(), -1, -1);
}
display_size_px_ = dest_size_px;
gfx::Size viewport_dst =
gfx::ScaleToCeiledSize(display_size_px_, 1.f / buffer_scale_);
- wp_viewport_set_destination(viewport(), viewport_dst.width(),
- viewport_dst.height());
+ if (viewport()) {
+ wp_viewport_set_destination(viewport(), viewport_dst.width(),
+ viewport_dst.height());
+ }
}
wl::Object<wl_subsurface> WaylandSurface::CreateSubsurface(
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_surface.h b/chromium/ui/ozone/platform/wayland/host/wayland_surface.h
index c026bc22cb7..2f7284aeac3 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_surface.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_surface.h
@@ -9,6 +9,7 @@
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/gpu_fence_handle.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/overlay_transform.h"
#include "ui/ozone/platform/wayland/common/wayland_object.h"
@@ -29,6 +30,9 @@ class WaylandSurface {
WaylandWindow* root_window() const { return root_window_; }
wl_surface* surface() const { return surface_.get(); }
wp_viewport* viewport() const { return viewport_.get(); }
+ zwp_linux_surface_synchronization_v1* surface_sync() const {
+ return surface_sync_.get();
+ }
int32_t buffer_scale() const { return buffer_scale_; }
void set_buffer_scale(int32_t scale) { buffer_scale_ = scale; }
@@ -47,6 +51,10 @@ class WaylandSurface {
// (e.g: window/tab dragging sessions).
void UnsetRootWindow();
+ // Sets a non-null in-fence, must be combined with an AttachBuffer() and a
+ // Commit().
+ void SetAcquireFence(const gfx::GpuFenceHandle& acquire_fence);
+
// Attaches the given wl_buffer to the underlying wl_surface at (0, 0).
void AttachBuffer(wl_buffer* buffer);
@@ -67,8 +75,16 @@ class WaylandSurface {
// Sets the region that is opaque on this surface in physical pixels. This is
// expected to be called whenever the region that the surface span changes or
- // the opacity changes.
- void SetOpaqueRegion(const gfx::Rect& bounds_px);
+ // the opacity changes. |region_px| is specified surface-local, in physical
+ // pixels.
+ void SetOpaqueRegion(const gfx::Rect& region_px);
+
+ // Sets the input region on this surface in physical pixels.
+ // The input region indicates which parts of the surface accept pointer and
+ // touch input events. This is expected to be called from ToplevelWindow
+ // whenever the region that the surface span changes or window state changes
+ // when custom frame is used.
+ void SetInputRegion(const gfx::Rect& region_px);
// Set the source rectangle of the associated wl_surface.
// See:
@@ -89,10 +105,13 @@ class WaylandSurface {
wl::Object<wl_subsurface> CreateSubsurface(WaylandSurface* parent);
private:
+ wl::Object<wl_region> CreateAndAddRegion(const gfx::Rect& region_px);
+
WaylandConnection* const connection_;
WaylandWindow* root_window_ = nullptr;
wl::Object<wl_surface> surface_;
wl::Object<wp_viewport> viewport_;
+ wl::Object<zwp_linux_surface_synchronization_v1> surface_sync_;
// Transformation for how the compositor interprets the contents of the
// buffer.
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc b/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc
index f58063afdb3..8290a7ea497 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc
@@ -9,23 +9,20 @@
#include "base/run_loop.h"
#include "base/unguessable_token.h"
#include "build/chromeos_buildflags.h"
-#include "ui/base/dragdrop/drag_drop_types.h"
-#include "ui/base/dragdrop/os_exchange_data.h"
+#include "third_party/skia/include/core/SkPath.h"
#include "ui/base/hit_test.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/ozone/platform/wayland/host/shell_object_factory.h"
-#include "ui/ozone/platform/wayland/host/shell_surface_wrapper.h"
+#include "ui/ozone/platform/wayland/host/shell_toplevel_wrapper.h"
#include "ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
-#include "ui/ozone/platform/wayland/host/wayland_data_drag_controller.h"
#include "ui/ozone/platform/wayland/host/wayland_event_source.h"
#include "ui/ozone/platform/wayland/host/wayland_window.h"
#include "ui/ozone/platform/wayland/host/wayland_window_drag_controller.h"
#include "ui/ozone/platform/wayland/host/wayland_zaura_shell.h"
#include "ui/platform_window/extensions/wayland_extension.h"
-#include "ui/platform_window/wm/wm_drop_handler.h"
-#if BUILDFLAG(IS_LACROS)
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
// TODO(jamescook): The nogncheck is to work around false-positive failures on
// the code search bot. Remove after https://crrev.com/c/2432137 lands.
#include "chromeos/crosapi/cpp/crosapi_constants.h" // nogncheck
@@ -40,45 +37,41 @@ WaylandToplevelWindow::WaylandToplevelWindow(PlatformWindowDelegate* delegate,
// Set a class property key, which allows |this| to be used for interactive
// events, e.g. move or resize.
SetWmMoveResizeHandler(this, AsWmMoveResizeHandler());
-
- // Set a class property key, which allows |this| to be used for drag action.
- SetWmDragHandler(this, this);
}
-WaylandToplevelWindow::~WaylandToplevelWindow() {
- if (drag_handler_delegate_) {
- drag_handler_delegate_->OnDragFinished(
- DragDropTypes::DragOperation::DRAG_NONE);
- }
- CancelDrag();
-}
+WaylandToplevelWindow::~WaylandToplevelWindow() = default;
-bool WaylandToplevelWindow::CreateShellSurface() {
+bool WaylandToplevelWindow::CreateShellToplevel() {
ShellObjectFactory factory;
- shell_surface_ = factory.CreateShellSurfaceWrapper(connection(), this);
- if (!shell_surface_) {
- LOG(ERROR) << "Failed to create a ShellSurface.";
+ shell_toplevel_ = factory.CreateShellToplevelWrapper(connection(), this);
+ if (!shell_toplevel_) {
+ LOG(ERROR) << "Failed to create a ShellToplevel.";
return false;
}
-#if BUILDFLAG(IS_LACROS)
- shell_surface_->SetAppId(window_unique_id_);
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+ shell_toplevel_->SetAppId(window_unique_id_);
#else
- shell_surface_->SetAppId(wm_class_class_);
+ shell_toplevel_->SetAppId(wm_class_class_);
#endif
- shell_surface_->SetTitle(window_title_);
+ shell_toplevel_->SetTitle(window_title_);
SetSizeConstraints();
TriggerStateChanges();
+ InitializeAuraShellSurface();
+ OnDecorationModeChanged();
+ // This could be the proper time to update window mask using
+ // NonClientView::GetWindowMask, since |non_client_view| is not created yet
+ // during the call to WaylandWindow::Initialize().
+ UpdateWindowMask();
return true;
}
void WaylandToplevelWindow::ApplyPendingBounds() {
if (pending_bounds_dip_.IsEmpty())
return;
- DCHECK(shell_surface_);
+ DCHECK(shell_toplevel_);
SetBoundsDip(pending_bounds_dip_);
- shell_surface_->SetWindowGeometry(pending_bounds_dip_);
pending_bounds_dip_ = gfx::Rect();
connection()->ScheduleFlush();
}
@@ -86,47 +79,22 @@ void WaylandToplevelWindow::ApplyPendingBounds() {
void WaylandToplevelWindow::DispatchHostWindowDragMovement(
int hittest,
const gfx::Point& pointer_location_in_px) {
- DCHECK(shell_surface_);
+ DCHECK(shell_toplevel_);
connection()->event_source()->ResetPointerFlags();
if (hittest == HTCAPTION)
- shell_surface_->SurfaceMove(connection());
+ shell_toplevel_->SurfaceMove(connection());
else
- shell_surface_->SurfaceResize(connection(), hittest);
+ shell_toplevel_->SurfaceResize(connection(), hittest);
connection()->ScheduleFlush();
}
-bool WaylandToplevelWindow::StartDrag(const ui::OSExchangeData& data,
- int operation,
- gfx::NativeCursor cursor,
- bool can_grab_pointer,
- WmDragHandler::Delegate* delegate) {
- DCHECK(!drag_handler_delegate_);
- drag_handler_delegate_ = delegate;
- connection()->data_drag_controller()->StartSession(data, operation);
-
- base::RunLoop drag_loop(base::RunLoop::Type::kNestableTasksAllowed);
- drag_loop_quit_closure_ = drag_loop.QuitClosure();
-
- auto alive = weak_ptr_factory_.GetWeakPtr();
- drag_loop.Run();
- if (!alive)
- return false;
- return true;
-}
-
-void WaylandToplevelWindow::CancelDrag() {
- if (drag_loop_quit_closure_.is_null())
- return;
- std::move(drag_loop_quit_closure_).Run();
-}
-
void WaylandToplevelWindow::Show(bool inactive) {
- if (shell_surface_)
+ if (shell_toplevel_)
return;
- if (!CreateShellSurface()) {
+ if (!CreateShellToplevel()) {
Close();
return;
}
@@ -140,7 +108,7 @@ void WaylandToplevelWindow::Show(bool inactive) {
}
void WaylandToplevelWindow::Hide() {
- if (!shell_surface_)
+ if (!shell_toplevel_)
return;
if (child_window()) {
@@ -148,7 +116,7 @@ void WaylandToplevelWindow::Hide() {
set_child_window(nullptr);
}
- shell_surface_.reset();
+ shell_toplevel_.reset();
connection()->ScheduleFlush();
// Detach buffer from surface in order to completely shutdown menus and
@@ -159,7 +127,7 @@ void WaylandToplevelWindow::Hide() {
bool WaylandToplevelWindow::IsVisible() const {
// X and Windows return true if the window is minimized. For consistency, do
// the same.
- return !!shell_surface_ || state_ == PlatformWindowState::kMinimized;
+ return !!shell_toplevel_ || state_ == PlatformWindowState::kMinimized;
}
void WaylandToplevelWindow::SetTitle(const base::string16& title) {
@@ -168,8 +136,8 @@ void WaylandToplevelWindow::SetTitle(const base::string16& title) {
window_title_ = title;
- if (shell_surface_) {
- shell_surface_->SetTitle(title);
+ if (shell_toplevel_) {
+ shell_toplevel_->SetTitle(title);
connection()->ScheduleFlush();
}
}
@@ -203,7 +171,7 @@ void WaylandToplevelWindow::Minimize() {
}
void WaylandToplevelWindow::Restore() {
- DCHECK(shell_surface_);
+ DCHECK(shell_toplevel_);
// Differently from other platforms, under Wayland, unmaximizing the dragged
// window before starting the drag loop is not needed as it is assumed to be
@@ -222,30 +190,59 @@ PlatformWindowState WaylandToplevelWindow::GetPlatformWindowState() const {
return state_;
}
+void WaylandToplevelWindow::Activate() {
+ // Only supported by compositors that support zaura_shell (e.g. exo).
+ // TODO(https://crbug.com/1175327): Use standard Wayland extensions, such as
+ // xdg-activation, when those are available.
+ if (aura_surface_)
+ zaura_surface_activate(aura_surface_.get());
+}
+
void WaylandToplevelWindow::SizeConstraintsChanged() {
// Size constraints only make sense for normal windows.
- if (!shell_surface_)
+ if (!shell_toplevel_)
return;
- DCHECK(delegate());
- min_size_ = delegate()->GetMinimumSizeForWindow();
- max_size_ = delegate()->GetMaximumSizeForWindow();
SetSizeConstraints();
}
std::string WaylandToplevelWindow::GetWindowUniqueId() const {
-#if BUILDFLAG(IS_LACROS)
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
return window_unique_id_;
#else
return std::string();
#endif
}
-void WaylandToplevelWindow::HandleSurfaceConfigure(int32_t width,
- int32_t height,
- bool is_maximized,
- bool is_fullscreen,
- bool is_activated) {
+void WaylandToplevelWindow::SetUseNativeFrame(bool use_native_frame) {
+ if (use_native_frame_ == use_native_frame)
+ return;
+ use_native_frame_ = use_native_frame;
+ if (shell_toplevel_)
+ OnDecorationModeChanged();
+
+ UpdateWindowMask();
+}
+
+bool WaylandToplevelWindow::ShouldUseNativeFrame() const {
+ // This depends on availability of xdg-decoration protocol extension.
+ // Returns false if there is no xdg-decoration protocol extension provided
+ // even if use_native_frame_ is true.
+ return use_native_frame_ && const_cast<WaylandToplevelWindow*>(this)
+ ->connection()
+ ->xdg_decoration_manager_v1();
+}
+
+base::Optional<std::vector<gfx::Rect>> WaylandToplevelWindow::GetWindowShape()
+ const {
+ return window_shape_in_dips_;
+}
+
+void WaylandToplevelWindow::HandleToplevelConfigure(int32_t width,
+ int32_t height,
+ bool is_maximized,
+ bool is_fullscreen,
+ bool is_activated) {
// Store the old state to propagte state changes if Wayland decides to change
// the state to something else.
PlatformWindowState old_state = state_;
@@ -259,9 +256,14 @@ void WaylandToplevelWindow::HandleSurfaceConfigure(int32_t width,
state_ = PlatformWindowState::kNormal;
}
- const bool state_changed = old_state != state_;
const bool is_normal = state_ == PlatformWindowState::kNormal;
+ bool did_send_delegate_notification = !!requested_window_show_state_count_;
+ if (requested_window_show_state_count_)
+ requested_window_show_state_count_--;
+
+ const bool did_window_show_state_change = old_state != state_;
+
// Update state before notifying delegate.
const bool did_active_change = is_active_ != is_activated;
is_active_ = is_activated;
@@ -287,7 +289,6 @@ void WaylandToplevelWindow::HandleSurfaceConfigure(int32_t width,
gfx::ScaleToRoundedSize(GetRestoredBoundsInPixels().IsEmpty()
? GetBounds().size()
: GetRestoredBoundsInPixels().size(),
-
1.0 / buffer_scale()));
}
@@ -295,71 +296,60 @@ void WaylandToplevelWindow::HandleSurfaceConfigure(int32_t width,
// It can be client or compositor side change from normal to something else.
// Thus, we must store previous bounds to restore later.
SetOrResetRestoredBounds();
- ApplyPendingBounds();
- if (state_changed)
+ if (did_window_show_state_change && !did_send_delegate_notification) {
+ previous_state_ = old_state;
delegate()->OnWindowStateChanged(state_);
+ }
if (did_active_change)
delegate()->OnActivationChanged(is_active_);
}
-void WaylandToplevelWindow::OnDragEnter(const gfx::PointF& point,
- std::unique_ptr<OSExchangeData> data,
- int operation) {
- WmDropHandler* drop_handler = GetWmDropHandler(*this);
- if (!drop_handler)
- return;
+void WaylandToplevelWindow::HandleSurfaceConfigure(uint32_t serial) {
+ if (pending_bounds_dip_.size() ==
+ gfx::ScaleToRoundedSize(GetBounds().size(), 1.f / buffer_scale())) {
+ // If |pending_bounds_dip_| matches GetBounds(), then a frame matching
+ // |pending_bounds_dip_| may not arrive soon, despite the window delegate
+ // receives the updated bounds. Without a new frame, UpdateVisualSize() is
+ // not invoked, leaving this |configure| unacknowledged.
+ // E.g. With static window content, |configure| that does not
+ // change window size will not cause the window to redraw.
+ // Hence, acknowledge this |configure| now to tell the Wayland compositor
+ // that this window has been configured.
+ shell_toplevel()->SetWindowGeometry(pending_bounds_dip_);
+ shell_toplevel()->AckConfigure(serial);
+ } else {
+ // Otherwise, push the pending |configure| to |pending_configures_|, wait
+ // for a frame update, which will invoke UpdateVisualSize().
+ DCHECK_LT(pending_configures_.size(), 25u);
+ pending_configures_.push_back({pending_bounds_dip_.size(), serial});
+ }
- // Wayland sends locations in DIP so they need to be translated to
- // physical pixels.
- // TODO(crbug.com/1102857): get the real event modifier here.
- drop_handler->OnDragEnter(
- gfx::ScalePoint(point, buffer_scale(), buffer_scale()), std::move(data),
- operation,
- /*modifiers=*/0);
+ ApplyPendingBounds();
}
-int WaylandToplevelWindow::OnDragMotion(const gfx::PointF& point,
- int operation) {
- WmDropHandler* drop_handler = GetWmDropHandler(*this);
- if (!drop_handler)
- return 0;
+void WaylandToplevelWindow::UpdateVisualSize(const gfx::Size& size_px) {
+ WaylandWindow::UpdateVisualSize(size_px);
- // Wayland sends locations in DIP so they need to be translated to
- // physical pixels.
- // TODO(crbug.com/1102857): get the real event modifier here.
- return drop_handler->OnDragMotion(
- gfx::ScalePoint(point, buffer_scale(), buffer_scale()), operation,
- /*modifiers=*/0);
-}
-
-void WaylandToplevelWindow::OnDragDrop(std::unique_ptr<OSExchangeData> data) {
- WmDropHandler* drop_handler = GetWmDropHandler(*this);
- if (!drop_handler)
+ if (!shell_toplevel_)
return;
- // TODO(crbug.com/1102857): get the real event modifier here.
- drop_handler->OnDragDrop(std::move(data), /*modifiers=*/0);
-}
+ auto size_dip = gfx::ScaleToRoundedSize(size_px, 1.f / buffer_scale());
+ auto result = std::find_if(
+ pending_configures_.begin(), pending_configures_.end(),
+ [&size_dip](auto& configure) { return size_dip == configure.size_dip; });
-void WaylandToplevelWindow::OnDragLeave() {
- WmDropHandler* drop_handler = GetWmDropHandler(*this);
- if (!drop_handler)
+ if (result == pending_configures_.end())
return;
- drop_handler->OnDragLeave();
-}
-void WaylandToplevelWindow::OnDragSessionClose(uint32_t dnd_action) {
- DCHECK(drag_handler_delegate_);
- drag_handler_delegate_->OnDragFinished(dnd_action);
- drag_handler_delegate_ = nullptr;
- connection()->event_source()->ResetPointerFlags();
- std::move(drag_loop_quit_closure_).Run();
+ shell_toplevel()->SetWindowGeometry(gfx::Rect(size_dip));
+ shell_toplevel()->AckConfigure(result->serial);
+ pending_configures_.erase(pending_configures_.begin(), ++result);
}
bool WaylandToplevelWindow::OnInitialize(
PlatformWindowInitProperties properties) {
-#if BUILDFLAG(IS_LACROS)
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
auto token = base::UnguessableToken::Create();
window_unique_id_ =
std::string(crosapi::kLacrosAppIdPrefix) + token.ToString();
@@ -368,7 +358,6 @@ bool WaylandToplevelWindow::OnInitialize(
#endif
SetWaylandExtension(this, static_cast<WaylandExtension*>(this));
SetWmMoveLoopHandler(this, static_cast<WmMoveLoopHandler*>(this));
- InitializeAuraShell();
return true;
}
@@ -391,34 +380,99 @@ void WaylandToplevelWindow::StartWindowDraggingSessionIfNeeded() {
connection()->window_drag_controller()->StartDragSession();
}
-void WaylandToplevelWindow::TriggerStateChanges() {
- if (!shell_surface_)
+void WaylandToplevelWindow::SetImmersiveFullscreenStatus(bool status) {
+ if (aura_surface_) {
+ auto mode = status ? ZAURA_SURFACE_FULLSCREEN_MODE_IMMERSIVE
+ : ZAURA_SURFACE_FULLSCREEN_MODE_PLAIN;
+ zaura_surface_set_fullscreen_mode(aura_surface_.get(), mode);
+ } else {
+ // TODO(https://crbug.com/1113900): Implement AuraShell support for
+ // non-browser windows and replace this if-else clause by a DCHECK.
+ NOTIMPLEMENTED_LOG_ONCE()
+ << "Implement AuraShell support for non-browser windows.";
+ }
+}
+
+void WaylandToplevelWindow::ShowSnapPreview(
+ WaylandWindowSnapDirection snap_direction) {
+ if (aura_surface_ && zaura_surface_get_version(aura_surface_.get()) >=
+ ZAURA_SURFACE_INTENT_TO_SNAP_SINCE_VERSION) {
+ uint32_t zaura_shell_snap_direction = ZAURA_SURFACE_SNAP_DIRECTION_NONE;
+ switch (snap_direction) {
+ case WaylandWindowSnapDirection::kLeft:
+ zaura_shell_snap_direction = ZAURA_SURFACE_SNAP_DIRECTION_LEFT;
+ break;
+ case WaylandWindowSnapDirection::kRight:
+ zaura_shell_snap_direction = ZAURA_SURFACE_SNAP_DIRECTION_RIGHT;
+ break;
+ case WaylandWindowSnapDirection::kNone:
+ break;
+ }
+ zaura_surface_intent_to_snap(aura_surface_.get(),
+ zaura_shell_snap_direction);
return;
+ }
- if (state_ == PlatformWindowState::kFullScreen)
- shell_surface_->SetFullscreen();
- else
- shell_surface_->UnSetFullscreen();
+ NOTIMPLEMENTED_LOG_ONCE()
+ << "Window snapping isn't available for non-lacros builds.";
+}
+
+void WaylandToplevelWindow::CommitSnap(
+ WaylandWindowSnapDirection snap_direction) {
+ if (aura_surface_ && zaura_surface_get_version(aura_surface_.get()) >=
+ ZAURA_SURFACE_UNSET_SNAP_SINCE_VERSION) {
+ switch (snap_direction) {
+ case WaylandWindowSnapDirection::kLeft:
+ zaura_surface_set_snap_left(aura_surface_.get());
+ return;
+ case WaylandWindowSnapDirection::kRight:
+ zaura_surface_set_snap_right(aura_surface_.get());
+ return;
+ case WaylandWindowSnapDirection::kNone:
+ zaura_surface_unset_snap(aura_surface_.get());
+ return;
+ }
+ }
+
+ NOTIMPLEMENTED_LOG_ONCE()
+ << "Window snapping isn't available for non-lacros builds.";
+}
+
+void WaylandToplevelWindow::TriggerStateChanges() {
+ if (!shell_toplevel_)
+ return;
// Call UnSetMaximized only if current state is normal. Otherwise, if the
// current state is fullscreen and the previous is maximized, calling
// UnSetMaximized may result in wrong restored window position that clients
// are not allowed to know about.
- if (state_ == PlatformWindowState::kMaximized)
- shell_surface_->SetMaximized();
- else if (state_ == PlatformWindowState::kNormal)
- shell_surface_->UnSetMaximized();
+ if (state_ == PlatformWindowState::kMinimized) {
+ shell_toplevel_->SetMinimized();
+ } else if (state_ == PlatformWindowState::kFullScreen) {
+ shell_toplevel_->SetFullscreen();
+ } else if (previous_state_ == PlatformWindowState::kFullScreen) {
+ shell_toplevel_->UnSetFullscreen();
+ } else if (state_ == PlatformWindowState::kMaximized) {
+ shell_toplevel_->SetMaximized();
+ } else if (state_ == PlatformWindowState::kNormal) {
+ shell_toplevel_->UnSetMaximized();
+ }
- if (state_ == PlatformWindowState::kMinimized)
- shell_surface_->SetMinimized();
+ delegate()->OnWindowStateChanged(state_);
connection()->ScheduleFlush();
}
void WaylandToplevelWindow::SetWindowState(PlatformWindowState state) {
- previous_state_ = state_;
- state_ = state;
- TriggerStateChanges();
+ if (state_ != state) {
+ previous_state_ = state_;
+ state_ = state;
+
+ // Tracks this window show state change request, coming from the Browser.
+ requested_window_show_state_count_++;
+
+ TriggerStateChanges();
+ }
}
WmMoveResizeHandler* WaylandToplevelWindow::AsWmMoveResizeHandler() {
@@ -426,10 +480,22 @@ WmMoveResizeHandler* WaylandToplevelWindow::AsWmMoveResizeHandler() {
}
void WaylandToplevelWindow::SetSizeConstraints() {
- if (min_size_.has_value())
- shell_surface_->SetMinSize(min_size_->width(), min_size_->height());
- if (max_size_.has_value())
- shell_surface_->SetMaxSize(max_size_->width(), max_size_->height());
+ DCHECK(delegate());
+
+ min_size_ = delegate()->GetMinimumSizeForWindow();
+ max_size_ = delegate()->GetMaximumSizeForWindow();
+
+ if (min_size_.has_value()) {
+ auto min_size_dip =
+ gfx::ScaleToRoundedSize(min_size_.value(), 1.0f / buffer_scale());
+ shell_toplevel_->SetMinSize(min_size_dip.width(), min_size_dip.height());
+ }
+
+ if (max_size_.has_value()) {
+ auto max_size_dip =
+ gfx::ScaleToRoundedSize(max_size_.value(), 1.0f / buffer_scale());
+ shell_toplevel_->SetMaxSize(max_size_dip.width(), max_size_dip.height());
+ }
connection()->ScheduleFlush();
}
@@ -447,14 +513,56 @@ void WaylandToplevelWindow::SetOrResetRestoredBounds() {
}
}
-void WaylandToplevelWindow::InitializeAuraShell() {
- if (connection()->zaura_shell()) {
- DCHECK(!aura_surface_);
+void WaylandToplevelWindow::InitializeAuraShellSurface() {
+ // InitializeAuraShellSurface() should be called after the XDG surface is
+ // initialized.
+ DCHECK(shell_toplevel_);
+
+ if (connection()->zaura_shell() && !aura_surface_) {
aura_surface_.reset(zaura_shell_get_aura_surface(
connection()->zaura_shell()->wl_object(), root_surface()->surface()));
- zaura_surface_set_fullscreen_mode(aura_surface_.get(),
- ZAURA_SURFACE_FULLSCREEN_MODE_IMMERSIVE);
+ SetImmersiveFullscreenStatus(false);
+ }
+}
+
+void WaylandToplevelWindow::OnDecorationModeChanged() {
+ DCHECK(shell_toplevel_);
+ if (use_native_frame_) {
+ // Set server-side decoration for windows using a native frame,
+ // e.g. taskmanager
+ shell_toplevel_->SetDecoration(
+ ShellToplevelWrapper::DecorationMode::kServerSide);
+ } else if (aura_surface_ &&
+ zaura_surface_get_version(aura_surface_.get()) >=
+ ZAURA_SURFACE_SET_SERVER_START_RESIZE_SINCE_VERSION) {
+ // Sets custom-decoration mode for window that supports aura_shell.
+ // e.g. lacros-browser.
+ zaura_surface_set_server_start_resize(aura_surface_.get());
+ } else {
+ shell_toplevel_->SetDecoration(
+ ShellToplevelWrapper::DecorationMode::kClientSide);
+ }
+}
+
+void WaylandToplevelWindow::UpdateWindowMask() {
+ // TODO(http://crbug.com/1158733): When supporting PlatformWindow::SetShape,
+ // update window region with the given |shape|.
+ WaylandWindow::UpdateWindowMask();
+ root_surface()->SetInputRegion(gfx::Rect(visual_size_px()));
+}
+
+void WaylandToplevelWindow::UpdateWindowShape() {
+ // Create |window_shape_in_dips_| using the window mask of
+ // PlatformWindowDelegate otherwise resets it.
+ SkPath window_mask_in_pixels =
+ delegate()->GetWindowMaskForWindowShapeInPixels();
+ if (window_mask_in_pixels.isEmpty()) {
+ window_shape_in_dips_.reset();
+ return;
}
+ SkPath window_mask_in_dips =
+ wl::ConvertPathToDIP(window_mask_in_pixels, buffer_scale());
+ window_shape_in_dips_ = wl::CreateRectsFromSkPath(window_mask_in_dips);
}
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.h b/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.h
index 7f091d3f48f..849ee9ae60d 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.h
@@ -5,21 +5,20 @@
#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_TOPLEVEL_WINDOW_H_
#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_TOPLEVEL_WINDOW_H_
+#include "base/containers/circular_deque.h"
#include "build/chromeos_buildflags.h"
#include "ui/gfx/geometry/vector2d.h"
#include "ui/ozone/platform/wayland/host/wayland_window.h"
#include "ui/platform_window/extensions/wayland_extension.h"
-#include "ui/platform_window/wm/wm_drag_handler.h"
#include "ui/platform_window/wm/wm_move_loop_handler.h"
#include "ui/platform_window/wm/wm_move_resize_handler.h"
namespace ui {
-class ShellSurfaceWrapper;
+class ShellToplevelWrapper;
class WaylandToplevelWindow : public WaylandWindow,
public WmMoveResizeHandler,
- public WmDragHandler,
public WmMoveLoopHandler,
public WaylandExtension {
public:
@@ -29,7 +28,7 @@ class WaylandToplevelWindow : public WaylandWindow,
WaylandToplevelWindow& operator=(const WaylandToplevelWindow&) = delete;
~WaylandToplevelWindow() override;
- ShellSurfaceWrapper* shell_surface() const { return shell_surface_.get(); }
+ ShellToplevelWrapper* shell_toplevel() const { return shell_toplevel_.get(); }
// Apply the bounds specified in the most recent configure event. This should
// be called after processing all pending events in the wayland connection.
@@ -40,15 +39,7 @@ class WaylandToplevelWindow : public WaylandWindow,
int hittest,
const gfx::Point& pointer_location_in_px) override;
- // WmDragHandler
- bool StartDrag(const ui::OSExchangeData& data,
- int operation,
- gfx::NativeCursor cursor,
- bool can_grab_pointer,
- WmDragHandler::Delegate* delegate) override;
- void CancelDrag() override;
-
- // PlatformWindow
+ // PlatformWindow:
void Show(bool inactive) override;
void Hide() override;
bool IsVisible() const override;
@@ -58,25 +49,33 @@ class WaylandToplevelWindow : public WaylandWindow,
void Minimize() override;
void Restore() override;
PlatformWindowState GetPlatformWindowState() const override;
+ void Activate() override;
void SizeConstraintsChanged() override;
std::string GetWindowUniqueId() const override;
+ // SetUseNativeFrame and ShouldUseNativeFrame decide on
+ // xdg-decoration mode for a window.
+ void SetUseNativeFrame(bool use_native_frame) override;
+ bool ShouldUseNativeFrame() const override;
+
+ // WaylandWindow overrides:
+ base::Optional<std::vector<gfx::Rect>> GetWindowShape() const override;
private:
// WaylandWindow overrides:
- void HandleSurfaceConfigure(int32_t widht,
- int32_t height,
- bool is_maximized,
- bool is_fullscreen,
- bool is_activated) override;
- void OnDragEnter(const gfx::PointF& point,
- std::unique_ptr<OSExchangeData> data,
- int operation) override;
- int OnDragMotion(const gfx::PointF& point, int operation) override;
- void OnDragDrop(std::unique_ptr<OSExchangeData> data) override;
- void OnDragLeave() override;
- void OnDragSessionClose(uint32_t dnd_action) override;
+ void HandleToplevelConfigure(int32_t width,
+ int32_t height,
+ bool is_maximized,
+ bool is_fullscreen,
+ bool is_activated) override;
+ void HandleSurfaceConfigure(uint32_t serial) override;
+ void UpdateVisualSize(const gfx::Size& size_px) override;
bool OnInitialize(PlatformWindowInitProperties properties) override;
bool IsActive() const override;
+ // Calls UpdateWindowShape, set_input_region and set_opaque_region
+ // for this toplevel window.
+ void UpdateWindowMask() override;
+ // Update the window shape using the window mask of PlatformWindowDelegate.
+ void UpdateWindowShape() override;
// WmMoveLoopHandler:
bool RunMoveLoop(const gfx::Vector2d& drag_offset) override;
@@ -84,27 +83,32 @@ class WaylandToplevelWindow : public WaylandWindow,
// WaylandExtension:
void StartWindowDraggingSessionIfNeeded() override;
+ void SetImmersiveFullscreenStatus(bool status) override;
+ void ShowSnapPreview(WaylandWindowSnapDirection snap) override;
+ void CommitSnap(WaylandWindowSnapDirection snap) override;
void TriggerStateChanges();
void SetWindowState(PlatformWindowState state);
// Creates a surface window, which is visible as a main window.
- bool CreateShellSurface();
+ bool CreateShellToplevel();
WmMoveResizeHandler* AsWmMoveResizeHandler();
- // Propagates the |min_size_| and |max_size_| to the ShellSurface.
+ // Propagates the |min_size_| and |max_size_| to the ShellToplevel.
void SetSizeConstraints();
void SetOrResetRestoredBounds();
- // Initializes the aura-shell EXO extension, if available.
- void InitializeAuraShell();
+ // Initializes the aura-shell surface, in the case aura-shell EXO extension
+ // is available.
+ void InitializeAuraShellSurface();
- // Wrappers around shell surface.
- std::unique_ptr<ShellSurfaceWrapper> shell_surface_;
+ // Sets decoration mode for a window.
+ void OnDecorationModeChanged();
- WmDragHandler::Delegate* drag_handler_delegate_ = nullptr;
+ // Wrappers around shell surface.
+ std::unique_ptr<ShellToplevelWrapper> shell_toplevel_;
// These bounds attributes below have suffices that indicate units used.
// Wayland operates in DIP but the platform operates in physical pixels so
@@ -125,7 +129,7 @@ class WaylandToplevelWindow : public WaylandWindow,
bool is_active_ = false;
-#if BUILDFLAG(IS_LACROS)
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
// Unique ID for this window. May be shared over non-Wayland IPC transports
// (e.g. mojo) to identify the window.
std::string window_unique_id_;
@@ -137,18 +141,40 @@ class WaylandToplevelWindow : public WaylandWindow,
std::string wm_class_class_;
#endif
- // Title of the ShellSurface.
+ // Title of the ShellToplevel.
base::string16 window_title_;
// Max and min sizes of the WaylandToplevelWindow window.
base::Optional<gfx::Size> min_size_;
base::Optional<gfx::Size> max_size_;
- base::OnceClosure drag_loop_quit_closure_;
-
wl::Object<zaura_surface> aura_surface_;
- base::WeakPtrFactory<WaylandToplevelWindow> weak_ptr_factory_{this};
+ // When use_native_frame is false, client-side decoration is set,
+ // e.g. lacros-browser.
+ // When use_native_frame is true, server-side decoration is set,
+ // e.g. lacros-taskmanager.
+ bool use_native_frame_ = false;
+
+ base::Optional<std::vector<gfx::Rect>> window_shape_in_dips_;
+
+ // Pending xdg-shell configures, once this window is drawn to |size_dip|,
+ // ack_configure with |serial| will be sent to the Wayland compositor.
+ struct PendingConfigure {
+ gfx::Size size_dip;
+ uint32_t serial;
+ };
+ base::circular_deque<PendingConfigure> pending_configures_;
+
+ // Tracks how many the window show state requests by made by the Browser
+ // are currently being processed by the Wayland Compositor. In practice,
+ // each individual increment corresponds to an explicit window show state
+ // change request, and gets a response by the Compositor.
+ //
+ // This mechanism allows Ozone/Wayland to filter out notifying the delegate
+ // (PlatformWindowDelegate) more than once, for the same window show state
+ // change.
+ uint32_t requested_window_show_state_count_ = 0;
};
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_touch.cc b/chromium/ui/ozone/platform/wayland/host/wayland_touch.cc
index 6bb9802ed9a..8eba29721e8 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_touch.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_touch.cc
@@ -22,14 +22,11 @@ WaylandTouch::WaylandTouch(wl_touch* touch,
&WaylandTouch::Frame, &WaylandTouch::Cancel,
};
- DCHECK(delegate_);
- delegate_->OnTouchCreated(this);
-
wl_touch_add_listener(obj_.get(), &listener, this);
}
WaylandTouch::~WaylandTouch() {
- delegate_->OnTouchDestroyed(this);
+ delegate_->OnTouchCancelEvent();
}
void WaylandTouch::Down(void* data,
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_touch.h b/chromium/ui/ozone/platform/wayland/host/wayland_touch.h
index 14c9aaa0f78..4c3e3b7aaac 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_touch.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_touch.h
@@ -61,8 +61,6 @@ class WaylandTouch {
class WaylandTouch::Delegate {
public:
- virtual void OnTouchCreated(WaylandTouch* touch) = 0;
- virtual void OnTouchDestroyed(WaylandTouch* touch) = 0;
virtual void OnTouchPressEvent(WaylandWindow* window,
const gfx::PointF& location,
base::TimeTicks timestamp,
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window.cc b/chromium/ui/ozone/platform/wayland/host/wayland_window.cc
index f59e227aba9..edc21c70b89 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_window.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window.cc
@@ -4,27 +4,37 @@
#include "ui/ozone/platform/wayland/host/wayland_window.h"
+#include <wayland-cursor.h>
#include <algorithm>
#include <memory>
#include "base/bind.h"
+#include "base/run_loop.h"
#include "build/chromeos_buildflags.h"
#include "ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h"
+#include "ui/base/dragdrop/drag_drop_types.h"
+#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/events/event.h"
#include "ui/events/event_utils.h"
#include "ui/events/ozone/events_ozone.h"
#include "ui/events/platform/platform_event_source.h"
#include "ui/gfx/geometry/point_f.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/native_widget_types.h"
#include "ui/ozone/common/features.h"
#include "ui/ozone/platform/wayland/common/wayland_util.h"
#include "ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
#include "ui/ozone/platform/wayland/host/wayland_cursor_position.h"
+#include "ui/ozone/platform/wayland/host/wayland_data_drag_controller.h"
+#include "ui/ozone/platform/wayland/host/wayland_event_source.h"
#include "ui/ozone/platform/wayland/host/wayland_output_manager.h"
#include "ui/ozone/platform/wayland/host/wayland_pointer.h"
#include "ui/ozone/platform/wayland/host/wayland_subsurface.h"
#include "ui/ozone/platform/wayland/host/wayland_zcr_cursor_shapes.h"
#include "ui/ozone/public/mojom/wayland/wayland_overlay_config.mojom.h"
+#include "ui/platform_window/wm/wm_drag_handler.h"
+#include "ui/platform_window/wm/wm_drop_handler.h"
namespace {
@@ -42,9 +52,13 @@ WaylandWindow::WaylandWindow(PlatformWindowDelegate* delegate,
WaylandConnection* connection)
: delegate_(delegate),
connection_(connection),
- wayland_overlay_delegation_enabled_(IsWaylandOverlayDelegationEnabled()),
+ wayland_overlay_delegation_enabled_(connection->viewporter() &&
+ IsWaylandOverlayDelegationEnabled()),
accelerated_widget_(
- connection->wayland_window_manager()->AllocateAcceleratedWidget()) {}
+ connection->wayland_window_manager()->AllocateAcceleratedWidget()) {
+ // Set a class property key, which allows |this| to be used for drag action.
+ SetWmDragHandler(this, this);
+}
WaylandWindow::~WaylandWindow() {
shutting_down_ = true;
@@ -97,11 +111,11 @@ void WaylandWindow::UpdateBufferScale(bool update_bounds) {
else
ui_scale_ = display.device_scale_factor();
}
- // At this point, buffer_scale() still returns the old scale.
- if (update_bounds)
- SetBoundsDip(gfx::ScaleToRoundedRect(bounds_px_, 1.0 / buffer_scale()));
-
+ int32_t old_scale = buffer_scale();
root_surface_->SetBufferScale(new_scale, update_bounds);
+ // We need to keep DIP size of the window the same whenever the scale changes.
+ if (update_bounds)
+ SetBoundsDip(gfx::ScaleToRoundedRect(bounds_px_, 1.0 / old_scale));
}
gfx::AcceleratedWidget WaylandWindow::GetWidget() const {
@@ -115,14 +129,46 @@ void WaylandWindow::SetPointerFocus(bool focus) {
// cursor. Otherwise, it is invalidated whenever the pointer leaves the
// surface and is not restored by the Wayland compositor.
if (has_pointer_focus_ && bitmap_) {
- // Translate physical pixels to DIPs.
- gfx::Point hotspot_in_dips =
- gfx::ScaleToRoundedPoint(bitmap_->hotspot(), 1.0f / ui_scale_);
- connection_->SetCursorBitmap(bitmap_->bitmaps(), hotspot_in_dips,
- buffer_scale());
+ // Check for theme-provided cursor.
+ if (bitmap_->platform_data()) {
+ connection_->SetPlatformCursor(
+ reinterpret_cast<wl_cursor*>(bitmap_->platform_data()),
+ buffer_scale());
+ } else {
+ // Translate physical pixels to DIPs.
+ gfx::Point hotspot_in_dips =
+ gfx::ScaleToRoundedPoint(bitmap_->hotspot(), 1.0f / ui_scale_);
+ connection_->SetCursorBitmap(bitmap_->bitmaps(), hotspot_in_dips,
+ buffer_scale());
+ }
}
}
+bool WaylandWindow::StartDrag(const ui::OSExchangeData& data,
+ int operation,
+ gfx::NativeCursor cursor,
+ bool can_grab_pointer,
+ WmDragHandler::Delegate* delegate) {
+ DCHECK(!drag_handler_delegate_);
+ drag_handler_delegate_ = delegate;
+ connection()->data_drag_controller()->StartSession(data, operation);
+
+ base::RunLoop drag_loop(base::RunLoop::Type::kNestableTasksAllowed);
+ drag_loop_quit_closure_ = drag_loop.QuitClosure();
+
+ auto alive = weak_ptr_factory_.GetWeakPtr();
+ drag_loop.Run();
+ if (!alive)
+ return false;
+ return true;
+}
+
+void WaylandWindow::CancelDrag() {
+ if (drag_loop_quit_closure_.is_null())
+ return;
+ std::move(drag_loop_quit_closure_).Run();
+}
+
void WaylandWindow::Show(bool inactive) {
if (background_buffer_id_ != 0u)
should_attach_background_buffer_ = true;
@@ -141,14 +187,18 @@ bool WaylandWindow::IsVisible() const {
return false;
}
-void WaylandWindow::PrepareForShutdown() {}
+void WaylandWindow::PrepareForShutdown() {
+ if (drag_handler_delegate_)
+ OnDragSessionClose(DragDropTypes::DRAG_NONE);
+}
void WaylandWindow::SetBounds(const gfx::Rect& bounds_px) {
if (bounds_px_ == bounds_px)
return;
bounds_px_ = bounds_px;
- root_surface_->SetOpaqueRegion(bounds_px);
+ if (update_visual_size_immediately_)
+ UpdateVisualSize(bounds_px.size());
delegate_->OnBoundsChanged(bounds_px_);
}
@@ -194,22 +244,20 @@ PlatformWindowState WaylandWindow::GetPlatformWindowState() const {
return PlatformWindowState::kNormal;
}
-void WaylandWindow::Activate() {
- NOTIMPLEMENTED_LOG_ONCE();
-}
+void WaylandWindow::Activate() {}
void WaylandWindow::Deactivate() {
NOTIMPLEMENTED_LOG_ONCE();
}
void WaylandWindow::SetUseNativeFrame(bool use_native_frame) {
- // See comment below in ShouldUseNativeFrame.
- NOTIMPLEMENTED_LOG_ONCE();
+ // Do nothing here since only shell surfaces can handle server-side
+ // decoration.
}
bool WaylandWindow::ShouldUseNativeFrame() const {
- // This depends on availability of XDG-Decoration protocol extension.
- NOTIMPLEMENTED_LOG_ONCE();
+ // Always returns false here since only shell surfaces can handle server-side
+ // decoration.
return false;
}
@@ -227,6 +275,12 @@ void WaylandWindow::SetCursor(PlatformCursor cursor) {
buffer_scale());
return;
}
+ // Check for theme-provided cursor.
+ if (bitmap_->platform_data()) {
+ connection_->SetPlatformCursor(
+ reinterpret_cast<wl_cursor*>(bitmap_->platform_data()), buffer_scale());
+ return;
+ }
// Check for Wayland server-side cursor support (e.g. exo for lacros).
if (connection_->zcr_cursor_shapes()) {
base::Optional<int32_t> shape =
@@ -282,6 +336,10 @@ void WaylandWindow::SetWindowIcons(const gfx::ImageSkia& window_icon,
void WaylandWindow::SizeConstraintsChanged() {}
+bool WaylandWindow::ShouldUseLayerForShapedWindow() const {
+ return true;
+}
+
bool WaylandWindow::CanDispatchEvent(const PlatformEvent& event) {
if (event->IsMouseEvent())
return has_pointer_focus_;
@@ -304,6 +362,7 @@ uint32_t WaylandWindow::DispatchEvent(const PlatformEvent& native_event) {
// Wayland sends locations in DIP so they need to be translated to
// physical pixels.
+ UpdateCursorPositionFromEvent(Event::Clone(*event));
event->AsLocatedEvent()->set_location_f(gfx::ScalePoint(
event->AsLocatedEvent()->location_f(), buffer_scale(), buffer_scale()));
@@ -333,36 +392,98 @@ uint32_t WaylandWindow::DispatchEvent(const PlatformEvent& native_event) {
return DispatchEventToDelegate(native_event);
}
-void WaylandWindow::HandleSurfaceConfigure(int32_t widht,
- int32_t height,
- bool is_maximized,
- bool is_fullscreen,
- bool is_activated) {
+void WaylandWindow::HandleSurfaceConfigure(uint32_t serial) {
NOTREACHED()
<< "Only shell surfaces must receive HandleSurfaceConfigure calls.";
}
+void WaylandWindow::HandleToplevelConfigure(int32_t widht,
+ int32_t height,
+ bool is_maximized,
+ bool is_fullscreen,
+ bool is_activated) {
+ NOTREACHED()
+ << "Only shell toplevels must receive HandleToplevelConfigure calls.";
+}
+
void WaylandWindow::HandlePopupConfigure(const gfx::Rect& bounds_dip) {
NOTREACHED() << "Only shell popups must receive HandlePopupConfigure calls.";
}
+void WaylandWindow::UpdateVisualSize(const gfx::Size& size_px) {
+ visual_size_px_ = size_px;
+ UpdateWindowMask();
+}
+
void WaylandWindow::OnCloseRequest() {
delegate_->OnCloseRequest();
}
+base::Optional<std::vector<gfx::Rect>> WaylandWindow::GetWindowShape() const {
+ return base::nullopt;
+}
+
+void WaylandWindow::UpdateWindowMask() {
+ UpdateWindowShape();
+ root_surface_->SetOpaqueRegion(gfx::Rect(visual_size_px()));
+}
+
+void WaylandWindow::UpdateWindowShape() {}
+
void WaylandWindow::OnDragEnter(const gfx::PointF& point,
std::unique_ptr<OSExchangeData> data,
- int operation) {}
+ int operation) {
+ WmDropHandler* drop_handler = GetWmDropHandler(*this);
+ if (!drop_handler)
+ return;
+
+ auto location_px = gfx::ScalePoint(TranslateLocationToRootWindow(point),
+ buffer_scale(), buffer_scale());
+
+ // Wayland sends locations in DIP so they need to be translated to
+ // physical pixels.
+ // TODO(crbug.com/1102857): get the real event modifier here.
+ drop_handler->OnDragEnter(location_px, std::move(data), operation,
+ /*modifiers=*/0);
+}
int WaylandWindow::OnDragMotion(const gfx::PointF& point, int operation) {
- return -1;
+ WmDropHandler* drop_handler = GetWmDropHandler(*this);
+ if (!drop_handler)
+ return 0;
+
+ auto location_px = gfx::ScalePoint(TranslateLocationToRootWindow(point),
+ buffer_scale(), buffer_scale());
+
+ // Wayland sends locations in DIP so they need to be translated to
+ // physical pixels.
+ // TODO(crbug.com/1102857): get the real event modifier here.
+ return drop_handler->OnDragMotion(location_px, operation,
+ /*modifiers=*/0);
}
-void WaylandWindow::OnDragDrop(std::unique_ptr<OSExchangeData> data) {}
+void WaylandWindow::OnDragDrop() {
+ WmDropHandler* drop_handler = GetWmDropHandler(*this);
+ if (!drop_handler)
+ return;
+ // TODO(crbug.com/1102857): get the real event modifier here.
+ drop_handler->OnDragDrop({}, /*modifiers=*/0);
+}
-void WaylandWindow::OnDragLeave() {}
+void WaylandWindow::OnDragLeave() {
+ WmDropHandler* drop_handler = GetWmDropHandler(*this);
+ if (!drop_handler)
+ return;
+ drop_handler->OnDragLeave();
+}
-void WaylandWindow::OnDragSessionClose(uint32_t dnd_action) {}
+void WaylandWindow::OnDragSessionClose(uint32_t dnd_action) {
+ DCHECK(drag_handler_delegate_);
+ drag_handler_delegate_->OnDragFinished(dnd_action);
+ drag_handler_delegate_ = nullptr;
+ connection()->event_source()->ResetPointerFlags();
+ std::move(drag_loop_quit_closure_).Run();
+}
void WaylandWindow::SetBoundsDip(const gfx::Rect& bounds_dip) {
SetBounds(gfx::ScaleToRoundedRect(bounds_dip, buffer_scale()));
@@ -403,7 +524,7 @@ bool WaylandWindow::Initialize(PlatformWindowInitProperties properties) {
// Will do nothing for menus because they have got their scale above.
UpdateBufferScale(false);
- root_surface_->SetOpaqueRegion(bounds_px_);
+ root_surface_->SetOpaqueRegion(gfx::Rect(bounds_px_.size()));
return true;
}
@@ -416,7 +537,7 @@ void WaylandWindow::AddEnteredOutputId(struct wl_output* output) {
// Wayland does weird things for menus so instead of tracking outputs that
// we entered or left, we take that from the parent window and ignore this
// event.
- if (wl::IsMenuType(type()))
+ if (wl::IsMenuType(type()) || type() == ui::PlatformWindowType::kTooltip)
return;
const uint32_t entered_output_id =
@@ -480,8 +601,16 @@ void WaylandWindow::UpdateCursorPositionFromEvent(
}
}
-WaylandWindow* WaylandWindow::GetTopLevelWindow() {
- return parent_window_ ? parent_window_->GetTopLevelWindow() : this;
+gfx::PointF WaylandWindow::TranslateLocationToRootWindow(
+ const gfx::PointF& location) {
+ auto* root_window = GetRootParentWindow();
+ DCHECK(root_window);
+ if (root_window == this)
+ return location;
+
+ gfx::Vector2d offset =
+ GetBounds().origin() - root_window->GetBounds().origin();
+ return location + gfx::Vector2dF(offset);
}
WaylandWindow* WaylandWindow::GetTopMostChildWindow() {
@@ -499,10 +628,6 @@ bool WaylandWindow::IsActive() const {
uint32_t WaylandWindow::DispatchEventToDelegate(
const PlatformEvent& native_event) {
- auto* event = static_cast<Event*>(native_event);
- if (event->IsLocatedEvent())
- UpdateCursorPositionFromEvent(Event::Clone(*event));
-
bool handled = DispatchEventFromNativeUiEvent(
native_event, base::BindOnce(&PlatformWindowDelegate::DispatchEvent,
base::Unretained(delegate_)));
@@ -584,6 +709,9 @@ bool WaylandWindow::CommitOverlays(
if (!ArrangeSubsurfaceStack(above, below))
return false;
+ if (wayland_overlay_delegation_enabled_)
+ connection_->buffer_manager_host()->StartFrame(root_surface());
+
{
// Iterate through |subsurface_stack_below_|, setup subsurfaces and place
// them in corresponding order. Commit wl_buffers once a subsurface is
@@ -608,7 +736,9 @@ bool WaylandWindow::CommitOverlays(
nullptr, reference_above);
connection_->buffer_manager_host()->CommitBufferInternal(
(*iter)->wayland_surface(), (*overlay_iter)->buffer_id, gfx::Rect(),
- /*wait_for_frame_callback=*/false);
+ /*wait_for_frame_callback=*/true,
+ /*commit_synced_subsurface=*/true,
+ std::move((*overlay_iter)->access_fence_handle));
} else {
// If there're more subsurfaces requested that we don't need at the
// moment, hide them.
@@ -637,7 +767,9 @@ bool WaylandWindow::CommitOverlays(
reference_below, nullptr);
connection_->buffer_manager_host()->CommitBufferInternal(
(*iter)->wayland_surface(), (*overlay_iter)->buffer_id, gfx::Rect(),
- /*wait_for_frame_callback=*/false);
+ /*wait_for_frame_callback=*/true,
+ /*commit_synced_subsurface=*/true,
+ std::move((*overlay_iter)->access_fence_handle));
} else {
// If there're more subsurfaces requested that we don't need at the
// moment, hide them.
@@ -646,7 +778,13 @@ bool WaylandWindow::CommitOverlays(
}
}
+ if (!num_primary_planes && overlays.front()->z_order == INT32_MIN)
+ split = overlays.begin();
+ UpdateVisualSize((*split)->bounds_rect.size());
+ root_surface_->SetViewportDestination(visual_size_px_);
+
if (!wayland_overlay_delegation_enabled_) {
+ root_surface_->SetViewportSource((*split)->crop_rect);
connection_->buffer_manager_host()->CommitBufferInternal(
root_surface(), (*split)->buffer_id, (*split)->damage_region,
/*wait_for_frame_callback=*/true);
@@ -659,26 +797,27 @@ bool WaylandWindow::CommitOverlays(
(*split)->enable_blend, nullptr, nullptr);
connection_->buffer_manager_host()->CommitBufferInternal(
primary_subsurface_->wayland_surface(), (*split)->buffer_id,
- (*split)->damage_region, /*wait_for_frame_callback=*/false);
+ (*split)->damage_region,
+ /*wait_for_frame_callback=*/true,
+ /*commit_synced_subsurface=*/true,
+ std::move((*split)->access_fence_handle));
}
- root_surface_->SetViewportDestination(bounds_px_.size());
-
+ gfx::Rect background_damage;
if (overlays.front()->z_order == INT32_MIN) {
background_buffer_id_ = overlays.front()->buffer_id;
+ background_damage = overlays.front()->damage_region;
should_attach_background_buffer_ = true;
}
if (should_attach_background_buffer_) {
- connection_->buffer_manager_host()->CommitBufferInternal(
- root_surface(), background_buffer_id_, /*damage_region=*/gfx::Rect(),
- /*wait_for_frame_callback=*/true);
+ connection_->buffer_manager_host()->EndFrame(background_buffer_id_,
+ background_damage);
should_attach_background_buffer_ = false;
} else {
// Subsurfaces are set to sync, above surface configs will only take effect
// when root_surface is committed.
- connection_->buffer_manager_host()->CommitWithoutBufferInternal(
- root_surface(), /*wait_for_frame_callback=*/true);
+ connection_->buffer_manager_host()->EndFrame();
}
return true;
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window.h b/chromium/ui/ozone/platform/wayland/host/wayland_window.h
index e719914fdd4..8bcc007f766 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_window.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window.h
@@ -15,6 +15,7 @@
#include "base/gtest_prod_util.h"
#include "base/memory/ref_counted.h"
#include "ui/events/platform/platform_event_dispatcher.h"
+#include "ui/gfx/geometry/point_f.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/ozone/platform/wayland/common/wayland_object.h"
@@ -23,10 +24,7 @@
#include "ui/platform_window/platform_window.h"
#include "ui/platform_window/platform_window_delegate.h"
#include "ui/platform_window/platform_window_init_properties.h"
-
-namespace gfx {
-class PointF;
-}
+#include "ui/platform_window/wm/wm_drag_handler.h"
namespace ui {
@@ -38,7 +36,9 @@ class WaylandWindowDragController;
using WidgetSubsurfaceSet = base::flat_set<std::unique_ptr<WaylandSubsurface>>;
-class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
+class WaylandWindow : public PlatformWindow,
+ public PlatformEventDispatcher,
+ public WmDragHandler {
public:
~WaylandWindow() override;
@@ -111,6 +111,21 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
// Returns current type of the window.
PlatformWindowType type() const { return type_; }
+ gfx::Size visual_size_px() const { return visual_size_px_; }
+
+ // This is never intended to be used except in unit tests.
+ void set_update_visual_size_immediately(bool update_immediately) {
+ update_visual_size_immediately_ = update_immediately;
+ }
+
+ // WmDragHandler
+ bool StartDrag(const ui::OSExchangeData& data,
+ int operation,
+ gfx::NativeCursor cursor,
+ bool can_grab_pointer,
+ WmDragHandler::Delegate* delegate) override;
+ void CancelDrag() override;
+
// PlatformWindow
void Show(bool inactive) override;
void Hide() override;
@@ -142,6 +157,7 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
void SetWindowIcons(const gfx::ImageSkia& window_icon,
const gfx::ImageSkia& app_icon) override;
void SizeConstraintsChanged() override;
+ bool ShouldUseLayerForShapedWindow() const override;
// PlatformEventDispatcher
bool CanDispatchEvent(const PlatformEvent& event) override;
@@ -150,12 +166,14 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
// Handles the configuration events coming from the shell objects.
// The width and height come in DIP of the output that the surface is
// currently bound to.
- virtual void HandleSurfaceConfigure(int32_t widht,
- int32_t height,
- bool is_maximized,
- bool is_fullscreen,
- bool is_activated);
+ virtual void HandleSurfaceConfigure(uint32_t serial);
+ virtual void HandleToplevelConfigure(int32_t widht,
+ int32_t height,
+ bool is_maximized,
+ bool is_fullscreen,
+ bool is_activated);
virtual void HandlePopupConfigure(const gfx::Rect& bounds);
+ virtual void UpdateVisualSize(const gfx::Size& size_px);
// Handles close requests.
virtual void OnCloseRequest();
@@ -165,10 +183,12 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
std::unique_ptr<OSExchangeData> data,
int operation);
virtual int OnDragMotion(const gfx::PointF& point, int operation);
- virtual void OnDragDrop(std::unique_ptr<OSExchangeData> data);
+ virtual void OnDragDrop();
virtual void OnDragLeave();
virtual void OnDragSessionClose(uint32_t dnd_action);
+ virtual base::Optional<std::vector<gfx::Rect>> GetWindowShape() const;
+
// Returns a root parent window within the same hierarchy.
WaylandWindow* GetRootParentWindow();
@@ -203,6 +223,9 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
void set_ui_scale(int32_t ui_scale) { ui_scale_ = ui_scale; }
+ // Calls set_opaque_region for this window.
+ virtual void UpdateWindowMask();
+
private:
FRIEND_TEST_ALL_PREFIXES(WaylandScreenTest, SetBufferScale);
@@ -211,13 +234,15 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
void UpdateCursorPositionFromEvent(std::unique_ptr<Event> event);
- WaylandWindow* GetTopLevelWindow();
+ gfx::PointF TranslateLocationToRootWindow(const gfx::PointF& location);
uint32_t DispatchEventToDelegate(const PlatformEvent& native_event);
// Additional initialization of derived classes.
virtual bool OnInitialize(PlatformWindowInitProperties properties) = 0;
+ virtual void UpdateWindowShape();
+
// WaylandWindowDragController might need to take ownership of the wayland
// surface whether the window that originated the DND session gets destroyed
// in the middle of that session (e.g: when it is snapped into a tab strip).
@@ -253,10 +278,23 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
// The current cursor bitmap (immutable).
scoped_refptr<BitmapCursorOzone> bitmap_;
- // Current bounds of the platform window.
+ // Current bounds of the platform window. This is either initialized, or the
+ // requested size by the Wayland compositor. When this is set in SetBounds(),
+ // delegate_->OnBoundsChanged() is called and updates current_surface_size in
+ // Viz. However, it is not guaranteed that the next arriving frame will match
+ // |bounds_px_|.
gfx::Rect bounds_px_;
// The bounds of the platform window before it went maximized or fullscreen.
gfx::Rect restored_bounds_px_;
+ // The size presented by the gpu process. This is the visible size of the
+ // window, which can be different from |bounds_px_| due to renderers taking
+ // time to produce a compositor frame.
+ // The rough flow of size changes:
+ // Wayland compositor -> xdg_surface.configure()
+ // -> WaylandWindow::SetBounds() -> IPC -> DisplayPrivate::Resize()
+ // -> OutputSurface::SwapBuffers() -> WaylandWindow::UpdateVisualSize()
+ // -> xdg_surface.ack_configure() -> Wayland compositor.
+ gfx::Size visual_size_px_;
bool has_pointer_focus_ = false;
bool has_keyboard_focus_ = false;
@@ -285,9 +323,21 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
// Set when the window enters in shutdown process.
bool shutting_down_ = false;
+ // In a non-test environment, a frame update makes a SetBounds() change
+ // visible in |visual_size_px_|, but in some unit tests there will never be
+ // any frame updates. This flag causes UpdateVisualSize() to be invoked during
+ // SetBounds() in unit tests.
+ bool update_visual_size_immediately_ = false;
+
// AcceleratedWidget for this window. This will be unique even over time.
gfx::AcceleratedWidget accelerated_widget_;
+ WmDragHandler::Delegate* drag_handler_delegate_ = nullptr;
+
+ base::OnceClosure drag_loop_quit_closure_;
+
+ base::WeakPtrFactory<WaylandWindow> weak_ptr_factory_{this};
+
DISALLOW_COPY_AND_ASSIGN(WaylandWindow);
};
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.cc b/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.cc
index 05f6bcc2ec7..3431631b596 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.cc
@@ -36,7 +36,6 @@
#include "ui/ozone/platform/wayland/host/wayland_data_device_manager.h"
#include "ui/ozone/platform/wayland/host/wayland_data_offer.h"
#include "ui/ozone/platform/wayland/host/wayland_data_source.h"
-#include "ui/ozone/platform/wayland/host/wayland_event_source.h"
#include "ui/ozone/platform/wayland/host/wayland_pointer.h"
#include "ui/ozone/platform/wayland/host/wayland_surface.h"
#include "ui/ozone/platform/wayland/host/wayland_window.h"
@@ -142,11 +141,14 @@ bool WaylandWindowDragController::Drag(WaylandToplevelWindow* window,
RunLoop();
SetDraggedWindow(nullptr, {});
- DCHECK(state_ == State::kAttached || state_ == State::kDropped);
- bool dropped = state_ == State::kDropped;
- if (dropped)
- HandleDropAndResetState();
- return dropped;
+ DCHECK(state_ == State::kAttaching || state_ == State::kDropped);
+ if (state_ == State::kAttaching) {
+ state_ = State::kAttached;
+ return false;
+ }
+
+ HandleDropAndResetState();
+ return true;
}
void WaylandWindowDragController::StopDragging() {
@@ -158,7 +160,7 @@ void WaylandWindowDragController::StopDragging() {
// This function is supposed to be called to indicate that the window was just
// snapped into a tab strip. So switch to |kAttached| state, store the focused
// window as the pointer grabber and ask to quit the nested loop.
- state_ = State::kAttached;
+ state_ = State::kAttaching;
pointer_grab_owner_ = window_manager_->GetCurrentFocusedWindow();
DCHECK(pointer_grab_owner_);
QuitLoop();
@@ -209,7 +211,7 @@ void WaylandWindowDragController::OnDragEnter(WaylandWindow* window,
DCHECK_EQ(data_offer_->mime_types().front(), kMimeTypeChromiumWindow);
// Accept the offer and set the dnd action.
- data_offer_->SetAction(kDndActionWindowDrag, kDndActionWindowDrag);
+ data_offer_->SetActions(kDndActionWindowDrag);
data_offer_->Accept(serial, kMimeTypeChromiumWindow);
}
@@ -217,6 +219,11 @@ void WaylandWindowDragController::OnDragMotion(const gfx::PointF& location) {
DCHECK_GE(state_, State::kAttached);
VLOG(2) << "OnMotion. location=" << location.ToString();
+ // Motion events are not expected to be dispatched while waiting for the drag
+ // loop to exit, ie: kAttaching transitional state. See crbug.com/1169446.
+ if (state_ == State::kAttaching)
+ return;
+
// Forward cursor location update info to the input handling delegate.
should_process_drag_event_ = true;
pointer_location_ = location;
@@ -225,7 +232,6 @@ void WaylandWindowDragController::OnDragMotion(const gfx::PointF& location) {
void WaylandWindowDragController::OnDragLeave() {
DCHECK_GE(state_, State::kAttached);
- DCHECK_LE(state_, State::kDetached);
// In order to guarantee ET_MOUSE_RELEASED event is delivered once the DND
// session finishes, the focused window is not reset here. This is similar to
@@ -324,8 +330,6 @@ uint32_t WaylandWindowDragController::DispatchEvent(
DCHECK_EQ(state_, State::kDetached);
DCHECK(base::CurrentUIThread::IsSet());
- VLOG(2) << "Dispatch. event=" << event->GetName();
-
if (event->type() == ET_MOUSE_MOVED || event->type() == ET_MOUSE_DRAGGED) {
HandleMotionEvent(event->AsMouseEvent());
return POST_DISPATCH_STOP_PROPAGATION;
@@ -348,7 +352,6 @@ void WaylandWindowDragController::OnToplevelWindowCreated(
<< " calculated_offset=" << offset.ToString();
SetDraggedWindow(window, offset);
- state_ = State::kDetached;
}
void WaylandWindowDragController::OnWindowRemoved(WaylandWindow* window) {
@@ -395,7 +398,6 @@ void WaylandWindowDragController::HandleDropAndResetState() {
VLOG(1) << "Notifying drop. window=" << pointer_grab_owner_;
EventFlags pointer_button = EF_LEFT_MOUSE_BUTTON;
- DCHECK(connection_->event_source()->IsPointerButtonPressed(pointer_button));
pointer_delegate_->OnPointerButtonEvent(ET_MOUSE_RELEASED, pointer_button,
pointer_grab_owner_);
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.h b/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.h
index 94dae03f336..96da9124b5c 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.h
@@ -46,10 +46,11 @@ class WaylandWindowDragController : public WaylandDataDevice::DragDelegate,
public:
// Constants used to keep track of the drag controller state.
enum class State {
- kIdle, // No DnD session nor drag loop running.
- kAttached, // DnD session ongoing but no drag loop running.
- kDetached, // Drag loop running. ie: blocked in a Drag() call.
- kDropped // Drop event was just received.
+ kIdle, // No DnD session nor drag loop running.
+ kAttached, // DnD session ongoing but no drag loop running.
+ kDetached, // Drag loop running. ie: blocked in a Drag() call.
+ kDropped, // Drop event was just received.
+ kAttaching, // About to transition back to |kAttached|.
};
WaylandWindowDragController(WaylandConnection* connection,
@@ -153,8 +154,10 @@ class WaylandWindowDragController : public WaylandDataDevice::DragDelegate,
std::unique_ptr<ScopedEventDispatcher> nested_dispatcher_;
base::OnceClosure quit_loop_closure_;
- // Tells if the current drag event should be processedc. E.g: received through
- // wl_data_device::motion wayland event.
+ // Tells if the current drag event should be processed. Buggy compositors may
+ // send wl_pointer::motion events, for example, while a DND session is still
+ // in progress, which leads to issues in window dragging sessions, this flag
+ // is used to make window drag controller resistant to such scenarios.
bool should_process_drag_event_ = false;
base::WeakPtrFactory<WaylandWindowDragController> weak_factory_{this};
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller_unittest.cc
index db3944812a3..79f66eb7db1 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller_unittest.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller_unittest.cc
@@ -10,6 +10,7 @@
#include <cstdint>
+#include "base/bind.h"
#include "base/notreached.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/base_event_utils.h"
@@ -30,7 +31,7 @@
#include "ui/ozone/platform/wayland/test/test_data_offer.h"
#include "ui/ozone/platform/wayland/test/test_data_source.h"
#include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h"
-#include "ui/ozone/platform/wayland/test/wayland_test.h"
+#include "ui/ozone/platform/wayland/test/wayland_drag_drop_test.h"
#include "ui/ozone/test/mock_platform_window_delegate.h"
#include "ui/platform_window/extensions/wayland_extension.h"
#include "ui/platform_window/platform_window_delegate.h"
@@ -41,14 +42,14 @@ using testing::Mock;
namespace ui {
-class WaylandWindowDragControllerTest : public WaylandTest,
- public wl::TestDataDevice::Delegate {
+class WaylandWindowDragControllerTest : public WaylandDragDropTest {
public:
WaylandWindowDragControllerTest() = default;
~WaylandWindowDragControllerTest() override = default;
void SetUp() override {
- WaylandTest::SetUp();
+ WaylandDragDropTest::SetUp();
+
screen_ = std::make_unique<WaylandScreen>(connection_.get());
wl_seat_send_capabilities(server_.seat()->resource(),
@@ -59,16 +60,6 @@ class WaylandWindowDragControllerTest : public WaylandTest,
EXPECT_FALSE(window_->has_pointer_focus());
EXPECT_EQ(State::kIdle, drag_controller()->state());
-
- data_device_manager_ = server_.data_device_manager();
- DCHECK(data_device_manager_);
-
- source_ = nullptr;
- data_device_manager_->data_device()->set_delegate(this);
- }
-
- void TearDown() override {
- data_device_manager_->data_device()->set_delegate(nullptr);
}
WaylandWindowDragController* drag_controller() const {
@@ -79,52 +70,11 @@ class WaylandWindowDragControllerTest : public WaylandTest,
return connection_->wayland_window_manager();
}
- uint32_t NextSerial() const {
- static uint32_t serial = 0;
- return ++serial;
- }
-
- uint32_t NextTime() const {
- static uint32_t timestamp = 0;
- return ++timestamp;
- }
+ MockPlatformWindowDelegate& delegate() { return delegate_; }
protected:
using State = WaylandWindowDragController::State;
- // wl::TestDataDevice::Delegate:
- void StartDrag(wl::TestDataSource* source,
- wl::MockSurface* origin,
- uint32_t serial) override {
- EXPECT_FALSE(source_);
- source_ = source;
- OfferAndEnter(origin);
- }
-
- // Helper functions
- void SendDndMotion(const gfx::Point& location) {
- EXPECT_TRUE(source_);
- wl_fixed_t x = wl_fixed_from_int(location.x());
- wl_fixed_t y = wl_fixed_from_int(location.y());
- data_device_manager_->data_device()->OnMotion(NextTime(), x, y);
- }
-
- void SendDndEnter(WaylandWindow* window) {
- EXPECT_TRUE(window);
- OfferAndEnter(server_.GetObject<wl::MockSurface>(
- window->root_surface()->GetSurfaceId()));
- }
-
- void SendDndLeave() {
- EXPECT_TRUE(source_);
- data_device_manager_->data_device()->OnLeave();
- }
-
- void SendDndDrop() {
- EXPECT_TRUE(source_);
- source_->OnCancelled();
- }
-
void SendPointerEnter(WaylandWindow* window,
MockPlatformWindowDelegate* delegate) {
auto* surface = server_.GetObject<wl::MockSurface>(
@@ -181,24 +131,17 @@ class WaylandWindowDragControllerTest : public WaylandTest,
screen_->GetLocalProcessWidgetAtPoint(location, {}));
}
- void OfferAndEnter(wl::MockSurface* surface) {
- EXPECT_TRUE(source_);
- auto* data_device = data_device_manager_->data_device();
- auto* offer = data_device->OnDataOffer();
- EXPECT_EQ(1u, source_->mime_types().size());
- for (const auto& mime_type : source_->mime_types())
- offer->OnOffer(mime_type, {});
-
- wl_data_device_send_enter(data_device->resource(), NextSerial(),
- surface->resource(), 0, 0, offer->resource());
- }
+ // For the context of window drag, "drop" is detected through
+ // wl_data_source::cancelled in the regular case. Unless extended-drag
+ // protocol is available.
+ //
+ // TODO(crbug.com/1116431): Support extended-drag in test compositor.
+ void SendDndDrop() { SendDndCancelled(); }
// client objects
std::unique_ptr<WaylandScreen> screen_;
// server objects
- wl::TestDataDeviceManager* data_device_manager_;
- wl::TestDataSource* source_;
wl::MockPointer* pointer_;
};
@@ -471,7 +414,7 @@ TEST_P(WaylandWindowDragControllerTest, DragToOtherWindowSnapDragDrop) {
// Exit |source_window| and enter the |target_window|.
SendDndLeave();
- SendDndEnter(target_window);
+ SendDndEnter(target_window, {});
test_step = kEnteredTarget;
});
@@ -723,6 +666,65 @@ TEST_P(WaylandWindowDragControllerTest, IgnorePointerEventsUntilDrop) {
screen_->GetLocalProcessWidgetAtPoint({20, 20}, {}));
}
+// Regression test for https://crbug.com/1169446.
+TEST_P(WaylandWindowDragControllerTest, MotionEventsSkippedWhileReattaching) {
+ auto* dragged_window = window_.get();
+ EXPECT_TRUE(dragged_window);
+
+ SendPointerEnter(dragged_window, &delegate_);
+ SendPointerPress(dragged_window, &delegate_, BTN_LEFT);
+ SendPointerMotion(dragged_window, &delegate_, {10, 10});
+
+ auto* wayland_extension = GetWaylandExtension(*window_);
+ wayland_extension->StartWindowDraggingSessionIfNeeded();
+ EXPECT_EQ(State::kAttached, drag_controller()->state());
+
+ auto* move_loop_handler = GetWmMoveLoopHandler(*window_);
+ ASSERT_TRUE(move_loop_handler);
+
+ auto test = [](WaylandWindowDragControllerTest* self,
+ WmMoveLoopHandler* move_loop_handler) {
+ // While in |kDetached| state, motion events are expected to be propagated
+ // by window drag controller.
+ EXPECT_EQ(State::kDetached, self->drag_controller()->state());
+ self->SendDndMotion({30, 30});
+ EXPECT_CALL(self->delegate(), DispatchEvent(_)).Times(1);
+ self->Sync();
+
+ move_loop_handler->EndMoveLoop();
+ self->Sync();
+
+ // Otherwise, after the move loop is requested to quit, but before it really
+ // ends (ie. kAttaching state), motion events are **not** expected to be
+ // propagated.
+ EXPECT_EQ(State::kAttaching, self->drag_controller()->state());
+ self->SendDndMotion({30, 30});
+ EXPECT_CALL(self->delegate(), DispatchEvent(_)).Times(0);
+ self->Sync();
+ };
+ ScheduleTestTask(base::BindOnce(test, base::Unretained(this),
+ base::Unretained(move_loop_handler)));
+
+ // Spins move loop for |window_1|.
+ move_loop_handler->RunMoveLoop({});
+
+ // When the transition to |kAttached| state is finally done (ie. nested loop
+ // quits), motion events are then expected to be propagated by window drag
+ // controller as usual.
+ EXPECT_EQ(State::kAttached, drag_controller()->state());
+ SendDndMotion({30, 30});
+ EXPECT_CALL(delegate(), DispatchEvent(_)).Times(1);
+ Sync();
+
+ SendDndDrop();
+ EXPECT_CALL(delegate(), DispatchEvent(_)).Times(1);
+ Sync();
+
+ SendPointerEnter(window_.get(), &delegate_);
+
+ EXPECT_EQ(State::kIdle, drag_controller()->state());
+}
+
INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
WaylandWindowDragControllerTest,
::testing::Values(kXdgShellStable));
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window_factory.cc b/chromium/ui/ozone/platform/wayland/host/wayland_window_factory.cc
index 7cca6ba6a82..90f2b76a2b0 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_window_factory.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_factory.cc
@@ -4,12 +4,14 @@
#include <memory>
+#include "base/compiler_specific.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/ozone/platform/wayland/host/wayland_auxiliary_window.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
#include "ui/ozone/platform/wayland/host/wayland_popup.h"
#include "ui/ozone/platform/wayland/host/wayland_toplevel_window.h"
#include "ui/ozone/platform/wayland/host/wayland_window.h"
+#include "ui/platform_window/platform_window_init_properties.h"
namespace ui {
@@ -20,32 +22,32 @@ std::unique_ptr<WaylandWindow> WaylandWindow::Create(
PlatformWindowInitProperties properties) {
std::unique_ptr<WaylandWindow> window;
switch (properties.type) {
- case PlatformWindowType::kMenu:
case PlatformWindowType::kPopup:
if (connection->IsDragInProgress()) {
// We are in the process of drag and requested a popup. Most probably,
// it is an arrow window.
window = std::make_unique<WaylandAuxiliaryWindow>(delegate, connection);
+ break;
+ }
+ FALLTHROUGH;
+ case PlatformWindowType::kMenu:
+ // Set the parent window in advance otherwise it is not possible to know
+ // if the popup is able to find one and if WaylandWindow::Initialize()
+ // fails or not. Otherwise, WaylandWindow::Create() returns nullptr and
+ // makes the browser to fail. To fix this problem, search for the parent
+ // window and if one is not found, create WaylandToplevelWindow instead.
+ // It's also worth noting that searching twice (one time here and
+ // another by WaylandPopup) is a bad practice, and the parent window is
+ // set here instead. TODO(crbug.com/1078328): Feed ozone/wayland with full
+ // layout info required to properly position popup windows.
+ if (auto* parent_window =
+ connection->wayland_window_manager()->FindParentForNewWindow(
+ properties.parent_widget)) {
+ window = std::make_unique<WaylandPopup>(delegate, connection);
+ window->set_parent_window(parent_window);
} else {
- auto* parent_window =
- connection->wayland_window_manager()->FindParentForNewWindow(
- properties.parent_widget);
- if (parent_window) {
- // Set the parent window in advance otherwise it is not possible to
- // know if the WaylandPopup is able to find one and if
- // WaylandWindow::Initialize() fails or not. Otherwise,
- // WaylandWindow::Create() returns nullptr and makes the browser to
- // fail. To fix this problem, search for the parent window and if
- // one is not found, create WaylandToplevelWindow instead. It's
- // also worth noting that searching twice (one time here and another
- // by WaylandPopup) is a bad practice, and the parent window is set
- // here instead.
- window = std::make_unique<WaylandPopup>(delegate, connection);
- window->set_parent_window(parent_window);
- } else {
- window =
- std::make_unique<WaylandToplevelWindow>(delegate, connection);
- }
+ DLOG(WARNING) << "Failed to determine for menu/popup window.";
+ window = std::make_unique<WaylandToplevelWindow>(delegate, connection);
}
break;
case PlatformWindowType::kTooltip:
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
index 458f6b5f0a4..f6be452b0a1 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
@@ -34,6 +34,7 @@
#include "ui/ozone/platform/wayland/test/mock_pointer.h"
#include "ui/ozone/platform/wayland/test/mock_surface.h"
#include "ui/ozone/platform/wayland/test/test_keyboard.h"
+#include "ui/ozone/platform/wayland/test/test_output.h"
#include "ui/ozone/platform/wayland/test/test_region.h"
#include "ui/ozone/platform/wayland/test/test_touch.h"
#include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h"
@@ -44,7 +45,9 @@
#include "ui/platform_window/wm/wm_move_resize_handler.h"
using ::testing::_;
+using ::testing::DoAll;
using ::testing::Eq;
+using ::testing::InvokeWithoutArgs;
using ::testing::Mock;
using ::testing::Return;
using ::testing::SaveArg;
@@ -270,6 +273,146 @@ TEST_P(WaylandWindowTest, SetTitle) {
window_->SetTitle(base::ASCIIToUTF16("hello"));
}
+TEST_P(WaylandWindowTest, UpdateVisualSizeConfiguresWaylandWindow) {
+ const auto kNormalBounds = gfx::Rect{0, 0, 500, 300};
+ uint32_t serial = 0;
+ auto state = InitializeWlArrayWithActivatedState();
+
+ window_->set_update_visual_size_immediately(false);
+ auto* mock_surface = server_.GetObject<wl::MockSurface>(
+ window_->root_surface()->GetSurfaceId());
+
+ // Configure event makes Wayland update bounds, but does not change toplevel
+ // input region, opaque region or window geometry immediately. Such actions
+ // are postponed to UpdateVisualSize();
+ EXPECT_CALL(delegate_, OnBoundsChanged(kNormalBounds));
+ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds.width(),
+ kNormalBounds.height()))
+ .Times(0);
+ EXPECT_CALL(*xdg_surface_, AckConfigure(1)).Times(0);
+ EXPECT_CALL(*mock_surface, SetOpaqueRegion(_)).Times(0);
+ EXPECT_CALL(*mock_surface, SetInputRegion(_)).Times(0);
+ SendConfigureEvent(xdg_surface_, kNormalBounds.width(),
+ kNormalBounds.height(), ++serial, state.get());
+
+ Sync();
+
+ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds.width(),
+ kNormalBounds.height()));
+ EXPECT_CALL(*xdg_surface_, AckConfigure(1));
+ EXPECT_CALL(*mock_surface, SetOpaqueRegion(_));
+ EXPECT_CALL(*mock_surface, SetInputRegion(_));
+ window_->UpdateVisualSize(kNormalBounds.size());
+}
+
+TEST_P(WaylandWindowTest, ShuffledUpdateVisualSizeOrder) {
+ const auto kNormalBounds1 = gfx::Rect{0, 0, 500, 300};
+ const auto kNormalBounds2 = gfx::Rect{0, 0, 800, 600};
+ const auto kNormalBounds3 = gfx::Rect{0, 0, 700, 400};
+ uint32_t serial = 1;
+
+ window_->set_update_visual_size_immediately(false);
+
+ // Send 3 configures and only ack the second one, the first pending configure
+ // is cleared. The second can still be ack'ed.
+ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds1.width(),
+ kNormalBounds1.height()))
+ .Times(0);
+ EXPECT_CALL(*xdg_surface_, AckConfigure(2)).Times(0);
+ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds2.width(),
+ kNormalBounds2.height()));
+ EXPECT_CALL(*xdg_surface_, AckConfigure(3));
+ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds3.width(),
+ kNormalBounds3.height()));
+ EXPECT_CALL(*xdg_surface_, AckConfigure(4));
+
+ auto state = InitializeWlArrayWithActivatedState();
+ SendConfigureEvent(xdg_surface_, kNormalBounds1.width(),
+ kNormalBounds1.height(), ++serial, state.get());
+ state = InitializeWlArrayWithActivatedState();
+ SendConfigureEvent(xdg_surface_, kNormalBounds2.width(),
+ kNormalBounds2.height(), ++serial, state.get());
+ state = InitializeWlArrayWithActivatedState();
+ SendConfigureEvent(xdg_surface_, kNormalBounds3.width(),
+ kNormalBounds3.height(), ++serial, state.get());
+ Sync();
+
+ window_->UpdateVisualSize(kNormalBounds2.size());
+ window_->UpdateVisualSize(kNormalBounds1.size());
+ window_->UpdateVisualSize(kNormalBounds3.size());
+}
+
+TEST_P(WaylandWindowTest, MismatchUpdateVisualSize) {
+ const auto kNormalBounds1 = gfx::Rect{0, 0, 500, 300};
+ const auto kNormalBounds2 = gfx::Rect{0, 0, 800, 600};
+ const auto kNormalBounds3 = gfx::Rect{0, 0, 700, 400};
+ uint32_t serial = 1;
+
+ window_->set_update_visual_size_immediately(false);
+ auto* mock_surface = server_.GetObject<wl::MockSurface>(
+ window_->root_surface()->GetSurfaceId());
+
+ // UpdateVisualSize with different size from configure events does not
+ // acknowledge toplevel configure.
+ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(_, _, _, _)).Times(0);
+ EXPECT_CALL(*xdg_surface_, AckConfigure(_)).Times(0);
+ EXPECT_CALL(*mock_surface, SetOpaqueRegion(_));
+ EXPECT_CALL(*mock_surface, SetInputRegion(_));
+
+ auto state = InitializeWlArrayWithActivatedState();
+ SendConfigureEvent(xdg_surface_, kNormalBounds1.width(),
+ kNormalBounds1.height(), ++serial, state.get());
+ state = InitializeWlArrayWithActivatedState();
+ SendConfigureEvent(xdg_surface_, kNormalBounds2.width(),
+ kNormalBounds2.height(), ++serial, state.get());
+ state = InitializeWlArrayWithActivatedState();
+ SendConfigureEvent(xdg_surface_, kNormalBounds3.width(),
+ kNormalBounds3.height(), ++serial, state.get());
+ Sync();
+
+ window_->UpdateVisualSize({100, 100});
+}
+
+TEST_P(WaylandWindowTest, UpdateVisualSizeClearsPreviousUnackedConfigures) {
+ const auto kNormalBounds1 = gfx::Rect{0, 0, 500, 300};
+ const auto kNormalBounds2 = gfx::Rect{0, 0, 800, 600};
+ const auto kNormalBounds3 = gfx::Rect{0, 0, 700, 400};
+ uint32_t serial = 1;
+ auto state = InitializeWlArrayWithActivatedState();
+
+ window_->set_update_visual_size_immediately(false);
+
+ // Send 3 configures and only ack the second one, the first pending configure
+ // is cleared. The second can still be ack'ed.
+ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds1.width(),
+ kNormalBounds1.height()))
+ .Times(0);
+ EXPECT_CALL(*xdg_surface_, AckConfigure(2)).Times(0);
+ SendConfigureEvent(xdg_surface_, kNormalBounds1.width(),
+ kNormalBounds1.height(), ++serial, state.get());
+ Sync();
+
+ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds2.width(),
+ kNormalBounds2.height()));
+ EXPECT_CALL(*xdg_surface_, AckConfigure(3));
+ state = InitializeWlArrayWithActivatedState();
+ SendConfigureEvent(xdg_surface_, kNormalBounds2.width(),
+ kNormalBounds2.height(), ++serial, state.get());
+ Sync();
+
+ EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds3.width(),
+ kNormalBounds3.height()));
+ EXPECT_CALL(*xdg_surface_, AckConfigure(4));
+ state = InitializeWlArrayWithActivatedState();
+ SendConfigureEvent(xdg_surface_, kNormalBounds3.width(),
+ kNormalBounds3.height(), ++serial, state.get());
+ Sync();
+
+ window_->UpdateVisualSize(kNormalBounds2.size());
+ window_->UpdateVisualSize(kNormalBounds1.size());
+ window_->UpdateVisualSize(kNormalBounds3.size());
+}
+
TEST_P(WaylandWindowTest, MaximizeAndRestore) {
const auto kNormalBounds = gfx::Rect{0, 0, 500, 300};
const auto kMaximizedBounds = gfx::Rect{0, 0, 800, 600};
@@ -295,7 +438,7 @@ TEST_P(WaylandWindowTest, MaximizeAndRestore) {
kMaximizedBounds.height()));
EXPECT_CALL(delegate_, OnActivationChanged(Eq(true)));
EXPECT_CALL(delegate_, OnBoundsChanged(kMaximizedBounds));
- EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
+ EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(1);
window_->Maximize();
SendConfigureEvent(xdg_surface_, kMaximizedBounds.width(),
kMaximizedBounds.height(), ++serial,
@@ -326,7 +469,7 @@ TEST_P(WaylandWindowTest, MaximizeAndRestore) {
EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds.width(),
kNormalBounds.height()));
- EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
+ EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(1);
EXPECT_CALL(delegate_, OnActivationChanged(_)).Times(0);
EXPECT_CALL(delegate_, OnBoundsChanged(kNormalBounds));
EXPECT_CALL(*GetXdgToplevel(), UnsetMaximized());
@@ -346,7 +489,7 @@ TEST_P(WaylandWindowTest, Minimize) {
Sync();
EXPECT_CALL(*GetXdgToplevel(), SetMinimized());
- EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
+ EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(1);
window_->Minimize();
EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kMinimized);
@@ -363,8 +506,14 @@ TEST_P(WaylandWindowTest, Minimize) {
// Send one additional empty configuration event (which means the surface is
// not maximized, fullscreen or activated) to ensure, WaylandWindow stays in
- // the same minimized state and doesn't notify its delegate.
- EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
+ // the same minimized state, but the delegate is always notified.
+ //
+ // TODO(tonikito): Improve filtering of delegate notification here.
+ ui::PlatformWindowState state;
+ EXPECT_CALL(delegate_, OnWindowStateChanged(_))
+ .WillRepeatedly(DoAll(SaveArg<0>(&state), InvokeWithoutArgs([&]() {
+ EXPECT_EQ(state, PlatformWindowState::kMinimized);
+ })));
SendConfigureEvent(xdg_surface_, 0, 0, 3, states.get());
Sync();
@@ -384,7 +533,7 @@ TEST_P(WaylandWindowTest, SetFullscreenAndRestore) {
AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, states.get());
EXPECT_CALL(*GetXdgToplevel(), SetFullscreen());
- EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
+ EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(1);
window_->ToggleFullscreen();
// Make sure than WaylandWindow manually handles fullscreen states. Check the
// comment in the WaylandWindow::ToggleFullscreen.
@@ -394,7 +543,7 @@ TEST_P(WaylandWindowTest, SetFullscreenAndRestore) {
Sync();
EXPECT_CALL(*GetXdgToplevel(), UnsetFullscreen());
- EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
+ EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(1);
window_->Restore();
EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kNormal);
// Reinitialize wl_array, which removes previous old states.
@@ -467,12 +616,11 @@ TEST_P(WaylandWindowTest, StartMaximized) {
// Make sure the window is initialized to normal state from the beginning.
EXPECT_EQ(PlatformWindowState::kNormal, window_->GetPlatformWindowState());
- // The state must not be changed to the fullscreen before the surface is
- // activated.
+ // The state gets changed to maximize and the delegate notified.
auto* mock_surface = server_.GetObject<wl::MockSurface>(
window->root_surface()->GetSurfaceId());
EXPECT_FALSE(mock_surface->xdg_surface());
- EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
+ EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(1);
window_->Maximize();
// The state of the window must already be fullscreen one.
@@ -480,8 +628,8 @@ TEST_P(WaylandWindowTest, StartMaximized) {
Sync();
- // Once the surface will be activated, the window state mustn't be changed
- // and retain the same.
+ // Window show state should be already up to date, so delegate is not
+ // notified.
EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kMaximized);
@@ -521,6 +669,8 @@ TEST_P(WaylandWindowTest, CompositorSideStateChanges) {
EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, normal_bounds.width(),
normal_bounds.height()));
+ Sync();
+
// Now, set to fullscreen.
AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, states.get());
SendConfigureEvent(xdg_surface_, 2005, 2005, 3, states.get());
@@ -598,7 +748,7 @@ TEST_P(WaylandWindowTest, SetMaximizedFullscreenAndRestore) {
kMaximizedBounds.height()));
EXPECT_CALL(delegate_, OnActivationChanged(Eq(true)));
EXPECT_CALL(delegate_, OnBoundsChanged(kMaximizedBounds));
- EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
+ EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(1);
window_->Maximize();
// State changes are synchronous.
EXPECT_EQ(PlatformWindowState::kMaximized, window_->GetPlatformWindowState());
@@ -614,7 +764,7 @@ TEST_P(WaylandWindowTest, SetMaximizedFullscreenAndRestore) {
EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kMaximizedBounds.width(),
kMaximizedBounds.height()));
EXPECT_CALL(delegate_, OnBoundsChanged(_)).Times(0);
- EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
+ EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(1);
window_->ToggleFullscreen();
// State changes are synchronous.
EXPECT_EQ(PlatformWindowState::kFullScreen,
@@ -632,9 +782,8 @@ TEST_P(WaylandWindowTest, SetMaximizedFullscreenAndRestore) {
EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds.width(),
kNormalBounds.height()));
EXPECT_CALL(*GetXdgToplevel(), UnsetFullscreen());
- EXPECT_CALL(*GetXdgToplevel(), UnsetMaximized());
EXPECT_CALL(delegate_, OnBoundsChanged(kNormalBounds));
- EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
+ EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(1);
window_->Restore();
EXPECT_EQ(PlatformWindowState::kNormal, window_->GetPlatformWindowState());
// Reinitialize wl_array, which removes previous old states.
@@ -808,6 +957,51 @@ TEST_P(WaylandWindowTest, SendsBoundsOnRequest) {
EXPECT_EQ(restored_bounds, gfx::Rect());
}
+TEST_P(WaylandWindowTest, UpdateWindowRegion) {
+ wl::MockSurface* mock_surface = server_.GetObject<wl::MockSurface>(
+ window_->root_surface()->GetSurfaceId());
+
+ // Change bounds.
+ const gfx::Rect initial_bounds = window_->GetBounds();
+ const gfx::Rect new_bounds = gfx::Rect(0, 0, initial_bounds.width() + 10,
+ initial_bounds.height() + 10);
+ EXPECT_CALL(*mock_surface, SetOpaqueRegion(_)).Times(1);
+ EXPECT_CALL(*mock_surface, SetInputRegion(_)).Times(1);
+ window_->SetBounds(new_bounds);
+ Sync();
+ VerifyAndClearExpectations();
+ EXPECT_EQ(mock_surface->opaque_region(), new_bounds);
+ EXPECT_EQ(mock_surface->input_region(), new_bounds);
+
+ // Maximize.
+ ScopedWlArray states = InitializeWlArrayWithActivatedState();
+ EXPECT_CALL(*mock_surface, SetOpaqueRegion(_)).Times(1);
+ EXPECT_CALL(*mock_surface, SetInputRegion(_)).Times(1);
+ const gfx::Rect maximized_bounds = gfx::Rect(0, 0, 1024, 768);
+ window_->Maximize();
+ AddStateToWlArray(XDG_TOPLEVEL_STATE_MAXIMIZED, states.get());
+ SendConfigureEvent(xdg_surface_, maximized_bounds.width(),
+ maximized_bounds.height(), 1, states.get());
+ Sync();
+ VerifyAndClearExpectations();
+ EXPECT_EQ(mock_surface->opaque_region(), maximized_bounds);
+ EXPECT_EQ(mock_surface->input_region(), maximized_bounds);
+
+ // Restore.
+ const gfx::Rect restored_bounds = window_->GetRestoredBoundsInPixels();
+ EXPECT_CALL(*mock_surface, SetOpaqueRegion(_)).Times(1);
+ EXPECT_CALL(*mock_surface, SetInputRegion(_)).Times(1);
+ window_->Restore();
+ // Reinitialize wl_array, which removes previous old states.
+ auto active = InitializeWlArrayWithActivatedState();
+ SendConfigureEvent(xdg_surface_, 0, 0, 2, active.get());
+ Sync();
+ VerifyAndClearExpectations();
+
+ EXPECT_EQ(mock_surface->opaque_region(), restored_bounds);
+ EXPECT_EQ(mock_surface->input_region(), restored_bounds);
+}
+
TEST_P(WaylandWindowTest, CanDispatchMouseEventDefault) {
EXPECT_FALSE(window_->CanDispatchEvent(&test_mouse_event_));
}
@@ -1397,6 +1591,102 @@ TEST_P(WaylandWindowTest, DispatchWindowResize) {
}
}
+TEST_P(WaylandWindowTest, ToplevelWindowUpdateBufferScale) {
+ VerifyAndClearExpectations();
+
+ // Buffer scale must be 1 when no output has been entered by the window.
+ EXPECT_EQ(1, window_->buffer_scale());
+
+ // Creating an output with scale 1.
+ wl::TestOutput* output1 = server_.CreateAndInitializeOutput();
+ output1->SetRect(gfx::Rect(0, 0, 1920, 1080));
+ output1->SetScale(1);
+ Sync();
+
+ // Creating an output with scale 2.
+ wl::TestOutput* output2 = server_.CreateAndInitializeOutput();
+ output2->SetRect(gfx::Rect(0, 0, 1920, 1080));
+ output2->SetScale(2);
+ Sync();
+
+ // Send the window to |output1|.
+ wl::MockSurface* surface = server_.GetObject<wl::MockSurface>(
+ window_->root_surface()->GetSurfaceId());
+ ASSERT_TRUE(surface);
+ wl_surface_send_enter(surface->resource(), output1->resource());
+ Sync();
+
+ // The window's scale and bounds must remain unchanged.
+ EXPECT_EQ(1, window_->buffer_scale());
+ EXPECT_EQ(gfx::Rect(0, 0, 800, 600), window_->GetBounds());
+
+ // Simulating drag process from |output1| to |output2|.
+ wl_surface_send_enter(surface->resource(), output2->resource());
+ wl_surface_send_leave(surface->resource(), output1->resource());
+ Sync();
+
+ // The window must change its scale and bounds to keep DIP bounds the same.
+ EXPECT_EQ(2, window_->buffer_scale());
+ EXPECT_EQ(gfx::Rect(0, 0, 1600, 1200), window_->GetBounds());
+}
+
+TEST_P(WaylandWindowTest, AuxiliaryWindowUpdateBufferScale) {
+ VerifyAndClearExpectations();
+
+ // Creating an output with scale 1.
+ wl::TestOutput* output1 = server_.CreateAndInitializeOutput();
+ output1->SetRect(gfx::Rect(0, 0, 1920, 1080));
+ output1->SetScale(1);
+ Sync();
+
+ // Creating an output with scale 2.
+ wl::TestOutput* output2 = server_.CreateAndInitializeOutput();
+ output2->SetRect(gfx::Rect(0, 0, 1920, 1080));
+ output2->SetScale(2);
+ Sync();
+
+ // Send the window to |output1|.
+ wl::MockSurface* surface = server_.GetObject<wl::MockSurface>(
+ window_->root_surface()->GetSurfaceId());
+ ASSERT_TRUE(surface);
+ wl_surface_send_enter(surface->resource(), output1->resource());
+ Sync();
+
+ // Creating a tooltip on |window_|.
+ window_->SetPointerFocus(true);
+ gfx::Rect subsurface_bounds(15, 15, 10, 10);
+ std::unique_ptr<WaylandWindow> auxiliary_window =
+ CreateWaylandWindowWithParams(PlatformWindowType::kTooltip,
+ gfx::kNullAcceleratedWidget,
+ subsurface_bounds, &delegate_);
+ EXPECT_TRUE(auxiliary_window);
+
+ auxiliary_window->Show(false);
+
+ // |auxiliary_window| should inherit its buffer scale from the focused window.
+ EXPECT_EQ(1, auxiliary_window->buffer_scale());
+ EXPECT_EQ(subsurface_bounds, auxiliary_window->GetBounds());
+ auxiliary_window->Hide();
+
+ // Send the window to |output2|.
+ wl_surface_send_enter(surface->resource(), output2->resource());
+ wl_surface_send_leave(surface->resource(), output1->resource());
+ Sync();
+
+ EXPECT_EQ(2, window_->buffer_scale());
+ auxiliary_window->Show(false);
+
+ // |auxiliary_window|'s scale and bounds must change whenever its parents
+ // scale is changed.
+ EXPECT_EQ(2, window_->buffer_scale());
+ EXPECT_EQ(2, auxiliary_window->buffer_scale());
+ EXPECT_EQ(gfx::ScaleToRoundedRect(subsurface_bounds, 2),
+ auxiliary_window->GetBounds());
+
+ auxiliary_window->Hide();
+ window_->SetPointerFocus(false);
+}
+
// Tests WaylandWindow repositions menu windows to be relative to parent window
// in a right way.
TEST_P(WaylandWindowTest, AdjustPopupBounds) {
@@ -1408,26 +1698,29 @@ TEST_P(WaylandWindowTest, AdjustPopupBounds) {
ZXDG_POSITIONER_V6_ANCHOR_BOTTOM | ZXDG_POSITIONER_V6_ANCHOR_RIGHT,
ZXDG_POSITIONER_V6_GRAVITY_BOTTOM | ZXDG_POSITIONER_V6_GRAVITY_RIGHT,
ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_X |
- ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_Y};
+ ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_Y |
+ ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_Y};
nested_menu_window_positioner = {
gfx::Rect(4, 80, 279, 1), gfx::Size(305, 99),
ZXDG_POSITIONER_V6_ANCHOR_TOP | ZXDG_POSITIONER_V6_ANCHOR_RIGHT,
ZXDG_POSITIONER_V6_GRAVITY_BOTTOM | ZXDG_POSITIONER_V6_GRAVITY_RIGHT,
ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_X |
- ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_Y};
+ ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_Y |
+ ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_Y};
} else {
- menu_window_positioner = {gfx::Rect(439, 46, 1, 30), gfx::Size(287, 409),
- XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT,
- XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT,
- XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X |
- XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y};
-
+ menu_window_positioner = {
+ gfx::Rect(439, 46, 1, 30), gfx::Size(287, 409),
+ XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT, XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT,
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X |
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y |
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y};
nested_menu_window_positioner = {
gfx::Rect(4, 80, 279, 1), gfx::Size(305, 99),
XDG_POSITIONER_ANCHOR_TOP_RIGHT, XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT,
XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X |
- XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y};
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y |
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y};
}
auto* toplevel_window = window_.get();
@@ -1590,6 +1883,7 @@ TEST_P(WaylandWindowTest, SetOpaqueRegion) {
Sync();
VerifyAndClearExpectations();
+ EXPECT_EQ(mock_surface->opaque_region(), new_bounds);
new_bounds.set_size(gfx::Size(1000, 534));
SendConfigureEvent(xdg_surface_, new_bounds.width(), new_bounds.height(), 2,
@@ -1601,6 +1895,7 @@ TEST_P(WaylandWindowTest, SetOpaqueRegion) {
Sync();
VerifyAndClearExpectations();
+ EXPECT_EQ(mock_surface->opaque_region(), new_bounds);
}
TEST_P(WaylandWindowTest, OnCloseRequest) {
@@ -1617,23 +1912,16 @@ TEST_P(WaylandWindowTest, OnCloseRequest) {
TEST_P(WaylandWindowTest, AuxiliaryWindowSimpleParent) {
VerifyAndClearExpectations();
- std::unique_ptr<WaylandWindow> second_window = CreateWaylandWindowWithParams(
- PlatformWindowType::kWindow, gfx::kNullAcceleratedWidget,
- gfx::Rect(0, 0, 640, 480), &delegate_);
- EXPECT_TRUE(second_window);
-
- // Test case 1: if the subsurface is provided with a parent widget, it must
- // always use that as a parent.
+ // Auxiliary window must ignore the parent provided by aura and should always
+ // use focused window instead.
gfx::Rect subsurface_bounds(gfx::Point(15, 15), gfx::Size(10, 10));
std::unique_ptr<WaylandWindow> auxiliary_window =
CreateWaylandWindowWithParams(PlatformWindowType::kTooltip,
- window_->GetWidget(), subsurface_bounds,
- &delegate_);
+ gfx::kNullAcceleratedWidget,
+ subsurface_bounds, &delegate_);
EXPECT_TRUE(auxiliary_window);
- // The subsurface mustn't take the focused window as a parent, but use the
- // provided one.
- second_window->SetPointerFocus(true);
+ window_->SetPointerFocus(true);
auxiliary_window->Show(false);
Sync();
@@ -1644,6 +1932,8 @@ TEST_P(WaylandWindowTest, AuxiliaryWindowSimpleParent) {
EXPECT_EQ(test_subsurface->position(), subsurface_bounds.origin());
EXPECT_FALSE(test_subsurface->sync());
+ EXPECT_EQ(mock_surface_subsurface->opaque_region(),
+ gfx::Rect(subsurface_bounds.size()));
auto* parent_resource =
server_
@@ -1651,47 +1941,7 @@ TEST_P(WaylandWindowTest, AuxiliaryWindowSimpleParent) {
->resource();
EXPECT_EQ(parent_resource, test_subsurface->parent_resource());
- // Test case 2: the subsurface must use the focused window as its parent.
- auxiliary_window = CreateWaylandWindowWithParams(
- PlatformWindowType::kTooltip, gfx::kNullAcceleratedWidget,
- subsurface_bounds, &delegate_);
- EXPECT_TRUE(auxiliary_window);
-
- // The tooltip must take the focused window.
- second_window->SetPointerFocus(true);
- auxiliary_window->Show(false);
-
- Sync();
-
- // Get new surface after recreating the WaylandAuxiliaryWindow.
- mock_surface_subsurface = server_.GetObject<wl::MockSurface>(
- auxiliary_window->root_surface()->GetSurfaceId());
- test_subsurface = mock_surface_subsurface->sub_surface();
-
- auto* second_parent_resource =
- server_
- .GetObject<wl::MockSurface>(
- second_window->root_surface()->GetSurfaceId())
- ->resource();
- EXPECT_EQ(second_parent_resource, test_subsurface->parent_resource());
-
auxiliary_window->Hide();
-
- Sync();
-
- // The subsurface must take the focused window.
- second_window->SetPointerFocus(false);
- window_->SetPointerFocus(true);
- auxiliary_window->Show(false);
-
- Sync();
-
- // The subsurface is invalidated on each Hide call.
- test_subsurface = mock_surface_subsurface->sub_surface();
-
- // The |window_|'s resource must be the parent resource.
- EXPECT_EQ(parent_resource, test_subsurface->parent_resource());
-
window_->SetPointerFocus(false);
}
@@ -1850,6 +2100,7 @@ TEST_P(WaylandWindowTest, AuxiliaryWindowNestedParent) {
EXPECT_TRUE(menu_window);
VerifyAndClearExpectations();
+ menu_window->SetPointerFocus(true);
gfx::Rect subsurface_bounds(gfx::Point(15, 15), gfx::Size(10, 10));
std::unique_ptr<WaylandWindow> auxiliary_window =
@@ -1860,8 +2111,6 @@ TEST_P(WaylandWindowTest, AuxiliaryWindowNestedParent) {
VerifyAndClearExpectations();
- menu_window->SetPointerFocus(true);
-
auxiliary_window->Show(false);
Sync();
@@ -1873,6 +2122,8 @@ TEST_P(WaylandWindowTest, AuxiliaryWindowNestedParent) {
auto new_origin = subsurface_bounds.origin() -
menu_window_bounds.origin().OffsetFromOrigin();
EXPECT_EQ(test_subsurface->position(), new_origin);
+ EXPECT_EQ(mock_surface_subsurface->opaque_region(),
+ gfx::Rect(subsurface_bounds.size()));
menu_window->SetPointerFocus(false);
}
@@ -1969,7 +2220,7 @@ TEST_P(WaylandWindowTest, RemovesReattachesBackgroundOnHideShow) {
EXPECT_TRUE(connection_->buffer_manager_host());
auto interface_ptr = connection_->buffer_manager_host()->BindInterface();
- buffer_manager_gpu_->Initialize(std::move(interface_ptr), {}, false);
+ buffer_manager_gpu_->Initialize(std::move(interface_ptr), {}, false, false);
// Setup wl_buffers.
constexpr uint32_t buffer_id1 = 1;
@@ -2078,8 +2329,12 @@ TEST_P(WaylandWindowTest, SetsPropertiesOnShow) {
// Now, propagate size constraints and title.
base::Optional<gfx::Size> min_size(gfx::Size(1, 1));
base::Optional<gfx::Size> max_size(gfx::Size(100, 100));
- EXPECT_CALL(delegate, GetMinimumSizeForWindow()).WillOnce(Return(min_size));
- EXPECT_CALL(delegate, GetMaximumSizeForWindow()).WillOnce(Return(max_size));
+ EXPECT_CALL(delegate, GetMinimumSizeForWindow())
+ .Times(2)
+ .WillRepeatedly(Return(min_size));
+ EXPECT_CALL(delegate, GetMaximumSizeForWindow())
+ .Times(2)
+ .WillRepeatedly(Return(max_size));
EXPECT_CALL(*mock_xdg_toplevel,
SetMinSize(min_size.value().width(), min_size.value().height()));
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_zaura_shell.cc b/chromium/ui/ozone/platform/wayland/host/wayland_zaura_shell.cc
index 518a1a7cce6..2f926a008a2 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_zaura_shell.cc
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_zaura_shell.cc
@@ -21,12 +21,17 @@ WaylandZAuraShell::WaylandZAuraShell(zaura_shell* aura_shell,
static const zaura_shell_listener zaura_shell_listener = {
&WaylandZAuraShell::OnLayoutMode,
+ &WaylandZAuraShell::OnBugFix,
};
zaura_shell_add_listener(obj_.get(), &zaura_shell_listener, this);
}
WaylandZAuraShell::~WaylandZAuraShell() = default;
+bool WaylandZAuraShell::HasBugFix(uint32_t id) {
+ return bug_fix_ids_.find(id) != bug_fix_ids_.end();
+}
+
// static
void WaylandZAuraShell::OnLayoutMode(void* data,
struct zaura_shell* zaura_shell,
@@ -47,4 +52,12 @@ void WaylandZAuraShell::OnLayoutMode(void* data,
}
}
+// static
+void WaylandZAuraShell::OnBugFix(void* data,
+ struct zaura_shell* zaura_shell,
+ uint32_t id) {
+ auto* self = static_cast<WaylandZAuraShell*>(data);
+ self->bug_fix_ids_.insert(id);
+}
+
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_zaura_shell.h b/chromium/ui/ozone/platform/wayland/host/wayland_zaura_shell.h
index 3057ff66ce8..9c0e8251b1b 100644
--- a/chromium/ui/ozone/platform/wayland/host/wayland_zaura_shell.h
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_zaura_shell.h
@@ -5,6 +5,9 @@
#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_ZAURA_SHELL_H_
#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_ZAURA_SHELL_H_
+#include <string>
+
+#include "base/containers/flat_set.h"
#include "ui/ozone/platform/wayland/common/wayland_object.h"
namespace ui {
@@ -20,15 +23,24 @@ class WaylandZAuraShell {
~WaylandZAuraShell();
zaura_shell* wl_object() const { return obj_.get(); }
+ // Due to version skew between Lacros and Ash, there may be certain bug
+ // fixes in one but not in the other (crbug.com/1151508). Lacros can use
+ // |HasBugFix| to provide a temporary workaround to an exo bug until Ash
+ // uprevs and starts reporting that a given bug ID has been fixed.
+ bool HasBugFix(uint32_t id);
private:
- // zaura_shell_listener
+ // zaura_shell_listeners
static void OnLayoutMode(void* data,
struct zaura_shell* zaura_shell,
uint32_t layout_mode);
+ static void OnBugFix(void* data,
+ struct zaura_shell* zaura_shell,
+ uint32_t id);
wl::Object<zaura_shell> obj_;
WaylandConnection* const connection_;
+ base::flat_set<uint32_t> bug_fix_ids_;
};
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_zaura_shell_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_zaura_shell_unittest.cc
new file mode 100644
index 00000000000..a8bba1eb24d
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/host/wayland_zaura_shell_unittest.cc
@@ -0,0 +1,53 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <aura-shell-server-protocol.h>
+
+#include "base/run_loop.h"
+#include "base/test/task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_event_source.h"
+#include "ui/ozone/platform/wayland/host/wayland_zaura_shell.h"
+#include "ui/ozone/platform/wayland/test/global_object.h"
+#include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h"
+
+namespace ui {
+
+namespace {
+
+constexpr uint32_t kXdgVersionStable = 7;
+constexpr uint32_t kZAuraShellVersion = 14;
+
+} // namespace
+
+TEST(WaylandZauraShellTest, Foo) {
+ base::test::SingleThreadTaskEnvironment task_environment(
+ base::test::SingleThreadTaskEnvironment::MainThreadType::UI);
+ wl::TestWaylandServerThread server;
+ ASSERT_TRUE(server.Start(kXdgVersionStable));
+ wl::GlobalObject zaura_shell_obj(
+ &zaura_shell_interface, nullptr /* implementation */, kZAuraShellVersion);
+ zaura_shell_obj.Initialize(server.display());
+
+ WaylandConnection connection;
+ ASSERT_TRUE(connection.Initialize());
+ connection.event_source()->StartProcessingEvents();
+
+ base::RunLoop().RunUntilIdle();
+ server.Pause();
+
+ zaura_shell_send_bug_fix(zaura_shell_obj.resource(), 1);
+ zaura_shell_send_bug_fix(zaura_shell_obj.resource(), 3);
+
+ server.Resume();
+ base::RunLoop().RunUntilIdle();
+ server.Pause();
+
+ ASSERT_TRUE(connection.zaura_shell()->HasBugFix(1));
+ ASSERT_TRUE(connection.zaura_shell()->HasBugFix(3));
+ ASSERT_FALSE(connection.zaura_shell()->HasBugFix(2));
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc b/chromium/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc
index cee4e46e6c1..c43f6c212fd 100644
--- a/chromium/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc
+++ b/chromium/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.cc
@@ -17,17 +17,17 @@
#include "ui/gfx/geometry/rect.h"
#include "ui/ozone/platform/wayland/common/wayland_util.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
-#include "ui/ozone/platform/wayland/host/wayland_event_source.h"
#include "ui/ozone/platform/wayland/host/wayland_pointer.h"
#include "ui/ozone/platform/wayland/host/wayland_popup.h"
#include "ui/ozone/platform/wayland/host/wayland_toplevel_window.h"
#include "ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h"
+#include "ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.h"
namespace ui {
namespace {
-uint32_t TranslateAnchorStable(WlAnchor anchor) {
+uint32_t TranslateAnchor(WlAnchor anchor) {
switch (anchor) {
case WlAnchor::None:
return XDG_POSITIONER_ANCHOR_NONE;
@@ -50,7 +50,7 @@ uint32_t TranslateAnchorStable(WlAnchor anchor) {
}
}
-uint32_t TranslateGravityStable(WlGravity gravity) {
+uint32_t TranslateGravity(WlGravity gravity) {
switch (gravity) {
case WlGravity::None:
return XDG_POSITIONER_GRAVITY_NONE;
@@ -73,7 +73,7 @@ uint32_t TranslateGravityStable(WlGravity gravity) {
}
}
-uint32_t TranslateContraintAdjustmentStable(
+uint32_t TranslateContraintAdjustment(
WlConstraintAdjustment constraint_adjustment) {
uint32_t res = 0;
if ((constraint_adjustment & WlConstraintAdjustment::SlideX) !=
@@ -97,175 +97,14 @@ uint32_t TranslateContraintAdjustmentStable(
return res;
}
-uint32_t TranslateAnchorV6(WlAnchor anchor) {
- switch (anchor) {
- case WlAnchor::None:
- return ZXDG_POSITIONER_V6_ANCHOR_NONE;
- case WlAnchor::Top:
- return ZXDG_POSITIONER_V6_ANCHOR_TOP;
- case WlAnchor::Bottom:
- return ZXDG_POSITIONER_V6_ANCHOR_BOTTOM;
- case WlAnchor::Left:
- return ZXDG_POSITIONER_V6_ANCHOR_LEFT;
- case WlAnchor::Right:
- return ZXDG_POSITIONER_V6_ANCHOR_RIGHT;
- case WlAnchor::TopLeft:
- return ZXDG_POSITIONER_V6_ANCHOR_TOP | ZXDG_POSITIONER_V6_ANCHOR_LEFT;
- case WlAnchor::BottomLeft:
- return ZXDG_POSITIONER_V6_ANCHOR_BOTTOM | ZXDG_POSITIONER_V6_ANCHOR_LEFT;
- case WlAnchor::TopRight:
- return ZXDG_POSITIONER_V6_ANCHOR_TOP | ZXDG_POSITIONER_V6_ANCHOR_RIGHT;
- case WlAnchor::BottomRight:
- return ZXDG_POSITIONER_V6_ANCHOR_BOTTOM | ZXDG_POSITIONER_V6_ANCHOR_RIGHT;
- }
-}
-
-uint32_t TranslateGravityV6(WlGravity gravity) {
- switch (gravity) {
- case WlGravity::None:
- return ZXDG_POSITIONER_V6_GRAVITY_NONE;
- case WlGravity::Top:
- return ZXDG_POSITIONER_V6_GRAVITY_TOP;
- case WlGravity::Bottom:
- return ZXDG_POSITIONER_V6_GRAVITY_BOTTOM;
- case WlGravity::Left:
- return ZXDG_POSITIONER_V6_GRAVITY_LEFT;
- case WlGravity::Right:
- return ZXDG_POSITIONER_V6_GRAVITY_RIGHT;
- case WlGravity::TopLeft:
- return ZXDG_POSITIONER_V6_GRAVITY_TOP | ZXDG_POSITIONER_V6_GRAVITY_LEFT;
- case WlGravity::BottomLeft:
- return ZXDG_POSITIONER_V6_GRAVITY_BOTTOM |
- ZXDG_POSITIONER_V6_GRAVITY_LEFT;
- case WlGravity::TopRight:
- return ZXDG_POSITIONER_V6_GRAVITY_TOP | ZXDG_POSITIONER_V6_GRAVITY_RIGHT;
- case WlGravity::BottomRight:
- return ZXDG_POSITIONER_V6_GRAVITY_BOTTOM |
- ZXDG_POSITIONER_V6_GRAVITY_RIGHT;
- }
-}
-
-uint32_t TranslateContraintAdjustmentV6(
- WlConstraintAdjustment constraint_adjustment) {
- uint32_t res = 0;
- if ((constraint_adjustment & WlConstraintAdjustment::SlideX) !=
- WlConstraintAdjustment::None)
- res |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_X;
- if ((constraint_adjustment & WlConstraintAdjustment::SlideY) !=
- WlConstraintAdjustment::None)
- res |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_Y;
- if ((constraint_adjustment & WlConstraintAdjustment::FlipX) !=
- WlConstraintAdjustment::None)
- res |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_X;
- if ((constraint_adjustment & WlConstraintAdjustment::FlipY) !=
- WlConstraintAdjustment::None)
- res |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_Y;
- if ((constraint_adjustment & WlConstraintAdjustment::ResizeX) !=
- WlConstraintAdjustment::None)
- res |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_X;
- if ((constraint_adjustment & WlConstraintAdjustment::ResizeY) !=
- WlConstraintAdjustment::None)
- res |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_Y;
- return res;
-}
-
-uint32_t GetAnchor(MenuType menu_type, const gfx::Rect& bounds, bool stable) {
- WlAnchor anchor = WlAnchor::None;
- switch (menu_type) {
- case MenuType::TYPE_RIGHT_CLICK:
- anchor = WlAnchor::TopLeft;
- break;
- case MenuType::TYPE_3DOT_PARENT_MENU:
- anchor = WlAnchor::BottomRight;
- break;
- case MenuType::TYPE_3DOT_CHILD_MENU:
- // Chromium may want to manually position a child menu on the left side of
- // its parent menu. Thus, react accordingly. Positive x means the child is
- // located on the right side of the parent and negative - on the left
- // side.
- if (bounds.x() >= 0)
- anchor = WlAnchor::TopRight;
- else
- anchor = WlAnchor::TopLeft;
- break;
- case MenuType::TYPE_UNKNOWN:
- NOTREACHED() << "Unsupported menu type";
- break;
- }
-
- if (stable)
- return TranslateAnchorStable(anchor);
- else {
- return TranslateAnchorV6(anchor);
- }
-}
-
-uint32_t GetGravity(MenuType menu_type, const gfx::Rect& bounds, bool stable) {
- WlGravity gravity = WlGravity::None;
- switch (menu_type) {
- case MenuType::TYPE_RIGHT_CLICK:
- gravity = WlGravity::BottomRight;
- break;
- case MenuType::TYPE_3DOT_PARENT_MENU:
- gravity = WlGravity::BottomRight;
- break;
- case MenuType::TYPE_3DOT_CHILD_MENU:
- // Chromium may want to manually position a child menu on the left side of
- // its parent menu. Thus, react accordingly. Positive x means the child is
- // located on the right side of the parent and negative - on the left
- // side.
- if (bounds.x() >= 0)
- gravity = WlGravity::BottomRight;
- else
- gravity = WlGravity::BottomLeft;
- break;
- case MenuType::TYPE_UNKNOWN:
- NOTREACHED() << "Unsupported menu type";
- break;
- }
-
- if (stable)
- return TranslateGravityStable(gravity);
- else {
- return TranslateGravityV6(gravity);
- }
-}
-
-uint32_t GetConstraintAdjustment(MenuType menu_type, bool stable) {
- WlConstraintAdjustment constraint = WlConstraintAdjustment::None;
-
- switch (menu_type) {
- case MenuType::TYPE_RIGHT_CLICK:
- constraint = WlConstraintAdjustment::SlideX |
- WlConstraintAdjustment::SlideY |
- WlConstraintAdjustment::FlipY;
- break;
- case MenuType::TYPE_3DOT_PARENT_MENU:
- constraint =
- WlConstraintAdjustment::SlideX | WlConstraintAdjustment::FlipY;
- break;
- case MenuType::TYPE_3DOT_CHILD_MENU:
- constraint =
- WlConstraintAdjustment::SlideY | WlConstraintAdjustment::FlipX;
- break;
- case MenuType::TYPE_UNKNOWN:
- NOTREACHED() << "Unsupported menu type";
- break;
- }
- if (stable)
- return TranslateContraintAdjustmentStable(constraint);
- else {
- return TranslateContraintAdjustmentV6(constraint);
- }
-}
-
} // namespace
XDGPopupWrapperImpl::XDGPopupWrapperImpl(
std::unique_ptr<XDGSurfaceWrapperImpl> surface,
WaylandWindow* wayland_window)
- : wayland_window_(wayland_window), xdg_surface_(std::move(surface)) {
- DCHECK(xdg_surface_);
+ : wayland_window_(wayland_window),
+ xdg_surface_wrapper_(std::move(surface)) {
+ DCHECK(xdg_surface_wrapper_);
DCHECK(wayland_window_ && wayland_window_->parent_window());
}
@@ -286,15 +125,16 @@ bool XDGPopupWrapperImpl::Initialize(WaylandConnection* connection,
static_cast<WaylandPopup*>(wayland_window_->parent_window());
XDGPopupWrapperImpl* popup =
static_cast<XDGPopupWrapperImpl*>(wayland_popup->shell_popup());
- parent_xdg_surface = popup->xdg_surface();
+ parent_xdg_surface = popup->xdg_surface_wrapper();
} else {
WaylandToplevelWindow* wayland_surface =
static_cast<WaylandToplevelWindow*>(wayland_window_->parent_window());
parent_xdg_surface =
- static_cast<XDGSurfaceWrapperImpl*>(wayland_surface->shell_surface());
+ static_cast<XDGToplevelWrapperImpl*>(wayland_surface->shell_toplevel())
+ ->xdg_surface_wrapper();
}
- if (!xdg_surface_ || !parent_xdg_surface)
+ if (!xdg_surface_wrapper_ || !parent_xdg_surface)
return false;
auto new_bounds = bounds;
@@ -306,8 +146,6 @@ bool XDGPopupWrapperImpl::Initialize(WaylandConnection* connection,
if (connection->shell())
return InitializeStable(connection, new_bounds, parent_xdg_surface);
- else if (connection->shell_v6())
- return InitializeV6(connection, new_bounds, parent_xdg_surface);
return false;
}
@@ -316,16 +154,16 @@ bool XDGPopupWrapperImpl::InitializeStable(
const gfx::Rect& bounds,
XDGSurfaceWrapperImpl* parent_xdg_surface) {
static const struct xdg_popup_listener xdg_popup_listener = {
- &XDGPopupWrapperImpl::ConfigureStable,
- &XDGPopupWrapperImpl::PopupDoneStable,
+ &XDGPopupWrapperImpl::Configure,
+ &XDGPopupWrapperImpl::PopupDone,
};
- struct xdg_positioner* positioner = CreatePositionerStable(
- connection, wayland_window_->parent_window(), bounds);
+ struct xdg_positioner* positioner =
+ CreatePositioner(connection, wayland_window_->parent_window(), bounds);
if (!positioner)
return false;
- xdg_popup_.reset(xdg_surface_get_popup(xdg_surface_->xdg_surface(),
+ xdg_popup_.reset(xdg_surface_get_popup(xdg_surface_wrapper_->xdg_surface(),
parent_xdg_surface->xdg_surface(),
positioner));
if (!xdg_popup_)
@@ -342,7 +180,12 @@ bool XDGPopupWrapperImpl::InitializeStable(
return true;
}
-struct xdg_positioner* XDGPopupWrapperImpl::CreatePositionerStable(
+void XDGPopupWrapperImpl::AckConfigure(uint32_t serial) {
+ DCHECK(xdg_surface_wrapper_);
+ xdg_surface_wrapper_->AckConfigure(serial);
+}
+
+struct xdg_positioner* XDGPopupWrapperImpl::CreatePositioner(
WaylandConnection* connection,
WaylandWindow* parent_window,
const gfx::Rect& bounds) {
@@ -366,115 +209,19 @@ struct xdg_positioner* XDGPopupWrapperImpl::CreatePositionerStable(
xdg_positioner_set_anchor_rect(positioner, anchor_rect.x(), anchor_rect.y(),
anchor_rect.width(), anchor_rect.height());
xdg_positioner_set_size(positioner, bounds.width(), bounds.height());
- xdg_positioner_set_anchor(positioner, GetAnchor(menu_type, bounds, true));
- xdg_positioner_set_gravity(positioner, GetGravity(menu_type, bounds, true));
+ xdg_positioner_set_anchor(positioner,
+ TranslateAnchor(GetAnchor(menu_type, bounds)));
+ xdg_positioner_set_gravity(positioner,
+ TranslateGravity(GetGravity(menu_type, bounds)));
xdg_positioner_set_constraint_adjustment(
- positioner, GetConstraintAdjustment(menu_type, true));
+ positioner,
+ TranslateContraintAdjustment(GetConstraintAdjustment(menu_type)));
return positioner;
}
-bool XDGPopupWrapperImpl::InitializeV6(
- WaylandConnection* connection,
- const gfx::Rect& bounds,
- XDGSurfaceWrapperImpl* parent_xdg_surface) {
- static const struct zxdg_popup_v6_listener zxdg_popup_v6_listener = {
- &XDGPopupWrapperImpl::ConfigureV6,
- &XDGPopupWrapperImpl::PopupDoneV6,
- };
-
- zxdg_positioner_v6* positioner =
- CreatePositionerV6(connection, wayland_window_->parent_window(), bounds);
- if (!positioner)
- return false;
-
- zxdg_popup_v6_.reset(zxdg_surface_v6_get_popup(
- xdg_surface_->zxdg_surface(), parent_xdg_surface->zxdg_surface(),
- positioner));
- if (!zxdg_popup_v6_)
- return false;
-
- zxdg_positioner_v6_destroy(positioner);
-
- if (CanGrabPopup(connection)) {
- zxdg_popup_v6_grab(zxdg_popup_v6_.get(), connection->seat(),
- connection->serial());
- }
- zxdg_popup_v6_add_listener(zxdg_popup_v6_.get(), &zxdg_popup_v6_listener,
- this);
-
- wayland_window_->root_surface()->Commit();
- return true;
-}
-
-zxdg_positioner_v6* XDGPopupWrapperImpl::CreatePositionerV6(
- WaylandConnection* connection,
- WaylandWindow* parent_window,
- const gfx::Rect& bounds) {
- struct zxdg_positioner_v6* positioner;
- positioner = zxdg_shell_v6_create_positioner(connection->shell_v6());
- if (!positioner)
- return nullptr;
-
- auto menu_type = GetMenuTypeForPositioner(connection, parent_window);
-
- // The parent we got must be the topmost in the stack of the same family
- // windows.
- DCHECK_EQ(parent_window->GetTopMostChildWindow(), parent_window);
-
- // Place anchor to the end of the possible position.
- gfx::Rect anchor_rect = GetAnchorRect(
- menu_type, bounds,
- gfx::ScaleToRoundedRect(parent_window->GetBounds(),
- 1.0 / parent_window->buffer_scale()));
-
- zxdg_positioner_v6_set_anchor_rect(positioner, anchor_rect.x(),
- anchor_rect.y(), anchor_rect.width(),
- anchor_rect.height());
- zxdg_positioner_v6_set_size(positioner, bounds.width(), bounds.height());
- zxdg_positioner_v6_set_anchor(positioner,
- GetAnchor(menu_type, bounds, false));
- zxdg_positioner_v6_set_gravity(positioner,
- GetGravity(menu_type, bounds, false));
- zxdg_positioner_v6_set_constraint_adjustment(
- positioner, GetConstraintAdjustment(menu_type, false));
- return positioner;
-}
-
-MenuType XDGPopupWrapperImpl::GetMenuTypeForPositioner(
- WaylandConnection* connection,
- WaylandWindow* parent_window) const {
- bool is_right_click_menu =
- connection->event_source()->last_pointer_button_pressed() &
- EF_RIGHT_MOUSE_BUTTON;
-
- // Different types of menu require different anchors, constraint adjustments,
- // gravity and etc.
- if (is_right_click_menu)
- return MenuType::TYPE_RIGHT_CLICK;
- else if (!wl::IsMenuType(parent_window->type()))
- return MenuType::TYPE_3DOT_PARENT_MENU;
- else
- return MenuType::TYPE_3DOT_CHILD_MENU;
-}
-
-bool XDGPopupWrapperImpl::CanGrabPopup(WaylandConnection* connection) const {
- // When drag process starts, as described the protocol -
- // https://goo.gl/1Mskq3, the client must have an active implicit grab. If
- // we try to create a popup and grab it, it will be immediately dismissed.
- // Thus, do not take explicit grab during drag process.
- if (connection->IsDragInProgress() || !connection->seat())
- return false;
-
- // According to the definition of the xdg protocol, the grab request must be
- // used in response to some sort of user action like a button press, key
- // press, or touch down event.
- EventType last_event_type = connection->event_serial().event_type;
- return last_event_type == ET_TOUCH_PRESSED ||
- last_event_type == ET_KEY_PRESSED ||
- last_event_type == ET_MOUSE_PRESSED;
-}
-
+// static
void XDGPopupWrapperImpl::Configure(void* data,
+ struct xdg_popup* xdg_popup,
int32_t x,
int32_t y,
int32_t width,
@@ -492,7 +239,7 @@ void XDGPopupWrapperImpl::Configure(void* data,
}
// static
-void XDGPopupWrapperImpl::PopupDone(void* data) {
+void XDGPopupWrapperImpl::PopupDone(void* data, struct xdg_popup* xdg_popup) {
WaylandWindow* window =
static_cast<XDGPopupWrapperImpl*>(data)->wayland_window_;
DCHECK(window);
@@ -500,41 +247,9 @@ void XDGPopupWrapperImpl::PopupDone(void* data) {
window->OnCloseRequest();
}
-// static
-void XDGPopupWrapperImpl::ConfigureStable(void* data,
- struct xdg_popup* xdg_popup,
- int32_t x,
- int32_t y,
- int32_t width,
- int32_t height) {
- Configure(data, x, y, width, height);
-}
-
-// static
-void XDGPopupWrapperImpl::PopupDoneStable(void* data,
- struct xdg_popup* xdg_popup) {
- PopupDone(data);
-}
-
-// static
-void XDGPopupWrapperImpl::ConfigureV6(void* data,
- struct zxdg_popup_v6* zxdg_popup_v6,
- int32_t x,
- int32_t y,
- int32_t width,
- int32_t height) {
- Configure(data, x, y, width, height);
-}
-
-// static
-void XDGPopupWrapperImpl::PopupDoneV6(void* data,
- struct zxdg_popup_v6* zxdg_popup_v6) {
- PopupDone(data);
-}
-
-XDGSurfaceWrapperImpl* XDGPopupWrapperImpl::xdg_surface() {
- DCHECK(xdg_surface_.get());
- return xdg_surface_.get();
+XDGSurfaceWrapperImpl* XDGPopupWrapperImpl::xdg_surface_wrapper() const {
+ DCHECK(xdg_surface_wrapper_.get());
+ return xdg_surface_wrapper_.get();
}
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h b/chromium/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h
index 62f38a2dc6a..0ffd6674836 100644
--- a/chromium/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h
+++ b/chromium/ui/ozone/platform/wayland/host/xdg_popup_wrapper_impl.h
@@ -16,7 +16,7 @@ class XDGSurfaceWrapperImpl;
class WaylandConnection;
class WaylandWindow;
-// Popup wrapper for xdg-shell stable and xdg-shell-unstable-v6
+// Popup wrapper for xdg-shell stable
class XDGPopupWrapperImpl : public ShellPopupWrapper {
public:
XDGPopupWrapperImpl(std::unique_ptr<XDGSurfaceWrapperImpl> surface,
@@ -26,61 +26,35 @@ class XDGPopupWrapperImpl : public ShellPopupWrapper {
// XDGPopupWrapper:
bool Initialize(WaylandConnection* connection,
const gfx::Rect& bounds) override;
+ void AckConfigure(uint32_t serial) override;
private:
bool InitializeStable(WaylandConnection* connection,
const gfx::Rect& bounds,
- XDGSurfaceWrapperImpl* parent_xdg_surface);
- struct xdg_positioner* CreatePositionerStable(WaylandConnection* connection,
- WaylandWindow* parent_window,
- const gfx::Rect& bounds);
-
- bool InitializeV6(WaylandConnection* connection,
- const gfx::Rect& bounds,
- XDGSurfaceWrapperImpl* parent_xdg_surface);
- struct zxdg_positioner_v6* CreatePositionerV6(WaylandConnection* connection,
- WaylandWindow* parent_window,
- const gfx::Rect& bounds);
-
- MenuType GetMenuTypeForPositioner(WaylandConnection* connection,
- WaylandWindow* parent_window) const;
-
- bool CanGrabPopup(WaylandConnection* connection) const;
+ XDGSurfaceWrapperImpl* parent_xdg_surface_wrapper);
+ struct xdg_positioner* CreatePositioner(WaylandConnection* connection,
+ WaylandWindow* parent_window,
+ const gfx::Rect& bounds);
// xdg_popup_listener
static void Configure(void* data,
- int32_t x,
- int32_t y,
- int32_t width,
- int32_t height);
- static void ConfigureStable(void* data,
struct xdg_popup* xdg_popup,
int32_t x,
int32_t y,
int32_t width,
int32_t height);
- static void ConfigureV6(void* data,
- struct zxdg_popup_v6* zxdg_popup_v6,
- int32_t x,
- int32_t y,
- int32_t width,
- int32_t height);
- static void PopupDone(void* data);
- static void PopupDoneStable(void* data, struct xdg_popup* xdg_popup);
- static void PopupDoneV6(void* data, struct zxdg_popup_v6* zxdg_popup_v6);
-
- XDGSurfaceWrapperImpl* xdg_surface();
+ static void PopupDone(void* data, struct xdg_popup* xdg_popup);
+
+ XDGSurfaceWrapperImpl* xdg_surface_wrapper() const;
// Non-owned WaylandWindow that uses this popup.
WaylandWindow* const wayland_window_;
// Ground surface for this popup.
- std::unique_ptr<XDGSurfaceWrapperImpl> xdg_surface_;
+ std::unique_ptr<XDGSurfaceWrapperImpl> xdg_surface_wrapper_;
// XDG Shell Stable object.
wl::Object<xdg_popup> xdg_popup_;
- // XDG Shell V6 object.
- wl::Object<zxdg_popup_v6> zxdg_popup_v6_;
DISALLOW_COPY_AND_ASSIGN(XDGPopupWrapperImpl);
};
diff --git a/chromium/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.cc b/chromium/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.cc
index 6ee18c65b7e..852573ae6fc 100644
--- a/chromium/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.cc
+++ b/chromium/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.cc
@@ -4,13 +4,8 @@
#include "ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h"
-#include <xdg-decoration-unstable-v1-client-protocol.h>
#include <xdg-shell-client-protocol.h>
-#include <xdg-shell-unstable-v6-client-protocol.h>
-#include "base/strings/utf_string_conversions.h"
-#include "ui/base/hit_test.h"
-#include "ui/ozone/platform/wayland/common/wayland_util.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
#include "ui/ozone/platform/wayland/host/wayland_window.h"
@@ -20,244 +15,51 @@ XDGSurfaceWrapperImpl::XDGSurfaceWrapperImpl(WaylandWindow* wayland_window,
WaylandConnection* connection)
: wayland_window_(wayland_window), connection_(connection) {}
-XDGSurfaceWrapperImpl::~XDGSurfaceWrapperImpl() {}
+XDGSurfaceWrapperImpl::~XDGSurfaceWrapperImpl() = default;
-bool XDGSurfaceWrapperImpl::Initialize(bool with_toplevel) {
- if (connection_->shell())
- return InitializeStable(with_toplevel);
- else if (connection_->shell_v6())
- return InitializeV6(with_toplevel);
- NOTREACHED() << "Wrong shell protocol";
- return false;
-}
-
-void XDGSurfaceWrapperImpl::SetMaximized() {
- if (xdg_toplevel_) {
- xdg_toplevel_set_maximized(xdg_toplevel_.get());
- } else {
- DCHECK(zxdg_toplevel_v6_);
- zxdg_toplevel_v6_set_maximized(zxdg_toplevel_v6_.get());
- }
-}
-
-void XDGSurfaceWrapperImpl::UnSetMaximized() {
- if (xdg_toplevel_) {
- xdg_toplevel_unset_maximized(xdg_toplevel_.get());
- } else {
- DCHECK(zxdg_toplevel_v6_);
- zxdg_toplevel_v6_unset_maximized(zxdg_toplevel_v6_.get());
- }
-}
-
-void XDGSurfaceWrapperImpl::SetFullscreen() {
- if (xdg_toplevel_) {
- xdg_toplevel_set_fullscreen(xdg_toplevel_.get(), nullptr);
- } else {
- DCHECK(zxdg_toplevel_v6_);
- zxdg_toplevel_v6_set_fullscreen(zxdg_toplevel_v6_.get(), nullptr);
- }
-}
-
-void XDGSurfaceWrapperImpl::UnSetFullscreen() {
- if (xdg_toplevel_) {
- xdg_toplevel_unset_fullscreen(xdg_toplevel_.get());
- } else {
- DCHECK(zxdg_toplevel_v6_);
- zxdg_toplevel_v6_unset_fullscreen(zxdg_toplevel_v6_.get());
- }
-}
-
-void XDGSurfaceWrapperImpl::SetMinimized() {
- if (xdg_toplevel_) {
- xdg_toplevel_set_minimized(xdg_toplevel_.get());
- } else {
- DCHECK(zxdg_toplevel_v6_);
- zxdg_toplevel_v6_set_minimized(zxdg_toplevel_v6_.get());
+bool XDGSurfaceWrapperImpl::Initialize() {
+ if (!connection_->shell()) {
+ NOTREACHED() << "Wrong shell protocol";
+ return false;
}
-}
-void XDGSurfaceWrapperImpl::SurfaceMove(WaylandConnection* connection) {
- if (xdg_toplevel_) {
- xdg_toplevel_move(xdg_toplevel_.get(), connection_->seat(),
- connection_->serial());
- } else {
- DCHECK(zxdg_toplevel_v6_);
- zxdg_toplevel_v6_move(zxdg_toplevel_v6_.get(), connection_->seat(),
- connection_->serial());
- }
-}
+ static const xdg_surface_listener xdg_surface_listener = {
+ &XDGSurfaceWrapperImpl::Configure,
+ };
-void XDGSurfaceWrapperImpl::SurfaceResize(WaylandConnection* connection,
- uint32_t hittest) {
- if (xdg_toplevel_) {
- xdg_toplevel_resize(xdg_toplevel_.get(), connection_->seat(),
- connection_->serial(),
- wl::IdentifyDirection(*connection, hittest));
- } else {
- DCHECK(zxdg_toplevel_v6_);
- zxdg_toplevel_v6_resize(zxdg_toplevel_v6_.get(), connection_->seat(),
- connection_->serial(),
- wl::IdentifyDirection(*connection, hittest));
+ xdg_surface_.reset(xdg_wm_base_get_xdg_surface(
+ connection_->shell(), wayland_window_->root_surface()->surface()));
+ if (!xdg_surface_) {
+ LOG(ERROR) << "Failed to create xdg_surface";
+ return false;
}
-}
-void XDGSurfaceWrapperImpl::SetTitle(const base::string16& title) {
- if (xdg_toplevel_) {
- xdg_toplevel_set_title(xdg_toplevel_.get(),
- base::UTF16ToUTF8(title).c_str());
- } else {
- DCHECK(zxdg_toplevel_v6_);
- zxdg_toplevel_v6_set_title(zxdg_toplevel_v6_.get(),
- base::UTF16ToUTF8(title).c_str());
- }
+ xdg_surface_add_listener(xdg_surface_.get(), &xdg_surface_listener, this);
+ connection_->ScheduleFlush();
+ return true;
}
-void XDGSurfaceWrapperImpl::AckConfigure() {
- if (xdg_surface_) {
- xdg_surface_ack_configure(xdg_surface_.get(), pending_configure_serial_);
- } else {
- DCHECK(zxdg_surface_v6_);
- zxdg_surface_v6_ack_configure(zxdg_surface_v6_.get(),
- pending_configure_serial_);
- }
+void XDGSurfaceWrapperImpl::AckConfigure(uint32_t serial) {
+ DCHECK(xdg_surface_);
+ xdg_surface_ack_configure(xdg_surface_.get(), serial);
connection_->wayland_window_manager()->NotifyWindowConfigured(
wayland_window_);
}
void XDGSurfaceWrapperImpl::SetWindowGeometry(const gfx::Rect& bounds) {
- if (xdg_surface_) {
- xdg_surface_set_window_geometry(xdg_surface_.get(), bounds.x(), bounds.y(),
- bounds.width(), bounds.height());
- } else {
- DCHECK(zxdg_surface_v6_);
- zxdg_surface_v6_set_window_geometry(zxdg_surface_v6_.get(), bounds.x(),
- bounds.y(), bounds.width(),
- bounds.height());
- }
-}
-
-void XDGSurfaceWrapperImpl::SetMinSize(int32_t width, int32_t height) {
- if (xdg_toplevel_) {
- xdg_toplevel_set_min_size(xdg_toplevel_.get(), width, height);
- } else {
- DCHECK(zxdg_toplevel_v6_);
- zxdg_toplevel_v6_set_min_size(zxdg_toplevel_v6_.get(), width, height);
- }
-}
-
-void XDGSurfaceWrapperImpl::SetMaxSize(int32_t width, int32_t height) {
- if (xdg_toplevel_) {
- xdg_toplevel_set_max_size(xdg_toplevel_.get(), width, height);
- } else {
- DCHECK(zxdg_toplevel_v6_);
- zxdg_toplevel_v6_set_max_size(zxdg_toplevel_v6_.get(), width, height);
- }
-}
-
-void XDGSurfaceWrapperImpl::SetAppId(const std::string& app_id) {
- if (xdg_toplevel_) {
- xdg_toplevel_set_app_id(xdg_toplevel_.get(), app_id.c_str());
- } else {
- DCHECK(zxdg_toplevel_v6_);
- zxdg_toplevel_v6_set_app_id(zxdg_toplevel_v6_.get(), app_id.c_str());
- }
-}
-
-// static
-void XDGSurfaceWrapperImpl::ConfigureStable(void* data,
- struct xdg_surface* xdg_surface,
- uint32_t serial) {
- auto* surface = static_cast<XDGSurfaceWrapperImpl*>(data);
- DCHECK(surface);
- surface->pending_configure_serial_ = serial;
-
- surface->AckConfigure();
-}
-
-// static
-void XDGSurfaceWrapperImpl::ConfigureTopLevelStable(
- void* data,
- struct xdg_toplevel* xdg_toplevel,
- int32_t width,
- int32_t height,
- struct wl_array* states) {
- auto* surface = static_cast<XDGSurfaceWrapperImpl*>(data);
- DCHECK(surface);
-
- bool is_maximized =
- CheckIfWlArrayHasValue(states, XDG_TOPLEVEL_STATE_MAXIMIZED);
- bool is_fullscreen =
- CheckIfWlArrayHasValue(states, XDG_TOPLEVEL_STATE_FULLSCREEN);
- bool is_activated =
- CheckIfWlArrayHasValue(states, XDG_TOPLEVEL_STATE_ACTIVATED);
-
- surface->wayland_window_->HandleSurfaceConfigure(width, height, is_maximized,
- is_fullscreen, is_activated);
-}
-
-// static
-void XDGSurfaceWrapperImpl::CloseTopLevelStable(
- void* data,
- struct xdg_toplevel* xdg_toplevel) {
- auto* surface = static_cast<XDGSurfaceWrapperImpl*>(data);
- DCHECK(surface);
- surface->wayland_window_->OnCloseRequest();
-}
-
-void XDGSurfaceWrapperImpl::SetTopLevelDecorationMode(
- zxdg_toplevel_decoration_v1_mode requested_mode) {
- if (requested_mode == decoration_mode_)
- return;
-
- decoration_mode_ = requested_mode;
- zxdg_toplevel_decoration_v1_set_mode(zxdg_toplevel_decoration_.get(),
- requested_mode);
-}
-
-// static
-void XDGSurfaceWrapperImpl::ConfigureV6(void* data,
- struct zxdg_surface_v6* zxdg_surface_v6,
- uint32_t serial) {
- auto* surface = static_cast<XDGSurfaceWrapperImpl*>(data);
- DCHECK(surface);
- surface->pending_configure_serial_ = serial;
-
- surface->AckConfigure();
-}
-
-// static
-void XDGSurfaceWrapperImpl::ConfigureTopLevelV6(
- void* data,
- struct zxdg_toplevel_v6* zxdg_toplevel_v6,
- int32_t width,
- int32_t height,
- struct wl_array* states) {
- auto* surface = static_cast<XDGSurfaceWrapperImpl*>(data);
- DCHECK(surface);
-
- bool is_maximized =
- CheckIfWlArrayHasValue(states, ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED);
- bool is_fullscreen =
- CheckIfWlArrayHasValue(states, ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN);
- bool is_activated =
- CheckIfWlArrayHasValue(states, ZXDG_TOPLEVEL_V6_STATE_ACTIVATED);
-
- surface->wayland_window_->HandleSurfaceConfigure(width, height, is_maximized,
- is_fullscreen, is_activated);
+ DCHECK(xdg_surface_);
+ xdg_surface_set_window_geometry(xdg_surface_.get(), bounds.x(), bounds.y(),
+ bounds.width(), bounds.height());
}
// static
-void XDGSurfaceWrapperImpl::CloseTopLevelV6(
- void* data,
- struct zxdg_toplevel_v6* zxdg_toplevel_v6) {
+void XDGSurfaceWrapperImpl::Configure(void* data,
+ struct xdg_surface* xdg_surface,
+ uint32_t serial) {
auto* surface = static_cast<XDGSurfaceWrapperImpl*>(data);
DCHECK(surface);
- surface->wayland_window_->OnCloseRequest();
-}
-zxdg_surface_v6* XDGSurfaceWrapperImpl::zxdg_surface() const {
- DCHECK(zxdg_surface_v6_);
- return zxdg_surface_v6_.get();
+ surface->wayland_window_->HandleSurfaceConfigure(serial);
}
xdg_surface* XDGSurfaceWrapperImpl::xdg_surface() const {
@@ -265,112 +67,4 @@ xdg_surface* XDGSurfaceWrapperImpl::xdg_surface() const {
return xdg_surface_.get();
}
-// static
-void XDGSurfaceWrapperImpl::ConfigureDecoration(
- void* data,
- struct zxdg_toplevel_decoration_v1* decoration,
- uint32_t mode) {
- auto* surface = static_cast<XDGSurfaceWrapperImpl*>(data);
- DCHECK(surface);
- surface->SetTopLevelDecorationMode(
- static_cast<zxdg_toplevel_decoration_v1_mode>(mode));
-}
-
-bool XDGSurfaceWrapperImpl::InitializeStable(bool with_toplevel) {
- static const xdg_surface_listener xdg_surface_listener = {
- &XDGSurfaceWrapperImpl::ConfigureStable,
- };
- static const xdg_toplevel_listener xdg_toplevel_listener = {
- &XDGSurfaceWrapperImpl::ConfigureTopLevelStable,
- &XDGSurfaceWrapperImpl::CloseTopLevelStable,
- };
-
- // if this surface is created for the popup role, mark that it requires
- // configuration acknowledgement on each configure event.
- surface_for_popup_ = !with_toplevel;
-
- xdg_surface_.reset(xdg_wm_base_get_xdg_surface(
- connection_->shell(), wayland_window_->root_surface()->surface()));
- if (!xdg_surface_) {
- LOG(ERROR) << "Failed to create xdg_surface";
- return false;
- }
- xdg_surface_add_listener(xdg_surface_.get(), &xdg_surface_listener, this);
- // XDGPopup requires a separate surface to be created, so this is just a
- // request to get an xdg_surface for it.
- if (surface_for_popup_) {
- connection_->ScheduleFlush();
- return true;
- }
-
- xdg_toplevel_.reset(xdg_surface_get_toplevel(xdg_surface_.get()));
- if (!xdg_toplevel_) {
- LOG(ERROR) << "Failed to create xdg_toplevel";
- return false;
- }
-
- xdg_toplevel_add_listener(xdg_toplevel_.get(), &xdg_toplevel_listener, this);
-
- InitializeXdgDecoration();
-
- wayland_window_->root_surface()->Commit();
- connection_->ScheduleFlush();
- return true;
-}
-
-bool XDGSurfaceWrapperImpl::InitializeV6(bool with_toplevel) {
- static const zxdg_surface_v6_listener zxdg_surface_v6_listener = {
- &XDGSurfaceWrapperImpl::ConfigureV6,
- };
- static const zxdg_toplevel_v6_listener zxdg_toplevel_v6_listener = {
- &XDGSurfaceWrapperImpl::ConfigureTopLevelV6,
- &XDGSurfaceWrapperImpl::CloseTopLevelV6,
- };
-
- // if this surface is created for the popup role, mark that it requires
- // configuration acknowledgement on each configure event.
- surface_for_popup_ = !with_toplevel;
-
- zxdg_surface_v6_.reset(zxdg_shell_v6_get_xdg_surface(
- connection_->shell_v6(), wayland_window_->root_surface()->surface()));
- if (!zxdg_surface_v6_) {
- LOG(ERROR) << "Failed to create zxdg_surface";
- return false;
- }
- zxdg_surface_v6_add_listener(zxdg_surface_v6_.get(),
- &zxdg_surface_v6_listener, this);
- // XDGPopupV6 requires a separate surface to be created, so this is just a
- // request to get an xdg_surface for it.
- if (surface_for_popup_) {
- connection_->ScheduleFlush();
- return true;
- }
-
- zxdg_toplevel_v6_.reset(zxdg_surface_v6_get_toplevel(zxdg_surface_v6_.get()));
- if (!zxdg_toplevel_v6_) {
- LOG(ERROR) << "Failed to create zxdg_toplevel";
- return false;
- }
- zxdg_toplevel_v6_add_listener(zxdg_toplevel_v6_.get(),
- &zxdg_toplevel_v6_listener, this);
-
- wayland_window_->root_surface()->Commit();
- connection_->ScheduleFlush();
- return true;
-}
-
-void XDGSurfaceWrapperImpl::InitializeXdgDecoration() {
- if (connection_->xdg_decoration_manager_v1()) {
- DCHECK(!zxdg_toplevel_decoration_);
- static const zxdg_toplevel_decoration_v1_listener decoration_listener = {
- &XDGSurfaceWrapperImpl::ConfigureDecoration,
- };
- zxdg_toplevel_decoration_.reset(
- zxdg_decoration_manager_v1_get_toplevel_decoration(
- connection_->xdg_decoration_manager_v1(), xdg_toplevel_.get()));
- zxdg_toplevel_decoration_v1_add_listener(zxdg_toplevel_decoration_.get(),
- &decoration_listener, this);
- }
-}
-
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h b/chromium/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h
index da945779a76..c88eccfba82 100644
--- a/chromium/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h
+++ b/chromium/ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h
@@ -7,8 +7,6 @@
#include "ui/ozone/platform/wayland/host/shell_surface_wrapper.h"
-#include <xdg-decoration-unstable-v1-client-protocol.h>
-
#include <cstdint>
#include <string>
@@ -24,7 +22,7 @@ namespace ui {
class WaylandConnection;
class WaylandWindow;
-// Surface wrapper for xdg-shell stable and xdg-shell-unstable-v6
+// Surface wrapper for xdg-shell stable
class XDGSurfaceWrapperImpl : public ShellSurfaceWrapper {
public:
XDGSurfaceWrapperImpl(WaylandWindow* wayland_window,
@@ -34,84 +32,23 @@ class XDGSurfaceWrapperImpl : public ShellSurfaceWrapper {
~XDGSurfaceWrapperImpl() override;
// ShellSurfaceWrapper overrides:
- bool Initialize(bool with_toplevel) override;
- void SetMaximized() override;
- void UnSetMaximized() override;
- void SetFullscreen() override;
- void UnSetFullscreen() override;
- void SetMinimized() override;
- void SurfaceMove(WaylandConnection* connection) override;
- void SurfaceResize(WaylandConnection* connection, uint32_t hittest) override;
- void SetTitle(const base::string16& title) override;
- void AckConfigure() override;
+ bool Initialize() override;
+ void AckConfigure(uint32_t serial) override;
void SetWindowGeometry(const gfx::Rect& bounds) override;
- void SetMinSize(int32_t width, int32_t height) override;
- void SetMaxSize(int32_t width, int32_t height) override;
- void SetAppId(const std::string& app_id) override;
// xdg_surface_listener
- static void ConfigureV6(void* data,
- struct zxdg_surface_v6* zxdg_surface_v6,
- uint32_t serial);
- static void ConfigureTopLevelV6(void* data,
- struct zxdg_toplevel_v6* zxdg_toplevel_v6,
- int32_t width,
- int32_t height,
- struct wl_array* states);
-
- static void ConfigureStable(void* data,
- struct xdg_surface* xdg_surface,
- uint32_t serial);
- static void ConfigureTopLevelStable(void* data,
- struct xdg_toplevel* xdg_toplevel,
- int32_t width,
- int32_t height,
- struct wl_array* states);
-
- // xdg_toplevel_listener
- static void CloseTopLevelStable(void* data,
- struct xdg_toplevel* xdg_toplevel);
- static void CloseTopLevelV6(void* data,
- struct zxdg_toplevel_v6* zxdg_toplevel_v6);
-
- void SetTopLevelDecorationMode(
- zxdg_toplevel_decoration_v1_mode requested_mode);
- // zxdg_decoration_listener
- static void ConfigureDecoration(
- void* data,
- struct zxdg_toplevel_decoration_v1* decoration,
- uint32_t mode);
+ static void Configure(void* data,
+ struct xdg_surface* xdg_surface,
+ uint32_t serial);
struct xdg_surface* xdg_surface() const;
- zxdg_surface_v6* zxdg_surface() const;
private:
- // Initializes using XDG Shell Stable protocol.
- bool InitializeStable(bool with_toplevel);
- // Initializes using XDG Shell V6 protocol.
- bool InitializeV6(bool with_toplevel);
-
- // Initializes the xdg-decoration protocol extension, if available.
- void InitializeXdgDecoration();
-
// Non-owing WaylandWindow that uses this surface wrapper.
WaylandWindow* const wayland_window_;
WaylandConnection* const connection_;
- uint32_t pending_configure_serial_ = 0;
-
- wl::Object<zxdg_surface_v6> zxdg_surface_v6_;
- wl::Object<zxdg_toplevel_v6> zxdg_toplevel_v6_;
wl::Object<struct xdg_surface> xdg_surface_;
- wl::Object<xdg_toplevel> xdg_toplevel_;
- wl::Object<zxdg_toplevel_decoration_v1> zxdg_toplevel_decoration_;
-
- bool surface_for_popup_ = false;
-
- // Keeps track of the decoration mode currently in use if xdg-decoration
- // protocol extension is available, otherwise CLIENT_SIDE is assumed.
- enum zxdg_toplevel_decoration_v1_mode decoration_mode_ =
- ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE;
};
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.cc b/chromium/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.cc
new file mode 100644
index 00000000000..cd57c613a36
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.cc
@@ -0,0 +1,202 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.h"
+
+#include <xdg-decoration-unstable-v1-client-protocol.h>
+#include <xdg-shell-client-protocol.h>
+#include <xdg-shell-unstable-v6-client-protocol.h>
+
+#include "base/strings/utf_string_conversions.h"
+#include "ui/base/hit_test.h"
+#include "ui/ozone/platform/wayland/common/wayland_util.h"
+#include "ui/ozone/platform/wayland/host/shell_surface_wrapper.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
+#include "ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h"
+
+namespace ui {
+
+XDGToplevelWrapperImpl::XDGToplevelWrapperImpl(
+ std::unique_ptr<XDGSurfaceWrapperImpl> surface,
+ WaylandWindow* wayland_window,
+ WaylandConnection* connection)
+ : xdg_surface_wrapper_(std::move(surface)),
+ wayland_window_(wayland_window),
+ connection_(connection),
+ decoration_mode_(DecorationMode::kClientSide) {}
+
+XDGToplevelWrapperImpl::~XDGToplevelWrapperImpl() = default;
+
+bool XDGToplevelWrapperImpl::Initialize() {
+ if (!connection_->shell()) {
+ NOTREACHED() << "Wrong shell protocol";
+ return false;
+ }
+
+ static const xdg_toplevel_listener xdg_toplevel_listener = {
+ &XDGToplevelWrapperImpl::ConfigureTopLevel,
+ &XDGToplevelWrapperImpl::CloseTopLevel,
+ };
+
+ if (!xdg_surface_wrapper_)
+ return false;
+
+ xdg_toplevel_.reset(
+ xdg_surface_get_toplevel(xdg_surface_wrapper_->xdg_surface()));
+ if (!xdg_toplevel_) {
+ LOG(ERROR) << "Failed to create xdg_toplevel";
+ return false;
+ }
+
+ xdg_toplevel_add_listener(xdg_toplevel_.get(), &xdg_toplevel_listener, this);
+
+ InitializeXdgDecoration();
+
+ wayland_window_->root_surface()->Commit();
+ connection_->ScheduleFlush();
+ return true;
+}
+
+void XDGToplevelWrapperImpl::SetMaximized() {
+ DCHECK(xdg_toplevel_);
+ xdg_toplevel_set_maximized(xdg_toplevel_.get());
+}
+
+void XDGToplevelWrapperImpl::UnSetMaximized() {
+ DCHECK(xdg_toplevel_);
+ xdg_toplevel_unset_maximized(xdg_toplevel_.get());
+}
+
+void XDGToplevelWrapperImpl::SetFullscreen() {
+ DCHECK(xdg_toplevel_);
+ xdg_toplevel_set_fullscreen(xdg_toplevel_.get(), nullptr);
+}
+
+void XDGToplevelWrapperImpl::UnSetFullscreen() {
+ DCHECK(xdg_toplevel_);
+ xdg_toplevel_unset_fullscreen(xdg_toplevel_.get());
+}
+
+void XDGToplevelWrapperImpl::SetMinimized() {
+ DCHECK(xdg_toplevel_);
+ xdg_toplevel_set_minimized(xdg_toplevel_.get());
+}
+
+void XDGToplevelWrapperImpl::SurfaceMove(WaylandConnection* connection) {
+ DCHECK(xdg_toplevel_);
+ xdg_toplevel_move(xdg_toplevel_.get(), connection->seat(),
+ connection->serial());
+}
+
+void XDGToplevelWrapperImpl::SurfaceResize(WaylandConnection* connection,
+ uint32_t hittest) {
+ DCHECK(xdg_toplevel_);
+ xdg_toplevel_resize(xdg_toplevel_.get(), connection->seat(),
+ connection->serial(),
+ wl::IdentifyDirection(*connection, hittest));
+}
+
+void XDGToplevelWrapperImpl::SetTitle(const base::string16& title) {
+ DCHECK(xdg_toplevel_);
+ xdg_toplevel_set_title(xdg_toplevel_.get(), base::UTF16ToUTF8(title).c_str());
+}
+
+void XDGToplevelWrapperImpl::SetWindowGeometry(const gfx::Rect& bounds) {
+ xdg_surface_wrapper_->SetWindowGeometry(bounds);
+}
+
+void XDGToplevelWrapperImpl::SetMinSize(int32_t width, int32_t height) {
+ DCHECK(xdg_toplevel_);
+ xdg_toplevel_set_min_size(xdg_toplevel_.get(), width, height);
+}
+
+void XDGToplevelWrapperImpl::SetMaxSize(int32_t width, int32_t height) {
+ DCHECK(xdg_toplevel_);
+ xdg_toplevel_set_max_size(xdg_toplevel_.get(), width, height);
+}
+
+void XDGToplevelWrapperImpl::SetAppId(const std::string& app_id) {
+ DCHECK(xdg_toplevel_);
+ xdg_toplevel_set_app_id(xdg_toplevel_.get(), app_id.c_str());
+}
+
+void XDGToplevelWrapperImpl::SetDecoration(DecorationMode decoration) {
+ SetTopLevelDecorationMode(decoration);
+}
+
+void XDGToplevelWrapperImpl::AckConfigure(uint32_t serial) {
+ DCHECK(xdg_surface_wrapper_);
+ xdg_surface_wrapper_->AckConfigure(serial);
+}
+
+// static
+void XDGToplevelWrapperImpl::ConfigureTopLevel(
+ void* data,
+ struct xdg_toplevel* xdg_toplevel,
+ int32_t width,
+ int32_t height,
+ struct wl_array* states) {
+ auto* surface = static_cast<XDGToplevelWrapperImpl*>(data);
+ DCHECK(surface);
+
+ bool is_maximized =
+ CheckIfWlArrayHasValue(states, XDG_TOPLEVEL_STATE_MAXIMIZED);
+ bool is_fullscreen =
+ CheckIfWlArrayHasValue(states, XDG_TOPLEVEL_STATE_FULLSCREEN);
+ bool is_activated =
+ CheckIfWlArrayHasValue(states, XDG_TOPLEVEL_STATE_ACTIVATED);
+
+ surface->wayland_window_->HandleToplevelConfigure(
+ width, height, is_maximized, is_fullscreen, is_activated);
+}
+
+// static
+void XDGToplevelWrapperImpl::CloseTopLevel(void* data,
+ struct xdg_toplevel* xdg_toplevel) {
+ auto* surface = static_cast<XDGToplevelWrapperImpl*>(data);
+ DCHECK(surface);
+ surface->wayland_window_->OnCloseRequest();
+}
+
+void XDGToplevelWrapperImpl::SetTopLevelDecorationMode(
+ DecorationMode requested_mode) {
+ if (!zxdg_toplevel_decoration_ || requested_mode == decoration_mode_)
+ return;
+
+ decoration_mode_ = requested_mode;
+ zxdg_toplevel_decoration_v1_set_mode(zxdg_toplevel_decoration_.get(),
+ static_cast<uint32_t>(requested_mode));
+}
+
+// static
+void XDGToplevelWrapperImpl::ConfigureDecoration(
+ void* data,
+ struct zxdg_toplevel_decoration_v1* decoration,
+ uint32_t mode) {
+ auto* surface = static_cast<XDGToplevelWrapperImpl*>(data);
+ DCHECK(surface);
+ surface->SetTopLevelDecorationMode(static_cast<DecorationMode>(mode));
+}
+
+void XDGToplevelWrapperImpl::InitializeXdgDecoration() {
+ if (connection_->xdg_decoration_manager_v1()) {
+ DCHECK(!zxdg_toplevel_decoration_);
+ static const zxdg_toplevel_decoration_v1_listener decoration_listener = {
+ &XDGToplevelWrapperImpl::ConfigureDecoration,
+ };
+ zxdg_toplevel_decoration_.reset(
+ zxdg_decoration_manager_v1_get_toplevel_decoration(
+ connection_->xdg_decoration_manager_v1(), xdg_toplevel_.get()));
+ zxdg_toplevel_decoration_v1_add_listener(zxdg_toplevel_decoration_.get(),
+ &decoration_listener, this);
+ }
+}
+
+XDGSurfaceWrapperImpl* XDGToplevelWrapperImpl::xdg_surface_wrapper() const {
+ DCHECK(xdg_surface_wrapper_.get());
+ return xdg_surface_wrapper_.get();
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.h b/chromium/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.h
new file mode 100644
index 00000000000..867a54dd79e
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.h
@@ -0,0 +1,88 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_XDG_TOPLEVEL_WRAPPER_IMPL_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_XDG_TOPLEVEL_WRAPPER_IMPL_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "ui/ozone/platform/wayland/host/shell_toplevel_wrapper.h"
+
+namespace ui {
+
+class XDGSurfaceWrapperImpl;
+class WaylandConnection;
+class WaylandWindow;
+
+// Toplevel wrapper for xdg-shell stable
+class XDGToplevelWrapperImpl : public ShellToplevelWrapper {
+ public:
+ XDGToplevelWrapperImpl(std::unique_ptr<XDGSurfaceWrapperImpl> surface,
+ WaylandWindow* wayland_window,
+ WaylandConnection* connection);
+ XDGToplevelWrapperImpl(const XDGToplevelWrapperImpl&) = delete;
+ XDGToplevelWrapperImpl& operator=(const XDGToplevelWrapperImpl&) = delete;
+ ~XDGToplevelWrapperImpl() override;
+
+ // ShellSurfaceWrapper overrides:
+ bool Initialize() override;
+ void SetMaximized() override;
+ void UnSetMaximized() override;
+ void SetFullscreen() override;
+ void UnSetFullscreen() override;
+ void SetMinimized() override;
+ void SurfaceMove(WaylandConnection* connection) override;
+ void SurfaceResize(WaylandConnection* connection, uint32_t hittest) override;
+ void SetTitle(const base::string16& title) override;
+ void AckConfigure(uint32_t serial) override;
+ void SetWindowGeometry(const gfx::Rect& bounds) override;
+ void SetMinSize(int32_t width, int32_t height) override;
+ void SetMaxSize(int32_t width, int32_t height) override;
+ void SetAppId(const std::string& app_id) override;
+ void SetDecoration(DecorationMode decoration) override;
+
+ XDGSurfaceWrapperImpl* xdg_surface_wrapper() const;
+
+ private:
+ // xdg_toplevel_listener
+ static void ConfigureTopLevel(void* data,
+ struct xdg_toplevel* xdg_toplevel,
+ int32_t width,
+ int32_t height,
+ struct wl_array* states);
+ static void CloseTopLevel(void* data, struct xdg_toplevel* xdg_toplevel);
+
+ // zxdg_decoration_listener
+ static void ConfigureDecoration(
+ void* data,
+ struct zxdg_toplevel_decoration_v1* decoration,
+ uint32_t mode);
+
+ // Send request to wayland compositor to enable a requested decoration mode.
+ void SetTopLevelDecorationMode(DecorationMode requested_mode);
+
+ // Initializes the xdg-decoration protocol extension, if available.
+ void InitializeXdgDecoration();
+
+ // Ground surface for this toplevel wrapper.
+ std::unique_ptr<XDGSurfaceWrapperImpl> xdg_surface_wrapper_;
+
+ // Non-owing WaylandWindow that uses this toplevel wrapper.
+ WaylandWindow* const wayland_window_;
+ WaylandConnection* const connection_;
+
+ // XDG Shell Stable object.
+ wl::Object<xdg_toplevel> xdg_toplevel_;
+
+ wl::Object<zxdg_toplevel_decoration_v1> zxdg_toplevel_decoration_;
+
+ // On client side, it keeps track of the decoration mode currently in
+ // use if xdg-decoration protocol extension is available.
+ DecorationMode decoration_mode_;
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_XDG_TOPLEVEL_WRAPPER_IMPL_H_
diff --git a/chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_device.cc b/chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_device.cc
index afa819257d6..a9e657d387b 100644
--- a/chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_device.cc
+++ b/chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_device.cc
@@ -6,9 +6,9 @@
#include <primary-selection-unstable-v1-client-protocol.h>
-#include "ui/ozone/platform/wayland/host/zwp_primary_selection_offer.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
#include "ui/ozone/platform/wayland/host/wayland_data_source.h"
+#include "ui/ozone/platform/wayland/host/zwp_primary_selection_offer.h"
namespace ui {
@@ -18,7 +18,8 @@ ZwpPrimarySelectionDevice::ZwpPrimarySelectionDevice(
zwp_primary_selection_device_v1* data_device)
: WaylandDataDeviceBase(connection), data_device_(data_device) {
static const struct zwp_primary_selection_device_v1_listener kListener = {
- ZwpPrimarySelectionDevice::OnDataOffer, ZwpPrimarySelectionDevice::OnSelection};
+ ZwpPrimarySelectionDevice::OnDataOffer,
+ ZwpPrimarySelectionDevice::OnSelection};
zwp_primary_selection_device_v1_add_listener(data_device_.get(), &kListener,
this);
}
@@ -40,10 +41,6 @@ void ZwpPrimarySelectionDevice::OnDataOffer(
zwp_primary_selection_offer_v1* offer) {
auto* self = static_cast<ZwpPrimarySelectionDevice*>(data);
DCHECK(self);
-
- self->connection()->clipboard()->UpdateSequenceNumber(
- ClipboardBuffer::kSelection);
-
self->set_data_offer(std::make_unique<ZwpPrimarySelectionOffer>(offer));
}
@@ -56,17 +53,16 @@ void ZwpPrimarySelectionDevice::OnSelection(
DCHECK(self);
// 'offer' will be null to indicate that the selection is no longer valid,
- // i.e. there is no longer clipboard data available to paste.
+ // i.e. there is no longer selection data available to be fetched.
if (!offer) {
self->ResetDataOffer();
-
- // Clear Clipboard cache.
- self->connection()->clipboard()->SetData({}, {});
- return;
+ } else {
+ DCHECK(self->data_offer());
+ self->data_offer()->EnsureTextMimeTypeIfNeeded();
}
- DCHECK(self->data_offer());
- self->data_offer()->EnsureTextMimeTypeIfNeeded();
+ if (self->selection_delegate())
+ self->selection_delegate()->OnSelectionOffer(self->data_offer());
}
} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_device.h b/chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_device.h
index 69a7ee2c397..c4d36a2ee51 100644
--- a/chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_device.h
+++ b/chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_device.h
@@ -19,10 +19,11 @@ class WaylandConnection;
class ZwpPrimarySelectionDevice : public WaylandDataDeviceBase {
public:
ZwpPrimarySelectionDevice(WaylandConnection* connection,
- zwp_primary_selection_device_v1* data_device);
+ zwp_primary_selection_device_v1* data_device);
ZwpPrimarySelectionDevice(const ZwpPrimarySelectionDevice&) = delete;
- ZwpPrimarySelectionDevice& operator =(const ZwpPrimarySelectionDevice&) = delete;
+ ZwpPrimarySelectionDevice& operator=(const ZwpPrimarySelectionDevice&) =
+ delete;
~ZwpPrimarySelectionDevice() override;
diff --git a/chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_device_manager.h b/chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_device_manager.h
index 4f48f897065..8fa4d2f74db 100644
--- a/chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_device_manager.h
+++ b/chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_device_manager.h
@@ -23,7 +23,8 @@ class ZwpPrimarySelectionDeviceManager {
ZwpPrimarySelectionDeviceManager(
zwp_primary_selection_device_manager_v1* manager,
WaylandConnection* connection);
- ZwpPrimarySelectionDeviceManager(const ZwpPrimarySelectionDeviceManager&) = delete;
+ ZwpPrimarySelectionDeviceManager(const ZwpPrimarySelectionDeviceManager&) =
+ delete;
ZwpPrimarySelectionDeviceManager& operator=(
const ZwpPrimarySelectionDeviceManager&) = delete;
~ZwpPrimarySelectionDeviceManager();
diff --git a/chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_offer.cc b/chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_offer.cc
index 9a869e789b4..667cfd5abb4 100644
--- a/chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_offer.cc
+++ b/chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_offer.cc
@@ -10,8 +10,8 @@
#include <algorithm>
#include "base/check.h"
+#include "base/containers/contains.h"
#include "base/files/file_util.h"
-#include "base/stl_util.h"
#include "ui/base/clipboard/clipboard_constants.h"
namespace ui {
diff --git a/chromium/ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1.cc b/chromium/ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1.cc
index 8ae6849a3fe..456b19474f1 100644
--- a/chromium/ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1.cc
+++ b/chromium/ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1.cc
@@ -82,7 +82,21 @@ void ZWPTextInputWrapperV1::SetCursorRect(const gfx::Rect& rect) {
void ZWPTextInputWrapperV1::SetSurroundingText(
const base::string16& text,
const gfx::Range& selection_range) {
+ static constexpr size_t kWaylandMessageDataMaxLength = 4000;
const std::string text_utf8 = base::UTF16ToUTF8(text);
+ // The text length for set_surrounding_text can not be longer than the maximum
+ // length of wayland messages. The maximum length of the text is explicitly
+ // specified as 4000 in the protocol spec of text-input-unstable-v3.
+ // If the client is unware of the text around the cursor, we can skip sending
+ // set_surrounding_text requests. We fall back to this case when the text is
+ // too long.
+ // TODO(fukino): If the length of |text| doesn't fit into the 4000 bytes
+ // limitation, we should truncate the text and adjust indices of
+ // |selection_range| to make use of set_surrounding_text as much as possible.
+ // crbug.com/1173465.
+ if (text_utf8.size() > kWaylandMessageDataMaxLength)
+ return;
+
zwp_text_input_v1_set_surrounding_text(obj_.get(), text_utf8.c_str(),
selection_range.start(),
selection_range.end());
diff --git a/chromium/ui/ozone/platform/wayland/host/zxdg_popup_v6_wrapper_impl.cc b/chromium/ui/ozone/platform/wayland/host/zxdg_popup_v6_wrapper_impl.cc
new file mode 100644
index 00000000000..f506f0af5f9
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/host/zxdg_popup_v6_wrapper_impl.cc
@@ -0,0 +1,262 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/ozone/platform/wayland/host/zxdg_popup_v6_wrapper_impl.h"
+
+#include <xdg-shell-unstable-v6-client-protocol.h>
+
+#include <memory>
+
+#include "base/environment.h"
+#include "base/nix/xdg_util.h"
+#include "ui/events/event.h"
+#include "ui/events/event_constants.h"
+#include "ui/events/types/event_type.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/ozone/platform/wayland/common/wayland_util.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_pointer.h"
+#include "ui/ozone/platform/wayland/host/wayland_popup.h"
+#include "ui/ozone/platform/wayland/host/wayland_toplevel_window.h"
+#include "ui/ozone/platform/wayland/host/zxdg_surface_v6_wrapper_impl.h"
+#include "ui/ozone/platform/wayland/host/zxdg_toplevel_v6_wrapper_impl.h"
+
+namespace ui {
+
+namespace {
+
+uint32_t TranslateAnchor(WlAnchor anchor) {
+ switch (anchor) {
+ case WlAnchor::None:
+ return ZXDG_POSITIONER_V6_ANCHOR_NONE;
+ case WlAnchor::Top:
+ return ZXDG_POSITIONER_V6_ANCHOR_TOP;
+ case WlAnchor::Bottom:
+ return ZXDG_POSITIONER_V6_ANCHOR_BOTTOM;
+ case WlAnchor::Left:
+ return ZXDG_POSITIONER_V6_ANCHOR_LEFT;
+ case WlAnchor::Right:
+ return ZXDG_POSITIONER_V6_ANCHOR_RIGHT;
+ case WlAnchor::TopLeft:
+ return ZXDG_POSITIONER_V6_ANCHOR_TOP | ZXDG_POSITIONER_V6_ANCHOR_LEFT;
+ case WlAnchor::BottomLeft:
+ return ZXDG_POSITIONER_V6_ANCHOR_BOTTOM | ZXDG_POSITIONER_V6_ANCHOR_LEFT;
+ case WlAnchor::TopRight:
+ return ZXDG_POSITIONER_V6_ANCHOR_TOP | ZXDG_POSITIONER_V6_ANCHOR_RIGHT;
+ case WlAnchor::BottomRight:
+ return ZXDG_POSITIONER_V6_ANCHOR_BOTTOM | ZXDG_POSITIONER_V6_ANCHOR_RIGHT;
+ }
+}
+
+uint32_t TranslateGravity(WlGravity gravity) {
+ switch (gravity) {
+ case WlGravity::None:
+ return ZXDG_POSITIONER_V6_GRAVITY_NONE;
+ case WlGravity::Top:
+ return ZXDG_POSITIONER_V6_GRAVITY_TOP;
+ case WlGravity::Bottom:
+ return ZXDG_POSITIONER_V6_GRAVITY_BOTTOM;
+ case WlGravity::Left:
+ return ZXDG_POSITIONER_V6_GRAVITY_LEFT;
+ case WlGravity::Right:
+ return ZXDG_POSITIONER_V6_GRAVITY_RIGHT;
+ case WlGravity::TopLeft:
+ return ZXDG_POSITIONER_V6_GRAVITY_TOP | ZXDG_POSITIONER_V6_GRAVITY_LEFT;
+ case WlGravity::BottomLeft:
+ return ZXDG_POSITIONER_V6_GRAVITY_BOTTOM |
+ ZXDG_POSITIONER_V6_GRAVITY_LEFT;
+ case WlGravity::TopRight:
+ return ZXDG_POSITIONER_V6_GRAVITY_TOP | ZXDG_POSITIONER_V6_GRAVITY_RIGHT;
+ case WlGravity::BottomRight:
+ return ZXDG_POSITIONER_V6_GRAVITY_BOTTOM |
+ ZXDG_POSITIONER_V6_GRAVITY_RIGHT;
+ }
+}
+
+uint32_t TranslateConstraintAdjustment(
+ WlConstraintAdjustment constraint_adjustment) {
+ uint32_t res = 0;
+ if ((constraint_adjustment & WlConstraintAdjustment::SlideX) !=
+ WlConstraintAdjustment::None)
+ res |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_X;
+ if ((constraint_adjustment & WlConstraintAdjustment::SlideY) !=
+ WlConstraintAdjustment::None)
+ res |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_Y;
+ if ((constraint_adjustment & WlConstraintAdjustment::FlipX) !=
+ WlConstraintAdjustment::None)
+ res |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_X;
+ if ((constraint_adjustment & WlConstraintAdjustment::FlipY) !=
+ WlConstraintAdjustment::None)
+ res |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_Y;
+ if ((constraint_adjustment & WlConstraintAdjustment::ResizeX) !=
+ WlConstraintAdjustment::None)
+ res |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_X;
+ if ((constraint_adjustment & WlConstraintAdjustment::ResizeY) !=
+ WlConstraintAdjustment::None)
+ res |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_Y;
+ return res;
+}
+
+} // namespace
+
+ZXDGPopupV6WrapperImpl::ZXDGPopupV6WrapperImpl(
+ std::unique_ptr<ZXDGSurfaceV6WrapperImpl> surface,
+ WaylandWindow* wayland_window)
+ : wayland_window_(wayland_window),
+ zxdg_surface_v6_wrapper_(std::move(surface)) {
+ DCHECK(zxdg_surface_v6_wrapper_);
+ DCHECK(wayland_window_ && wayland_window_->parent_window());
+}
+
+ZXDGPopupV6WrapperImpl::~ZXDGPopupV6WrapperImpl() = default;
+
+bool ZXDGPopupV6WrapperImpl::Initialize(WaylandConnection* connection,
+ const gfx::Rect& bounds) {
+ if (!connection->shell() && !connection->shell_v6()) {
+ NOTREACHED() << "Wrong shell protocol";
+ return false;
+ }
+
+ ZXDGSurfaceV6WrapperImpl* parent_xdg_surface = nullptr;
+ // If the parent window is a popup, the surface of that popup must be used as
+ // a parent.
+ if (wl::IsMenuType(wayland_window_->parent_window()->type())) {
+ auto* wayland_popup =
+ static_cast<WaylandPopup*>(wayland_window_->parent_window());
+ ZXDGPopupV6WrapperImpl* popup =
+ static_cast<ZXDGPopupV6WrapperImpl*>(wayland_popup->shell_popup());
+ parent_xdg_surface = popup->zxdg_surface_v6_wrapper();
+ } else {
+ WaylandToplevelWindow* wayland_surface =
+ static_cast<WaylandToplevelWindow*>(wayland_window_->parent_window());
+ parent_xdg_surface = static_cast<ZXDGToplevelV6WrapperImpl*>(
+ wayland_surface->shell_toplevel())
+ ->zxdg_surface_v6_wrapper();
+ }
+
+ if (!zxdg_surface_v6_wrapper_ || !parent_xdg_surface)
+ return false;
+
+ auto new_bounds = bounds;
+ // Wayland doesn't allow empty bounds. If a zero or negative size is set, the
+ // invalid_input error is raised. Thus, use the least possible one.
+ // WaylandPopup will update its bounds upon the following configure event.
+ if (new_bounds.IsEmpty())
+ new_bounds.set_size({1, 1});
+
+ if (connection->shell_v6())
+ return InitializeV6(connection, new_bounds, parent_xdg_surface);
+
+ return false;
+}
+
+bool ZXDGPopupV6WrapperImpl::InitializeV6(
+ WaylandConnection* connection,
+ const gfx::Rect& bounds,
+ ZXDGSurfaceV6WrapperImpl* parent_xdg_surface) {
+ static const struct zxdg_popup_v6_listener zxdg_popup_v6_listener = {
+ &ZXDGPopupV6WrapperImpl::Configure,
+ &ZXDGPopupV6WrapperImpl::PopupDone,
+ };
+
+ zxdg_positioner_v6* positioner =
+ CreatePositioner(connection, wayland_window_->parent_window(), bounds);
+ if (!positioner)
+ return false;
+
+ zxdg_popup_v6_.reset(zxdg_surface_v6_get_popup(
+ zxdg_surface_v6_wrapper_->zxdg_surface(),
+ parent_xdg_surface->zxdg_surface(), positioner));
+ if (!zxdg_popup_v6_)
+ return false;
+
+ zxdg_positioner_v6_destroy(positioner);
+
+ if (CanGrabPopup(connection)) {
+ zxdg_popup_v6_grab(zxdg_popup_v6_.get(), connection->seat(),
+ connection->serial());
+ }
+ zxdg_popup_v6_add_listener(zxdg_popup_v6_.get(), &zxdg_popup_v6_listener,
+ this);
+
+ wayland_window_->root_surface()->Commit();
+ return true;
+}
+
+void ZXDGPopupV6WrapperImpl::AckConfigure(uint32_t serial) {
+ DCHECK(zxdg_surface_v6_wrapper_);
+ zxdg_surface_v6_wrapper_->AckConfigure(serial);
+}
+
+zxdg_positioner_v6* ZXDGPopupV6WrapperImpl::CreatePositioner(
+ WaylandConnection* connection,
+ WaylandWindow* parent_window,
+ const gfx::Rect& bounds) {
+ struct zxdg_positioner_v6* positioner;
+ positioner = zxdg_shell_v6_create_positioner(connection->shell_v6());
+ if (!positioner)
+ return nullptr;
+
+ auto menu_type = GetMenuTypeForPositioner(connection, parent_window);
+
+ // The parent we got must be the topmost in the stack of the same family
+ // windows.
+ DCHECK_EQ(parent_window->GetTopMostChildWindow(), parent_window);
+
+ // Place anchor to the end of the possible position.
+ gfx::Rect anchor_rect = GetAnchorRect(
+ menu_type, bounds,
+ gfx::ScaleToRoundedRect(parent_window->GetBounds(),
+ 1.0 / parent_window->buffer_scale()));
+
+ zxdg_positioner_v6_set_anchor_rect(positioner, anchor_rect.x(),
+ anchor_rect.y(), anchor_rect.width(),
+ anchor_rect.height());
+ zxdg_positioner_v6_set_size(positioner, bounds.width(), bounds.height());
+ zxdg_positioner_v6_set_anchor(positioner,
+ TranslateAnchor(GetAnchor(menu_type, bounds)));
+ zxdg_positioner_v6_set_gravity(
+ positioner, TranslateGravity(GetGravity(menu_type, bounds)));
+ zxdg_positioner_v6_set_constraint_adjustment(
+ positioner,
+ TranslateConstraintAdjustment(GetConstraintAdjustment(menu_type)));
+ return positioner;
+}
+
+// static
+void ZXDGPopupV6WrapperImpl::Configure(void* data,
+ struct zxdg_popup_v6* zxdg_popup_v6,
+ int32_t x,
+ int32_t y,
+ int32_t width,
+ int32_t height) {
+ // As long as the Wayland compositor repositions/requires to position windows
+ // relative to their parents, do not propagate final bounds information to
+ // Chromium. The browser places windows in respect to screen origin, but
+ // Wayland requires doing so in respect to parent window's origin. To properly
+ // place windows, the bounds are translated and adjusted according to the
+ // Wayland compositor needs during WaylandWindow::CreateXdgPopup call.
+ WaylandWindow* window =
+ static_cast<ZXDGPopupV6WrapperImpl*>(data)->wayland_window_;
+ DCHECK(window);
+ window->HandlePopupConfigure({x, y, width, height});
+}
+
+// static
+void ZXDGPopupV6WrapperImpl::PopupDone(void* data,
+ struct zxdg_popup_v6* zxdg_popup_v6) {
+ WaylandWindow* window =
+ static_cast<ZXDGPopupV6WrapperImpl*>(data)->wayland_window_;
+ DCHECK(window);
+ window->Hide();
+ window->OnCloseRequest();
+}
+
+ZXDGSurfaceV6WrapperImpl* ZXDGPopupV6WrapperImpl::zxdg_surface_v6_wrapper()
+ const {
+ DCHECK(zxdg_surface_v6_wrapper_.get());
+ return zxdg_surface_v6_wrapper_.get();
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/zxdg_popup_v6_wrapper_impl.h b/chromium/ui/ozone/platform/wayland/host/zxdg_popup_v6_wrapper_impl.h
new file mode 100644
index 00000000000..4c32a1e8f51
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/host/zxdg_popup_v6_wrapper_impl.h
@@ -0,0 +1,64 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_ZXDG_POPUP_V6_WRAPPER_IMPL_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_ZXDG_POPUP_V6_WRAPPER_IMPL_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "ui/ozone/platform/wayland/host/shell_popup_wrapper.h"
+
+namespace ui {
+
+class ZXDGSurfaceV6WrapperImpl;
+class WaylandConnection;
+class WaylandWindow;
+
+// Popup wrapper for xdg-shell-unstable-v6
+class ZXDGPopupV6WrapperImpl : public ShellPopupWrapper {
+ public:
+ ZXDGPopupV6WrapperImpl(std::unique_ptr<ZXDGSurfaceV6WrapperImpl> surface,
+ WaylandWindow* wayland_window);
+ ~ZXDGPopupV6WrapperImpl() override;
+
+ // XDGPopupWrapper:
+ bool Initialize(WaylandConnection* connection,
+ const gfx::Rect& bounds) override;
+ void AckConfigure(uint32_t serial) override;
+
+ private:
+ bool InitializeV6(WaylandConnection* connection,
+ const gfx::Rect& bounds,
+ ZXDGSurfaceV6WrapperImpl* parent_zxdg_surface_v6_wrapper);
+ struct zxdg_positioner_v6* CreatePositioner(WaylandConnection* connection,
+ WaylandWindow* parent_window,
+ const gfx::Rect& bounds);
+
+ // zxdg_popup_v6_listener
+ static void Configure(void* data,
+ struct zxdg_popup_v6* zxdg_popup_v6,
+ int32_t x,
+ int32_t y,
+ int32_t width,
+ int32_t height);
+ static void PopupDone(void* data, struct zxdg_popup_v6* zxdg_popup_v6);
+
+ ZXDGSurfaceV6WrapperImpl* zxdg_surface_v6_wrapper() const;
+
+ // Non-owned WaylandWindow that uses this popup.
+ WaylandWindow* const wayland_window_;
+
+ // Ground surface for this popup.
+ std::unique_ptr<ZXDGSurfaceV6WrapperImpl> zxdg_surface_v6_wrapper_;
+
+ // XDG Shell V6 object.
+ wl::Object<zxdg_popup_v6> zxdg_popup_v6_;
+
+ DISALLOW_COPY_AND_ASSIGN(ZXDGPopupV6WrapperImpl);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_ZXDG_POPUP_V6_WRAPPER_IMPL_H_
diff --git a/chromium/ui/ozone/platform/wayland/host/zxdg_surface_v6_wrapper_impl.cc b/chromium/ui/ozone/platform/wayland/host/zxdg_surface_v6_wrapper_impl.cc
new file mode 100644
index 00000000000..385638d528b
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/host/zxdg_surface_v6_wrapper_impl.cc
@@ -0,0 +1,74 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/ozone/platform/wayland/host/zxdg_surface_v6_wrapper_impl.h"
+
+#include <xdg-shell-unstable-v6-client-protocol.h>
+
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
+
+namespace ui {
+
+ZXDGSurfaceV6WrapperImpl::ZXDGSurfaceV6WrapperImpl(
+ WaylandWindow* wayland_window,
+ WaylandConnection* connection)
+ : wayland_window_(wayland_window), connection_(connection) {}
+
+ZXDGSurfaceV6WrapperImpl::~ZXDGSurfaceV6WrapperImpl() = default;
+
+bool ZXDGSurfaceV6WrapperImpl::Initialize() {
+ if (!connection_->shell_v6()) {
+ NOTREACHED() << "Wrong shell protocol";
+ return false;
+ }
+
+ static const zxdg_surface_v6_listener zxdg_surface_v6_listener = {
+ &ZXDGSurfaceV6WrapperImpl::Configure,
+ };
+
+ zxdg_surface_v6_.reset(zxdg_shell_v6_get_xdg_surface(
+ connection_->shell_v6(), wayland_window_->root_surface()->surface()));
+ if (!zxdg_surface_v6_) {
+ LOG(ERROR) << "Failed to create zxdg_surface";
+ return false;
+ }
+
+ zxdg_surface_v6_add_listener(zxdg_surface_v6_.get(),
+ &zxdg_surface_v6_listener, this);
+ connection_->ScheduleFlush();
+ return true;
+}
+
+void ZXDGSurfaceV6WrapperImpl::AckConfigure(uint32_t serial) {
+ DCHECK(zxdg_surface_v6_);
+ zxdg_surface_v6_ack_configure(zxdg_surface_v6_.get(), serial);
+ connection_->wayland_window_manager()->NotifyWindowConfigured(
+ wayland_window_);
+}
+
+void ZXDGSurfaceV6WrapperImpl::SetWindowGeometry(const gfx::Rect& bounds) {
+ DCHECK(zxdg_surface_v6_);
+ zxdg_surface_v6_set_window_geometry(zxdg_surface_v6_.get(), bounds.x(),
+ bounds.y(), bounds.width(),
+ bounds.height());
+}
+
+// static
+void ZXDGSurfaceV6WrapperImpl::Configure(
+ void* data,
+ struct zxdg_surface_v6* zxdg_surface_v6,
+ uint32_t serial) {
+ auto* surface = static_cast<ZXDGSurfaceV6WrapperImpl*>(data);
+ DCHECK(surface);
+
+ surface->wayland_window_->HandleSurfaceConfigure(serial);
+}
+
+zxdg_surface_v6* ZXDGSurfaceV6WrapperImpl::zxdg_surface() const {
+ DCHECK(zxdg_surface_v6_);
+ return zxdg_surface_v6_.get();
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/zxdg_surface_v6_wrapper_impl.h b/chromium/ui/ozone/platform/wayland/host/zxdg_surface_v6_wrapper_impl.h
new file mode 100644
index 00000000000..8fa9a289b6b
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/host/zxdg_surface_v6_wrapper_impl.h
@@ -0,0 +1,56 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_ZXDG_SURFACE_V6_WRAPPER_IMPL_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_ZXDG_SURFACE_V6_WRAPPER_IMPL_H_
+
+#include "ui/ozone/platform/wayland/host/shell_surface_wrapper.h"
+
+#include <cstdint>
+#include <string>
+
+#include "base/strings/string16.h"
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
+
+namespace gfx {
+class Rect;
+}
+
+namespace ui {
+
+class WaylandConnection;
+class WaylandWindow;
+
+// Surface wrapper for xdg-shell-unstable-v6
+class ZXDGSurfaceV6WrapperImpl : public ShellSurfaceWrapper {
+ public:
+ ZXDGSurfaceV6WrapperImpl(WaylandWindow* wayland_window,
+ WaylandConnection* connection);
+ ZXDGSurfaceV6WrapperImpl(const ZXDGSurfaceV6WrapperImpl&) = delete;
+ ZXDGSurfaceV6WrapperImpl& operator=(const ZXDGSurfaceV6WrapperImpl&) = delete;
+ ~ZXDGSurfaceV6WrapperImpl() override;
+
+ // ShellSurfaceWrapper overrides:
+ bool Initialize() override;
+ void AckConfigure(uint32_t serial) override;
+ void SetWindowGeometry(const gfx::Rect& bounds) override;
+
+ // zxdg_surface_v6_listener
+ static void Configure(void* data,
+ struct zxdg_surface_v6* zxdg_surface_v6,
+ uint32_t serial);
+
+ zxdg_surface_v6* zxdg_surface() const;
+
+ private:
+ // Non-owing WaylandWindow that uses this surface wrapper.
+ WaylandWindow* const wayland_window_;
+ WaylandConnection* const connection_;
+
+ wl::Object<zxdg_surface_v6> zxdg_surface_v6_;
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_ZXDG_SURFACE_V6_WRAPPER_IMPL_H_
diff --git a/chromium/ui/ozone/platform/wayland/host/zxdg_toplevel_v6_wrapper_impl.cc b/chromium/ui/ozone/platform/wayland/host/zxdg_toplevel_v6_wrapper_impl.cc
new file mode 100644
index 00000000000..ea31771a618
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/host/zxdg_toplevel_v6_wrapper_impl.cc
@@ -0,0 +1,166 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/ozone/platform/wayland/host/zxdg_toplevel_v6_wrapper_impl.h"
+
+#include <xdg-decoration-unstable-v1-client-protocol.h>
+#include <xdg-shell-client-protocol.h>
+#include <xdg-shell-unstable-v6-client-protocol.h>
+
+#include "base/strings/utf_string_conversions.h"
+#include "ui/base/hit_test.h"
+#include "ui/ozone/platform/wayland/common/wayland_util.h"
+#include "ui/ozone/platform/wayland/host/shell_surface_wrapper.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
+#include "ui/ozone/platform/wayland/host/zxdg_surface_v6_wrapper_impl.h"
+
+namespace ui {
+
+ZXDGToplevelV6WrapperImpl::ZXDGToplevelV6WrapperImpl(
+ std::unique_ptr<ZXDGSurfaceV6WrapperImpl> surface,
+ WaylandWindow* wayland_window,
+ WaylandConnection* connection)
+ : zxdg_surface_v6_wrapper_(std::move(surface)),
+ wayland_window_(wayland_window),
+ connection_(connection) {}
+
+ZXDGToplevelV6WrapperImpl::~ZXDGToplevelV6WrapperImpl() = default;
+
+bool ZXDGToplevelV6WrapperImpl::Initialize() {
+ if (!connection_->shell_v6()) {
+ NOTREACHED() << "Wrong shell protocol";
+ return false;
+ }
+
+ static const zxdg_toplevel_v6_listener zxdg_toplevel_v6_listener = {
+ &ZXDGToplevelV6WrapperImpl::ConfigureTopLevel,
+ &ZXDGToplevelV6WrapperImpl::CloseTopLevel,
+ };
+
+ if (!zxdg_surface_v6_wrapper_)
+ return false;
+
+ zxdg_toplevel_v6_.reset(
+ zxdg_surface_v6_get_toplevel(zxdg_surface_v6_wrapper_->zxdg_surface()));
+ if (!zxdg_toplevel_v6_) {
+ LOG(ERROR) << "Failed to create zxdg_toplevel";
+ return false;
+ }
+ zxdg_toplevel_v6_add_listener(zxdg_toplevel_v6_.get(),
+ &zxdg_toplevel_v6_listener, this);
+
+ wayland_window_->root_surface()->Commit();
+ connection_->ScheduleFlush();
+ return true;
+}
+
+void ZXDGToplevelV6WrapperImpl::SetMaximized() {
+ DCHECK(zxdg_toplevel_v6_);
+ zxdg_toplevel_v6_set_maximized(zxdg_toplevel_v6_.get());
+}
+
+void ZXDGToplevelV6WrapperImpl::UnSetMaximized() {
+ DCHECK(zxdg_toplevel_v6_);
+ zxdg_toplevel_v6_unset_maximized(zxdg_toplevel_v6_.get());
+}
+
+void ZXDGToplevelV6WrapperImpl::SetFullscreen() {
+ DCHECK(zxdg_toplevel_v6_);
+ zxdg_toplevel_v6_set_fullscreen(zxdg_toplevel_v6_.get(), nullptr);
+}
+
+void ZXDGToplevelV6WrapperImpl::UnSetFullscreen() {
+ DCHECK(zxdg_toplevel_v6_);
+ zxdg_toplevel_v6_unset_fullscreen(zxdg_toplevel_v6_.get());
+}
+
+void ZXDGToplevelV6WrapperImpl::SetMinimized() {
+ DCHECK(zxdg_toplevel_v6_);
+ zxdg_toplevel_v6_set_minimized(zxdg_toplevel_v6_.get());
+}
+
+void ZXDGToplevelV6WrapperImpl::SurfaceMove(WaylandConnection* connection) {
+ DCHECK(zxdg_toplevel_v6_);
+ zxdg_toplevel_v6_move(zxdg_toplevel_v6_.get(), connection->seat(),
+ connection->serial());
+}
+
+void ZXDGToplevelV6WrapperImpl::SurfaceResize(WaylandConnection* connection,
+ uint32_t hittest) {
+ DCHECK(zxdg_toplevel_v6_);
+ zxdg_toplevel_v6_resize(zxdg_toplevel_v6_.get(), connection->seat(),
+ connection->serial(),
+ wl::IdentifyDirection(*connection, hittest));
+}
+
+void ZXDGToplevelV6WrapperImpl::SetTitle(const base::string16& title) {
+ DCHECK(zxdg_toplevel_v6_);
+ zxdg_toplevel_v6_set_title(zxdg_toplevel_v6_.get(),
+ base::UTF16ToUTF8(title).c_str());
+}
+
+void ZXDGToplevelV6WrapperImpl::SetWindowGeometry(const gfx::Rect& bounds) {
+ zxdg_surface_v6_wrapper_->SetWindowGeometry(bounds);
+}
+
+void ZXDGToplevelV6WrapperImpl::SetMinSize(int32_t width, int32_t height) {
+ DCHECK(zxdg_toplevel_v6_);
+ zxdg_toplevel_v6_set_min_size(zxdg_toplevel_v6_.get(), width, height);
+}
+
+void ZXDGToplevelV6WrapperImpl::SetMaxSize(int32_t width, int32_t height) {
+ DCHECK(zxdg_toplevel_v6_);
+ zxdg_toplevel_v6_set_max_size(zxdg_toplevel_v6_.get(), width, height);
+}
+
+void ZXDGToplevelV6WrapperImpl::SetAppId(const std::string& app_id) {
+ DCHECK(zxdg_toplevel_v6_);
+ zxdg_toplevel_v6_set_app_id(zxdg_toplevel_v6_.get(), app_id.c_str());
+}
+
+void ZXDGToplevelV6WrapperImpl::SetDecoration(DecorationMode decoration) {}
+
+void ZXDGToplevelV6WrapperImpl::AckConfigure(uint32_t serial) {
+ DCHECK(zxdg_surface_v6_wrapper_);
+ zxdg_surface_v6_wrapper_->AckConfigure(serial);
+}
+
+// static
+void ZXDGToplevelV6WrapperImpl::ConfigureTopLevel(
+ void* data,
+ struct zxdg_toplevel_v6* zxdg_toplevel_v6,
+ int32_t width,
+ int32_t height,
+ struct wl_array* states) {
+ auto* surface = static_cast<ZXDGToplevelV6WrapperImpl*>(data);
+ DCHECK(surface);
+
+ bool is_maximized =
+ CheckIfWlArrayHasValue(states, ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED);
+ bool is_fullscreen =
+ CheckIfWlArrayHasValue(states, ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN);
+ bool is_activated =
+ CheckIfWlArrayHasValue(states, ZXDG_TOPLEVEL_V6_STATE_ACTIVATED);
+
+ surface->wayland_window_->HandleToplevelConfigure(
+ width, height, is_maximized, is_fullscreen, is_activated);
+}
+
+// static
+void ZXDGToplevelV6WrapperImpl::CloseTopLevel(
+ void* data,
+ struct zxdg_toplevel_v6* zxdg_toplevel_v6) {
+ auto* surface = static_cast<ZXDGToplevelV6WrapperImpl*>(data);
+ DCHECK(surface);
+ surface->wayland_window_->OnCloseRequest();
+}
+
+ZXDGSurfaceV6WrapperImpl* ZXDGToplevelV6WrapperImpl::zxdg_surface_v6_wrapper()
+ const {
+ DCHECK(zxdg_surface_v6_wrapper_.get());
+ return zxdg_surface_v6_wrapper_.get();
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/host/zxdg_toplevel_v6_wrapper_impl.h b/chromium/ui/ozone/platform/wayland/host/zxdg_toplevel_v6_wrapper_impl.h
new file mode 100644
index 00000000000..7727bfec007
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/host/zxdg_toplevel_v6_wrapper_impl.h
@@ -0,0 +1,72 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_ZXDG_TOPLEVEL_V6_WRAPPER_IMPL_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_ZXDG_TOPLEVEL_V6_WRAPPER_IMPL_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "ui/ozone/platform/wayland/host/shell_toplevel_wrapper.h"
+
+namespace ui {
+
+class ZXDGSurfaceV6WrapperImpl;
+class WaylandConnection;
+class WaylandWindow;
+
+// Toplevel wrapper for xdg-shell-unstable-v6
+class ZXDGToplevelV6WrapperImpl : public ShellToplevelWrapper {
+ public:
+ ZXDGToplevelV6WrapperImpl(std::unique_ptr<ZXDGSurfaceV6WrapperImpl> surface,
+ WaylandWindow* wayland_window,
+ WaylandConnection* connection);
+ ZXDGToplevelV6WrapperImpl(const ZXDGToplevelV6WrapperImpl&) = delete;
+ ZXDGToplevelV6WrapperImpl& operator=(const ZXDGToplevelV6WrapperImpl&) =
+ delete;
+ ~ZXDGToplevelV6WrapperImpl() override;
+
+ // ShellSurfaceWrapper overrides:
+ bool Initialize() override;
+ void SetMaximized() override;
+ void UnSetMaximized() override;
+ void SetFullscreen() override;
+ void UnSetFullscreen() override;
+ void SetMinimized() override;
+ void SurfaceMove(WaylandConnection* connection) override;
+ void SurfaceResize(WaylandConnection* connection, uint32_t hittest) override;
+ void SetTitle(const base::string16& title) override;
+ void AckConfigure(uint32_t serial) override;
+ void SetWindowGeometry(const gfx::Rect& bounds) override;
+ void SetMinSize(int32_t width, int32_t height) override;
+ void SetMaxSize(int32_t width, int32_t height) override;
+ void SetAppId(const std::string& app_id) override;
+ void SetDecoration(DecorationMode decoration) override;
+
+ ZXDGSurfaceV6WrapperImpl* zxdg_surface_v6_wrapper() const;
+
+ private:
+ // zxdg_toplevel_v6_listener
+ static void ConfigureTopLevel(void* data,
+ struct zxdg_toplevel_v6* zxdg_toplevel_v6,
+ int32_t width,
+ int32_t height,
+ struct wl_array* states);
+ static void CloseTopLevel(void* data,
+ struct zxdg_toplevel_v6* zxdg_toplevel_v6);
+
+ // Ground surface for this toplevel wrapper.
+ std::unique_ptr<ZXDGSurfaceV6WrapperImpl> zxdg_surface_v6_wrapper_;
+
+ // Non-owing WaylandWindow that uses this toplevel wrapper.
+ WaylandWindow* const wayland_window_;
+ WaylandConnection* const connection_;
+
+ // XDG Shell V6 object.
+ wl::Object<zxdg_toplevel_v6> zxdg_toplevel_v6_;
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_ZXDG_TOPLEVEL_V6_WRAPPER_IMPL_H_
diff --git a/chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc b/chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc
index ab143cad1e2..b568018a8dc 100644
--- a/chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc
+++ b/chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc
@@ -16,7 +16,6 @@
#include "base/threading/sequenced_task_runner_handle.h"
#include "ui/base/buildflags.h"
#include "ui/base/cursor/cursor_factory.h"
-#include "ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h"
#include "ui/base/ime/linux/input_method_auralinux.h"
#include "ui/base/ui_base_features.h"
#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
@@ -31,6 +30,7 @@
#include "ui/ozone/platform/wayland/host/wayland_buffer_manager_connector.h"
#include "ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_cursor_factory.h"
#include "ui/ozone/platform/wayland/host/wayland_input_method_context_factory.h"
#include "ui/ozone/platform/wayland/host/wayland_menu_utils.h"
#include "ui/ozone/platform/wayland/host/wayland_output_manager.h"
@@ -171,7 +171,11 @@ class OzonePlatformWayland : public OzonePlatform {
buffer_manager_connector_ = std::make_unique<WaylandBufferManagerConnector>(
connection_->buffer_manager_host());
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
cursor_factory_ = std::make_unique<BitmapCursorFactoryOzone>();
+#else
+ cursor_factory_ = std::make_unique<WaylandCursorFactory>(connection_.get());
+#endif
input_controller_ = CreateStubInputController();
gpu_platform_support_host_.reset(CreateStubGpuPlatformSupportHost());
@@ -224,6 +228,8 @@ class OzonePlatformWayland : public OzonePlatform {
// https://github.com/wayland-project/wayland-protocols/commit/76d1ae8c65739eff3434ef219c58a913ad34e988
properties->custom_frame_pref_default = true;
+ properties->uses_external_vulkan_image_factory = true;
+
// Wayland doesn't provide clients with global screen coordinates.
// Instead, it forces clients to position windows relative to their top
// level windows if the have child-parent relationship. In case of
@@ -250,7 +256,8 @@ class OzonePlatformWayland : public OzonePlatform {
properties;
static bool initialized = false;
if (!initialized) {
- properties->supports_overlays = ui::IsWaylandOverlayDelegationEnabled();
+ properties->supports_overlays =
+ ui::IsWaylandOverlayDelegationEnabled() && connection_->viewporter();
initialized = true;
}
return *properties;
diff --git a/chromium/ui/ozone/platform/wayland/test/mock_surface.cc b/chromium/ui/ozone/platform/wayland/test/mock_surface.cc
index d7ec1ec227b..33b9ae348c0 100644
--- a/chromium/ui/ozone/platform/wayland/test/mock_surface.cc
+++ b/chromium/ui/ozone/platform/wayland/test/mock_surface.cc
@@ -4,6 +4,8 @@
#include "ui/ozone/platform/wayland/test/mock_surface.h"
+#include "ui/ozone/platform/wayland/test/test_region.h"
+
namespace wl {
namespace {
@@ -20,13 +22,13 @@ void Attach(wl_client* client,
void SetOpaqueRegion(wl_client* client,
wl_resource* resource,
wl_resource* region) {
- GetUserDataAs<MockSurface>(resource)->SetOpaqueRegion(region);
+ GetUserDataAs<MockSurface>(resource)->SetOpaqueRegionImpl(region);
}
void SetInputRegion(wl_client* client,
wl_resource* resource,
wl_resource* region) {
- GetUserDataAs<MockSurface>(resource)->SetInputRegion(region);
+ GetUserDataAs<MockSurface>(resource)->SetInputRegionImpl(region);
}
void Damage(wl_client* client,
@@ -100,6 +102,35 @@ MockSurface* MockSurface::FromResource(wl_resource* resource) {
return GetUserDataAs<MockSurface>(resource);
}
+void MockSurface::SetOpaqueRegionImpl(wl_resource* region) {
+ if (!region) {
+ opaque_region_ = gfx::Rect(-1, -1, 0, 0);
+ return;
+ }
+ auto bounds = GetUserDataAs<TestRegion>(region)->getBounds();
+ opaque_region_ =
+ gfx::Rect(bounds.fLeft, bounds.fTop, bounds.fRight - bounds.fLeft,
+ bounds.fBottom - bounds.fTop);
+
+ SetOpaqueRegion(region);
+}
+
+void MockSurface::SetInputRegionImpl(wl_resource* region) {
+ // It is unsafe to always treat |region| as a valid pointer.
+ // According to the protocol about wl_surface::set_input_region
+ // "A NULL wl_region cuases the input region to be set to infinite."
+ if (!region) {
+ input_region_ = gfx::Rect(-1, -1, 0, 0);
+ return;
+ }
+ auto bounds = GetUserDataAs<TestRegion>(region)->getBounds();
+ input_region_ =
+ gfx::Rect(bounds.fLeft, bounds.fTop, bounds.fRight - bounds.fLeft,
+ bounds.fBottom - bounds.fTop);
+
+ SetInputRegion(region);
+}
+
void MockSurface::AttachNewBuffer(wl_resource* buffer_resource,
int32_t x,
int32_t y) {
diff --git a/chromium/ui/ozone/platform/wayland/test/mock_surface.h b/chromium/ui/ozone/platform/wayland/test/mock_surface.h
index 5c4e5cfb795..fd682b8fa87 100644
--- a/chromium/ui/ozone/platform/wayland/test/mock_surface.h
+++ b/chromium/ui/ozone/platform/wayland/test/mock_surface.h
@@ -56,6 +56,9 @@ class MockSurface : public ServerObject {
void set_viewport(TestViewport* viewport) { viewport_ = viewport; }
TestViewport* viewport() { return viewport_; }
+ gfx::Rect opaque_region() const { return opaque_region_; }
+ gfx::Rect input_region() const { return input_region_; }
+
void set_frame_callback(wl_resource* callback_resource) {
DCHECK(!frame_callback_);
frame_callback_ = callback_resource;
@@ -66,6 +69,8 @@ class MockSurface : public ServerObject {
bool has_role() const { return !!xdg_surface_ || !!sub_surface_; }
+ void SetOpaqueRegionImpl(wl_resource* region);
+ void SetInputRegionImpl(wl_resource* region);
void AttachNewBuffer(wl_resource* buffer_resource, int32_t x, int32_t y);
void DestroyPrevAttachedBuffer();
void ReleaseBuffer(wl_resource* buffer);
@@ -75,6 +80,8 @@ class MockSurface : public ServerObject {
MockXdgSurface* xdg_surface_ = nullptr;
TestSubSurface* sub_surface_ = nullptr;
TestViewport* viewport_ = nullptr;
+ gfx::Rect opaque_region_ = {-1, -1, 0, 0};
+ gfx::Rect input_region_ = {-1, -1, 0, 0};
wl_resource* frame_callback_ = nullptr;
diff --git a/chromium/ui/ozone/platform/wayland/test/test_compositor.cc b/chromium/ui/ozone/platform/wayland/test/test_compositor.cc
index 9a6244b0cb3..80fab9ab4bb 100644
--- a/chromium/ui/ozone/platform/wayland/test/test_compositor.cc
+++ b/chromium/ui/ozone/platform/wayland/test/test_compositor.cc
@@ -12,9 +12,9 @@
namespace wl {
-namespace {
+constexpr uint32_t TestCompositor::kVersion;
-constexpr uint32_t kCompositorVersion = 4;
+namespace {
void CreateSurface(wl_client* client,
wl_resource* compositor_resource,
@@ -42,11 +42,9 @@ const struct wl_compositor_interface kTestCompositorImpl = {
};
TestCompositor::TestCompositor()
- : GlobalObject(&wl_compositor_interface,
- &kTestCompositorImpl,
- kCompositorVersion) {}
+ : GlobalObject(&wl_compositor_interface, &kTestCompositorImpl, kVersion) {}
-TestCompositor::~TestCompositor() {}
+TestCompositor::~TestCompositor() = default;
void TestCompositor::AddSurface(MockSurface* surface) {
surfaces_.push_back(surface);
diff --git a/chromium/ui/ozone/platform/wayland/test/test_compositor.h b/chromium/ui/ozone/platform/wayland/test/test_compositor.h
index 1b54cfb4173..6cc6c0f5759 100644
--- a/chromium/ui/ozone/platform/wayland/test/test_compositor.h
+++ b/chromium/ui/ozone/platform/wayland/test/test_compositor.h
@@ -17,6 +17,8 @@ class MockSurface;
// Manage wl_compositor object.
class TestCompositor : public GlobalObject {
public:
+ static constexpr uint32_t kVersion = 4;
+
TestCompositor();
~TestCompositor() override;
diff --git a/chromium/ui/ozone/platform/wayland/test/test_data_offer.cc b/chromium/ui/ozone/platform/wayland/test/test_data_offer.cc
index 73736c7b002..861e685ae9a 100644
--- a/chromium/ui/ozone/platform/wayland/test/test_data_offer.cc
+++ b/chromium/ui/ozone/platform/wayland/test/test_data_offer.cc
@@ -54,7 +54,8 @@ void DataOfferSetActions(wl_client* client,
wl_resource* resource,
uint32_t dnd_actions,
uint32_t preferred_action) {
- NOTIMPLEMENTED();
+ GetUserDataAs<TestDataOffer>(resource)->SetActions(dnd_actions,
+ preferred_action);
}
} // namespace
@@ -85,4 +86,19 @@ void TestDataOffer::OnOffer(const std::string& mime_type,
wl_data_offer_send_offer(resource(), mime_type.c_str());
}
+void TestDataOffer::SetActions(uint32_t dnd_actions,
+ uint32_t preferred_action) {
+ client_supported_actions_ = dnd_actions;
+ client_preferred_action_ = preferred_action;
+ OnAction(client_preferred_action_);
+}
+
+void TestDataOffer::OnSourceActions(uint32_t source_actions) {
+ wl_data_offer_send_source_actions(resource(), source_actions);
+}
+
+void TestDataOffer::OnAction(uint32_t dnd_action) {
+ wl_data_offer_send_action(resource(), dnd_action);
+}
+
} // namespace wl
diff --git a/chromium/ui/ozone/platform/wayland/test/test_data_offer.h b/chromium/ui/ozone/platform/wayland/test/test_data_offer.h
index 6b96582da7d..77c389c6919 100644
--- a/chromium/ui/ozone/platform/wayland/test/test_data_offer.h
+++ b/chromium/ui/ozone/platform/wayland/test/test_data_offer.h
@@ -34,11 +34,21 @@ class TestDataOffer : public ServerObject {
void Receive(const std::string& mime_type, base::ScopedFD fd);
void OnOffer(const std::string& mime_type, ui::PlatformClipboard::Data data);
+ void SetActions(uint32_t dnd_actions, uint32_t preferred_action);
+
+ void OnSourceActions(uint32_t source_actions);
+ void OnAction(uint32_t dnd_action);
+
+ uint32_t supported_actions() const { return client_supported_actions_; }
+ uint32_t preferred_action() const { return client_preferred_action_; }
private:
const scoped_refptr<base::SequencedTaskRunner> task_runner_;
ui::PlatformClipboard::DataMap data_to_offer_;
+ uint32_t client_supported_actions_ = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
+ uint32_t client_preferred_action_ = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
+
base::WeakPtrFactory<TestDataOffer> write_data_weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(TestDataOffer);
diff --git a/chromium/ui/ozone/platform/wayland/test/test_wayland_server_thread.cc b/chromium/ui/ozone/platform/wayland/test/test_wayland_server_thread.cc
index 6cf79816b5c..7cf3193cbc2 100644
--- a/chromium/ui/ozone/platform/wayland/test/test_wayland_server_thread.cc
+++ b/chromium/ui/ozone/platform/wayland/test/test_wayland_server_thread.cc
@@ -36,6 +36,10 @@ TestWaylandServerThread::~TestWaylandServerThread() {
if (client_)
wl_client_destroy(client_);
+ // Stop watching the descriptor here to guarantee that no new events will come
+ // during or after the destruction of the display.
+ controller_.StopWatchingFileDescriptor();
+
Resume();
Stop();
}
@@ -146,7 +150,8 @@ TestWaylandServerThread::CreateMessagePump() {
void TestWaylandServerThread::OnFileCanReadWithoutBlocking(int fd) {
wl_event_loop_dispatch(event_loop_, 0);
- wl_display_flush_clients(display_.get());
+ if (display_)
+ wl_display_flush_clients(display_.get());
}
void TestWaylandServerThread::OnFileCanWriteWithoutBlocking(int fd) {}
diff --git a/chromium/ui/ozone/platform/wayland/test/wayland_drag_drop_test.cc b/chromium/ui/ozone/platform/wayland/test/wayland_drag_drop_test.cc
new file mode 100644
index 00000000000..259e8541c78
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/test/wayland_drag_drop_test.cc
@@ -0,0 +1,127 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/ozone/platform/wayland/test/wayland_drag_drop_test.h"
+
+#include <wayland-util.h>
+
+#include <cstdint>
+
+#include "base/callback.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
+#include "ui/ozone/platform/wayland/test/mock_surface.h"
+#include "ui/ozone/platform/wayland/test/test_data_device.h"
+#include "ui/ozone/platform/wayland/test/test_data_device_manager.h"
+#include "ui/ozone/platform/wayland/test/test_data_offer.h"
+#include "ui/ozone/platform/wayland/test/test_data_source.h"
+
+namespace ui {
+
+WaylandDragDropTest::WaylandDragDropTest() = default;
+
+void WaylandDragDropTest::SendDndEnter(WaylandWindow* window,
+ const gfx::Point& location) {
+ auto* surface = server_.GetObject<wl::MockSurface>(
+ window->root_surface()->GetSurfaceId());
+ OfferAndEnter(surface, location);
+}
+
+void WaylandDragDropTest::SendDndLeave() {
+ data_device_manager_->data_device()->OnLeave();
+}
+
+void WaylandDragDropTest::SendDndMotion(const gfx::Point& location) {
+ EXPECT_TRUE(data_source_);
+ wl_fixed_t x = wl_fixed_from_int(location.x());
+ wl_fixed_t y = wl_fixed_from_int(location.y());
+ data_device_manager_->data_device()->OnMotion(NextTime(), x, y);
+}
+
+void WaylandDragDropTest::SendDndCancelled() {
+ EXPECT_TRUE(data_source_);
+ data_source_->OnCancelled();
+}
+
+void WaylandDragDropTest::ReadData(
+ const std::string& mime_type,
+ wl::TestDataSource::ReadDataCallback callback) {
+ ASSERT_TRUE(data_source_);
+ data_source_->ReadData(mime_type, std::move(callback));
+}
+
+void WaylandDragDropTest::SetUp() {
+ WaylandTest::SetUp();
+ Sync();
+
+ data_device_manager_ = server_.data_device_manager();
+ ASSERT_TRUE(data_device_manager_);
+
+ data_source_ = nullptr;
+ data_device_manager_->data_device()->set_delegate(this);
+}
+
+void WaylandDragDropTest::TearDown() {
+ data_device_manager_->data_device()->set_delegate(nullptr);
+ data_device_manager_ = nullptr;
+}
+
+// wl::TestDataDevice::Delegate:
+void WaylandDragDropTest::StartDrag(wl::TestDataSource* source,
+ wl::MockSurface* origin,
+ uint32_t serial) {
+ EXPECT_FALSE(data_source_);
+ data_source_ = source;
+ OfferAndEnter(origin, {});
+}
+
+uint32_t WaylandDragDropTest::NextSerial() const {
+ static uint32_t serial = 0;
+ return ++serial;
+}
+
+uint32_t WaylandDragDropTest::NextTime() const {
+ static uint32_t timestamp = 0;
+ return ++timestamp;
+}
+
+void WaylandDragDropTest::OfferAndEnter(wl::MockSurface* surface,
+ const gfx::Point& location) {
+ ASSERT_TRUE(data_source_);
+ auto* data_device = data_device_manager_->data_device();
+
+ // Emulate server sending an wl_data_device::offer event.
+ auto* data_offer = data_device->OnDataOffer();
+ for (const auto& mime_type : data_source_->mime_types())
+ data_offer->OnOffer(mime_type, {});
+
+ // Emulate server sending an wl_data_device::enter event.
+ wl_data_device_send_enter(
+ data_device->resource(), NextSerial(), surface->resource(),
+ wl_fixed_from_int(location.x()), wl_fixed_from_int(location.y()),
+ data_offer->resource());
+}
+
+void WaylandDragDropTest::ScheduleTestTask(base::OnceClosure test_task) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(&WaylandDragDropTest::RunTestTask,
+ base::Unretained(this), std::move(test_task)));
+}
+
+void WaylandDragDropTest::RunTestTask(base::OnceClosure test_task) {
+ Sync();
+
+ // The data source is created asynchronously by the drag controller. If it is
+ // null at this point, it means that the task for that has not yet executed,
+ // so try again a bit later.
+ if (!data_device_manager_->data_source()) {
+ ScheduleTestTask(std::move(test_task));
+ return;
+ }
+
+ std::move(test_task).Run();
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/wayland/test/wayland_drag_drop_test.h b/chromium/ui/ozone/platform/wayland/test/wayland_drag_drop_test.h
new file mode 100644
index 00000000000..3455909c765
--- /dev/null
+++ b/chromium/ui/ozone/platform/wayland/test/wayland_drag_drop_test.h
@@ -0,0 +1,68 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_OZONE_PLATFORM_WAYLAND_TEST_WAYLAND_DRAG_DROP_TEST_H_
+#define UI_OZONE_PLATFORM_WAYLAND_TEST_WAYLAND_DRAG_DROP_TEST_H_
+
+#include "base/callback_forward.h"
+#include "ui/ozone/platform/wayland/test/test_data_device.h"
+#include "ui/ozone/platform/wayland/test/test_data_source.h"
+#include "ui/ozone/platform/wayland/test/wayland_test.h"
+
+namespace gfx {
+class Point;
+}
+
+namespace wl {
+class MockSurface;
+class TestDataDeviceManager;
+} // namespace wl
+
+namespace ui {
+
+class WaylandWindow;
+
+// Base class for Wayland drag-and-drop tests. Public methods allow test code to
+// emulate dnd-related events from the test compositor and can be used in both
+// data and window dragging test cases.
+class WaylandDragDropTest : public WaylandTest,
+ public wl::TestDataDevice::Delegate {
+ public:
+ WaylandDragDropTest();
+ WaylandDragDropTest(const WaylandDragDropTest&) = delete;
+ WaylandDragDropTest& operator=(const WaylandDragDropTest&) = delete;
+
+ // These are public for convenience, as they must be callable from lambda
+ // functions, usually posted to task queue while the drag loop runs.
+ void SendDndEnter(WaylandWindow* window, const gfx::Point& location);
+ void SendDndLeave();
+ void SendDndMotion(const gfx::Point& location);
+ void SendDndCancelled();
+ void ReadData(const std::string& mime_type,
+ wl::TestDataSource::ReadDataCallback callback);
+
+ protected:
+ // WaylandTest:
+ void SetUp() override;
+ void TearDown() override;
+
+ // wl::TestDataDevice::Delegate:
+ void StartDrag(wl::TestDataSource* source,
+ wl::MockSurface* origin,
+ uint32_t serial) override;
+
+ void OfferAndEnter(wl::MockSurface* surface, const gfx::Point& location);
+ uint32_t NextSerial() const;
+ uint32_t NextTime() const;
+ void ScheduleTestTask(base::OnceClosure test_task);
+ void RunTestTask(base::OnceClosure test_task);
+
+ // Server objects
+ wl::TestDataDeviceManager* data_device_manager_;
+ wl::TestDataSource* data_source_;
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_WAYLAND_TEST_WAYLAND_DRAG_DROP_TEST_H_
diff --git a/chromium/ui/ozone/platform/wayland/test/wayland_test.cc b/chromium/ui/ozone/platform/wayland/test/wayland_test.cc
index 58e395d8e82..b226e31dbc3 100644
--- a/chromium/ui/ozone/platform/wayland/test/wayland_test.cc
+++ b/chromium/ui/ozone/platform/wayland/test/wayland_test.cc
@@ -69,6 +69,7 @@ void WaylandTest::SetUp() {
properties.type = PlatformWindowType::kWindow;
window_ = WaylandWindow::Create(&delegate_, connection_.get(),
std::move(properties));
+ window_->set_update_visual_size_immediately(true);
ASSERT_NE(widget_, gfx::kNullAcceleratedWidget);
window_->Show(false);
@@ -118,17 +119,17 @@ void WaylandTest::SendConfigureEvent(wl::MockXdgSurface* xdg_surface,
// Please note that toplevel surfaces may not exist if the surface was created
// for the popup role.
if (GetParam() == kXdgShellV6) {
- zxdg_surface_v6_send_configure(xdg_surface->resource(), serial);
if (xdg_surface->xdg_toplevel()) {
zxdg_toplevel_v6_send_configure(xdg_surface->xdg_toplevel()->resource(),
width, height, states);
}
+ zxdg_surface_v6_send_configure(xdg_surface->resource(), serial);
} else {
- xdg_surface_send_configure(xdg_surface->resource(), serial);
if (xdg_surface->xdg_toplevel()) {
xdg_toplevel_send_configure(xdg_surface->xdg_toplevel()->resource(),
width, height, states);
}
+ xdg_surface_send_configure(xdg_surface->resource(), serial);
}
}
diff --git a/chromium/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc b/chromium/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc
index 8721395d80b..a8767ae8265 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc
+++ b/chromium/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc
@@ -84,7 +84,7 @@ class WaylandBufferManagerTest : public WaylandTest {
// callback and bind the interface again if the manager failed.
manager_host_->SetTerminateGpuCallback(callback_.Get());
auto interface_ptr = manager_host_->BindInterface();
- buffer_manager_gpu_->Initialize(std::move(interface_ptr), {}, false);
+ buffer_manager_gpu_->Initialize(std::move(interface_ptr), {}, false, false);
}
protected:
@@ -119,7 +119,7 @@ class WaylandBufferManagerTest : public WaylandTest {
// Recreate the gpu side manager (the production code does the
// same).
buffer_manager_gpu_ = std::make_unique<WaylandBufferManagerGpu>();
- buffer_manager_gpu_->Initialize(std::move(interface_ptr), {},
+ buffer_manager_gpu_->Initialize(std::move(interface_ptr), {}, false,
false);
}));
}
@@ -341,7 +341,8 @@ TEST_P(WaylandBufferManagerTest, CreateAndDestroyBuffer) {
CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/,
kBufferId1);
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, window_->GetBounds());
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, window_->GetBounds(),
+ window_->GetBounds());
CreateDmabufBasedBufferAndSetTerminateExpectation(true /*fail*/,
kBufferId1);
@@ -364,7 +365,8 @@ TEST_P(WaylandBufferManagerTest, CreateAndDestroyBuffer) {
CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/,
kBufferId1);
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, window_->GetBounds());
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, window_->GetBounds(),
+ window_->GetBounds());
DestroyBufferAndSetTerminateExpectation(gfx::kNullAcceleratedWidget,
kBufferId1, true /*fail*/);
@@ -385,7 +387,8 @@ TEST_P(WaylandBufferManagerTest, CreateAndDestroyBuffer) {
CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/,
kBufferId1);
// Attach to a surface.
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, window_->GetBounds());
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, window_->GetBounds(),
+ window_->GetBounds());
// Created non-attached buffer as well.
CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/,
@@ -418,7 +421,32 @@ TEST_P(WaylandBufferManagerTest, CommitBufferNonExistingBufferId) {
// Can't commit for non-existing buffer id.
SetTerminateCallbackExpectationAndDestroyChannel(&callback_, true /*fail*/);
buffer_manager_gpu_->CommitBuffer(window_->GetWidget(), 5u,
- window_->GetBounds());
+ window_->GetBounds(), window_->GetBounds());
+
+ Sync();
+}
+
+TEST_P(WaylandBufferManagerTest, CommitOverlaysNonExistingBufferId) {
+ EXPECT_CALL(*server_.zwp_linux_dmabuf_v1(), CreateParams(_, _, _)).Times(1);
+ CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/, 1u);
+
+ // Can't commit for non-existing buffer id.
+ SetTerminateCallbackExpectationAndDestroyChannel(&callback_, true /*fail*/);
+
+ std::vector<ui::ozone::mojom::WaylandOverlayConfigPtr> overlay_configs;
+ overlay_configs.push_back(ui::ozone::mojom::WaylandOverlayConfig::New(
+ INT32_MIN, gfx::OverlayTransform::OVERLAY_TRANSFORM_NONE, 1u,
+ window_->GetBounds(), gfx::RectF(), window_->GetBounds(), false,
+ gfx::GpuFenceHandle()));
+
+ // Non-existing buffer id
+ overlay_configs.push_back(ui::ozone::mojom::WaylandOverlayConfig::New(
+ 0, gfx::OverlayTransform::OVERLAY_TRANSFORM_NONE, 2u,
+ window_->GetBounds(), gfx::RectF(), window_->GetBounds(), false,
+ gfx::GpuFenceHandle()));
+
+ buffer_manager_gpu_->CommitOverlays(window_->GetWidget(),
+ std::move(overlay_configs));
Sync();
}
@@ -431,7 +459,7 @@ TEST_P(WaylandBufferManagerTest, CommitBufferNullWidget) {
// Can't commit for non-existing widget.
SetTerminateCallbackExpectationAndDestroyChannel(&callback_, true /*fail*/);
buffer_manager_gpu_->CommitBuffer(gfx::kNullAcceleratedWidget, kBufferId,
- window_->GetBounds());
+ window_->GetBounds(), window_->GetBounds());
Sync();
}
@@ -474,7 +502,7 @@ TEST_P(WaylandBufferManagerTest, EnsureCorrectOrderOfCallbacks) {
ASSERT_TRUE(!connection_->presentation());
EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId1, _)).Times(1);
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds, bounds);
Sync();
@@ -485,7 +513,7 @@ TEST_P(WaylandBufferManagerTest, EnsureCorrectOrderOfCallbacks) {
Sync();
// Commit second buffer now.
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds, bounds);
Sync();
@@ -514,7 +542,7 @@ TEST_P(WaylandBufferManagerTest, EnsureCorrectOrderOfCallbacks) {
.Times(1);
// Commit second buffer now.
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds, bounds);
Sync();
@@ -591,7 +619,7 @@ TEST_P(WaylandBufferManagerTest,
EXPECT_CALL(mock_surface_gpu,
OnSubmission(kBufferId1, gfx::SwapResult::SWAP_ACK))
.Times(1);
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds, bounds);
mock_surface->SendFrameCallback();
Sync();
@@ -600,7 +628,7 @@ TEST_P(WaylandBufferManagerTest,
mock_wp_presentation->set_presentation_callback(nullptr);
// Commit second buffer now.
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds, bounds);
mock_surface->SendFrameCallback();
Sync();
@@ -621,7 +649,7 @@ TEST_P(WaylandBufferManagerTest,
// Commit buffer 3 then send the presentation callback for it. This should
// not call OnPresentation as OnSubmission hasn't been called yet.
EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(0);
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId3, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId3, bounds, bounds);
mock_surface->SendFrameCallback();
mock_wp_presentation->SendPresentationCallback();
Sync();
@@ -703,7 +731,7 @@ TEST_P(WaylandBufferManagerTest,
EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(0);
// Commit first buffer
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds, bounds);
Sync();
@@ -721,7 +749,7 @@ TEST_P(WaylandBufferManagerTest,
EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(0);
// Commit second buffer
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds, bounds);
Sync();
@@ -741,7 +769,7 @@ TEST_P(WaylandBufferManagerTest,
EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(0);
// Commit third buffer
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId3, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId3, bounds, bounds);
Sync();
@@ -826,7 +854,7 @@ TEST_P(WaylandBufferManagerTest, TestCommitBufferConditions) {
EXPECT_CALL(*mock_surface, Commit()).Times(0);
buffer_manager_gpu_->CommitBuffer(widget, kDmabufBufferId,
- window_->GetBounds());
+ window_->GetBounds(), window_->GetBounds());
Sync();
EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(1);
@@ -859,7 +887,7 @@ TEST_P(WaylandBufferManagerTest, TestCommitBufferConditions) {
EXPECT_CALL(*mock_surface, Commit()).Times(0);
buffer_manager_gpu_->CommitBuffer(widget, kDmabufBufferId2,
- window_->GetBounds());
+ window_->GetBounds(), window_->GetBounds());
Sync();
@@ -925,14 +953,16 @@ TEST_P(WaylandBufferManagerTest, TestCommitBufferConditionsAckConfigured) {
EXPECT_CALL(*mock_surface, Frame(_)).Times(0);
EXPECT_CALL(*mock_surface, Commit()).Times(0);
- buffer_manager_gpu_->CommitBuffer(widget, kDmabufBufferId,
- window_->GetBounds());
+ buffer_manager_gpu_->CommitBuffer(
+ widget, kDmabufBufferId, window_->GetBounds(), window_->GetBounds());
Sync();
if (type != PlatformWindowType::kTooltip) {
DCHECK(mock_surface->xdg_surface());
ActivateSurface(mock_surface->xdg_surface());
} else {
+ // WaylandAuxiliaryWindow uses the focused window as a parent.
+ window_->SetPointerFocus(true);
// See the comment near Show() call above.
temp_window->Show(false);
}
@@ -943,6 +973,7 @@ TEST_P(WaylandBufferManagerTest, TestCommitBufferConditionsAckConfigured) {
Sync();
+ window_->SetPointerFocus(false);
temp_window.reset();
DestroyBufferAndSetTerminateExpectation(widget, kDmabufBufferId,
false /*fail*/);
@@ -991,7 +1022,7 @@ TEST_P(WaylandBufferManagerTest, AnonymousBufferAttachedAndReleased) {
EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId1, _)).Times(1);
// Commit second buffer now.
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds, bounds);
Sync();
@@ -1015,7 +1046,7 @@ TEST_P(WaylandBufferManagerTest, AnonymousBufferAttachedAndReleased) {
EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId2, _)).Times(1);
// Commit second buffer now.
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds, bounds);
Sync();
@@ -1039,7 +1070,7 @@ TEST_P(WaylandBufferManagerTest, AnonymousBufferAttachedAndReleased) {
.Times(0);
EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId3, _)).Times(0);
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId3, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId3, bounds, bounds);
Sync();
@@ -1075,7 +1106,7 @@ TEST_P(WaylandBufferManagerTest, DestroyBufferForDestroyedWindow) {
Sync();
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId,
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId, temp_window->GetBounds(),
temp_window->GetBounds());
Sync();
@@ -1108,7 +1139,7 @@ TEST_P(WaylandBufferManagerTest, DestroyedWindowNoSubmissionSingleBuffer) {
temp_window.reset();
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId, bounds, bounds);
Sync();
@@ -1149,7 +1180,7 @@ TEST_P(WaylandBufferManagerTest, DestroyedWindowNoSubmissionMultipleBuffers) {
EXPECT_CALL(mock_surface_gpu, OnSubmission(_, _)).Times(1);
EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(1);
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds, bounds);
Sync();
@@ -1169,7 +1200,7 @@ TEST_P(WaylandBufferManagerTest, DestroyedWindowNoSubmissionMultipleBuffers) {
.Times(1);
EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId2, _)).Times(1);
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds, bounds);
Sync();
@@ -1181,7 +1212,7 @@ TEST_P(WaylandBufferManagerTest, DestroyedWindowNoSubmissionMultipleBuffers) {
EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(0);
temp_window.reset();
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds, bounds);
Sync();
@@ -1217,7 +1248,7 @@ TEST_P(WaylandBufferManagerTest, DestroyBufferCommittedTwiceInARow) {
.Times(1);
EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId1, _)).Times(1);
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds, bounds);
mock_surface->SendFrameCallback();
Sync();
testing::Mock::VerifyAndClearExpectations(&mock_surface_gpu);
@@ -1226,11 +1257,11 @@ TEST_P(WaylandBufferManagerTest, DestroyBufferCommittedTwiceInARow) {
EXPECT_CALL(mock_surface_gpu, OnSubmission(_, _)).Times(0);
EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(0);
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds, bounds);
mock_surface->SendFrameCallback();
Sync();
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds, bounds);
mock_surface->SendFrameCallback();
Sync();
@@ -1281,7 +1312,7 @@ TEST_P(WaylandBufferManagerTest, ReleaseBufferCommittedTwiceInARow) {
.Times(1);
EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId1, _)).Times(1);
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds, bounds);
mock_surface->SendFrameCallback();
Sync();
testing::Mock::VerifyAndClearExpectations(&mock_surface_gpu);
@@ -1291,11 +1322,11 @@ TEST_P(WaylandBufferManagerTest, ReleaseBufferCommittedTwiceInARow) {
EXPECT_CALL(mock_surface_gpu, OnSubmission(_, _)).Times(0);
EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(0);
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds, bounds);
mock_surface->SendFrameCallback();
Sync();
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds, bounds);
mock_surface->SendFrameCallback();
Sync();
@@ -1346,7 +1377,7 @@ TEST_P(WaylandBufferManagerTest, ReleaseOrderDifferentToCommitOrder) {
EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId1, _)).Times(1);
EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(1);
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds, bounds);
mock_surface->SendFrameCallback();
Sync();
testing::Mock::VerifyAndClearExpectations(&mock_surface_gpu);
@@ -1357,12 +1388,12 @@ TEST_P(WaylandBufferManagerTest, ReleaseOrderDifferentToCommitOrder) {
EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(0);
EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(2);
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds, bounds);
mock_surface->SendFrameCallback();
Sync();
auto* wl_buffer2 = mock_surface->attached_buffer();
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId3, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId3, bounds, bounds);
mock_surface->SendFrameCallback();
Sync();
@@ -1432,7 +1463,7 @@ TEST_P(WaylandBufferManagerTest,
.Times(1);
EXPECT_CALL(*mock_surface, Commit()).Times(1);
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds, bounds);
Sync();
@@ -1454,7 +1485,7 @@ TEST_P(WaylandBufferManagerTest,
EXPECT_CALL(*mock_surface, Commit()).Times(1);
// Commit second buffer now.
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds, bounds);
Sync();
@@ -1496,7 +1527,7 @@ TEST_P(WaylandBufferManagerTest,
EXPECT_CALL(*mock_surface, Commit()).Times(1);
// Commit second buffer now.
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds, bounds);
Sync();
@@ -1530,7 +1561,7 @@ TEST_P(WaylandBufferManagerTest,
.Times(1);
EXPECT_CALL(*mock_surface, Commit()).Times(1);
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds, bounds);
Sync();
@@ -1579,12 +1610,77 @@ TEST_P(WaylandBufferManagerTest, OnSubmissionCalledForSingleBuffer) {
.Times(1);
EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId1, _)).Times(1);
- buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds);
+ buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds, bounds);
Sync();
DestroyBufferAndSetTerminateExpectation(widget, kBufferId1, false /*fail*/);
}
+// Tests that when CommitOverlays(), root_surface can only be committed once all
+// overlays in the frame are committed.
+TEST_P(WaylandBufferManagerTest, RootSurfaceIsCommittedLast) {
+ constexpr uint32_t kBufferId1 = 1;
+ constexpr uint32_t kBufferId2 = 2;
+ constexpr uint32_t kBufferId3 = 3;
+
+ const gfx::AcceleratedWidget widget = window_->GetWidget();
+ const gfx::Rect bounds = window_->GetBounds();
+
+ MockSurfaceGpu mock_surface_gpu(buffer_manager_gpu_.get(), widget);
+
+ auto* linux_dmabuf = server_.zwp_linux_dmabuf_v1();
+ EXPECT_CALL(*linux_dmabuf, CreateParams(_, _, _)).Times(3);
+ CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/, kBufferId1);
+ CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/, kBufferId2);
+ CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/, kBufferId3);
+
+ Sync();
+
+ // Ack creation for only the first 2 wl_buffers.
+ LOG(ERROR) << linux_dmabuf->buffer_params().size();
+ zwp_linux_buffer_params_v1_send_created(
+ linux_dmabuf->buffer_params()[0]->resource(),
+ linux_dmabuf->buffer_params()[0]->buffer_resource());
+ zwp_linux_buffer_params_v1_send_created(
+ linux_dmabuf->buffer_params()[1]->resource(),
+ linux_dmabuf->buffer_params()[1]->buffer_resource());
+
+ auto* mock_surface = server_.GetObject<wl::MockSurface>(
+ window_->root_surface()->GetSurfaceId());
+
+ // root_surface shall not be committed as one of its subsurface is not
+ // committed yet due to pending wl_buffer creation.
+ EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(0);
+ EXPECT_CALL(*mock_surface, Frame(_)).Times(0);
+ EXPECT_CALL(*mock_surface, Commit()).Times(0);
+
+ std::vector<ui::ozone::mojom::WaylandOverlayConfigPtr> overlay_configs;
+ overlay_configs.push_back(ui::ozone::mojom::WaylandOverlayConfig::New(
+ INT32_MIN, gfx::OverlayTransform::OVERLAY_TRANSFORM_NONE, kBufferId1,
+ bounds, gfx::RectF(), bounds, false, gfx::GpuFenceHandle()));
+ overlay_configs.push_back(ui::ozone::mojom::WaylandOverlayConfig::New(
+ 0, gfx::OverlayTransform::OVERLAY_TRANSFORM_NONE, kBufferId2, bounds,
+ gfx::RectF(), bounds, false, gfx::GpuFenceHandle()));
+ overlay_configs.push_back(ui::ozone::mojom::WaylandOverlayConfig::New(
+ 1, gfx::OverlayTransform::OVERLAY_TRANSFORM_NONE, kBufferId3, bounds,
+ gfx::RectF(), bounds, false, gfx::GpuFenceHandle()));
+ buffer_manager_gpu_->CommitOverlays(window_->GetWidget(),
+ std::move(overlay_configs));
+ Sync();
+ testing::Mock::VerifyAndClearExpectations(mock_surface);
+
+ // Once wl_buffer is created, all subsurfaces are committed, hence
+ // root_surface can be committed.
+ zwp_linux_buffer_params_v1_send_created(
+ linux_dmabuf->buffer_params()[0]->resource(),
+ linux_dmabuf->buffer_params()[0]->buffer_resource());
+ EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(1);
+ EXPECT_CALL(*mock_surface, Frame(_)).Times(1);
+ EXPECT_CALL(*mock_surface, Commit()).Times(1);
+
+ Sync();
+}
+
INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
WaylandBufferManagerTest,
::testing::Values(kXdgShellStable));
diff --git a/chromium/ui/ozone/platform/x11/BUILD.gn b/chromium/ui/ozone/platform/x11/BUILD.gn
index 731c7d7c0a0..7cf0bfdff6c 100644
--- a/chromium/ui/ozone/platform/x11/BUILD.gn
+++ b/chromium/ui/ozone/platform/x11/BUILD.gn
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/chromeos/ui_mode.gni")
import("//build/config/linux/gtk/gtk.gni")
import("//gpu/vulkan/features.gni")
import("//ui/base/ui_features.gni")
@@ -37,6 +38,7 @@ source_set("x11") {
deps = [
"//base",
"//build:chromecast_buildflags",
+ "//build:chromeos_buildflags",
"//gpu/vulkan:buildflags",
"//skia",
"//ui/base:base",
@@ -57,6 +59,8 @@ source_set("x11") {
"//ui/events/x",
"//ui/gfx",
"//ui/gfx/geometry",
+ "//ui/gfx/linux:gbm",
+ "//ui/gfx/linux:gpu_memory_buffer_support_x11",
"//ui/gfx/x",
"//ui/gl",
"//ui/ozone:ozone_base",
@@ -66,7 +70,7 @@ source_set("x11") {
"//ui/platform_window/x11",
]
- if (is_chromeos) {
+ if (is_chromeos_ash) {
deps += [ "//ui/base/ime/chromeos" ]
} else {
sources += [
diff --git a/chromium/ui/ozone/platform/x11/client_native_pixmap_factory_x11.cc b/chromium/ui/ozone/platform/x11/client_native_pixmap_factory_x11.cc
index 13d2b2d9048..d7346528ff0 100644
--- a/chromium/ui/ozone/platform/x11/client_native_pixmap_factory_x11.cc
+++ b/chromium/ui/ozone/platform/x11/client_native_pixmap_factory_x11.cc
@@ -4,12 +4,12 @@
#include "ui/ozone/platform/x11/client_native_pixmap_factory_x11.h"
-#include "ui/ozone/common/stub_client_native_pixmap_factory.h"
+#include "ui/gfx/linux/client_native_pixmap_factory_dmabuf.h"
namespace ui {
gfx::ClientNativePixmapFactory* CreateClientNativePixmapFactoryX11() {
- return CreateStubClientNativePixmapFactory();
+ return gfx::CreateClientNativePixmapFactoryDmabuf();
}
} // namespace ui
diff --git a/chromium/ui/ozone/platform/x11/gl_egl_utility_x11.cc b/chromium/ui/ozone/platform/x11/gl_egl_utility_x11.cc
index 3c8e0d04ce4..d5612033adc 100644
--- a/chromium/ui/ozone/platform/x11/gl_egl_utility_x11.cc
+++ b/chromium/ui/ozone/platform/x11/gl_egl_utility_x11.cc
@@ -38,4 +38,17 @@ bool GLEGLUtilityX11::X11DoesVisualHaveAlphaForTest() const {
return ui::DoesVisualHaveAlphaForTest();
}
+bool GLEGLUtilityX11::HasVisualManager() {
+ return true;
+}
+
+bool GLEGLUtilityX11::UpdateVisualsOnGpuInfoChanged(
+ bool software_rendering,
+ uint32_t default_visual_id,
+ uint32_t transparent_visual_id) {
+ return ui::UpdateVisualsOnGpuInfoChanged(
+ software_rendering, static_cast<x11::VisualId>(default_visual_id),
+ static_cast<x11::VisualId>(transparent_visual_id));
+}
+
} // namespace ui
diff --git a/chromium/ui/ozone/platform/x11/gl_egl_utility_x11.h b/chromium/ui/ozone/platform/x11/gl_egl_utility_x11.h
index 807d3a7d20c..1ca2ddf3878 100644
--- a/chromium/ui/ozone/platform/x11/gl_egl_utility_x11.h
+++ b/chromium/ui/ozone/platform/x11/gl_egl_utility_x11.h
@@ -27,6 +27,10 @@ class GLEGLUtilityX11 : public PlatformGLEGLUtility {
void CollectGpuExtraInfo(bool enable_native_gpu_memory_buffers,
gfx::GpuExtraInfo& gpu_extra_info) const override;
bool X11DoesVisualHaveAlphaForTest() const override;
+ bool HasVisualManager() override;
+ bool UpdateVisualsOnGpuInfoChanged(bool software_rendering,
+ uint32_t default_visual_id,
+ uint32_t transparent_visual_id) override;
};
} // namespace ui
diff --git a/chromium/ui/ozone/platform/x11/ozone_platform_x11.cc b/chromium/ui/ozone/platform/x11/ozone_platform_x11.cc
index 399bd0678bb..455f238ac68 100644
--- a/chromium/ui/ozone/platform/x11/ozone_platform_x11.cc
+++ b/chromium/ui/ozone/platform/x11/ozone_platform_x11.cc
@@ -9,10 +9,13 @@
#include "base/message_loop/message_pump_type.h"
#include "base/metrics/histogram_functions.h"
+#include "base/metrics/histogram_macros.h"
#include "base/no_destructor.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/task/thread_pool.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "ui/base/buildflags.h"
#include "ui/base/cursor/cursor_factory.h"
#include "ui/base/dragdrop/os_exchange_data_provider_factory.h"
@@ -25,6 +28,7 @@
#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
#include "ui/events/ozone/layout/stub/stub_keyboard_layout_engine.h"
#include "ui/events/platform/x11/x11_event_source.h"
+#include "ui/gfx/linux/gpu_memory_buffer_support_x11.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/ozone/common/stub_overlay_manager.h"
#include "ui/ozone/platform/x11/gl_egl_utility_x11.h"
@@ -41,7 +45,7 @@
#include "ui/platform_window/platform_window_init_properties.h"
#include "ui/platform_window/x11/x11_window.h"
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ui/base/dragdrop/os_exchange_data_provider_non_backed.h"
#include "ui/base/ime/chromeos/input_method_chromeos.h"
#else
@@ -123,13 +127,15 @@ class OzonePlatformX11 : public OzonePlatform,
}
PlatformGLEGLUtility* GetPlatformGLEGLUtility() override {
+ if (!gl_egl_utility_)
+ gl_egl_utility_ = std::make_unique<GLEGLUtilityX11>();
return gl_egl_utility_.get();
}
std::unique_ptr<InputMethod> CreateInputMethod(
internal::InputMethodDelegate* delegate,
gfx::AcceleratedWidget) override {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
return std::make_unique<InputMethodChromeOS>(delegate);
#else
// This method is used by upper layer components (e.g: GtkUi) to determine
@@ -147,7 +153,7 @@ class OzonePlatformX11 : public OzonePlatform,
}
std::unique_ptr<OSExchangeDataProvider> CreateProvider() override {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
return std::make_unique<OSExchangeDataProviderNonBacked>();
#else
return std::make_unique<X11OSExchangeDataProviderOzone>();
@@ -169,9 +175,12 @@ class OzonePlatformX11 : public OzonePlatform,
properties->message_pump_type_for_viz_compositor =
base::MessagePumpType::UI;
properties->supports_vulkan_swap_chain = true;
+ properties->uses_external_vulkan_image_factory = true;
+ properties->skia_can_fall_back_to_x11 = true;
properties->platform_shows_drag_image = false;
properties->supports_global_application_menus = true;
properties->app_modal_dialogs_use_event_blocker = true;
+ properties->fetch_buffer_formats_for_gmb_on_gpu = true;
initialised = true;
}
@@ -179,6 +188,13 @@ class OzonePlatformX11 : public OzonePlatform,
return *properties;
}
+ bool IsNativePixmapConfigSupported(gfx::BufferFormat format,
+ gfx::BufferUsage usage) const override {
+ // Native pixmap support is determined on gpu process via gpu extra info
+ // that gets this information from GpuMemoryBufferSupportX11.
+ return false;
+ }
+
void InitializeUI(const InitParams& params) override {
InitializeCommon(params);
CreatePlatformEventSource();
@@ -215,7 +231,13 @@ class OzonePlatformX11 : public OzonePlatform,
void InitializeGPU(const InitParams& params) override {
InitializeCommon(params);
-
+ if (params.enable_native_gpu_memory_buffers) {
+ base::ThreadPool::PostTask(
+ FROM_HERE, base::BindOnce([]() {
+ SCOPED_UMA_HISTOGRAM_TIMER("Linux.X11.GbmSupportX11CreationTime");
+ ui::GpuMemoryBufferSupportX11::GetInstance();
+ }));
+ }
// In single process mode either the UI thread will create an event source
// or it's a test and an event source isn't desired.
if (!params.single_process)
@@ -227,7 +249,6 @@ class OzonePlatformX11 : public OzonePlatform,
connection->DetachFromSequence();
surface_factory_ozone_ =
std::make_unique<X11SurfaceFactory>(std::move(connection));
- gl_egl_utility_ = std::make_unique<GLEGLUtilityX11>();
}
void PostMainMessageLoopStart(
@@ -253,7 +274,7 @@ class OzonePlatformX11 : public OzonePlatform,
// If opening the connection failed there is nothing we can do. Crash here
// instead of crashing later. If you are crashing here, make sure there is
// an X server running and $DISPLAY is set.
- CHECK(x11::Connection::Get()) << "Missing X server or $DISPLAY";
+ CHECK(x11::Connection::Get()->Ready()) << "Missing X server or $DISPLAY";
common_initialized_ = true;
}
diff --git a/chromium/ui/ozone/platform/x11/x11_clipboard_ozone.cc b/chromium/ui/ozone/platform/x11/x11_clipboard_ozone.cc
index 40945c6dbf1..5944973e00c 100644
--- a/chromium/ui/ozone/platform/x11/x11_clipboard_ozone.cc
+++ b/chromium/ui/ozone/platform/x11/x11_clipboard_ozone.cc
@@ -7,11 +7,12 @@
#include <algorithm>
#include <vector>
+#include "base/containers/contains.h"
#include "base/containers/span.h"
#include "base/logging.h"
-#include "base/stl_util.h"
#include "ui/base/clipboard/clipboard_constants.h"
#include "ui/base/x/x11_util.h"
+#include "ui/events/platform/x11/x11_event_source.h"
#include "ui/gfx/x/extension_manager.h"
#include "ui/gfx/x/x11_atom_cache.h"
#include "ui/gfx/x/xproto.h"
@@ -78,12 +79,12 @@ struct X11ClipboardOzone::SelectionState {
};
X11ClipboardOzone::X11ClipboardOzone()
- : atom_clipboard_(gfx::GetAtom(kClipboard)),
- atom_targets_(gfx::GetAtom(kTargets)),
- atom_timestamp_(gfx::GetAtom(kTimestamp)),
- x_property_(gfx::GetAtom(kChromeSelection)),
+ : atom_clipboard_(x11::GetAtom(kClipboard)),
+ atom_targets_(x11::GetAtom(kTargets)),
+ atom_timestamp_(x11::GetAtom(kTimestamp)),
+ x_property_(x11::GetAtom(kChromeSelection)),
connection_(x11::Connection::Get()),
- x_window_(CreateDummyWindow("Chromium Clipboard Window")) {
+ x_window_(x11::CreateDummyWindow("Chromium Clipboard Window")) {
connection_->xfixes().QueryVersion(
{x11::XFixes::major_version, x11::XFixes::minor_version});
if (!connection_->xfixes().present())
@@ -91,7 +92,7 @@ X11ClipboardOzone::X11ClipboardOzone()
using_xfixes_ = true;
// Register to receive standard X11 events.
- X11EventSource::GetInstance()->AddXEventDispatcher(this);
+ connection_->AddEventObserver(this);
for (auto atom : {atom_clipboard_, x11::Atom::PRIMARY}) {
// Register the selection state.
@@ -105,29 +106,31 @@ X11ClipboardOzone::X11ClipboardOzone()
}
X11ClipboardOzone::~X11ClipboardOzone() {
- X11EventSource::GetInstance()->RemoveXEventDispatcher(this);
+ connection_->RemoveEventObserver(this);
}
-bool X11ClipboardOzone::DispatchXEvent(x11::Event* xev) {
- if (auto* request = xev->As<x11::SelectionRequestEvent>())
- return request->owner == x_window_ && OnSelectionRequest(*request);
- if (auto* notify = xev->As<x11::SelectionNotifyEvent>())
- return notify->requestor == x_window_ && OnSelectionNotify(*notify);
- if (auto* notify = xev->As<x11::XFixes::SelectionNotifyEvent>())
- return notify->window == x_window_ && OnSetSelectionOwnerNotify(*notify);
-
- return false;
+void X11ClipboardOzone::OnEvent(const x11::Event& xev) {
+ if (auto* request = xev.As<x11::SelectionRequestEvent>()) {
+ if (request->owner == x_window_)
+ OnSelectionRequest(*request);
+ } else if (auto* notify = xev.As<x11::SelectionNotifyEvent>()) {
+ if (notify->requestor == x_window_)
+ OnSelectionNotify(*notify);
+ } else if (auto* notify = xev.As<x11::XFixes::SelectionNotifyEvent>()) {
+ if (notify->window == x_window_)
+ OnSetSelectionOwnerNotify(*notify);
+ }
}
// We are the clipboard owner, and a remote peer has requested either:
// TARGETS: List of mime types that we support for the clipboard.
// TIMESTAMP: Time when we took ownership of the clipboard.
// <mime-type>: Mime type to receive clipboard as.
-bool X11ClipboardOzone::OnSelectionRequest(
+void X11ClipboardOzone::OnSelectionRequest(
const x11::SelectionRequestEvent& event) {
// The property must be set.
if (event.property == x11::Atom::None)
- return false;
+ return;
// target=TARGETS.
auto& selection_state =
@@ -145,14 +148,13 @@ bool X11ClipboardOzone::OnSelectionRequest(
ExpandTypes(&targets);
std::vector<x11::Atom> atoms;
for (auto& entry : targets)
- atoms.push_back(gfx::GetAtom(entry.c_str()));
- ui::SetArrayProperty(event.requestor, event.property, x11::Atom::ATOM,
- atoms);
+ atoms.push_back(x11::GetAtom(entry.c_str()));
+ SetArrayProperty(event.requestor, event.property, x11::Atom::ATOM, atoms);
} else if (target == atom_timestamp_) {
// target=TIMESTAMP.
- ui::SetProperty(event.requestor, event.property, x11::Atom::INTEGER,
- selection_state.acquired_selection_timestamp);
+ SetProperty(event.requestor, event.property, x11::Atom::INTEGER,
+ selection_state.acquired_selection_timestamp);
} else {
// Send clipboard data.
std::string target_name;
@@ -170,8 +172,8 @@ bool X11ClipboardOzone::OnSelectionRequest(
}
auto it = offer_data_map.find(key);
if (it != offer_data_map.end()) {
- ui::SetArrayProperty(event.requestor, event.property, event.target,
- it->second->data());
+ SetArrayProperty(event.requestor, event.property, event.target,
+ it->second->data());
}
}
@@ -185,20 +187,19 @@ bool X11ClipboardOzone::OnSelectionRequest(
};
x11::SendEvent(selection_event, selection_event.requestor,
x11::EventMask::NoEvent);
- return true;
}
// A remote peer owns the clipboard. This event is received in response to
// our request for TARGETS (GetAvailableMimeTypes), or a specific mime type
// (RequestClipboardData).
-bool X11ClipboardOzone::OnSelectionNotify(
+void X11ClipboardOzone::OnSelectionNotify(
const x11::SelectionNotifyEvent& event) {
// GetAvailableMimeTypes.
auto selection = static_cast<x11::Atom>(event.selection);
auto& selection_state = GetSelectionState(selection);
if (static_cast<x11::Atom>(event.target) == atom_targets_) {
std::vector<x11::Atom> targets;
- ui::GetArrayProperty(x_window_, x_property_, &targets);
+ GetArrayProperty(x_window_, x_property_, &targets);
selection_state.mime_types.clear();
for (auto target : targets) {
@@ -217,16 +218,14 @@ bool X11ClipboardOzone::OnSelectionNotify(
selection_state.data_mime_type = kMimeTypeText;
ReadRemoteClipboard(selection);
}
-
- return true;
}
// RequestClipboardData.
if (static_cast<x11::Atom>(event.property) == x_property_) {
x11::Atom type;
std::vector<uint8_t> data;
- ui::GetArrayProperty(x_window_, x_property_, &data, &type);
- ui::DeleteProperty(x_window_, x_property_);
+ GetArrayProperty(x_window_, x_property_, &data, &type);
+ x11::DeleteProperty(x_window_, x_property_);
if (type != x11::Atom::None)
selection_state.data = scoped_refptr<base::RefCountedBytes>(
base::RefCountedBytes::TakeVector(&data));
@@ -240,20 +239,16 @@ bool X11ClipboardOzone::OnSelectionNotify(
std::move(selection_state.request_clipboard_data_callback)
.Run(selection_state.data);
}
- return true;
} else if (static_cast<x11::Atom>(event.property) == x11::Atom::None &&
selection_state.request_clipboard_data_callback) {
// If the remote peer could not send data in the format we requested,
// or failed for any reason, we will send empty data.
std::move(selection_state.request_clipboard_data_callback)
.Run(selection_state.data);
- return true;
}
-
- return false;
}
-bool X11ClipboardOzone::OnSetSelectionOwnerNotify(
+void X11ClipboardOzone::OnSetSelectionOwnerNotify(
const x11::XFixes::SelectionNotifyEvent& event) {
// Reset state and fetch remote clipboard if there is a new remote owner.
x11::Atom selection = event.selection;
@@ -268,8 +263,6 @@ bool X11ClipboardOzone::OnSetSelectionOwnerNotify(
// Increase the sequence number if the callback is set.
if (update_sequence_cb_)
update_sequence_cb_.Run(BufferForSelectionAtom(selection));
-
- return true;
}
x11::Atom X11ClipboardOzone::SelectionAtomForBuffer(
@@ -320,7 +313,7 @@ void X11ClipboardOzone::ReadRemoteClipboard(x11::Atom selection) {
}
}
- connection_->ConvertSelection({x_window_, selection, gfx::GetAtom(target),
+ connection_->ConvertSelection({x_window_, selection, x11::GetAtom(target),
x_property_, x11::Time::CurrentTime});
}
@@ -361,6 +354,14 @@ void X11ClipboardOzone::RequestClipboardData(
std::move(callback).Run(selection_state.data);
return;
}
+
+ // If we know the available mime types, and it is not this, send empty now.
+ if (!selection_state.mime_types.empty() &&
+ !Contains(selection_state.mime_types, mime_type)) {
+ std::move(callback).Run(PlatformClipboard::Data());
+ return;
+ }
+
selection_state.data_mime_type = mime_type;
selection_state.request_data_map = data_map;
DCHECK(selection_state.request_clipboard_data_callback.is_null());
diff --git a/chromium/ui/ozone/platform/x11/x11_clipboard_ozone.h b/chromium/ui/ozone/platform/x11/x11_clipboard_ozone.h
index 9592b8df86c..4802f02ee08 100644
--- a/chromium/ui/ozone/platform/x11/x11_clipboard_ozone.h
+++ b/chromium/ui/ozone/platform/x11/x11_clipboard_ozone.h
@@ -10,7 +10,7 @@
#include "base/callback.h"
#include "base/containers/flat_map.h"
-#include "ui/events/platform/x11/x11_event_source.h"
+#include "ui/gfx/x/connection.h"
#include "ui/gfx/x/event.h"
#include "ui/gfx/x/xfixes.h"
#include "ui/gfx/x/xproto.h"
@@ -26,7 +26,7 @@ namespace ui {
// text/plain. Otherwise GetAvailableMimeTypes and RequestClipboardData call
// the appropriate X11 functions and invoke callbacks when the associated events
// are received.
-class X11ClipboardOzone : public PlatformClipboard, public XEventDispatcher {
+class X11ClipboardOzone : public PlatformClipboard, public x11::EventObserver {
public:
X11ClipboardOzone();
~X11ClipboardOzone() override;
@@ -52,12 +52,12 @@ class X11ClipboardOzone : public PlatformClipboard, public XEventDispatcher {
private:
struct SelectionState;
- // XEventDispatcher:
- bool DispatchXEvent(x11::Event* xev) override;
+ // x11::EventObserver:
+ void OnEvent(const x11::Event& xev) override;
- bool OnSelectionRequest(const x11::SelectionRequestEvent& event);
- bool OnSelectionNotify(const x11::SelectionNotifyEvent& event);
- bool OnSetSelectionOwnerNotify(
+ void OnSelectionRequest(const x11::SelectionRequestEvent& event);
+ void OnSelectionNotify(const x11::SelectionNotifyEvent& event);
+ void OnSetSelectionOwnerNotify(
const x11::XFixes::SelectionNotifyEvent& event);
// Returns an X atom for a clipboard buffer type.
diff --git a/chromium/ui/ozone/platform/x11/x11_os_exchange_data_provider_ozone.cc b/chromium/ui/ozone/platform/x11/x11_os_exchange_data_provider_ozone.cc
index 4c3b56653dd..8409a940dbc 100644
--- a/chromium/ui/ozone/platform/x11/x11_os_exchange_data_provider_ozone.cc
+++ b/chromium/ui/ozone/platform/x11/x11_os_exchange_data_provider_ozone.cc
@@ -20,12 +20,12 @@ X11OSExchangeDataProviderOzone::X11OSExchangeDataProviderOzone(
X11OSExchangeDataProviderOzone::X11OSExchangeDataProviderOzone() {
DCHECK(own_window());
- X11EventSource::GetInstance()->AddXEventDispatcher(this);
+ x11::Connection::Get()->AddEventObserver(this);
}
X11OSExchangeDataProviderOzone::~X11OSExchangeDataProviderOzone() {
if (own_window())
- X11EventSource::GetInstance()->RemoveXEventDispatcher(this);
+ x11::Connection::Get()->RemoveEventObserver(this);
}
std::unique_ptr<OSExchangeDataProvider> X11OSExchangeDataProviderOzone::Clone()
@@ -36,13 +36,10 @@ std::unique_ptr<OSExchangeDataProvider> X11OSExchangeDataProviderOzone::Clone()
return std::move(ret);
}
-bool X11OSExchangeDataProviderOzone::DispatchXEvent(x11::Event* xev) {
- auto* selection_request = xev->As<x11::SelectionRequestEvent>();
- if (selection_request && selection_request->owner == x_window()) {
- selection_owner().OnSelectionRequest(*xev);
- return true;
- }
- return false;
+void X11OSExchangeDataProviderOzone::OnEvent(const x11::Event& xev) {
+ auto* selection_request = xev.As<x11::SelectionRequestEvent>();
+ if (selection_request && selection_request->owner == x_window())
+ selection_owner().OnSelectionRequest(*selection_request);
}
} // namespace ui
diff --git a/chromium/ui/ozone/platform/x11/x11_os_exchange_data_provider_ozone.h b/chromium/ui/ozone/platform/x11/x11_os_exchange_data_provider_ozone.h
index 65542ea14d3..cc544e464a4 100644
--- a/chromium/ui/ozone/platform/x11/x11_os_exchange_data_provider_ozone.h
+++ b/chromium/ui/ozone/platform/x11/x11_os_exchange_data_provider_ozone.h
@@ -6,14 +6,14 @@
#define UI_OZONE_PLATFORM_X11_X11_OS_EXCHANGE_DATA_PROVIDER_OZONE_H_
#include "ui/base/x/x11_os_exchange_data_provider.h"
-#include "ui/events/platform/x11/x11_event_source.h"
+#include "ui/gfx/x/connection.h"
#include "ui/gfx/x/event.h"
namespace ui {
// OSExchangeDataProvider implementation for Ozone/X11.
class X11OSExchangeDataProviderOzone : public XOSExchangeDataProvider,
- public XEventDispatcher {
+ public x11::EventObserver {
public:
X11OSExchangeDataProviderOzone(x11::Window x_window,
const SelectionFormatMap& selection);
@@ -27,8 +27,8 @@ class X11OSExchangeDataProviderOzone : public XOSExchangeDataProvider,
// OSExchangeDataProvider:
std::unique_ptr<OSExchangeDataProvider> Clone() const override;
- // XEventDispatcher:
- bool DispatchXEvent(x11::Event* xev) override;
+ // x11::EventObserver:
+ void OnEvent(const x11::Event& xev) override;
};
} // namespace ui
diff --git a/chromium/ui/ozone/platform/x11/x11_screen_ozone.cc b/chromium/ui/ozone/platform/x11/x11_screen_ozone.cc
index d9ea9078d14..718cb627f4f 100644
--- a/chromium/ui/ozone/platform/x11/x11_screen_ozone.cc
+++ b/chromium/ui/ozone/platform/x11/x11_screen_ozone.cc
@@ -42,17 +42,13 @@ X11ScreenOzone::X11ScreenOzone()
}
X11ScreenOzone::~X11ScreenOzone() {
- if (x11_display_manager_->IsXrandrAvailable() &&
- X11EventSource::HasInstance()) {
- X11EventSource::GetInstance()->RemoveXEventDispatcher(this);
- }
+ if (x11_display_manager_->IsXrandrAvailable())
+ x11::Connection::Get()->RemoveEventObserver(this);
}
void X11ScreenOzone::Init() {
- if (x11_display_manager_->IsXrandrAvailable() &&
- X11EventSource::HasInstance()) {
- X11EventSource::GetInstance()->AddXEventDispatcher(this);
- }
+ if (x11_display_manager_->IsXrandrAvailable())
+ x11::Connection::Get()->AddEventObserver(this);
x11_display_manager_->Init();
}
@@ -154,8 +150,8 @@ base::Value X11ScreenOzone::GetGpuExtraInfoAsListValue(
gpu_extra_info.rgba_visual);
}
-bool X11ScreenOzone::DispatchXEvent(x11::Event* xev) {
- return x11_display_manager_->ProcessEvent(xev);
+void X11ScreenOzone::OnEvent(const x11::Event& xev) {
+ x11_display_manager_->OnEvent(xev);
}
gfx::Point X11ScreenOzone::GetCursorLocation() const {
diff --git a/chromium/ui/ozone/platform/x11/x11_screen_ozone.h b/chromium/ui/ozone/platform/x11/x11_screen_ozone.h
index 2d61903d35f..4f498468610 100644
--- a/chromium/ui/ozone/platform/x11/x11_screen_ozone.h
+++ b/chromium/ui/ozone/platform/x11/x11_screen_ozone.h
@@ -12,7 +12,6 @@
#include "base/macros.h"
#include "base/observer_list.h"
#include "ui/base/x/x11_display_manager.h"
-#include "ui/events/platform/x11/x11_event_source.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/x/event.h"
#include "ui/ozone/public/platform_screen.h"
@@ -23,7 +22,7 @@ class X11WindowManager;
// A PlatformScreen implementation for X11.
class X11ScreenOzone : public PlatformScreen,
- public XEventDispatcher,
+ public x11::EventObserver,
public XDisplayManager::Delegate {
public:
X11ScreenOzone();
@@ -56,8 +55,8 @@ class X11ScreenOzone : public PlatformScreen,
base::Value GetGpuExtraInfoAsListValue(
const gfx::GpuExtraInfo& gpu_extra_info) override;
- // Overridden from ui::XEventDispatcher:
- bool DispatchXEvent(x11::Event* event) override;
+ // Overridden from x11::EventObserver:
+ void OnEvent(const x11::Event& event) override;
private:
friend class X11ScreenOzoneTest;
diff --git a/chromium/ui/ozone/platform/x11/x11_surface_factory.cc b/chromium/ui/ozone/platform/x11/x11_surface_factory.cc
index e416f3fa817..e081380d06f 100644
--- a/chromium/ui/ozone/platform/x11/x11_surface_factory.cc
+++ b/chromium/ui/ozone/platform/x11/x11_surface_factory.cc
@@ -8,6 +8,9 @@
#include "gpu/vulkan/buildflags.h"
#include "ui/events/platform/x11/x11_event_source.h"
+#include "ui/gfx/linux/gbm_buffer.h"
+#include "ui/gfx/linux/gpu_memory_buffer_support_x11.h"
+#include "ui/gfx/linux/native_pixmap_dmabuf.h"
#include "ui/gfx/x/connection.h"
#include "ui/gl/gl_surface_egl.h"
#include "ui/gl/gl_surface_egl_x11_gles2.h"
@@ -102,9 +105,10 @@ GLOzone* X11SurfaceFactory::GetGLOzone(gl::GLImplementation implementation) {
#if BUILDFLAG(ENABLE_VULKAN)
std::unique_ptr<gpu::VulkanImplementation>
-X11SurfaceFactory::CreateVulkanImplementation(bool allow_protected_memory,
+X11SurfaceFactory::CreateVulkanImplementation(bool use_swiftshader,
+ bool allow_protected_memory,
bool enforce_protected_memory) {
- return std::make_unique<gpu::VulkanImplementationX11>();
+ return std::make_unique<gpu::VulkanImplementationX11>(use_swiftshader);
}
#endif
@@ -121,4 +125,37 @@ std::unique_ptr<SurfaceOzoneCanvas> X11SurfaceFactory::CreateCanvasForWidget(
return std::make_unique<X11CanvasSurface>(widget);
}
+scoped_refptr<gfx::NativePixmap> X11SurfaceFactory::CreateNativePixmap(
+ gfx::AcceleratedWidget widget,
+ VkDevice vk_device,
+ gfx::Size size,
+ gfx::BufferFormat format,
+ gfx::BufferUsage usage,
+ base::Optional<gfx::Size> framebuffer_size) {
+ scoped_refptr<gfx::NativePixmapDmaBuf> pixmap;
+ auto buffer = ui::GpuMemoryBufferSupportX11::GetInstance()->CreateBuffer(
+ format, size, usage);
+ if (buffer) {
+ gfx::NativePixmapHandle handle = buffer->ExportHandle();
+ pixmap = base::MakeRefCounted<gfx::NativePixmapDmaBuf>(size, format,
+ std::move(handle));
+ }
+
+ // CreateNativePixmap is non-blocking operation. Thus, it is safe to call it
+ // and return the result with the provided callback.
+ return pixmap;
+}
+
+void X11SurfaceFactory::CreateNativePixmapAsync(gfx::AcceleratedWidget widget,
+ VkDevice vk_device,
+ gfx::Size size,
+ gfx::BufferFormat format,
+ gfx::BufferUsage usage,
+ NativePixmapCallback callback) {
+ // CreateNativePixmap is non-blocking operation. Thus, it is safe to call it
+ // and return the result with the provided callback.
+ std::move(callback).Run(
+ CreateNativePixmap(widget, vk_device, size, format, usage));
+}
+
} // namespace ui
diff --git a/chromium/ui/ozone/platform/x11/x11_surface_factory.h b/chromium/ui/ozone/platform/x11/x11_surface_factory.h
index fb5431bf47a..70209cc94be 100644
--- a/chromium/ui/ozone/platform/x11/x11_surface_factory.h
+++ b/chromium/ui/ozone/platform/x11/x11_surface_factory.h
@@ -28,11 +28,25 @@ class X11SurfaceFactory : public SurfaceFactoryOzone {
GLOzone* GetGLOzone(gl::GLImplementation implementation) override;
#if BUILDFLAG(ENABLE_VULKAN)
std::unique_ptr<gpu::VulkanImplementation> CreateVulkanImplementation(
+ bool use_swiftshader,
bool allow_protected_memory,
bool enforce_protected_memory) override;
#endif
std::unique_ptr<SurfaceOzoneCanvas> CreateCanvasForWidget(
gfx::AcceleratedWidget widget) override;
+ scoped_refptr<gfx::NativePixmap> CreateNativePixmap(
+ gfx::AcceleratedWidget widget,
+ VkDevice vk_device,
+ gfx::Size size,
+ gfx::BufferFormat format,
+ gfx::BufferUsage usage,
+ base::Optional<gfx::Size> framebuffer_size = base::nullopt) override;
+ void CreateNativePixmapAsync(gfx::AcceleratedWidget widget,
+ VkDevice vk_device,
+ gfx::Size size,
+ gfx::BufferFormat format,
+ gfx::BufferUsage usage,
+ NativePixmapCallback callback) override;
private:
std::unique_ptr<GLOzone> glx_implementation_;
diff --git a/chromium/ui/ozone/platform/x11/x11_window_ozone_unittest.cc b/chromium/ui/ozone/platform/x11/x11_window_ozone_unittest.cc
index 07c43384e1a..63037c7c771 100644
--- a/chromium/ui/ozone/platform/x11/x11_window_ozone_unittest.cc
+++ b/chromium/ui/ozone/platform/x11/x11_window_ozone_unittest.cc
@@ -70,8 +70,7 @@ class X11WindowOzoneTest : public testing::Test {
~X11WindowOzoneTest() override = default;
void SetUp() override {
- auto* connection = x11::Connection::Get();
- event_source_ = std::make_unique<X11EventSource>(connection);
+ event_source_ = std::make_unique<X11EventSource>(x11::Connection::Get());
test_screen_ = new TestScreen();
display::Screen::SetScreenInstance(test_screen_);
@@ -96,7 +95,7 @@ class X11WindowOzoneTest : public testing::Test {
auto* device_event = event->As<x11::Input::DeviceEvent>();
DCHECK(device_event);
device_event->event = static_cast<x11::Window>(widget);
- event_source_->ProcessXEvent(event);
+ x11::Connection::Get()->DispatchEvent(*event);
}
X11WindowManager* window_manager() const {
diff --git a/chromium/ui/ozone/public/input_controller.cc b/chromium/ui/ozone/public/input_controller.cc
index 43e5fca8d2e..35fdf8c9a06 100644
--- a/chromium/ui/ozone/public/input_controller.cc
+++ b/chromium/ui/ozone/public/input_controller.cc
@@ -50,6 +50,9 @@ class StubInputController : public InputController {
void SuspendMouseAcceleration() override {}
void EndMouseAccelerationSuspension() override {}
void SetMouseScrollAcceleration(bool enabled) override {}
+ void SetPointingStickSensitivity(int value) override {}
+ void SetPointingStickPrimaryButtonRight(bool right) override {}
+ void SetPointingStickAcceleration(bool enabled) override {}
void SetTouchpadAcceleration(bool enabled) override {}
void SetTouchpadScrollAcceleration(bool enabled) override {}
void SetTapToClickPaused(bool state) override {}
diff --git a/chromium/ui/ozone/public/input_controller.h b/chromium/ui/ozone/public/input_controller.h
index 27b5ad3acd8..c18ba9c72ef 100644
--- a/chromium/ui/ozone/public/input_controller.h
+++ b/chromium/ui/ozone/public/input_controller.h
@@ -71,6 +71,9 @@ class COMPONENT_EXPORT(OZONE_BASE) InputController {
// Mouse settings.
virtual void SetMouseSensitivity(int value) = 0;
virtual void SetMouseScrollSensitivity(int value) = 0;
+
+ // Sets the primary button for the mouse. Passing true sets the right button
+ // as primary, while false (the default) sets the left as primary.
virtual void SetPrimaryButtonRight(bool right) = 0;
virtual void SetMouseReverseScroll(bool enabled) = 0;
virtual void SetMouseAcceleration(bool enabled) = 0;
@@ -78,6 +81,14 @@ class COMPONENT_EXPORT(OZONE_BASE) InputController {
virtual void EndMouseAccelerationSuspension() = 0;
virtual void SetMouseScrollAcceleration(bool enabled) = 0;
+ // Pointing stick settings.
+ virtual void SetPointingStickSensitivity(int value) = 0;
+
+ // Sets the primary button for the pointing stick. Passing true sets the right
+ // button as primary, while false (the default) sets the left as primary.
+ virtual void SetPointingStickPrimaryButtonRight(bool right) = 0;
+ virtual void SetPointingStickAcceleration(bool enabled) = 0;
+
// Touch log collection.
virtual void GetTouchDeviceStatus(GetTouchDeviceStatusReply reply) = 0;
virtual void GetTouchEventLog(const base::FilePath& out_dir,
diff --git a/chromium/ui/ozone/public/mojom/device_cursor.mojom b/chromium/ui/ozone/public/mojom/device_cursor.mojom
index a86e09970f0..f165e5eb833 100644
--- a/chromium/ui/ozone/public/mojom/device_cursor.mojom
+++ b/chromium/ui/ozone/public/mojom/device_cursor.mojom
@@ -15,11 +15,10 @@ interface DeviceCursor {
// Sets the cursor |bitmaps| on |window| at |point| with
// |frame_delay_ms|.
SetCursor(gfx.mojom.AcceleratedWidget window,
- array<skia.mojom.Bitmap> bitmaps,
+ array<skia.mojom.BitmapN32> bitmaps,
gfx.mojom.Point point,
int32 frame_delay_ms);
// Moves the cursor in |window| to |point|.
MoveCursor(gfx.mojom.AcceleratedWidget window, gfx.mojom.Point point);
};
-
diff --git a/chromium/ui/ozone/public/mojom/drm_device.mojom b/chromium/ui/ozone/public/mojom/drm_device.mojom
index caf4a7e5a7b..cf0e17009a1 100644
--- a/chromium/ui/ozone/public/mojom/drm_device.mojom
+++ b/chromium/ui/ozone/public/mojom/drm_device.mojom
@@ -51,11 +51,11 @@ interface DrmDevice {
// Instructs the GPU to abandon a DRM device.
RemoveGraphicsDevice(mojo_base.mojom.FilePath path);
- // Configures (Enables/Disables) DRM displays, returns a map: each configured
- // display ID to its status, true on success.
+ // Configures (Enables/Disables) DRM displays, returns whether or not the
+ // configuration was successful.
ConfigureNativeDisplays(
array<display.mojom.DisplayConfigurationParams> config_requests) =>
- (map<int64, bool> statuses);
+ (bool config_success);
// Gets high-definition content protection (HDCP) (DRM as in
// digital rights management) state.
diff --git a/chromium/ui/ozone/public/mojom/wayland/wayland_buffer_manager.mojom b/chromium/ui/ozone/public/mojom/wayland/wayland_buffer_manager.mojom
index 37fcaa56ace..1a99bc0bb98 100644
--- a/chromium/ui/ozone/public/mojom/wayland/wayland_buffer_manager.mojom
+++ b/chromium/ui/ozone/public/mojom/wayland/wayland_buffer_manager.mojom
@@ -33,7 +33,7 @@ interface WaylandBufferManagerHost {
// buffer, which is used to identify imported wl_buffers on the browser
// process side and map them with the buffer objects on the gpu process side.
// The buffer will be associated with an AcceleratedWidget as soon as the
- // very first CommitBuffer request comes from viz to browser process.
+ // very first CommitOverlays request comes from viz to browser process.
// If the buffer has been committed at least once, it is not possible to
// reassign it to another AcceleratedWidget.
CreateDmabufBasedBuffer(handle<platform> dmabuf_fd,
@@ -50,7 +50,7 @@ interface WaylandBufferManagerHost {
// The |length| is the length of the shared memory, |size|
// is the size of buffer and |buffer_id| is the id of the buffer.
// The buffer will be associated with an AcceleratedWidget as soon as the
- // very first CommitBuffer request comes from viz to browser process. If
+ // very first CommitOverlays request comes from viz to browser process. If
// the buffer has been committed at least once, it is not possible to
// reassign it to another AcceleratedWidget.
CreateShmBasedBuffer(handle<platform> shm_fd,
@@ -69,14 +69,6 @@ interface WaylandBufferManagerHost {
// |buffer_id| will result in the termination of the GPU process.
DestroyBuffer(gfx.mojom.AcceleratedWidget widget, uint32 buffer_id);
- // Attaches a wl_buffer to a WaylandWindow's surface with the following
- // |widget|. The |damage_region| describes the changed region of the buffer.
- // The |buffer_id| is a unique id for the buffer, which is used to
- // identify imported wl_buffers on the browser process side mapped with
- // the ones on the gpu process.
- CommitBuffer(gfx.mojom.AcceleratedWidget widget, uint32 buffer_id,
- gfx.mojom.Rect damage_region);
-
// Send overlay configurations for a frame to a WaylandWindow with the
// following |widget|.
CommitOverlays(gfx.mojom.AcceleratedWidget widget,
@@ -95,10 +87,14 @@ interface WaylandBufferManagerGpu {
// instance to avoid using zwp_linux_dmabuf protocol by setting
// |supports_dma_buf| to false, which results in using wl_egl_surface in a
// single process mode, and software rendering in a multiple process mode.
+ // |supports_acquire_fence| indicates whether acquire fences can be submitted
+ // with buffers for wayland servers to wait on before accessing buffer
+ // contents.
Initialize(pending_remote<WaylandBufferManagerHost> remote_host,
map<gfx.mojom.BufferFormat,
array<uint64>> buffer_formats_with_modifiers,
- bool supports_dma_buf);
+ bool supports_dma_buf,
+ bool supports_acquire_fence);
// Signals about swap completion.
OnSubmission(gfx.mojom.AcceleratedWidget widget,
diff --git a/chromium/ui/ozone/public/overlay_manager_ozone.h b/chromium/ui/ozone/public/overlay_manager_ozone.h
index 54e73e58933..c72edc50752 100644
--- a/chromium/ui/ozone/public/overlay_manager_ozone.h
+++ b/chromium/ui/ozone/public/overlay_manager_ozone.h
@@ -22,6 +22,15 @@ class OverlayManagerOzone {
// Get the hal struct to check for overlay support.
virtual std::unique_ptr<OverlayCandidatesOzone> CreateOverlayCandidates(
gfx::AcceleratedWidget w) = 0;
+
+ bool allow_sync_and_real_buffer_page_flip_testing() const {
+ return allow_sync_and_real_buffer_page_flip_testing_;
+ }
+
+ protected:
+ // TODO(fangzhoug): Some Chrome OS boards still use the legacy video decoder.
+ // Remove this once ChromeOSVideoDecoder is on everywhere.
+ bool allow_sync_and_real_buffer_page_flip_testing_ = false;
};
} // namespace ui
diff --git a/chromium/ui/ozone/public/overlay_surface_candidate.h b/chromium/ui/ozone/public/overlay_surface_candidate.h
index ebd82e96706..46b7e85d7f6 100644
--- a/chromium/ui/ozone/public/overlay_surface_candidate.h
+++ b/chromium/ui/ozone/public/overlay_surface_candidate.h
@@ -67,6 +67,8 @@ class COMPONENT_EXPORT(OZONE_BASE) OverlaySurfaceCandidate {
// To be modified by the implementer if this candidate can go into
// an overlay.
bool overlay_handled = false;
+ // If this candidate requires an overlay for proper display.
+ bool requires_overlay = false;
};
using OverlaySurfaceCandidateList = std::vector<OverlaySurfaceCandidate>;
diff --git a/chromium/ui/ozone/public/ozone_platform.cc b/chromium/ui/ozone/public/ozone_platform.cc
index 898a9c5c1b2..29fd78fa4c7 100644
--- a/chromium/ui/ozone/public/ozone_platform.cc
+++ b/chromium/ui/ozone/public/ozone_platform.cc
@@ -87,7 +87,7 @@ OzonePlatform* OzonePlatform::GetInstance() {
}
// static
-const char* OzonePlatform::GetPlatformName() {
+std::string OzonePlatform::GetPlatformNameForTest() {
return GetOzonePlatformName();
}
diff --git a/chromium/ui/ozone/public/ozone_platform.h b/chromium/ui/ozone/public/ozone_platform.h
index 739ffae079d..274915a23e7 100644
--- a/chromium/ui/ozone/public/ozone_platform.h
+++ b/chromium/ui/ozone/public/ozone_platform.h
@@ -6,6 +6,7 @@
#define UI_OZONE_PUBLIC_OZONE_PLATFORM_H_
#include <memory>
+#include <string>
#include <vector>
#include "base/callback.h"
@@ -69,6 +70,18 @@ class COMPONENT_EXPORT(OZONE) OzonePlatform {
// operate as a single process for platforms (i.e. drm) that are usually
// split between a host and viz specific portion.
bool single_process = false;
+
+ // Setting this to true indicates the the platform can do additional
+ // initialization for the GpuMemoryBuffer framework.
+ bool enable_native_gpu_memory_buffers = false;
+
+ // The direct VideoDecoder is disallowed on some particular SoC/platforms.
+ // This flag is a reflection of whatever the ChromeOS command line builder
+ // says. If false, overlay manager will not use synchronous pageflip
+ // testing with real buffer.
+ // TODO(fangzhoug): Some Chrome OS boards still use the legacy video
+ // decoder. Remove this once ChromeOSVideoDecoder is on everywhere.
+ bool allow_sync_and_real_buffer_page_flip_testing = false;
};
// Struct used to indicate platform properties.
@@ -103,6 +116,13 @@ class COMPONENT_EXPORT(OZONE) OzonePlatform {
// Determines if the platform supports vulkan swap chain.
bool supports_vulkan_swap_chain = false;
+ // Linux only: determines if the platform uses the external Vulkan image
+ // factory.
+ bool uses_external_vulkan_image_factory = false;
+
+ // Linux only: determines if Skia can fall back to the X11 output device.
+ bool skia_can_fall_back_to_x11 = false;
+
// Wayland only: determines if the client must ignore the screen bounds when
// calculating bounds of menu windows.
bool ignore_screen_bounds_for_menus = false;
@@ -121,6 +141,10 @@ class COMPONENT_EXPORT(OZONE) OzonePlatform {
// Determines if the application modal dialogs should use the event blocker
// to allow the only browser window receiving UI events.
bool app_modal_dialogs_use_event_blocker = false;
+
+ // Determines whether buffer formats should be fetched on GPU and passed
+ // back via gpu extra info.
+ bool fetch_buffer_formats_for_gmb_on_gpu = false;
};
// Properties available in the host process after initialization.
@@ -168,12 +192,8 @@ class COMPONENT_EXPORT(OZONE) OzonePlatform {
static OzonePlatform* GetInstance();
// Returns the current ozone platform name.
- // TODO(crbug.com/1002674): This is temporary and meant to make it possible
- // for higher level components to take run-time actions depending on the
- // current ozone platform selected. Which implies in layering violations,
- // which are tolerated during the X11 migration to Ozone and must be fixed
- // once it is done.
- static const char* GetPlatformName();
+ // Some tests may skip based on the platform name.
+ static std::string GetPlatformNameForTest();
// Factory getters to override in subclasses. The returned objects will be
// injected into the appropriate layer at startup. Subclasses should not
diff --git a/chromium/ui/ozone/public/ozone_switches.cc b/chromium/ui/ozone/public/ozone_switches.cc
index b9754475467..2d308f9ee30 100644
--- a/chromium/ui/ozone/public/ozone_switches.cc
+++ b/chromium/ui/ozone/public/ozone_switches.cc
@@ -15,6 +15,9 @@ const char kOzoneDumpFile[] = "ozone-dump-file";
// Try to enable wayland input method editor.
const char kEnableWaylandIme[] = "enable-wayland-ime";
+// Disable wayland input method editor.
+const char kDisableWaylandIme[] = "disable-wayland-ime";
+
// Disable explicit DMA-fences
const char kDisableExplicitDmaFences[] = "disable-explicit-dma-fences";
@@ -22,4 +25,7 @@ const char kDisableExplicitDmaFences[] = "disable-explicit-dma-fences";
const char kDisableRunningAsSystemCompositor[] =
"disable-running-as-system-compositor";
+// Disable buffer bandwidth compression
+const char kDisableBufferBWCompression[] = "disable-buffer-bw-compression";
+
} // namespace switches
diff --git a/chromium/ui/ozone/public/ozone_switches.h b/chromium/ui/ozone/public/ozone_switches.h
index 12dd34e2b51..baabdfdd8fe 100644
--- a/chromium/ui/ozone/public/ozone_switches.h
+++ b/chromium/ui/ozone/public/ozone_switches.h
@@ -16,11 +16,15 @@ COMPONENT_EXPORT(OZONE_BASE) extern const char kOzoneDumpFile[];
COMPONENT_EXPORT(OZONE_BASE) extern const char kEnableWaylandIme[];
+COMPONENT_EXPORT(OZONE_BASE) extern const char kDisableWaylandIme[];
+
COMPONENT_EXPORT(OZONE_BASE) extern const char kDisableExplicitDmaFences[];
COMPONENT_EXPORT(OZONE_BASE)
extern const char kDisableRunningAsSystemCompositor[];
+COMPONENT_EXPORT(OZONE_BASE) extern const char kDisableBufferBWCompression[];
+
} // namespace switches
#endif // UI_OZONE_PUBLIC_OZONE_SWITCHES_H_
diff --git a/chromium/ui/ozone/public/platform_gl_egl_utility.cc b/chromium/ui/ozone/public/platform_gl_egl_utility.cc
new file mode 100644
index 00000000000..38a135e4a0b
--- /dev/null
+++ b/chromium/ui/ozone/public/platform_gl_egl_utility.cc
@@ -0,0 +1,29 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/ozone/public/platform_gl_egl_utility.h"
+
+#include "base/logging.h"
+#include "base/notreached.h"
+
+namespace ui {
+
+PlatformGLEGLUtility::PlatformGLEGLUtility() = default;
+
+PlatformGLEGLUtility::~PlatformGLEGLUtility() = default;
+
+bool PlatformGLEGLUtility::HasVisualManager() {
+ return false;
+}
+
+bool PlatformGLEGLUtility::UpdateVisualsOnGpuInfoChanged(
+ bool software_rendering,
+ uint32_t default_visual_id,
+ uint32_t transparent_visual_id) {
+ NOTREACHED() << "This must not be called if the platform does not support "
+ "X11 visuals.";
+ return false;
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/public/platform_gl_egl_utility.h b/chromium/ui/ozone/public/platform_gl_egl_utility.h
index 96acbaf1ad9..568ea5644a7 100644
--- a/chromium/ui/ozone/public/platform_gl_egl_utility.h
+++ b/chromium/ui/ozone/public/platform_gl_egl_utility.h
@@ -18,7 +18,8 @@ namespace ui {
// Provides platform specific EGL attributes/configs.
class COMPONENT_EXPORT(OZONE_BASE) PlatformGLEGLUtility {
public:
- virtual ~PlatformGLEGLUtility() = default;
+ PlatformGLEGLUtility();
+ virtual ~PlatformGLEGLUtility();
// Gets additional display attributes based on |platform_type|.
virtual void GetAdditionalEGLAttributes(
@@ -41,6 +42,17 @@ class COMPONENT_EXPORT(OZONE_BASE) PlatformGLEGLUtility {
// X11 specific; returns whether the test configuration supports alpha for
// window visuals.
virtual bool X11DoesVisualHaveAlphaForTest() const = 0;
+
+ // X11 specific; returns whether the platform supports visuals.
+ virtual bool HasVisualManager();
+
+ // X11 specific; sets new visuals.
+ // Must be called only if the X11 visual manager is available.
+ // Should be called when the updated GPU info is available.
+ // Returns whether the visuals provided were valid.
+ virtual bool UpdateVisualsOnGpuInfoChanged(bool software_rendering,
+ uint32_t default_visual_id,
+ uint32_t transparent_visual_id);
};
} // namespace ui
diff --git a/chromium/ui/ozone/public/surface_factory_ozone.cc b/chromium/ui/ozone/public/surface_factory_ozone.cc
index e297254340f..c42cea806b1 100644
--- a/chromium/ui/ozone/public/surface_factory_ozone.cc
+++ b/chromium/ui/ozone/public/surface_factory_ozone.cc
@@ -35,7 +35,8 @@ GLOzone* SurfaceFactoryOzone::GetGLOzone(gl::GLImplementation implementation) {
#if BUILDFLAG(ENABLE_VULKAN)
std::unique_ptr<gpu::VulkanImplementation>
-SurfaceFactoryOzone::CreateVulkanImplementation(bool allow_protected_memory,
+SurfaceFactoryOzone::CreateVulkanImplementation(bool use_swiftshader,
+ bool allow_protected_memory,
bool enforce_protected_memory) {
return nullptr;
}
diff --git a/chromium/ui/ozone/public/surface_factory_ozone.h b/chromium/ui/ozone/public/surface_factory_ozone.h
index 773537d40e4..c68f421852a 100644
--- a/chromium/ui/ozone/public/surface_factory_ozone.h
+++ b/chromium/ui/ozone/public/surface_factory_ozone.h
@@ -78,11 +78,14 @@ class COMPONENT_EXPORT(OZONE_BASE) SurfaceFactoryOzone {
#if BUILDFLAG(ENABLE_VULKAN)
// Creates the vulkan implementation. This object should be capable of
// creating surfaces that swap to a platform window.
+ // |use_swiftshader| suggests using Swiftshader. The actual support depends
+ // on the platform.
// |allow_protected_memory| suggests that the vulkan implementation should
// create protected-capable resources, such as VkQueue.
// |enforce_protected_memory| suggests that the vulkan implementation should
// always use protected memory and resources, such as CommandBuffers.
virtual std::unique_ptr<gpu::VulkanImplementation> CreateVulkanImplementation(
+ bool use_swiftshader,
bool allow_protected_memory,
bool enforce_protected_memory);