diff options
Diffstat (limited to 'chromium/ui/ozone/platform/wayland')
222 files changed, 5622 insertions, 2391 deletions
diff --git a/chromium/ui/ozone/platform/wayland/BUILD.gn b/chromium/ui/ozone/platform/wayland/BUILD.gn index 60e1d262d2c..4ac34cea88c 100644 --- a/chromium/ui/ozone/platform/wayland/BUILD.gn +++ b/chromium/ui/ozone/platform/wayland/BUILD.gn @@ -82,6 +82,8 @@ source_set("wayland") { "host/wayland_buffer_backing_shm.h", "host/wayland_buffer_backing_solid_color.cc", "host/wayland_buffer_backing_solid_color.h", + "host/wayland_buffer_factory.cc", + "host/wayland_buffer_factory.h", "host/wayland_buffer_handle.cc", "host/wayland_buffer_handle.h", "host/wayland_buffer_manager_connector.cc", @@ -124,8 +126,6 @@ source_set("wayland") { "host/wayland_input_controller.h", "host/wayland_input_method_context.cc", "host/wayland_input_method_context.h", - "host/wayland_input_method_context_factory.cc", - "host/wayland_input_method_context_factory.h", "host/wayland_keyboard.cc", "host/wayland_keyboard.h", "host/wayland_menu_utils.cc", @@ -169,6 +169,16 @@ source_set("wayland") { "host/wayland_zaura_output.h", "host/wayland_zaura_shell.cc", "host/wayland_zaura_shell.h", + "host/wayland_zcr_color_management_output.cc", + "host/wayland_zcr_color_management_output.h", + "host/wayland_zcr_color_management_surface.cc", + "host/wayland_zcr_color_management_surface.h", + "host/wayland_zcr_color_manager.cc", + "host/wayland_zcr_color_manager.h", + "host/wayland_zcr_color_space.cc", + "host/wayland_zcr_color_space.h", + "host/wayland_zcr_color_space_creator.cc", + "host/wayland_zcr_color_space_creator.h", "host/wayland_zcr_cursor_shapes.cc", "host/wayland_zcr_cursor_shapes.h", "host/wayland_zcr_touchpad_haptics.cc", @@ -181,6 +191,8 @@ source_set("wayland") { "host/wayland_zwp_pointer_gestures.h", "host/wayland_zwp_relative_pointer_manager.cc", "host/wayland_zwp_relative_pointer_manager.h", + "host/xdg_activation.cc", + "host/xdg_activation.h", "host/xdg_foreign_wrapper.cc", "host/xdg_foreign_wrapper.h", "host/xdg_output.cc", @@ -228,6 +240,7 @@ source_set("wayland") { "//build/config/linux/libdrm", "//components/crash/core/common:crash_key", "//components/exo/wayland/protocol:aura_shell_protocol", + "//components/exo/wayland/protocol:chrome_color_management_protocol", "//components/exo/wayland/protocol:overlay_prioritizer_protocol", "//components/exo/wayland/protocol:surface_augmenter_protocol", "//mojo/public/cpp/bindings", @@ -258,6 +271,7 @@ source_set("wayland") { "//third_party/wayland-protocols:touchpad_haptics_protocol", "//third_party/wayland-protocols:viewporter_protocol", "//third_party/wayland-protocols:wayland_drm_protocol", + "//third_party/wayland-protocols:xdg_activation", "//third_party/wayland-protocols:xdg_decoration_protocol", "//third_party/wayland-protocols:xdg_foreign", "//third_party/wayland-protocols:xdg_output_protocol", @@ -267,13 +281,15 @@ source_set("wayland") { "//ui/base:data_exchange", "//ui/base:features", "//ui/base/cursor", - "//ui/base/cursor:theme_manager", "//ui/base/cursor/mojom:cursor_type", "//ui/base/dragdrop:types", "//ui/base/dragdrop/mojom", "//ui/base/ime/linux", + "//ui/base/wayland:color_manager_util", "//ui/base/wayland:wayland_client_input_types", + "//ui/display", "//ui/display/util:gpu_info_util", + "//ui/display/util:util", "//ui/events", "//ui/events:dom_keycode_converter", "//ui/events/devices", @@ -293,6 +309,10 @@ source_set("wayland") { "//ui/platform_window/wm", ] + if (is_linux) { + deps += [ "//ui/linux:linux_ui" ] + } + if (use_dbus) { sources += [ "host/org_gnome_mutter_idle_monitor.cc", @@ -480,6 +500,12 @@ source_set("test_support") { "test/test_xdg_popup.h", "test/test_zaura_output.cc", "test/test_zaura_output.h", + "test/test_zaura_popup.cc", + "test/test_zaura_popup.h", + "test/test_zaura_surface.cc", + "test/test_zaura_surface.h", + "test/test_zaura_toplevel.cc", + "test/test_zaura_toplevel.h", "test/test_zcr_stylus.cc", "test/test_zcr_stylus.h", "test/test_zcr_text_input_extension.cc", @@ -643,6 +669,7 @@ source_set("ui_test_support") { "//ui/events:test_support", "//ui/events/types:headers", "//ui/gfx", + "//ui/ozone/platform/wayland", "//ui/platform_window/common", ] } diff --git a/chromium/ui/ozone/platform/wayland/DEPS b/chromium/ui/ozone/platform/wayland/DEPS index ea0ca3d0877..39c1c917668 100644 --- a/chromium/ui/ozone/platform/wayland/DEPS +++ b/chromium/ui/ozone/platform/wayland/DEPS @@ -2,4 +2,5 @@ include_rules = [ "+mojo/public", "+third_party/wayland", "+ui/base", + "+ui/linux", ] diff --git a/chromium/ui/ozone/platform/wayland/common/wayland_object.cc b/chromium/ui/ozone/platform/wayland/common/wayland_object.cc index d5d45a7d7a3..a1e1d810e39 100644 --- a/chromium/ui/ozone/platform/wayland/common/wayland_object.cc +++ b/chromium/ui/ozone/platform/wayland/common/wayland_object.cc @@ -6,6 +6,7 @@ #include <alpha-compositing-unstable-v1-client-protocol.h> #include <aura-shell-client-protocol.h> +#include <chrome-color-management-client-protocol.h> #include <cursor-shapes-unstable-v1-client-protocol.h> #include <extended-drag-unstable-v1-client-protocol.h> #include <gtk-primary-selection-client-protocol.h> @@ -31,6 +32,7 @@ #include <wayland-client-core.h> #include <wayland-cursor.h> #include <wayland-drm-client-protocol.h> +#include <xdg-activation-v1-client-protocol.h> #include <xdg-decoration-unstable-v1-client-protocol.h> #include <xdg-foreign-unstable-v1-client-protocol.h> #include <xdg-foreign-unstable-v2-client-protocol.h> @@ -88,6 +90,42 @@ void delete_touch(wl_touch* touch) { wl_touch_destroy(touch); } +void delete_zaura_shell(zaura_shell* shell) { + if (wl::get_version_of_object(shell) >= ZAURA_SHELL_RELEASE_SINCE_VERSION) + zaura_shell_release(shell); + else + zaura_shell_destroy(shell); +} + +void delete_zaura_surface(zaura_surface* surface) { + if (wl::get_version_of_object(surface) >= ZAURA_SURFACE_RELEASE_SINCE_VERSION) + zaura_surface_release(surface); + else + zaura_surface_destroy(surface); +} + +void delete_zaura_output(zaura_output* output) { + if (wl::get_version_of_object(output) >= ZAURA_OUTPUT_RELEASE_SINCE_VERSION) + zaura_output_release(output); + else + zaura_output_destroy(output); +} + +void delete_zaura_toplevel(zaura_toplevel* toplevel) { + if (wl::get_version_of_object(toplevel) >= + ZAURA_TOPLEVEL_RELEASE_SINCE_VERSION) + zaura_toplevel_release(toplevel); + else + zaura_toplevel_destroy(toplevel); +} + +void delete_zaura_popup(zaura_popup* popup) { + if (wl::get_version_of_object(popup) >= ZAURA_POPUP_RELEASE_SINCE_VERSION) + zaura_popup_release(popup); + else + zaura_popup_destroy(popup); +} + } // namespace bool CanBind(const std::string& interface, @@ -172,17 +210,26 @@ IMPLEMENT_WAYLAND_OBJECT_TRAITS(wp_presentation) IMPLEMENT_WAYLAND_OBJECT_TRAITS(wp_presentation_feedback) IMPLEMENT_WAYLAND_OBJECT_TRAITS(wp_viewport) IMPLEMENT_WAYLAND_OBJECT_TRAITS(wp_viewporter) +IMPLEMENT_WAYLAND_OBJECT_TRAITS(xdg_activation_v1) +IMPLEMENT_WAYLAND_OBJECT_TRAITS(xdg_activation_token_v1) IMPLEMENT_WAYLAND_OBJECT_TRAITS(xdg_popup) IMPLEMENT_WAYLAND_OBJECT_TRAITS(xdg_positioner) IMPLEMENT_WAYLAND_OBJECT_TRAITS(xdg_surface) IMPLEMENT_WAYLAND_OBJECT_TRAITS(xdg_toplevel) IMPLEMENT_WAYLAND_OBJECT_TRAITS(xdg_wm_base) -IMPLEMENT_WAYLAND_OBJECT_TRAITS(zaura_output) -IMPLEMENT_WAYLAND_OBJECT_TRAITS(zaura_shell) -IMPLEMENT_WAYLAND_OBJECT_TRAITS(zaura_surface) -IMPLEMENT_WAYLAND_OBJECT_TRAITS(zaura_toplevel) -IMPLEMENT_WAYLAND_OBJECT_TRAITS(zaura_popup) +IMPLEMENT_WAYLAND_OBJECT_TRAITS_WITH_DELETER(zaura_shell, delete_zaura_shell) +IMPLEMENT_WAYLAND_OBJECT_TRAITS_WITH_DELETER(zaura_surface, + delete_zaura_surface) +IMPLEMENT_WAYLAND_OBJECT_TRAITS_WITH_DELETER(zaura_output, delete_zaura_output) +IMPLEMENT_WAYLAND_OBJECT_TRAITS_WITH_DELETER(zaura_toplevel, + delete_zaura_toplevel) +IMPLEMENT_WAYLAND_OBJECT_TRAITS_WITH_DELETER(zaura_popup, delete_zaura_popup) IMPLEMENT_WAYLAND_OBJECT_TRAITS(zcr_cursor_shapes_v1) +IMPLEMENT_WAYLAND_OBJECT_TRAITS(zcr_color_manager_v1) +IMPLEMENT_WAYLAND_OBJECT_TRAITS(zcr_color_management_output_v1) +IMPLEMENT_WAYLAND_OBJECT_TRAITS(zcr_color_management_surface_v1) +IMPLEMENT_WAYLAND_OBJECT_TRAITS(zcr_color_space_creator_v1) +IMPLEMENT_WAYLAND_OBJECT_TRAITS(zcr_color_space_v1) IMPLEMENT_WAYLAND_OBJECT_TRAITS(zcr_keyboard_extension_v1) IMPLEMENT_WAYLAND_OBJECT_TRAITS(zcr_extended_keyboard_v1) IMPLEMENT_WAYLAND_OBJECT_TRAITS(zcr_extended_drag_v1) diff --git a/chromium/ui/ozone/platform/wayland/common/wayland_object.h b/chromium/ui/ozone/platform/wayland/common/wayland_object.h index 8d278bbe95c..b32ae8bc91b 100644 --- a/chromium/ui/ozone/platform/wayland/common/wayland_object.h +++ b/chromium/ui/ozone/platform/wayland/common/wayland_object.h @@ -143,6 +143,8 @@ DECLARE_WAYLAND_OBJECT_TRAITS(wp_presentation) DECLARE_WAYLAND_OBJECT_TRAITS(wp_presentation_feedback) DECLARE_WAYLAND_OBJECT_TRAITS(wp_viewport) DECLARE_WAYLAND_OBJECT_TRAITS(wp_viewporter) +DECLARE_WAYLAND_OBJECT_TRAITS(xdg_activation_v1) +DECLARE_WAYLAND_OBJECT_TRAITS(xdg_activation_token_v1) DECLARE_WAYLAND_OBJECT_TRAITS(xdg_popup) DECLARE_WAYLAND_OBJECT_TRAITS(xdg_positioner) DECLARE_WAYLAND_OBJECT_TRAITS(xdg_surface) @@ -154,6 +156,11 @@ DECLARE_WAYLAND_OBJECT_TRAITS(zaura_surface) DECLARE_WAYLAND_OBJECT_TRAITS(zaura_toplevel) DECLARE_WAYLAND_OBJECT_TRAITS(zaura_popup) DECLARE_WAYLAND_OBJECT_TRAITS(zcr_cursor_shapes_v1) +DECLARE_WAYLAND_OBJECT_TRAITS(zcr_color_manager_v1) +DECLARE_WAYLAND_OBJECT_TRAITS(zcr_color_management_output_v1) +DECLARE_WAYLAND_OBJECT_TRAITS(zcr_color_management_surface_v1) +DECLARE_WAYLAND_OBJECT_TRAITS(zcr_color_space_creator_v1) +DECLARE_WAYLAND_OBJECT_TRAITS(zcr_color_space_v1) DECLARE_WAYLAND_OBJECT_TRAITS(zcr_blending_v1) DECLARE_WAYLAND_OBJECT_TRAITS(zcr_alpha_compositing_v1) DECLARE_WAYLAND_OBJECT_TRAITS(zcr_keyboard_extension_v1) diff --git a/chromium/ui/ozone/platform/wayland/common/wayland_overlay_config.cc b/chromium/ui/ozone/platform/wayland/common/wayland_overlay_config.cc index b9a35cac7ff..c6c649a0a25 100644 --- a/chromium/ui/ozone/platform/wayland/common/wayland_overlay_config.cc +++ b/chromium/ui/ozone/platform/wayland/common/wayland_overlay_config.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "ui/ozone/platform/wayland/common/wayland_overlay_config.h" +#include "ui/gfx/color_space.h" namespace wl { @@ -16,6 +17,7 @@ WaylandOverlayConfig::WaylandOverlayConfig(const gfx::OverlayPlaneData& data, BufferId buffer_id, float scale_factor) : z_order(data.z_order), + color_space(data.color_space), transform(data.plane_transform), buffer_id(buffer_id), surface_scale_factor(scale_factor), diff --git a/chromium/ui/ozone/platform/wayland/common/wayland_overlay_config.h b/chromium/ui/ozone/platform/wayland/common/wayland_overlay_config.h index 41dbe49702a..c6704f59ec2 100644 --- a/chromium/ui/ozone/platform/wayland/common/wayland_overlay_config.h +++ b/chromium/ui/ozone/platform/wayland/common/wayland_overlay_config.h @@ -7,6 +7,7 @@ #include <memory> +#include "ui/gfx/color_space.h" #include "ui/gfx/gpu_fence.h" #include "ui/gfx/gpu_fence_handle.h" #include "ui/gfx/overlay_plane_data.h" @@ -32,6 +33,9 @@ struct WaylandOverlayConfig { // plane. int z_order = 0; + // Specifies the color space data of the wayland config. + gfx::ColorSpace color_space = gfx::ColorSpace::CreateSRGB(); + // Specifies how the buffer is to be transformed during composition. gfx::OverlayTransform transform = gfx::OverlayTransform::OVERLAY_TRANSFORM_NONE; @@ -79,7 +83,7 @@ struct WaylandOverlayConfig { gfx::RRectF rounded_clip_bounds; // Optional: background color of this overlay plane. - absl::optional<SkColor> background_color; + absl::optional<SkColor4f> background_color; }; } // 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 56e0da69fc8..fca201f81fc 100644 --- a/chromium/ui/ozone/platform/wayland/common/wayland_util.cc +++ b/chromium/ui/ozone/platform/wayland/common/wayland_util.cc @@ -353,7 +353,11 @@ SkPath ConvertPathToDIP(const SkPath& path_in_pixels, float scale) { void SkColorToWlArray(const SkColor& color, wl_array& array) { SkColor4f precise_color = SkColor4f::FromColor(color); - for (float component : precise_color.array()) { + SkColorToWlArray(precise_color, array); +} + +void SkColorToWlArray(const SkColor4f& color, wl_array& array) { + for (float component : color.array()) { float* ptr = static_cast<float*>(wl_array_add(&array, sizeof(float))); DCHECK(ptr); *ptr = component; diff --git a/chromium/ui/ozone/platform/wayland/common/wayland_util.h b/chromium/ui/ozone/platform/wayland/common/wayland_util.h index 6a2d12bd34e..836258d6e32 100644 --- a/chromium/ui/ozone/platform/wayland/common/wayland_util.h +++ b/chromium/ui/ozone/platform/wayland/common/wayland_util.h @@ -104,6 +104,9 @@ SkPath ConvertPathToDIP(const SkPath& path_in_pixels, float scale); // Converts SkColor into wl_array. void SkColorToWlArray(const SkColor& color, wl_array& array); +// Converts SkColor4f into wl_array. +void SkColorToWlArray(const SkColor4f& color, wl_array& array); + } // namespace wl #endif // UI_OZONE_PLATFORM_WAYLAND_COMMON_WAYLAND_UTIL_H_ diff --git a/chromium/ui/ozone/platform/wayland/emulate/wayland_input_emulate.cc b/chromium/ui/ozone/platform/wayland/emulate/wayland_input_emulate.cc index cecdf9b0dac..036b01fd8b0 100644 --- a/chromium/ui/ozone/platform/wayland/emulate/wayland_input_emulate.cc +++ b/chromium/ui/ozone/platform/wayland/emulate/wayland_input_emulate.cc @@ -7,34 +7,56 @@ #include <linux/input.h> #include <wayland-client-protocol.h> #include <weston-test-client-protocol.h> +#include <weston-test-server-protocol.h> #include <memory> #include "base/logging.h" #include "base/time/time.h" +#include "ui/base/test/ui_controls.h" #include "ui/events/keycodes/dom/keycode_converter.h" +#include "ui/ozone/platform/wayland/host/wayland_window.h" #include "ui/platform_window/common/platform_window_defaults.h" namespace wl { WaylandInputEmulate::PendingEvent::PendingEvent( ui::EventType event_type, - gfx::AcceleratedWidget target_widget) + gfx::AcceleratedWidget target_widget, + WaylandInputEmulate* emulate) : type(event_type), widget(target_widget) { DCHECK(type == ui::EventType::ET_MOUSE_MOVED || type == ui::EventType::ET_MOUSE_PRESSED || type == ui::EventType::ET_MOUSE_RELEASED || type == ui::EventType::ET_KEY_PRESSED || - type == ui::EventType::ET_KEY_RELEASED); + type == ui::EventType::ET_KEY_RELEASED || + type == ui::EventType::ET_TOUCH_PRESSED || + type == ui::EventType::ET_TOUCH_MOVED || + type == ui::EventType::ET_TOUCH_RELEASED); + auto it = emulate->windows_.find(widget); + if (it != emulate->windows_.end()) { + test_window = it->second->weak_factory.GetWeakPtr(); + } } -WaylandInputEmulate::PendingEvent::~PendingEvent() = default; +namespace { -WaylandInputEmulate::TestWindow::TestWindow( - gfx::AcceleratedWidget target_widget, - WaylandInputEmulate* input_emulate) - : widget(target_widget), emulate(input_emulate) {} +int EventTypeToWaylandTouchType(ui::EventType event_type) { + switch (event_type) { + case ui::EventType::ET_TOUCH_PRESSED: + return WL_TOUCH_DOWN; + case ui::EventType::ET_TOUCH_MOVED: + return WL_TOUCH_MOTION; + default: + return WL_TOUCH_UP; + } +} + +} // namespace + +WaylandInputEmulate::PendingEvent::~PendingEvent() = default; +WaylandInputEmulate::TestWindow::TestWindow() = default; WaylandInputEmulate::TestWindow::~TestWindow() = default; WaylandInputEmulate::WaylandInputEmulate() { @@ -61,6 +83,8 @@ WaylandInputEmulate::WaylandInputEmulate() { &WaylandInputEmulate::HandlePointerPosition, &WaylandInputEmulate::HandlePointerButton, &WaylandInputEmulate::HandleKeyboardKey, + nullptr, // capture_screenshot_done + &WaylandInputEmulate::HandleTouchReceived, }; weston_test_add_listener(weston_test_, &test_listener, this); } @@ -83,40 +107,50 @@ void WaylandInputEmulate::RemoveObserver(Observer* obs) { observers_.RemoveObserver(obs); } -void WaylandInputEmulate::EmulatePointerMotion(gfx::AcceleratedWidget widget, - gfx::Point mouse_surface_loc) { - auto it = windows_.find(widget); - DCHECK(it != windows_.end()); - - auto* test_window = it->second.get(); - if (!test_window->buffer_attached_and_configured) { - auto pending_event = - std::make_unique<PendingEvent>(ui::EventType::ET_MOUSE_MOVED, widget); - pending_event->pointer_surface_location_in_px = mouse_surface_loc; - test_window->pending_events.emplace_back(std::move(pending_event)); +void WaylandInputEmulate::EmulatePointerMotion( + gfx::AcceleratedWidget widget, + const gfx::Point& mouse_surface_loc, + const gfx::Point& mouse_screen_loc_in_px) { + if (AnyWindowWaitingForBufferCommit()) { + auto pending_event = std::make_unique<PendingEvent>( + ui::EventType::ET_MOUSE_MOVED, widget, this); + pending_event->pointer_surface_location = mouse_surface_loc; + pending_event->pointer_screen_location_in_px = mouse_screen_loc_in_px; + pending_events_.emplace_back(std::move(pending_event)); return; } + // If the widget does not have a buffer, pretend it doesn't exist. It is + // treated similarly on the server. + auto it = windows_.find(widget); + if (it != windows_.end()) { + if (!it->second->buffer_attached_and_configured) + widget = 0; + } + auto* wayland_proxy = wl::WaylandProxy::GetInstance(); DCHECK(wayland_proxy); - auto* wlsurface = wayland_proxy->GetWlSurfaceForAcceleratedWidget(widget); - - // If it's a toplevel window, activate it. This results in raising the the - // parent window and its children windows. - auto window_type = wayland_proxy->GetWindowType(widget); - if (window_type != ui::PlatformWindowType::kTooltip && - window_type != ui::PlatformWindowType::kMenu && - !wayland_proxy->WindowHasPointerFocus(widget)) { - weston_test_activate_surface(weston_test_, wlsurface); + wl_surface* target_surface = nullptr; + gfx::Point target_location = mouse_screen_loc_in_px; + if (widget) { + auto* wlsurface = wayland_proxy->GetWlSurfaceForAcceleratedWidget(widget); + bool screen_coordinates = + wayland_proxy->GetWaylandWindowForAcceleratedWidget(widget) + ->IsScreenCoordinatesEnabled(); + + target_surface = screen_coordinates ? nullptr : wlsurface; + target_location = + screen_coordinates ? mouse_screen_loc_in_px : mouse_surface_loc; } + // TODO(crbug.com/1306688): The coordinate should be in DIP. timespec ts = (base::TimeTicks::Now() - base::TimeTicks()).ToTimeSpec(); - weston_test_move_pointer(weston_test_, wlsurface, + weston_test_move_pointer(weston_test_, target_surface, static_cast<uint64_t>(ts.tv_sec) >> 32, ts.tv_sec & 0xffffffff, ts.tv_nsec, - mouse_surface_loc.x(), mouse_surface_loc.y()); - wayland_proxy->ScheduleDisplayFlush(); + target_location.x(), target_location.y()); + wayland_proxy->FlushForTesting(); } void WaylandInputEmulate::EmulatePointerButton(gfx::AcceleratedWidget widget, @@ -124,16 +158,12 @@ void WaylandInputEmulate::EmulatePointerButton(gfx::AcceleratedWidget widget, uint32_t changed_button) { DCHECK(event_type == ui::EventType::ET_MOUSE_PRESSED || event_type == ui::EventType::ET_MOUSE_RELEASED); - // A button press/release event uses previous location that Ozone/Wayland got - // when OnPointerMotionEvent was called. - auto it = windows_.find(widget); - DCHECK(it != windows_.end()); - auto* test_window = it->second.get(); - if (!test_window->buffer_attached_and_configured) { - auto pending_event = std::make_unique<PendingEvent>(event_type, widget); + if (AnyWindowWaitingForBufferCommit()) { + auto pending_event = + std::make_unique<PendingEvent>(event_type, widget, this); pending_event->mouse_button = changed_button; - test_window->pending_events.emplace_back(std::move(pending_event)); + pending_events_.emplace_back(std::move(pending_event)); return; } @@ -144,6 +174,8 @@ void WaylandInputEmulate::EmulatePointerButton(gfx::AcceleratedWidget widget, (event_type == ui::EventType::ET_MOUSE_PRESSED ? WL_POINTER_BUTTON_STATE_PRESSED : WL_POINTER_BUTTON_STATE_RELEASED)); + auto* wayland_proxy = wl::WaylandProxy::GetInstance(); + wayland_proxy->FlushForTesting(); } void WaylandInputEmulate::EmulateKeyboardKey(gfx::AcceleratedWidget widget, @@ -152,26 +184,14 @@ void WaylandInputEmulate::EmulateKeyboardKey(gfx::AcceleratedWidget widget, DCHECK(event_type == ui::EventType::ET_KEY_PRESSED || event_type == ui::EventType::ET_KEY_RELEASED); - auto it = windows_.find(widget); - DCHECK(it != windows_.end()); - - auto* test_window = it->second.get(); - if (!test_window->buffer_attached_and_configured) { - auto pending_event = std::make_unique<PendingEvent>(event_type, widget); + if (AnyWindowWaitingForBufferCommit()) { + auto pending_event = + std::make_unique<PendingEvent>(event_type, widget, this); pending_event->key_dom_code = dom_code; - test_window->pending_events.emplace_back(std::move(pending_event)); + pending_events_.emplace_back(std::move(pending_event)); return; } - auto* wayland_proxy = wl::WaylandProxy::GetInstance(); - DCHECK(wayland_proxy); - - auto* wlsurface = wayland_proxy->GetWlSurfaceForAcceleratedWidget(widget); - - // Raise the window and set keyboard focus. - if (!wayland_proxy->WindowHasKeyboardFocus(widget)) - weston_test_activate_surface(weston_test_, wlsurface); - timespec ts = (base::TimeTicks::Now() - base::TimeTicks()).ToTimeSpec(); weston_test_send_key(weston_test_, static_cast<uint64_t>(ts.tv_sec) >> 32, ts.tv_sec & 0xffffffff, ts.tv_nsec, @@ -179,7 +199,31 @@ void WaylandInputEmulate::EmulateKeyboardKey(gfx::AcceleratedWidget widget, (event_type == ui::EventType::ET_KEY_PRESSED ? WL_KEYBOARD_KEY_STATE_PRESSED : WL_KEYBOARD_KEY_STATE_RELEASED)); - wayland_proxy->ScheduleDisplayFlush(); + auto* wayland_proxy = wl::WaylandProxy::GetInstance(); + wayland_proxy->FlushForTesting(); +} + +void WaylandInputEmulate::EmulateTouch(gfx::AcceleratedWidget widget, + ui::EventType event_type, + int id, + const gfx::Point& touch_screen_loc) { + if (AnyWindowWaitingForBufferCommit()) { + auto pending_event = + std::make_unique<PendingEvent>(event_type, widget, this); + pending_event->touch_screen_location = touch_screen_loc; + pending_event->touch_id = id; + pending_events_.emplace_back(std::move(pending_event)); + return; + } + + timespec ts = (base::TimeTicks::Now() - base::TimeTicks()).ToTimeSpec(); + weston_test_send_touch(weston_test_, static_cast<uint64_t>(ts.tv_sec) >> 32, + ts.tv_sec & 0xffffffff, ts.tv_nsec, id, + wl_fixed_from_int(touch_screen_loc.x()), + wl_fixed_from_int(touch_screen_loc.y()), + EventTypeToWaylandTouchType(event_type)); + auto* wayland_proxy = wl::WaylandProxy::GetInstance(); + wayland_proxy->FlushForTesting(); } void WaylandInputEmulate::OnWindowConfigured(gfx::AcceleratedWidget widget, @@ -192,6 +236,7 @@ void WaylandInputEmulate::OnWindowConfigured(gfx::AcceleratedWidget widget, // the configuration event comes. if (!is_configured) { test_surface->buffer_attached_and_configured = false; + test_surface->waiting_for_buffer_commit = false; // Also destroy the frame callback... if (test_surface->frame_callback) { wl_callback_destroy(test_surface->frame_callback); @@ -202,15 +247,17 @@ void WaylandInputEmulate::OnWindowConfigured(gfx::AcceleratedWidget widget, auto* wayland_proxy = wl::WaylandProxy::GetInstance(); DCHECK(wayland_proxy); wayland_proxy->DestroyShmForWlBuffer(test_surface->buffer); - wayland_proxy->ScheduleDisplayFlush(); + wayland_proxy->FlushForTesting(); test_surface->buffer = nullptr; } + DispatchPendingEvents(); return; } if (test_surface->buffer_attached_and_configured) return; + test_surface->waiting_for_buffer_commit = true; auto* wayland_proxy = wl::WaylandProxy::GetInstance(); DCHECK(wayland_proxy); @@ -220,7 +267,9 @@ void WaylandInputEmulate::OnWindowConfigured(gfx::AcceleratedWidget widget, // // This is needed as running some tests doesn't result in sending frames that // require buffers to be created. - auto buffer_size = wayland_proxy->GetWindowBounds(widget).size(); + auto* wayland_window = + wayland_proxy->GetWaylandWindowForAcceleratedWidget(widget); + auto buffer_size = wayland_window->GetBoundsInPixels().size(); // Adjust the buffer size in case if the window was created with empty size. if (buffer_size.IsEmpty()) buffer_size.SetSize(1, 1); @@ -242,7 +291,17 @@ void WaylandInputEmulate::OnWindowConfigured(gfx::AcceleratedWidget widget, wl_surface_commit(wlsurface); - wayland_proxy->ScheduleDisplayFlush(); + wayland_proxy->FlushForTesting(); +} + +void WaylandInputEmulate::OnWindowRoleAssigned(gfx::AcceleratedWidget widget) { + auto it = windows_.find(widget); + DCHECK(it != windows_.end()); + + // If a window has been assigned a popup role, then we must wait for a buffer + // to be committed before any events can be processed. + auto* test_surface = it->second.get(); + test_surface->waiting_for_buffer_commit = true; } void WaylandInputEmulate::OnWindowRemoved(gfx::AcceleratedWidget widget) { @@ -260,7 +319,7 @@ void WaylandInputEmulate::OnWindowRemoved(gfx::AcceleratedWidget widget) { auto* wayland_proxy = wl::WaylandProxy::GetInstance(); DCHECK(wayland_proxy); wayland_proxy->DestroyShmForWlBuffer(it->second->buffer); - wayland_proxy->ScheduleDisplayFlush(); + wayland_proxy->FlushForTesting(); } windows_.erase(it); } @@ -271,13 +330,28 @@ void WaylandInputEmulate::OnWindowAdded(gfx::AcceleratedWidget widget) { // a button pressed state left if the previous test crashed. if (windows_.empty()) { weston_test_reset_pointer(weston_test_); + + // Release all meta-keys to deal with carry-over state from previous tests. + std::vector<ui::DomCode> meta_keys = { + ui::DomCode::CONTROL_LEFT, ui::DomCode::SHIFT_LEFT, + ui::DomCode::ALT_LEFT, ui::DomCode::META_LEFT, + ui::DomCode::CONTROL_RIGHT, ui::DomCode::SHIFT_RIGHT, + ui::DomCode::ALT_RIGHT, ui::DomCode::META_RIGHT, + }; + for (auto key : meta_keys) { + timespec ts = (base::TimeTicks::Now() - base::TimeTicks()).ToTimeSpec(); + weston_test_send_key(weston_test_, static_cast<uint64_t>(ts.tv_sec) >> 32, + ts.tv_sec & 0xffffffff, ts.tv_nsec, + ui::KeycodeConverter::DomCodeToEvdevCode(key), + WL_KEYBOARD_KEY_STATE_RELEASED); + } + auto* wayland_proxy = wl::WaylandProxy::GetInstance(); DCHECK(wayland_proxy); - wayland_proxy->ScheduleDisplayFlush(); + wayland_proxy->FlushForTesting(); } - windows_.emplace( - widget, std::make_unique<WaylandInputEmulate::TestWindow>(widget, this)); + windows_.emplace(widget, std::make_unique<WaylandInputEmulate::TestWindow>()); } // static @@ -286,8 +360,8 @@ void WaylandInputEmulate::HandlePointerPosition(void* data, wl_fixed_t x, wl_fixed_t y) { WaylandInputEmulate* emulate = static_cast<WaylandInputEmulate*>(data); - auto mouse_position_on_screen_px = - gfx::Point(wl_fixed_to_int(x), wl_fixed_to_int(y)); + gfx::Point mouse_position_on_screen_px(wl_fixed_to_int(x), + wl_fixed_to_int(y)); for (WaylandInputEmulate::Observer& observer : emulate->observers_) observer.OnPointerMotionGlobal(mouse_position_on_screen_px); } @@ -315,6 +389,18 @@ void WaylandInputEmulate::HandleKeyboardKey(void* data, } // static +void WaylandInputEmulate::HandleTouchReceived(void* data, + struct weston_test* weston_test, + wl_fixed_t x, + wl_fixed_t y) { + WaylandInputEmulate* emulate = static_cast<WaylandInputEmulate*>(data); + auto touch_position_on_screen_px = + gfx::Point(wl_fixed_to_int(x), wl_fixed_to_int(y)); + for (WaylandInputEmulate::Observer& observer : emulate->observers_) + observer.OnTouchReceived(touch_position_on_screen_px); +} + +// static void WaylandInputEmulate::Global(void* data, wl_registry* registry, uint32_t name, @@ -345,36 +431,57 @@ void WaylandInputEmulate::FrameCallbackHandler(void* data, } } - if (!window) - return; + if (window) { + wl_callback_destroy(window->frame_callback); + window->frame_callback = nullptr; - wl_callback_destroy(window->frame_callback); - window->frame_callback = nullptr; + DCHECK(!window->buffer_attached_and_configured); + window->buffer_attached_and_configured = true; + window->waiting_for_buffer_commit = false; + } - DCHECK(!window->buffer_attached_and_configured); - window->buffer_attached_and_configured = true; + emulate->DispatchPendingEvents(); +} - while (!window->pending_events.empty()) { - auto event = std::move(window->pending_events.front()); - window->pending_events.pop_front(); +bool WaylandInputEmulate::AnyWindowWaitingForBufferCommit() { + for (auto& it : windows_) { + if (it.second->waiting_for_buffer_commit) + return true; + } + return false; +} - auto* input_emulate = window->emulate; - DCHECK(input_emulate); +void WaylandInputEmulate::DispatchPendingEvents() { + while (!pending_events_.empty()) { + // Cannot dispatch pending events if there's a window waiting for a buffer + // commit. + if (AnyWindowWaitingForBufferCommit()) + return; + auto event = std::move(pending_events_.front()); + pending_events_.pop_front(); switch (event->type) { case ui::EventType::ET_MOUSE_MOVED: - input_emulate->EmulatePointerMotion( - window->widget, event->pointer_surface_location_in_px); + // If the test window has been destroyed then do not use a widget. + if (!event->test_window) + event->widget = 0; + EmulatePointerMotion( + /*widget=*/event->widget, event->pointer_surface_location, + event->pointer_screen_location_in_px); break; case ui::EventType::ET_MOUSE_PRESSED: case ui::EventType::ET_MOUSE_RELEASED: - input_emulate->EmulatePointerButton(window->widget, event->type, - event->mouse_button); + EmulatePointerButton(/*widget=*/0, event->type, event->mouse_button); break; case ui::EventType::ET_KEY_PRESSED: case ui::EventType::ET_KEY_RELEASED: - input_emulate->EmulateKeyboardKey(window->widget, event->type, - event->key_dom_code); + EmulateKeyboardKey(/*widget=*/0, event->type, event->key_dom_code); + break; + case ui::EventType::ET_TOUCH_PRESSED: + case ui::EventType::ET_TOUCH_MOVED: + case ui::EventType::ET_TOUCH_RELEASED: + EmulateTouch(/*widget=*/0, event->type, event->touch_id, + event->touch_screen_location); break; default: NOTREACHED(); diff --git a/chromium/ui/ozone/platform/wayland/emulate/wayland_input_emulate.h b/chromium/ui/ozone/platform/wayland/emulate/wayland_input_emulate.h index 77a5ec61a55..34646f09775 100644 --- a/chromium/ui/ozone/platform/wayland/emulate/wayland_input_emulate.h +++ b/chromium/ui/ozone/platform/wayland/emulate/wayland_input_emulate.h @@ -12,6 +12,8 @@ #include "base/component_export.h" #include "base/containers/circular_deque.h" #include "base/containers/flat_map.h" +#include "base/memory/raw_ptr.h" +#include "base/memory/weak_ptr.h" #include "base/observer_list.h" #include "ui/events/keycodes/dom/dom_code.h" #include "ui/events/types/event_type.h" @@ -26,7 +28,7 @@ struct wl_callback; namespace wl { -// Emulates Keyboard, Pointer, Touch events that ui_interactive_tests test +// Emulates Keyboard, Pointer, and Touch events that ui_interactive_tests test // suite sends. Mustn't be used in production code. class WaylandInputEmulate : public wl::WaylandProxy::Delegate { public: @@ -43,6 +45,10 @@ class WaylandInputEmulate : public wl::WaylandProxy::Delegate { // event codes in Linux's input-event-codes.h. virtual void OnKeyboardKey(int32_t key, bool pressed) = 0; + // Notifies that the Wayland compositor has sent a touch event to + // |screen_position|. + virtual void OnTouchReceived(const gfx::Point& screen_position) = 0; + protected: ~Observer() override = default; }; @@ -53,49 +59,62 @@ class WaylandInputEmulate : public wl::WaylandProxy::Delegate { void AddObserver(Observer* obs); void RemoveObserver(Observer* obs); void EmulatePointerMotion(gfx::AcceleratedWidget widget, - gfx::Point mouse_surface_loc); + const gfx::Point& mouse_surface_loc, + const gfx::Point& mouse_screen_loc_in_px); + + // |widget| is only needed to queue up the event if the widget is not yet + // configured. If the event is being dequeued then |widget| will be 0. void EmulatePointerButton(gfx::AcceleratedWidget widget, ui::EventType event_type, uint32_t changed_button); void EmulateKeyboardKey(gfx::AcceleratedWidget widget, ui::EventType event_type, ui::DomCode dom_code); + void EmulateTouch(gfx::AcceleratedWidget widget, + ui::EventType event_type, + int id, + const gfx::Point& touch_screen_loc); private: + struct TestWindow; + // Pending emulated events. Can be ET_MOUSE_MOVED, - // ET_MOUSE_PRESSED/ET_MOUSE_RELEASED, or ET_KEY_PRESSED/ET_KEY_RELEASED. + // ET_MOUSE_PRESSED/ET_MOUSE_RELEASED, ET_KEY_PRESSED/ET_KEY_RELEASED, or + // ET_TOUCH_PRESSED/ET_TOUCH_MOVED/ET_TOUCH_RELEASED. struct PendingEvent { PendingEvent(ui::EventType event_type, - gfx::AcceleratedWidget target_widget); + gfx::AcceleratedWidget target_widget, + WaylandInputEmulate*); ~PendingEvent(); ui::EventType type; gfx::AcceleratedWidget widget; + base::WeakPtr<TestWindow> test_window; + + // Set for type == ET_MOUSE_MOVED. Locations are + // in surface local, and pixel screen coordinates respectively. + gfx::Point pointer_surface_location; + gfx::Point pointer_screen_location_in_px; - // Set for type == ET_MOUSE_MOVED. - gfx::Point pointer_surface_location_in_px; + // Set for type == ET_TOUCH_*. Location is in dip screen coordinates. + gfx::Point touch_screen_location; // Set for type == ET_MOUSE_PRESSED || type == ET_MOUSE_RELEASED. uint32_t mouse_button = 0; // Set for type == ET_KEY_PRESSED || type == ET_KEY_RELEASED. ui::DomCode key_dom_code = ui::DomCode::NONE; + + // Set for type == ET_TOUCH_*. + int touch_id = 0; }; // A container that tracks created WaylandWindows and keeps some fundamental // bits to make emulation work flawlessly. struct TestWindow { - TestWindow(gfx::AcceleratedWidget target_widget, - WaylandInputEmulate* emulate); + TestWindow(); ~TestWindow(); - // Widget that this TestWindow represents. This corresponds to a - // WaylandWindow created on the Ozone/Wayland side. - gfx::AcceleratedWidget widget; - - // Non-owned pointer to input emulation. - WaylandInputEmulate* emulate = nullptr; - // Control flag that says if the buffer has been attached and a consequent // frame callback has been received. This is required to be able to know // that the surface has consumed the attached buffer and Wayland properly @@ -104,15 +123,17 @@ class WaylandInputEmulate : public wl::WaylandProxy::Delegate { // call. bool buffer_attached_and_configured = false; - // Pending events to be sent for this TestWindow. These are sent after - // buffer_attached_and_configured is set to true. - base::circular_deque<std::unique_ptr<PendingEvent>> pending_events; - // Frame callback that invokes WaylandInputEmulate::FrameCallbackHandler. - struct wl_callback* frame_callback = nullptr; + raw_ptr<struct wl_callback> frame_callback = nullptr; // The attached buffer. - wl_buffer* buffer = nullptr; + raw_ptr<wl_buffer> buffer = nullptr; + + // True if the window was created or assigned a role and is now waiting for + // a buffer to be committed. + bool waiting_for_buffer_commit = false; + + base::WeakPtrFactory<TestWindow> weak_factory{this}; }; // WaylandProxy::Delegate. @@ -120,6 +141,7 @@ class WaylandInputEmulate : public wl::WaylandProxy::Delegate { void OnWindowRemoved(gfx::AcceleratedWidget widget) override; void OnWindowConfigured(gfx::AcceleratedWidget widget, bool is_configured) override; + void OnWindowRoleAssigned(gfx::AcceleratedWidget widget) override; // weston_test_listener. static void HandlePointerPosition(void* data, @@ -134,6 +156,10 @@ class WaylandInputEmulate : public wl::WaylandProxy::Delegate { struct weston_test* weston_test, uint32_t key, uint32_t state); + static void HandleTouchReceived(void* data, + struct weston_test* weston_test, + wl_fixed_t x, + wl_fixed_t y); // wl_registry_listener. static void Global(void* data, @@ -147,18 +173,33 @@ class WaylandInputEmulate : public wl::WaylandProxy::Delegate { struct wl_callback* callback, uint32_t time); - // Stores existing windows. + // Returns true if there is at least one window that has been created but that + // does not yet have a buffer committed. + bool AnyWindowWaitingForBufferCommit(); + + // Dispatches all pending events. + void DispatchPendingEvents(); + + // Window creation is asynchronous in wayland. First we create the window, + // then we must attach and commit a buffer before the server will treat it + // properly w.r.t. input events. This member stores all windows that have been + // created. base::flat_map<gfx::AcceleratedWidget, std::unique_ptr<WaylandInputEmulate::TestWindow>> windows_; + // Stores pending events in a global queue. We will not dispatch any pending + // events while there are windows that are still in the process of being + // created. + base::circular_deque<std::unique_ptr<PendingEvent>> pending_events_; + base::ObserverList<WaylandInputEmulate::Observer> observers_; // Owned raw pointers. wl::Object is not used because the component this // class belongs to cannot depend on the "wayland" target in the // //ui/ozone/platform/wayland/BUILD.gn - struct wl_registry* registry_ = nullptr; - struct weston_test* weston_test_ = nullptr; + raw_ptr<struct wl_registry> registry_ = nullptr; + raw_ptr<struct weston_test> weston_test_ = nullptr; }; } // namespace wl diff --git a/chromium/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.h b/chromium/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.h index 06d02905d05..9e8b2faae0a 100644 --- a/chromium/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.h +++ b/chromium/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.h @@ -9,6 +9,7 @@ #include <vector> #include "base/files/scoped_file.h" +#include "base/memory/raw_ptr.h" #include "ui/gfx/buffer_types.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/linux/gbm_buffer.h" @@ -78,7 +79,7 @@ class GbmPixmapWayland : public gfx::NativePixmap { std::unique_ptr<GbmBuffer> gbm_bo_; // Represents a connection to Wayland. - WaylandBufferManagerGpu* const buffer_manager_; + const raw_ptr<WaylandBufferManagerGpu> buffer_manager_; // Represents widget this pixmap backs. gfx::AcceleratedWidget widget_ = gfx::kNullAcceleratedWidget; 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 1bfdcd2d510..44630f401e6 100644 --- a/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc +++ b/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc @@ -45,7 +45,7 @@ GbmSurfacelessWayland::SolidColorBufferHolder::~SolidColorBufferHolder() = BufferId GbmSurfacelessWayland::SolidColorBufferHolder::GetOrCreateSolidColorBuffer( - SkColor color, + SkColor4f color, WaylandBufferManagerGpu* buffer_manager) { BufferId next_buffer_id = 0; @@ -111,9 +111,10 @@ void GbmSurfacelessWayland::SolidColorBufferHolder::EraseBuffers( } GbmSurfacelessWayland::GbmSurfacelessWayland( + gl::GLDisplayEGL* display, WaylandBufferManagerGpu* buffer_manager, gfx::AcceleratedWidget widget) - : SurfacelessEGL(gl::GLSurfaceEGL::GetGLDisplayEGL(), gfx::Size()), + : SurfacelessEGL(display, gfx::Size()), buffer_manager_(buffer_manager), widget_(widget), solid_color_buffers_holder_(std::make_unique<SolidColorBufferHolder>()), 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 ba10a39b5b5..ec69bd0949a 100644 --- a/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h +++ b/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h @@ -9,6 +9,7 @@ #include <vector> #include "base/gtest_prod_util.h" +#include "base/memory/raw_ptr.h" #include "base/memory/weak_ptr.h" #include "ui/gfx/native_widget_types.h" #include "ui/gl/gl_surface_egl.h" @@ -29,7 +30,8 @@ using BufferId = uint32_t; class GbmSurfacelessWayland : public gl::SurfacelessEGL, public WaylandSurfaceGpu { public: - GbmSurfacelessWayland(WaylandBufferManagerGpu* buffer_manager, + GbmSurfacelessWayland(gl::GLDisplayEGL* display, + WaylandBufferManagerGpu* buffer_manager, gfx::AcceleratedWidget widget); GbmSurfacelessWayland(const GbmSurfacelessWayland&) = delete; @@ -72,7 +74,7 @@ class GbmSurfacelessWayland : public gl::SurfacelessEGL, bool has_alpha) override; void SetForceGlFlushOnSwapBuffers() override; - BufferId GetOrCreateSolidColorBuffer(SkColor color, const gfx::Size& size); + BufferId GetOrCreateSolidColorBuffer(SkColor4f color, const gfx::Size& size); private: FRIEND_TEST_ALL_PREFIXES(WaylandSurfaceFactoryTest, @@ -91,7 +93,7 @@ class GbmSurfacelessWayland : public gl::SurfacelessEGL, ~SolidColorBufferHolder(); BufferId GetOrCreateSolidColorBuffer( - SkColor color, + SkColor4f color, WaylandBufferManagerGpu* buffer_manager); void OnSubmission(BufferId buffer_id, @@ -103,14 +105,14 @@ class GbmSurfacelessWayland : public gl::SurfacelessEGL, // anything and stored on the gpu side for convenience so that WBHM doesn't // become more complex. struct SolidColorBuffer { - SolidColorBuffer(SkColor color, BufferId buffer_id) + SolidColorBuffer(const SkColor4f& color, BufferId buffer_id) : color(color), buffer_id(buffer_id) {} SolidColorBuffer(SolidColorBuffer&& buffer) = default; SolidColorBuffer& operator=(SolidColorBuffer&& buffer) = default; ~SolidColorBuffer() = default; // Color of the buffer. - SkColor color = SK_ColorWHITE; + SkColor4f color = SkColors::kWhite; // The buffer id that is mapped with the buffer id created on the browser // side. BufferId buffer_id = 0; @@ -163,7 +165,7 @@ class GbmSurfacelessWayland : public gl::SurfacelessEGL, // Sets a flag that skips glFlush step in unittests. void SetNoGLFlushForTests(); - WaylandBufferManagerGpu* const buffer_manager_; + const raw_ptr<WaylandBufferManagerGpu> buffer_manager_; // The native surface. Deleting this is allowed to free the EGLNativeWindow. gfx::AcceleratedWidget widget_; 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 9e955388c5f..8452279ad51 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 @@ -27,9 +27,12 @@ GLSurfaceEglReadbackWayland::PixelBuffer::PixelBuffer( GLSurfaceEglReadbackWayland::PixelBuffer::~PixelBuffer() = default; GLSurfaceEglReadbackWayland::GLSurfaceEglReadbackWayland( + gl::GLDisplayEGL* display, gfx::AcceleratedWidget widget, WaylandBufferManagerGpu* buffer_manager) - : widget_(widget), buffer_manager_(buffer_manager) { + : GLSurfaceEglReadback(display), + widget_(widget), + buffer_manager_(buffer_manager) { buffer_manager_->RegisterSurface(widget_, this); } @@ -119,7 +122,8 @@ void GLSurfaceEglReadbackWayland::SwapBuffersAsync( const auto bounds = gfx::Rect(GetSize()); buffer_manager_->CommitBuffer(widget_, next_buffer->buffer_id_, /*frame_id*/ next_buffer->buffer_id_, bounds, - surface_scale_factor_, bounds); + gfx::RoundedCornersF(), surface_scale_factor_, + bounds); } gfx::SurfaceOrigin GLSurfaceEglReadbackWayland::GetOrigin() const { diff --git a/chromium/ui/ozone/platform/wayland/gpu/gl_surface_egl_readback_wayland.h b/chromium/ui/ozone/platform/wayland/gpu/gl_surface_egl_readback_wayland.h index 8d8f915307d..df7d6a92a61 100644 --- a/chromium/ui/ozone/platform/wayland/gpu/gl_surface_egl_readback_wayland.h +++ b/chromium/ui/ozone/platform/wayland/gpu/gl_surface_egl_readback_wayland.h @@ -6,6 +6,7 @@ #define UI_OZONE_PLATFORM_WAYLAND_GPU_GL_SURFACE_EGL_READBACK_WAYLAND_H_ #include "base/containers/circular_deque.h" +#include "base/memory/raw_ptr.h" #include "base/memory/shared_memory_mapping.h" #include "ui/ozone/common/gl_surface_egl_readback.h" #include "ui/ozone/platform/wayland/gpu/wayland_surface_gpu.h" @@ -32,7 +33,8 @@ class WaylandBufferManagerGpu; class GLSurfaceEglReadbackWayland : public GLSurfaceEglReadback, public WaylandSurfaceGpu { public: - GLSurfaceEglReadbackWayland(gfx::AcceleratedWidget widget, + GLSurfaceEglReadbackWayland(gl::GLDisplayEGL* display, + gfx::AcceleratedWidget widget, WaylandBufferManagerGpu* buffer_manager); GLSurfaceEglReadbackWayland(const GLSurfaceEglReadbackWayland&) = delete; GLSurfaceEglReadbackWayland& operator=(const GLSurfaceEglReadbackWayland&) = @@ -82,7 +84,7 @@ class GLSurfaceEglReadbackWayland : public GLSurfaceEglReadback, // Widget of the window that this readback writes pixels to. const gfx::AcceleratedWidget widget_; - WaylandBufferManagerGpu* const buffer_manager_; + const raw_ptr<WaylandBufferManagerGpu> buffer_manager_; // Size of the buffer. gfx::Size size_; 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 0bf1c8fd0a6..b428f74401c 100644 --- a/chromium/ui/ozone/platform/wayland/gpu/gl_surface_wayland.cc +++ b/chromium/ui/ozone/platform/wayland/gpu/gl_surface_wayland.cc @@ -24,7 +24,7 @@ void EGLWindowDeleter::operator()(wl_egl_window* egl_window) { std::unique_ptr<wl_egl_window, EGLWindowDeleter> CreateWaylandEglWindow( WaylandWindow* window) { - gfx::Size size = window->GetBoundsInPixels().size(); + gfx::Size size = window->size_px(); return std::unique_ptr<wl_egl_window, EGLWindowDeleter>(wl_egl_window_create( window->root_surface()->surface(), size.width(), size.height())); } @@ -117,7 +117,7 @@ GLSurfaceWayland::~GLSurfaceWayland() { void GLSurfaceWayland::UpdateVisualSize() { window_->ui_task_runner()->PostTask( FROM_HERE, base::BindOnce(&WaylandWindow::UpdateVisualSize, - window_->AsWeakPtr(), size_, scale_factor_)); + window_->AsWeakPtr(), size_)); } } // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/gpu/gl_surface_wayland.h b/chromium/ui/ozone/platform/wayland/gpu/gl_surface_wayland.h index 21c65411c28..b7c3a1dc00e 100644 --- a/chromium/ui/ozone/platform/wayland/gpu/gl_surface_wayland.h +++ b/chromium/ui/ozone/platform/wayland/gpu/gl_surface_wayland.h @@ -8,6 +8,7 @@ #include <memory> #include "base/callback_forward.h" +#include "base/memory/raw_ptr.h" #include "ui/gfx/geometry/size.h" #include "ui/gl/gl_surface_egl.h" @@ -55,7 +56,7 @@ class GLSurfaceWayland : public gl::NativeViewGLSurfaceEGL { void UpdateVisualSize(); WaylandEglWindowPtr egl_window_; - WaylandWindow* const window_; + const raw_ptr<WaylandWindow> window_; float scale_factor_ = 1.f; }; 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 03860d6826a..0be711fc0c8 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 @@ -16,6 +16,7 @@ #include "ui/gfx/geometry/rrect_f.h" #include "ui/gfx/linux/drm_util_linux.h" #include "ui/gfx/overlay_priority_hint.h" +#include "ui/gl/gl_bindings.h" #include "ui/gl/gl_surface_egl.h" #include "ui/ozone/platform/wayland/common/wayland_overlay_config.h" #include "ui/ozone/platform/wayland/gpu/wayland_surface_gpu.h" @@ -104,7 +105,6 @@ void WaylandBufferManagerGpu::OnSubmission(gfx::AcceleratedWidget widget, gfx::GpuFenceHandle release_fence) { DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_); - base::AutoLock scoped_lock(lock_); DCHECK_LE(commit_thread_runners_.count(widget), 1u); // Return back to the same thread where the commit request came from. auto it = commit_thread_runners_.find(widget); @@ -123,7 +123,6 @@ void WaylandBufferManagerGpu::OnPresentation( const gfx::PresentationFeedback& feedback) { DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_); - base::AutoLock scoped_lock(lock_); DCHECK_LE(commit_thread_runners_.count(widget), 1u); // Return back to the same thread where the commit request came from. auto it = commit_thread_runners_.find(widget); @@ -220,7 +219,7 @@ void WaylandBufferManagerGpu::CreateShmBasedBuffer(base::ScopedFD shm_fd, RunOrQueueTask(std::move(task)); } -void WaylandBufferManagerGpu::CreateSolidColorBuffer(SkColor color, +void WaylandBufferManagerGpu::CreateSolidColorBuffer(SkColor4f color, const gfx::Size& size, uint32_t buf_id) { DCHECK(gpu_thread_runner_); @@ -243,6 +242,7 @@ void WaylandBufferManagerGpu::CommitBuffer(gfx::AcceleratedWidget widget, uint32_t frame_id, uint32_t buffer_id, const gfx::Rect& bounds_rect, + const gfx::RoundedCornersF& corners, float surface_scale_factor, const gfx::Rect& damage_region) { // This surface only commits one buffer per frame, use INT32_MIN to attach @@ -253,7 +253,8 @@ void WaylandBufferManagerGpu::CommitBuffer(gfx::AcceleratedWidget widget, INT32_MIN, gfx::OverlayTransform::OVERLAY_TRANSFORM_NONE, gfx::RectF(bounds_rect), gfx::RectF(1.f, 1.f) /* no crop */, false, damage_region, 1.0f /*opacity*/, gfx::OverlayPriorityHint::kNone, - gfx::RRectF(), gfx::ColorSpace(), absl::nullopt), + gfx::RRectF(gfx::RectF(bounds_rect), corners), gfx::ColorSpace(), + absl::nullopt), nullptr, buffer_id, surface_scale_factor); CommitOverlays(widget, frame_id, std::move(overlay_configs)); } @@ -297,10 +298,9 @@ void WaylandBufferManagerGpu::DestroyBuffer(uint32_t buffer_id) { #if defined(WAYLAND_GBM) GbmDevice* WaylandBufferManagerGpu::GetGbmDevice() { // Wayland won't support wl_drm or zwp_linux_dmabuf without this extension. - if (!supports_dmabuf_ || - (!gl::GLSurfaceEGL::GetGLDisplayEGL()->HasEGLExtension( - "EGL_EXT_image_dma_buf_import") && - !use_fake_gbm_device_for_test_)) { + if (!supports_dmabuf_ || (!gl::GLSurfaceEGL::GetGLDisplayEGL() + ->ext->b_EGL_EXT_image_dma_buf_import && + !use_fake_gbm_device_for_test_)) { supports_dmabuf_ = false; return nullptr; } @@ -480,7 +480,7 @@ void WaylandBufferManagerGpu::CreateShmBasedBufferTask(base::ScopedFD shm_fd, length, size, buffer_id); } -void WaylandBufferManagerGpu::CreateSolidColorBufferTask(SkColor color, +void WaylandBufferManagerGpu::CreateSolidColorBufferTask(SkColor4f color, const gfx::Size& size, uint32_t buf_id) { DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_); 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 1843b146861..61e40ff8fbe 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 @@ -102,7 +102,7 @@ class WaylandBufferManagerGpu : public ozone::mojom::WaylandBufferManagerGpu { // Asks Wayland to create a solid color wl_buffer that is not backed by // anything on the gpu side. Requires surface-augmenter protocol. - void CreateSolidColorBuffer(SkColor color, + void CreateSolidColorBuffer(SkColor4f color, const gfx::Size& size, uint32_t buf_id); @@ -123,6 +123,7 @@ class WaylandBufferManagerGpu : public ozone::mojom::WaylandBufferManagerGpu { uint32_t frame_id, uint32_t buffer_id, const gfx::Rect& bounds_rect, + const gfx::RoundedCornersF& corners, float surface_scale_factor, const gfx::Rect& damage_region); // Send overlay configurations for a frame to a WaylandWindow identified by @@ -216,7 +217,7 @@ class WaylandBufferManagerGpu : public ozone::mojom::WaylandBufferManagerGpu { size_t length, gfx::Size size, uint32_t buffer_id); - void CreateSolidColorBufferTask(SkColor color, + void CreateSolidColorBufferTask(SkColor4f color, const gfx::Size& size, uint32_t buf_id); void CommitOverlaysTask(gfx::AcceleratedWidget widget, 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 a58e342a74f..bdf254653bc 100644 --- a/chromium/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.cc +++ b/chromium/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.cc @@ -8,6 +8,7 @@ #include <utility> #include "base/files/scoped_file.h" +#include "base/memory/raw_ptr.h" #include "base/memory/shared_memory_mapping.h" #include "base/memory/unsafe_shared_memory_region.h" #include "base/numerics/checked_math.h" @@ -96,7 +97,8 @@ class WaylandCanvasSurface::SharedMemoryBuffer { void CommitBuffer(const gfx::Rect& damage, float buffer_scale) { buffer_manager_->CommitBuffer(widget_, buffer_id_, /*frame_id*/ buffer_id_, - gfx::Rect(size_), buffer_scale, damage); + gfx::Rect(size_), gfx::RoundedCornersF(), + buffer_scale, damage); } void OnUse() { @@ -151,7 +153,7 @@ class WaylandCanvasSurface::SharedMemoryBuffer { const gfx::AcceleratedWidget widget_; // Non-owned pointer to the buffer manager on the gpu process/thread side. - WaylandBufferManagerGpu* const buffer_manager_; + const raw_ptr<WaylandBufferManagerGpu> buffer_manager_; // Shared memory for the buffer. base::WritableSharedMemoryMapping shm_mapping_; diff --git a/chromium/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.h b/chromium/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.h index cbf4414ee6d..d8ab7aad8c6 100644 --- a/chromium/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.h +++ b/chromium/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.h @@ -8,6 +8,7 @@ #include <memory> #include <vector> +#include "base/memory/raw_ptr.h" #include "base/memory/weak_ptr.h" #include "base/time/time.h" #include "third_party/skia/include/core/SkRefCnt.h" @@ -83,7 +84,7 @@ class WaylandCanvasSurface : public SurfaceOzoneCanvas, sk_sp<SkSurface> GetNextSurface(); std::unique_ptr<SharedMemoryBuffer> CreateSharedMemoryBuffer(); - WaylandBufferManagerGpu* const buffer_manager_; + const raw_ptr<WaylandBufferManagerGpu> buffer_manager_; const gfx::AcceleratedWidget widget_; gfx::Size size_; @@ -95,14 +96,14 @@ class WaylandCanvasSurface : public SurfaceOzoneCanvas, // Pending buffer that is to be placed into the |unsubmitted_buffers_| to be // processed. - SharedMemoryBuffer* pending_buffer_ = nullptr; + raw_ptr<SharedMemoryBuffer> pending_buffer_ = nullptr; // Currently used buffer. Set on PresentCanvas() and released on // OnSubmission() call. - SharedMemoryBuffer* current_buffer_ = nullptr; + raw_ptr<SharedMemoryBuffer> current_buffer_ = nullptr; // Previously used buffer. Set on OnSubmission(). - SharedMemoryBuffer* previous_buffer_ = nullptr; + raw_ptr<SharedMemoryBuffer> previous_buffer_ = nullptr; // Used by the internal VSyncProvider implementation. Set on OnPresentation(). base::TimeTicks last_timestamp_; diff --git a/chromium/ui/ozone/platform/wayland/gpu/wayland_overlay_candidates.h b/chromium/ui/ozone/platform/wayland/gpu/wayland_overlay_candidates.h index 67efe200d14..9223273facc 100644 --- a/chromium/ui/ozone/platform/wayland/gpu/wayland_overlay_candidates.h +++ b/chromium/ui/ozone/platform/wayland/gpu/wayland_overlay_candidates.h @@ -7,6 +7,7 @@ #include <vector> +#include "base/memory/raw_ptr.h" #include "ui/gfx/native_widget_types.h" #include "ui/ozone/public/overlay_candidates_ozone.h" @@ -29,7 +30,7 @@ class WaylandOverlayCandidates : public OverlayCandidatesOzone { std::vector<OverlaySurfaceCandidate>* candidates) override; private: - WaylandOverlayManager* const overlay_manager_; // Not owned. + const raw_ptr<WaylandOverlayManager> overlay_manager_; // Not owned. const gfx::AcceleratedWidget widget_; }; diff --git a/chromium/ui/ozone/platform/wayland/gpu/wayland_overlay_manager.h b/chromium/ui/ozone/platform/wayland/gpu/wayland_overlay_manager.h index ad9f1e31002..22249029940 100644 --- a/chromium/ui/ozone/platform/wayland/gpu/wayland_overlay_manager.h +++ b/chromium/ui/ozone/platform/wayland/gpu/wayland_overlay_manager.h @@ -5,6 +5,7 @@ #ifndef UI_OZONE_PLATFORM_WAYLAND_GPU_WAYLAND_OVERLAY_MANAGER_H_ #define UI_OZONE_PLATFORM_WAYLAND_GPU_WAYLAND_OVERLAY_MANAGER_H_ +#include "base/memory/raw_ptr.h" #include "ui/gfx/native_widget_types.h" #include "ui/ozone/public/overlay_candidates_ozone.h" #include "ui/ozone/public/overlay_manager_ozone.h" @@ -39,7 +40,7 @@ class WaylandOverlayManager : public OverlayManagerOzone { bool CanHandleCandidate(const OverlaySurfaceCandidate& candidate, gfx::AcceleratedWidget widget) const; - WaylandBufferManagerGpu* const manager_gpu_; + const raw_ptr<WaylandBufferManagerGpu> manager_gpu_; // Same as features::IsDelegatedCompositingEnabled. bool is_delegated_context_ = false; 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 907de8ba061..0cbfdb8b019 100644 --- a/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory.cc +++ b/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory.cc @@ -7,9 +7,13 @@ #include <memory> #include "base/memory/ptr_util.h" +#include "base/memory/raw_ptr.h" #include "ui/gfx/linux/client_native_pixmap_dmabuf.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" +#include "ui/ozone/common/native_pixmap_egl_binding.h" #include "ui/ozone/platform/wayland/common/wayland_object.h" #include "ui/ozone/platform/wayland/gpu/gl_surface_egl_readback_wayland.h" #include "ui/ozone/platform/wayland/gpu/gl_surface_wayland.h" @@ -44,13 +48,27 @@ class GLOzoneEGLWayland : public GLOzoneEGL { ~GLOzoneEGLWayland() override {} + bool CanImportNativePixmap() override; + + std::unique_ptr<NativePixmapGLBinding> ImportNativePixmap( + scoped_refptr<gfx::NativePixmap> pixmap, + gfx::BufferFormat plane_format, + gfx::BufferPlane plane, + gfx::Size plane_size, + const gfx::ColorSpace& color_space, + GLenum target, + GLuint texture_id) override; + scoped_refptr<gl::GLSurface> CreateViewGLSurface( + gl::GLDisplay* display, gfx::AcceleratedWidget widget) override; scoped_refptr<gl::GLSurface> CreateSurfacelessViewGLSurface( + gl::GLDisplay* display, gfx::AcceleratedWidget window) override; scoped_refptr<gl::GLSurface> CreateOffscreenGLSurface( + gl::GLDisplay* display, const gfx::Size& size) override; protected: @@ -58,11 +76,29 @@ class GLOzoneEGLWayland : public GLOzoneEGL { bool LoadGLES2Bindings(const gl::GLImplementationParts& impl) override; private: - WaylandConnection* const connection_; - WaylandBufferManagerGpu* const buffer_manager_; + const raw_ptr<WaylandConnection> connection_; + const raw_ptr<WaylandBufferManagerGpu> buffer_manager_; }; +bool GLOzoneEGLWayland::CanImportNativePixmap() { + return gl::GLSurfaceEGL::GetGLDisplayEGL() + ->ext->b_EGL_EXT_image_dma_buf_import; +} + +std::unique_ptr<NativePixmapGLBinding> GLOzoneEGLWayland::ImportNativePixmap( + scoped_refptr<gfx::NativePixmap> pixmap, + gfx::BufferFormat plane_format, + gfx::BufferPlane plane, + gfx::Size plane_size, + const gfx::ColorSpace& color_space, + GLenum target, + GLuint texture_id) { + return NativePixmapEGLBinding::Create(pixmap, plane_format, plane, plane_size, + color_space, target, texture_id); +} + scoped_refptr<gl::GLSurface> GLOzoneEGLWayland::CreateViewGLSurface( + gl::GLDisplay* display, gfx::AcceleratedWidget widget) { // Only EGLGLES2 is supported with surfaceless view gl. if ((gl::GetGLImplementation() != gl::kGLImplementationEGLGLES2) || @@ -80,22 +116,23 @@ scoped_refptr<gl::GLSurface> GLOzoneEGLWayland::CreateViewGLSurface( if (!egl_window) return nullptr; return gl::InitializeGLSurface(new GLSurfaceWayland( - gl::GLSurfaceEGL::GetGLDisplayEGL(), std::move(egl_window), window)); + display->GetAs<gl::GLDisplayEGL>(), std::move(egl_window), window)); } scoped_refptr<gl::GLSurface> GLOzoneEGLWayland::CreateSurfacelessViewGLSurface( + gl::GLDisplay* display, gfx::AcceleratedWidget window) { if (gl::IsSoftwareGLImplementation(gl::GetGLImplementationParts())) { return gl::InitializeGLSurface( - base::MakeRefCounted<GLSurfaceEglReadbackWayland>(window, - buffer_manager_)); + base::MakeRefCounted<GLSurfaceEglReadbackWayland>( + display->GetAs<gl::GLDisplayEGL>(), window, buffer_manager_)); } else { #if defined(WAYLAND_GBM) // If there is a gbm device available, use surfaceless gl surface. if (!buffer_manager_->GetGbmDevice()) return nullptr; - return gl::InitializeGLSurface( - new GbmSurfacelessWayland(buffer_manager_, window)); + return gl::InitializeGLSurface(new GbmSurfacelessWayland( + display->GetAs<gl::GLDisplayEGL>(), buffer_manager_, window)); #else return nullptr; #endif @@ -103,14 +140,15 @@ scoped_refptr<gl::GLSurface> GLOzoneEGLWayland::CreateSurfacelessViewGLSurface( } scoped_refptr<gl::GLSurface> GLOzoneEGLWayland::CreateOffscreenGLSurface( + gl::GLDisplay* display, const gfx::Size& size) { - if (gl::GLSurfaceEGL::GetGLDisplayEGL()->IsEGLSurfacelessContextSupported() && + if (display->GetAs<gl::GLDisplayEGL>()->IsEGLSurfacelessContextSupported() && size.width() == 0 && size.height() == 0) { return gl::InitializeGLSurface( - new gl::SurfacelessEGL(gl::GLSurfaceEGL::GetGLDisplayEGL(), size)); + new gl::SurfacelessEGL(display->GetAs<gl::GLDisplayEGL>(), size)); } else { return gl::InitializeGLSurface( - new gl::PbufferGLSurfaceEGL(gl::GLSurfaceEGL::GetGLDisplayEGL(), size)); + new gl::PbufferGLSurfaceEGL(display->GetAs<gl::GLDisplayEGL>(), size)); } } 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 61666835c59..c1daea1c6a1 100644 --- a/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory.h +++ b/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_factory.h @@ -7,6 +7,7 @@ #include <memory> +#include "base/memory/raw_ptr.h" #include "base/memory/ref_counted.h" #include "base/task/single_thread_task_runner.h" #include "base/threading/sequenced_task_runner_handle.h" @@ -61,8 +62,8 @@ class WaylandSurfaceFactory : public SurfaceFactoryOzone { bool SupportsNativePixmaps() const; private: - WaylandConnection* const connection_; - WaylandBufferManagerGpu* const buffer_manager_; + const raw_ptr<WaylandConnection> connection_; + const raw_ptr<WaylandBufferManagerGpu> buffer_manager_; std::unique_ptr<GLOzone> egl_implementation_; }; 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 b4fcc3a1da9..6b5aa5cefeb 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 @@ -23,6 +23,7 @@ #include "ui/gfx/overlay_plane_data.h" #include "ui/gfx/overlay_priority_hint.h" #include "ui/gl/gl_image_egl.h" +#include "ui/gl/gl_utils.h" #include "ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h" #include "ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.h" #include "ui/ozone/platform/wayland/gpu/wayland_surface_factory.h" @@ -180,8 +181,8 @@ class WaylandSurfaceFactoryTest : public WaylandTest { WaylandTest::SetUp(); - window_->set_update_visual_size_immediately(false); - window_->set_apply_pending_state_on_update_visual_size(false); + window_->set_update_visual_size_immediately_for_testing(false); + window_->set_apply_pending_state_on_update_visual_size_for_testing(false); auto manager_ptr = connection_->buffer_manager_host()->BindInterface(); buffer_manager_gpu_->Initialize( @@ -214,12 +215,12 @@ class WaylandSurfaceFactoryTest : public WaylandTest { int z_order) { gl_surface->ScheduleOverlayPlane( image, nullptr, - gfx::OverlayPlaneData( - z_order, gfx::OverlayTransform::OVERLAY_TRANSFORM_NONE, - gfx::RectF(window_->GetBoundsInPixels()), {}, false, - gfx::Rect(window_->GetBoundsInPixels().size()), 1.0f, - gfx::OverlayPriorityHint::kNone, gfx::RRectF(), - gfx::ColorSpace::CreateSRGB(), absl::nullopt)); + gfx::OverlayPlaneData(z_order, + gfx::OverlayTransform::OVERLAY_TRANSFORM_NONE, + gfx::RectF(window_->GetBoundsInPixels()), {}, + false, gfx::Rect(window_->size_px()), 1.0f, + gfx::OverlayPriorityHint::kNone, gfx::RRectF(), + gfx::ColorSpace::CreateSRGB(), absl::nullopt)); } }; @@ -237,7 +238,8 @@ TEST_P(WaylandSurfaceFactoryTest, auto* gl_ozone = surface_factory_->GetGLOzone( gl::GLImplementationParts(gl::kGLImplementationEGLGLES2)); - auto gl_surface = gl_ozone->CreateSurfacelessViewGLSurface(widget_); + auto gl_surface = gl_ozone->CreateSurfacelessViewGLSurface( + gl::GetDefaultDisplay(), widget_); EXPECT_TRUE(gl_surface); gl_surface->SetRelyOnImplicitSync(); static_cast<ui::GbmSurfacelessWayland*>(gl_surface.get()) @@ -250,10 +252,10 @@ TEST_P(WaylandSurfaceFactoryTest, std::vector<scoped_refptr<FakeGLImageNativePixmap>> fake_gl_image; for (int i = 0; i < 4; ++i) { auto native_pixmap = surface_factory_->CreateNativePixmap( - widget_, nullptr, window_->GetBoundsInPixels().size(), - gfx::BufferFormat::BGRA_8888, gfx::BufferUsage::SCANOUT); + widget_, nullptr, window_->size_px(), gfx::BufferFormat::BGRA_8888, + gfx::BufferUsage::SCANOUT); fake_gl_image.push_back(base::MakeRefCounted<FakeGLImageNativePixmap>( - native_pixmap, window_->GetBoundsInPixels().size())); + native_pixmap, window_->size_px())); } auto* root_surface = server_.GetObject<wl::MockSurface>( @@ -529,7 +531,8 @@ TEST_P(WaylandSurfaceFactoryTest, auto* gl_ozone = surface_factory_->GetGLOzone( gl::GLImplementationParts(gl::kGLImplementationEGLGLES2)); - auto gl_surface = gl_ozone->CreateSurfacelessViewGLSurface(widget_); + auto gl_surface = gl_ozone->CreateSurfacelessViewGLSurface( + gl::GetDefaultDisplay(), widget_); EXPECT_TRUE(gl_surface); gl_surface->SetRelyOnImplicitSync(); static_cast<ui::GbmSurfacelessWayland*>(gl_surface.get()) @@ -539,10 +542,10 @@ TEST_P(WaylandSurfaceFactoryTest, std::vector<scoped_refptr<FakeGLImageNativePixmap>> fake_gl_image; for (int i = 0; i < 5; ++i) { auto native_pixmap = surface_factory_->CreateNativePixmap( - widget_, nullptr, window_->GetBoundsInPixels().size(), - gfx::BufferFormat::BGRA_8888, gfx::BufferUsage::SCANOUT); + widget_, nullptr, window_->size_px(), gfx::BufferFormat::BGRA_8888, + gfx::BufferUsage::SCANOUT); fake_gl_image.push_back(base::MakeRefCounted<FakeGLImageNativePixmap>( - native_pixmap, window_->GetBoundsInPixels().size())); + native_pixmap, window_->size_px())); } auto* root_surface = server_.GetObject<wl::MockSurface>( @@ -785,7 +788,7 @@ TEST_P(WaylandSurfaceFactoryTest, Canvas) { auto canvas = CreateCanvas(widget_); ASSERT_TRUE(canvas); - auto bounds_px = window_->GetBoundsInPixels(); + auto bounds_px = window_->GetBoundsInDIP(); bounds_px = gfx::ScaleToRoundedRect(bounds_px, scale_factor); canvas->ResizeCanvas(bounds_px.size(), scale_factor); @@ -827,7 +830,7 @@ TEST_P(WaylandSurfaceFactoryTest, CanvasResize) { auto canvas = CreateCanvas(widget_); ASSERT_TRUE(canvas); - canvas->ResizeCanvas(window_->GetBoundsInPixels().size(), 1); + canvas->ResizeCanvas(window_->GetBoundsInDIP().size(), 1); auto* sk_canvas = canvas->GetCanvas(); DCHECK(sk_canvas); canvas->ResizeCanvas(gfx::Size(100, 50), 1); @@ -864,7 +867,8 @@ TEST_P(WaylandSurfaceFactoryTest, CreateSurfaceCheckGbm) { auto* gl_ozone = surface_factory_->GetGLOzone( gl::GLImplementationParts(gl::kGLImplementationEGLGLES2)); EXPECT_TRUE(gl_ozone); - auto gl_surface = gl_ozone->CreateSurfacelessViewGLSurface(widget_); + auto gl_surface = gl_ozone->CreateSurfacelessViewGLSurface( + gl::GetDefaultDisplay(), widget_); EXPECT_FALSE(gl_surface); // Now, set gbm. @@ -872,20 +876,23 @@ TEST_P(WaylandSurfaceFactoryTest, CreateSurfaceCheckGbm) { // It's still impossible to create the device if supports_dmabuf is false. EXPECT_FALSE(buffer_manager_gpu_->GetGbmDevice()); - gl_surface = gl_ozone->CreateSurfacelessViewGLSurface(widget_); + gl_surface = gl_ozone->CreateSurfacelessViewGLSurface(gl::GetDefaultDisplay(), + widget_); EXPECT_FALSE(gl_surface); // Now set supports_dmabuf. buffer_manager_gpu_->supports_dmabuf_ = true; EXPECT_TRUE(buffer_manager_gpu_->GetGbmDevice()); - gl_surface = gl_ozone->CreateSurfacelessViewGLSurface(widget_); + gl_surface = gl_ozone->CreateSurfacelessViewGLSurface(gl::GetDefaultDisplay(), + widget_); EXPECT_TRUE(gl_surface); // Reset gbm now. WaylandConnectionProxy can reset it when zwp is not // available. And factory must behave the same way as previously. buffer_manager_gpu_->gbm_device_ = nullptr; EXPECT_FALSE(buffer_manager_gpu_->GetGbmDevice()); - gl_surface = gl_ozone->CreateSurfacelessViewGLSurface(widget_); + gl_surface = gl_ozone->CreateSurfacelessViewGLSurface(gl::GetDefaultDisplay(), + widget_); EXPECT_FALSE(gl_surface); } @@ -904,7 +911,8 @@ TEST_P(WaylandSurfaceFactoryCompositorV3, SurfaceDamageTest) { auto* gl_ozone = surface_factory_->GetGLOzone( gl::GLImplementationParts(gl::kGLImplementationEGLGLES2)); - auto gl_surface = gl_ozone->CreateSurfacelessViewGLSurface(widget_); + auto gl_surface = gl_ozone->CreateSurfacelessViewGLSurface( + gl::GetDefaultDisplay(), widget_); EXPECT_TRUE(gl_surface); gl_surface->SetRelyOnImplicitSync(); static_cast<ui::GbmSurfacelessWayland*>(gl_surface.get()) @@ -920,8 +928,8 @@ TEST_P(WaylandSurfaceFactoryCompositorV3, SurfaceDamageTest) { gfx::RectF crop_uv = {0.1f, 0.2f, 0.5, 0.5f}; gfx::RectF expected_combined_uv = {0.2, 0.2, 0.8, 0.64}; gfx::Rect expected_surface_dmg = gfx::ToEnclosingRect( - gfx::ScaleRect(expected_combined_uv, window_->GetBoundsInPixels().width(), - window_->GetBoundsInPixels().height())); + gfx::ScaleRect(expected_combined_uv, window_->size_px().width(), + window_->size_px().height())); // Create buffers and FakeGlImageNativePixmap. std::vector<scoped_refptr<FakeGLImageNativePixmap>> fake_gl_image; diff --git a/chromium/ui/ozone/platform/wayland/host/DEPS b/chromium/ui/ozone/platform/wayland/host/DEPS index 7fcfe4fe54f..d4d7c78b672 100644 --- a/chromium/ui/ozone/platform/wayland/host/DEPS +++ b/chromium/ui/ozone/platform/wayland/host/DEPS @@ -3,6 +3,7 @@ include_rules = [ "+chromeos/crosapi/mojom", "+chromeos/crosapi/cpp/crosapi_constants.h", "+chromeos/startup/browser_init_params.h", + "+chromeos/startup/browser_params_proxy.h", "+chromeos/ui/base", # Common includes. diff --git a/chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.h b/chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.h index e3584086a76..bbbc1982a06 100644 --- a/chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.h +++ b/chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.h @@ -7,6 +7,7 @@ #include <memory> +#include "base/memory/raw_ptr.h" #include "ui/ozone/platform/wayland/common/wayland_object.h" #include "ui/ozone/platform/wayland/host/wayland_data_source.h" @@ -46,7 +47,7 @@ class GtkPrimarySelectionDeviceManager private: wl::Object<gtk_primary_selection_device_manager> device_manager_; - WaylandConnection* const connection_; + const raw_ptr<WaylandConnection> connection_; std::unique_ptr<GtkPrimarySelectionDevice> device_; }; diff --git a/chromium/ui/ozone/platform/wayland/host/linux_ui_delegate_wayland.cc b/chromium/ui/ozone/platform/wayland/host/linux_ui_delegate_wayland.cc index deb42335650..1c69d738480 100644 --- a/chromium/ui/ozone/platform/wayland/host/linux_ui_delegate_wayland.cc +++ b/chromium/ui/ozone/platform/wayland/host/linux_ui_delegate_wayland.cc @@ -7,7 +7,7 @@ #include <utility> #include "base/logging.h" -#include "ui/base/linux/linux_ui_delegate.h" +#include "ui/linux/linux_ui_delegate.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" diff --git a/chromium/ui/ozone/platform/wayland/host/linux_ui_delegate_wayland.h b/chromium/ui/ozone/platform/wayland/host/linux_ui_delegate_wayland.h index d0f3a68d989..beb0aecb69c 100644 --- a/chromium/ui/ozone/platform/wayland/host/linux_ui_delegate_wayland.h +++ b/chromium/ui/ozone/platform/wayland/host/linux_ui_delegate_wayland.h @@ -5,9 +5,10 @@ #ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_LINUX_UI_DELEGATE_WAYLAND_H_ #define UI_OZONE_PLATFORM_WAYLAND_HOST_LINUX_UI_DELEGATE_WAYLAND_H_ +#include "base/memory/raw_ptr.h" #include "base/memory/weak_ptr.h" -#include "ui/base/linux/linux_ui_delegate.h" #include "ui/gfx/native_widget_types.h" +#include "ui/linux/linux_ui_delegate.h" namespace ui { @@ -31,7 +32,7 @@ class LinuxUiDelegateWayland : public LinuxUiDelegate { void OnHandleForward(base::OnceCallback<void(std::string)> callback, const std::string& handle); - WaylandConnection* const connection_; + const raw_ptr<WaylandConnection> connection_; base::WeakPtrFactory<LinuxUiDelegateWayland> weak_factory_{this}; }; diff --git a/chromium/ui/ozone/platform/wayland/host/org_gnome_mutter_idle_monitor.h b/chromium/ui/ozone/platform/wayland/host/org_gnome_mutter_idle_monitor.h index 087efe4f2d6..f8a68af4286 100644 --- a/chromium/ui/ozone/platform/wayland/host/org_gnome_mutter_idle_monitor.h +++ b/chromium/ui/ozone/platform/wayland/host/org_gnome_mutter_idle_monitor.h @@ -5,6 +5,7 @@ #ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_ORG_GNOME_MUTTER_IDLE_MONITOR_H_ #define UI_OZONE_PLATFORM_WAYLAND_HOST_ORG_GNOME_MUTTER_IDLE_MONITOR_H_ +#include "base/memory/raw_ptr.h" #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" #include "base/threading/thread_checker.h" @@ -74,7 +75,7 @@ class OrgGnomeMutterIdleMonitor { scoped_refptr<dbus::Bus> bus_; scoped_refptr<base::SequencedTaskRunner> task_runner_; - dbus::ObjectProxy* proxy_ = nullptr; + raw_ptr<dbus::ObjectProxy> proxy_ = nullptr; THREAD_CHECKER(main_thread_checker_); diff --git a/chromium/ui/ozone/platform/wayland/host/org_kde_kwin_idle.h b/chromium/ui/ozone/platform/wayland/host/org_kde_kwin_idle.h index 7be8c268902..1b3e67c6e27 100644 --- a/chromium/ui/ozone/platform/wayland/host/org_kde_kwin_idle.h +++ b/chromium/ui/ozone/platform/wayland/host/org_kde_kwin_idle.h @@ -7,6 +7,7 @@ #include <memory> +#include "base/memory/raw_ptr.h" #include "base/time/time.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/ozone/platform/wayland/common/wayland_object.h" @@ -43,7 +44,7 @@ class OrgKdeKwinIdle : public wl::GlobalObjectRegistrar<OrgKdeKwinIdle> { // The actual idle timeout connection point. mutable std::unique_ptr<Timeout> idle_timeout_; - WaylandConnection* const connection_; + const raw_ptr<WaylandConnection> connection_; }; } // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/host/proxy/wayland_proxy.h b/chromium/ui/ozone/platform/wayland/host/proxy/wayland_proxy.h index 5f3246079f6..260b562e298 100644 --- a/chromium/ui/ozone/platform/wayland/host/proxy/wayland_proxy.h +++ b/chromium/ui/ozone/platform/wayland/host/proxy/wayland_proxy.h @@ -14,10 +14,13 @@ struct wl_display; struct wl_surface; namespace gfx { -class Rect; class Size; } // namespace gfx +namespace ui { +class WaylandWindow; +} + namespace wl { // A proxy interface to Ozone/Wayland that is used by input emulation. The @@ -42,6 +45,9 @@ class COMPONENT_EXPORT(WAYLAND_PROXY) WaylandProxy { virtual void OnWindowConfigured(gfx::AcceleratedWidget widget, bool is_configured) = 0; + // Invoked when an existing surface is assigned a role. + virtual void OnWindowRoleAssigned(gfx::AcceleratedWidget widget) = 0; + protected: virtual ~Delegate() = default; }; @@ -64,6 +70,9 @@ class COMPONENT_EXPORT(WAYLAND_PROXY) WaylandProxy { // Returns wl_surface that backs the |widget|. virtual wl_surface* GetWlSurfaceForAcceleratedWidget( gfx::AcceleratedWidget widget) = 0; + // Returns WaylandWindow backed by |widget|. + virtual ui::WaylandWindow* GetWaylandWindowForAcceleratedWidget( + gfx::AcceleratedWidget widget) = 0; // Creates and returns a shm based wl_buffer with |buffer_size|. The shared // memory is hold until DestroyShmForWlBuffer is called. @@ -72,16 +81,16 @@ class COMPONENT_EXPORT(WAYLAND_PROXY) WaylandProxy { // When this is called, |buffer| becomes invalid and mustn't be used any more. virtual void DestroyShmForWlBuffer(wl_buffer* buffer) = 0; - // Schedules display flush that dispatches pending events. + // Schedules display flush that dispatches pending requests. virtual void ScheduleDisplayFlush() = 0; + // Immediately flushes pending requests for testing. + virtual void FlushForTesting() = 0; + // Returns platform window type of a window backed by the |widget|. virtual ui::PlatformWindowType GetWindowType( gfx::AcceleratedWidget widget) = 0; - // Returns bounds in px of the window backed by |widget|. - virtual gfx::Rect GetWindowBounds(gfx::AcceleratedWidget widget) = 0; - virtual bool WindowHasPointerFocus(gfx::AcceleratedWidget widget) = 0; virtual bool WindowHasKeyboardFocus(gfx::AcceleratedWidget widget) = 0; diff --git a/chromium/ui/ozone/platform/wayland/host/proxy/wayland_proxy_impl.cc b/chromium/ui/ozone/platform/wayland/host/proxy/wayland_proxy_impl.cc index 23c34fc2d2d..01c594842ca 100644 --- a/chromium/ui/ozone/platform/wayland/host/proxy/wayland_proxy_impl.cc +++ b/chromium/ui/ozone/platform/wayland/host/proxy/wayland_proxy_impl.cc @@ -49,9 +49,17 @@ wl_surface* WaylandProxyImpl::GetWlSurfaceForAcceleratedWidget( return window->root_surface()->surface(); } +ui::WaylandWindow* WaylandProxyImpl::GetWaylandWindowForAcceleratedWidget( + gfx::AcceleratedWidget widget) { + auto* window = connection_->wayland_window_manager()->GetWindow(widget); + DCHECK(window); + return window; +} + wl_buffer* WaylandProxyImpl::CreateShmBasedWlBuffer( const gfx::Size& buffer_size) { - ui::WaylandShmBuffer shm_buffer(connection_->shm(), buffer_size); + ui::WaylandShmBuffer shm_buffer(connection_->wayland_buffer_factory(), + buffer_size); auto* wlbuffer = shm_buffer.get(); DCHECK(wlbuffer); shm_buffers_.emplace_back(std::move(shm_buffer)); @@ -70,6 +78,10 @@ void WaylandProxyImpl::ScheduleDisplayFlush() { connection_->ScheduleFlush(); } +void WaylandProxyImpl::FlushForTesting() { + connection_->Flush(); +} + ui::PlatformWindowType WaylandProxyImpl::GetWindowType( gfx::AcceleratedWidget widget) { auto* window = connection_->wayland_window_manager()->GetWindow(widget); @@ -77,22 +89,16 @@ ui::PlatformWindowType WaylandProxyImpl::GetWindowType( return window->type(); } -gfx::Rect WaylandProxyImpl::GetWindowBounds(gfx::AcceleratedWidget widget) { - auto* window = connection_->wayland_window_manager()->GetWindow(widget); - DCHECK(window); - return window->GetBoundsInPixels(); -} - bool WaylandProxyImpl::WindowHasPointerFocus(gfx::AcceleratedWidget widget) { auto* window = connection_->wayland_window_manager()->GetWindow(widget); DCHECK(window); - return window->has_pointer_focus(); + return window->HasPointerFocus(); } bool WaylandProxyImpl::WindowHasKeyboardFocus(gfx::AcceleratedWidget widget) { auto* window = connection_->wayland_window_manager()->GetWindow(widget); DCHECK(window); - return window->has_keyboard_focus(); + return window->HasKeyboardFocus(); } void WaylandProxyImpl::OnWindowAdded(ui::WaylandWindow* window) { @@ -111,4 +117,9 @@ void WaylandProxyImpl::OnWindowConfigured(ui::WaylandWindow* window) { window->IsSurfaceConfigured()); } +void WaylandProxyImpl::OnWindowRoleAssigned(ui::WaylandWindow* window) { + DCHECK(delegate_); + delegate_->OnWindowRoleAssigned(window->GetWidget()); +} + } // namespace wl diff --git a/chromium/ui/ozone/platform/wayland/host/proxy/wayland_proxy_impl.h b/chromium/ui/ozone/platform/wayland/host/proxy/wayland_proxy_impl.h index cf5ee8b568d..c1fb56dbd53 100644 --- a/chromium/ui/ozone/platform/wayland/host/proxy/wayland_proxy_impl.h +++ b/chromium/ui/ozone/platform/wayland/host/proxy/wayland_proxy_impl.h @@ -7,12 +7,14 @@ #include <vector> +#include "base/memory/raw_ptr.h" #include "ui/ozone/platform/wayland/host/proxy/wayland_proxy.h" #include "ui/ozone/platform/wayland/host/wayland_window_observer.h" namespace ui { class WaylandConnection; class WaylandShmBuffer; +class WaylandWindow; } // namespace ui namespace wl { @@ -29,11 +31,13 @@ class WaylandProxyImpl : public WaylandProxy, public ui::WaylandWindowObserver { void RoundTripQueue() override; wl_surface* GetWlSurfaceForAcceleratedWidget( gfx::AcceleratedWidget widget) override; + ui::WaylandWindow* GetWaylandWindowForAcceleratedWidget( + gfx::AcceleratedWidget widget) override; wl_buffer* CreateShmBasedWlBuffer(const gfx::Size& buffer_size) override; void DestroyShmForWlBuffer(wl_buffer* buffer) override; void ScheduleDisplayFlush() override; + void FlushForTesting() override; ui::PlatformWindowType GetWindowType(gfx::AcceleratedWidget widget) override; - gfx::Rect GetWindowBounds(gfx::AcceleratedWidget widget) override; bool WindowHasPointerFocus(gfx::AcceleratedWidget widget) override; bool WindowHasKeyboardFocus(gfx::AcceleratedWidget widget) override; @@ -42,10 +46,11 @@ class WaylandProxyImpl : public WaylandProxy, public ui::WaylandWindowObserver { void OnWindowAdded(ui::WaylandWindow* window) override; void OnWindowRemoved(ui::WaylandWindow* window) override; void OnWindowConfigured(ui::WaylandWindow* window) override; + void OnWindowRoleAssigned(ui::WaylandWindow* window) override; - ui::WaylandConnection* const connection_; + const raw_ptr<ui::WaylandConnection> connection_; - WaylandProxy::Delegate* delegate_ = nullptr; + raw_ptr<WaylandProxy::Delegate> delegate_ = nullptr; std::vector<ui::WaylandShmBuffer> shm_buffers_; }; 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 9cce96699b5..4637acdfff4 100644 --- a/chromium/ui/ozone/platform/wayland/host/shell_popup_wrapper.h +++ b/chromium/ui/ozone/platform/wayland/host/shell_popup_wrapper.h @@ -61,6 +61,13 @@ class ShellPopupWrapper { OwnedWindowAnchorGravity* anchor_gravity, OwnedWindowConstraintAdjustment* constraints) const; + // Whether the protocol supports surface decoration. + virtual bool SupportsDecoration() = 0; + + // Must only be called if SupportsDecoration() returns true. + // Decorates the surface with a drop shadow. + virtual void Decorate() = 0; + protected: // Asks the compositor to take explicit-grab for this popup. virtual void Grab(uint32_t serial) = 0; diff --git a/chromium/ui/ozone/platform/wayland/host/shell_toplevel_wrapper.h b/chromium/ui/ozone/platform/wayland/host/shell_toplevel_wrapper.h index 76a9dfe3e3f..6fecb34f55f 100644 --- a/chromium/ui/ozone/platform/wayland/host/shell_toplevel_wrapper.h +++ b/chromium/ui/ozone/platform/wayland/host/shell_toplevel_wrapper.h @@ -17,6 +17,7 @@ class Rect; namespace ui { class WaylandConnection; +enum class ZOrderLevel; // A wrapper around different versions of xdg toplevels. Allows // WaylandToplevelWindow to set window-like properties such as maximize, @@ -127,6 +128,14 @@ class ShellToplevelWrapper { // Enables screen coordinates support. This is no-op if the server does not // support the screen coordinates. virtual void EnableScreenCoordinates() = 0; + + // Sets/usets a native window to float state. This places it on top of other + // windows. + virtual void SetFloat() = 0; + virtual void UnSetFloat() = 0; + + // Sets the z order of the window. + virtual void SetZOrder(ZOrderLevel z_order) = 0; }; // Look for |value| in |wl_array| in C++ style. diff --git a/chromium/ui/ozone/platform/wayland/host/surface_augmenter.cc b/chromium/ui/ozone/platform/wayland/host/surface_augmenter.cc index 8dffa9802d5..e04604dfd37 100644 --- a/chromium/ui/ozone/platform/wayland/host/surface_augmenter.cc +++ b/chromium/ui/ozone/platform/wayland/host/surface_augmenter.cc @@ -75,7 +75,7 @@ wl::Object<augmented_sub_surface> SurfaceAugmenter::CreateAugmentedSubSurface( } wl::Object<wl_buffer> SurfaceAugmenter::CreateSolidColorBuffer( - SkColor color, + const SkColor4f& color, const gfx::Size& size) { wl_array color_data; wl_array_init(&color_data); diff --git a/chromium/ui/ozone/platform/wayland/host/surface_augmenter.h b/chromium/ui/ozone/platform/wayland/host/surface_augmenter.h index bdb3ccf91f8..2c1502ad9db 100644 --- a/chromium/ui/ozone/platform/wayland/host/surface_augmenter.h +++ b/chromium/ui/ozone/platform/wayland/host/surface_augmenter.h @@ -42,7 +42,7 @@ class SurfaceAugmenter : public wl::GlobalObjectRegistrar<SurfaceAugmenter> { wl::Object<augmented_sub_surface> CreateAugmentedSubSurface( wl_subsurface* subsurface); - wl::Object<wl_buffer> CreateSolidColorBuffer(SkColor color, + wl::Object<wl_buffer> CreateSolidColorBuffer(const SkColor4f& color, const gfx::Size& size); private: diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_buffer_backing.cc b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_backing.cc index b4a964b285b..f94f87b8fd0 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_buffer_backing.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_backing.cc @@ -12,8 +12,12 @@ namespace ui { WaylandBufferBacking::WaylandBufferBacking(const WaylandConnection* connection, uint32_t buffer_id, - const gfx::Size& size) - : connection_(connection), buffer_id_(buffer_id), size_(size) { + const gfx::Size& size, + uint32_t format) + : connection_(connection), + format_(format), + buffer_id_(buffer_id), + size_(size) { DCHECK(connection_); DCHECK_NE(buffer_id_, kInvalidBufferId); } diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_buffer_backing.h b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_backing.h index 59cfd268f0b..96231ac912e 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_buffer_backing.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_backing.h @@ -7,6 +7,8 @@ #include "base/callback_forward.h" #include "base/containers/flat_map.h" +#include "base/memory/raw_ptr.h" +#include "drm_fourcc.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/native_widget_types.h" #include "ui/ozone/platform/wayland/common/wayland_object.h" @@ -30,9 +32,12 @@ class WaylandBufferBacking { WaylandBufferBacking& operator=(const WaylandBufferBacking&) = delete; WaylandBufferBacking(const WaylandConnection* connection, uint32_t buffer_id, - const gfx::Size& size); + const gfx::Size& size, + uint32_t format = DRM_FORMAT_INVALID); virtual ~WaylandBufferBacking(); + const WaylandConnection* connection() const { return connection_; } + uint32_t format() const { return format_; } uint32_t id() const { return buffer_id_; } gfx::Size size() const { return size_; } @@ -48,11 +53,13 @@ class WaylandBufferBacking { // Same as above but does not do the requesting. WaylandBufferHandle* GetBufferHandle(WaylandSurface* requestor); - protected: + private: // Non-owned pointer to the main connection. - const WaylandConnection* connection_; + raw_ptr<const WaylandConnection> connection_; + + // DRM buffer format if specified, otherwise DRM_FORMAT_INVALID (0) + const uint32_t format_; - private: // Requests a new wl_buffer. |callback| will be run with the created wl_buffer // object when creation is complete. virtual void RequestBufferHandle( diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_buffer_backing_dmabuf.cc b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_backing_dmabuf.cc index d22fbb09f45..8d7d99bbbec 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_buffer_backing_dmabuf.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_backing_dmabuf.cc @@ -4,9 +4,8 @@ #include "ui/ozone/platform/wayland/host/wayland_buffer_backing_dmabuf.h" +#include "ui/ozone/platform/wayland/host/wayland_buffer_factory.h" #include "ui/ozone/platform/wayland/host/wayland_connection.h" -#include "ui/ozone/platform/wayland/host/wayland_drm.h" -#include "ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.h" namespace ui { @@ -20,12 +19,11 @@ WaylandBufferBackingDmabuf::WaylandBufferBackingDmabuf( uint32_t format, uint32_t planes_count, uint32_t buffer_id) - : WaylandBufferBacking(connection, buffer_id, size), + : WaylandBufferBacking(connection, buffer_id, size, format), fd_(std::move(fd)), strides_(std::move(strides)), offsets_(std::move(offsets)), modifiers_(std::move(modifiers)), - format_(format), planes_count_(planes_count) {} WaylandBufferBackingDmabuf::~WaylandBufferBackingDmabuf() = default; @@ -34,19 +32,9 @@ void WaylandBufferBackingDmabuf::RequestBufferHandle( base::OnceCallback<void(wl::Object<wl_buffer>)> callback) { DCHECK(!callback.is_null()); DCHECK(fd_.is_valid()); - if (connection_->zwp_dmabuf()) { - connection_->zwp_dmabuf()->CreateBuffer(fd_, size(), strides_, offsets_, - modifiers_, format_, planes_count_, - std::move(callback)); - } else if (connection_->drm()) { - connection_->drm()->CreateBuffer(fd_, size(), strides_, offsets_, - modifiers_, format_, planes_count_, - std::move(callback)); - } else { - // This method must never be called if neither zwp_linux_dmabuf or wl_drm - // are supported. - NOTREACHED(); - } + connection()->wayland_buffer_factory()->CreateDmabufBuffer( + fd_, size(), strides_, offsets_, modifiers_, format(), planes_count_, + std::move(callback)); if (UseExplicitSyncRelease()) auto close = std::move(fd_); diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_buffer_backing_dmabuf.h b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_backing_dmabuf.h index 2d524acac00..e86f029c190 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_buffer_backing_dmabuf.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_backing_dmabuf.h @@ -37,7 +37,6 @@ class WaylandBufferBackingDmabuf : public WaylandBufferBacking { const std::vector<uint32_t> strides_; const std::vector<uint32_t> offsets_; const std::vector<uint64_t> modifiers_; - const uint32_t format_; const uint32_t planes_count_; }; diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_buffer_backing_shm.cc b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_backing_shm.cc index 43f7d2592ca..e6dc7d65c7e 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_buffer_backing_shm.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_backing_shm.cc @@ -5,8 +5,8 @@ #include "ui/ozone/platform/wayland/host/wayland_buffer_backing_shm.h" #include "build/chromeos_buildflags.h" +#include "ui/ozone/platform/wayland/host/wayland_buffer_factory.h" #include "ui/ozone/platform/wayland/host/wayland_connection.h" -#include "ui/ozone/platform/wayland/host/wayland_shm.h" namespace ui { @@ -39,8 +39,9 @@ void WaylandBufferBackingShm::RequestBufferHandle( #else const bool with_alpha_channel = true; #endif - std::move(callback).Run(connection_->shm()->CreateBuffer(fd_, length_, size(), - with_alpha_channel)); + std::move(callback).Run( + connection()->wayland_buffer_factory()->CreateShmBuffer( + fd_, length_, size(), with_alpha_channel)); if (UseExplicitSyncRelease()) auto close = std::move(fd_); } diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_buffer_backing_solid_color.cc b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_backing_solid_color.cc index 4c83a4ed9ad..bcc77a254e1 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_buffer_backing_solid_color.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_backing_solid_color.cc @@ -11,7 +11,7 @@ namespace ui { WaylandBufferBackingSolidColor::WaylandBufferBackingSolidColor( const WaylandConnection* connection, - SkColor color, + SkColor4f color, const gfx::Size& size, uint32_t buffer_id) : WaylandBufferBacking(connection, buffer_id, size), color_(color) {} @@ -22,7 +22,8 @@ void WaylandBufferBackingSolidColor::RequestBufferHandle( base::OnceCallback<void(wl::Object<wl_buffer>)> callback) { DCHECK(!callback.is_null()); std::move(callback).Run( - connection_->surface_augmenter()->CreateSolidColorBuffer(color_, size())); + connection()->surface_augmenter()->CreateSolidColorBuffer(color_, + size())); } } // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_buffer_backing_solid_color.h b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_backing_solid_color.h index c0807885588..7ffe8948cad 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_buffer_backing_solid_color.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_backing_solid_color.h @@ -20,7 +20,7 @@ class WaylandBufferBackingSolidColor : public WaylandBufferBacking { WaylandBufferBackingSolidColor& operator=( const WaylandBufferBackingSolidColor&) = delete; WaylandBufferBackingSolidColor(const WaylandConnection* connection, - SkColor color, + SkColor4f color, const gfx::Size& size, uint32_t buffer_id); ~WaylandBufferBackingSolidColor() override; @@ -30,7 +30,7 @@ class WaylandBufferBackingSolidColor : public WaylandBufferBacking { void RequestBufferHandle( base::OnceCallback<void(wl::Object<wl_buffer>)> callback) override; - SkColor color_; + SkColor4f color_; }; } // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_buffer_factory.cc b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_factory.cc new file mode 100644 index 00000000000..bad5a26711c --- /dev/null +++ b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_factory.cc @@ -0,0 +1,82 @@ +// Copyright 2022 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_buffer_factory.h" + +#include <memory> + +#include "ui/ozone/platform/wayland/host/wayland_drm.h" +#include "ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.h" + +namespace ui { + +WaylandBufferFactory::WaylandBufferFactory() = default; + +WaylandBufferFactory::~WaylandBufferFactory() = default; + +void WaylandBufferFactory::CreateDmabufBuffer( + const base::ScopedFD& fd, + const gfx::Size& size, + const std::vector<uint32_t>& strides, + const std::vector<uint32_t>& offsets, + const std::vector<uint64_t>& modifiers, + uint32_t format, + uint32_t planes_count, + wl::OnRequestBufferCallback callback) const { + DCHECK(SupportsDmabuf()); + if (wayland_zwp_dmabuf_) { + wayland_zwp_dmabuf_->CreateBuffer(fd, size, strides, offsets, modifiers, + format, planes_count, + std::move(callback)); + } else if (wayland_drm_) { + wayland_drm_->CreateBuffer(fd, size, strides, offsets, modifiers, format, + planes_count, std::move(callback)); + } else { + // This method must never be called if neither zwp_linux_dmabuf or wl_drm + // are supported. + NOTREACHED(); + } +} + +wl::Object<struct wl_buffer> WaylandBufferFactory::CreateShmBuffer( + const base::ScopedFD& fd, + size_t length, + const gfx::Size& size, + bool with_alpha_channel) const { + if (UNLIKELY(!wayland_shm_)) + return {}; + return wayland_shm_->CreateBuffer(fd, length, size, with_alpha_channel); +} + +wl::BufferFormatsWithModifiersMap +WaylandBufferFactory::GetSupportedBufferFormats() const { +#if defined(WAYLAND_GBM) + if (wayland_zwp_dmabuf_) + return wayland_zwp_dmabuf_->supported_buffer_formats(); + else if (wayland_drm_) + return wayland_drm_->supported_buffer_formats(); +#endif + return {}; +} + +bool WaylandBufferFactory::SupportsDmabuf() const { +#if defined(WAYLAND_GBM) + return !!wayland_zwp_dmabuf_ || + (wayland_drm_ && wayland_drm_->SupportsDrmPrime()); +#else + return false; +#endif +} + +bool WaylandBufferFactory::CanCreateDmabufImmed() const { +#if defined(WAYLAND_GBM) + if (wayland_zwp_dmabuf_) + return wayland_zwp_dmabuf_->CanCreateBufferImmed(); + else if (wayland_drm_) + return wayland_drm_->CanCreateBufferImmed(); +#endif + return false; +} + +} // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_buffer_factory.h b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_factory.h new file mode 100644 index 00000000000..25b93f16e06 --- /dev/null +++ b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_factory.h @@ -0,0 +1,91 @@ +// Copyright 2022 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_BUFFER_FACTORY_H_ +#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_BUFFER_FACTORY_H_ + +#include <vector> + +#include "base/files/scoped_file.h" +#include "ui/ozone/platform/wayland/common/wayland_object.h" +#include "ui/ozone/platform/wayland/host/wayland_shm.h" + +namespace gfx { +class Size; +} // namespace gfx + +namespace ui { + +class WaylandDrm; +class WaylandZwpLinuxDmabuf; + +// A factory that wraps different wayland objects that are able to create +// wl_buffers. +class WaylandBufferFactory { + public: + WaylandBufferFactory(); + WaylandBufferFactory(const WaylandBufferFactory&) = delete; + WaylandBufferFactory& operator=(const WaylandBufferFactory&) = delete; + ~WaylandBufferFactory(); + + // Requests to create a wl_buffer backed by the dmabuf prime |fd| descriptor. + // The result is sent back via the |callback|. If buffer creation failed, + // nullptr is sent back via the callback. Otherwise, a pointer to the + // |wl_buffer| is sent. Depending on the result of |CanCreateDmabufImmed|, + // a buffer can be created immediately which means the callback will be fired + // immediately and the client will not have to wait until the buffer is + // created. + void CreateDmabufBuffer(const base::ScopedFD& fd, + const gfx::Size& size, + const std::vector<uint32_t>& strides, + const std::vector<uint32_t>& offsets, + const std::vector<uint64_t>& modifiers, + uint32_t format, + uint32_t planes_count, + wl::OnRequestBufferCallback callback) const; + + // Creates a wl_buffer based on shared memory handle with the specified + // |length| and |size|. Whereas |with_alpha_channel| indicates whether the + // buffer's color format should use or not the alpha channel. + // + // TODO(crbug.com/1269044): Remove |with_alpha_channel| parameter once + // Exo-side Skia Renderer issue is fixed. + wl::Object<struct wl_buffer> CreateShmBuffer( + const base::ScopedFD& fd, + size_t length, + const gfx::Size& size, + bool with_alpha_channel = true) const; + + // Returns supported buffer formats received from the Wayland compositor. + wl::BufferFormatsWithModifiersMap GetSupportedBufferFormats() const; + + // Returns true if dmabuf is supported. + bool SupportsDmabuf() const; + + // Returns true if a dmabuf buffer can be created immediately. If not, a + // dmabuf backed buffer is created asynchronously. + bool CanCreateDmabufImmed() const; + + // Returns wl_shm. This has to be unfortunately exposed as + // WaylandCursorFactory uses wl_cursor_theme_load to load a cursor theme, + // which requires to pass the wl_shm object as a parameter when called. + wl_shm* shm() const { return wayland_shm_ ? wayland_shm_->get() : nullptr; } + + private: + // Exposed so that globals are able to create these objects when exist. + friend class WaylandDrm; + friend class WaylandShm; + friend class WaylandZwpLinuxDmabuf; + + // A wrapper around wl_drm. + std::unique_ptr<WaylandDrm> wayland_drm_; + // A wrapper around wl_shm. + std::unique_ptr<WaylandShm> wayland_shm_; + // A wrapper around zwp_linux_dmabuf. + std::unique_ptr<WaylandZwpLinuxDmabuf> wayland_zwp_dmabuf_; +}; + +} // namespace ui + +#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_BUFFER_FACTORY_H_ diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_buffer_handle.h b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_handle.h index f85c2ea304c..bfdc42dc82e 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_buffer_handle.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_handle.h @@ -7,6 +7,7 @@ #include "base/callback.h" #include "base/containers/flat_map.h" +#include "base/memory/raw_ptr.h" #include "base/memory/weak_ptr.h" #include "ui/gfx/gpu_fence_handle.h" #include "ui/gfx/native_widget_types.h" @@ -65,7 +66,7 @@ class WaylandBufferHandle { // wl_buffer_listener: static void BufferRelease(void* data, struct wl_buffer* wl_buffer); - const WaylandBufferBacking* backing_; + raw_ptr<const WaylandBufferBacking> backing_; // A wl_buffer backed by the dmabuf/shm |backing_| created on the GPU side. wl::Object<struct wl_buffer> wl_buffer_; diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_connector.h b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_connector.h index a08e874fac9..469d1e9c83d 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_connector.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_manager_connector.h @@ -5,6 +5,7 @@ #ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_BUFFER_MANAGER_CONNECTOR_H_ #define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_BUFFER_MANAGER_CONNECTOR_H_ +#include "base/memory/raw_ptr.h" #include "ui/ozone/public/gpu_platform_support_host.h" #include "base/threading/thread_checker.h" @@ -41,7 +42,7 @@ class WaylandBufferManagerConnector : public GpuPlatformSupportHost { // Non-owned pointer, which is used to bind a mojo pointer to the // WaylandBufferManagerHost. - WaylandBufferManagerHost* const buffer_manager_host_; + const raw_ptr<WaylandBufferManagerHost> buffer_manager_host_; GpuHostBindInterfaceCallback binder_; GpuHostTerminateCallback terminate_callback_; 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 582c434557d..6409019f959 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 @@ -22,12 +22,10 @@ #include "ui/ozone/platform/wayland/host/wayland_buffer_backing_dmabuf.h" #include "ui/ozone/platform/wayland/host/wayland_buffer_backing_shm.h" #include "ui/ozone/platform/wayland/host/wayland_buffer_backing_solid_color.h" +#include "ui/ozone/platform/wayland/host/wayland_buffer_factory.h" #include "ui/ozone/platform/wayland/host/wayland_buffer_handle.h" #include "ui/ozone/platform/wayland/host/wayland_connection.h" -#include "ui/ozone/platform/wayland/host/wayland_drm.h" -#include "ui/ozone/platform/wayland/host/wayland_shm.h" #include "ui/ozone/platform/wayland/host/wayland_window.h" -#include "ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.h" namespace ui { @@ -75,18 +73,11 @@ void WaylandBufferManagerHost::OnChannelDestroyed() { wl::BufferFormatsWithModifiersMap WaylandBufferManagerHost::GetSupportedBufferFormats() const { -#if defined(WAYLAND_GBM) - if (connection_->zwp_dmabuf()) - return connection_->zwp_dmabuf()->supported_buffer_formats(); - else if (connection_->drm()) - return connection_->drm()->supported_buffer_formats(); -#endif - return {}; + return connection_->wayland_buffer_factory()->GetSupportedBufferFormats(); } bool WaylandBufferManagerHost::SupportsDmabuf() const { - return !!connection_->zwp_dmabuf() || - (connection_->drm() && connection_->drm()->SupportsDrmPrime()); + return connection_->wayland_buffer_factory()->SupportsDmabuf(); } bool WaylandBufferManagerHost::SupportsAcquireFence() const { @@ -189,7 +180,7 @@ void WaylandBufferManagerHost::CreateShmBasedBuffer(mojo::PlatformHandle shm_fd, } void WaylandBufferManagerHost::CreateSolidColorBuffer(const gfx::Size& size, - SkColor color, + const SkColor4f& color, uint32_t buffer_id) { DCHECK(base::CurrentUIThread::IsSet()); DCHECK(error_message_.empty()); @@ -254,6 +245,18 @@ WaylandBufferHandle* WaylandBufferManagerHost::GetBufferHandle( return it->second->GetBufferHandle(requestor); } +uint32_t WaylandBufferManagerHost::GetBufferFormat(WaylandSurface* requestor, + uint32_t buffer_id) { + DCHECK(base::CurrentUIThread::IsSet()); + DCHECK(requestor); + + auto it = buffer_backings_.find(buffer_id); + if (it == buffer_backings_.end()) + return DRM_FORMAT_INVALID; + + return it->second.get()->format(); +} + void WaylandBufferManagerHost::CommitOverlays( gfx::AcceleratedWidget widget, uint32_t frame_id, 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 3243f26aabe..0109078bc41 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 @@ -13,6 +13,7 @@ #include "base/containers/flat_map.h" #include "base/files/scoped_file.h" #include "base/gtest_prod_util.h" +#include "base/memory/raw_ptr.h" #include "mojo/public/cpp/bindings/associated_remote.h" #include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/cpp/bindings/remote.h" @@ -99,7 +100,7 @@ class WaylandBufferManagerHost : public ozone::mojom::WaylandBufferManagerHost { // ui/ozone/platform/wayland/mojom/wayland_buffer_manager.mojom. The // availability of this depends on existence of surface-augmenter protocol. void CreateSolidColorBuffer(const gfx::Size& size, - SkColor color, + const SkColor4f& color, uint32_t buffer_id) override; // Called by the GPU to destroy the imported wl_buffer with a |buffer_id|. @@ -121,6 +122,10 @@ class WaylandBufferManagerHost : public ozone::mojom::WaylandBufferManagerHost { WaylandBufferHandle* GetBufferHandle(WaylandSurface* requestor, uint32_t buffer_id); + // Gets the buffer format of |buffer_id| used for |requestor| if it is a + // DMA based buffer. + uint32_t GetBufferFormat(WaylandSurface* requestor, uint32_t buffer_id); + // Tells the |buffer_manager_gpu_ptr_| the result of a swap call and provides // it with the presentation feedback. void OnSubmission(gfx::AcceleratedWidget widget, @@ -158,7 +163,7 @@ class WaylandBufferManagerHost : public ozone::mojom::WaylandBufferManagerHost { std::string error_message_; // Non-owned pointer to the main connection. - WaylandConnection* const connection_; + const raw_ptr<WaylandConnection> connection_; mojo::AssociatedRemote<ozone::mojom::WaylandBufferManagerGpu> buffer_manager_gpu_associated_; diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.cc b/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.cc index b7fa2877766..855d8526d72 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.cc @@ -11,6 +11,7 @@ #include "base/bind.h" #include "base/check.h" #include "base/logging.h" +#include "base/memory/raw_ptr.h" #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" #include "base/notreached.h" @@ -189,7 +190,7 @@ class ClipboardImpl final : public Clipboard, public DataSource::Delegate { } // The device manager used to access data device and create data sources. - Manager* const manager_; + const raw_ptr<Manager> manager_; // The clipboard buffer managed by this |this|. const ui::ClipboardBuffer buffer_; @@ -203,7 +204,7 @@ class ClipboardImpl final : public Clipboard, public DataSource::Delegate { // Notifies when clipboard data changes. Can be empty if not set. ClipboardDataChangedCallback clipboard_changed_callback_; - ui::WaylandConnection* const connection_; + const raw_ptr<ui::WaylandConnection> connection_; base::WeakPtrFactory<ClipboardImpl> weak_factory_{this}; }; diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.h b/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.h index 3471f9a3468..fe68fc03850 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.h @@ -10,6 +10,7 @@ #include "base/callback.h" #include "base/gtest_prod_util.h" +#include "base/memory/raw_ptr.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" @@ -65,7 +66,7 @@ class WaylandClipboard : public PlatformClipboard { // WaylandConnection providing optional data device managers, e.g: gtk // primary selection. - WaylandConnection* const connection_; + const raw_ptr<WaylandConnection> connection_; 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 index 21fcd9b4b08..2c27d665ace 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_clipboard_unittest.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_clipboard_unittest.cc @@ -14,6 +14,7 @@ #include "base/callback_forward.h" #include "base/containers/flat_set.h" #include "base/location.h" +#include "base/memory/raw_ptr.h" #include "base/run_loop.h" #include "base/strings/utf_string_conversions.h" #include "base/task/thread_pool/thread_pool_instance.h" @@ -146,11 +147,11 @@ class WaylandClipboardTestBase : public WaylandTest { } /* Server objects */ - wl::MockPointer* pointer_; - wl::TestTouch* touch_; - wl::TestKeyboard* keyboard_; + raw_ptr<wl::MockPointer> pointer_; + raw_ptr<wl::TestTouch> touch_; + raw_ptr<wl::TestKeyboard> keyboard_; - WaylandClipboard* clipboard_ = nullptr; + raw_ptr<WaylandClipboard> clipboard_ = nullptr; uint32_t serial_ = 0; uint32_t timestamp_ = 0; diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_connection.cc b/chromium/ui/ozone/platform/wayland/host/wayland_connection.cc index 8e9b1d43b69..003c907f8e4 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_connection.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_connection.cc @@ -20,25 +20,22 @@ #include "base/strings/string_util.h" #include "base/task/current_thread.h" #include "base/threading/thread_task_runner_handle.h" -#include "base/time/time.h" #include "ui/events/devices/device_data_manager.h" #include "ui/events/devices/input_device.h" #include "ui/events/ozone/layout/keyboard_layout_engine_manager.h" #include "ui/gfx/geometry/point.h" #include "ui/ozone/common/features.h" -#include "ui/ozone/platform/wayland/common/wayland_object.h" #include "ui/ozone/platform/wayland/host/gtk_primary_selection_device_manager.h" #include "ui/ozone/platform/wayland/host/gtk_shell1.h" #include "ui/ozone/platform/wayland/host/org_kde_kwin_idle.h" #include "ui/ozone/platform/wayland/host/overlay_prioritizer.h" #include "ui/ozone/platform/wayland/host/proxy/wayland_proxy_impl.h" #include "ui/ozone/platform/wayland/host/surface_augmenter.h" +#include "ui/ozone/platform/wayland/host/wayland_buffer_factory.h" #include "ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h" -#include "ui/ozone/platform/wayland/host/wayland_clipboard.h" #include "ui/ozone/platform/wayland/host/wayland_cursor.h" #include "ui/ozone/platform/wayland/host/wayland_cursor_position.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_drm.h" #include "ui/ozone/platform/wayland/host/wayland_event_source.h" #include "ui/ozone/platform/wayland/host/wayland_input_method_context.h" @@ -50,12 +47,15 @@ #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/ozone/platform/wayland/host/wayland_zcr_color_management_output.h" +#include "ui/ozone/platform/wayland/host/wayland_zcr_color_manager.h" #include "ui/ozone/platform/wayland/host/wayland_zcr_cursor_shapes.h" #include "ui/ozone/platform/wayland/host/wayland_zcr_touchpad_haptics.h" #include "ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.h" #include "ui/ozone/platform/wayland/host/wayland_zwp_pointer_constraints.h" #include "ui/ozone/platform/wayland/host/wayland_zwp_pointer_gestures.h" #include "ui/ozone/platform/wayland/host/wayland_zwp_relative_pointer_manager.h" +#include "ui/ozone/platform/wayland/host/xdg_activation.h" #include "ui/ozone/platform/wayland/host/xdg_foreign_wrapper.h" #include "ui/ozone/platform/wayland/host/zwp_idle_inhibit_manager.h" #include "ui/ozone/platform/wayland/host/zwp_primary_selection_device_manager.h" @@ -76,12 +76,12 @@ namespace { // advertised by the server. constexpr uint32_t kMaxCompositorVersion = 4; constexpr uint32_t kMaxKeyboardExtensionVersion = 2; -constexpr uint32_t kMaxXdgShellVersion = 3; +constexpr uint32_t kMaxXdgShellVersion = 5; constexpr uint32_t kMaxZXdgShellVersion = 1; constexpr uint32_t kMaxWpPresentationVersion = 1; constexpr uint32_t kMaxWpViewporterVersion = 1; constexpr uint32_t kMaxTextInputManagerVersion = 1; -constexpr uint32_t kMaxTextInputExtensionVersion = 2; +constexpr uint32_t kMaxTextInputExtensionVersion = 5; constexpr uint32_t kMaxExplicitSyncVersion = 2; constexpr uint32_t kMaxAlphaCompositingVersion = 1; constexpr uint32_t kMaxXdgDecorationVersion = 1; @@ -183,6 +183,8 @@ bool WaylandConnection::Initialize() { &WaylandShm::Instantiate); RegisterGlobalObjectFactory(WaylandZAuraShell::kInterfaceName, &WaylandZAuraShell::Instantiate); + RegisterGlobalObjectFactory(WaylandZcrColorManager::kInterfaceName, + &WaylandZcrColorManager::Instantiate); RegisterGlobalObjectFactory(WaylandZcrCursorShapes::kInterfaceName, &WaylandZcrCursorShapes::Instantiate); RegisterGlobalObjectFactory(WaylandZcrTouchpadHaptics::kInterfaceName, @@ -195,6 +197,8 @@ bool WaylandConnection::Initialize() { &WaylandZwpPointerGestures::Instantiate); RegisterGlobalObjectFactory(WaylandZwpRelativePointerManager::kInterfaceName, &WaylandZwpRelativePointerManager::Instantiate); + RegisterGlobalObjectFactory(XdgActivation::kInterfaceName, + &XdgActivation::Instantiate); RegisterGlobalObjectFactory(XdgForeignWrapper::kInterfaceNameV1, &XdgForeignWrapper::Instantiate); RegisterGlobalObjectFactory(XdgForeignWrapper::kInterfaceNameV2, @@ -211,7 +215,7 @@ bool WaylandConnection::Initialize() { display_.reset(wl_display_connect(nullptr)); if (!display_) { - LOG(ERROR) << "Failed to connect to Wayland display"; + PLOG(ERROR) << "Failed to connect to Wayland display"; return false; } @@ -234,6 +238,10 @@ bool WaylandConnection::Initialize() { event_source_ = std::make_unique<WaylandEventSource>( display(), event_queue_.get(), wayland_window_manager(), this); + // Create the buffer factory before registry listener is set so that shm, drm, + // zwp_linux_dmabuf objects are able to be stored. + wayland_buffer_factory_ = std::make_unique<WaylandBufferFactory>(); + wl_registry_add_listener(registry_.get(), ®istry_listener, this); while (!wayland_output_manager_ || !wayland_output_manager_->IsOutputReady()) { @@ -246,7 +254,7 @@ bool WaylandConnection::Initialize() { LOG(ERROR) << "No wl_compositor object"; return false; } - if (!shm_) { + if (!wayland_buffer_factory()->shm()) { LOG(ERROR) << "No wl_shm object"; return false; } diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_connection.h b/chromium/ui/ozone/platform/wayland/host/wayland_connection.h index b89866d63e0..b45280eb9f3 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_connection.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_connection.h @@ -12,6 +12,7 @@ #include "base/callback_forward.h" #include "base/containers/flat_map.h" +#include "base/memory/raw_ptr.h" #include "base/time/time.h" #include "third_party/skia/include/core/SkBitmap.h" #include "ui/display/tablet_state.h" @@ -39,21 +40,20 @@ namespace ui { class DeviceHotplugEventObserver; class OrgKdeKwinIdle; class SurfaceAugmenter; +class WaylandBufferFactory; class WaylandBufferManagerHost; class WaylandCursor; class WaylandCursorBufferListener; -class WaylandDrm; class WaylandEventSource; class WaylandOutputManager; class WaylandSeat; -class WaylandShm; class WaylandZAuraShell; +class WaylandZcrColorManager; class WaylandZcrCursorShapes; class WaylandZcrTouchpadHaptics; class WaylandZwpPointerConstraints; class WaylandZwpPointerGestures; class WaylandZwpRelativePointerManager; -class WaylandZwpLinuxDmabuf; class WaylandDataDeviceManager; class WaylandCursorPosition; class WaylandWindowDragController; @@ -61,6 +61,7 @@ class GtkPrimarySelectionDeviceManager; class GtkShell1; class ZwpIdleInhibitManager; class ZwpPrimarySelectionDeviceManager; +class XdgActivation; class XdgForeignWrapper; class OverlayPrioritizer; @@ -95,6 +96,9 @@ class WaylandConnection { // Schedules a flush of the Wayland connection. void ScheduleFlush(); + // Immediately flushes. Public for testing. + void Flush(); + // Calls wl_display_roundtrip_queue. Might be required during initialization // of some objects that should block until they are initialized. void RoundTripQueue(); @@ -181,6 +185,10 @@ class WaylandConnection { WaylandZAuraShell* zaura_shell() const { return zaura_shell_.get(); } + WaylandZcrColorManager* zcr_color_manager() const { + return zcr_color_manager_.get(); + } + WaylandZcrCursorShapes* zcr_cursor_shapes() const { return zcr_cursor_shapes_.get(); } @@ -189,16 +197,14 @@ class WaylandConnection { return zcr_touchpad_haptics_.get(); } - WaylandZwpLinuxDmabuf* zwp_dmabuf() const { return zwp_dmabuf_.get(); } - - WaylandDrm* drm() const { return drm_.get(); } - - WaylandShm* shm() const { return shm_.get(); } - WaylandWindowManager* wayland_window_manager() { return &wayland_window_manager_; } + WaylandBufferFactory* wayland_buffer_factory() const { + return wayland_buffer_factory_.get(); + } + WaylandDataDeviceManager* data_device_manager() const { return data_device_manager_.get(); } @@ -238,6 +244,8 @@ class WaylandConnection { return wayland_zwp_relative_pointer_manager_.get(); } + const XdgActivation* xdg_activation() const { return xdg_activation_.get(); } + XdgForeignWrapper* xdg_foreign() const { return xdg_foreign_.get(); } ZwpIdleInhibitManager* zwp_idle_inhibit_manager() const { @@ -314,17 +322,16 @@ class WaylandConnection { friend class OverlayPrioritizer; friend class SurfaceAugmenter; friend class WaylandDataDeviceManager; - friend class WaylandDrm; friend class WaylandOutput; friend class WaylandSeat; - friend class WaylandShm; friend class WaylandZAuraShell; friend class WaylandZcrTouchpadHaptics; - friend class WaylandZwpLinuxDmabuf; friend class WaylandZwpPointerConstraints; friend class WaylandZwpPointerGestures; friend class WaylandZwpRelativePointerManager; + friend class WaylandZcrColorManager; friend class WaylandZcrCursorShapes; + friend class XdgActivation; friend class XdgForeignWrapper; friend class ZwpIdleInhibitManager; friend class ZwpPrimarySelectionDeviceManager; @@ -332,7 +339,6 @@ class WaylandConnection { void RegisterGlobalObjectFactory(const char* interface_name, wl::GlobalObjectFactory factory); - void Flush(); void UpdateInputDevices(); // Initialize data-related objects if required protocol objects are already @@ -391,11 +397,16 @@ class WaylandConnection { // outlives them so thus being able to properly handle their destruction. std::unique_ptr<WaylandEventSource> event_source_; + // Factory that wraps all the supported wayland objects that are provide + // capabilities to create wl_buffers. + std::unique_ptr<WaylandBufferFactory> wayland_buffer_factory_; + std::unique_ptr<WaylandCursor> cursor_; std::unique_ptr<WaylandDataDeviceManager> data_device_manager_; std::unique_ptr<WaylandOutputManager> wayland_output_manager_; std::unique_ptr<WaylandCursorPosition> wayland_cursor_position_; std::unique_ptr<WaylandZAuraShell> zaura_shell_; + std::unique_ptr<WaylandZcrColorManager> zcr_color_manager_; std::unique_ptr<WaylandZcrCursorShapes> zcr_cursor_shapes_; std::unique_ptr<WaylandZcrTouchpadHaptics> zcr_touchpad_haptics_; std::unique_ptr<WaylandZwpPointerConstraints> @@ -403,11 +414,9 @@ class WaylandConnection { std::unique_ptr<WaylandZwpRelativePointerManager> wayland_zwp_relative_pointer_manager_; std::unique_ptr<WaylandZwpPointerGestures> wayland_zwp_pointer_gestures_; - std::unique_ptr<WaylandZwpLinuxDmabuf> zwp_dmabuf_; - std::unique_ptr<WaylandDrm> drm_; std::unique_ptr<WaylandSeat> seat_; - std::unique_ptr<WaylandShm> shm_; std::unique_ptr<WaylandBufferManagerHost> buffer_manager_host_; + std::unique_ptr<XdgActivation> xdg_activation_; std::unique_ptr<XdgForeignWrapper> xdg_foreign_; std::unique_ptr<ZwpIdleInhibitManager> zwp_idle_inhibit_manager_; std::unique_ptr<OverlayPrioritizer> overlay_prioritizer_; @@ -438,7 +447,7 @@ class WaylandConnection { // created when platform window test config is set. std::unique_ptr<wl::WaylandProxy> wayland_proxy_; - WaylandCursorBufferListener* listener_ = nullptr; + raw_ptr<WaylandCursorBufferListener> listener_ = nullptr; // The current window table mode layout state. display::TabletState tablet_layout_state_ = diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_connection_test_api.h b/chromium/ui/ozone/platform/wayland/host/wayland_connection_test_api.h index 1013067cef6..8c53b70c63a 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_connection_test_api.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_connection_test_api.h @@ -8,6 +8,7 @@ #include <memory> #include <utility> +#include "base/memory/raw_ptr.h" #include "ui/ozone/platform/wayland/host/wayland_connection.h" #include "ui/ozone/platform/wayland/host/wayland_zcr_cursor_shapes.h" @@ -32,7 +33,7 @@ class WaylandConnectionTestApi { } private: - WaylandConnection* const impl_; + const raw_ptr<WaylandConnection> impl_; }; } // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_cursor.cc b/chromium/ui/ozone/platform/wayland/host/wayland_cursor.cc index f78e436d439..babf9c2d150 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_cursor.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_cursor.cc @@ -16,7 +16,6 @@ #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_serial_tracker.h" -#include "ui/ozone/platform/wayland/host/wayland_shm.h" namespace ui { @@ -38,7 +37,6 @@ void WaylandCursor::OnBufferRelease(void* data, wl_buffer* buffer) { void WaylandCursor::UpdateBitmap(const std::vector<SkBitmap>& cursor_image, const gfx::Point& hotspot_in_dips, int buffer_scale) { - DCHECK(connection_->shm()); if (!pointer_) return; @@ -50,7 +48,7 @@ void WaylandCursor::UpdateBitmap(const std::vector<SkBitmap>& cursor_image, return HideCursor(); gfx::Size image_size = gfx::SkISizeToSize(image.dimensions()); - WaylandShmBuffer buffer(connection_->shm(), image_size); + WaylandShmBuffer buffer(connection_->wayland_buffer_factory(), image_size); if (!buffer.IsValid()) { LOG(ERROR) << "Failed to create SHM buffer for Cursor Bitmap."; @@ -58,7 +56,8 @@ void WaylandCursor::UpdateBitmap(const std::vector<SkBitmap>& cursor_image, } buffer_scale_ = buffer_scale; - wl_surface_set_buffer_scale(pointer_surface_.get(), buffer_scale_); + if (!connection_->surface_submission_in_pixel_coordinates()) + wl_surface_set_buffer_scale(pointer_surface_.get(), buffer_scale_); static constexpr wl_buffer_listener wl_buffer_listener{ &WaylandCursor::OnBufferRelease}; @@ -86,7 +85,8 @@ void WaylandCursor::SetPlatformShape(wl_cursor* cursor_data, int buffer_scale) { buffer_scale_ = buffer_scale; current_image_index_ = 0; - wl_surface_set_buffer_scale(pointer_surface_.get(), buffer_scale_); + if (!connection_->surface_submission_in_pixel_coordinates()) + wl_surface_set_buffer_scale(pointer_surface_.get(), buffer_scale_); SetPlatformShapeInternal(); diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_cursor.h b/chromium/ui/ozone/platform/wayland/host/wayland_cursor.h index b07751fbddd..862b0a29a5b 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_cursor.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_cursor.h @@ -8,6 +8,7 @@ #include <vector> #include "base/containers/flat_map.h" +#include "base/memory/raw_ptr.h" #include "base/timer/timer.h" #include "third_party/skia/include/core/SkSurface.h" #include "ui/ozone/platform/wayland/common/wayland_object.h" @@ -88,16 +89,16 @@ class WaylandCursor { uint32_t hotspot_x_dip, uint32_t hotspot_y_dip); - WaylandPointer* const pointer_; - WaylandConnection* const connection_; + const raw_ptr<WaylandPointer> pointer_; + const raw_ptr<WaylandConnection> connection_; const wl::Object<wl_surface> pointer_surface_; // Holds the buffers and their memory until the compositor releases them. base::flat_map<wl_buffer*, WaylandShmBuffer> buffers_; - WaylandCursorBufferListener* listener_ = nullptr; + raw_ptr<WaylandCursorBufferListener> listener_ = nullptr; // Current platform cursor. - wl_cursor* cursor_data_ = nullptr; + raw_ptr<wl_cursor> cursor_data_ = nullptr; size_t current_image_index_ = 0; int buffer_scale_ = 1; base::RepeatingTimer animation_timer_; diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_cursor_factory.cc b/chromium/ui/ozone/platform/wayland/host/wayland_cursor_factory.cc index d72ff37b737..02e8a628a6f 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_cursor_factory.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_cursor_factory.cc @@ -13,8 +13,8 @@ #include "ui/base/cursor/platform_cursor.h" #include "ui/ozone/common/bitmap_cursor.h" #include "ui/ozone/common/bitmap_cursor_factory.h" +#include "ui/ozone/platform/wayland/host/wayland_buffer_factory.h" #include "ui/ozone/platform/wayland/host/wayland_connection.h" -#include "ui/ozone/platform/wayland/host/wayland_shm.h" namespace ui { @@ -45,9 +45,9 @@ WaylandCursorFactory::WaylandCursorFactory(WaylandConnection* connection) WaylandCursorFactory::~WaylandCursorFactory() = default; void WaylandCursorFactory::ObserveThemeChanges() { - auto* cursor_theme_manager = CursorThemeManager::GetInstance(); - DCHECK(cursor_theme_manager); - cursor_theme_observer_.Observe(cursor_theme_manager); + auto* linux_ui = LinuxUi::instance(); + DCHECK(linux_ui); + cursor_theme_observer_.Observe(linux_ui); } scoped_refptr<PlatformCursor> WaylandCursorFactory::GetDefaultCursor( @@ -146,7 +146,7 @@ void WaylandCursorFactory::ReloadThemeCursors() { FROM_HERE, {base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}, base::BindOnce(LoadCursorTheme, name_, size_, scale_, - connection_->shm()->get()), + connection_->wayland_buffer_factory()->shm()), base::BindOnce(&WaylandCursorFactory::OnThemeLoaded, weak_factory_.GetWeakPtr(), name_, size_)); } diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_cursor_factory.h b/chromium/ui/ozone/platform/wayland/host/wayland_cursor_factory.h index 8e4a97a6e29..9542bf4d656 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_cursor_factory.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_cursor_factory.h @@ -9,10 +9,11 @@ #include "base/containers/flat_map.h" #include "base/gtest_prod_util.h" +#include "base/memory/raw_ptr.h" #include "base/memory/scoped_refptr.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/linux/cursor_theme_manager_observer.h" +#include "ui/linux/linux_ui.h" #include "ui/ozone/common/bitmap_cursor_factory.h" #include "ui/ozone/platform/wayland/common/wayland_object.h" #include "ui/ozone/platform/wayland/host/wayland_cursor.h" @@ -70,9 +71,12 @@ class WaylandCursorFactory : public BitmapCursorFactory, int loaded_theme_size, wl_cursor_theme* loaded_theme); - WaylandConnection* const connection_; + const raw_ptr<WaylandConnection> connection_; - base::ScopedObservation<CursorThemeManager, CursorThemeManagerObserver> + base::ScopedObservation<LinuxUi, + CursorThemeManagerObserver, + &LinuxUi::AddCursorThemeObserver, + &LinuxUi::RemoveCursorThemeObserver> cursor_theme_observer_{this}; // Name of the current theme. 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 5f32a769eba..8186611a64b 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_data_device.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_device.h @@ -12,6 +12,7 @@ #include "base/callback.h" #include "base/files/scoped_file.h" #include "base/gtest_prod_util.h" +#include "base/memory/raw_ptr.h" #include "ui/ozone/platform/wayland/common/wayland_object.h" #include "ui/ozone/platform/wayland/host/wayland_data_device_base.h" #include "ui/ozone/platform/wayland/host/wayland_data_source.h" @@ -124,7 +125,7 @@ class WaylandDataDevice : public WaylandDataDeviceBase { // The wl_data_device wrapped by this WaylandDataDevice. wl::Object<wl_data_device> data_device_; - DragDelegate* drag_delegate_ = nullptr; + raw_ptr<DragDelegate> drag_delegate_ = nullptr; // There are two separate data offers at a time, the drag offer and the // selection offer, each with independent lifetimes. When we receive a new 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 eac004dc7c8..f59b679443e 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 @@ -9,6 +9,7 @@ #include "base/callback.h" #include "base/files/scoped_file.h" +#include "base/memory/raw_ptr.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" @@ -78,7 +79,7 @@ class WaylandDataDeviceBase { // Used to call out to WaylandConnection once clipboard data has been // successfully read. - WaylandConnection* const connection_; + const raw_ptr<WaylandConnection> 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_manager.h b/chromium/ui/ozone/platform/wayland/host/wayland_data_device_manager.h index fa6899c6a70..fdabde5cade 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_data_device_manager.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_device_manager.h @@ -7,6 +7,7 @@ #include <memory> +#include "base/memory/raw_ptr.h" #include "ui/ozone/platform/wayland/common/wayland_object.h" #include "ui/ozone/platform/wayland/host/wayland_data_source.h" @@ -42,7 +43,7 @@ class WaylandDataDeviceManager private: wl::Object<wl_data_device_manager> device_manager_; - WaylandConnection* const connection_; + const raw_ptr<WaylandConnection> connection_; std::unique_ptr<WaylandDataDevice> device_; }; 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 3472a5ed3b0..8733b4cf91a 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 @@ -220,7 +220,8 @@ void WaylandDataDragController::DrawIconInternal() { DCHECK(!icon_bitmap_->empty()); gfx::Size size(icon_bitmap_->width(), icon_bitmap_->height()); - icon_buffer_ = std::make_unique<WaylandShmBuffer>(connection_->shm(), size); + icon_buffer_ = std::make_unique<WaylandShmBuffer>( + connection_->wayland_buffer_factory(), size); if (!icon_buffer_->IsValid()) { LOG(ERROR) << "Failed to create drag icon buffer."; return; @@ -256,10 +257,12 @@ void WaylandDataDragController::OnDragEnter(WaylandWindow* window, if (pointer_grabber_for_window_drag_) { DCHECK(drag_source_.has_value()); - if (*drag_source_ == DragSource::kMouse) - pointer_delegate_->OnPointerFocusChanged(window, location); - else + if (*drag_source_ == DragSource::kMouse) { + pointer_delegate_->OnPointerFocusChanged( + window, location, wl::EventDispatchPolicy::kImmediate); + } else { touch_delegate_->OnTouchFocusChanged(window); + } pointer_grabber_for_window_drag_ = window_manager_->GetCurrentPointerOrTouchFocusedWindow(); 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 c0f824984f6..a341650e633 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 @@ -10,6 +10,7 @@ #include <string> #include "base/gtest_prod_util.h" +#include "base/memory/raw_ptr.h" #include "base/memory/weak_ptr.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/base/dragdrop/mojom/drag_drop_types.mojom-forward.h" @@ -177,12 +178,12 @@ class WaylandDataDragController : public WaylandDataDevice::DragDelegate, struct wl_callback* callback, uint32_t time); - WaylandConnection* const connection_; - WaylandDataDeviceManager* const data_device_manager_; - WaylandDataDevice* const data_device_; - WaylandWindowManager* const window_manager_; - WaylandPointer::Delegate* const pointer_delegate_; - WaylandTouch::Delegate* const touch_delegate_; + const raw_ptr<WaylandConnection> connection_; + const raw_ptr<WaylandDataDeviceManager> data_device_manager_; + const raw_ptr<WaylandDataDevice> data_device_; + const raw_ptr<WaylandWindowManager> window_manager_; + const raw_ptr<WaylandPointer::Delegate> pointer_delegate_; + const raw_ptr<WaylandTouch::Delegate> touch_delegate_; State state_ = State::kIdle; absl::optional<DragSource> drag_source_; @@ -207,10 +208,10 @@ class WaylandDataDragController : public WaylandDataDevice::DragDelegate, // The window that initiated the drag session. Can be null when the session // has been started by an external Wayland client. - WaylandWindow* origin_window_ = nullptr; + raw_ptr<WaylandWindow> origin_window_ = nullptr; // Current window under pointer. - WaylandWindow* window_ = nullptr; + raw_ptr<WaylandWindow> window_ = nullptr; // The most recent location received while dragging the data. gfx::PointF last_drag_location_; @@ -224,13 +225,13 @@ class WaylandDataDragController : public WaylandDataDevice::DragDelegate, // Drag icon related variables. std::unique_ptr<WaylandSurface> icon_surface_; std::unique_ptr<WaylandShmBuffer> icon_buffer_; - const SkBitmap* icon_bitmap_ = nullptr; + raw_ptr<const SkBitmap> icon_bitmap_ = nullptr; gfx::Point icon_offset_; wl::Object<wl_callback> icon_frame_callback_; // Keeps track of the window that holds the pointer grab, i.e. the window that // will receive the mouse release event from DispatchPointerRelease(). - WaylandWindow* pointer_grabber_for_window_drag_ = nullptr; + raw_ptr<WaylandWindow> pointer_grabber_for_window_drag_ = nullptr; std::unique_ptr<ScopedEventDispatcher> nested_dispatcher_; 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 b586e750eed..3dd10b81704 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 @@ -261,7 +261,6 @@ class WaylandDataDragControllerTest : public WaylandDragDropTest { }; TEST_P(WaylandDataDragControllerTest, StartDrag) { - const bool restored_focus = window_->has_pointer_focus(); FocusAndPressLeftPointerButton(window_.get(), &delegate_); auto test = [](WaylandDataDragControllerTest* self) { @@ -290,12 +289,9 @@ TEST_P(WaylandDataDragControllerTest, StartDrag) { // Ensure drag delegate it properly reset when the drag loop quits. EXPECT_FALSE(data_device()->drag_delegate_); - - window_->SetPointerFocus(restored_focus); } TEST_P(WaylandDataDragControllerTest, StartDragWithWrongMimeType) { - bool restored_focus = window_->has_pointer_focus(); FocusAndPressLeftPointerButton(window_.get(), &delegate_); // The client starts dragging offering data with |kMimeTypeHTML| @@ -319,7 +315,6 @@ TEST_P(WaylandDataDragControllerTest, StartDragWithWrongMimeType) { data_device_manager_->data_source()->ReadData(kMimeTypeText, std::move(callback)); run_loop.Run(); - window_->SetPointerFocus(restored_focus); } // Ensures data drag controller properly offers dragged data with custom @@ -328,7 +323,6 @@ TEST_P(WaylandDataDragControllerTest, StartDragWithWrongMimeType) { // - https://crbug.com/1207607 // - https://crbug.com/1247063 TEST_P(WaylandDataDragControllerTest, StartDragWithCustomFormats) { - bool restored_focus = window_->has_pointer_focus(); FocusAndPressLeftPointerButton(window_.get(), &delegate_); OSExchangeData data(OSExchangeDataProviderFactory::CreateProvider()); ClipboardFormatType kCustomFormats[] = { @@ -351,12 +345,9 @@ TEST_P(WaylandDataDragControllerTest, StartDragWithCustomFormats) { EXPECT_TRUE(base::Contains(mime_types, format.GetName())) << "Format '" << format.GetName() << "' should be offered."; } - - window_->SetPointerFocus(restored_focus); } TEST_P(WaylandDataDragControllerTest, StartDragWithText) { - bool restored_focus = window_->has_pointer_focus(); FocusAndPressLeftPointerButton(window_.get(), &delegate_); // The client starts dragging offering text mime type. @@ -381,11 +372,9 @@ TEST_P(WaylandDataDragControllerTest, StartDragWithText) { data_device_manager_->data_source()->ReadData(kMimeTypeMozillaURL, std::move(callback)); run_loop.Run(); - window_->SetPointerFocus(restored_focus); } TEST_P(WaylandDataDragControllerTest, StartDragWithFileContents) { - bool restored_focus = window_->has_pointer_focus(); FocusAndPressLeftPointerButton(window_.get(), &delegate_); // The client starts dragging offering text mime type. @@ -413,7 +402,6 @@ TEST_P(WaylandDataDragControllerTest, StartDragWithFileContents) { EXPECT_EQ(1u, data_device_manager_->data_source()->mime_types().size()); EXPECT_EQ("application/octet-stream;name=\"t\\\\est\\\".jpg\"", data_device_manager_->data_source()->mime_types().front()); - window_->SetPointerFocus(restored_focus); } MATCHER_P(PointFNear, n, "") { @@ -686,7 +674,6 @@ TEST_P(WaylandDataDragControllerTest, ValidateDroppedXMozUrl) { // Verifies the correct delegate functions are called when a drag session is // started and cancelled within the same surface. TEST_P(WaylandDataDragControllerTest, StartAndCancel) { - const bool restored_focus = window_->has_pointer_focus(); FocusAndPressLeftPointerButton(window_.get(), &delegate_); // Schedule a wl_data_source::cancelled event to be sent asynchronously @@ -694,8 +681,6 @@ TEST_P(WaylandDataDragControllerTest, StartAndCancel) { ScheduleDragCancel(); RunMouseDragWithSampleData(window_.get(), DragDropTypes::DRAG_COPY); - - window_->SetPointerFocus(restored_focus); } TEST_P(WaylandDataDragControllerTest, ForeignDragHandleAskAction) { @@ -736,7 +721,6 @@ TEST_P(WaylandDataDragControllerTest, ForeignDragHandleAskAction) { // 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(); FocusAndPressLeftPointerButton(window_1, &delegate_); ASSERT_EQ(PlatformWindowType::kWindow, window_1->type()); @@ -771,16 +755,14 @@ TEST_P(WaylandDataDragControllerTest, DestroyEnteredSurface) { ScheduleTestTask(base::BindOnce(test, base::Unretained(this))); RunMouseDragWithSampleData(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); + SetPointerFocusedWindow(nullptr); + ASSERT_EQ(PlatformWindowType::kWindow, window_1->type()); auto test = [](WaylandDataDragControllerTest* self, @@ -821,14 +803,11 @@ TEST_P(WaylandDataDragControllerTest, DestroyOriginSurface) { SendDndLeave(); SendDndCancelled(); Sync(); - - window_1->SetPointerFocus(restored_focus); } // 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(); FocusAndPressLeftPointerButton(origin_window, &delegate_); auto test = [](WaylandDataDragControllerTest* self, @@ -879,15 +858,12 @@ TEST_P(WaylandDataDragControllerTest, DragToNonToplevelWindows) { // Request to start the drag session, which spins a nested run loop. RunMouseDragWithSampleData(origin_window, DragDropTypes::DRAG_COPY); - - origin_window->SetPointerFocus(restored_focus); } // Ensures that requests to create a |PlatformWindowType::kPopup| during drag // sessions return xdg_popup-backed windows. TEST_P(WaylandDataDragControllerTest, PopupRequestCreatesPopupWindow) { auto* origin_window = window_.get(); - const bool restored_focus = origin_window->has_pointer_focus(); FocusAndPressLeftPointerButton(origin_window, &delegate_); std::unique_ptr<WaylandWindow> popup_window; @@ -913,15 +889,12 @@ TEST_P(WaylandDataDragControllerTest, PopupRequestCreatesPopupWindow) { auto* surface = GetMockSurface(popup_window->root_surface()->GetSurfaceId()); ASSERT_TRUE(surface); EXPECT_NE(nullptr, surface->xdg_surface()->xdg_popup()); - - 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(); FocusAndPressLeftPointerButton(origin_window, &delegate_); auto test = [](WaylandDataDragControllerTest* self, @@ -947,8 +920,6 @@ TEST_P(WaylandDataDragControllerTest, MenuRequestCreatesPopupWindow) { // Request to start the drag session, which spins a nested run loop. RunMouseDragWithSampleData(origin_window, DragDropTypes::DRAG_COPY); - - origin_window->SetPointerFocus(restored_focus); } // Regression test for https://crbug.com/1209269. @@ -962,7 +933,6 @@ TEST_P(WaylandDataDragControllerTest, MenuRequestCreatesPopupWindow) { // gracefully reset state and quit drag loop as if the drag session was // cancelled as usual. TEST_P(WaylandDataDragControllerTest, AsyncNoopStartDrag) { - const bool restored_focus = window_->has_pointer_focus(); OSExchangeData os_exchange_data; os_exchange_data.SetString(sample_text_for_dnd()); @@ -1011,14 +981,10 @@ TEST_P(WaylandDataDragControllerTest, AsyncNoopStartDrag) { Mock::VerifyAndClearExpectations(this); EXPECT_FALSE(drag_controller()->origin_window_); EXPECT_FALSE(drag_controller()->nested_dispatcher_); - - window_->SetPointerFocus(restored_focus); } // Regression test for https://crbug.com/1175083. TEST_P(WaylandDataDragControllerTest, StartDragWithCorrectSerial) { - const bool restored_focus = window_->has_pointer_focus(); - FocusAndPressLeftPointerButton(window_.get(), &delegate_); uint32_t mouse_press_serial = current_serial_; @@ -1047,15 +1013,11 @@ TEST_P(WaylandDataDragControllerTest, StartDragWithCorrectSerial) { RunMouseDragWithSampleData(window_.get(), DragDropTypes::DRAG_COPY); Mock::VerifyAndClearExpectations(drop_handler_.get()); Mock::VerifyAndClearExpectations(this); - - window_->SetPointerFocus(restored_focus); } // Check drag session is correctly started when there are both mouse button and // a touch point pressed. TEST_P(WaylandDataDragControllerTest, StartDragWithCorrectSerialForDragSource) { - const bool pointer_focus = window_->has_pointer_focus(); - const bool touch_focus = window_->has_touch_focus(); OSExchangeData os_exchange_data; os_exchange_data.SetString(sample_text_for_dnd()); @@ -1098,10 +1060,6 @@ TEST_P(WaylandDataDragControllerTest, StartDragWithCorrectSerialForDragSource) { EXPECT_TRUE(success); Mock::VerifyAndClearExpectations(drop_handler_.get()); Mock::VerifyAndClearExpectations(this); - - // Restore window's focus state. - window_->SetPointerFocus(pointer_focus); - window_->set_touch_focus(touch_focus); } INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest, diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_source.h b/chromium/ui/ozone/platform/wayland/host/wayland_data_source.h index 0311b369cd2..ef6e5e9b8a5 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_data_source.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_source.h @@ -9,6 +9,7 @@ #include <string> #include <vector> +#include "base/memory/raw_ptr.h" #include "base/notreached.h" #include "ui/ozone/platform/wayland/common/wayland_object.h" @@ -89,9 +90,9 @@ class DataSource { wl::Object<T> data_source_; - ui::WaylandConnection* const connection_; + const raw_ptr<ui::WaylandConnection> connection_; - Delegate* const delegate_; + const raw_ptr<Delegate> delegate_; // Action selected by the compositor uint32_t dnd_action_ = 0; diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_drm.cc b/chromium/ui/ozone/platform/wayland/host/wayland_drm.cc index 19401e812ae..12cd5656448 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_drm.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_drm.cc @@ -11,6 +11,7 @@ #include "base/logging.h" #include "ui/gfx/buffer_format_util.h" #include "ui/gfx/linux/drm_util_linux.h" +#include "ui/ozone/platform/wayland/host/wayland_buffer_factory.h" #include "ui/ozone/platform/wayland/host/wayland_connection.h" #include "ui/ozone/platform/wayland/host/wayland_drm.h" @@ -31,7 +32,8 @@ void WaylandDrm::Instantiate(WaylandConnection* connection, uint32_t version) { DCHECK_EQ(interface, kInterfaceName); - if (connection->drm_ || + auto* buffer_factory = connection->wayland_buffer_factory(); + if (buffer_factory->wayland_drm_ || !wl::CanBind(interface, version, kMinVersion, kMinVersion)) { return; } @@ -41,7 +43,8 @@ void WaylandDrm::Instantiate(WaylandConnection* connection, LOG(ERROR) << "Failed to bind wl_drm"; return; } - connection->drm_ = std::make_unique<WaylandDrm>(wl_drm.release(), connection); + buffer_factory->wayland_drm_ = + std::make_unique<WaylandDrm>(wl_drm.release(), connection); } WaylandDrm::WaylandDrm(wl_drm* drm, WaylandConnection* connection) @@ -92,6 +95,12 @@ void WaylandDrm::CreateBuffer(const base::ScopedFD& fd, std::move(callback).Run(std::move(buffer)); } +bool WaylandDrm::CanCreateBufferImmed() const { + // Unlike the WaylandZwpLinuxDmabuf, the WaylandDrm always creates wl_buffers + // immediately. + return true; +} + void WaylandDrm::HandleDrmFailure(const std::string& error) { LOG(WARNING) << error; wl_drm_.reset(); diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_drm.h b/chromium/ui/ozone/platform/wayland/host/wayland_drm.h index d292e1283d9..fcc98252555 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_drm.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_drm.h @@ -10,6 +10,7 @@ #include <vector> #include "base/files/scoped_file.h" +#include "base/memory/raw_ptr.h" #include "ui/ozone/platform/wayland/common/wayland_object.h" #include "ui/ozone/platform/wayland/common/wayland_util.h" @@ -64,6 +65,9 @@ class WaylandDrm : public wl::GlobalObjectRegistrar<WaylandDrm> { return supported_buffer_formats_; } + // Says if a new buffer can be created immediately. + bool CanCreateBufferImmed() const; + private: // Resets the |wl_drm| and prints the error. void HandleDrmFailure(const std::string& error); @@ -92,7 +96,7 @@ class WaylandDrm : public wl::GlobalObjectRegistrar<WaylandDrm> { wl::Object<wl_drm> wl_drm_; // Non-owned. - WaylandConnection* const connection_; + const raw_ptr<WaylandConnection> connection_; // Holds supported DRM formats translated to gfx::BufferFormat. Note that // |wl_drm| neither announces modifiers nor allows to create buffers with 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 a619b69b4cb..11acbefd60d 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_event_source.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_event_source.cc @@ -11,6 +11,7 @@ #include "base/check.h" #include "base/containers/cxx20_erase.h" #include "base/logging.h" +#include "base/memory/raw_ptr.h" #include "base/time/time.h" #include "build/chromeos_buildflags.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -28,6 +29,7 @@ #include "ui/gfx/geometry/point_f.h" #include "ui/gfx/geometry/vector2d_f.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_event_watcher.h" #include "ui/ozone/platform/wayland/host/wayland_keyboard.h" #include "ui/ozone/platform/wayland/host/wayland_window.h" @@ -48,11 +50,48 @@ std::vector<uint8_t> ToLittleEndianByteVector(uint32_t value) { static_cast<uint8_t>(value >> 16), static_cast<uint8_t>(value >> 24)}; } +EventTarget* GetRootTarget(EventTarget* target) { + EventTarget* parent = target->GetParentTarget(); + return parent ? GetRootTarget(parent) : target; +} + +gfx::Point GetOriginInScreen(WaylandWindow* target) { + // The origin for located events and positions of popup windows is the window + // geometry. + // See https://crbug.com/1292486 + gfx::Point origin = target->GetBoundsInDIP().origin() - + target->GetWindowGeometryOffsetInDIP(); + auto* parent = static_cast<WaylandWindow*>(target->GetParentTarget()); + while (parent) { + origin += parent->GetBoundsInDIP().origin().OffsetFromOrigin(); + parent = static_cast<WaylandWindow*>(parent->GetParentTarget()); + } + return origin; +} + +gfx::Point GetLocationInScreen(LocatedEvent* event) { + auto* root_window = + static_cast<WaylandWindow*>(GetRootTarget(event->target())); + return event->root_location() + + root_window->GetBoundsInDIP().origin().OffsetFromOrigin(); +} + +void SetRootLocation(LocatedEvent* event) { + gfx::PointF location = event->location_f(); + auto* target = static_cast<WaylandWindow*>(event->target()); + + while (target->GetParentTarget()) { + location += target->GetBoundsInDIP().origin().OffsetFromOrigin(); + target = static_cast<WaylandWindow*>(target->GetParentTarget()); + } + event->set_root_location_f(location); +} + // Number of fingers for scroll gestures. constexpr int kGestureScrollFingerCount = 2; -// Maximum size of the stored recent pointer frame information. -constexpr int kRecentPointerFrameMaxSize = 20; +// Maximum size of the latest pointer scroll data set to be stored. +constexpr int kPointerScrollDataSetMaxSize = 20; } // namespace @@ -60,7 +99,7 @@ struct WaylandEventSource::TouchPoint { TouchPoint(gfx::PointF location, WaylandWindow* current_window); ~TouchPoint() = default; - WaylandWindow* window; + raw_ptr<WaylandWindow> window; gfx::PointF last_known_location; }; @@ -70,24 +109,39 @@ WaylandEventSource::TouchPoint::TouchPoint(gfx::PointF location, DCHECK(window); } -WaylandEventSource::PointerFrame::PointerFrame() = default; -WaylandEventSource::PointerFrame::PointerFrame(const PointerFrame&) = default; -WaylandEventSource::PointerFrame::PointerFrame(PointerFrame&&) = default; -WaylandEventSource::PointerFrame::~PointerFrame() = default; +// WaylandEventSource::PointerScrollData implementation +WaylandEventSource::PointerScrollData::PointerScrollData() = default; +WaylandEventSource::PointerScrollData::PointerScrollData( + const PointerScrollData&) = default; +WaylandEventSource::PointerScrollData::PointerScrollData(PointerScrollData&&) = + default; +WaylandEventSource::PointerScrollData::~PointerScrollData() = default; -WaylandEventSource::PointerFrame& WaylandEventSource::PointerFrame::operator=( - const PointerFrame&) = default; -WaylandEventSource::PointerFrame& WaylandEventSource::PointerFrame::operator=( - PointerFrame&&) = default; +WaylandEventSource::PointerScrollData& +WaylandEventSource::PointerScrollData::operator=(const PointerScrollData&) = + default; +WaylandEventSource::PointerScrollData& +WaylandEventSource::PointerScrollData::operator=(PointerScrollData&&) = default; -WaylandEventSource::TouchFrame::TouchFrame(const TouchEvent& e, - base::OnceCallback<void()> cb) - : event(e), completion_cb(std::move(cb)) {} +// WaylandEventSource::FrameData implementation +WaylandEventSource::FrameData::FrameData(const Event& e, + base::OnceCallback<void()> cb) + : event(e.Clone()), completion_cb(std::move(cb)) {} -WaylandEventSource::TouchFrame::~TouchFrame() = default; +WaylandEventSource::FrameData::~FrameData() = default; // WaylandEventSource implementation +// static +void WaylandEventSource::ConvertEventToTarget(const EventTarget* new_target, + LocatedEvent* event) { + auto* current_target = static_cast<WaylandWindow*>(event->target()); + gfx::Vector2d diff = GetOriginInScreen(current_target) - + GetOriginInScreen(static_cast<WaylandWindow*>( + const_cast<EventTarget*>(new_target))); + event->set_location_f(event->location_f() + diff); +} + WaylandEventSource::WaylandEventSource(wl_display* display, wl_event_queue* event_queue, WaylandWindowManager* window_manager, @@ -153,16 +207,17 @@ uint32_t WaylandEventSource::OnKeyboardKeyEvent( int state_before_event = keyboard_modifiers_; #endif - if (!repeat) { - int flag = ModifierDomKeyToEventFlag(dom_key); - UpdateKeyboardModifiers(flag, type == ET_KEY_PRESSED); - } - KeyEvent event(type, key_code, dom_code, keyboard_modifiers_ | (repeat ? EF_IS_REPEAT : 0), dom_key, timestamp); event.set_source_device_id(device_id); + auto* focus = window_manager_->GetCurrentKeyboardFocusedWindow(); + if (!focus) + return POST_DISPATCH_STOP_PROPAGATION; + + Event::DispatcherApi(&event).set_target(focus); + Event::Properties properties; #if BUILDFLAG(USE_GTK) // GTK uses XKB keycodes. @@ -192,8 +247,10 @@ uint32_t WaylandEventSource::OnKeyboardKeyEvent( return DispatchEvent(&event); } -void WaylandEventSource::OnPointerFocusChanged(WaylandWindow* window, - const gfx::PointF& location) { +void WaylandEventSource::OnPointerFocusChanged( + WaylandWindow* window, + const gfx::PointF& location, + wl::EventDispatchPolicy dispatch_policy) { bool focused = !!window; if (focused) { // Save new pointer location. @@ -201,13 +258,29 @@ void WaylandEventSource::OnPointerFocusChanged(WaylandWindow* window, window_manager_->SetPointerFocusedWindow(window); } - EventType type = focused ? ET_MOUSE_ENTERED : ET_MOUSE_EXITED; - MouseEvent event(type, pointer_location_, pointer_location_, - EventTimeForNow(), pointer_flags_, 0); - DispatchEvent(&event); + auto closure = focused ? base::NullCallback() + : base::BindOnce( + [](WaylandWindowManager* wwm) { + wwm->SetPointerFocusedWindow(nullptr); + }, + window_manager_); + + auto* target = window_manager_->GetCurrentPointerFocusedWindow(); + if (target) { + EventType type = focused ? ET_MOUSE_ENTERED : ET_MOUSE_EXITED; + MouseEvent event(type, pointer_location_, pointer_location_, + EventTimeForNow(), pointer_flags_, 0); + if (dispatch_policy == wl::EventDispatchPolicy::kImmediate) { + SetTargetAndDispatchEvent(&event, target); + } else { + pointer_frames_.push_back( + std::make_unique<FrameData>(event, std::move(closure))); + return; + } + } - if (!focused) - window_manager_->SetPointerFocusedWindow(nullptr); + if (!closure.is_null()) + std::move(closure).Run(); } void WaylandEventSource::OnPointerButtonEvent(EventType type, @@ -230,7 +303,11 @@ void WaylandEventSource::OnPointerButtonEvent(EventType type, MouseEvent event(type, pointer_location_, pointer_location_, EventTimeForNow(), flags, changed_button, PointerDetailsForDispatching()); - DispatchEvent(&event); + + auto* target = window_manager_->GetCurrentPointerFocusedWindow(); + // A window may be deleted when the event arrived from the server. + if (target) + SetTargetAndDispatchEvent(&event, target); if (window) window_manager_->SetPointerFocusedWindow(prev_focused_window); @@ -242,12 +319,17 @@ void WaylandEventSource::OnPointerMotionEvent(const gfx::PointF& location) { int flags = pointer_flags_ | keyboard_modifiers_; MouseEvent event(ET_MOUSE_MOVED, pointer_location_, pointer_location_, EventTimeForNow(), flags, 0, PointerDetailsForDispatching()); - DispatchEvent(&event); + auto* target = window_manager_->GetCurrentPointerFocusedWindow(); + + // A window may be deleted when the event arrived from the server. + if (!target) + return; + SetTargetAndDispatchEvent(&event, target); } void WaylandEventSource::OnPointerAxisEvent(const gfx::Vector2dF& offset) { - current_pointer_frame_.dx += offset.x(); - current_pointer_frame_.dy += offset.y(); + EnsurePointerScrollData().dx += offset.x(); + EnsurePointerScrollData().dy += offset.y(); } void WaylandEventSource::OnResetPointerFlags() { @@ -264,74 +346,39 @@ const gfx::PointF& WaylandEventSource::GetPointerLocation() const { void WaylandEventSource::OnPointerFrameEvent() { base::TimeTicks now = EventTimeForNow(); - current_pointer_frame_.dt = now - last_pointer_frame_time_; - last_pointer_frame_time_ = now; + if (pointer_scroll_data_) { + pointer_scroll_data_->dt = now - last_pointer_frame_time_; + ProcessPointerScrollData(); + } - int flags = pointer_flags_ | keyboard_modifiers_; + last_pointer_frame_time_ = now; - static constexpr bool supports_trackpad_kinetic_scrolling = -#if BUILDFLAG(IS_CHROMEOS_LACROS) - true; -#else - false; -#endif + auto* target = window_manager_->GetCurrentPointerFocusedWindow(); + if (!target) + return; - // Dispatch Fling event if pointer.axis_stop is notified and the recent - // pointer.axis events meets the criteria to start fling scroll. - if (current_pointer_frame_.dx == 0 && current_pointer_frame_.dy == 0 && - current_pointer_frame_.is_axis_stop && - supports_trackpad_kinetic_scrolling) { - gfx::Vector2dF initial_velocity = ComputeFlingVelocity(); - float vx = initial_velocity.x(); - float vy = initial_velocity.y(); - ScrollEvent event( - vx == 0 && vy == 0 ? ET_SCROLL_FLING_CANCEL : ET_SCROLL_FLING_START, - pointer_location_, pointer_location_, now, flags, vx, vy, vx, vy, - kGestureScrollFingerCount); - DispatchEvent(&event); - recent_pointer_frames_.clear(); - } else if (current_pointer_frame_.axis_source) { - if (*current_pointer_frame_.axis_source == WL_POINTER_AXIS_SOURCE_WHEEL || - *current_pointer_frame_.axis_source == - WL_POINTER_AXIS_SOURCE_WHEEL_TILT) { - MouseWheelEvent event( - gfx::Vector2d(current_pointer_frame_.dx, current_pointer_frame_.dy), - pointer_location_, pointer_location_, EventTimeForNow(), flags, 0); - DispatchEvent(&event); - } else if (*current_pointer_frame_.axis_source == - WL_POINTER_AXIS_SOURCE_FINGER || - *current_pointer_frame_.axis_source == - WL_POINTER_AXIS_SOURCE_CONTINUOUS) { - ScrollEvent event(ET_SCROLL, pointer_location_, pointer_location_, - EventTimeForNow(), flags, current_pointer_frame_.dx, - current_pointer_frame_.dy, current_pointer_frame_.dx, - current_pointer_frame_.dy, kGestureScrollFingerCount); - DispatchEvent(&event); - } + while (!pointer_frames_.empty()) { + // It is safe to pop the first queued event for processing. + auto pointer_frame = std::move(pointer_frames_.front()); + pointer_frames_.pop_front(); - if (recent_pointer_frames_.size() + 1 > kRecentPointerFrameMaxSize) - recent_pointer_frames_.pop_back(); - recent_pointer_frames_.push_front(current_pointer_frame_); + SetTargetAndDispatchEvent(pointer_frame->event.get(), target); + if (!pointer_frame->completion_cb.is_null()) + std::move(pointer_frame->completion_cb).Run(); } - - // Reset |current_pointer_frame_|. - current_pointer_frame_.dx = 0; - current_pointer_frame_.dy = 0; - current_pointer_frame_.is_axis_stop = false; - current_pointer_frame_.axis_source.reset(); } void WaylandEventSource::OnPointerAxisSourceEvent(uint32_t axis_source) { - current_pointer_frame_.axis_source = axis_source; + EnsurePointerScrollData().axis_source = axis_source; } void WaylandEventSource::OnPointerAxisStopEvent(uint32_t axis) { if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) { - current_pointer_frame_.dy = 0; + EnsurePointerScrollData().dy = 0; } else if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) { - current_pointer_frame_.dx = 0; + EnsurePointerScrollData().dx = 0; } - current_pointer_frame_.is_axis_stop = true; + EnsurePointerScrollData().is_axis_stop = true; } void WaylandEventSource::OnTouchPressEvent( @@ -339,7 +386,7 @@ void WaylandEventSource::OnTouchPressEvent( const gfx::PointF& location, base::TimeTicks timestamp, PointerId id, - EventDispatchPolicy dispatch_policy) { + wl::EventDispatchPolicy dispatch_policy) { DCHECK(window); HandleTouchFocusChange(window, true); @@ -351,18 +398,18 @@ void WaylandEventSource::OnTouchPressEvent( return; } - PointerDetails details(PointerDetailsForDispatching(id)); + PointerDetails details(EventPointerType::kTouch, id); TouchEvent event(ET_TOUCH_PRESSED, location, location, timestamp, details, keyboard_modifiers_); - DCHECK_EQ(dispatch_policy, DispatchPolicy::kOnFrame); - touch_frames_.push_front( - std::make_unique<TouchFrame>(event, base::NullCallback())); + DCHECK_EQ(dispatch_policy, wl::EventDispatchPolicy::kOnFrame); + touch_frames_.push_back( + std::make_unique<FrameData>(event, base::NullCallback())); } void WaylandEventSource::OnTouchReleaseEvent( base::TimeTicks timestamp, PointerId id, - EventDispatchPolicy dispatch_policy) { + wl::EventDispatchPolicy dispatch_policy) { // Make sure this touch point was present before. const auto it = touch_points_.find(id); if (it == touch_points_.end()) { @@ -376,11 +423,11 @@ void WaylandEventSource::OnTouchReleaseEvent( TouchEvent event(ET_TOUCH_RELEASED, location, location, timestamp, details, keyboard_modifiers_); - if (dispatch_policy == EventDispatchPolicy::kImmediate) { - DispatchEvent(&event); + if (dispatch_policy == wl::EventDispatchPolicy::kImmediate) { + SetTouchTargetAndDispatchTouchEvent(&event); OnTouchReleaseInternal(id); } else { - touch_frames_.push_front(std::make_unique<TouchFrame>( + touch_frames_.push_back(std::make_unique<FrameData>( event, base::BindOnce(&WaylandEventSource::OnTouchReleaseInternal, base::Unretained(this), id))); } @@ -406,16 +453,40 @@ void WaylandEventSource::OnTouchReleaseInternal(PointerId id) { touch_points_.erase(it); // Clean up stylus touch tracking, if any. - const auto stylus_it = last_touch_stylus_tool_.find(id); - if (stylus_it != last_touch_stylus_tool_.end()) - last_touch_stylus_tool_.erase(stylus_it); + const auto stylus_data_it = last_touch_stylus_data_.find(id); + if (stylus_data_it != last_touch_stylus_data_.end()) + last_touch_stylus_data_.erase(stylus_data_it); +} + +void WaylandEventSource::SetTargetAndDispatchEvent(Event* event, + EventTarget* target) { + Event::DispatcherApi(event).set_target(target); + if (event->IsLocatedEvent()) { + SetRootLocation(event->AsLocatedEvent()); + auto* cursor_position = connection_->wayland_cursor_position(); + if (cursor_position) { + cursor_position->OnCursorPositionChanged( + GetLocationInScreen(event->AsLocatedEvent())); + } + } + DispatchEvent(event); +} + +void WaylandEventSource::SetTouchTargetAndDispatchTouchEvent( + TouchEvent* event) { + auto iter = touch_points_.find(event->pointer_details().id); + auto target = iter != touch_points_.end() ? iter->second->window : nullptr; + // Skip if the touch target has alrady been removed. + if (!target.get()) + return; + SetTargetAndDispatchEvent(event, target.get()); } void WaylandEventSource::OnTouchMotionEvent( const gfx::PointF& location, base::TimeTicks timestamp, PointerId id, - EventDispatchPolicy dispatch_policy) { + wl::EventDispatchPolicy dispatch_policy) { const auto it = touch_points_.find(id); // Make sure this touch point was present before. if (it == touch_points_.end()) { @@ -423,14 +494,14 @@ void WaylandEventSource::OnTouchMotionEvent( return; } it->second->last_known_location = location; - PointerDetails details(PointerDetailsForDispatching(id)); + PointerDetails details(EventPointerType::kTouch, id); TouchEvent event(ET_TOUCH_MOVED, location, location, timestamp, details, keyboard_modifiers_); - if (dispatch_policy == DispatchPolicy::kImmediate) { - DispatchEvent(&event); + if (dispatch_policy == wl::EventDispatchPolicy::kImmediate) { + SetTouchTargetAndDispatchTouchEvent(&event); } else { - touch_frames_.push_front( - std::make_unique<TouchFrame>(event, base::NullCallback())); + touch_frames_.push_back( + std::make_unique<FrameData>(event, base::NullCallback())); } } @@ -448,20 +519,31 @@ void WaylandEventSource::OnTouchCancelEvent() { PointerId id = touch_point.first; TouchEvent event(ET_TOUCH_CANCELLED, location, location, timestamp, PointerDetails(EventPointerType::kTouch, id)); - DispatchEvent(&event); + SetTouchTargetAndDispatchTouchEvent(&event); HandleTouchFocusChange(touch_point.second->window, false); } touch_points_.clear(); - last_touch_stylus_tool_.clear(); + last_touch_stylus_data_.clear(); } void WaylandEventSource::OnTouchFrame() { while (!touch_frames_.empty()) { - // It is OK/safe to pop the first queued event for processing. + // It is safe to pop the first queued event for processing. auto touch_frame = std::move(touch_frames_.front()); touch_frames_.pop_front(); - DispatchEvent(&(touch_frame->event)); + // In case there are touch stylus information, override the current 'event' + // instance, given that PointerDetails is 'const'. + auto pointer_details_with_stylus_data = AmendStylusData( + touch_frame->event->AsTouchEvent()->pointer_details().id); + if (pointer_details_with_stylus_data) { + auto old_event = std::move(touch_frame->event); + touch_frame->event = std::make_unique<TouchEvent>( + old_event->type(), old_event->AsTouchEvent()->location_f(), + old_event->AsTouchEvent()->root_location_f(), old_event->time_stamp(), + pointer_details_with_stylus_data.value(), old_event->flags()); + } + SetTouchTargetAndDispatchTouchEvent(touch_frame->event->AsTouchEvent()); if (!touch_frame->completion_cb.is_null()) std::move(touch_frame->completion_cb).Run(); } @@ -481,12 +563,29 @@ std::vector<PointerId> WaylandEventSource::GetActiveTouchPointIds() { void WaylandEventSource::OnTouchStylusToolChanged( PointerId pointer_id, EventPointerType pointer_type) { - last_touch_stylus_tool_[pointer_id] = pointer_type; + StylusData stylus_data = {.type = pointer_type, + .tilt = gfx::Vector2dF(), + .force = std::numeric_limits<float>::quiet_NaN()}; + bool inserted = + last_touch_stylus_data_.try_emplace(pointer_id, stylus_data).second; + DCHECK(inserted); +} + +void WaylandEventSource::OnTouchStylusForceChanged(PointerId pointer_id, + float force) { + DCHECK(last_touch_stylus_data_[pointer_id].has_value()); + last_touch_stylus_data_[pointer_id]->force = force; +} + +void WaylandEventSource::OnTouchStylusTiltChanged(PointerId pointer_id, + const gfx::Vector2dF& tilt) { + DCHECK(last_touch_stylus_data_[pointer_id].has_value()); + last_touch_stylus_data_[pointer_id]->tilt = tilt; } const WaylandWindow* WaylandEventSource::GetTouchTarget(PointerId id) const { const auto it = touch_points_.find(id); - return it == touch_points_.end() ? nullptr : it->second->window; + return it == touch_points_.end() ? nullptr : it->second->window.get(); } void WaylandEventSource::OnPinchEvent(EventType event_type, @@ -503,7 +602,13 @@ void WaylandEventSource::OnPinchEvent(EventType event_type, GestureEvent event(location.x(), location.y(), 0 /* flags */, timestamp, details); event.set_source_device_id(device_id); - DispatchEvent(&event); + + auto* target = window_manager_->GetCurrentPointerFocusedWindow(); + // A window may be deleted when the event arrived from the server. + if (!target) + return; + + SetTargetAndDispatchEvent(&event, target); } void WaylandEventSource::SetRelativePointerMotionEnabled(bool enabled) { @@ -557,25 +662,6 @@ void WaylandEventSource::OnWindowRemoved(WaylandWindow* window) { }); } -// Currently EF_MOD3_DOWN means that the CapsLock key is currently down, and -// EF_CAPS_LOCK_ON means the caps lock state is enabled (and the key may or -// may not be down, but usually isn't). There does need to be two different -// flags, since the physical CapsLock key is subject to remapping, but the -// caps lock state (which can be triggered in a variety of ways) is not. -// -// TODO(crbug.com/1076661): This is likely caused by some CrOS-specific code. -// Get rid of this function once it is properly guarded under OS_CHROMEOS. -void WaylandEventSource::UpdateKeyboardModifiers(int modifier, bool down) { - if (modifier == EF_NONE) - return; - - if (modifier == EF_CAPS_LOCK_ON) { - modifier = (modifier & ~EF_CAPS_LOCK_ON) | EF_MOD3_DOWN; - } - keyboard_modifiers_ = down ? (keyboard_modifiers_ | modifier) - : (keyboard_modifiers_ & ~modifier); -} - void WaylandEventSource::HandleTouchFocusChange(WaylandWindow* window, bool focused, absl::optional<PointerId> id) { @@ -600,7 +686,7 @@ gfx::Vector2dF WaylandEventSource::ComputeFlingVelocity() { base::TimeDelta dt; float dx = 0.0f; float dy = 0.0f; - for (auto& frame : recent_pointer_frames_) { + for (auto& frame : pointer_scroll_data_set_) { if (frame.axis_source && *frame.axis_source != WL_POINTER_AXIS_SOURCE_FINGER) { break; @@ -614,6 +700,8 @@ gfx::Vector2dF WaylandEventSource::ComputeFlingVelocity() { dy += frame.dy; dt += frame.dt; } + pointer_scroll_data_set_.clear(); + float dt_inv = 1.0f / dt.InSecondsF(); return dt.is_zero() ? gfx::Vector2dF() : gfx::Vector2dF(dx * dt_inv, dy * dt_inv); @@ -631,15 +719,83 @@ PointerDetails WaylandEventSource::PointerDetailsForDispatching() const { return PointerDetails(*last_pointer_stylus_tool_); } -PointerDetails WaylandEventSource::PointerDetailsForDispatching( +absl::optional<PointerDetails> WaylandEventSource::AmendStylusData( PointerId pointer_id) const { - const auto it = last_touch_stylus_tool_.find(pointer_id); - if (it == last_touch_stylus_tool_.end() || !it->second || - it->second == EventPointerType::kTouch) { - return PointerDetails(EventPointerType::kTouch, pointer_id); + const auto it = last_touch_stylus_data_.find(pointer_id); + if (it == last_touch_stylus_data_.end() || !it->second || + it->second->type == EventPointerType::kTouch) { + return absl::nullopt; + } + + // The values below come from the default values in pointer_details.cc|h. + return PointerDetails(it->second->type, pointer_id, + /*radius_x=*/1.0f, + /*radius_y=*/1.0f, it->second->force, + /*twist=*/0.0f, it->second->tilt.x(), + it->second->tilt.y()); +} + +WaylandEventSource::PointerScrollData& +WaylandEventSource::EnsurePointerScrollData() { + if (!pointer_scroll_data_) + pointer_scroll_data_ = PointerScrollData(); + + return *pointer_scroll_data_; +} + +void WaylandEventSource::ProcessPointerScrollData() { + DCHECK(pointer_scroll_data_); + + int flags = pointer_flags_ | keyboard_modifiers_; + + static constexpr bool supports_trackpad_kinetic_scrolling = +#if BUILDFLAG(IS_CHROMEOS_LACROS) + true; +#else + false; +#endif + + // Dispatch Fling event if pointer.axis_stop is notified and the recent + // pointer.axis events meets the criteria to start fling scroll. + if (pointer_scroll_data_->dx == 0 && pointer_scroll_data_->dy == 0 && + pointer_scroll_data_->is_axis_stop && + supports_trackpad_kinetic_scrolling) { + gfx::Vector2dF initial_velocity = ComputeFlingVelocity(); + float vx = initial_velocity.x(); + float vy = initial_velocity.y(); + ScrollEvent event( + vx == 0 && vy == 0 ? ET_SCROLL_FLING_CANCEL : ET_SCROLL_FLING_START, + pointer_location_, pointer_location_, EventTimeForNow(), flags, vx, vy, + vx, vy, kGestureScrollFingerCount); + pointer_frames_.push_back( + std::make_unique<FrameData>(event, base::NullCallback())); + } else if (pointer_scroll_data_->axis_source) { + if (*pointer_scroll_data_->axis_source == WL_POINTER_AXIS_SOURCE_WHEEL || + *pointer_scroll_data_->axis_source == + WL_POINTER_AXIS_SOURCE_WHEEL_TILT) { + MouseWheelEvent event( + gfx::Vector2d(pointer_scroll_data_->dx, pointer_scroll_data_->dy), + pointer_location_, pointer_location_, EventTimeForNow(), flags, 0); + pointer_frames_.push_back( + std::make_unique<FrameData>(event, base::NullCallback())); + } else if (*pointer_scroll_data_->axis_source == + WL_POINTER_AXIS_SOURCE_FINGER || + *pointer_scroll_data_->axis_source == + WL_POINTER_AXIS_SOURCE_CONTINUOUS) { + ScrollEvent event(ET_SCROLL, pointer_location_, pointer_location_, + EventTimeForNow(), flags, pointer_scroll_data_->dx, + pointer_scroll_data_->dy, pointer_scroll_data_->dx, + pointer_scroll_data_->dy, kGestureScrollFingerCount); + pointer_frames_.push_back( + std::make_unique<FrameData>(event, base::NullCallback())); + } + + if (pointer_scroll_data_set_.size() + 1 > kPointerScrollDataSetMaxSize) + pointer_scroll_data_set_.pop_back(); + pointer_scroll_data_set_.push_front(*pointer_scroll_data_); } - return PointerDetails(it->second.value(), pointer_id); + pointer_scroll_data_.reset(); } } // namespace ui 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 9f6f40d373b..441c150c118 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_event_source.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_event_source.h @@ -9,6 +9,7 @@ #include <memory> #include "base/containers/flat_map.h" +#include "base/memory/raw_ptr.h" #include "base/time/time.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/events/event.h" @@ -32,6 +33,15 @@ namespace gfx { class Vector2dF; } +namespace wl { + +enum class EventDispatchPolicy { + kImmediate, + kOnFrame, +}; + +} // namespace wl + namespace ui { class WaylandConnection; @@ -54,6 +64,9 @@ class WaylandEventSource : public PlatformEventSource, public WaylandZwpPointerGestures::Delegate, public WaylandZwpRelativePointerManager::Delegate { public: + static void ConvertEventToTarget(const EventTarget* new_target, + LocatedEvent* event); + WaylandEventSource(wl_display* display, wl_event_queue* event_queue, WaylandWindowManager* window_manager, @@ -100,7 +113,8 @@ class WaylandEventSource : public PlatformEventSource, // WaylandPointer::Delegate void OnPointerFocusChanged(WaylandWindow* window, - const gfx::PointF& location) override; + const gfx::PointF& location, + wl::EventDispatchPolicy dispatch_policy) override; void OnPointerButtonEvent(EventType evtype, int changed_button, WaylandWindow* window = nullptr) override; @@ -116,19 +130,18 @@ class WaylandEventSource : public PlatformEventSource, const WaylandWindow* GetPointerTarget() const override; // WaylandTouch::Delegate - using DispatchPolicy = WaylandTouch::Delegate::EventDispatchPolicy; void OnTouchPressEvent(WaylandWindow* window, const gfx::PointF& location, base::TimeTicks timestamp, PointerId id, - EventDispatchPolicy dispatch_policy) override; + wl::EventDispatchPolicy dispatch_policy) override; void OnTouchReleaseEvent(base::TimeTicks timestamp, PointerId id, - EventDispatchPolicy dispatch_policy) override; + wl::EventDispatchPolicy dispatch_policy) override; void OnTouchMotionEvent(const gfx::PointF& location, base::TimeTicks timestamp, PointerId id, - EventDispatchPolicy dispatch_policy) override; + wl::EventDispatchPolicy dispatch_policy) override; void OnTouchCancelEvent() override; void OnTouchFrame() override; void OnTouchFocusChanged(WaylandWindow* window) override; @@ -136,6 +149,9 @@ class WaylandEventSource : public PlatformEventSource, const WaylandWindow* GetTouchTarget(PointerId id) const override; void OnTouchStylusToolChanged(PointerId pointer_id, EventPointerType pointer_type) override; + void OnTouchStylusForceChanged(PointerId pointer_id, float force) override; + void OnTouchStylusTiltChanged(PointerId pointer_id, + const gfx::Vector2dF& tilt) override; // WaylandZwpPointerGesture::Delegate: void OnPinchEvent(EventType event_type, @@ -149,14 +165,14 @@ class WaylandEventSource : public PlatformEventSource, void OnRelativePointerMotion(const gfx::Vector2dF& delta) override; private: - struct PointerFrame { - PointerFrame(); - PointerFrame(const PointerFrame& other); - PointerFrame(PointerFrame&&); - ~PointerFrame(); + struct PointerScrollData { + PointerScrollData(); + PointerScrollData(const PointerScrollData& other); + PointerScrollData(PointerScrollData&&); + ~PointerScrollData(); - PointerFrame& operator=(const PointerFrame&); - PointerFrame& operator=(PointerFrame&&); + PointerScrollData& operator=(const PointerScrollData&); + PointerScrollData& operator=(PointerScrollData&&); absl::optional<uint32_t> axis_source; float dx = 0.0f; @@ -165,14 +181,13 @@ class WaylandEventSource : public PlatformEventSource, bool is_axis_stop = false; }; - struct TouchFrame { - TouchFrame(const TouchEvent& event, - base::OnceCallback<void()> completion_cb); - TouchFrame(const TouchFrame& other) = delete; - TouchFrame(TouchFrame&&) = delete; - ~TouchFrame(); + struct FrameData { + FrameData(const Event& event, base::OnceCallback<void()> completion_cb); + FrameData(const FrameData& other) = delete; + FrameData(FrameData&&) = delete; + ~FrameData(); - TouchEvent event; + std::unique_ptr<Event> event; base::OnceCallback<void()> completion_cb; }; @@ -182,7 +197,6 @@ class WaylandEventSource : public PlatformEventSource, // WaylandWindowObserver: void OnWindowRemoved(WaylandWindow* window) override; - void UpdateKeyboardModifiers(int modifier, bool down); void HandleTouchFocusChange(WaylandWindow* window, bool focused, absl::optional<PointerId> id = absl::nullopt); @@ -197,14 +211,25 @@ class WaylandEventSource : public PlatformEventSource, PointerDetails PointerDetailsForDispatching() const; // For touch events. - PointerDetails PointerDetailsForDispatching(PointerId pointer_id) const; + absl::optional<PointerDetails> AmendStylusData(PointerId pointer_id) const; // Wrap up method to support async touch release processing. void OnTouchReleaseInternal(PointerId id); - WaylandWindowManager* const window_manager_; + // Ensure a valid instance of the PointerScrollData class member. + PointerScrollData& EnsurePointerScrollData(); + + void ProcessPointerScrollData(); + + // Set the target to the event, then dispatch the event. + void SetTargetAndDispatchEvent(Event* event, EventTarget* target); + + // Find and set the target for the touch event, then dispatch the event. + void SetTouchTargetAndDispatchTouchEvent(TouchEvent* event); - WaylandConnection* const connection_; + const raw_ptr<WaylandWindowManager> window_manager_; + + const raw_ptr<WaylandConnection> connection_; // Bitmask of EventFlags used to keep track of the the pointer state. int pointer_flags_ = 0; @@ -213,6 +238,7 @@ class WaylandEventSource : public PlatformEventSource, int last_pointer_button_pressed_ = 0; // Bitmask of EventFlags used to keep track of the the keyboard state. + // See ui/events/event_constants.h for examples and details. int keyboard_modifiers_ = 0; // Last known pointer location. @@ -221,8 +247,12 @@ class WaylandEventSource : public PlatformEventSource, // Last known relative pointer location (used for pointer lock). absl::optional<gfx::PointF> relative_pointer_location_; - // Current frame - PointerFrame current_pointer_frame_; + // Accumulates the scroll data within a pointer frame internal. + absl::optional<PointerScrollData> pointer_scroll_data_; + + // Latest set of pointer scroll data to compute fling scroll. + // Front is newer, and back is older. + std::deque<PointerScrollData> pointer_scroll_data_set_; // Time of the last pointer frame event. base::TimeTicks last_pointer_frame_time_; @@ -231,17 +261,20 @@ class WaylandEventSource : public PlatformEventSource, absl::optional<EventPointerType> last_pointer_stylus_tool_; // Last known touch stylus type (eg touch, pen or eraser). - // absl::optional<PointerId, EventPointerType> last_touch_stylus_tool_; - base::flat_map<PointerId, absl::optional<EventPointerType>> - last_touch_stylus_tool_; - - // Recent pointer frames to compute fling scroll. - // Front is newer, and back is older. - std::deque<PointerFrame> recent_pointer_frames_; + struct StylusData { + EventPointerType type = EventPointerType::kUnknown; + gfx::Vector2dF tilt; + float force = std::numeric_limits<float>::quiet_NaN(); + }; + base::flat_map<PointerId, absl::optional<StylusData>> last_touch_stylus_data_; // Order set of touch events to be dispatching on the next // wl_touch::frame event. - std::deque<std::unique_ptr<TouchFrame>> touch_frames_; + std::deque<std::unique_ptr<FrameData>> touch_frames_; + + // Order set of pointer events to be dispatching on the next + // wl_pointer::frame event. + std::deque<std::unique_ptr<FrameData>> pointer_frames_; // Map that keeps track of the current touch points, associating touch IDs to // to the surface/location where they happened. diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_event_source_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_event_source_unittest.cc index 77994d52f06..eeb38c114da 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_event_source_unittest.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_event_source_unittest.cc @@ -4,11 +4,13 @@ #include <linux/input.h> +#include "base/memory/raw_ptr.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/ozone/platform/wayland/host/wayland_event_source.h" #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_touch.h" #include "ui/ozone/platform/wayland/test/wayland_test.h" #include "ui/ozone/test/mock_platform_window_delegate.h" @@ -52,7 +54,7 @@ class WaylandEventSourceTest : public WaylandTest { return window; } - WaylandPointer::Delegate* pointer_delegate_ = nullptr; + raw_ptr<WaylandPointer::Delegate> pointer_delegate_ = nullptr; }; // Verify WaylandEventSource properly manages its internal state as pointer @@ -87,6 +89,7 @@ TEST_P(WaylandEventSourceTest, CheckPointerButtonHandling) { wl_resource* pointer_res = server_.seat()->pointer()->resource(); wl_pointer_send_enter(pointer_res, serial++, surface_res, 0, 0); + wl_pointer_send_frame(pointer_res); wl_pointer_send_button(pointer_res, serial++, tstamp++, BTN_LEFT, WL_POINTER_BUTTON_STATE_PRESSED); EXPECT_CALL(delegate, DispatchEvent(_)).Times(2); @@ -113,6 +116,43 @@ TEST_P(WaylandEventSourceTest, CheckPointerButtonHandling) { pointer_delegate_->IsPointerButtonPressed(EF_RIGHT_MOUSE_BUTTON)); } +// Verify WaylandEventSource properly manages its internal state as pointer +// button events are sent. More specifically - pointer flags. +TEST_P(WaylandEventSourceTest, DeleteBeforeTouchFrame) { + MockPlatformWindowDelegate delegate; + wl_seat_send_capabilities(server_.seat()->resource(), + WL_SEAT_CAPABILITY_TOUCH); + + auto window1 = CreateWaylandWindowWithParams(PlatformWindowType::kWindow, + kDefaultBounds, &delegate); + Sync(); + + ASSERT_TRUE(server_.seat()->touch()); + + uint32_t serial = 0; + uint32_t tstamp = 0; + wl_resource* surface_res = + server_ + .GetObject<wl::MockSurface>(window1->root_surface()->GetSurfaceId()) + ->resource(); + wl_resource* touch_res = server_.seat()->touch()->resource(); + + wl_touch_send_down(touch_res, serial++, tstamp++, surface_res, /*id=*/0, 0, + 0); + wl_touch_send_down(touch_res, serial++, tstamp++, surface_res, /*id=*/1, 0, + 0); + + Sync(); + + // Removint the target during touch event sequece should not cause crash. + window1.reset(); + + wl_touch_send_frame(touch_res); + EXPECT_CALL(delegate, DispatchEvent(_)).Times(0); + + Sync(); +} + INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest, WaylandEventSourceTest, Values(wl::ServerConfig{ diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_event_watcher.h b/chromium/ui/ozone/platform/wayland/host/wayland_event_watcher.h index 9b06d48c52c..d8e10d15c2e 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_event_watcher.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_event_watcher.h @@ -6,6 +6,7 @@ #define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_EVENT_WATCHER_H_ #include "base/callback.h" +#include "base/memory/raw_ptr.h" #include "base/message_loop/message_pump_for_ui.h" struct wl_display; @@ -81,8 +82,8 @@ class WaylandEventWatcher { // and false is returned. void WlDisplayCheckForErrors(); - wl_display* const display_; // Owned by WaylandConnection. - wl_event_queue* const event_queue_; // Owned by WaylandConnection. + const raw_ptr<wl_display> display_; // Owned by WaylandConnection. + const raw_ptr<wl_event_queue> event_queue_; // Owned by WaylandConnection. bool watching_ = false; bool prepared_ = false; diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_event_watcher_glib.cc b/chromium/ui/ozone/platform/wayland/host/wayland_event_watcher_glib.cc index 25cca1df5c4..be78e0b3f2e 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_event_watcher_glib.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_event_watcher_glib.cc @@ -6,6 +6,8 @@ #include <glib.h> +#include "base/memory/raw_ptr.h" + namespace ui { namespace { @@ -13,8 +15,8 @@ namespace { struct GLibWaylandSource : public GSource { // Note: The GLibWaylandSource is created and destroyed by GLib. So its // constructor/destructor may or may not get called. - WaylandEventWatcherGlib* event_watcher; - GPollFD* poll_fd; + raw_ptr<WaylandEventWatcherGlib> event_watcher; + raw_ptr<GPollFD> poll_fd; }; gboolean WatchSourcePrepare(GSource* source, gint* timeout_ms) { @@ -22,7 +24,7 @@ gboolean WatchSourcePrepare(GSource* source, gint* timeout_ms) { *timeout_ms = -1; auto* event_watcher_glib = - static_cast<GLibWaylandSource*>(source)->event_watcher; + static_cast<GLibWaylandSource*>(source)->event_watcher.get(); if (event_watcher_glib->HandlePrepare()) return FALSE; @@ -41,7 +43,7 @@ gboolean WatchSourceDispatch(GSource* source, GSourceFunc unused_func, gpointer data) { auto* event_watcher_glib = - static_cast<GLibWaylandSource*>(source)->event_watcher; + static_cast<GLibWaylandSource*>(source)->event_watcher.get(); event_watcher_glib->HandleDispatch(); return TRUE; } diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_event_watcher_glib.h b/chromium/ui/ozone/platform/wayland/host/wayland_event_watcher_glib.h index 2efcc923de9..716bff97c7e 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_event_watcher_glib.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_event_watcher_glib.h @@ -5,6 +5,7 @@ #ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_EVENT_WATCHER_GLIB_H_ #define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_EVENT_WATCHER_GLIB_H_ +#include "base/memory/raw_ptr.h" #include "ui/ozone/platform/wayland/host/wayland_event_watcher.h" using GPollFD = struct _GPollFD; @@ -37,7 +38,7 @@ class WaylandEventWatcherGlib : public WaylandEventWatcher { bool started_ = false; // The GLib event source for Wayland events. - GSource* wayland_source_ = nullptr; + raw_ptr<GSource> wayland_source_ = nullptr; // The poll attached to |wayland_source_|. std::unique_ptr<GPollFD> wayland_poll_; diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_exchange_data_provider_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_exchange_data_provider_unittest.cc index a852290685e..7ab699d99c2 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_exchange_data_provider_unittest.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_exchange_data_provider_unittest.cc @@ -66,7 +66,7 @@ TEST(WaylandExchangeDataProviderTest, ExtractPickledData) { #if BUILDFLAG(IS_CHROMEOS_LACROS) TEST(WaylandExchangeDataProviderTest, AddAndExtractDataTransferEndpoint) { std::string kExpectedEncodedDte = - R"({"endpoint_type":"url","url":"https://www.google.com/","url_origin":"https://www.google.com"})"; + R"({"endpoint_type":"url","url":"https://www.google.com/"})"; const DataTransferEndpoint expected_dte = ui::DataTransferEndpoint(GURL("https://www.google.com")); diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_frame_manager.cc b/chromium/ui/ozone/platform/wayland/host/wayland_frame_manager.cc index a120c6ff1ad..edf3880df58 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_frame_manager.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_frame_manager.cc @@ -10,6 +10,7 @@ #include "base/containers/adapters.h" #include "ui/gfx/geometry/rect_conversions.h" #include "ui/gfx/geometry/size_conversions.h" +#include "ui/ozone/platform/wayland/host/wayland_buffer_factory.h" #include "ui/ozone/platform/wayland/host/wayland_buffer_handle.h" #include "ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h" #include "ui/ozone/platform/wayland/host/wayland_connection.h" @@ -79,25 +80,24 @@ WaylandFrameManager::~WaylandFrameManager() { void WaylandFrameManager::RecordFrame(std::unique_ptr<WaylandFrame> frame) { DCHECK_LE(pending_frames_.size(), 6u); - // Request for buffer handle creation at record time. - for (auto& subsurface_to_overlay : frame->subsurfaces_to_overlays) { - if (subsurface_to_overlay.second.buffer_id) { - auto* handle = connection_->buffer_manager_host()->EnsureBufferHandle( - subsurface_to_overlay.first->wayland_surface(), - subsurface_to_overlay.second.buffer_id); - if (!handle) - return; - } - } - if (frame->root_config.buffer_id) { - auto* handle = connection_->buffer_manager_host()->EnsureBufferHandle( - frame->root_surface, frame->root_config.buffer_id); - if (!handle) - return; + bool buffer_pending_creation = false; + // The |frame| may have buffers to be sent for submission, which might not + // have been created yet. This must be done now if they cannot be created + // immediately. Thus, dispatch this request so that buffers are created by the + // time this frame is played back if |pending_frames_| is not empty. + // Otherwise, there is no point to ensure wl_buffers exist as + // MaybeProcessPendingFrame will do that as well. + if (!connection_->wayland_buffer_factory()->CanCreateDmabufImmed() && + !pending_frames_.empty()) { + buffer_pending_creation = + EnsureWlBuffersExist(*frame) && !frame->buffer_lost; } pending_frames_.push_back(std::move(frame)); - MaybeProcessPendingFrame(); + // There are wl_buffers missing, need to wait. MaybeProcessPendingFrame will + // be called as soon as buffers are created. + if (!buffer_pending_creation) + MaybeProcessPendingFrame(); } void WaylandFrameManager::MaybeProcessPendingFrame() { @@ -109,53 +109,54 @@ void WaylandFrameManager::MaybeProcessPendingFrame() { if (!frame) return; - // Ensure wl_buffer existence. - WaylandBufferHandle* handle_pending_creation = nullptr; - for (auto& subsurface_to_overlay : frame->subsurfaces_to_overlays) { - if (subsurface_to_overlay.second.buffer_id) { - auto* handle = connection_->buffer_manager_host()->EnsureBufferHandle( - subsurface_to_overlay.first->wayland_surface(), - subsurface_to_overlay.second.buffer_id); - // Buffer is gone while this frame is pending, remove this config. - if (!handle) { - frame->buffer_lost = true; - subsurface_to_overlay.second = wl::WaylandOverlayConfig(); - } else if (!handle->wl_buffer() && !handle_pending_creation) { - // Found the first not-ready buffer, let handle invoke - // MaybeProcessPendingFrame() when wl_buffer is created. - handle_pending_creation = handle; - } - } - } - if (frame->root_config.buffer_id) { - auto* handle = connection_->buffer_manager_host()->EnsureBufferHandle( - frame->root_surface, frame->root_config.buffer_id); - if (!handle) { - frame->buffer_lost = true; - frame->root_config = wl::WaylandOverlayConfig(); - } else if (!handle->wl_buffer() && !handle_pending_creation) { - handle_pending_creation = handle; - } - } - - // There are wl_buffers missing, need to wait. - if (handle_pending_creation) { - handle_pending_creation->set_buffer_created_callback( - base::BindOnce(&WaylandFrameManager::MaybeProcessPendingFrame, - weak_factory_.GetWeakPtr())); - return; - } // Frame callback hasn't been acked, need to wait. if (!submitted_frames_.empty() && submitted_frames_.back()->wl_frame_callback) { return; } - // Window is not configured, need to wait. - if (!window_->can_submit_frames()) + + // Window is still neither configured nor has pending configure bounds, need + // to wait. Probably happens only in early stages of window initialization. + if (!window_->received_configure_event()) return; - std::unique_ptr<WaylandFrame> playback = std::move(pending_frames_.front()); - PlayBackFrame(std::move(playback)); + // Ensure wl_buffer existence. This is called for the first time in the + // following cases: + // 1) if it is possible to create buffers immediately to ensure + // WaylandBufferHandles are not lost and to create wl_buffers if they have not + // existed yet (a new buffer is submitted). + // 2) or |pending_frames| was empty when RecordFrame for this |frame| was + // called regardless whether it is possible to create wl_buffers immediately + // or not. + const bool has_buffer_pending_creation = EnsureWlBuffersExist(*frame); + // There are wl_buffers missing, need to wait. + if (has_buffer_pending_creation && !frame->buffer_lost) { + DLOG_IF(FATAL, + has_buffer_pending_creation && + connection_->wayland_buffer_factory()->CanCreateDmabufImmed()) + << "Buffers should have been created immediately."; + return; + } + + // If processing a valid frame, update window's visual size, which may result + // in surface configuration being done, i.e: xdg_surface set_window_geometry + + // ack_configure requests being issued. + const wl::WaylandOverlayConfig& config = frame->root_config; + if (!frame->buffer_lost && !!config.buffer_id) { + window_->UpdateVisualSize(gfx::ToRoundedSize(config.bounds_rect.size())); + } + + // Skip this frame if: + // 1. It can't be submitted due to lost buffers. + // 2. Even after updating visual size above, |window_| is still not fully + // configured, which might mean that the current frame sent by the gpu + // is still out-of-sync with the pending configure sequences received from + // the Wayland compositor. This avoids protocol errors as observed in + // https://crbug.com/1313023. + if (frame->buffer_lost || !window_->IsSurfaceConfigured()) + DiscardFrame(std::move(pending_frames_.front())); + else + PlayBackFrame(std::move(pending_frames_.front())); pending_frames_.pop_front(); @@ -169,25 +170,13 @@ void WaylandFrameManager::MaybeProcessPendingFrame() { } void WaylandFrameManager::PlayBackFrame(std::unique_ptr<WaylandFrame> frame) { - // Skip this frame if we can't playback this frame due to lost buffers. - if (frame->buffer_lost) { - frame->feedback = gfx::PresentationFeedback::Failure(); - submitted_frames_.push_back(std::move(frame)); - VerifyNumberOfSubmittedFrames(); - MaybeProcessSubmittedFrames(); - return; - } + DCHECK(!frame->buffer_lost); + DCHECK(window_->IsSurfaceConfigured()); - auto* root_surface = frame->root_surface; + auto* root_surface = frame->root_surface.get(); auto& root_config = frame->root_config; bool empty_frame = !root_config.buffer_id; - if (!empty_frame) { - window_->UpdateVisualSize( - gfx::ToRoundedSize(root_config.bounds_rect.size()), - root_config.surface_scale_factor); - } - // Configure subsurfaces. Traverse the deque backwards s.t. we can set // frame_callback and presentation_feedback on the top-most possible surface. WaylandSubsurface* reference_above = nullptr; @@ -246,6 +235,13 @@ void WaylandFrameManager::PlayBackFrame(std::unique_ptr<WaylandFrame> frame) { MaybeProcessSubmittedFrames(); } +void WaylandFrameManager::DiscardFrame(std::unique_ptr<WaylandFrame> frame) { + frame->feedback = gfx::PresentationFeedback::Failure(); + submitted_frames_.push_back(std::move(frame)); + VerifyNumberOfSubmittedFrames(); + MaybeProcessSubmittedFrames(); +} + void WaylandFrameManager::ApplySurfaceConfigure( WaylandFrame* frame, WaylandSurface* surface, @@ -441,6 +437,49 @@ void WaylandFrameManager::VerifyNumberOfSubmittedFrames() { } } +bool WaylandFrameManager::EnsureWlBuffersExist(WaylandFrame& frame) { + WaylandBufferHandle* handle_pending_creation = nullptr; + for (auto& subsurface_to_overlay : frame.subsurfaces_to_overlays) { + if (subsurface_to_overlay.second.buffer_id) { + auto* handle = connection_->buffer_manager_host()->EnsureBufferHandle( + subsurface_to_overlay.first->wayland_surface(), + subsurface_to_overlay.second.buffer_id); + // Buffer is gone while this frame is pending, remove this config. + if (!handle) { + frame.buffer_lost = true; + subsurface_to_overlay.second = wl::WaylandOverlayConfig(); + } else if (!handle->wl_buffer() && !handle_pending_creation) { + // Found the first not-ready buffer, let handle invoke + // MaybeProcessPendingFrame() when wl_buffer is created. + handle_pending_creation = handle; + } + } + } + if (frame.root_config.buffer_id) { + auto* handle = connection_->buffer_manager_host()->EnsureBufferHandle( + frame.root_surface, frame.root_config.buffer_id); + if (!handle) { + frame.buffer_lost = true; + frame.root_config = wl::WaylandOverlayConfig(); + } else if (!handle->wl_buffer() && !handle_pending_creation) { + handle_pending_creation = handle; + } + } + + // Some buffers might have been lost. No need to wait. + if (frame.buffer_lost) + handle_pending_creation = nullptr; + + // There are wl_buffers missing, schedule MaybeProcessPendingFrame so that + // it's called when buffers are created. + if (handle_pending_creation) { + handle_pending_creation->set_buffer_created_callback( + base::BindOnce(&WaylandFrameManager::MaybeProcessPendingFrame, + weak_factory_.GetWeakPtr())); + } + return !!handle_pending_creation; +} + void WaylandFrameManager::OnExplicitBufferRelease(WaylandSurface* surface, struct wl_buffer* wl_buffer, base::ScopedFD fence) { diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_frame_manager.h b/chromium/ui/ozone/platform/wayland/host/wayland_frame_manager.h index 1780de0fea0..2fcace1757a 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_frame_manager.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_frame_manager.h @@ -12,6 +12,7 @@ #include "base/containers/circular_deque.h" #include "base/containers/flat_map.h" #include "base/files/scoped_file.h" +#include "base/memory/raw_ptr.h" #include "base/memory/weak_ptr.h" #include "ui/gfx/gpu_fence_handle.h" #include "ui/gfx/presentation_feedback.h" @@ -56,7 +57,7 @@ struct WaylandFrame { friend class WaylandFrameManager; uint32_t frame_id; - WaylandSurface* root_surface; + raw_ptr<WaylandSurface> root_surface; wl::WaylandOverlayConfig root_config; base::circular_deque<std::pair<WaylandSubsurface*, wl::WaylandOverlayConfig>> subsurfaces_to_overlays; @@ -121,6 +122,8 @@ class WaylandFrameManager { private: void PlayBackFrame(std::unique_ptr<WaylandFrame> frame); + void DiscardFrame(std::unique_ptr<WaylandFrame> frame); + // Configures |surface| but does not commit wl_surface states yet. void ApplySurfaceConfigure(WaylandFrame* frame, WaylandSurface* surface, @@ -168,7 +171,14 @@ class WaylandFrameManager { // feedbacks if the number is too big. void VerifyNumberOfSubmittedFrames(); - WaylandWindow* const window_; + // Verifies wl_buffers for the given |frame| exist. If they do not yet exist, + // a callback to |MaybeProcessPendingFrame| is set and false is returned. + // If the frame contains a buffer id for an invalid WaylandBufferHandle, the + // |frame::buffer_lost| is set and false is returned. That means that the + // frame must not be used for the further submission. + bool EnsureWlBuffersExist(WaylandFrame& frame); + + const raw_ptr<WaylandWindow> window_; // When RecordFrame() is called, a Frame is pushed to |pending_frames_|. See // RecordFrame(). @@ -179,7 +189,7 @@ class WaylandFrameManager { base::circular_deque<std::unique_ptr<WaylandFrame>> submitted_frames_; // Non-owned pointer to the main connection. - WaylandConnection* const connection_; + const raw_ptr<WaylandConnection> connection_; base::WeakPtrFactory<WaylandFrameManager> weak_factory_; }; diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_input_controller.cc b/chromium/ui/ozone/platform/wayland/host/wayland_input_controller.cc index 87c79997a44..d320c7d4a4e 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_input_controller.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_input_controller.cc @@ -4,6 +4,7 @@ #include "ui/ozone/platform/wayland/host/wayland_input_controller.h" +#include "base/memory/raw_ptr.h" #include "ui/events/devices/haptic_touchpad_effects.h" #include "ui/events/devices/stylus_state.h" #include "ui/ozone/platform/wayland/host/wayland_connection.h" @@ -112,7 +113,7 @@ class WaylandInputController : public InputController { } private: - WaylandConnection* const connection_; + const raw_ptr<WaylandConnection> connection_; }; } // namespace 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 54c4c61800e..778dfc036bb 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 @@ -39,7 +39,7 @@ #if BUILDFLAG(IS_CHROMEOS_LACROS) #include "base/check.h" #include "chromeos/crosapi/mojom/crosapi.mojom.h" -#include "chromeos/startup/browser_init_params.h" +#include "chromeos/startup/browser_params_proxy.h" #endif namespace ui { @@ -75,10 +75,10 @@ bool IsImeEnabled() { // 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 crosapi::mojom::BrowserInitParams* init_params = - chromeos::BrowserInitParams::Get(); - if (init_params && init_params->exo_ime_support != - crosapi::mojom::ExoImeSupport::kUnsupported) { + const chromeos::BrowserParamsProxy* init_params = + chromeos::BrowserParamsProxy::Get(); + if (init_params->ExoImeSupport() != + crosapi::mojom::ExoImeSupport::kUnsupported) { return true; } #endif @@ -122,12 +122,10 @@ ConvertStyle(uint32_t style) { WaylandInputMethodContext::WaylandInputMethodContext( WaylandConnection* connection, WaylandKeyboard::Delegate* key_delegate, - LinuxInputMethodContextDelegate* ime_delegate, - bool is_simple) + LinuxInputMethodContextDelegate* ime_delegate) : connection_(connection), key_delegate_(key_delegate), ime_delegate_(ime_delegate), - is_simple_(is_simple), text_input_(nullptr) { connection_->wayland_window_manager()->AddObserver(this); Init(); @@ -135,8 +133,8 @@ WaylandInputMethodContext::WaylandInputMethodContext( WaylandInputMethodContext::~WaylandInputMethodContext() { if (text_input_) { + DismissVirtualKeyboard(); text_input_->Deactivate(); - text_input_->HideInputPanel(); } connection_->wayland_window_manager()->RemoveObserver(this); } @@ -147,7 +145,7 @@ void WaylandInputMethodContext::Init(bool initialize_for_testing) { // 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. - if (use_ozone_wayland_vkb && !is_simple_ && !text_input_ && + if (use_ozone_wayland_vkb && !text_input_ && connection_->text_input_manager_v1()) { text_input_ = std::make_unique<ZWPTextInputWrapperV1>( connection_, this, connection_->text_input_manager_v1(), @@ -209,32 +207,24 @@ void WaylandInputMethodContext::Reset() { void WaylandInputMethodContext::UpdateFocus(bool has_client, TextInputType old_type, TextInputType new_type) { - // TODO(b/226781965): Known issue that this does not work. - if (is_simple_) { - // simple context can be used in any textfield, including password box, and - // even if the focused text input client's text input type is - // ui::TEXT_INPUT_TYPE_NONE. - if (has_client) - Focus(); - else - Blur(); - } else { - // Otherwise We only focus when the focus is in a textfield. - if (old_type != TEXT_INPUT_TYPE_NONE) - Blur(); - if (new_type != TEXT_INPUT_TYPE_NONE) - Focus(); - } + // This prevents unnecessarily hiding/showing the virtual keyboard. + bool skip_vk_update = + old_type != TEXT_INPUT_TYPE_NONE && new_type != TEXT_INPUT_TYPE_NONE; + + if (old_type != TEXT_INPUT_TYPE_NONE) + Blur(skip_vk_update); + if (new_type != TEXT_INPUT_TYPE_NONE) + Focus(skip_vk_update); } -void WaylandInputMethodContext::Focus() { +void WaylandInputMethodContext::Focus(bool skip_virtual_keyboard_update) { focused_ = true; - MaybeUpdateActivated(); + MaybeUpdateActivated(skip_virtual_keyboard_update); } -void WaylandInputMethodContext::Blur() { +void WaylandInputMethodContext::Blur(bool skip_virtual_keyboard_update) { focused_ = false; - MaybeUpdateActivated(); + MaybeUpdateActivated(skip_virtual_keyboard_update); } void WaylandInputMethodContext::SetCursorLocation(const gfx::Rect& rect) { @@ -347,6 +337,21 @@ void WaylandInputMethodContext::SetContentType(TextInputType type, text_input_->SetContentType(type, mode, flags, should_do_learning); } +void WaylandInputMethodContext::SetGrammarFragmentAtCursor( + const GrammarFragment& fragment) { + if (!text_input_) + return; + text_input_->SetGrammarFragmentAtCursor(fragment); +} + +void WaylandInputMethodContext::SetAutocorrectInfo( + const gfx::Range& autocorrect_range, + const gfx::Rect& autocorrect_bounds) { + if (!text_input_) + return; + text_input_->SetAutocorrectInfo(autocorrect_range, autocorrect_bounds); +} + VirtualKeyboardController* WaylandInputMethodContext::GetVirtualKeyboardController() { if (!text_input_) @@ -421,9 +426,39 @@ void WaylandInputMethodContext::OnPreeditString( } void WaylandInputMethodContext::OnCommitString(base::StringPiece text) { + if (pending_keep_selection_) { + ime_delegate_->OnConfirmCompositionText(true); + pending_keep_selection_ = false; + return; + } ime_delegate_->OnCommit(base::UTF8ToUTF16(text)); } +void WaylandInputMethodContext::OnCursorPosition(int32_t index, + int32_t anchor) { + if (surrounding_text_.empty()) { + LOG(ERROR) << "SetSurroundingText should run before OnCursorPosition."; + return; + } + + if (index < 0 || static_cast<uint32_t>(index) > surrounding_text_.size()) { + LOG(ERROR) << "Invalid index is specified."; + return; + } + if (anchor < 0 || static_cast<uint32_t>(anchor) > surrounding_text_.size()) { + LOG(ERROR) << "Invalid anchor is specified."; + return; + } + +#if BUILDFLAG(IS_CHROMEOS_LACROS) + if (selection_range_utf8_ == gfx::Range(index, anchor)) { + pending_keep_selection_ = true; + } else { + NOTIMPLEMENTED_LOG_ONCE(); + } +#endif +} + void WaylandInputMethodContext::OnDeleteSurroundingText(int32_t index, uint32_t length) { // |index| and |length| are expected to be in UTF8 form, so we convert these @@ -576,6 +611,33 @@ void WaylandInputMethodContext::OnSetPreeditRegion( ime_text_spans); } +void WaylandInputMethodContext::OnClearGrammarFragments( + const gfx::Range& range) { + std::vector<size_t> offsets = {range.start(), range.end()}; + base::UTF8ToUTF16AndAdjustOffsets(surrounding_text_, &offsets); + ime_delegate_->OnClearGrammarFragments(gfx::Range( + static_cast<uint32_t>(offsets[0]), static_cast<uint32_t>(offsets[1]))); +} + +void WaylandInputMethodContext::OnAddGrammarFragment( + const GrammarFragment& fragment) { + std::vector<size_t> offsets = {fragment.range.start(), fragment.range.end()}; + base::UTF8ToUTF16AndAdjustOffsets(surrounding_text_, &offsets); + ime_delegate_->OnAddGrammarFragment( + {GrammarFragment(gfx::Range(static_cast<uint32_t>(offsets[0]), + static_cast<uint32_t>(offsets[1])), + fragment.suggestion)}); +} + +void WaylandInputMethodContext::OnSetAutocorrectRange(const gfx::Range& range) { + ime_delegate_->OnSetAutocorrectRange(range); +} + +void WaylandInputMethodContext::OnSetVirtualKeyboardOccludedBounds( + const gfx::Rect& screen_bounds) { + ime_delegate_->OnSetVirtualKeyboardOccludedBounds(screen_bounds); +} + void WaylandInputMethodContext::OnInputPanelState(uint32_t state) { virtual_keyboard_visible_ = (state & 1) != 0; // Note: Currently there's no support of VirtualKeyboardControllerObserver. @@ -590,10 +652,11 @@ void WaylandInputMethodContext::OnModifiersMap( } void WaylandInputMethodContext::OnKeyboardFocusedWindowChanged() { - MaybeUpdateActivated(); + MaybeUpdateActivated(false); } -void WaylandInputMethodContext::MaybeUpdateActivated() { +void WaylandInputMethodContext::MaybeUpdateActivated( + bool skip_virtual_keyboard_update) { if (!text_input_) return; @@ -613,10 +676,12 @@ void WaylandInputMethodContext::MaybeUpdateActivated() { activated_ = activated; if (activated) { text_input_->Activate(window); - text_input_->ShowInputPanel(); + if (!skip_virtual_keyboard_update) + DisplayVirtualKeyboard(); } else { + if (!skip_virtual_keyboard_update) + DismissVirtualKeyboard(); text_input_->Deactivate(); - text_input_->HideInputPanel(); } } diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_input_method_context.h b/chromium/ui/ozone/platform/wayland/host/wayland_input_method_context.h index e1954530f0d..24d0a57027e 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_input_method_context.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_input_method_context.h @@ -8,6 +8,7 @@ #include <memory> #include <vector> +#include "base/memory/raw_ptr.h" #include "base/strings/string_piece.h" #include "ui/base/ime/character_composer.h" #include "ui/base/ime/linux/linux_input_method_context.h" @@ -31,8 +32,7 @@ class WaylandInputMethodContext : public LinuxInputMethodContext, WaylandInputMethodContext(WaylandConnection* connection, WaylandKeyboard::Delegate* key_delegate, - LinuxInputMethodContextDelegate* ime_delegate, - bool is_simple); + LinuxInputMethodContextDelegate* ime_delegate); WaylandInputMethodContext(const WaylandInputMethodContext&) = delete; WaylandInputMethodContext& operator=(const WaylandInputMethodContext&) = delete; @@ -55,6 +55,9 @@ class WaylandInputMethodContext : public LinuxInputMethodContext, void UpdateFocus(bool has_client, TextInputType old_type, TextInputType new_type) override; + void SetGrammarFragmentAtCursor(const GrammarFragment& fragment) override; + void SetAutocorrectInfo(const gfx::Range& autocorrect_range, + const gfx::Rect& autocorrect_bounds) override; void Reset() override; VirtualKeyboardController* GetVirtualKeyboardController() override; @@ -73,28 +76,38 @@ class WaylandInputMethodContext : public LinuxInputMethodContext, const std::vector<SpanStyle>& spans, int32_t preedit_cursor) override; void OnCommitString(base::StringPiece text) override; + void OnCursorPosition(int32_t index, int32_t anchor) override; void OnDeleteSurroundingText(int32_t index, uint32_t length) override; void OnKeysym(uint32_t keysym, uint32_t state, uint32_t modifiers) override; void OnSetPreeditRegion(int32_t index, uint32_t length, const std::vector<SpanStyle>& spans) override; + void OnClearGrammarFragments(const gfx::Range& range) override; + void OnAddGrammarFragment(const GrammarFragment& fragment) override; + void OnSetAutocorrectRange(const gfx::Range& range) override; + void OnSetVirtualKeyboardOccludedBounds( + const gfx::Rect& screen_bounds) override; void OnInputPanelState(uint32_t state) override; void OnModifiersMap(std::vector<std::string> modifiers_map) override; private: - void Focus(); - void Blur(); + void Focus(bool skip_virtual_keyboard_update); + void Blur(bool skip_virtual_keyboard_update); void UpdatePreeditText(const std::u16string& preedit_text); - void MaybeUpdateActivated(); + // If |skip_virtual_keyboard_update| is true, no virtual keyboard show/hide + // requests will be sent. This is used to prevent flickering the virtual + // keyboard when it would be immediately reshown anyway, e.g. when changing + // focus from one text input to another. + void MaybeUpdateActivated(bool skip_virtual_keyboard_update); - WaylandConnection* const connection_; // TODO(jani) Handle this better + const raw_ptr<WaylandConnection> + connection_; // TODO(jani) Handle this better // Delegate key events to be injected into PlatformEvent system. - WaylandKeyboard::Delegate* const key_delegate_; + const raw_ptr<WaylandKeyboard::Delegate> key_delegate_; // Delegate IME-specific events to be handled by //ui code. - LinuxInputMethodContextDelegate* const ime_delegate_; - bool is_simple_; + const raw_ptr<LinuxInputMethodContextDelegate> ime_delegate_; std::unique_ptr<ZWPTextInputWrapper> text_input_; @@ -117,6 +130,12 @@ class WaylandInputMethodContext : public LinuxInputMethodContext, // The selection range in UTF-8 offsets in the |surrounding_text_|. gfx::Range selection_range_utf8_ = gfx::Range::InvalidRange(); + // Whether the next CommitString should be treated as part of a + // ConfirmCompositionText operation which keeps the current selection. This + // allows ConfirmCompositionText to be implemented as an atomic operation + // using CursorPosition and CommitString. + bool pending_keep_selection_ = false; + // Caches VirtualKeyboard visibility. bool virtual_keyboard_visible_ = false; diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_input_method_context_factory.cc b/chromium/ui/ozone/platform/wayland/host/wayland_input_method_context_factory.cc deleted file mode 100644 index d95b8430974..00000000000 --- a/chromium/ui/ozone/platform/wayland/host/wayland_input_method_context_factory.cc +++ /dev/null @@ -1,39 +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 "ui/ozone/platform/wayland/host/wayland_input_method_context_factory.h" - -#include <memory> - -#include "base/bind.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_input_method_context.h" - -namespace ui { - -WaylandInputMethodContextFactory::WaylandInputMethodContextFactory( - WaylandConnection* connection) - : connection_(connection) { - DCHECK(connection_); -} - -WaylandInputMethodContextFactory::~WaylandInputMethodContextFactory() = default; - -std::unique_ptr<LinuxInputMethodContext> -WaylandInputMethodContextFactory::CreateInputMethodContext( - LinuxInputMethodContextDelegate* delegate, - bool is_simple) const { - return CreateWaylandInputMethodContext(delegate, is_simple); -} - -std::unique_ptr<WaylandInputMethodContext> -WaylandInputMethodContextFactory::CreateWaylandInputMethodContext( - LinuxInputMethodContextDelegate* delegate, - bool is_simple) const { - return std::make_unique<WaylandInputMethodContext>( - connection_, connection_->event_source(), delegate, is_simple); -} - -} // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_input_method_context_factory.h b/chromium/ui/ozone/platform/wayland/host/wayland_input_method_context_factory.h deleted file mode 100644 index f34ac04f96a..00000000000 --- a/chromium/ui/ozone/platform/wayland/host/wayland_input_method_context_factory.h +++ /dev/null @@ -1,43 +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. - -#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_INPUT_METHOD_CONTEXT_FACTORY_H_ -#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_INPUT_METHOD_CONTEXT_FACTORY_H_ - -#include <memory> - -#include "ui/base/ime/linux/linux_input_method_context_factory.h" - -namespace ui { - -class WaylandConnection; -class WaylandInputMethodContext; - -class WaylandInputMethodContextFactory : public LinuxInputMethodContextFactory { - public: - explicit WaylandInputMethodContextFactory(WaylandConnection* connection); - - WaylandInputMethodContextFactory(const WaylandInputMethodContextFactory&) = - delete; - WaylandInputMethodContextFactory& operator=( - const WaylandInputMethodContextFactory&) = delete; - - ~WaylandInputMethodContextFactory() override; - - std::unique_ptr<LinuxInputMethodContext> CreateInputMethodContext( - LinuxInputMethodContextDelegate* delegate, - bool is_simple) const override; - - // Exposed for unit tests but also called by CreateInputMethodContext - std::unique_ptr<WaylandInputMethodContext> CreateWaylandInputMethodContext( - ui::LinuxInputMethodContextDelegate* delegate, - bool is_simple) const; - - private: - WaylandConnection* const connection_; -}; - -} // namespace ui - -#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_INPUT_METHOD_CONTEXT_FACTORY_H_ diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_input_method_context_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_input_method_context_unittest.cc index 13bc3a347c0..3907d1d89e5 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_input_method_context_unittest.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_input_method_context_unittest.cc @@ -7,6 +7,7 @@ #include <memory> #include "base/i18n/break_iterator.h" +#include "base/memory/raw_ptr.h" #include "base/strings/utf_string_conversions.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -16,8 +17,8 @@ #include "ui/base/ime/text_input_type.h" #include "ui/events/event.h" #include "ui/gfx/range/range.h" +#include "ui/ozone/platform/wayland/host/wayland_event_source.h" #include "ui/ozone/platform/wayland/host/wayland_input_method_context.h" -#include "ui/ozone/platform/wayland/host/wayland_input_method_context_factory.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/mock_zcr_extended_text_input.h" @@ -27,6 +28,7 @@ using ::testing::_; using ::testing::DoAll; +using ::testing::InSequence; using ::testing::Mock; using ::testing::SaveArg; using ::testing::Values; @@ -58,9 +60,21 @@ class TestInputMethodContextDelegate : public LinuxInputMethodContextDelegate { void OnCommit(const std::u16string& text) override { was_on_commit_called_ = true; } + void OnConfirmCompositionText(bool keep_selection) override { + was_on_confirm_composition_text_called_ = true; + } void OnPreeditChanged(const ui::CompositionText& composition_text) override { was_on_preedit_changed_called_ = true; } + void OnClearGrammarFragments(const gfx::Range& range) override { + was_on_clear_grammar_fragments_called_ = true; + } + void OnAddGrammarFragment(const ui::GrammarFragment& fragment) override { + was_on_add_grammar_fragment_called_ = true; + } + void OnSetAutocorrectRange(const gfx::Range& range) override { + was_on_set_autocorrect_range_called_ = true; + } void OnPreeditEnd() override {} void OnPreeditStart() override {} void OnDeleteSurroundingText(size_t before, size_t after) override { @@ -72,8 +86,17 @@ class TestInputMethodContextDelegate : public LinuxInputMethodContextDelegate { was_on_set_preedit_region_called_ = true; } + void OnSetVirtualKeyboardOccludedBounds( + const gfx::Rect& screen_bounds) override { + virtual_keyboard_bounds_ = screen_bounds; + } + bool was_on_commit_called() const { return was_on_commit_called_; } + bool was_on_confirm_composition_text_called() const { + return was_on_confirm_composition_text_called_; + } + bool was_on_preedit_changed_called() const { return was_on_preedit_changed_called_; } @@ -82,17 +105,38 @@ class TestInputMethodContextDelegate : public LinuxInputMethodContextDelegate { return was_on_set_preedit_region_called_; } + bool was_on_clear_grammar_fragments_called() const { + return was_on_clear_grammar_fragments_called_; + } + + bool was_on_add_grammar_fragment_called() const { + return was_on_add_grammar_fragment_called_; + } + + bool was_on_set_autocorrect_range_called() const { + return was_on_set_autocorrect_range_called_; + } + const absl::optional<std::pair<size_t, size_t>>& last_on_delete_surrounding_text_args() const { return last_on_delete_surrounding_text_args_; } + const absl::optional<gfx::Rect>& virtual_keyboard_bounds() const { + return virtual_keyboard_bounds_; + } + private: bool was_on_commit_called_ = false; + bool was_on_confirm_composition_text_called_ = false; bool was_on_preedit_changed_called_ = false; bool was_on_set_preedit_region_called_ = false; + bool was_on_clear_grammar_fragments_called_ = false; + bool was_on_add_grammar_fragment_called_ = false; + bool was_on_set_autocorrect_range_called_ = false; absl::optional<std::pair<size_t, size_t>> last_on_delete_surrounding_text_args_; + absl::optional<gfx::Rect> virtual_keyboard_bounds_; }; class WaylandInputMethodContextTest : public WaylandTest { @@ -121,11 +165,11 @@ class WaylandInputMethodContextTest : public WaylandTest { input_method_context_delegate_ = std::make_unique<TestInputMethodContextDelegate>(); - WaylandInputMethodContextFactory factory(connection_.get()); - LinuxInputMethodContextFactory::SetInstance(&factory); - - input_method_context_ = factory.CreateWaylandInputMethodContext( - input_method_context_delegate_.get(), false); + auto input_method_context = std::make_unique<WaylandInputMethodContext>( + connection_.get(), connection_->event_source(), + input_method_context_delegate_.get()); + input_method_context_.reset(static_cast<WaylandInputMethodContext*>( + input_method_context.release())); input_method_context_->Init(true); connection_->ScheduleFlush(); @@ -146,8 +190,8 @@ class WaylandInputMethodContextTest : public WaylandTest { std::unique_ptr<TestInputMethodContextDelegate> input_method_context_delegate_; std::unique_ptr<WaylandInputMethodContext> input_method_context_; - wl::MockZwpTextInput* zwp_text_input_ = nullptr; - wl::MockZcrExtendedTextInput* zcr_extended_text_input_ = nullptr; + raw_ptr<wl::MockZwpTextInput> zwp_text_input_ = nullptr; + raw_ptr<wl::MockZcrExtendedTextInput> zcr_extended_text_input_ = nullptr; }; TEST_P(WaylandInputMethodContextTest, ActivateDeactivate) { @@ -157,6 +201,7 @@ TEST_P(WaylandInputMethodContextTest, ActivateDeactivate) { // Scenario 1: InputMethod focus is set, then Keyboard focus is set. // Unset them in the reversed order. + InSequence s; EXPECT_CALL(*zwp_text_input_, Activate(surface_->resource())).Times(0); EXPECT_CALL(*zwp_text_input_, ShowInputPanel()).Times(0); input_method_context_->UpdateFocus(true, ui::TEXT_INPUT_TYPE_NONE, @@ -173,15 +218,15 @@ TEST_P(WaylandInputMethodContextTest, ActivateDeactivate) { Sync(); Mock::VerifyAndClearExpectations(zwp_text_input_); - EXPECT_CALL(*zwp_text_input_, Deactivate()); EXPECT_CALL(*zwp_text_input_, HideInputPanel()); + EXPECT_CALL(*zwp_text_input_, Deactivate()); connection_->wayland_window_manager()->SetKeyboardFocusedWindow(nullptr); connection_->ScheduleFlush(); Sync(); Mock::VerifyAndClearExpectations(zwp_text_input_); - EXPECT_CALL(*zwp_text_input_, Deactivate()).Times(0); EXPECT_CALL(*zwp_text_input_, HideInputPanel()).Times(0); + EXPECT_CALL(*zwp_text_input_, Deactivate()).Times(0); input_method_context_->UpdateFocus(true, ui::TEXT_INPUT_TYPE_TEXT, ui::TEXT_INPUT_TYPE_NONE); connection_->ScheduleFlush(); @@ -206,16 +251,16 @@ TEST_P(WaylandInputMethodContextTest, ActivateDeactivate) { Sync(); Mock::VerifyAndClearExpectations(zwp_text_input_); - EXPECT_CALL(*zwp_text_input_, Deactivate()); EXPECT_CALL(*zwp_text_input_, HideInputPanel()); + EXPECT_CALL(*zwp_text_input_, Deactivate()); input_method_context_->UpdateFocus(true, ui::TEXT_INPUT_TYPE_TEXT, ui::TEXT_INPUT_TYPE_NONE); connection_->ScheduleFlush(); Sync(); Mock::VerifyAndClearExpectations(zwp_text_input_); - EXPECT_CALL(*zwp_text_input_, Deactivate()).Times(0); EXPECT_CALL(*zwp_text_input_, HideInputPanel()).Times(0); + EXPECT_CALL(*zwp_text_input_, Deactivate()).Times(0); connection_->wayland_window_manager()->SetKeyboardFocusedWindow(nullptr); connection_->ScheduleFlush(); Sync(); @@ -427,6 +472,35 @@ TEST_P(WaylandInputMethodContextTest, OnCommit) { EXPECT_TRUE(input_method_context_delegate_->was_on_commit_called()); } +// TODO(1353668): WaylandInputMethodContext::OnCursorPosition sets +// |pending_keep_selection| only on lacros. That's the reason why this test +// doesn't pass on Linux. We need to clarify that. +#if BUILDFLAG(IS_CHROMEOS_LACROS) +#define MAYBE(x) x +#else +#define MAYBE(x) DISABLED_##x +#endif + +TEST_P(WaylandInputMethodContextTest, MAYBE(OnConfirmCompositionText)) { + constexpr char16_t text[] = u"ab😀cあdef"; + const gfx::Range range(5, 6); // あ is selected. + + // SetSurroundingText should be called in UTF-8. + EXPECT_CALL(*zwp_text_input_, + SetSurroundingText("ab😀cあdef", gfx::Range(7, 10))); + input_method_context_->SetSurroundingText(text, range); + connection_->ScheduleFlush(); + Sync(); + Mock::VerifyAndClearExpectations(zwp_text_input_); + + zwp_text_input_v1_send_cursor_position(zwp_text_input_->resource(), 7, 10); + zwp_text_input_v1_send_commit_string(zwp_text_input_->resource(), 0, + "ab😀cあdef"); + Sync(); + EXPECT_TRUE( + input_method_context_delegate_->was_on_confirm_composition_text_called()); +} + TEST_P(WaylandInputMethodContextTest, OnSetPreeditRegion_Success) { constexpr char16_t text[] = u"abcあdef"; const gfx::Range range(3, 4); // あ is selected. @@ -514,6 +588,35 @@ TEST_P(WaylandInputMethodContextTest, input_method_context_delegate_->was_on_set_preedit_region_called()); } +TEST_P(WaylandInputMethodContextTest, OnClearGrammarFragments) { + input_method_context_->OnClearGrammarFragments(gfx::Range(1, 5)); + Sync(); + EXPECT_TRUE( + input_method_context_delegate_->was_on_clear_grammar_fragments_called()); +} + +TEST_P(WaylandInputMethodContextTest, OnAddGrammarFragments) { + input_method_context_->OnAddGrammarFragment( + ui::GrammarFragment(gfx::Range(1, 5), "test")); + Sync(); + EXPECT_TRUE( + input_method_context_delegate_->was_on_add_grammar_fragment_called()); +} + +TEST_P(WaylandInputMethodContextTest, OnSetAutocorrectRange) { + input_method_context_->OnSetAutocorrectRange(gfx::Range(1, 5)); + Sync(); + EXPECT_TRUE( + input_method_context_delegate_->was_on_set_autocorrect_range_called()); +} + +TEST_P(WaylandInputMethodContextTest, OnSetVirtualKeyboardOccludedBounds) { + const gfx::Rect bounds(10, 20, 300, 400); + input_method_context_->OnSetVirtualKeyboardOccludedBounds(bounds); + Sync(); + EXPECT_EQ(input_method_context_delegate_->virtual_keyboard_bounds(), bounds); +} + TEST_P(WaylandInputMethodContextTest, DisplayVirtualKeyboard) { EXPECT_CALL(*zwp_text_input_, ShowInputPanel()); EXPECT_TRUE(input_method_context_->DisplayVirtualKeyboard()); @@ -560,6 +663,7 @@ TEST_P(WaylandInputMethodContextNoKeyboardTest, ActivateDeactivate) { // Because there is no keyboard, Activate is called as soon as InputMethod's // TextInputClient focus is met. + InSequence s; EXPECT_CALL(*zwp_text_input_, Activate(surface_->resource())); EXPECT_CALL(*zwp_text_input_, ShowInputPanel()); input_method_context_->UpdateFocus(true, ui::TEXT_INPUT_TYPE_NONE, @@ -568,8 +672,8 @@ TEST_P(WaylandInputMethodContextNoKeyboardTest, ActivateDeactivate) { Sync(); Mock::VerifyAndClearExpectations(zwp_text_input_); - EXPECT_CALL(*zwp_text_input_, Deactivate()); EXPECT_CALL(*zwp_text_input_, HideInputPanel()); + EXPECT_CALL(*zwp_text_input_, Deactivate()); input_method_context_->UpdateFocus(false, ui::TEXT_INPUT_TYPE_TEXT, ui::TEXT_INPUT_TYPE_NONE); connection_->ScheduleFlush(); @@ -577,6 +681,31 @@ TEST_P(WaylandInputMethodContextNoKeyboardTest, ActivateDeactivate) { Mock::VerifyAndClearExpectations(zwp_text_input_); } +TEST_P(WaylandInputMethodContextNoKeyboardTest, UpdateFocusBetweenTextFields) { + // Because there is no keyboard, Activate is called as soon as InputMethod's + // TextInputClient focus is met. + + InSequence s; + EXPECT_CALL(*zwp_text_input_, Activate(surface_->resource())); + EXPECT_CALL(*zwp_text_input_, ShowInputPanel()); + input_method_context_->UpdateFocus(true, ui::TEXT_INPUT_TYPE_NONE, + ui::TEXT_INPUT_TYPE_TEXT); + connection_->ScheduleFlush(); + Sync(); + Mock::VerifyAndClearExpectations(zwp_text_input_); + + // Make sure virtual keyboard is not unnecessarily hidden. + EXPECT_CALL(*zwp_text_input_, HideInputPanel()).Times(0); + EXPECT_CALL(*zwp_text_input_, Deactivate()); + EXPECT_CALL(*zwp_text_input_, Activate(surface_->resource())); + EXPECT_CALL(*zwp_text_input_, ShowInputPanel()).Times(0); + input_method_context_->UpdateFocus(false, ui::TEXT_INPUT_TYPE_TEXT, + ui::TEXT_INPUT_TYPE_TEXT); + connection_->ScheduleFlush(); + Sync(); + Mock::VerifyAndClearExpectations(zwp_text_input_); +} + INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest, WaylandInputMethodContextTest, Values(wl::ServerConfig{ diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.cc b/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.cc index 243944bf6b4..5afac64fe2b 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.cc @@ -12,6 +12,7 @@ #include <utility> #include "base/logging.h" +#include "base/memory/raw_ptr.h" #include "base/memory/ref_counted_memory.h" #include "base/unguessable_token.h" #include "ui/base/buildflags.h" @@ -74,7 +75,7 @@ class WaylandKeyboard::ZCRExtendedKeyboard { serial, time, key, state, WaylandKeyboard::KeyEventKind::kPeekKey); } - WaylandKeyboard* const keyboard_; + const raw_ptr<WaylandKeyboard> keyboard_; wl::Object<zcr_extended_keyboard_v1> obj_; }; @@ -288,8 +289,8 @@ void WaylandKeyboard::OnKey(uint32_t serial, } DispatchKey(key, 0 /*scan_code*/, down, false /*repeat*/, - down ? absl::make_optional(serial) : absl::nullopt, - EventTimeForNow(), device_id(), EF_NONE, kind); + absl::make_optional(serial), EventTimeForNow(), device_id(), + EF_NONE, kind); } void WaylandKeyboard::DispatchKey(unsigned int key, diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.h b/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.h index c49934d7057..9bd0ed1cb31 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_keyboard.h @@ -7,6 +7,7 @@ #include <cstdint> +#include "base/memory/raw_ptr.h" #include "base/time/time.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/base/buildflags.h" @@ -126,8 +127,8 @@ class WaylandKeyboard : public EventAutoRepeatHandler::Delegate { wl::Object<wl_keyboard> obj_; std::unique_ptr<ZCRExtendedKeyboard> extended_keyboard_; - WaylandConnection* const connection_; - Delegate* const delegate_; + const raw_ptr<WaylandConnection> connection_; + const raw_ptr<Delegate> delegate_; // Key repeat handler. static const wl_callback_listener callback_listener_; @@ -135,7 +136,7 @@ class WaylandKeyboard : public EventAutoRepeatHandler::Delegate { base::OnceClosure auto_repeat_closure_; wl::Object<wl_callback> sync_callback_; - LayoutEngine* layout_engine_; + raw_ptr<LayoutEngine> layout_engine_; }; class WaylandKeyboard::Delegate { diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_keyboard_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_keyboard_unittest.cc index 3b08e97e8e7..817cb5349be 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_keyboard_unittest.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_keyboard_unittest.cc @@ -6,6 +6,7 @@ #include <wayland-server.h> #include <memory> +#include "base/memory/raw_ptr.h" #include "base/test/test_mock_time_task_runner.h" #include "base/timer/timer.h" #include "testing/gmock/include/gmock/gmock.h" @@ -82,7 +83,7 @@ class WaylandKeyboardTest : public WaylandTest { } protected: - wl::TestKeyboard* keyboard_; + raw_ptr<wl::TestKeyboard> keyboard_; // There may be a pending wl_display_sync event, which is triggered by auto // key repeat and needs to be processed. Wait for its completion. @@ -114,7 +115,7 @@ class WaylandKeyboardTest : public WaylandTest { }; ACTION_P(CloneEvent, ptr) { - *ptr = Event::Clone(*arg0); + *ptr = arg0->Clone(); } TEST_P(WaylandKeyboardTest, Keypress) { @@ -147,81 +148,6 @@ TEST_P(WaylandKeyboardTest, Keypress) { EXPECT_CALL(delegate_, DispatchEvent(_)).Times(0); } -TEST_P(WaylandKeyboardTest, AltModifierKeypress) { - struct wl_array empty; - wl_array_init(&empty); - wl_keyboard_send_enter(keyboard_->resource(), 1, surface_->resource(), - &empty); - wl_array_release(&empty); - - // Alt - wl_keyboard_send_key(keyboard_->resource(), 2, 0, 56 /* left Alt */, - WL_KEYBOARD_KEY_STATE_PRESSED); - - std::unique_ptr<Event> event; - EXPECT_CALL(delegate_, DispatchEvent(_)).WillOnce(CloneEvent(&event)); - - Sync(); - ASSERT_TRUE(event); - ASSERT_TRUE(event->IsKeyEvent()); - - auto* key_event = event->AsKeyEvent(); - - EXPECT_EQ(ui::EF_ALT_DOWN, key_event->flags()); - EXPECT_EQ(ui::VKEY_MENU, key_event->key_code()); - EXPECT_EQ(ET_KEY_PRESSED, key_event->type()); -} - -TEST_P(WaylandKeyboardTest, ControlModifierKeypress) { - struct wl_array empty; - wl_array_init(&empty); - wl_keyboard_send_enter(keyboard_->resource(), 1, surface_->resource(), - &empty); - wl_array_release(&empty); - - // Control - wl_keyboard_send_key(keyboard_->resource(), 2, 0, 29 /* left Control */, - WL_KEYBOARD_KEY_STATE_PRESSED); - - std::unique_ptr<Event> event; - EXPECT_CALL(delegate_, DispatchEvent(_)).WillOnce(CloneEvent(&event)); - - Sync(); - ASSERT_TRUE(event); - ASSERT_TRUE(event->IsKeyEvent()); - - auto* key_event = event->AsKeyEvent(); - - EXPECT_EQ(ui::EF_CONTROL_DOWN, key_event->flags()); - EXPECT_EQ(ui::VKEY_CONTROL, key_event->key_code()); - EXPECT_EQ(ET_KEY_PRESSED, key_event->type()); -} - -TEST_P(WaylandKeyboardTest, ShiftModifierKeypress) { - struct wl_array empty; - wl_array_init(&empty); - wl_keyboard_send_enter(keyboard_->resource(), 1, surface_->resource(), - &empty); - wl_array_release(&empty); - - // Shift - wl_keyboard_send_key(keyboard_->resource(), 2, 0, 42 /* left Shift */, - WL_KEYBOARD_KEY_STATE_PRESSED); - - std::unique_ptr<Event> event; - EXPECT_CALL(delegate_, DispatchEvent(_)).WillOnce(CloneEvent(&event)); - - Sync(); - ASSERT_TRUE(event); - ASSERT_TRUE(event->IsKeyEvent()); - - auto* key_event = event->AsKeyEvent(); - - EXPECT_EQ(ui::EF_SHIFT_DOWN, key_event->flags()); - EXPECT_EQ(ui::VKEY_SHIFT, key_event->key_code()); - EXPECT_EQ(ET_KEY_PRESSED, key_event->type()); -} - TEST_P(WaylandKeyboardTest, ControlShiftModifiers) { struct wl_array empty; wl_array_init(&empty); @@ -274,50 +200,6 @@ TEST_P(WaylandKeyboardTest, ControlShiftModifiers) { EXPECT_EQ(ET_KEY_PRESSED, key_event3->type()); } -TEST_P(WaylandKeyboardTest, CapsLockKeypress) { - struct wl_array empty; - wl_array_init(&empty); - wl_array_init(&empty); - wl_keyboard_send_enter(keyboard_->resource(), 1, surface_->resource(), - &empty); - wl_array_release(&empty); - - // Capslock - wl_keyboard_send_key(keyboard_->resource(), 2, 0, 58 /* Capslock */, - WL_KEYBOARD_KEY_STATE_PRESSED); - - std::unique_ptr<Event> event; - EXPECT_CALL(delegate_, DispatchEvent(_)).WillOnce(CloneEvent(&event)); - - Sync(); - ASSERT_TRUE(event); - ASSERT_TRUE(event->IsKeyEvent()); - - auto* key_event = event->AsKeyEvent(); - - EXPECT_EQ(ui::EF_MOD3_DOWN, key_event->flags()); - EXPECT_EQ(ui::VKEY_CAPITAL, key_event->key_code()); - EXPECT_EQ(ET_KEY_PRESSED, key_event->type()); - - Sync(); - - wl_keyboard_send_key(keyboard_->resource(), 2, 0, 58 /* Capslock */, - WL_KEYBOARD_KEY_STATE_RELEASED); - - std::unique_ptr<Event> event2; - EXPECT_CALL(delegate_, DispatchEvent(_)).WillOnce(CloneEvent(&event2)); - - Sync(); - ASSERT_TRUE(event2); - ASSERT_TRUE(event2->IsKeyEvent()); - - auto* key_event2 = event2->AsKeyEvent(); - - EXPECT_EQ(0, key_event2->flags()); - EXPECT_EQ(ui::VKEY_CAPITAL, key_event2->key_code()); - EXPECT_EQ(ET_KEY_RELEASED, key_event2->type()); -} - #if BUILDFLAG(USE_XKBCOMMON) TEST_P(WaylandKeyboardTest, CapsLockModifier) { struct wl_array empty; diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_menu_utils.h b/chromium/ui/ozone/platform/wayland/host/wayland_menu_utils.h index 43d1e859536..bff2f84105d 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_menu_utils.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_menu_utils.h @@ -5,6 +5,7 @@ #ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_MENU_UTILS_H_ #define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_MENU_UTILS_H_ +#include "base/memory/raw_ptr.h" #include "ui/ozone/public/platform_menu_utils.h" namespace ui { @@ -22,7 +23,7 @@ class WaylandMenuUtils : public PlatformMenuUtils { std::string ToDBusKeySym(KeyboardCode code) const override; private: - WaylandConnection* const connection_; + const raw_ptr<WaylandConnection> connection_; }; } // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_output.cc b/chromium/ui/ozone/platform/wayland/host/wayland_output.cc index d6d58296331..49011678f75 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_output.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_output.cc @@ -5,14 +5,19 @@ #include "ui/ozone/platform/wayland/host/wayland_output.h" #include <aura-shell-client-protocol.h> +#include <chrome-color-management-client-protocol.h> #include <xdg-output-unstable-v1-client-protocol.h> #include "base/logging.h" +#include "base/strings/string_util.h" #include "ui/display/display.h" #include "ui/gfx/color_space.h" +#include "ui/ozone/platform/wayland/common/wayland_object.h" #include "ui/ozone/platform/wayland/host/wayland_connection.h" #include "ui/ozone/platform/wayland/host/wayland_output_manager.h" #include "ui/ozone/platform/wayland/host/wayland_zaura_output.h" +#include "ui/ozone/platform/wayland/host/wayland_zcr_color_management_output.h" +#include "ui/ozone/platform/wayland/host/wayland_zcr_color_manager.h" #include "ui/ozone/platform/wayland/host/xdg_output.h" namespace ui { @@ -74,6 +79,13 @@ void WaylandOutput::InitializeZAuraOutput(zaura_shell* aura_shell) { zaura_shell_get_aura_output(aura_shell, output_.get())); } +void WaylandOutput::InitializeColorManagementOutput( + WaylandZcrColorManager* zcr_color_manager) { + DCHECK(!color_management_output_); + color_management_output_ = std::make_unique<WaylandZcrColorManagementOutput>( + zcr_color_manager->CreateColorManagementOutput(output_.get()).release()); +} + void WaylandOutput::Initialize(Delegate* delegate) { DCHECK(!delegate_); delegate_ = delegate; @@ -114,10 +126,22 @@ gfx::Insets WaylandOutput::insets() const { return aura_output_ ? aura_output_->insets() : gfx::Insets(); } +const std::string& WaylandOutput::label() const { + return xdg_output_ ? xdg_output_->description() : base::EmptyString(); +} + +const std::string& WaylandOutput::name() const { + return xdg_output_ ? xdg_output_->name() : base::EmptyString(); +} + zaura_output* WaylandOutput::get_zaura_output() { return aura_output_ ? aura_output_->wl_object() : nullptr; } +void WaylandOutput::SetScaleFactorForTesting(float scale_factor) { + scale_factor_ = scale_factor; +} + void WaylandOutput::TriggerDelegateNotifications() { if (xdg_output_ && connection_->surface_submission_in_pixel_coordinates()) { DCHECK(!physical_size_.IsEmpty()); @@ -132,9 +156,9 @@ void WaylandOutput::TriggerDelegateNotifications() { scale_factor_ = max_physical_side / max_logical_side; } } - delegate_->OnOutputHandleMetrics(output_id_, origin(), logical_size(), - physical_size_, insets(), scale_factor_, - panel_transform_, logical_transform()); + delegate_->OnOutputHandleMetrics( + output_id_, origin(), logical_size(), physical_size_, insets(), + scale_factor_, panel_transform_, logical_transform(), label()); } // static diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_output.h b/chromium/ui/ozone/platform/wayland/host/wayland_output.h index c9571ccc43c..f6e95130aa8 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_output.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_output.h @@ -7,6 +7,7 @@ #include <stdint.h> +#include "base/memory/raw_ptr.h" #include "ui/display/types/display_snapshot.h" #include "ui/display/types/native_display_delegate.h" #include "ui/gfx/geometry/rect.h" @@ -15,6 +16,8 @@ namespace ui { class XDGOutput; +class WaylandZcrColorManager; +class WaylandZcrColorManagementOutput; class WaylandConnection; class WaylandZAuraOutput; @@ -39,7 +42,8 @@ class WaylandOutput : public wl::GlobalObjectRegistrar<WaylandOutput> { const gfx::Insets& insets, float scale_factor, int32_t panel_transform, - int32_t logical_transform) = 0; + int32_t logical_transform, + const std::string& label) = 0; protected: virtual ~Delegate() = default; @@ -57,6 +61,7 @@ class WaylandOutput : public wl::GlobalObjectRegistrar<WaylandOutput> { void Initialize(Delegate* delegate); void InitializeXdgOutput(struct zxdg_output_manager_v1* manager); void InitializeZAuraOutput(zaura_shell* aura_shell); + void InitializeColorManagementOutput(WaylandZcrColorManager* manager); float GetUIScaleFactor() const; uint32_t output_id() const { return output_id_; } @@ -68,6 +73,11 @@ class WaylandOutput : public wl::GlobalObjectRegistrar<WaylandOutput> { gfx::Size logical_size() const; gfx::Size physical_size() const { return physical_size_; } gfx::Insets insets() const; + const std::string& label() const; + const std::string& name() const; + WaylandZcrColorManagementOutput* color_management_output() const { + return color_management_output_.get(); + } // Tells if the output has already received physical screen dimensions in the // global compositor space. @@ -76,6 +86,8 @@ class WaylandOutput : public wl::GlobalObjectRegistrar<WaylandOutput> { wl_output* get_output() { return output_.get(); } zaura_output* get_zaura_output(); + void SetScaleFactorForTesting(float scale_factor); + private: static constexpr int32_t kDefaultScaleFactor = 1; @@ -109,6 +121,7 @@ class WaylandOutput : public wl::GlobalObjectRegistrar<WaylandOutput> { wl::Object<wl_output> output_; std::unique_ptr<XDGOutput> xdg_output_; std::unique_ptr<WaylandZAuraOutput> aura_output_; + std::unique_ptr<WaylandZcrColorManagementOutput> color_management_output_; float scale_factor_ = kDefaultScaleFactor; int32_t panel_transform_ = WL_OUTPUT_TRANSFORM_NORMAL; // Origin of the output in DIP screen coordinate. @@ -116,8 +129,8 @@ class WaylandOutput : public wl::GlobalObjectRegistrar<WaylandOutput> { // Size of the output in physical pixels. gfx::Size physical_size_; - Delegate* delegate_ = nullptr; - WaylandConnection* connection_ = nullptr; + raw_ptr<Delegate> delegate_ = nullptr; + raw_ptr<WaylandConnection> connection_ = nullptr; }; } // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_output_manager.cc b/chromium/ui/ozone/platform/wayland/host/wayland_output_manager.cc index 87542ed0640..52d4e4eec4a 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_output_manager.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_output_manager.cc @@ -50,6 +50,10 @@ void WaylandOutputManager::AddWaylandOutput(uint32_t output_id, wayland_output->InitializeZAuraOutput( connection_->zaura_shell()->wl_object()); } + if (connection_->zcr_color_manager()) { + wayland_output->InitializeColorManagementOutput( + connection_->zcr_color_manager()); + } DCHECK(!wayland_output->is_ready()); output_list_[output_id] = std::move(wayland_output); @@ -87,6 +91,13 @@ void WaylandOutputManager::InitializeAllZAuraOutputs() { } } +void WaylandOutputManager::InitializeAllColorManagementOutputs() { + DCHECK(connection_->zcr_color_manager()); + for (const auto& output : output_list_) + output.second->InitializeColorManagementOutput( + connection_->zcr_color_manager()); +} + std::unique_ptr<WaylandScreen> WaylandOutputManager::CreateWaylandScreen() { auto wayland_screen = std::make_unique<WaylandScreen>(connection_); wayland_screen_ = wayland_screen->GetWeakPtr(); @@ -109,7 +120,8 @@ void WaylandOutputManager::InitWaylandScreen(WaylandScreen* screen) { output.second->output_id(), output.second->origin(), output.second->logical_size(), output.second->physical_size(), output.second->insets(), output.second->scale_factor(), - output.second->panel_transform(), output.second->logical_transform()); + output.second->panel_transform(), output.second->logical_transform(), + output.second->label()); } } } @@ -128,6 +140,11 @@ WaylandOutput* WaylandOutputManager::GetPrimaryOutput() const { return nullptr; } +const WaylandOutputManager::OutputList& WaylandOutputManager::GetAllOutputs() + const { + return output_list_; +} + void WaylandOutputManager::OnOutputHandleMetrics(uint32_t output_id, const gfx::Point& origin, const gfx::Size& logical_size, @@ -135,15 +152,25 @@ void WaylandOutputManager::OnOutputHandleMetrics(uint32_t output_id, const gfx::Insets& insets, float scale_factor, int32_t panel_transform, - int32_t logical_transform) { + int32_t logical_transform, + const std::string& label) { if (wayland_screen_) { - wayland_screen_->OnOutputAddedOrUpdated(output_id, origin, logical_size, - physical_size, insets, scale_factor, - panel_transform, logical_transform); + wayland_screen_->OnOutputAddedOrUpdated( + output_id, origin, logical_size, physical_size, insets, scale_factor, + panel_transform, logical_transform, label); + } + + // Update scale of the windows currently associated with |output_id|. i.e: + // the ones whose GetPreferredEnteredOutputId() returns |output_id|; or those + // which have not yet entered any output (i.e: no wl_surface.enter event + // received for their root surface) and |output_id| is the primary output. + const bool is_primary = + wayland_screen_ && output_id == wayland_screen_->GetPrimaryDisplay().id(); + for (auto* window : connection_->wayland_window_manager()->GetAllWindows()) { + uint32_t entered_output = window->GetPreferredEnteredOutputId(); + if (entered_output == output_id || (!entered_output && is_primary)) + window->UpdateWindowScale(true); } - auto* wayland_window_manager = connection_->wayland_window_manager(); - for (auto* window : wayland_window_manager->GetWindowsOnOutput(output_id)) - window->UpdateWindowScale(true); } } // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_output_manager.h b/chromium/ui/ozone/platform/wayland/host/wayland_output_manager.h index 23a34a88066..e3b7d55457c 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_output_manager.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_output_manager.h @@ -5,6 +5,7 @@ #ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_OUTPUT_MANAGER_H_ #define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_OUTPUT_MANAGER_H_ +#include "base/memory/raw_ptr.h" #include "ui/ozone/platform/wayland/common/wayland_object.h" #include <memory> @@ -23,6 +24,8 @@ class WaylandOutput; class WaylandOutputManager : public WaylandOutput::Delegate { public: + using OutputList = base::flat_map<uint32_t, std::unique_ptr<WaylandOutput>>; + explicit WaylandOutputManager(WaylandConnection* connection); WaylandOutputManager(const WaylandOutputManager&) = delete; @@ -39,6 +42,7 @@ class WaylandOutputManager : public WaylandOutput::Delegate { void InitializeAllXdgOutputs(); void InitializeAllZAuraOutputs(); + void InitializeAllColorManagementOutputs(); // Creates a platform screen. std::unique_ptr<WaylandScreen> CreateWaylandScreen(); @@ -48,6 +52,7 @@ class WaylandOutputManager : public WaylandOutput::Delegate { WaylandOutput* GetOutput(uint32_t id) const; WaylandOutput* GetPrimaryOutput() const; + const OutputList& GetAllOutputs() const; WaylandScreen* wayland_screen() const { return wayland_screen_.get(); } @@ -60,13 +65,12 @@ class WaylandOutputManager : public WaylandOutput::Delegate { const gfx::Insets& insets, float scale_factor, int32_t panel_transform, - int32_t logical_transform) override; - - using OutputList = base::flat_map<uint32_t, std::unique_ptr<WaylandOutput>>; + int32_t logical_transform, + const std::string& label) override; OutputList output_list_; - WaylandConnection* const connection_; + const raw_ptr<WaylandConnection> connection_; // Non-owned wayland screen instance. base::WeakPtr<WaylandScreen> wayland_screen_; diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_pointer.cc b/chromium/ui/ozone/platform/wayland/host/wayland_pointer.cc index d9504ae4926..f0fa9e7799a 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_pointer.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_pointer.cc @@ -11,6 +11,7 @@ #include "ui/events/types/event_type.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_serial_tracker.h" #include "ui/ozone/platform/wayland/host/wayland_window.h" @@ -35,7 +36,8 @@ WaylandPointer::~WaylandPointer() { // 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_->OnPointerFocusChanged(nullptr, {}, + wl::EventDispatchPolicy::kImmediate); delegate_->OnResetPointerFlags(); } @@ -46,8 +48,7 @@ void WaylandPointer::Enter(void* data, wl_surface* surface, wl_fixed_t surface_x, wl_fixed_t surface_y) { - DCHECK(data); - WaylandPointer* pointer = static_cast<WaylandPointer*>(data); + auto* pointer = static_cast<WaylandPointer*>(data); pointer->connection_->serial_tracker().UpdateSerial( wl::SerialType::kMouseEnter, serial); @@ -56,7 +57,8 @@ void WaylandPointer::Enter(void* data, static_cast<float>(wl_fixed_to_double(surface_y))}; pointer->delegate_->OnPointerFocusChanged( - window, pointer->connection_->MaybeConvertLocation(location, window)); + window, pointer->connection_->MaybeConvertLocation(location, window), + wl::EventDispatchPolicy::kOnFrame); } // static @@ -64,13 +66,16 @@ void WaylandPointer::Leave(void* data, wl_pointer* obj, uint32_t serial, wl_surface* surface) { - DCHECK(data); - WaylandPointer* pointer = static_cast<WaylandPointer*>(data); + auto* pointer = static_cast<WaylandPointer*>(data); pointer->connection_->serial_tracker().ResetSerial( wl::SerialType::kMouseEnter); + // TODO(https://crrev.com/c/1352584): Switch from kImmediate to kOnFrame when + // Exo comply with other compositors in how it isolates each + // wl_pointer.enter|leave event with their respective wl_pointer.frame. pointer->delegate_->OnPointerFocusChanged( - nullptr, pointer->delegate_->GetPointerLocation()); + nullptr, pointer->delegate_->GetPointerLocation(), + wl::EventDispatchPolicy::kImmediate); } // static @@ -79,7 +84,7 @@ void WaylandPointer::Motion(void* data, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) { - WaylandPointer* pointer = static_cast<WaylandPointer*>(data); + auto* pointer = static_cast<WaylandPointer*>(data); gfx::PointF location(wl_fixed_to_double(surface_x), wl_fixed_to_double(surface_y)); const WaylandWindow* target = pointer->delegate_->GetPointerTarget(); @@ -95,7 +100,7 @@ void WaylandPointer::Button(void* data, uint32_t time, uint32_t button, uint32_t state) { - WaylandPointer* pointer = static_cast<WaylandPointer*>(data); + auto* pointer = static_cast<WaylandPointer*>(data); int changed_button; switch (button) { case BTN_LEFT: @@ -135,7 +140,7 @@ void WaylandPointer::Axis(void* data, uint32_t axis, wl_fixed_t value) { static const double kAxisValueScale = 10.0; - WaylandPointer* pointer = static_cast<WaylandPointer*>(data); + auto* pointer = static_cast<WaylandPointer*>(data); gfx::Vector2dF offset; // Wayland compositors send axis events with values in the surface coordinate // space. They send a value of 10 per mouse wheel click by convention, so @@ -163,7 +168,7 @@ void WaylandPointer::Axis(void* data, // static void WaylandPointer::Frame(void* data, wl_pointer* obj) { - WaylandPointer* pointer = static_cast<WaylandPointer*>(data); + auto* pointer = static_cast<WaylandPointer*>(data); // The frame event ends the sequence of pointer events. Clear the flag. The // next frame will set it when necessary. pointer->axis_source_received_ = false; @@ -174,7 +179,7 @@ void WaylandPointer::Frame(void* data, wl_pointer* obj) { void WaylandPointer::AxisSource(void* data, wl_pointer* obj, uint32_t axis_source) { - WaylandPointer* pointer = static_cast<WaylandPointer*>(data); + auto* pointer = static_cast<WaylandPointer*>(data); pointer->axis_source_received_ = true; pointer->delegate_->OnPointerAxisSourceEvent(axis_source); } @@ -184,7 +189,7 @@ void WaylandPointer::AxisStop(void* data, wl_pointer* obj, uint32_t time, uint32_t axis) { - WaylandPointer* pointer = static_cast<WaylandPointer*>(data); + auto* pointer = static_cast<WaylandPointer*>(data); pointer->delegate_->OnPointerAxisStopEvent(axis); } diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_pointer.h b/chromium/ui/ozone/platform/wayland/host/wayland_pointer.h index cdc03785927..d1789a17c8b 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_pointer.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_pointer.h @@ -7,6 +7,7 @@ #include <cstdint> +#include "base/memory/raw_ptr.h" #include "ui/events/event_constants.h" #include "ui/events/types/event_type.h" #include "ui/ozone/platform/wayland/common/wayland_object.h" @@ -16,6 +17,10 @@ class PointF; class Vector2dF; } // namespace gfx +namespace wl { +enum class EventDispatchPolicy; +} // namespace wl + namespace ui { class WaylandConnection; @@ -94,8 +99,8 @@ class WaylandPointer { wl::Object<wl_pointer> obj_; wl::Object<zcr_pointer_stylus_v2> zcr_pointer_stylus_v2_; - WaylandConnection* const connection_; - Delegate* const delegate_; + const raw_ptr<WaylandConnection> connection_; + const raw_ptr<Delegate> delegate_; // Whether the axis source event has been received for the current frame. // @@ -108,8 +113,10 @@ class WaylandPointer { class WaylandPointer::Delegate { public: - virtual void OnPointerFocusChanged(WaylandWindow* window, - const gfx::PointF& location) = 0; + virtual void OnPointerFocusChanged( + WaylandWindow* window, + const gfx::PointF& location, + wl::EventDispatchPolicy dispatch_policy) = 0; virtual void OnPointerButtonEvent(EventType evtype, int changed_button, WaylandWindow* window = nullptr) = 0; 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 e92b65da074..3b563cd7f71 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc @@ -8,6 +8,7 @@ #include <cmath> #include <memory> +#include "base/memory/raw_ptr.h" #include "base/memory/scoped_refptr.h" #include "build/chromeos_buildflags.h" #include "testing/gmock/include/gmock/gmock.h" @@ -60,7 +61,7 @@ class WaylandPointerTest : public WaylandTest { } protected: - wl::MockPointer* pointer_; + raw_ptr<wl::MockPointer> pointer_; }; void SendAxisEvents(struct wl_resource* resource, @@ -93,11 +94,12 @@ void SendAxisStopEvents(struct wl_resource* resource, uint32_t time) { } ACTION_P(CloneEvent, ptr) { - *ptr = Event::Clone(*arg0); + *ptr = arg0->Clone(); } TEST_P(WaylandPointerTest, Enter) { wl_pointer_send_enter(pointer_->resource(), 1, surface_->resource(), 0, 0); + wl_pointer_send_frame(pointer_->resource()); std::unique_ptr<Event> event; EXPECT_CALL(delegate_, DispatchEvent(_)).WillOnce(CloneEvent(&event)); @@ -133,12 +135,19 @@ TEST_P(WaylandPointerTest, Leave) { ASSERT_TRUE(other_surface); wl_pointer_send_enter(pointer_->resource(), 1, surface_->resource(), 0, 0); + wl_pointer_send_frame(pointer_->resource()); + wl_pointer_send_leave(pointer_->resource(), 2, surface_->resource()); + wl_pointer_send_frame(pointer_->resource()); + wl_pointer_send_enter(pointer_->resource(), 3, other_surface->resource(), 0, 0); + wl_pointer_send_frame(pointer_->resource()); + wl_pointer_send_button(pointer_->resource(), 4, 1004, BTN_LEFT, WL_POINTER_BUTTON_STATE_PRESSED); EXPECT_CALL(delegate_, DispatchEvent(_)).Times(2); + EXPECT_CALL(other_delegate, DispatchEvent(_)).Times(2); // Do an extra Sync() here so that we process the second enter event before we // destroy |other_window|. @@ -147,7 +156,7 @@ TEST_P(WaylandPointerTest, Leave) { ACTION_P3(CloneEventAndCheckCapture, window, result, ptr) { ASSERT_TRUE(window->HasCapture() == result); - *ptr = Event::Clone(*arg0); + *ptr = arg0->Clone(); } TEST_P(WaylandPointerTest, Motion) { @@ -203,6 +212,7 @@ TEST_P(WaylandPointerTest, MotionDragged) { TEST_P(WaylandPointerTest, AxisSourceTypes) { uint32_t time = 1001; wl_pointer_send_enter(pointer_->resource(), 1, surface_->resource(), 0, 0); + wl_pointer_send_frame(pointer_->resource()); Sync(); // We're interested only in checking axis source types events in this // test case, so skip Enter event here. @@ -249,7 +259,7 @@ TEST_P(WaylandPointerTest, AxisSourceTypes) { TEST_P(WaylandPointerTest, Axis) { wl_pointer_send_enter(pointer_->resource(), 1, surface_->resource(), wl_fixed_from_int(0), wl_fixed_from_int(0)); - + wl_pointer_send_frame(pointer_->resource()); Sync(); for (uint32_t axis : @@ -288,6 +298,7 @@ TEST_P(WaylandPointerTest, Axis) { TEST_P(WaylandPointerTest, SetBitmap) { wl_pointer_send_enter(pointer_->resource(), 1, surface_->resource(), wl_fixed_from_int(10), wl_fixed_from_int(10)); + wl_pointer_send_frame(pointer_->resource()); Sync(); SkBitmap dummy_cursor; @@ -329,6 +340,7 @@ TEST_P(WaylandPointerTest, SetBitmapAndScaleOnPointerFocus) { wl_pointer_send_enter(pointer_->resource(), ++serial, surface_->resource(), wl_fixed_from_int(10), wl_fixed_from_int(10)); + wl_pointer_send_frame(pointer_->resource()); Sync(); // Set a cursor. @@ -339,6 +351,7 @@ TEST_P(WaylandPointerTest, SetBitmapAndScaleOnPointerFocus) { connection_->ScheduleFlush(); wl_pointer_send_leave(pointer_->resource(), ++serial, surface_->resource()); + wl_pointer_send_frame(pointer_->resource()); Sync(); Mock::VerifyAndClearExpectations(pointer_); @@ -351,6 +364,7 @@ TEST_P(WaylandPointerTest, SetBitmapAndScaleOnPointerFocus) { EXPECT_CALL(*pointer_, SetCursor(Ne(nullptr), 5, 8)); wl_pointer_send_enter(pointer_->resource(), ++serial, surface_->resource(), wl_fixed_from_int(50), wl_fixed_from_int(75)); + wl_pointer_send_frame(pointer_->resource()); Sync(); connection_->ScheduleFlush(); @@ -360,6 +374,7 @@ TEST_P(WaylandPointerTest, SetBitmapAndScaleOnPointerFocus) { // Reset the focus for the next iteration. wl_pointer_send_leave(pointer_->resource(), ++serial, surface_->resource()); + wl_pointer_send_frame(pointer_->resource()); Sync(); connection_->ScheduleFlush(); Sync(); @@ -373,9 +388,10 @@ TEST_P(WaylandPointerTest, FlingVertical) { uint32_t time = 1001; wl_pointer_send_enter(pointer_->resource(), ++serial, surface_->resource(), wl_fixed_from_int(50), wl_fixed_from_int(75)); + wl_pointer_send_frame(pointer_->resource()); + wl_pointer_send_button(pointer_->resource(), ++serial, ++time, BTN_RIGHT, WL_POINTER_BUTTON_STATE_PRESSED); - Sync(); std::unique_ptr<Event> event1, event2, event3; @@ -427,9 +443,10 @@ TEST_P(WaylandPointerTest, FlingHorizontal) { uint32_t time = 1001; wl_pointer_send_enter(pointer_->resource(), ++serial, surface_->resource(), wl_fixed_from_int(50), wl_fixed_from_int(75)); + wl_pointer_send_frame(pointer_->resource()); + wl_pointer_send_button(pointer_->resource(), ++serial, ++time, BTN_RIGHT, WL_POINTER_BUTTON_STATE_PRESSED); - Sync(); std::unique_ptr<Event> event1, event2, event3; @@ -481,9 +498,10 @@ TEST_P(WaylandPointerTest, FlingCancel) { uint32_t time = 1001; wl_pointer_send_enter(pointer_->resource(), ++serial, surface_->resource(), wl_fixed_from_int(50), wl_fixed_from_int(75)); + wl_pointer_send_frame(pointer_->resource()); + wl_pointer_send_button(pointer_->resource(), ++serial, ++time, BTN_RIGHT, WL_POINTER_BUTTON_STATE_PRESSED); - Sync(); std::unique_ptr<Event> event1, event2, event3, event4; @@ -547,9 +565,10 @@ TEST_P(WaylandPointerTest, FlingDiagonal) { uint32_t time = 1001; wl_pointer_send_enter(pointer_->resource(), ++serial, surface_->resource(), wl_fixed_from_int(50), wl_fixed_from_int(75)); + wl_pointer_send_frame(pointer_->resource()); + wl_pointer_send_button(pointer_->resource(), ++serial, ++time, BTN_RIGHT, WL_POINTER_BUTTON_STATE_PRESSED); - Sync(); std::unique_ptr<Event> event1, event2, event3; diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_popup.cc b/chromium/ui/ozone/platform/wayland/host/wayland_popup.cc index 0582949b270..e5e32efdbce 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_popup.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_popup.cc @@ -50,12 +50,15 @@ bool WaylandPopup::CreateShellPopup() { params.bounds = bounds_dip; params.menu_type = delegate()->GetMenuType().value_or(MenuType::kRootContextMenu); - params.anchor = delegate()->GetOwnedWindowAnchorAndRectInPx(); + params.anchor = delegate()->GetOwnedWindowAnchorAndRectInDIP(); if (params.anchor.has_value()) { - // TODO(crbug.com/1306688): Change anchor_rect to DIP. + // The anchor should originate from the window geometry, not from the + // surface. See https://crbug.com/1292486. params.anchor->anchor_rect = - delegate()->ConvertRectToDIP(wl::TranslateBoundsToParentCoordinates( - params.anchor->anchor_rect, parent_window()->GetBoundsInPixels())); + wl::TranslateBoundsToParentCoordinates( + params.anchor->anchor_rect, parent_window()->GetBoundsInDIP()) - + parent_window()->GetWindowGeometryOffsetInDIP(); + // If size is empty, set 1x1. if (params.anchor->anchor_rect.size().IsEmpty()) params.anchor->anchor_rect.set_size({1, 1}); @@ -73,29 +76,33 @@ bool WaylandPopup::CreateShellPopup() { return false; } - const auto parent_insets_px = parent_window()->frame_insets_px(); - if (parent_insets_px && !parent_insets_px->IsEmpty()) { - set_frame_insets_px(*parent_insets_px); - // Popups should have the same offset for their geometry as their parents - // have, otherwise Wayland draws them incorrectly. - const gfx::Point p = gfx::ScaleToRoundedPoint( - {parent_insets_px->left(), parent_insets_px->top()}, - 1.f / window_scale()); - shell_popup_->SetWindowGeometry( - {p.x(), p.y(), params.bounds.width(), params.bounds.height()}); - } - parent_window()->set_child_window(this); - InitializeAuraShellSurface(); + UpdateDecoration(); return true; } -void WaylandPopup::InitializeAuraShellSurface() { +void WaylandPopup::UpdateDecoration() { DCHECK(shell_popup_); - if (!connection()->zaura_shell() || aura_surface_) + + // If the surface is already decorated early return. + if (!connection()->zaura_shell() || decorated_via_aura_popup_) + return; + + // Decorate the surface using the newer protocol. Relies on Ash >= M105. + if (shell_popup_->SupportsDecoration()) { + decorated_via_aura_popup_ = true; + shell_popup_->Decorate(); return; - aura_surface_.reset(zaura_shell_get_aura_surface( - connection()->zaura_shell()->wl_object(), root_surface()->surface())); + } + + // Decorate the frame using the older protocol. Can be removed once Lacros >= + // M107. Reshown popups will not be decorated if |aura_surface_| isn't reset + // when server implements the older protocol. + if (!aura_surface_) { + 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); @@ -129,10 +136,17 @@ void WaylandPopup::Hide() { child_window()->Hide(); WaylandWindow::Hide(); + if (aura_surface_ && wl::get_version_of_object(aura_surface_.get()) >= + ZAURA_SURFACE_RELEASE_SINCE_VERSION) { + aura_surface_.reset(); + } + if (shell_popup_) { parent_window()->set_child_window(nullptr); shell_popup_.reset(); + decorated_via_aura_popup_ = false; } + connection()->ScheduleFlush(); } @@ -140,9 +154,9 @@ bool WaylandPopup::IsVisible() const { return !!shell_popup_; } -void WaylandPopup::SetBoundsInPixels(const gfx::Rect& bounds_dip) { +void WaylandPopup::SetBoundsInDIP(const gfx::Rect& bounds_dip) { auto old_bounds_dip = GetBoundsInDIP(); - WaylandWindow::SetBoundsInPixels(bounds_dip); + WaylandWindow::SetBoundsInDIP(bounds_dip); // The shell popup can be null if bounds are being fixed during // the initialization. See WaylandPopup::CreateShellPopup. @@ -173,31 +187,35 @@ void WaylandPopup::SetBoundsInPixels(const gfx::Rect& bounds_dip) { } void WaylandPopup::HandlePopupConfigure(const gfx::Rect& bounds_dip) { + gfx::Rect pending_bounds_dip(bounds_dip); + if (pending_bounds_dip.IsEmpty()) + pending_bounds_dip.set_size(GetBoundsInDIP().size()); set_pending_bounds_dip(wl::TranslateBoundsToTopLevelCoordinates( - bounds_dip, parent_window()->GetBoundsInDIP())); + pending_bounds_dip, parent_window()->GetBoundsInDIP())); + set_pending_size_px( + delegate()->ConvertRectToPixels(pending_bounds_dip).size()); } void WaylandPopup::HandleSurfaceConfigure(uint32_t serial) { if (schedule_redraw_) { - delegate()->OnDamageRect(gfx::Rect{{0, 0}, GetBoundsInPixels().size()}); + delegate()->OnDamageRect(gfx::Rect{{0, 0}, size_px()}); schedule_redraw_ = false; } ProcessPendingBoundsDip(serial); } -void WaylandPopup::UpdateVisualSize(const gfx::Size& size_px, - float scale_factor) { - WaylandWindow::UpdateVisualSize(size_px, scale_factor); +void WaylandPopup::UpdateVisualSize(const gfx::Size& size_px) { + WaylandWindow::UpdateVisualSize(size_px); if (!shell_popup()) return; - ProcessVisualSizeUpdate(size_px, scale_factor); + ProcessVisualSizeUpdate(size_px); ApplyPendingBounds(); } void WaylandPopup::ApplyPendingBounds() { - if (HasPendingConfigures()) { + if (has_pending_configures()) { base::AutoReset<bool> auto_reset(&wayland_sets_bounds_, true); WaylandWindow::ApplyPendingBounds(); } @@ -235,6 +253,7 @@ bool WaylandPopup::IsSurfaceConfigured() { void WaylandPopup::SetWindowGeometry(gfx::Rect bounds_dip) { DCHECK(shell_popup_); gfx::Point p; + // TODO(crbug.com/1306688): Use DIP for frame_sets. if (frame_insets_px() && !frame_insets_px()->IsEmpty()) { p = gfx::ScaleToRoundedPoint( {frame_insets_px()->left(), frame_insets_px()->top()}, diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_popup.h b/chromium/ui/ozone/platform/wayland/host/wayland_popup.h index cf28a1a2258..44d8315b26e 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_popup.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_popup.h @@ -29,7 +29,7 @@ class WaylandPopup : public WaylandWindow { void Show(bool inactive) override; void Hide() override; bool IsVisible() const override; - void SetBoundsInPixels(const gfx::Rect& bounds) override; + void SetBoundsInDIP(const gfx::Rect& bounds) override; private: // WaylandWindow overrides: @@ -41,16 +41,15 @@ class WaylandPopup : public WaylandWindow { bool IsSurfaceConfigured() override; void SetWindowGeometry(gfx::Rect bounds) override; void AckConfigure(uint32_t serial) override; - void UpdateVisualSize(const gfx::Size& size_px, float scale_factor) override; + void UpdateVisualSize(const gfx::Size& size_px) override; void ApplyPendingBounds() override; void UpdateWindowMask() 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(); + // Decorates the surface, which requires custom extensions based on exo. + void UpdateDecoration(); // Returns bounds with origin relative to parent window's origin. gfx::Rect AdjustPopupWindowPosition(); @@ -59,6 +58,12 @@ class WaylandPopup : public WaylandWindow { // know anything about the version. std::unique_ptr<ShellPopupWrapper> shell_popup_; + // Set to true if the surface is decorated via aura_popup -- the custom exo + // extension to xdg_popup. + bool decorated_via_aura_popup_ = false; + + // Exists only if the frame is decorated via aura_surface. This is the + // deprecated path and can be removed once Ash is >= M105. wl::Object<zaura_surface> aura_surface_; PlatformWindowShadowType shadow_type_ = PlatformWindowShadowType::kNone; diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_screen.cc b/chromium/ui/ozone/platform/wayland/host/wayland_screen.cc index 0c7dc5c02b4..c0120f9b2ff 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_screen.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_screen.cc @@ -16,6 +16,7 @@ #include "ui/display/display.h" #include "ui/display/display_finder.h" #include "ui/display/display_list.h" +#include "ui/display/util/display_util.h" #include "ui/display/util/gpu_info_util.h" #include "ui/gfx/buffer_types.h" #include "ui/gfx/display_color_spaces.h" @@ -26,7 +27,9 @@ #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_output_manager.h" #include "ui/ozone/platform/wayland/host/wayland_window.h" +#include "ui/ozone/platform/wayland/host/wayland_zcr_color_management_output.h" #include "ui/ozone/platform/wayland/host/zwp_idle_inhibit_manager.h" #if defined(USE_DBUS) @@ -88,6 +91,9 @@ WaylandScreen::WaylandScreen(WaylandConnection* connection) // Enable that back when the issue is resolved. #endif // !BUILDFLAG(IS_CHROMEOS_LACROS) + if (format == gfx::BufferFormat::RGBA_1010102) + image_format_hdr_ = format; + if (!image_format_alpha_ && format == gfx::BufferFormat::BGRA_8888) image_format_alpha_ = gfx::BufferFormat::BGRA_8888; @@ -103,6 +109,8 @@ WaylandScreen::WaylandScreen(WaylandConnection* connection) image_format_alpha_ = gfx::BufferFormat::RGBA_8888; if (!image_format_no_alpha_) image_format_no_alpha_ = image_format_alpha_; + if (!image_format_hdr_) + image_format_hdr_ = image_format_alpha_; } WaylandScreen::~WaylandScreen() = default; @@ -114,9 +122,10 @@ void WaylandScreen::OnOutputAddedOrUpdated(uint32_t output_id, const gfx::Insets& insets, float scale, int32_t panel_transform, - int32_t logical_transform) { + int32_t logical_transform, + const std::string& label) { AddOrUpdateDisplay(output_id, origin, logical_size, physical_size, insets, - scale, panel_transform, logical_transform); + scale, panel_transform, logical_transform, label); } void WaylandScreen::OnOutputRemoved(uint32_t output_id) { @@ -152,7 +161,8 @@ void WaylandScreen::AddOrUpdateDisplay(uint32_t output_id, const gfx::Insets& insets, float scale_factor, int32_t panel_transform, - int32_t logical_transform) { + int32_t logical_transform, + const std::string& label) { display::Display changed_display(output_id); DCHECK_GE(panel_transform, WL_OUTPUT_TRANSFORM_NORMAL); @@ -188,8 +198,25 @@ void WaylandScreen::AddOrUpdateDisplay(uint32_t output_id, changed_display.UpdateWorkAreaFromInsets(insets); gfx::DisplayColorSpaces color_spaces; +#if BUILDFLAG(IS_CHROMEOS_LACROS) + auto* wayland_output = + connection_->wayland_output_manager()->GetOutput(output_id); + auto* color_management_output = + wayland_output ? wayland_output->color_management_output() : nullptr; + + if (color_management_output && color_management_output->gfx_color_space()) { + auto* gfx_color = color_management_output->gfx_color_space(); + color_spaces = display::CreateDisplayColorSpaces( + *gfx_color, image_format_hdr_ == gfx::BufferFormat::RGBA_1010102, {}); + } else { + color_spaces.SetOutputBufferFormats(image_format_no_alpha_.value(), + image_format_alpha_.value()); + } +#else color_spaces.SetOutputBufferFormats(image_format_no_alpha_.value(), image_format_alpha_.value()); +#endif + changed_display.set_color_spaces(color_spaces); // There are 2 cases where |changed_display| must be set as primary: @@ -210,6 +237,8 @@ void WaylandScreen::AddOrUpdateDisplay(uint32_t output_id, type = display::DisplayList::Type::PRIMARY; } + changed_display.set_label(label); + display_list_.AddOrUpdateDisplay(changed_display, type); } @@ -327,6 +356,37 @@ display::Display WaylandScreen::GetDisplayMatching( return display_matching ? *display_matching : GetPrimaryDisplay(); } +std::unique_ptr<WaylandScreen::WaylandScreenSaverSuspender> +WaylandScreen::WaylandScreenSaverSuspender::Create(WaylandScreen& screen) { + auto suspender = base::WrapUnique(new WaylandScreenSaverSuspender(screen)); + if (suspender->is_suspending_) { + screen.screen_saver_suspension_count_++; + return suspender; + } + + return nullptr; +} + +WaylandScreen::WaylandScreenSaverSuspender::WaylandScreenSaverSuspender( + WaylandScreen& screen) + : screen_(screen.GetWeakPtr()) { + is_suspending_ = screen.SetScreenSaverSuspended(true); +} + +WaylandScreen::WaylandScreenSaverSuspender::~WaylandScreenSaverSuspender() { + if (screen_ && is_suspending_) { + screen_->screen_saver_suspension_count_--; + if (screen_->screen_saver_suspension_count_ == 0) { + screen_->SetScreenSaverSuspended(false); + } + } +} + +std::unique_ptr<PlatformScreen::PlatformScreenSaverSuspender> +WaylandScreen::SuspendScreenSaver() { + return WaylandScreenSaverSuspender::Create(*this); +} + bool WaylandScreen::SetScreenSaverSuspended(bool suspend) { if (!connection_->zwp_idle_inhibit_manager()) return false; @@ -391,7 +451,7 @@ void WaylandScreen::RemoveObserver(display::DisplayObserver* observer) { display_list_.RemoveObserver(observer); } -std::vector<base::Value> WaylandScreen::GetGpuExtraInfo( +base::Value::List WaylandScreen::GetGpuExtraInfo( const gfx::GpuExtraInfo& gpu_extra_info) { auto values = GetDesktopEnvironmentInfo(); std::vector<std::string> protocols; @@ -400,7 +460,7 @@ std::vector<base::Value> WaylandScreen::GetGpuExtraInfo( protocol_and_version.first.c_str(), protocol_and_version.second)); } - values.push_back( + values.Append( display::BuildGpuInfoEntry("Interfaces exposed by the Wayland compositor", base::JoinString(protocols, " "))); StorePlatformNameIntoListOfValues(values, "wayland"); diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_screen.h b/chromium/ui/ozone/platform/wayland/host/wayland_screen.h index 87358f4f069..a9292900124 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_screen.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_screen.h @@ -8,8 +8,10 @@ #include <set> #include <vector> +#include "base/memory/raw_ptr.h" #include "base/memory/weak_ptr.h" #include "base/observer_list.h" +#include "base/values.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/display/display_list.h" #include "ui/display/display_observer.h" @@ -46,7 +48,8 @@ class WaylandScreen : public PlatformScreen { const gfx::Insets& insets, float scale, int32_t panel_transform, - int32_t logical_transform); + int32_t logical_transform, + const std::string& label); void OnOutputRemoved(uint32_t output_id); void OnTabletStateChanged(display::TabletState tablet_state); @@ -68,15 +71,42 @@ class WaylandScreen : public PlatformScreen { const gfx::Point& point) const override; display::Display GetDisplayMatching( const gfx::Rect& match_rect) const override; - bool SetScreenSaverSuspended(bool suspend) override; + std::unique_ptr<PlatformScreen::PlatformScreenSaverSuspender> + SuspendScreenSaver() override; bool IsScreenSaverActive() const override; base::TimeDelta CalculateIdleTime() const override; void AddObserver(display::DisplayObserver* observer) override; void RemoveObserver(display::DisplayObserver* observer) override; - std::vector<base::Value> GetGpuExtraInfo( + base::Value::List GetGpuExtraInfo( const gfx::GpuExtraInfo& gpu_extra_info) override; + protected: + // Suspends or un-suspends the platform-specific screensaver, and returns + // whether the operation was successful. Can be called more than once with the + // same value for |suspend|, but those states should not stack: the first + // alternating value should toggle the state of the suspend. + bool SetScreenSaverSuspended(bool suspend); + private: + class WaylandScreenSaverSuspender + : public PlatformScreen::PlatformScreenSaverSuspender { + public: + WaylandScreenSaverSuspender(const WaylandScreenSaverSuspender&) = delete; + WaylandScreenSaverSuspender& operator=(const WaylandScreenSaverSuspender&) = + delete; + + ~WaylandScreenSaverSuspender() override; + + static std::unique_ptr<WaylandScreenSaverSuspender> Create( + WaylandScreen& screen); + + private: + explicit WaylandScreenSaverSuspender(WaylandScreen& screen); + + base::WeakPtr<WaylandScreen> screen_; + bool is_suspending_ = false; + }; + // All parameters are in DIP screen coordinates/units except |physical_size|, // which is in physical pixels. void AddOrUpdateDisplay(uint32_t output_id, @@ -86,9 +116,10 @@ class WaylandScreen : public PlatformScreen { const gfx::Insets& insets, float scale, int32_t panel_transform, - int32_t logical_transform); + int32_t logical_transform, + const std::string& label); - WaylandConnection* connection_ = nullptr; + raw_ptr<WaylandConnection> connection_ = nullptr; display::DisplayList display_list_; @@ -96,6 +127,7 @@ class WaylandScreen : public PlatformScreen { absl::optional<gfx::BufferFormat> image_format_alpha_; absl::optional<gfx::BufferFormat> image_format_no_alpha_; + absl::optional<gfx::BufferFormat> image_format_hdr_; #if defined(USE_DBUS) mutable std::unique_ptr<OrgGnomeMutterIdleMonitor> @@ -103,6 +135,7 @@ class WaylandScreen : public PlatformScreen { #endif wl::Object<zwp_idle_inhibitor_v1> idle_inhibitor_; + uint32_t screen_saver_suspension_count_ = 0; base::WeakPtrFactory<WaylandScreen> weak_factory_; }; 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 a9a5bcadbe7..7ac51993c30 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc @@ -6,6 +6,7 @@ #include <wayland-server.h> #include <memory> +#include "base/memory/raw_ptr.h" #include "base/strings/stringprintf.h" #include "base/test/scoped_command_line.h" #include "testing/gtest/include/gtest/gtest.h" @@ -92,11 +93,6 @@ class WaylandScreenTest : public WaylandTest { WaylandTest::SetUp(); - // Initializing the MockZAuraShell gives ownership to the wl_display. - // TODO(fangzhoug): Investigate resulting memory leak. - mock_zaura_shell_ = new wl::MockZAuraShell(); - mock_zaura_shell_->Initialize(server_.display()); - output_->SetRect({kOutputWidth, kOutputHeight}); output_->SetScale(1); output_->Flush(); @@ -131,9 +127,8 @@ class WaylandScreenTest : public WaylandTest { EXPECT_EQ(display_for_widget.id(), expected_display_id); } - wl::MockZAuraShell* mock_zaura_shell_ = nullptr; - wl::TestOutput* output_ = nullptr; - WaylandOutputManager* output_manager_ = nullptr; + raw_ptr<wl::TestOutput> output_ = nullptr; + raw_ptr<WaylandOutputManager> output_manager_ = nullptr; std::unique_ptr<WaylandScreen> platform_screen_; }; @@ -299,178 +294,6 @@ TEST_P(WaylandScreenTest, MultipleOutputsAddedAndRemoved) { platform_screen_->RemoveObserver(&observer); } -TEST_P(WaylandScreenTest, OutputPropertyChanges) { - TestDisplayObserver observer; - platform_screen_->AddObserver(&observer); - - const gfx::Rect physical_bounds{800, 600}; - output_->SetRect(physical_bounds); - output_->Flush(); - - Sync(); - - uint32_t changed_values = display::DisplayObserver::DISPLAY_METRIC_BOUNDS | - display::DisplayObserver::DISPLAY_METRIC_WORK_AREA; - EXPECT_EQ(observer.GetAndClearChangedMetrics(), changed_values); - const gfx::Rect expected_bounds{800, 600}; - EXPECT_EQ(observer.GetDisplay().bounds(), expected_bounds); - const gfx::Size expected_size_in_pixels{800, 600}; - EXPECT_EQ(observer.GetDisplay().GetSizeInPixel(), expected_size_in_pixels); - EXPECT_EQ(observer.GetDisplay().work_area(), expected_bounds); - - // Test work area. - const gfx::Rect new_work_area{10, 20, 700, 500}; - const gfx::Insets expected_inset = expected_bounds.InsetsFrom(new_work_area); - ASSERT_TRUE(output_->GetAuraOutput()); - output_->GetAuraOutput()->SetInsets(expected_inset); - output_->Flush(); - - Sync(); - - changed_values = display::DisplayObserver::DISPLAY_METRIC_WORK_AREA; - EXPECT_EQ(observer.GetAndClearChangedMetrics(), changed_values); - // Bounds should be unchanged. - EXPECT_EQ(observer.GetDisplay().bounds(), expected_bounds); - EXPECT_EQ(observer.GetDisplay().GetSizeInPixel(), expected_size_in_pixels); - // Work area should have new value. - EXPECT_EQ(observer.GetDisplay().work_area(), new_work_area); - - // Test scaling. - const int32_t new_scale_value = 2; - output_->SetScale(new_scale_value); - output_->Flush(); - - Sync(); - - 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); - // Logical bounds should shrink due to scaling. - const gfx::Rect scaled_bounds{400, 300}; - EXPECT_EQ(observer.GetDisplay().bounds(), scaled_bounds); - // Size in pixel should stay unscaled. - EXPECT_EQ(observer.GetDisplay().GetSizeInPixel(), expected_size_in_pixels); - gfx::Rect scaled_work_area(scaled_bounds); - scaled_work_area.Inset(expected_inset); - EXPECT_EQ(observer.GetDisplay().work_area(), scaled_work_area); - - // Test rotation. - output_->SetTransform(WL_OUTPUT_TRANSFORM_90); - output_->Flush(); - - Sync(); - - changed_values = display::DisplayObserver::DISPLAY_METRIC_WORK_AREA | - display::DisplayObserver::DISPLAY_METRIC_BOUNDS | - display::DisplayObserver::DISPLAY_METRIC_ROTATION; - EXPECT_EQ(observer.GetAndClearChangedMetrics(), changed_values); - // Logical bounds should now be rotated to portrait. - const gfx::Rect rotated_bounds{300, 400}; - EXPECT_EQ(observer.GetDisplay().bounds(), rotated_bounds); - // Size in pixel gets rotated too, but stays unscaled. - const gfx::Size rotated_size_in_pixels{600, 800}; - EXPECT_EQ(observer.GetDisplay().GetSizeInPixel(), rotated_size_in_pixels); - gfx::Rect rotated_work_area(rotated_bounds); - rotated_work_area.Inset(expected_inset); - EXPECT_EQ(observer.GetDisplay().work_area(), rotated_work_area); - EXPECT_EQ(observer.GetDisplay().panel_rotation(), - display::Display::Rotation::ROTATE_270); - EXPECT_EQ(observer.GetDisplay().rotation(), - display::Display::Rotation::ROTATE_270); - - platform_screen_->RemoveObserver(&observer); -} - -// Regression test for crbug.com/1310981. -// Some devices use display panels built in portrait orientation, but are used -// in landscape orientation. Thus their physical bounds are in portrait -// orientation along with an offset transform, which differs from the usual -// landscape oriented bounds. -TEST_P(WaylandScreenTest, OutputPropertyChangesWithPortraitPanelRotation) { - TestDisplayObserver observer; - platform_screen_->AddObserver(&observer); - - // wl_output.geometry origin is set in DIP screen coordinates. - const gfx::Point origin(50, 70); - // wl_output.mode size is sent in physical coordinates, so it has portrait - // dimensions for a display panel with portrait natural orientation. - const gfx::Size physical_size(1200, 1600); - output_->SetRect({origin, physical_size}); - - // Inset is sent in logical coordinates. - const gfx::Insets insets = gfx::Insets::TLBR(10, 20, 30, 40); - ASSERT_TRUE(output_->GetAuraOutput()); - output_->GetAuraOutput()->SetInsets(insets); - - // Display panel's natural orientation is in portrait, so it needs a transform - // of 90 degrees to be in landscape. - output_->SetTransform(WL_OUTPUT_TRANSFORM_90); - // Begin with the logical transform at 0 degrees. - output_->GetAuraOutput()->SetLogicalTransform(WL_OUTPUT_TRANSFORM_NORMAL); - - output_->SetScale(2); - output_->Flush(); - - Sync(); - - uint32_t changed_values = - display::DisplayObserver::DISPLAY_METRIC_BOUNDS | - display::DisplayObserver::DISPLAY_METRIC_WORK_AREA | - display::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR | - display::DisplayObserver::DISPLAY_METRIC_ROTATION; - EXPECT_EQ(observer.GetAndClearChangedMetrics(), changed_values); - - // Logical bounds should be in landscape. - const gfx::Rect expected_bounds(origin, gfx::Size(800, 600)); - EXPECT_EQ(observer.GetDisplay().bounds(), expected_bounds); - const gfx::Size expected_size_in_pixels(1600, 1200); - EXPECT_EQ(observer.GetDisplay().GetSizeInPixel(), expected_size_in_pixels); - - gfx::Rect expected_work_area(expected_bounds); - expected_work_area.Inset(insets); - EXPECT_EQ(observer.GetDisplay().work_area(), expected_work_area); - - // Panel rotation and display rotation should have an offset. - EXPECT_EQ(observer.GetDisplay().panel_rotation(), - display::Display::Rotation::ROTATE_270); - EXPECT_EQ(observer.GetDisplay().rotation(), - display::Display::Rotation::ROTATE_0); - - // Further rotate the display to logical portrait orientation, which is 180 - // with the natural orientation offset. - output_->SetTransform(WL_OUTPUT_TRANSFORM_180); - output_->GetAuraOutput()->SetLogicalTransform(WL_OUTPUT_TRANSFORM_90); - output_->Flush(); - - Sync(); - - changed_values = display::DisplayObserver::DISPLAY_METRIC_BOUNDS | - display::DisplayObserver::DISPLAY_METRIC_WORK_AREA | - display::DisplayObserver::DISPLAY_METRIC_ROTATION; - EXPECT_EQ(observer.GetAndClearChangedMetrics(), changed_values); - - // Logical bounds should now be portrait. - const gfx::Rect portrait_bounds(origin, gfx::Size(600, 800)); - EXPECT_EQ(observer.GetDisplay().bounds(), portrait_bounds); - const gfx::Size portrait_size_in_pixels(1200, 1600); - EXPECT_EQ(observer.GetDisplay().GetSizeInPixel(), portrait_size_in_pixels); - - gfx::Rect portrait_work_area(portrait_bounds); - portrait_work_area.Inset(insets); - EXPECT_EQ(observer.GetDisplay().work_area(), portrait_work_area); - - // Panel rotation and display rotation should still have an offset. - EXPECT_EQ(observer.GetDisplay().panel_rotation(), - display::Display::Rotation::ROTATE_180); - EXPECT_EQ(observer.GetDisplay().rotation(), - display::Display::Rotation::ROTATE_270); - - platform_screen_->RemoveObserver(&observer); -} - TEST_P(WaylandScreenTest, OutputPropertyChangesMissingLogicalSize) { TestDisplayObserver observer; platform_screen_->AddObserver(&observer); @@ -485,9 +308,9 @@ TEST_P(WaylandScreenTest, OutputPropertyChangesMissingLogicalSize) { // Test with missing logical size. Should fall back to calculating from // physical size. - platform_screen_->OnOutputAddedOrUpdated(display_id, origin, gfx::Size(), - physical_size, insets, scale, - panel_transform, logical_transform); + platform_screen_->OnOutputAddedOrUpdated( + display_id, origin, gfx::Size(), physical_size, insets, scale, + panel_transform, logical_transform, "display"); const display::Display new_display(observer.GetDisplay()); EXPECT_EQ(new_display.id(), display_id); @@ -499,6 +322,7 @@ TEST_P(WaylandScreenTest, OutputPropertyChangesMissingLogicalSize) { EXPECT_EQ(new_display.panel_rotation(), display::Display::ROTATE_270); EXPECT_EQ(new_display.rotation(), display::Display::ROTATE_0); EXPECT_EQ(new_display.device_scale_factor(), scale); + EXPECT_EQ(new_display.label(), "display"); platform_screen_->RemoveObserver(&observer); } @@ -514,12 +338,12 @@ TEST_P(WaylandScreenTest, OutputPropertyChangesPrimaryDisplayChanged) { display1.id(), display1.bounds().origin(), display1.size(), display1.GetSizeInPixel(), display1.GetWorkAreaInsets(), display1.device_scale_factor(), WL_OUTPUT_TRANSFORM_NORMAL, - WL_OUTPUT_TRANSFORM_NORMAL); + WL_OUTPUT_TRANSFORM_NORMAL, std::string()); platform_screen_->OnOutputAddedOrUpdated( display2.id(), display2.bounds().origin(), display2.size(), display2.GetSizeInPixel(), display2.GetWorkAreaInsets(), display2.device_scale_factor(), WL_OUTPUT_TRANSFORM_NORMAL, - WL_OUTPUT_TRANSFORM_NORMAL); + WL_OUTPUT_TRANSFORM_NORMAL, std::string()); EXPECT_EQ(platform_screen_->GetPrimaryDisplay(), display1); @@ -533,12 +357,12 @@ TEST_P(WaylandScreenTest, OutputPropertyChangesPrimaryDisplayChanged) { display2.id(), display2.bounds().origin(), display2.size(), display2.GetSizeInPixel(), display2.GetWorkAreaInsets(), display2.device_scale_factor(), WL_OUTPUT_TRANSFORM_NORMAL, - WL_OUTPUT_TRANSFORM_NORMAL); + WL_OUTPUT_TRANSFORM_NORMAL, std::string()); platform_screen_->OnOutputAddedOrUpdated( display1.id(), display1.bounds().origin(), display1.size(), display1.GetSizeInPixel(), display1.GetWorkAreaInsets(), display1.device_scale_factor(), WL_OUTPUT_TRANSFORM_NORMAL, - WL_OUTPUT_TRANSFORM_NORMAL); + WL_OUTPUT_TRANSFORM_NORMAL, std::string()); EXPECT_EQ(platform_screen_->GetPrimaryDisplay(), display2); @@ -563,22 +387,22 @@ TEST_P(WaylandScreenTest, GetAcceleratedWidgetAtScreenPoint) { EXPECT_EQ(widget_at_screen_point, gfx::kNullAcceleratedWidget); // Set a focus to the main window. Now, that focused window must be returned. - window_->SetPointerFocus(true); + SetPointerFocusedWindow(window_.get()); widget_at_screen_point = platform_screen_->GetAcceleratedWidgetAtScreenPoint(gfx::Point(10, 10)); EXPECT_EQ(widget_at_screen_point, window_->GetWidget()); // Getting a widget at a screen point outside its bounds, must result in a // null widget. - const gfx::Rect window_bounds = window_->GetBoundsInPixels(); + const gfx::Rect window_bounds = window_->GetBoundsInDIP(); widget_at_screen_point = platform_screen_->GetAcceleratedWidgetAtScreenPoint( gfx::Point(window_bounds.width() + 1, window_bounds.height() + 1)); EXPECT_EQ(widget_at_screen_point, gfx::kNullAcceleratedWidget); MockWaylandPlatformWindowDelegate delegate; auto menu_window_bounds = - gfx::Rect(window_->GetBoundsInPixels().width() - 10, - window_->GetBoundsInPixels().height() - 10, 100, 100); + gfx::Rect(window_->GetBoundsInDIP().width() - 10, + window_->GetBoundsInDIP().height() - 10, 100, 100); std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithProperties(menu_window_bounds, PlatformWindowType::kMenu, @@ -588,24 +412,23 @@ TEST_P(WaylandScreenTest, GetAcceleratedWidgetAtScreenPoint) { // Imagine the mouse enters a menu window, which is located on top of the main // window, and gathers focus. - window_->SetPointerFocus(false); - menu_window->SetPointerFocus(true); + SetPointerFocusedWindow(menu_window.get()); + widget_at_screen_point = platform_screen_->GetAcceleratedWidgetAtScreenPoint( - gfx::Point(menu_window->GetBoundsInPixels().x() + 1, - menu_window->GetBoundsInPixels().y() + 1)); + gfx::Point(menu_window->GetBoundsInDIP().x() + 1, + menu_window->GetBoundsInDIP().y() + 1)); EXPECT_EQ(widget_at_screen_point, menu_window->GetWidget()); // Whenever a mouse pointer leaves the menu window, the accelerated widget // of that focused window must be returned. - window_->SetPointerFocus(true); - menu_window->SetPointerFocus(false); + SetPointerFocusedWindow(window_.get()); widget_at_screen_point = platform_screen_->GetAcceleratedWidgetAtScreenPoint(gfx::Point(0, 0)); EXPECT_EQ(widget_at_screen_point, window_->GetWidget()); // Reset the focus to avoid crash on dtor as long as there is no real pointer // object. - window_->SetPointerFocus(false); + SetPointerFocusedWindow(nullptr); // Part 2: test that the window is found when display's scale changes. // Update scale. @@ -614,11 +437,9 @@ TEST_P(WaylandScreenTest, GetAcceleratedWidgetAtScreenPoint) { Sync(); - auto menu_bounds_px = menu_window->GetBoundsInPixels(); - // Translate the point to dip. - auto point_in_screen = - gfx::ScaleToRoundedPoint(menu_bounds_px.origin(), 1.f / 2); - menu_window->SetPointerFocus(true); + auto menu_bounds = menu_window->GetBoundsInDIP(); + auto point_in_screen = menu_bounds.origin(); + SetPointerFocusedWindow(menu_window.get()); widget_at_screen_point = platform_screen_->GetAcceleratedWidgetAtScreenPoint(point_in_screen); EXPECT_EQ(widget_at_screen_point, menu_window->GetWidget()); @@ -630,7 +451,7 @@ TEST_P(WaylandScreenTest, GetLocalProcessWidgetAtPoint) { gfx::kNullAcceleratedWidget); // Set a focus to the main window. Now, that focused window must be returned. - window_->SetPointerFocus(true); + SetPointerFocusedWindow(window_.get()); EXPECT_EQ(platform_screen_->GetLocalProcessWidgetAtPoint(point, {}), window_->GetWidget()); @@ -640,10 +461,6 @@ TEST_P(WaylandScreenTest, GetLocalProcessWidgetAtPoint) { EXPECT_EQ( platform_screen_->GetLocalProcessWidgetAtPoint(point, {w - 1, w, w + 1}), gfx::kNullAcceleratedWidget); - - // Reset the focus to avoid crash on dtor as long as there is no real pointer - // object. - window_->SetPointerFocus(false); } TEST_P(WaylandScreenTest, GetDisplayMatching) { @@ -821,6 +638,7 @@ TEST_P(WaylandScreenTest, GetCursorScreenPoint) { uint32_t time = 1002; wl_pointer_send_enter(pointer->resource(), ++serial, surface->resource(), 0, 0); + wl_pointer_send_frame(pointer->resource()); wl_pointer_send_motion(pointer->resource(), ++time, wl_fixed_from_int(10), wl_fixed_from_int(20)); @@ -834,8 +652,10 @@ TEST_P(WaylandScreenTest, GetCursorScreenPoint) { ASSERT_TRUE(second_surface); // Now, leave the first surface and enter second one. wl_pointer_send_leave(pointer->resource(), ++serial, surface->resource()); + wl_pointer_send_frame(pointer->resource()); wl_pointer_send_enter(pointer->resource(), ++serial, second_surface->resource(), 0, 0); + wl_pointer_send_frame(pointer->resource()); wl_pointer_send_motion(pointer->resource(), ++time, wl_fixed_from_int(20), wl_fixed_from_int(10)); @@ -847,16 +667,17 @@ TEST_P(WaylandScreenTest, GetCursorScreenPoint) { // Clear pointer focus. wl_pointer_send_leave(pointer->resource(), ++serial, second_surface->resource()); + wl_pointer_send_frame(pointer->resource()); Sync(); // WaylandScreen must return a point, which is located outside of bounds of // any window. Basically, it means that it takes the largest window and adds // 10 pixels to its width and height, and returns the value. - const gfx::Rect second_window_bounds = second_window->GetBoundsInPixels(); + const gfx::Rect second_window_bounds = second_window->GetBoundsInDIP(); // A second window has largest bounds. Thus, these bounds must be taken as a // ground for the point outside any of the surfaces. - ASSERT_TRUE(window_->GetBoundsInPixels() < second_window_bounds); + ASSERT_TRUE(window_->GetBoundsInDIP() < second_window_bounds); EXPECT_EQ(gfx::Point(second_window_bounds.width() + 10, second_window_bounds.height() + 10), platform_screen_->GetCursorScreenPoint()); @@ -877,6 +698,7 @@ TEST_P(WaylandScreenTest, GetCursorScreenPoint) { wl_pointer_send_enter(pointer->resource(), ++serial, menu_surface->resource(), 0, 0); + wl_pointer_send_frame(pointer->resource()); wl_pointer_send_motion(pointer->resource(), ++time, wl_fixed_from_int(2), wl_fixed_from_int(1)); @@ -892,8 +714,10 @@ TEST_P(WaylandScreenTest, GetCursorScreenPoint) { // Leave the menu window and enter the top level window. wl_pointer_send_leave(pointer->resource(), ++serial, menu_surface->resource()); + wl_pointer_send_frame(pointer->resource()); wl_pointer_send_enter(pointer->resource(), ++serial, second_surface->resource(), 0, 0); + wl_pointer_send_frame(pointer->resource()); wl_pointer_send_motion(pointer->resource(), ++time, wl_fixed_from_int(1912), wl_fixed_from_int(1071)); @@ -905,11 +729,12 @@ TEST_P(WaylandScreenTest, GetCursorScreenPoint) { wl_pointer_send_leave(pointer->resource(), ++serial, second_surface->resource()); + wl_pointer_send_frame(pointer->resource()); // Now, create a nested menu window and make sure that the cursor screen point // still has been correct. The location of the window is on the right side of // the main menu window. - const gfx::Rect menu_window_bounds = menu_window->GetBoundsInPixels(); + const gfx::Rect menu_window_bounds = menu_window->GetBoundsInDIP(); std::unique_ptr<WaylandWindow> nested_menu_window = CreateWaylandWindowWithProperties( gfx::Rect(menu_window_bounds.x() + menu_window_bounds.width(), @@ -924,6 +749,7 @@ TEST_P(WaylandScreenTest, GetCursorScreenPoint) { wl_pointer_send_enter(pointer->resource(), ++serial, nested_menu_surface->resource(), 0, 0); + wl_pointer_send_frame(pointer->resource()); wl_pointer_send_motion(pointer->resource(), ++time, wl_fixed_from_int(2), wl_fixed_from_int(3)); @@ -935,8 +761,10 @@ TEST_P(WaylandScreenTest, GetCursorScreenPoint) { // point still must be reported correctly. wl_pointer_send_leave(pointer->resource(), ++serial, nested_menu_surface->resource()); + wl_pointer_send_frame(pointer->resource()); wl_pointer_send_enter(pointer->resource(), ++serial, menu_surface->resource(), 0, 0); + wl_pointer_send_frame(pointer->resource()); wl_pointer_send_motion(pointer->resource(), ++time, wl_fixed_from_int(2), wl_fixed_from_int(1)); @@ -987,6 +815,36 @@ TEST_P(WaylandScreenTest, SetWindowScale) { display::Display::ResetForceDeviceScaleFactorForTesting(); } +// Regression test for https://crbug.com/1346534. +// +// Scenario: With (at least) one output connected and a surface, with no output +// associated yet, ie: wl_surface.enter event not received yet for that surface, +// which implies in its scale being set to the primary output's scale at its +// initialization, any primary output scale update (or other properties that +// lead to scale change) must be propagated to the window. +TEST_P(WaylandScreenTest, SetWindowScaleWithoutEnteredOutput) { + // Test pre-conditions: single output setup whereas |output_| is the primary + // output managed by |output_manager_|, with initial scale == 1. + ASSERT_EQ(1u, output_manager_->GetAllOutputs().size()); + ASSERT_TRUE(output_); + ASSERT_EQ(1, output_->GetScale()); + + // Ensure |surface_| has not entered any wl_output. Assuming |window_| has + // been already initialized with |output_|'s scale. + wl_surface_send_leave(surface_->resource(), output_->resource()); + Sync(); + ASSERT_EQ(0u, window_->GetPreferredEnteredOutputId()); + + // Change |output_|'s scale and make sure |window_|'s scale is update + // accordingly. + output_->SetScale(2); + output_->Flush(); + Sync(); + + EXPECT_EQ(window_->window_scale(), 2); + EXPECT_EQ(window_->ui_scale(), 2); +} + // Checks that output transform is properly translated into Display orientation. // The first one is counter-clockwise, while the latter is clockwise. TEST_P(WaylandScreenTest, Transform) { @@ -1058,9 +916,9 @@ class LazilyConfiguredScreenTest aux_output_->SetRect({0, 0, 800, 600}); } - wl::TestOutput* primary_output_ = nullptr; - wl::TestOutput* aux_output_ = nullptr; - WaylandOutputManager* output_manager_ = nullptr; + raw_ptr<wl::TestOutput> primary_output_ = nullptr; + raw_ptr<wl::TestOutput> aux_output_ = nullptr; + raw_ptr<WaylandOutputManager> output_manager_ = nullptr; bool auto_configure; }; @@ -1089,10 +947,202 @@ TEST_P(LazilyConfiguredScreenTest, DualOutput) { EXPECT_EQ(2u, screen_->GetAllDisplays().size()); } +// Tests that use aura-shell extension should use wl::ShellVersion::kStable. +class WaylandAuraShellScreenTest : public WaylandScreenTest { + public: + WaylandAuraShellScreenTest() = default; + WaylandAuraShellScreenTest(const WaylandAuraShellScreenTest&) = delete; + WaylandAuraShellScreenTest& operator=(const WaylandAuraShellScreenTest&) = + delete; + ~WaylandAuraShellScreenTest() override = default; + + void SetUp() override { + ASSERT_EQ(GetParam().shell_version, wl::ShellVersion::kStable); + WaylandScreenTest::SetUp(); + } +}; + +TEST_P(WaylandAuraShellScreenTest, OutputPropertyChanges) { + TestDisplayObserver observer; + platform_screen_->AddObserver(&observer); + + const gfx::Rect physical_bounds{800, 600}; + output_->SetRect(physical_bounds); + output_->Flush(); + + Sync(); + + uint32_t changed_values = display::DisplayObserver::DISPLAY_METRIC_BOUNDS | + display::DisplayObserver::DISPLAY_METRIC_WORK_AREA; + EXPECT_EQ(observer.GetAndClearChangedMetrics(), changed_values); + const gfx::Rect expected_bounds{800, 600}; + EXPECT_EQ(observer.GetDisplay().bounds(), expected_bounds); + const gfx::Size expected_size_in_pixels{800, 600}; + EXPECT_EQ(observer.GetDisplay().GetSizeInPixel(), expected_size_in_pixels); + EXPECT_EQ(observer.GetDisplay().work_area(), expected_bounds); + + // Test work area. + const gfx::Rect new_work_area{10, 20, 700, 500}; + const gfx::Insets expected_inset = expected_bounds.InsetsFrom(new_work_area); + ASSERT_TRUE(output_->GetAuraOutput()); + output_->GetAuraOutput()->SetInsets(expected_inset); + output_->Flush(); + + Sync(); + + changed_values = display::DisplayObserver::DISPLAY_METRIC_WORK_AREA; + EXPECT_EQ(observer.GetAndClearChangedMetrics(), changed_values); + // Bounds should be unchanged. + EXPECT_EQ(observer.GetDisplay().bounds(), expected_bounds); + EXPECT_EQ(observer.GetDisplay().GetSizeInPixel(), expected_size_in_pixels); + // Work area should have new value. + EXPECT_EQ(observer.GetDisplay().work_area(), new_work_area); + + // Test scaling. + const int32_t new_scale_value = 2; + output_->SetScale(new_scale_value); + output_->Flush(); + + Sync(); + + 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); + // Logical bounds should shrink due to scaling. + const gfx::Rect scaled_bounds{400, 300}; + EXPECT_EQ(observer.GetDisplay().bounds(), scaled_bounds); + // Size in pixel should stay unscaled. + EXPECT_EQ(observer.GetDisplay().GetSizeInPixel(), expected_size_in_pixels); + gfx::Rect scaled_work_area(scaled_bounds); + scaled_work_area.Inset(expected_inset); + EXPECT_EQ(observer.GetDisplay().work_area(), scaled_work_area); + + // Test rotation. + output_->SetTransform(WL_OUTPUT_TRANSFORM_90); + output_->Flush(); + + Sync(); + + changed_values = display::DisplayObserver::DISPLAY_METRIC_WORK_AREA | + display::DisplayObserver::DISPLAY_METRIC_BOUNDS | + display::DisplayObserver::DISPLAY_METRIC_ROTATION; + EXPECT_EQ(observer.GetAndClearChangedMetrics(), changed_values); + // Logical bounds should now be rotated to portrait. + const gfx::Rect rotated_bounds{300, 400}; + EXPECT_EQ(observer.GetDisplay().bounds(), rotated_bounds); + // Size in pixel gets rotated too, but stays unscaled. + const gfx::Size rotated_size_in_pixels{600, 800}; + EXPECT_EQ(observer.GetDisplay().GetSizeInPixel(), rotated_size_in_pixels); + gfx::Rect rotated_work_area(rotated_bounds); + rotated_work_area.Inset(expected_inset); + EXPECT_EQ(observer.GetDisplay().work_area(), rotated_work_area); + EXPECT_EQ(observer.GetDisplay().panel_rotation(), + display::Display::Rotation::ROTATE_270); + EXPECT_EQ(observer.GetDisplay().rotation(), + display::Display::Rotation::ROTATE_270); + + platform_screen_->RemoveObserver(&observer); +} + +// Regression test for crbug.com/1310981. +// Some devices use display panels built in portrait orientation, but are used +// in landscape orientation. Thus their physical bounds are in portrait +// orientation along with an offset transform, which differs from the usual +// landscape oriented bounds. +TEST_P(WaylandAuraShellScreenTest, + OutputPropertyChangesWithPortraitPanelRotation) { + TestDisplayObserver observer; + platform_screen_->AddObserver(&observer); + + // wl_output.geometry origin is set in DIP screen coordinates. + const gfx::Point origin(50, 70); + // wl_output.mode size is sent in physical coordinates, so it has portrait + // dimensions for a display panel with portrait natural orientation. + const gfx::Size physical_size(1200, 1600); + output_->SetRect({origin, physical_size}); + + // Inset is sent in logical coordinates. + const gfx::Insets insets = gfx::Insets::TLBR(10, 20, 30, 40); + ASSERT_TRUE(output_->GetAuraOutput()); + output_->GetAuraOutput()->SetInsets(insets); + + // Display panel's natural orientation is in portrait, so it needs a transform + // of 90 degrees to be in landscape. + output_->SetTransform(WL_OUTPUT_TRANSFORM_90); + // Begin with the logical transform at 0 degrees. + output_->GetAuraOutput()->SetLogicalTransform(WL_OUTPUT_TRANSFORM_NORMAL); + + output_->SetScale(2); + output_->Flush(); + + Sync(); + + uint32_t changed_values = + display::DisplayObserver::DISPLAY_METRIC_BOUNDS | + display::DisplayObserver::DISPLAY_METRIC_WORK_AREA | + display::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR | + display::DisplayObserver::DISPLAY_METRIC_ROTATION; + EXPECT_EQ(observer.GetAndClearChangedMetrics(), changed_values); + + // Logical bounds should be in landscape. + const gfx::Rect expected_bounds(origin, gfx::Size(800, 600)); + EXPECT_EQ(observer.GetDisplay().bounds(), expected_bounds); + const gfx::Size expected_size_in_pixels(1600, 1200); + EXPECT_EQ(observer.GetDisplay().GetSizeInPixel(), expected_size_in_pixels); + + gfx::Rect expected_work_area(expected_bounds); + expected_work_area.Inset(insets); + EXPECT_EQ(observer.GetDisplay().work_area(), expected_work_area); + + // Panel rotation and display rotation should have an offset. + EXPECT_EQ(observer.GetDisplay().panel_rotation(), + display::Display::Rotation::ROTATE_270); + EXPECT_EQ(observer.GetDisplay().rotation(), + display::Display::Rotation::ROTATE_0); + + // Further rotate the display to logical portrait orientation, which is 180 + // with the natural orientation offset. + output_->SetTransform(WL_OUTPUT_TRANSFORM_180); + output_->GetAuraOutput()->SetLogicalTransform(WL_OUTPUT_TRANSFORM_90); + output_->Flush(); + + Sync(); + + changed_values = display::DisplayObserver::DISPLAY_METRIC_BOUNDS | + display::DisplayObserver::DISPLAY_METRIC_WORK_AREA | + display::DisplayObserver::DISPLAY_METRIC_ROTATION; + EXPECT_EQ(observer.GetAndClearChangedMetrics(), changed_values); + + // Logical bounds should now be portrait. + const gfx::Rect portrait_bounds(origin, gfx::Size(600, 800)); + EXPECT_EQ(observer.GetDisplay().bounds(), portrait_bounds); + const gfx::Size portrait_size_in_pixels(1200, 1600); + EXPECT_EQ(observer.GetDisplay().GetSizeInPixel(), portrait_size_in_pixels); + + gfx::Rect portrait_work_area(portrait_bounds); + portrait_work_area.Inset(insets); + EXPECT_EQ(observer.GetDisplay().work_area(), portrait_work_area); + + // Panel rotation and display rotation should still have an offset. + EXPECT_EQ(observer.GetDisplay().panel_rotation(), + display::Display::Rotation::ROTATE_180); + EXPECT_EQ(observer.GetDisplay().rotation(), + display::Display::Rotation::ROTATE_270); + + platform_screen_->RemoveObserver(&observer); +} + INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest, WaylandScreenTest, Values(wl::ServerConfig{ .shell_version = wl::ShellVersion::kStable})); +INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest, + WaylandAuraShellScreenTest, + Values(wl::ServerConfig{ + .shell_version = wl::ShellVersion::kStable})); INSTANTIATE_TEST_SUITE_P(XdgVersionV6Test, WaylandScreenTest, Values(wl::ServerConfig{ diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_seat.h b/chromium/ui/ozone/platform/wayland/host/wayland_seat.h index db07a4ea2e9..2139c13ac49 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_seat.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_seat.h @@ -7,6 +7,7 @@ #include <memory> +#include "base/memory/raw_ptr.h" #include "ui/ozone/platform/wayland/common/wayland_object.h" namespace ui { @@ -59,7 +60,7 @@ class WaylandSeat : public wl::GlobalObjectRegistrar<WaylandSeat> { // Wayland object wrapped by this class. wl::Object<wl_seat> obj_; - WaylandConnection* const connection_; + const raw_ptr<WaylandConnection> connection_; // Input device objects. std::unique_ptr<WaylandKeyboard> keyboard_; diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_shm.cc b/chromium/ui/ozone/platform/wayland/host/wayland_shm.cc index 3869b2858a7..b6de107bc0f 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_shm.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_shm.cc @@ -5,6 +5,7 @@ #include "ui/ozone/platform/wayland/host/wayland_shm.h" #include "base/logging.h" +#include "ui/ozone/platform/wayland/host/wayland_buffer_factory.h" #include "ui/ozone/platform/wayland/host/wayland_connection.h" namespace ui { @@ -24,7 +25,8 @@ void WaylandShm::Instantiate(WaylandConnection* connection, uint32_t version) { DCHECK_EQ(interface, kInterfaceName); - if (connection->shm_ || + auto* buffer_factory = connection->wayland_buffer_factory(); + if (buffer_factory->wayland_shm_ || !wl::CanBind(interface, version, kMinVersion, kMinVersion)) { return; } @@ -34,7 +36,8 @@ void WaylandShm::Instantiate(WaylandConnection* connection, LOG(ERROR) << "Failed to bind to wl_shm global"; return; } - connection->shm_ = std::make_unique<WaylandShm>(shm.release(), connection); + buffer_factory->wayland_shm_ = + std::make_unique<WaylandShm>(shm.release(), connection); } WaylandShm::WaylandShm(wl_shm* shm, WaylandConnection* connection) diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_shm.h b/chromium/ui/ozone/platform/wayland/host/wayland_shm.h index af32d3cdd01..7d137c196b0 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_shm.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_shm.h @@ -6,6 +6,7 @@ #define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_SHM_H_ #include "base/files/scoped_file.h" +#include "base/memory/raw_ptr.h" #include "ui/gfx/geometry/rect.h" #include "ui/ozone/platform/wayland/common/wayland_object.h" #include "ui/ozone/platform/wayland/common/wayland_util.h" @@ -38,19 +39,16 @@ class WaylandShm : public wl::GlobalObjectRegistrar<WaylandShm> { // Creates a wl_buffer based on shared memory handle with the specified // |length| and |size|. Whereas |with_alpha_channel| indicates whether the // buffer's color format should use or not the alpha channel. - // - // TODO(crbug.com/1269044): Remove |with_alpha_channel| parameter once - // Exo-side Skia Renderer issue is fixed. wl::Object<struct wl_buffer> CreateBuffer(const base::ScopedFD& fd, size_t length, const gfx::Size& size, - bool with_alpha_channel = true); + bool with_alpha_channel); private: wl::Object<wl_shm> const shm_; // Non-owned pointer to the main connection. - WaylandConnection* const connection_; + const raw_ptr<WaylandConnection> connection_; }; } // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_shm_buffer.cc b/chromium/ui/ozone/platform/wayland/host/wayland_shm_buffer.cc index 0592613cb1f..7f88515c4b1 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_shm_buffer.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_shm_buffer.cc @@ -8,14 +8,15 @@ #include "base/memory/platform_shared_memory_region.h" #include "base/memory/unsafe_shared_memory_region.h" #include "ui/gfx/geometry/skia_conversions.h" +#include "ui/ozone/platform/wayland/host/wayland_buffer_factory.h" #include "ui/ozone/platform/wayland/host/wayland_connection.h" -#include "ui/ozone/platform/wayland/host/wayland_shm.h" namespace ui { -WaylandShmBuffer::WaylandShmBuffer(WaylandShm* shm, const gfx::Size& size) +WaylandShmBuffer::WaylandShmBuffer(WaylandBufferFactory* buffer_factory, + const gfx::Size& size) : size_(size) { - Initialize(shm); + Initialize(buffer_factory); } WaylandShmBuffer::~WaylandShmBuffer() = default; @@ -23,8 +24,8 @@ WaylandShmBuffer::WaylandShmBuffer(WaylandShmBuffer&& buffer) = default; WaylandShmBuffer& WaylandShmBuffer::operator=(WaylandShmBuffer&& buffer) = default; -void WaylandShmBuffer::Initialize(WaylandShm* shm) { - DCHECK(shm); +void WaylandShmBuffer::Initialize(WaylandBufferFactory* buffer_factory) { + DCHECK(buffer_factory); SkImageInfo info = SkImageInfo::MakeN32Premul(size_.width(), size_.height()); int stride = info.minRowBytes(); @@ -46,7 +47,8 @@ void WaylandShmBuffer::Initialize(WaylandShm* shm) { base::subtle::ScopedFDPair fd_pair = platform_shared_memory.PassPlatformHandle(); - buffer_ = shm->CreateBuffer(std::move(fd_pair.fd), buffer_size, size_); + buffer_ = buffer_factory->CreateShmBuffer(std::move(fd_pair.fd), buffer_size, + size_); if (!buffer_) { shared_memory_mapping_ = base::WritableSharedMemoryMapping(); return; diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_shm_buffer.h b/chromium/ui/ozone/platform/wayland/host/wayland_shm_buffer.h index 01ad3013238..6e366f1d9f3 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_shm_buffer.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_shm_buffer.h @@ -13,7 +13,7 @@ namespace ui { -class WaylandShm; +class WaylandBufferFactory; // Encapsulates a Wayland SHM buffer, covering basically 2 use cases: // (1) Buffers created and mmap'ed locally to draw skia bitmap(s) into; and @@ -23,7 +23,7 @@ class WaylandShm; // wl_buffer and WritableSharedMemoryMapping (if any) instance. class WaylandShmBuffer { public: - WaylandShmBuffer(WaylandShm* shm, const gfx::Size& size); + WaylandShmBuffer(WaylandBufferFactory* buffer_factory, const gfx::Size& size); WaylandShmBuffer(const WaylandShmBuffer&) = delete; WaylandShmBuffer& operator=(const WaylandShmBuffer&) = delete; @@ -50,7 +50,7 @@ class WaylandShmBuffer { int stride() const { return stride_; } private: - void Initialize(WaylandShm* shm); + void Initialize(WaylandBufferFactory* buffer_factory); gfx::Size size_; int stride_; diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_subsurface.h b/chromium/ui/ozone/platform/wayland/host/wayland_subsurface.h index db2455a47b7..e829aed84cd 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_subsurface.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_subsurface.h @@ -6,6 +6,7 @@ #define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_SUBSURFACE_H_ #include "base/containers/linked_list.h" +#include "base/memory/raw_ptr.h" #include "ui/gfx/native_widget_types.h" #include "ui/ozone/platform/wayland/common/wayland_object.h" #include "ui/ozone/platform/wayland/host/wayland_surface.h" @@ -63,10 +64,10 @@ class WaylandSubsurface : public base::LinkNode<WaylandSubsurface> { wl::Object<augmented_sub_surface> augmented_subsurface_; gfx::PointF position_dip_; - WaylandConnection* const connection_; + const raw_ptr<WaylandConnection> connection_; // |parent_| refers to the WaylandWindow whose wl_surface is the parent to // this subsurface. - WaylandWindow* const parent_; + const raw_ptr<WaylandWindow> parent_; }; } // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_surface.cc b/chromium/ui/ozone/platform/wayland/host/wayland_surface.cc index 8d3139f77a4..77e002a38fd 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_surface.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_surface.cc @@ -83,7 +83,8 @@ WaylandSurface::~WaylandSurface() { if (explicit_release_callback_.is_null()) return; for (auto& release : linux_buffer_releases_) { - explicit_release_callback_.Run(release.second.buffer, base::ScopedFD()); + explicit_release_callback_.Run(release.second.buffer.get(), + base::ScopedFD()); } } @@ -277,38 +278,17 @@ wl::Object<wl_region> WaylandSurface::CreateAndAddRegion( wl::Object<wl_region> region( wl_compositor_create_region(connection_->compositor())); - auto window_shape_in_dips = root_window_->GetWindowShape(); - - bool surface_submission_in_pixel_coordinates = + const bool surface_submission_in_pixel_coordinates = SurfaceSubmissionInPixelCoordinates(); - // Only root_surface and primary_subsurface should use |window_shape_in_dips|. - // Do not use non empty |window_shape_in_dips| if |region_px| is empty, i.e. - // this surface is transluscent. - bool is_primary_or_root = - root_window_->root_surface() == this || - (root_window()->primary_subsurface() && - root_window()->primary_subsurface()->wayland_surface() == this); - bool is_empty = - std::all_of(region_px.begin(), region_px.end(), - [](const gfx::Rect& rect) { return rect.IsEmpty(); }); - if (window_shape_in_dips.has_value() && !is_empty && is_primary_or_root) { - for (auto& rect : window_shape_in_dips.value()) { - if (surface_submission_in_pixel_coordinates) - rect = gfx::ScaleToEnclosingRect(rect, root_window_->window_scale()); + for (const auto& rect_px : region_px) { + if (surface_submission_in_pixel_coordinates) { + wl_region_add(region.get(), rect_px.x(), rect_px.y(), rect_px.width(), + rect_px.height()); + } else { + gfx::Rect rect = gfx::ScaleToEnclosingRect(rect_px, 1.f / buffer_scale); wl_region_add(region.get(), rect.x(), rect.y(), rect.width(), rect.height()); } - } else { - for (const auto& rect_px : region_px) { - if (surface_submission_in_pixel_coordinates) { - wl_region_add(region.get(), rect_px.x(), rect_px.y(), rect_px.width(), - rect_px.height()); - } else { - gfx::Rect rect = gfx::ScaleToEnclosingRect(rect_px, 1.f / buffer_scale); - wl_region_add(region.get(), rect.x(), rect.y(), rect.width(), - rect.height()); - } - } } return region; } @@ -698,7 +678,7 @@ void WaylandSurface::ExplicitRelease( DCHECK(iter != linux_buffer_releases_.end()); DCHECK(iter->second.buffer); if (!explicit_release_callback_.is_null()) - explicit_release_callback_.Run(iter->second.buffer, std::move(fence)); + explicit_release_callback_.Run(iter->second.buffer.get(), std::move(fence)); linux_buffer_releases_.erase(iter); } @@ -806,7 +786,7 @@ void WaylandSurface::SetRoundedClipBounds( } void WaylandSurface::SetBackgroundColor( - absl::optional<SkColor> background_color) { + absl::optional<SkColor4f> background_color) { if (GetAugmentedSurface()) pending_state_.background_color = background_color; } diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_surface.h b/chromium/ui/ozone/platform/wayland/host/wayland_surface.h index 7b5dec9d11c..526a5982651 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_surface.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_surface.h @@ -11,6 +11,7 @@ #include "base/callback.h" #include "base/containers/flat_map.h" #include "base/files/scoped_file.h" +#include "base/memory/raw_ptr.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/gfx/geometry/rect.h" @@ -159,7 +160,7 @@ class WaylandSurface { // Sets the background color for this surface, which will be blended with the // wl_buffer contents during the compositing step on the Wayland compositor // side. - void SetBackgroundColor(absl::optional<SkColor> background_color); + void SetBackgroundColor(absl::optional<SkColor4f> background_color); // Validates the |pending_state_| and generates the corresponding requests. // Then copy |pending_states_| to |states_|. @@ -196,7 +197,7 @@ class WaylandSurface { wl::Object<zwp_linux_buffer_release_v1> linux_buffer_release; // The buffer associated with this explicit release. - wl_buffer* buffer; + raw_ptr<wl_buffer> buffer; }; struct State { @@ -217,7 +218,7 @@ class WaylandSurface { // buffer_handle owning this wl_buffer is destroyed. Accessing this field // should ensure wl_buffer exists by calling // WaylandBufferManagerHost::EnsureBufferHandle(buffer_id). - wl_buffer* buffer = nullptr; + raw_ptr<wl_buffer> buffer = nullptr; gfx::Size buffer_size_px; // Current scale factor of a next attached buffer used by the GPU process. @@ -252,7 +253,7 @@ class WaylandSurface { // Optional background color for this surface. This information // can be used by Wayland compositor to correctly display delegated textures // which require background color applied. - absl::optional<SkColor> background_color; + absl::optional<SkColor4f> background_color; }; // Tracks the last sent src and dst values across wayland protocol s.t. we @@ -282,8 +283,8 @@ class WaylandSurface { zwp_linux_surface_synchronization_v1* GetSurfaceSync(); augmented_surface* GetAugmentedSurface(); - WaylandConnection* const connection_; - WaylandWindow* root_window_ = nullptr; + const raw_ptr<WaylandConnection> connection_; + raw_ptr<WaylandWindow> root_window_ = nullptr; bool apply_state_immediately_ = false; wl::Object<wl_surface> surface_; wl::Object<wp_viewport> viewport_; 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 27b58bfd058..079bf56a31e 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc @@ -29,6 +29,7 @@ #include "ui/ozone/platform/wayland/host/wayland_window_drag_controller.h" #include "ui/ozone/platform/wayland/host/wayland_zaura_shell.h" #include "ui/ozone/platform/wayland/host/wayland_zwp_pointer_constraints.h" +#include "ui/ozone/platform/wayland/host/xdg_activation.h" #include "ui/platform_window/common/platform_window_defaults.h" #include "ui/platform_window/extensions/wayland_extension.h" @@ -93,9 +94,8 @@ bool WaylandToplevelWindow::CreateShellToplevel() { ZAURA_SURFACE_FRAME_TYPE_SHADOW); } - // TODO(oshima): Change to use DIP. if (screen_coordinates_enabled_) - SetBoundsInPixels(GetBoundsInPixels()); + SetBoundsInDIP(GetBoundsInDIP()); // This could be the proper time to update window mask using // NonClientView::GetWindowMask, since |non_client_view| is not created yet @@ -106,7 +106,7 @@ bool WaylandToplevelWindow::CreateShellToplevel() { } void WaylandToplevelWindow::ApplyPendingBounds() { - if (HasPendingConfigures()) { + if (has_pending_configures()) { DCHECK(shell_toplevel_); WaylandWindow::ApplyPendingBounds(); } @@ -153,6 +153,10 @@ void WaylandToplevelWindow::Hide() { } WaylandWindow::Hide(); + if (aura_surface_ && wl::get_version_of_object(aura_surface_.get()) >= + ZAURA_SURFACE_RELEASE_SINCE_VERSION) { + aura_surface_.reset(); + } shell_toplevel_.reset(); connection()->ScheduleFlush(); } @@ -236,6 +240,8 @@ void WaylandToplevelWindow::Activate() { if (aura_surface_ && zaura_surface_get_version(aura_surface_.get()) >= ZAURA_SURFACE_ACTIVATE_SINCE_VERSION) { zaura_surface_activate(aura_surface_.get()); + } else if (connection()->xdg_activation()) { + connection()->xdg_activation()->Activate(root_surface()->surface()); } else if (gtk_surface1_) { gtk_surface1_->RequestFocus(); } @@ -324,9 +330,8 @@ void WaylandToplevelWindow::SetAspectRatio(const gfx::SizeF& aspect_ratio) { } } -absl::optional<std::vector<gfx::Rect>> WaylandToplevelWindow::GetWindowShape() - const { - return window_shape_in_dips_; +bool WaylandToplevelWindow::IsScreenCoordinatesEnabled() const { + return screen_coordinates_enabled_; } // static @@ -409,14 +414,13 @@ void WaylandToplevelWindow::HandleAuraToplevelConfigure(int32_t x, bounds_dip.set_origin({x, y}); } } else if (is_normal) { - gfx::Size size_in_dip = restored_size_dip().IsEmpty() - ? GetBoundsInDIP().size() - : restored_size_dip(); - bounds_dip.set_origin(gfx::Point(x, y)); - bounds_dip.set_size(size_in_dip); + bounds_dip = !restored_size_dip().IsEmpty() ? gfx::Rect(restored_size_dip()) + : GetBoundsInDIP(); } set_pending_bounds_dip(AdjustBoundsToConstraintsDIP(bounds_dip)); + set_pending_size_px( + delegate()->ConvertRectToPixels(pending_bounds_dip()).size()); // Store the restored bounds if current state differs from the normal state. // It can be client or compositor side change from normal to something else. @@ -442,33 +446,41 @@ void WaylandToplevelWindow::SetBoundsInPixels(const gfx::Rect& bounds) { } } +void WaylandToplevelWindow::SetBoundsInDIP(const gfx::Rect& bounds_dip) { + WaylandWindow::SetBoundsInDIP(bounds_dip); + if (shell_toplevel_ && screen_coordinates_enabled_) + shell_toplevel_->RequestWindowBounds(bounds_dip); +} + void WaylandToplevelWindow::SetOrigin(const gfx::Point& origin) { - // TODO(crbug.com/1306688): Using UpdateBoundsInDIP changes the size of the - // window due to the rounding. Change this to use SetBoundsInDIP when - // `bounds_px_` becomes `bounds_dip_`. - gfx::Point origin_px = - gfx::ScaleToFlooredPoint(origin, window_scale(), window_scale()); - WaylandWindow::SetBoundsInPixels( - gfx::Rect(origin_px, GetBoundsInPixels().size())); + gfx::Rect new_bounds(origin, GetBoundsInDIP().size()); + WaylandWindow::SetBoundsInDIP(new_bounds); } void WaylandToplevelWindow::HandleSurfaceConfigure(uint32_t serial) { ProcessPendingBoundsDip(serial); set_pending_bounds_dip({}); + set_pending_size_px({}); } -void WaylandToplevelWindow::UpdateVisualSize(const gfx::Size& size_px, - float scale_factor) { - WaylandWindow::UpdateVisualSize(size_px, scale_factor); +void WaylandToplevelWindow::UpdateVisualSize(const gfx::Size& size_px) { + WaylandWindow::UpdateVisualSize(size_px); if (!shell_toplevel_) return; - if (!ProcessVisualSizeUpdate(size_px, scale_factor) && - set_geometry_on_next_frame_) { - auto size_dip = gfx::ScaleToRoundedSize(size_px, 1.f / scale_factor); - SetWindowGeometry(gfx::Rect(size_dip)); - set_geometry_on_next_frame_ = false; + if (!ProcessVisualSizeUpdate(size_px)) { + // Early-out if shell surface is still not configure at this point, which + // indicates it is not mapped yet, which should happen in an upcoming frame. + if (!shell_toplevel()->IsConfigured()) + return; + + if (set_geometry_on_next_frame_) { + auto size_dip = gfx::ScaleToRoundedSize(size_px, 1.f / window_scale()); + // TODO(crbug.com/3814157): Use DIP bounds instead. + SetWindowGeometry(gfx::Rect(size_dip)); + set_geometry_on_next_frame_ = false; + } } // UpdateVisualSize() indicates a frame update, which means we can forward new @@ -491,6 +503,8 @@ bool WaylandToplevelWindow::OnInitialize( SetWorkspaceExtensionDelegate(properties.workspace_extension_delegate); SetDeskExtension(this, static_cast<DeskExtension*>(this)); + z_order_ = properties.z_order; + if (!properties.workspace.empty()) { int workspace; base::StringToInt(properties.workspace, &workspace); @@ -873,17 +887,21 @@ void WaylandToplevelWindow::SetOrResetRestoredBounds() { void WaylandToplevelWindow::SetUpShellIntegration() { // This method should be called after the XDG surface is initialized. DCHECK(shell_toplevel_); - if (connection()->zaura_shell() && !aura_surface_) { - static constexpr zaura_surface_listener zaura_surface_listener = { - &OcclusionChanged, &LockFrame, &UnlockFrame, &OcclusionStateChanged, - &DeskChanged, &StartThrottle, &EndThrottle, - }; - aura_surface_.reset(zaura_shell_get_aura_surface( - connection()->zaura_shell()->wl_object(), root_surface()->surface())); - zaura_surface_add_listener(aura_surface_.get(), &zaura_surface_listener, - this); + if (connection()->zaura_shell()) { + if (!aura_surface_) { + static constexpr zaura_surface_listener zaura_surface_listener = { + &OcclusionChanged, &LockFrame, &UnlockFrame, + &OcclusionStateChanged, &DeskChanged, &StartThrottle, + &EndThrottle, + }; + aura_surface_.reset(zaura_shell_get_aura_surface( + connection()->zaura_shell()->wl_object(), root_surface()->surface())); + zaura_surface_add_listener(aura_surface_.get(), &zaura_surface_listener, + this); + } zaura_surface_set_occlusion_tracking(aura_surface_.get()); SetImmersiveFullscreenStatus(false); + SetInitialZOrder(); SetInitialWorkspace(); if (restore_window_id_) { DCHECK(!restore_window_id_source_); @@ -949,6 +967,10 @@ void WaylandToplevelWindow::SetInitialWorkspace() { } } +void WaylandToplevelWindow::SetInitialZOrder() { + shell_toplevel_->SetZOrder(z_order_); +} + void WaylandToplevelWindow::UpdateWindowMask() { std::vector<gfx::Rect> region{gfx::Rect({}, visual_size_px())}; root_surface()->SetOpaqueRegion(opaque_region_px_.has_value() @@ -962,4 +984,12 @@ bool WaylandToplevelWindow::GetTabletMode() { return connection()->GetTabletMode(); } +void WaylandToplevelWindow::SetFloat(bool value) { + DCHECK(shell_toplevel_); + if (value) + shell_toplevel_->SetFloat(); + else + shell_toplevel_->UnSetFloat(); +} + } // 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 2911821e5bb..d25ab3c0dc2 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.h @@ -5,6 +5,7 @@ #ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_TOPLEVEL_WINDOW_H_ #define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_TOPLEVEL_WINDOW_H_ +#include "base/memory/raw_ptr.h" #include "build/chromeos_buildflags.h" #include "ui/gfx/geometry/insets.h" #include "ui/gfx/geometry/vector2d.h" @@ -73,16 +74,13 @@ class WaylandToplevelWindow : public WaylandWindow, void NotifyStartupComplete(const std::string& startup_id) override; void SetAspectRatio(const gfx::SizeF& aspect_ratio) override; void SetBoundsInPixels(const gfx::Rect& bounds) override; + void SetBoundsInDIP(const gfx::Rect& bounds) override; // Sets the window's origin. void SetOrigin(const gfx::Point& origin); // WaylandWindow overrides: - absl::optional<std::vector<gfx::Rect>> GetWindowShape() const override; - - bool screen_coordinates_enabled() const { - return screen_coordinates_enabled_; - } + bool IsScreenCoordinatesEnabled() const override; // Client-side decorations on Wayland take some portion of the window surface, // and when they are turned on or off, the window geometry is changed. That @@ -108,7 +106,7 @@ class WaylandToplevelWindow : public WaylandWindow, bool is_fullscreen, bool is_activated) override; void HandleSurfaceConfigure(uint32_t serial) override; - void UpdateVisualSize(const gfx::Size& size_px, float scale_factor) override; + void UpdateVisualSize(const gfx::Size& size_px) override; bool OnInitialize(PlatformWindowInitProperties properties) override; bool IsActive() const override; bool IsSurfaceConfigured() override; @@ -157,6 +155,7 @@ class WaylandToplevelWindow : public WaylandWindow, void Lock(WaylandOrientationLockType lock_Type) override; void Unlock() override; bool GetTabletMode() override; + void SetFloat(bool value) override; // DeskExtension: int GetNumberOfDesks() const override; @@ -217,6 +216,10 @@ class WaylandToplevelWindow : public WaylandWindow, // This must be called in SetUpShellIntegration(). void SetInitialWorkspace(); + // Sets `z_order_` in the `shell_toplevel_`. + // Must be called in SetUpShellIntegration(). + void SetInitialZOrder(); + // Wrappers around shell surface. std::unique_ptr<ShellToplevelWrapper> shell_toplevel_; @@ -253,8 +256,6 @@ class WaylandToplevelWindow : public WaylandWindow, // e.g. lacros-taskmanager. bool use_native_frame_ = false; - absl::optional<std::vector<gfx::Rect>> window_shape_in_dips_; - absl::optional<std::vector<gfx::Rect>> opaque_region_px_; absl::optional<gfx::Rect> input_region_px_; @@ -299,10 +300,13 @@ class WaylandToplevelWindow : public WaylandWindow, // If |workspace_| is -1, window is visible on all workspaces. absl::optional<int> workspace_ = absl::nullopt; + // The z order for the window. + ZOrderLevel z_order_ = ZOrderLevel::kNormal; + // True when screen coordinates is enabled. bool screen_coordinates_enabled_; - WorkspaceExtensionDelegate* workspace_extension_delegate_ = nullptr; + raw_ptr<WorkspaceExtensionDelegate> workspace_extension_delegate_ = nullptr; }; } // 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 2f09d660dce..39926708863 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_touch.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_touch.cc @@ -12,6 +12,7 @@ #include "ui/gfx/geometry/point_f.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_serial_tracker.h" #include "ui/ozone/platform/wayland/host/wayland_window.h" @@ -45,7 +46,7 @@ void WaylandTouch::Down(void* data, if (!surface) return; - WaylandTouch* touch = static_cast<WaylandTouch*>(data); + auto* touch = static_cast<WaylandTouch*>(data); DCHECK(touch); touch->connection_->serial_tracker().UpdateSerial(wl::SerialType::kTouchPress, @@ -56,7 +57,7 @@ void WaylandTouch::Down(void* data, gfx::PointF(wl_fixed_to_double(x), wl_fixed_to_double(y)), window); base::TimeTicks timestamp = base::TimeTicks() + base::Milliseconds(time); touch->delegate_->OnTouchPressEvent(window, location, timestamp, id, - Delegate::EventDispatchPolicy::kOnFrame); + wl::EventDispatchPolicy::kOnFrame); } void WaylandTouch::Up(void* data, @@ -64,12 +65,22 @@ void WaylandTouch::Up(void* data, uint32_t serial, uint32_t time, int32_t id) { - WaylandTouch* touch = static_cast<WaylandTouch*>(data); + auto* touch = static_cast<WaylandTouch*>(data); DCHECK(touch); + // TODO(https://crbug.com/1353873): Gnome/Wayland, KDE and Weston compositors + // have a bug where wl_touch.up does not come accompanied by a respective + // wl_touch.frame event. On these particular set ups, dispatch the event + // immediately. + auto event_dispatch_policy = +#if BUILDFLAG(IS_CHROMEOS_LACROS) + wl::EventDispatchPolicy::kOnFrame; +#else + wl::EventDispatchPolicy::kImmediate; +#endif + base::TimeTicks timestamp = base::TimeTicks() + base::Milliseconds(time); - touch->delegate_->OnTouchReleaseEvent( - timestamp, id, Delegate::EventDispatchPolicy::kOnFrame); + touch->delegate_->OnTouchReleaseEvent(timestamp, id, event_dispatch_policy); } void WaylandTouch::Motion(void* data, @@ -78,8 +89,9 @@ void WaylandTouch::Motion(void* data, int32_t id, wl_fixed_t x, wl_fixed_t y) { - WaylandTouch* touch = static_cast<WaylandTouch*>(data); + auto* touch = static_cast<WaylandTouch*>(data); DCHECK(touch); + const WaylandWindow* target = touch->delegate_->GetTouchTarget(id); if (!target) { LOG(WARNING) << "Touch event fired with wrong id"; @@ -89,18 +101,20 @@ void WaylandTouch::Motion(void* data, gfx::PointF(wl_fixed_to_double(x), wl_fixed_to_double(y)), target); base::TimeTicks timestamp = base::TimeTicks() + base::Milliseconds(time); touch->delegate_->OnTouchMotionEvent(location, timestamp, id, - Delegate::EventDispatchPolicy::kOnFrame); + wl::EventDispatchPolicy::kOnFrame); } void WaylandTouch::Cancel(void* data, wl_touch* obj) { - WaylandTouch* touch = static_cast<WaylandTouch*>(data); + auto* touch = static_cast<WaylandTouch*>(data); DCHECK(touch); + touch->delegate_->OnTouchCancelEvent(); } void WaylandTouch::Frame(void* data, wl_touch* obj) { auto* touch = static_cast<WaylandTouch*>(data); DCHECK(touch); + touch->delegate_->OnTouchFrame(); } @@ -123,7 +137,8 @@ void WaylandTouch::Tool(void* data, struct zcr_touch_stylus_v2* obj, uint32_t id, uint32_t stylus_type) { - auto* pointer = static_cast<WaylandTouch*>(data); + auto* touch = static_cast<WaylandTouch*>(data); + DCHECK(touch); ui::EventPointerType pointer_type = ui::EventPointerType::kTouch; switch (stylus_type) { @@ -137,7 +152,7 @@ void WaylandTouch::Tool(void* data, break; } - pointer->delegate_->OnTouchStylusToolChanged(id, pointer_type); + touch->delegate_->OnTouchStylusToolChanged(id, pointer_type); } // static @@ -146,7 +161,10 @@ void WaylandTouch::Force(void* data, uint32_t time, uint32_t id, wl_fixed_t force) { - NOTIMPLEMENTED_LOG_ONCE(); + auto* touch = static_cast<WaylandTouch*>(data); + DCHECK(touch); + + touch->delegate_->OnTouchStylusForceChanged(id, wl_fixed_to_double(force)); } // static @@ -156,7 +174,12 @@ void WaylandTouch::Tilt(void* data, uint32_t id, wl_fixed_t tilt_x, wl_fixed_t tilt_y) { - NOTIMPLEMENTED_LOG_ONCE(); + auto* touch = static_cast<WaylandTouch*>(data); + DCHECK(touch); + + touch->delegate_->OnTouchStylusTiltChanged( + id, + gfx::Vector2dF(wl_fixed_to_double(tilt_x), wl_fixed_to_double(tilt_y))); } } // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_touch.h b/chromium/ui/ozone/platform/wayland/host/wayland_touch.h index 4b7b336e9c1..2d43acd27dc 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_touch.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_touch.h @@ -7,6 +7,7 @@ #include <vector> +#include "base/memory/raw_ptr.h" #include "base/time/time.h" #include "ui/events/pointer_details.h" #include "ui/ozone/platform/wayland/common/wayland_object.h" @@ -15,6 +16,10 @@ namespace gfx { class PointF; } // namespace gfx +namespace wl { +enum class EventDispatchPolicy; +} + namespace ui { class WaylandConnection; @@ -78,28 +83,24 @@ class WaylandTouch { wl::Object<wl_touch> obj_; wl::Object<zcr_touch_stylus_v2> zcr_touch_stylus_v2_; - WaylandConnection* const connection_; - Delegate* const delegate_; + const raw_ptr<WaylandConnection> connection_; + const raw_ptr<Delegate> delegate_; }; class WaylandTouch::Delegate { public: - enum class EventDispatchPolicy { - kImmediate, - kOnFrame, - }; virtual void OnTouchPressEvent(WaylandWindow* window, const gfx::PointF& location, base::TimeTicks timestamp, PointerId id, - EventDispatchPolicy dispatch_policy) = 0; + wl::EventDispatchPolicy dispatch_policy) = 0; virtual void OnTouchReleaseEvent(base::TimeTicks timestamp, PointerId id, - EventDispatchPolicy dispatch_policy) = 0; + wl::EventDispatchPolicy dispatch_policy) = 0; virtual void OnTouchMotionEvent(const gfx::PointF& location, base::TimeTicks timestamp, PointerId id, - EventDispatchPolicy dispatch_policy) = 0; + wl::EventDispatchPolicy dispatch_policy) = 0; virtual void OnTouchCancelEvent() = 0; virtual void OnTouchFrame() = 0; virtual void OnTouchFocusChanged(WaylandWindow* window) = 0; @@ -107,6 +108,9 @@ class WaylandTouch::Delegate { virtual const WaylandWindow* GetTouchTarget(PointerId id) const = 0; virtual void OnTouchStylusToolChanged(PointerId pointer_id, EventPointerType pointer_type) = 0; + virtual void OnTouchStylusForceChanged(PointerId pointer_id, float force) = 0; + virtual void OnTouchStylusTiltChanged(PointerId pointer_id, + const gfx::Vector2dF& tilt) = 0; }; } // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_touch_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_touch_unittest.cc index 95f56011dc2..6cb8bafb95c 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_touch_unittest.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_touch_unittest.cc @@ -8,6 +8,7 @@ #include <cstdint> #include <memory> +#include "base/memory/raw_ptr.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/events/devices/device_data_manager.h" @@ -22,6 +23,14 @@ #include "ui/ozone/platform/wayland/test/wayland_test.h" #include "ui/ozone/test/mock_platform_window_delegate.h" +#if BUILDFLAG(USE_XKBCOMMON) +#include "base/memory/free_deleter.h" +#include "base/memory/platform_shared_memory_region.h" +#include "base/memory/shared_memory_mapping.h" +#include "base/memory/unsafe_shared_memory_region.h" +#include "ui/events/keycodes/scoped_xkb.h" // nogncheck +#endif + using ::testing::_; using ::testing::SaveArg; using ::testing::Values; @@ -31,7 +40,12 @@ namespace ui { namespace { ACTION_P(CloneEvent, ptr) { - *ptr = Event::Clone(*arg0); + *ptr = arg0->Clone(); +} + +bool CompareFloat(float a, float b) { + constexpr float kEpsilon = std::numeric_limits<float>::epsilon(); + return std::isnan(a) ? std::isnan(b) : fabs(a - b) < kEpsilon; } } // namespace @@ -63,15 +77,22 @@ class WaylandTouchTest : public WaylandTest { void CheckEventType( ui::EventType event_type, ui::Event* event, - ui::EventPointerType pointer_type = ui::EventPointerType::kTouch) { + ui::EventPointerType pointer_type = ui::EventPointerType::kTouch, + float force = std::numeric_limits<float>::quiet_NaN(), + float tilt_x = 0.0, + float tilt_y = 0.0) { ASSERT_TRUE(event); ASSERT_TRUE(event->IsTouchEvent()); auto* touch_event = event->AsTouchEvent(); EXPECT_EQ(event_type, touch_event->type()); + EXPECT_EQ(pointer_type, touch_event->pointer_details().pointer_type); + EXPECT_TRUE(CompareFloat(force, touch_event->pointer_details().force)); + EXPECT_TRUE(CompareFloat(tilt_x, touch_event->pointer_details().tilt_x)); + EXPECT_TRUE(CompareFloat(tilt_y, touch_event->pointer_details().tilt_y)); } - wl::TestTouch* touch_; + raw_ptr<wl::TestTouch> touch_; }; TEST_P(WaylandTouchTest, TouchPressAndMotion) { @@ -126,7 +147,47 @@ TEST_P(WaylandTouchTest, TouchPressAndMotionWithStylus) { wl_touch_send_frame(touch_->resource()); Sync(); - CheckEventType(ui::ET_TOUCH_RELEASED, event.get()); + CheckEventType(ui::ET_TOUCH_RELEASED, event.get(), + ui::EventPointerType::kPen); +} + +// Tests that touch events with stylus pen work. This variant of the test sends +// the tool information after the touch down event, and ensures that +// wl_touch::frame event handles it correctly. +TEST_P(WaylandTouchTest, TouchPressAndMotionWithStylus2) { + std::unique_ptr<Event> event; + EXPECT_CALL(delegate_, DispatchEvent(_)).WillRepeatedly(CloneEvent(&event)); + + uint32_t time = 0; + wl_touch_send_down(touch_->resource(), 1, 0, surface_->resource(), 0 /* id */, + wl_fixed_from_int(50), wl_fixed_from_int(100)); + zcr_touch_stylus_v2_send_tool(touch_->touch_stylus()->resource(), 0 /* id */, + ZCR_TOUCH_STYLUS_V2_TOOL_TYPE_PEN); + zcr_touch_stylus_v2_send_force(touch_->touch_stylus()->resource(), ++time, + 0 /* id */, wl_fixed_from_double(1.0f)); + zcr_touch_stylus_v2_send_tilt(touch_->touch_stylus()->resource(), ++time, + 0 /* id */, wl_fixed_from_double(-45), + wl_fixed_from_double(45)); + wl_touch_send_frame(touch_->resource()); + + Sync(); + CheckEventType(ui::ET_TOUCH_PRESSED, event.get(), ui::EventPointerType::kPen, + 1.0f /* force */, -45.0f /* tilt_x */, 45.0f /* tilt_y */); + + wl_touch_send_motion(touch_->resource(), 500, 0 /* id */, + wl_fixed_from_int(100), wl_fixed_from_int(100)); + wl_touch_send_frame(touch_->resource()); + + Sync(); + CheckEventType(ui::ET_TOUCH_MOVED, event.get(), ui::EventPointerType::kPen, + 1.0f /* force */, -45.0f /* tilt_x */, 45.0f /* tilt_y */); + + wl_touch_send_up(touch_->resource(), 1, 1000, 0 /* id */); + wl_touch_send_frame(touch_->resource()); + + Sync(); + CheckEventType(ui::ET_TOUCH_RELEASED, event.get(), ui::EventPointerType::kPen, + 1.0f /* force */, -45.0f /* tilt_x */, 45.0f /* tilt_y */); } // Tests that touch focus is correctly set and released. @@ -226,7 +287,39 @@ TEST_P(WaylandTouchTest, KeyboardFlagsSet) { wl::TestKeyboard* keyboard = server_.seat()->keyboard(); ASSERT_TRUE(keyboard); +#if BUILDFLAG(USE_XKBCOMMON) + // Set up XKB bits and set the keymap to the client. + std::unique_ptr<xkb_context, ui::XkbContextDeleter> xkb_context( + xkb_context_new(XKB_CONTEXT_NO_FLAGS)); + std::unique_ptr<xkb_keymap, ui::XkbKeymapDeleter> xkb_keymap( + xkb_keymap_new_from_names(xkb_context.get(), nullptr /*names*/, + XKB_KEYMAP_COMPILE_NO_FLAGS)); + std::unique_ptr<xkb_state, ui::XkbStateDeleter> xkb_state( + xkb_state_new(xkb_keymap.get())); + + std::unique_ptr<char, base::FreeDeleter> keymap_string( + xkb_keymap_get_as_string(xkb_keymap.get(), XKB_KEYMAP_FORMAT_TEXT_V1)); + DCHECK(keymap_string.get()); + size_t keymap_size = strlen(keymap_string.get()) + 1; + + base::UnsafeSharedMemoryRegion shared_keymap_region = + base::UnsafeSharedMemoryRegion::Create(keymap_size); + base::WritableSharedMemoryMapping shared_keymap = shared_keymap_region.Map(); + base::subtle::PlatformSharedMemoryRegion platform_shared_keymap = + base::UnsafeSharedMemoryRegion::TakeHandleForSerialization( + std::move(shared_keymap_region)); + DCHECK(shared_keymap.IsValid()); + + memcpy(shared_keymap.memory(), keymap_string.get(), keymap_size); + wl_keyboard_send_keymap( + keyboard->resource(), WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, + platform_shared_keymap.GetPlatformHandle().fd, keymap_size); +#endif + // Press 'control' key. + wl_keyboard_send_modifiers(keyboard->resource(), 3, 4 /* mods_depressed*/, + 0 /* mods_latched */, 0 /* mods_locked */, + 0 /* group */); wl_keyboard_send_key(keyboard->resource(), ++serial, ++timestamp, 29 /* Control */, WL_KEYBOARD_KEY_STATE_PRESSED); Sync(); @@ -256,6 +349,9 @@ TEST_P(WaylandTouchTest, KeyboardFlagsSet) { EXPECT_TRUE(event->flags() & ui::EF_CONTROL_DOWN); // Release 'control' key. + wl_keyboard_send_modifiers(keyboard->resource(), 3, 0 /* mods_depressed*/, + 0 /* mods_latched */, 0 /* mods_locked */, + 0 /* group */); wl_keyboard_send_key(keyboard->resource(), ++serial, ++timestamp, 29 /* Control */, WL_KEYBOARD_KEY_STATE_RELEASED); Sync(); diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window.cc b/chromium/ui/ozone/platform/wayland/host/wayland_window.cc index 5ffe811c143..4b9e3781cef 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_window.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_window.cc @@ -21,9 +21,11 @@ #include "ui/base/dragdrop/mojom/drag_drop_types.mojom.h" #include "ui/base/dragdrop/os_exchange_data.h" #include "ui/events/event.h" +#include "ui/events/event_target_iterator.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/color_space.h" #include "ui/gfx/geometry/point_f.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/native_widget_types.h" @@ -32,7 +34,6 @@ #include "ui/ozone/common/features.h" #include "ui/ozone/platform/wayland/common/wayland_overlay_config.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_frame_manager.h" @@ -129,12 +130,8 @@ void WaylandWindow::UpdateWindowScale(bool update_bounds) { float new_scale = output->scale_factor(); ui_scale_ = output->GetUIScaleFactor(); - float old_scale = window_scale(); - window_scale_ = new_scale; - - // We need to keep DIP size of the window the same whenever the scale changes. - if (update_bounds) - UpdateBoundsInDIP(gfx::ScaleToEnclosedRect(bounds_px_, 1.0 / old_scale)); + if (SetWindowScale(new_scale)) + delegate_->OnBoundsChanged({true}); // Propagate update to the child windows if (child_window_) @@ -145,9 +142,12 @@ gfx::AcceleratedWidget WaylandWindow::GetWidget() const { return accelerated_widget_; } -void WaylandWindow::SetWindowScale(float new_scale) { +bool WaylandWindow::SetWindowScale(float new_scale) { DCHECK_GE(new_scale, 0.f); + bool changed = window_scale_ != new_scale; window_scale_ = new_scale; + size_px_ = gfx::ScaleToEnclosingRect(bounds_dip_, new_scale).size(); + return changed; } uint32_t WaylandWindow::GetPreferredEnteredOutputId() { @@ -194,16 +194,24 @@ uint32_t WaylandWindow::GetPreferredEnteredOutputId() { return preferred_output_id; } -void WaylandWindow::SetPointerFocus(bool focus) { - has_pointer_focus_ = focus; - +void WaylandWindow::OnPointerFocusChanged(bool focused) { // Whenever the window gets the pointer focus back, the cursor shape must be // updated. Otherwise, it is invalidated upon wl_pointer::leave and is not // restored by the Wayland compositor. - if (has_pointer_focus_ && cursor_) + if (focused && cursor_) UpdateCursorShape(cursor_); } +bool WaylandWindow::HasPointerFocus() const { + return this == connection_->wayland_window_manager() + ->GetCurrentPointerFocusedWindow(); +} + +bool WaylandWindow::HasKeyboardFocus() const { + return this == connection_->wayland_window_manager() + ->GetCurrentKeyboardFocusedWindow(); +} + void WaylandWindow::RemoveEnteredOutput(uint32_t output_id) { root_surface_->RemoveEnteredOutput(output_id); } @@ -245,7 +253,7 @@ void WaylandWindow::Show(bool inactive) { } void WaylandWindow::Hide() { - can_submit_frames_ = false; + received_configure_event_ = false; // Mutter compositor crashes if we don't remove subsurface roles when hiding. if (primary_subsurface_) { @@ -290,32 +298,30 @@ void WaylandWindow::PrepareForShutdown() { } void WaylandWindow::SetBoundsInPixels(const gfx::Rect& bounds_px) { - gfx::Rect adjusted_bounds_px = AdjustBoundsToConstraintsPx(bounds_px); - if (bounds_px_ == adjusted_bounds_px) - return; - bounds_px_ = adjusted_bounds_px; - - if (update_visual_size_immediately_) - UpdateVisualSize(bounds_px.size(), window_scale()); - delegate_->OnBoundsChanged(bounds_px_); + // TODO(crbug.com/): This is currently used only by unit tests. + // Figure out how to migrate to test only methods. + auto bounds_dip = delegate_->ConvertRectToDIP(bounds_px); + SetBoundsInDIP(bounds_dip); } gfx::Rect WaylandWindow::GetBoundsInPixels() const { - return bounds_px_; + // TODO(crbug.com/): This is currently used only by unit tests. + // Figure out how to migrate to test only methods. + return delegate_->ConvertRectToPixels(bounds_dip_); } -void WaylandWindow::SetBoundsInDIP(const gfx::Rect& bounds) { - SetBoundsInPixels(delegate_->ConvertRectToPixels(bounds)); +void WaylandWindow::SetBoundsInDIP(const gfx::Rect& bounds_dip) { + UpdateBoundsInDIP(bounds_dip); } gfx::Rect WaylandWindow::GetBoundsInDIP() const { - return delegate_->ConvertRectToDIP(bounds_px_); + return bounds_dip_; } void WaylandWindow::OnSurfaceConfigureEvent() { - if (can_submit_frames_) + if (received_configure_event_) return; - can_submit_frames_ = true; + received_configure_event_ = true; frame_manager_->MaybeProcessPendingFrame(); } @@ -438,15 +444,7 @@ bool WaylandWindow::ShouldUpdateWindowShape() const { } bool WaylandWindow::CanDispatchEvent(const PlatformEvent& event) { - if (event->IsMouseEvent() || event->IsPinchEvent()) - return has_pointer_focus_; - if (event->IsKeyEvent()) - return has_keyboard_focus_; - if (event->IsTouchEvent()) - return has_touch_focus_; - if (event->IsScrollEvent()) - return has_pointer_focus_; - return false; + return CanAcceptEvent(*event); } uint32_t WaylandWindow::DispatchEvent(const PlatformEvent& native_event) { @@ -457,8 +455,6 @@ uint32_t WaylandWindow::DispatchEvent(const PlatformEvent& native_event) { connection_->wayland_window_manager()->located_events_grabber(); auto* root_parent_window = GetRootParentWindow(); - UpdateCursorPositionFromEvent(event); - // We must reroute the events to the event grabber iff these windows belong // to the same root parent window. For example, there are 2 top level // Wayland windows. One of them (window_1) has a child menu window that is @@ -473,25 +469,51 @@ uint32_t WaylandWindow::DispatchEvent(const PlatformEvent& native_event) { event_grabber && root_parent_window == event_grabber->GetRootParentWindow(); if (send_to_grabber) { - ConvertEventLocationToTargetWindowLocation( - event_grabber->GetBoundsInDIP().origin(), GetBoundsInDIP().origin(), - event->AsLocatedEvent()); + WaylandEventSource::ConvertEventToTarget(event_grabber, + event->AsLocatedEvent()); + Event::DispatcherApi(event).set_target(event_grabber); } - // Wayland sends locations in DIP so they need to be translated to - // physical pixels. + // Wayland sends locations in DIP but dispatch code expects pixels, so they + // need to be translated to physical pixels. event->AsLocatedEvent()->set_location_f(gfx::ScalePoint( event->AsLocatedEvent()->location_f(), window_scale(), window_scale())); - if (send_to_grabber) - return event_grabber->DispatchEventToDelegate(native_event); + if (send_to_grabber) { + event_grabber->DispatchEventToDelegate(event); + // The event should be handled by the grabber, so don't send to next + // dispacher. + return POST_DISPATCH_STOP_PROPAGATION; + } } // Dispatch all keyboard events to the root window. if (event->IsKeyEvent()) return GetRootParentWindow()->DispatchEventToDelegate(event); - return DispatchEventToDelegate(native_event); + return DispatchEventToDelegate(event); +} + +// EventTarget: +bool WaylandWindow::CanAcceptEvent(const Event& event) { +#if DCHECK_IS_ON() + if (!disable_null_target_dcheck_for_test_) + DCHECK(event.target()); +#endif + return this == event.target(); +} + +EventTarget* WaylandWindow::GetParentTarget() { + return nullptr; +} + +std::unique_ptr<EventTargetIterator> WaylandWindow::GetChildIterator() const { + NOTREACHED(); + return nullptr; +} + +EventTargeter* WaylandWindow::GetEventTargeter() { + return nullptr; } void WaylandWindow::HandleSurfaceConfigure(uint32_t serial) { @@ -523,14 +545,13 @@ void WaylandWindow::HandlePopupConfigure(const gfx::Rect& bounds_dip) { NOTREACHED() << "Only shell popups must receive HandlePopupConfigure calls."; } -void WaylandWindow::UpdateVisualSize(const gfx::Size& size_px, - float scale_factor) { +void WaylandWindow::UpdateVisualSize(const gfx::Size& size_px) { if (visual_size_px_ == size_px) return; visual_size_px_ = size_px; UpdateWindowMask(); - if (apply_pending_state_on_update_visual_size_) { + if (apply_pending_state_on_update_visual_size_for_testing_) { root_surface_->ApplyPendingState(); connection_->ScheduleFlush(); } @@ -540,10 +561,6 @@ void WaylandWindow::OnCloseRequest() { delegate_->OnCloseRequest(); } -absl::optional<std::vector<gfx::Rect>> WaylandWindow::GetWindowShape() const { - return absl::nullopt; -} - void WaylandWindow::OnDragEnter(const gfx::PointF& point, std::unique_ptr<OSExchangeData> data, int operation) { @@ -589,10 +606,16 @@ void WaylandWindow::OnDragSessionClose(DragOperation operation) { } void WaylandWindow::UpdateBoundsInDIP(const gfx::Rect& bounds_dip) { - // This method is used to update the content size by calling WindowWindow's - // SetBounds, instead of WaylandToplevelWindow's override, which sends a - // request to the compositor. - WaylandWindow::SetBoundsInPixels(delegate_->ConvertRectToPixels(bounds_dip)); + gfx::Rect adjusted_bounds_dip = AdjustBoundsToConstraintsDIP(bounds_dip); + if (bounds_dip_ == adjusted_bounds_dip) + return; + bool origin_changed = bounds_dip_.origin() != bounds_dip.origin(); + bounds_dip_ = adjusted_bounds_dip; + size_px_ = delegate_->ConvertRectToPixels(bounds_dip).size(); + + if (update_visual_size_immediately_for_testing_) + UpdateVisualSize(size_px()); + delegate_->OnBoundsChanged({origin_changed}); } bool WaylandWindow::Initialize(PlatformWindowInitProperties properties) { @@ -607,13 +630,16 @@ bool WaylandWindow::Initialize(PlatformWindowInitProperties properties) { // Update visual size in tests immediately if the test config is set. // Otherwise, such tests as interactive_ui_tests fail. - if (!update_visual_size_immediately_) - set_update_visual_size_immediately(UseTestConfigForPlatformWindows()); + if (!update_visual_size_immediately_for_testing_) { + set_update_visual_size_immediately_for_testing( + UseTestConfigForPlatformWindows()); + } + bounds_dip_ = properties.bounds; // Properties contain DIP bounds but the buffer scale is initially 1 so it's // OK to assign. The bounds will be recalculated when the buffer scale // changes. - bounds_px_ = properties.bounds; + size_px_ = bounds_dip_.size(); opacity_ = properties.opacity; type_ = properties.type; @@ -634,7 +660,7 @@ bool WaylandWindow::Initialize(PlatformWindowInitProperties properties) { PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this); delegate_->OnAcceleratedWidgetAvailable(GetWidget()); - std::vector<gfx::Rect> region{gfx::Rect{bounds_px_.size()}}; + std::vector<gfx::Rect> region{gfx::Rect{size_px_}}; root_surface_->SetOpaqueRegion(®ion); root_surface_->ApplyPendingState(); connection_->ScheduleFlush(); @@ -644,6 +670,14 @@ bool WaylandWindow::Initialize(PlatformWindowInitProperties properties) { void WaylandWindow::SetWindowGeometry(gfx::Rect bounds) {} +gfx::Vector2d WaylandWindow::GetWindowGeometryOffsetInDIP() const { + if (!frame_insets_px_.has_value()) + return {}; + + return {static_cast<int>(frame_insets_px_->left() / window_scale_), + static_cast<int>(frame_insets_px_->top() / window_scale_)}; +} + void WaylandWindow::UpdateDecorations() {} WaylandWindow* WaylandWindow::GetRootParentWindow() { @@ -666,45 +700,8 @@ void WaylandWindow::OnLeftOutput() { // event. if (AsWaylandPopup()) return; - // Do not update the window scale where. It'll be updated when entring a new - // output. -} - -void WaylandWindow::UpdateCursorPositionFromEvent(const Event* orig_event) { - DCHECK(orig_event->IsLocatedEvent()); - - // This is a tricky part. Initially, Wayland sends events to surfaces the - // events are targeted for. But, in order to fulfill Chromium's assumptions - // about event targets, some of the events are rerouted and their locations - // are converted. The event we got here is rerouted and it has had its - // location fixed. - // - // Basically, this method must translate coordinates of all events - // in regards to top-level windows' coordinates as it's always located at - // origin (0,0) from Chromium point of view (remember that wl_shell/xdg_shell - // doesn't provide global coordinates to its clients). And it's totally fine - // to use it as the target. Thus, the location of the |event| is always - // converted using the top-level window's bounds as the target excluding - // cases, when the mouse/touch is over a top-level window. - auto* cursor_position = connection_->wayland_cursor_position(); - if (!cursor_position) - return; - const LocatedEvent* located_event = orig_event->AsLocatedEvent(); - std::unique_ptr<Event> event; - - auto* toplevel_window = GetRootParentWindow(); - if (toplevel_window != this) { - event = Event::Clone(*orig_event); - ConvertEventLocationToTargetWindowLocation( - toplevel_window->GetBoundsInDIP().origin(), GetBoundsInDIP().origin(), - event->AsLocatedEvent()); - located_event = event->AsLocatedEvent(); - } - - cursor_position->OnCursorPositionChanged( - located_event->location() + - toplevel_window->GetBoundsInDIP().origin().OffsetFromOrigin()); + UpdateWindowScale(true); } WaylandWindow* WaylandWindow::GetTopMostChildWindow() { @@ -724,6 +721,10 @@ WaylandPopup* WaylandWindow::AsWaylandPopup() { return nullptr; } +bool WaylandWindow::IsScreenCoordinatesEnabled() const { + return false; +} + uint32_t WaylandWindow::DispatchEventToDelegate( const PlatformEvent& native_event) { bool handled = DispatchEventFromNativeUiEvent( @@ -874,7 +875,7 @@ bool WaylandWindow::CommitOverlays( gfx::RectF(visual_size), gfx::RectF(), root_surface()->use_blending(), gfx::Rect(), root_surface()->opacity(), gfx::OverlayPriorityHint::kNone, - rounded_clip_bounds, gfx::ColorSpace(), absl::nullopt), + rounded_clip_bounds, gfx::ColorSpace::CreateSRGB(), absl::nullopt), nullptr, root_surface()->buffer_id(), buffer_scale); } @@ -964,7 +965,8 @@ void WaylandWindow::ProcessPendingBoundsDip(uint32_t serial) { // for a frame update, which will invoke UpdateVisualSize(). LOG_IF(WARNING, pending_configures_.size() > 100u) << "The queue of configures is longer than 100!"; - pending_configures_.push_back({pending_bounds_dip_, serial}); + pending_configures_.push_back( + {pending_bounds_dip_, pending_size_px_, serial}); // The Wayland compositor can generate xdg-shell.configure events more // frequently than frame updates from gpu process. Throttle // ApplyPendingBounds() such that we forward new bounds to @@ -1030,24 +1032,17 @@ gfx::Rect WaylandWindow::AdjustBoundsToConstraintsDIP( return adjusted_bounds_dip; } -bool WaylandWindow::ProcessVisualSizeUpdate(const gfx::Size& size_px, - float scale_factor) { +bool WaylandWindow::ProcessVisualSizeUpdate(const gfx::Size& size_px) { // TODO(crbug.com/1307501): Optimize this to be less expensive. Maybe // precompute in pixels for configure events. pending_configures_ can have 10s // of elements in it for several frames under some conditions. // The `pending_configures_` should store px size instead of dip. - auto result = std::find_if( - pending_configures_.begin(), pending_configures_.end(), - [this, &size_px, &scale_factor](auto& configure) { - // Since size_px comes from SetBounds via UpdateVisualSize in - // WaylandTopLevelWindow, we also need to adjust it for bounds to see if - // we match. - return AdjustBoundsToConstraintsPx( - gfx::ScaleToEnclosingRect(configure.bounds_dip, - scale_factor)) - .size() == size_px && - configure.set; - }); + auto result = + std::find_if(pending_configures_.begin(), pending_configures_.end(), + [&size_px](auto& configure) { + // Should we adjust? + return configure.size_px == size_px && configure.set; + }); if (result != pending_configures_.end()) { auto serial = result->serial; @@ -1064,11 +1059,8 @@ void WaylandWindow::ApplyPendingBounds() { DCHECK(!pending_configures_.empty()); for (auto& configure : pending_configures_) configure.set = true; + // Do not call SetBoundsInDIP which may be overridden by a subclass. UpdateBoundsInDIP(pending_configures_.back().bounds_dip); } -bool WaylandWindow::HasPendingConfigures() const { - return !pending_configures_.empty(); -} - } // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window.h b/chromium/ui/ozone/platform/wayland/host/wayland_window.h index 4c76e6140d5..603fb3cf3f6 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_window.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_window.h @@ -15,10 +15,12 @@ #include "base/containers/flat_set.h" #include "base/containers/linked_list.h" #include "base/gtest_prod_util.h" +#include "base/memory/raw_ptr.h" #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" #include "base/task/single_thread_task_runner.h" #include "ui/base/dragdrop/mojom/drag_drop_types.mojom-forward.h" +#include "ui/events/event_target.h" #include "ui/events/platform/platform_event_dispatcher.h" #include "ui/gfx/geometry/insets.h" #include "ui/gfx/geometry/point_f.h" @@ -51,7 +53,8 @@ using WidgetSubsurfaceSet = base::flat_set<std::unique_ptr<WaylandSubsurface>>; class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher, - public WmDragHandler { + public WmDragHandler, + public EventTarget { public: WaylandWindow(const WaylandWindow&) = delete; WaylandWindow& operator=(const WaylandWindow&) = delete; @@ -105,13 +108,12 @@ class WaylandWindow : public PlatformWindow, bool CommitOverlays(uint32_t frame_id, std::vector<wl::WaylandOverlayConfig>& overlays); - // Set whether this window has pointer focus and should dispatch mouse events. - void SetPointerFocus(bool focus); - bool has_pointer_focus() const { return has_pointer_focus_; } + // Called when the focus changed on this window. + void OnPointerFocusChanged(bool focused); - // Set whether this window has keyboard focus and should dispatch key events. - void set_keyboard_focus(bool focus) { has_keyboard_focus_ = focus; } - bool has_keyboard_focus() const { return has_keyboard_focus_; } + // Returns the focus status of this window. + bool HasPointerFocus() const; + bool HasKeyboardFocus() const; // The methods set or return whether this window has touch focus and should // dispatch touch events. @@ -124,9 +126,9 @@ class WaylandWindow : public PlatformWindow, WaylandWindow* child_window() const { return child_window_; } // Sets the window_scale for this window with respect to a display this window - // is located at. This determines how events can be translated and how size of - // the surface is treated (px to DIP conversion and vice versa.) - void SetWindowScale(float new_scale); + // is located at. Returns true if the scale has changed. This determines how + // events can be translated and how pixel size of the surface is treated. + bool SetWindowScale(float new_scale); float window_scale() const { return window_scale_; } float ui_scale() const { return ui_scale_; } @@ -140,6 +142,10 @@ class WaylandWindow : public PlatformWindow, // Returns current type of the window. PlatformWindowType type() const { return type_; } + // The pixel size of the surface. + gfx::Size size_px() const { return size_px_; } + + // The pixel size of the buffer for the surface. gfx::Size visual_size_px() const { return visual_size_px_; } absl::optional<gfx::Insets> frame_insets_px() const { @@ -147,15 +153,7 @@ class WaylandWindow : public PlatformWindow, } void set_frame_insets_px(gfx::Insets insets) { frame_insets_px_ = insets; } - bool can_submit_frames() const { return can_submit_frames_; } - - // These are never intended to be used except in unit tests. - void set_update_visual_size_immediately(bool update_immediately) { - update_visual_size_immediately_ = update_immediately; - } - void set_apply_pending_state_on_update_visual_size(bool apply_immediately) { - apply_pending_state_on_update_visual_size_ = apply_immediately; - } + bool received_configure_event() const { return received_configure_event_; } // Remove WaylandOutput associated with WaylandSurface of this window. void RemoveEnteredOutput(uint32_t output_id); @@ -211,6 +209,12 @@ class WaylandWindow : public PlatformWindow, bool CanDispatchEvent(const PlatformEvent& event) override; uint32_t DispatchEvent(const PlatformEvent& event) override; + // EventTarget: + bool CanAcceptEvent(const Event& event) override; + EventTarget* GetParentTarget() override; + std::unique_ptr<EventTargetIterator> GetChildIterator() const override; + EventTargeter* GetEventTargeter() override; + // 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. @@ -229,7 +233,7 @@ class WaylandWindow : public PlatformWindow, bool is_activated); virtual void HandlePopupConfigure(const gfx::Rect& bounds); // The final size of the Wayland surface is determined by the buffer size in - // px * scale that the Chromium compositor renders at. If the window changes a + // px that the Chromium compositor renders at. If the window changes a // display (and scale changes from 1 to 2), the buffers are recreated with // some delays. Thus, applying a visual size using window_scale (which is the // current scale of a wl_output where the window is located at) is wrong, as @@ -245,7 +249,7 @@ class WaylandWindow : public PlatformWindow, // factor than the primary display's one. Thus, this method gets a scale // factor that helps to determine size of the surface in dip respecting // size that GPU renders at. - virtual void UpdateVisualSize(const gfx::Size& size_px, float scale_factor); + virtual void UpdateVisualSize(const gfx::Size& size_px); // Handles close requests. virtual void OnCloseRequest(); @@ -260,8 +264,6 @@ class WaylandWindow : public PlatformWindow, virtual void OnDragLeave(); virtual void OnDragSessionClose(ui::mojom::DragOperation operation); - virtual absl::optional<std::vector<gfx::Rect>> GetWindowShape() const; - // Tells if the surface has already been configured. virtual bool IsSurfaceConfigured() = 0; @@ -272,6 +274,9 @@ class WaylandWindow : public PlatformWindow, // Sets the window geometry. virtual void SetWindowGeometry(gfx::Rect bounds); + // Returns the offset of the window geometry within the window surface. + gfx::Vector2d GetWindowGeometryOffsetInDIP() const; + // Sends configure acknowledgement to the wayland server. virtual void AckConfigure(uint32_t serial) = 0; @@ -306,6 +311,9 @@ class WaylandWindow : public PlatformWindow, // WaylandPopup, if |this| has type of WaylandPopup. virtual WaylandPopup* AsWaylandPopup(); + // Returns true if the window's bounds is in screen coordinates. + virtual bool IsScreenCoordinatesEnabled() const; + scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner() { return ui_task_runner_; } @@ -317,6 +325,23 @@ class WaylandWindow : public PlatformWindow, // Clears the state of the |frame_manager_| when the GPU channel is destroyed. void OnChannelDestroyed(); + // These are never intended to be used except in unit tests. + void set_update_visual_size_immediately_for_testing(bool update) { + update_visual_size_immediately_for_testing_ = update; + } + + void set_apply_pending_state_on_update_visual_size_for_testing(bool apply) { + apply_pending_state_on_update_visual_size_for_testing_ = apply; + } + +#if DCHECK_IS_ON() + void disable_null_target_dcheck_for_testing() { + disable_null_target_dcheck_for_test_ = true; + } +#endif + + bool has_pending_configures() const { return !pending_configures_.empty(); } + protected: WaylandWindow(PlatformWindowDelegate* delegate, WaylandConnection* connection); @@ -348,23 +373,24 @@ class WaylandWindow : public PlatformWindow, // Processes the size information form visual size update and returns true if // any pending configure is fulfilled. - bool ProcessVisualSizeUpdate(const gfx::Size& size_px, float scale_factor); + bool ProcessVisualSizeUpdate(const gfx::Size& size_px); // Applies pending bounds. virtual void ApplyPendingBounds(); - bool HasPendingConfigures() const; - gfx::Rect pending_bounds_dip() const { return pending_bounds_dip_; } - void set_pending_bounds_dip(const gfx::Rect rect) { + void set_pending_bounds_dip(const gfx::Rect& rect) { pending_bounds_dip_ = rect; } + gfx::Size pending_size_px() const { return pending_size_px_; } + void set_pending_size_px(const gfx::Size& size) { pending_size_px_ = size; } const gfx::Size& restored_size_dip() const { return restored_size_dip_; } private: friend class WaylandBufferManagerViewportTest; friend class BlockableWaylandToplevelWindow; + friend class WaylandWindowManager; FRIEND_TEST_ALL_PREFIXES(WaylandScreenTest, SetWindowScale); FRIEND_TEST_ALL_PREFIXES(WaylandBufferManagerTest, CanSubmitOverlayPriority); @@ -373,8 +399,6 @@ class WaylandWindow : public PlatformWindow, // Initializes the WaylandWindow with supplied properties. bool Initialize(PlatformWindowInitProperties properties); - void UpdateCursorPositionFromEvent(const Event* event); - uint32_t DispatchEventToDelegate(const PlatformEvent& native_event); // Additional initialization of derived classes. @@ -391,13 +415,13 @@ class WaylandWindow : public PlatformWindow, void UpdateCursorShape(scoped_refptr<BitmapCursor> cursor); - PlatformWindowDelegate* delegate_; - WaylandConnection* connection_; - WaylandWindow* parent_window_ = nullptr; - WaylandWindow* child_window_ = nullptr; + raw_ptr<PlatformWindowDelegate> delegate_; + raw_ptr<WaylandConnection> connection_; + raw_ptr<WaylandWindow> parent_window_ = nullptr; + raw_ptr<WaylandWindow> child_window_ = nullptr; std::unique_ptr<WaylandFrameManager> frame_manager_; - bool can_submit_frames_ = false; + bool received_configure_event_ = false; // |root_surface_| is a surface for the opaque background. Its z-order is // INT32_MIN. @@ -427,7 +451,10 @@ class WaylandWindow : public PlatformWindow, // 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_; + // gfx::Rect bounds_px_; + + gfx::Rect bounds_dip_; + gfx::Size size_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 @@ -443,8 +470,6 @@ class WaylandWindow : public PlatformWindow, // areas outside the geometry are used to draw client-side window decorations. absl::optional<gfx::Insets> frame_insets_px_; - bool has_pointer_focus_ = false; - bool has_keyboard_focus_ = false; bool has_touch_focus_ = false; // The UI scale may be forced through the command line, which means that it // replaces the default value that is equal to the natural device scale. @@ -466,13 +491,13 @@ class WaylandWindow : public PlatformWindow, // 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; + bool update_visual_size_immediately_for_testing_ = false; // In a non-test environment, root_surface_->ApplyPendingBounds() is called to // send Wayland protocol requests, but in some unit tests there will never be // any frame updates. This flag causes root_surface_->ApplyPendingBounds() to // be invoked during UpdateVisualSize() in unit tests. - bool apply_pending_state_on_update_visual_size_ = false; + bool apply_pending_state_on_update_visual_size_for_testing_ = false; // These bounds attributes below have suffixes that indicate units used. // Wayland operates in DIP but the platform operates in physical pixels so @@ -485,6 +510,7 @@ class WaylandWindow : public PlatformWindow, // bounds via |ApplyPendingBounds|. Measured in DIP because updated in the // handler that receives DIP from Wayland. gfx::Rect pending_bounds_dip_; + gfx::Size pending_size_px_; // The size of the platform window before it went maximized or fullscreen in // dip. @@ -494,6 +520,7 @@ class WaylandWindow : public PlatformWindow, // ack_configure request with |serial| will be sent to the Wayland compositor. struct PendingConfigure { gfx::Rect bounds_dip; + gfx::Size size_px; uint32_t serial; // True if this configure has been passed to the compositor for rendering. bool set = false; @@ -507,6 +534,10 @@ class WaylandWindow : public PlatformWindow, base::OnceClosure drag_loop_quit_closure_; +#if DCHECK_IS_ON() + bool disable_null_target_dcheck_for_test_ = false; +#endif + scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_; base::WeakPtrFactory<WaylandWindow> weak_ptr_factory_{this}; 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 06b5bfaaeda..191d7e0006b 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 @@ -40,6 +40,7 @@ #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_output_manager.h" #include "ui/ozone/platform/wayland/host/wayland_screen.h" #include "ui/ozone/platform/wayland/host/wayland_serial_tracker.h" @@ -228,10 +229,13 @@ void WaylandWindowDragController::OnDragEnter(WaylandWindow* window, pointer_location_ = location; DCHECK(drag_source_.has_value()); - if (*drag_source_ == DragSource::kMouse) - pointer_delegate_->OnPointerFocusChanged(window, location); - else + // Check if this is necessary. + if (*drag_source_ == DragSource::kMouse) { + pointer_delegate_->OnPointerFocusChanged( + window, location, wl::EventDispatchPolicy::kImmediate); + } else { touch_delegate_->OnTouchFocusChanged(window); + } DVLOG(1) << "OnEnter. widget=" << window->GetWidget(); @@ -269,9 +273,9 @@ void WaylandWindowDragController::OnDragMotion(const gfx::PointF& location) { base::TimeTicks timestamp = base::TimeTicks::Now(); auto touch_pointer_ids = touch_delegate_->GetActiveTouchPointIds(); DCHECK_EQ(touch_pointer_ids.size(), 1u); - touch_delegate_->OnTouchMotionEvent( - location, timestamp, touch_pointer_ids[0], - WaylandTouch::Delegate::EventDispatchPolicy::kImmediate); + touch_delegate_->OnTouchMotionEvent(location, timestamp, + touch_pointer_ids[0], + wl::EventDispatchPolicy::kImmediate); } } @@ -299,15 +303,15 @@ void WaylandWindowDragController::OnDragLeave() { DVLOG(1) << "OnLeave"; data_offer_.reset(); - // As Wayland clients are only aware of surface-local coordinates and there is - // no implicit grab during DND sessions, a fake motion event with negative - // y coordinate is used here to allow higher level UI components to detect - // when a window should be detached. E.g: On Chrome, dragging a tab all the - // way up to the top edge of the window won't work without this fake motion - // event upon wl_data_device::leave events. This is a workaround and should - // ideally be reworked in the future, at higher level layers such that they - // properly handle platforms that do not support global screen coordinates, - // like Wayland. + // As wl-shell/xdg-shell clients are only aware of surface-local coordinates + // and there is no implicit grab during DND sessions, a fake motion event with + // negative y coordinate is used here to allow higher level UI components to + // detect when a window should be detached. E.g: On Chrome, dragging a tab all + // the way up to the top edge of the window won't work without this fake + // motion event upon wl_data_device::leave events. This is a workaround and + // should ideally be reworked in the future, at higher level layers such that + // they properly handle platforms that do not support global screen + // coordinates, like Wayland. // // TODO(https://crbug.com/1282186): Find a better solution for upwards tab // detaching. @@ -328,8 +332,7 @@ void WaylandWindowDragController::OnDragLeave() { // the drag event is discarded. touch_delegate_->OnTouchMotionEvent( {pointer_location_.x(), kHorizontalRailExitThreshold}, timestamp, - touch_pointer_ids[0], - WaylandTouch::Delegate::EventDispatchPolicy::kImmediate); + touch_pointer_ids[0], wl::EventDispatchPolicy::kImmediate); } } @@ -373,8 +376,11 @@ void WaylandWindowDragController::OnDataSourceFinish(bool completed) { // In case of touch, though, we simply reset the focus altogether. if (IsExtendedDragAvailableInternal() && dragged_window_) { if (*drag_source_ == DragSource::kMouse) { - pointer_delegate_->OnPointerFocusChanged(dragged_window_, - pointer_location_); + // TODO: check if this usage is correct. + + pointer_delegate_->OnPointerFocusChanged( + dragged_window_, pointer_location_, + wl::EventDispatchPolicy::kImmediate); } else { touch_delegate_->OnTouchFocusChanged(dragged_window_); } @@ -456,15 +462,6 @@ void WaylandWindowDragController::HandleMotionEvent(LocatedEvent* event) { if (!should_process_drag_event_) return; - // Update current cursor position relative to the event source - // (focused window) so it can be retrieved later on through - // |Screen::GetCursorScreenPoint| API. - auto* pointer_focused_window = connection_->wayland_window_manager() - ->GetCurrentPointerOrTouchFocusedWindow(); - - if (pointer_focused_window) - pointer_focused_window->UpdateCursorPositionFromEvent(event); - // Notify listeners about window bounds change (i.e: re-positioning) event. // To do so, set the new bounds as per the motion event location and the drag // offset. Note that setting a new location (i.e: bounds.origin()) for a @@ -501,9 +498,9 @@ void WaylandWindowDragController::HandleDropAndResetState() { } else { auto touch_pointer_ids = touch_delegate_->GetActiveTouchPointIds(); DCHECK_EQ(touch_pointer_ids.size(), 1u); - touch_delegate_->OnTouchReleaseEvent( - base::TimeTicks::Now(), touch_pointer_ids[0], - WaylandTouch::Delegate::EventDispatchPolicy::kImmediate); + touch_delegate_->OnTouchReleaseEvent(base::TimeTicks::Now(), + touch_pointer_ids[0], + wl::EventDispatchPolicy::kImmediate); } pointer_grab_owner_ = nullptr; 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 d0f5bd5e589..667123b3137 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 @@ -11,6 +11,7 @@ #include <string> #include "base/callback_forward.h" +#include "base/memory/raw_ptr.h" #include "base/memory/weak_ptr.h" #include "ui/events/event.h" #include "ui/events/platform/platform_event_dispatcher.h" @@ -142,12 +143,12 @@ class WaylandWindowDragController : public WaylandDataDevice::DragDelegate, // |set_extended_drag_available_for_testing_|. bool IsExtendedDragAvailableInternal() const; - WaylandConnection* const connection_; - WaylandDataDeviceManager* const data_device_manager_; - WaylandDataDevice* const data_device_; - WaylandWindowManager* const window_manager_; - WaylandPointer::Delegate* const pointer_delegate_; - WaylandTouch::Delegate* const touch_delegate_; + const raw_ptr<WaylandConnection> connection_; + const raw_ptr<WaylandDataDeviceManager> data_device_manager_; + const raw_ptr<WaylandDataDevice> data_device_; + const raw_ptr<WaylandWindowManager> window_manager_; + const raw_ptr<WaylandPointer::Delegate> pointer_delegate_; + const raw_ptr<WaylandTouch::Delegate> touch_delegate_; State state_ = State::kIdle; absl::optional<DragSource> drag_source_; @@ -163,17 +164,17 @@ class WaylandWindowDragController : public WaylandDataDevice::DragDelegate, std::unique_ptr<ExtendedDragSource> extended_drag_source_; // The current toplevel window being dragged, when in detached mode. - WaylandToplevelWindow* dragged_window_ = nullptr; + raw_ptr<WaylandToplevelWindow> dragged_window_ = nullptr; // Keeps track of the window that holds the pointer grab. i.e: the owner of // the surface that must receive the mouse release event upon drop. - WaylandWindow* pointer_grab_owner_ = nullptr; + raw_ptr<WaylandWindow> pointer_grab_owner_ = nullptr; // The window where the DND session originated from. i.e: which had the // pointer focus when the session was initiated. - WaylandWindow* origin_window_ = nullptr; + raw_ptr<WaylandWindow> origin_window_ = nullptr; - WaylandWindow* drag_target_window_ = nullptr; + raw_ptr<WaylandWindow> drag_target_window_ = nullptr; // The |origin_window_| can be destroyed during the DND session. If this // happens, |origin_surface_| takes ownership of its surface and ensure it 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 630bf226a49..9c5805b2c2c 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 @@ -55,7 +55,7 @@ class WaylandWindowDragControllerTest : public WaylandDragDropTest { WaylandDragDropTest::SetUp(); drag_controller()->SetExtendedDragAvailableForTesting(); - EXPECT_FALSE(window_->has_pointer_focus()); + EXPECT_FALSE(window_->HasPointerFocus()); EXPECT_EQ(State::kIdle, drag_controller()->state()); } @@ -64,6 +64,7 @@ class WaylandWindowDragControllerTest : public WaylandDragDropTest { } MockWaylandPlatformWindowDelegate& delegate() { return delegate_; } + WaylandWindow* window() { return window_.get(); } protected: using State = WaylandWindowDragController::State; @@ -215,10 +216,11 @@ TEST_P(WaylandWindowDragControllerTest, DragInsideWindowAndDrop) { }); EXPECT_CALL(delegate_, OnBoundsChanged(_)) - .WillOnce([&](const PlatformWindowDelegate::BoundsChange& bounds) { + .WillOnce([&](const PlatformWindowDelegate::BoundsChange& change) { EXPECT_EQ(State::kDetached, drag_controller()->state()); EXPECT_EQ(kDragging, test_step); - EXPECT_EQ(gfx::Point(20, 20), bounds.bounds.origin()); + EXPECT_EQ(gfx::Point(20, 20), window_->GetBoundsInDIP().origin()); + EXPECT_TRUE(change.origin_changed); SendDndDrop(); test_step = kDropping; @@ -292,10 +294,11 @@ TEST_P(WaylandWindowDragControllerTest, DragInsideWindowAndDrop_TOUCH) { }); EXPECT_CALL(delegate_, OnBoundsChanged(_)) - .WillOnce([&](const PlatformWindowDelegate::BoundsChange& bounds) { + .WillOnce([&](const PlatformWindowDelegate::BoundsChange& change) { EXPECT_EQ(State::kDetached, drag_controller()->state()); EXPECT_EQ(kDragging, test_step); - EXPECT_EQ(gfx::Point(20, 20), bounds.bounds.origin()); + EXPECT_EQ(gfx::Point(20, 20), window_->GetBoundsInDIP().origin()); + EXPECT_TRUE(change.origin_changed); SendDndDrop(); test_step = kDropping; @@ -448,10 +451,11 @@ TEST_P(WaylandWindowDragControllerTest, DragExitWindowAndDrop) { }); EXPECT_CALL(delegate_, OnBoundsChanged(_)) - .WillOnce([&](const PlatformWindowDelegate::BoundsChange& bounds) { + .WillOnce([&](const PlatformWindowDelegate::BoundsChange& change) { EXPECT_EQ(State::kDetached, drag_controller()->state()); EXPECT_EQ(kDragging, test_step); - EXPECT_EQ(gfx::Point(20, 20), bounds.bounds.origin()); + EXPECT_EQ(gfx::Point(20, 20), window_->GetBoundsInDIP().origin()); + EXPECT_TRUE(change.origin_changed); SendDndLeave(); SendDndDrop(); @@ -557,10 +561,11 @@ TEST_P(WaylandWindowDragControllerTest, DragToOtherWindowSnapDragDrop) { }); EXPECT_CALL(delegate_, OnBoundsChanged(_)) - .WillOnce([&](const PlatformWindowDelegate::BoundsChange& bounds) { + .WillOnce([&](const PlatformWindowDelegate::BoundsChange& change) { EXPECT_EQ(State::kDetached, drag_controller()->state()); EXPECT_EQ(kDragging, test_step); - EXPECT_EQ(gfx::Point(50, 50), bounds.bounds.origin()); + EXPECT_EQ(gfx::Point(50, 50), window_->GetBoundsInDIP().origin()); + EXPECT_TRUE(change.origin_changed); // Exit |source_window| and enter the |target_window|. SendDndLeave(); @@ -687,10 +692,11 @@ TEST_P(WaylandWindowDragControllerTest, DragToOtherWindowSnapDragDrop_TOUCH) { } test_step = kStarted; EXPECT_CALL(delegate_, OnBoundsChanged(_)) - .WillOnce([&](const PlatformWindowDelegate::BoundsChange& bounds) { + .WillOnce([&](const PlatformWindowDelegate::BoundsChange& change) { EXPECT_EQ(State::kDetached, drag_controller()->state()); EXPECT_EQ(kDragging, test_step); - EXPECT_EQ(gfx::Point(50, 50), bounds.bounds.origin()); + EXPECT_EQ(gfx::Point(50, 50), window_->GetBoundsInDIP().origin()); + EXPECT_TRUE(change.origin_changed); // Exit |source_window| and enter the |target_window|. SendDndLeave(); @@ -858,18 +864,23 @@ TEST_P(WaylandWindowDragControllerTest, DragExitAttached_TOUCH) { Sync(); } +using BoundsChange = PlatformWindowDelegate::BoundsChange; + TEST_P(WaylandWindowDragControllerTest, RestoreDuringWindowDragSession) { - const gfx::Rect original_bounds = window_->GetBoundsInPixels(); + const gfx::Rect original_bounds = window_->GetBoundsInDIP(); wl::ScopedWlArray states({XDG_TOPLEVEL_STATE_ACTIVATED}); // Maximize and check restored bounds is correctly set. - gfx::Rect maximized_bounds = {0, 0, 1024, 768}; - EXPECT_CALL(delegate_, OnBoundsChanged(testing::Eq(maximized_bounds))); + constexpr gfx::Rect kMaximizedBounds{1024, 768}; + EXPECT_CALL(delegate_, OnBoundsChanged(testing::Eq(BoundsChange(false)))); window_->Maximize(); states.AddStateToWlArray(XDG_TOPLEVEL_STATE_MAXIMIZED); - SendConfigureEvent(surface_->xdg_surface(), maximized_bounds.width(), - maximized_bounds.height(), 1, states.get()); + SendConfigureEvent(surface_->xdg_surface(), kMaximizedBounds.size(), 1, + states.get()); Sync(); + + EXPECT_EQ(kMaximizedBounds, window_->GetBoundsInDIP()); + auto restored_bounds = window_->GetRestoredBoundsInDIP(); EXPECT_EQ(original_bounds, restored_bounds); @@ -970,10 +981,12 @@ TEST_P(WaylandWindowDragControllerTest, IgnorePointerEventsUntilDrop) { }); EXPECT_CALL(delegate_, OnBoundsChanged(_)) - .WillOnce([&](const PlatformWindowDelegate::BoundsChange& bounds) { + .WillOnce([&](const PlatformWindowDelegate::BoundsChange& change) { EXPECT_EQ(State::kDetached, drag_controller()->state()); EXPECT_EQ(kDragging, test_step); - EXPECT_EQ(gfx::Point(100, 100), bounds.bounds.origin()); + EXPECT_TRUE(change.origin_changed); + EXPECT_EQ(gfx::Point(100, 100), window_->GetBoundsInDIP().origin()); + EXPECT_TRUE(change.origin_changed); // Send a few wl_pointer::motion events skipping sync and dispatch // checks, which will be done at |kDropping| test step handling. @@ -1034,7 +1047,9 @@ TEST_P(WaylandWindowDragControllerTest, MotionEventsSkippedWhileReattaching) { self->SendDndMotion({30, 30}); EXPECT_CALL(self->delegate(), OnBoundsChanged(_)) .WillOnce([&](const PlatformWindowDelegate::BoundsChange& change) { - EXPECT_EQ(gfx::Point(30, 30), change.bounds.origin()); + EXPECT_EQ(gfx::Point(30, 30), + self->window()->GetBoundsInDIP().origin()); + EXPECT_TRUE(change.origin_changed); }); self->Sync(); 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 ed35763da2d..b270ef30fb6 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_window_factory.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_factory.cc @@ -58,8 +58,9 @@ std::unique_ptr<WaylandWindow> WaylandWindow::Create( NOTREACHED(); break; } - window->set_update_visual_size_immediately(update_visual_size_immediately); - window->set_apply_pending_state_on_update_visual_size( + window->set_update_visual_size_immediately_for_testing( + update_visual_size_immediately); + window->set_apply_pending_state_on_update_visual_size_for_testing( apply_pending_state_on_update_visual_size); return window && window->Initialize(std::move(properties)) ? std::move(window) : nullptr; diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window_manager.cc b/chromium/ui/ozone/platform/wayland/host/wayland_window_manager.cc index 85cda44d54d..d350c2af994 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_window_manager.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_manager.cc @@ -29,13 +29,18 @@ void WaylandWindowManager::NotifyWindowConfigured(WaylandWindow* window) { observer.OnWindowConfigured(window); } +void WaylandWindowManager::NotifyWindowRoleAssigned(WaylandWindow* window) { + for (WaylandWindowObserver& observer : observers_) + observer.OnWindowRoleAssigned(window); +} + void WaylandWindowManager::GrabLocatedEvents(WaylandWindow* window) { DCHECK_NE(located_events_grabber_, window); // Wayland doesn't allow to grab the mouse. However, we start forwarding all // mouse events received by WaylandWindow to the aura::WindowEventDispatcher // which has capture. - auto* old_grabber = located_events_grabber_; + auto* old_grabber = located_events_grabber_.get(); located_events_grabber_ = window; if (old_grabber) old_grabber->OnWindowLostCapture(); @@ -43,7 +48,7 @@ void WaylandWindowManager::GrabLocatedEvents(WaylandWindow* window) { void WaylandWindowManager::UngrabLocatedEvents(WaylandWindow* window) { DCHECK_EQ(located_events_grabber_, window); - auto* old_grabber = located_events_grabber_; + auto* old_grabber = located_events_grabber_.get(); located_events_grabber_ = nullptr; old_grabber->OnWindowLostCapture(); } @@ -80,9 +85,10 @@ WaylandWindow* WaylandWindowManager::GetCurrentActiveWindow() const { WaylandWindow* WaylandWindowManager::GetCurrentFocusedWindow() const { for (const auto& entry : window_map_) { WaylandWindow* window = entry.second; - if (window->has_pointer_focus() || window->has_touch_focus() || - window->has_keyboard_focus()) + if (window == pointer_focused_window_ || window->has_touch_focus() || + window == keyboard_focused_window_) { return window; + } } return nullptr; } @@ -102,19 +108,25 @@ WaylandWindow* WaylandWindowManager::GetCurrentPointerOrTouchFocusedWindow() for (const auto& entry : window_map_) { WaylandWindow* window = entry.second; - if (window->has_pointer_focus() || window->has_touch_focus()) + if (window == pointer_focused_window_ || window->has_touch_focus()) return window; } return nullptr; } WaylandWindow* WaylandWindowManager::GetCurrentPointerFocusedWindow() const { +#if DCHECK_IS_ON() + bool found = !pointer_focused_window_; for (const auto& entry : window_map_) { WaylandWindow* window = entry.second; - if (window->has_pointer_focus()) - return window; + if (window == pointer_focused_window_) { + found = true; + break; + } } - return nullptr; + DCHECK(found); +#endif + return pointer_focused_window_; } WaylandWindow* WaylandWindowManager::GetCurrentTouchFocusedWindow() const { @@ -127,12 +139,18 @@ WaylandWindow* WaylandWindowManager::GetCurrentTouchFocusedWindow() const { } WaylandWindow* WaylandWindowManager::GetCurrentKeyboardFocusedWindow() const { +#if DCHECK_IS_ON() + bool found = !keyboard_focused_window_; for (const auto& entry : window_map_) { WaylandWindow* window = entry.second; - if (window->has_keyboard_focus()) - return window; + if (window == keyboard_focused_window_) { + found = true; + break; + } } - return nullptr; + DCHECK(found); +#endif + return keyboard_focused_window_; } void WaylandWindowManager::SetPointerFocusedWindow(WaylandWindow* window) { @@ -140,9 +158,10 @@ void WaylandWindowManager::SetPointerFocusedWindow(WaylandWindow* window) { if (window == old_focused_window) return; if (old_focused_window) - old_focused_window->SetPointerFocus(false); + old_focused_window->OnPointerFocusChanged(false); + pointer_focused_window_ = window; if (window) - window->SetPointerFocus(true); + window->OnPointerFocusChanged(true); } void WaylandWindowManager::SetTouchFocusedWindow(WaylandWindow* window) { @@ -159,24 +178,11 @@ void WaylandWindowManager::SetKeyboardFocusedWindow(WaylandWindow* window) { auto* old_focused_window = GetCurrentKeyboardFocusedWindow(); if (window == old_focused_window) return; - if (old_focused_window) - old_focused_window->set_keyboard_focus(false); - if (window) - window->set_keyboard_focus(true); + keyboard_focused_window_ = window; for (auto& observer : observers_) observer.OnKeyboardFocusedWindowChanged(); } -std::vector<WaylandWindow*> WaylandWindowManager::GetWindowsOnOutput( - uint32_t output_id) { - std::vector<WaylandWindow*> result; - for (auto entry : window_map_) { - if (entry.second->GetPreferredEnteredOutputId() == output_id) - result.push_back(entry.second); - } - return result; -} - void WaylandWindowManager::AddWindow(gfx::AcceleratedWidget widget, WaylandWindow* window) { window_map_[widget] = window; @@ -194,10 +200,13 @@ void WaylandWindowManager::RemoveWindow(gfx::AcceleratedWidget widget) { for (WaylandWindowObserver& observer : observers_) observer.OnWindowRemoved(window); - if (window->has_keyboard_focus()) { + if (window == keyboard_focused_window_) { + keyboard_focused_window_ = nullptr; for (auto& observer : observers_) observer.OnKeyboardFocusedWindowChanged(); } + if (window == pointer_focused_window_) + pointer_focused_window_ = nullptr; } void WaylandWindowManager::AddSubsurface(gfx::AcceleratedWidget widget, @@ -229,4 +238,12 @@ std::vector<WaylandWindow*> WaylandWindowManager::GetAllWindows() const { return result; } +bool WaylandWindowManager::IsWindowValid(const WaylandWindow* window) const { + for (auto pair : window_map_) { + if (pair.second == window) + return true; + } + return false; +} + } // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window_manager.h b/chromium/ui/ozone/platform/wayland/host/wayland_window_manager.h index a746457627e..bc8c7e95b10 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_window_manager.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_manager.h @@ -8,6 +8,7 @@ #include <memory> #include "base/containers/flat_map.h" +#include "base/memory/raw_ptr.h" #include "base/observer_list.h" #include "ui/gfx/geometry/size_f.h" #include "ui/gfx/native_widget_types.h" @@ -35,6 +36,9 @@ class WaylandWindowManager { // WaylandBufferManagerHost can start attaching buffers to the |surface_|. void NotifyWindowConfigured(WaylandWindow* window); + // Notifies observers that the window's wayland role has been assigned. + void NotifyWindowRoleAssigned(WaylandWindow* window); + // Stores the window that should grab the located events. void GrabLocatedEvents(WaylandWindow* event_grabber); @@ -91,13 +95,12 @@ class WaylandWindowManager { // The given |window| must be managed by this manager. void SetKeyboardFocusedWindow(WaylandWindow* window); - // TODO(crbug.com/971525): remove this in favor of targeted subscription of - // windows to their outputs. - std::vector<WaylandWindow*> GetWindowsOnOutput(uint32_t output_id); - // Returns all stored windows. std::vector<WaylandWindow*> GetAllWindows() const; + // Returns true if the |window| still exists. + bool IsWindowValid(const WaylandWindow* window) const; + void AddWindow(gfx::AcceleratedWidget widget, WaylandWindow* window); void RemoveWindow(gfx::AcceleratedWidget widget); void AddSubsurface(gfx::AcceleratedWidget widget, @@ -109,13 +112,16 @@ class WaylandWindowManager { gfx::AcceleratedWidget AllocateAcceleratedWidget(); private: - WaylandConnection* const connection_; + WaylandWindow* pointer_focused_window_ = nullptr; + WaylandWindow* keyboard_focused_window_ = nullptr; + + const raw_ptr<WaylandConnection> connection_; base::ObserverList<WaylandWindowObserver> observers_; base::flat_map<gfx::AcceleratedWidget, WaylandWindow*> window_map_; - WaylandWindow* located_events_grabber_ = nullptr; + raw_ptr<WaylandWindow> located_events_grabber_ = nullptr; // Stores strictly monotonically increasing counter for allocating unique // AccelerateWidgets. diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window_manager_unittests.cc b/chromium/ui/ozone/platform/wayland/host/wayland_window_manager_unittests.cc index 0e8af0f518d..08e2d1594dd 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_window_manager_unittests.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_manager_unittests.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/memory/raw_ptr.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/ozone/platform/wayland/host/wayland_output.h" #include "ui/ozone/platform/wayland/test/mock_pointer.h" @@ -48,7 +49,7 @@ class WaylandWindowManagerTest : public WaylandTest { return window; } - WaylandWindowManager* manager_ = nullptr; + raw_ptr<WaylandWindowManager> manager_ = nullptr; }; TEST_P(WaylandWindowManagerTest, GetWindow) { @@ -93,8 +94,7 @@ TEST_P(WaylandWindowManagerTest, GetCurrentFocusedWindow) { auto window1 = CreateWaylandWindowWithParams(PlatformWindowType::kWindow, kDefaultBounds, &delegate); // When window is shown, it automatically gets keyboard focus. Reset it. - window_->set_keyboard_focus(false); - window1->set_keyboard_focus(false); + connection_->wayland_window_manager()->SetKeyboardFocusedWindow(nullptr); Sync(); @@ -108,6 +108,7 @@ TEST_P(WaylandWindowManagerTest, GetCurrentFocusedWindow) { wl::MockSurface* surface = server_.GetObject<wl::MockSurface>( window1->root_surface()->GetSurfaceId()); wl_pointer_send_enter(pointer->resource(), 1, surface->resource(), 0, 0); + wl_pointer_send_frame(pointer->resource()); Sync(); @@ -118,6 +119,7 @@ TEST_P(WaylandWindowManagerTest, GetCurrentFocusedWindow) { EXPECT_TRUE(window1.get() == manager_->GetCurrentPointerFocusedWindow()); wl_pointer_send_leave(pointer->resource(), 2, surface->resource()); + wl_pointer_send_frame(pointer->resource()); Sync(); @@ -137,8 +139,7 @@ TEST_P(WaylandWindowManagerTest, GetCurrentKeyboardFocusedWindow) { auto window1 = CreateWaylandWindowWithParams(PlatformWindowType::kWindow, kDefaultBounds, &delegate); // When window is shown, it automatically gets keyboard focus. Reset it. - window_->set_keyboard_focus(false); - window1->set_keyboard_focus(false); + connection_->wayland_window_manager()->SetKeyboardFocusedWindow(nullptr); Sync(); @@ -167,58 +168,6 @@ TEST_P(WaylandWindowManagerTest, GetCurrentKeyboardFocusedWindow) { EXPECT_FALSE(manager_->GetCurrentKeyboardFocusedWindow()); } -TEST_P(WaylandWindowManagerTest, GetWindowsOnOutput) { - MockPlatformWindowDelegate delegate; - - // Create a second wl_output. - wl::TestOutput* output = server_.CreateAndInitializeOutput(); - Sync(); - - // Place it at the right of the first output. - int x = server_.output()->GetRect().x(); - output->SetRect({x, 0, 800, 600}); - output->Flush(); - Sync(); - - auto window1 = CreateWaylandWindowWithParams(PlatformWindowType::kWindow, - kDefaultBounds, &delegate); - - auto window2 = CreateWaylandWindowWithParams(PlatformWindowType::kWindow, - kDefaultBounds, &delegate); - - Sync(); - - wl::MockSurface* surface = server_.GetObject<wl::MockSurface>( - window1->root_surface()->GetSurfaceId()); - ASSERT_TRUE(surface); - wl_surface_send_enter(surface->resource(), output->resource()); - - Sync(); - - auto entered_outputs_window1 = window1->root_surface()->entered_outputs(); - EXPECT_EQ(1u, entered_outputs_window1.size()); - - uint32_t output_id = (*entered_outputs_window1.begin()); - - auto windows_on_output = manager_->GetWindowsOnOutput(output_id); - EXPECT_EQ(1u, windows_on_output.size()); - - EXPECT_TRUE(window1.get() == *windows_on_output.begin()); - - surface = server_.GetObject<wl::MockSurface>( - window2->root_surface()->GetSurfaceId()); - ASSERT_TRUE(surface); - wl_surface_send_enter(surface->resource(), output->resource()); - - Sync(); - - windows_on_output = manager_->GetWindowsOnOutput(output_id); - EXPECT_EQ(2u, windows_on_output.size()); - - output->DestroyGlobal(); - Sync(); -} - TEST_P(WaylandWindowManagerTest, GetAllWindows) { MockPlatformWindowDelegate delegate; diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window_observer.cc b/chromium/ui/ozone/platform/wayland/host/wayland_window_observer.cc index 97c029f907b..de1e13431a5 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_window_observer.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_observer.cc @@ -14,6 +14,8 @@ void WaylandWindowObserver::OnWindowRemoved(WaylandWindow* window) {} void WaylandWindowObserver::OnWindowConfigured(WaylandWindow* window) {} +void WaylandWindowObserver::OnWindowRoleAssigned(WaylandWindow* window) {} + void WaylandWindowObserver::OnSubsurfaceAdded(WaylandWindow* window, WaylandSubsurface* subsurface) {} diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window_observer.h b/chromium/ui/ozone/platform/wayland/host/wayland_window_observer.h index cc577ffa38f..729bf9d665f 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_window_observer.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_observer.h @@ -24,6 +24,9 @@ class WaylandWindowObserver : public base::CheckedObserver { // Called when |window| has been ack configured. virtual void OnWindowConfigured(WaylandWindow* window); + // Called when |window| has been assigned a role. + virtual void OnWindowRoleAssigned(WaylandWindow* window); + // Called when |window| adds |subsurface|. virtual void OnSubsurfaceAdded(WaylandWindow* window, WaylandSubsurface* subsurface); 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 7df9e99d9b8..dbe56638bc4 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_window_unittest.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_unittest.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "ui/ozone/platform/wayland/host/wayland_window.h" +#include "base/memory/raw_ptr.h" #include <cstddef> #include <memory> @@ -30,6 +31,7 @@ #include "ui/base/hit_test.h" #include "ui/base/ui_base_types.h" #include "ui/display/display.h" +#include "ui/display/types/display_constants.h" #include "ui/events/base_event_utils.h" #include "ui/events/event.h" #include "ui/gfx/geometry/insets.h" @@ -139,6 +141,10 @@ class MockZcrCursorShapes : public WaylandZcrCursorShapes { MOCK_METHOD(void, SetCursorShape, (int32_t), (override)); }; +using BoundsChange = PlatformWindowDelegate::BoundsChange; + +constexpr BoundsChange kDefaultBoundsChange{false}; + } // namespace class WaylandWindowTest : public WaylandTest { @@ -155,9 +161,6 @@ class WaylandWindowTest : public WaylandTest { WaylandWindowTest& operator=(const WaylandWindowTest&) = delete; void SetUp() override { - disabled_features_.push_back( - ui::kWaylandSurfaceSubmissionInPixelCoordinates); - WaylandTest::SetUp(); xdg_surface_ = surface_->xdg_surface(); @@ -166,7 +169,7 @@ class WaylandWindowTest : public WaylandTest { protected: void SendConfigureEventPopup(WaylandWindow* menu_window, - const gfx::Rect bounds) { + const gfx::Rect& bounds) { auto* popup = GetTestXdgPopupByWindow(menu_window); ASSERT_TRUE(popup); if (GetParam().shell_version == wl::ShellVersion::kV6) { @@ -200,7 +203,7 @@ class WaylandWindowTest : public WaylandTest { std::unique_ptr<WaylandWindow> CreateWaylandWindowWithParams( PlatformWindowType type, gfx::AcceleratedWidget parent_widget, - const gfx::Rect bounds, + const gfx::Rect& bounds, MockWaylandPlatformWindowDelegate* delegate) { PlatformWindowInitProperties properties; // TODO(msisov): use a fancy method to calculate position of a popup window. @@ -253,10 +256,14 @@ class WaylandWindowTest : public WaylandTest { } void VerifyCanDispatchMouseEvents( - const std::vector<WaylandWindow*>& dispatching_windows, + WaylandWindow* dispatching_window, const std::vector<WaylandWindow*>& non_dispatching_windows) { - for (auto* window : dispatching_windows) - EXPECT_TRUE(window->CanDispatchEvent(&test_mouse_event_)); + auto* pointer_focused_window = + connection_->wayland_window_manager()->GetCurrentPointerFocusedWindow(); + + DCHECK(pointer_focused_window); + Event::DispatcherApi(&test_mouse_event_).set_target(pointer_focused_window); + EXPECT_TRUE(dispatching_window->CanDispatchEvent(&test_mouse_event_)); for (auto* window : non_dispatching_windows) EXPECT_FALSE(window->CanDispatchEvent(&test_mouse_event_)); } @@ -264,23 +271,55 @@ class WaylandWindowTest : public WaylandTest { void VerifyCanDispatchTouchEvents( const std::vector<WaylandWindow*>& dispatching_windows, const std::vector<WaylandWindow*>& non_dispatching_windows) { + DCHECK(dispatching_windows.size() < 2); + auto* touch_focused_window = + connection_->wayland_window_manager()->GetCurrentTouchFocusedWindow(); + // There must be focused window to dispatch. + if (dispatching_windows.size() == 0) + EXPECT_FALSE(touch_focused_window); + PointerDetails pointer_details(EventPointerType::kTouch, 1); TouchEvent test_touch_event(ET_TOUCH_PRESSED, {1, 1}, base::TimeTicks(), pointer_details); + if (touch_focused_window) + Event::DispatcherApi(&test_touch_event).set_target(touch_focused_window); for (auto* window : dispatching_windows) EXPECT_TRUE(window->CanDispatchEvent(&test_touch_event)); - for (auto* window : non_dispatching_windows) + for (auto* window : non_dispatching_windows) { + // Make sure that the CanDispatcEvent works on release build. +#if DCHECK_IS_ON() + // Disable DCHECK when enabled. + window->disable_null_target_dcheck_for_testing(); +#endif EXPECT_FALSE(window->CanDispatchEvent(&test_touch_event)); + } } void VerifyCanDispatchKeyEvents( const std::vector<WaylandWindow*>& dispatching_windows, const std::vector<WaylandWindow*>& non_dispatching_windows) { + DCHECK(dispatching_windows.size() < 2); + auto* keyboard_focused_window = connection_->wayland_window_manager() + ->GetCurrentKeyboardFocusedWindow(); + + // There must be focused window to dispatch. + if (dispatching_windows.size() == 0) + EXPECT_FALSE(keyboard_focused_window); + KeyEvent test_key_event(ET_KEY_PRESSED, VKEY_0, 0); + if (keyboard_focused_window) + Event::DispatcherApi(&test_key_event).set_target(keyboard_focused_window); + for (auto* window : dispatching_windows) EXPECT_TRUE(window->CanDispatchEvent(&test_key_event)); - for (auto* window : non_dispatching_windows) + for (auto* window : non_dispatching_windows) { + // Make sure that the CanDispatcEvent works on release build. +#if DCHECK_IS_ON() + // Disable DCHECK when enabled. + window->disable_null_target_dcheck_for_testing(); +#endif EXPECT_FALSE(window->CanDispatchEvent(&test_key_event)); + } } wl::TestXdgPopup* GetTestXdgPopupByWindow(WaylandWindow* window) { @@ -294,7 +333,7 @@ class WaylandWindowTest : public WaylandTest { return nullptr; } - wl::MockXdgSurface* xdg_surface_; + raw_ptr<wl::MockXdgSurface> xdg_surface_; MouseEvent test_mouse_event_; }; @@ -305,42 +344,40 @@ TEST_P(WaylandWindowTest, SetTitle) { } TEST_P(WaylandWindowTest, UpdateVisualSizeConfiguresWaylandWindow) { - const auto kNormalBounds = gfx::Rect{0, 0, 500, 300}; + constexpr gfx::Rect kNormalBounds{500, 300}; uint32_t serial = 0; auto state = InitializeWlArrayWithActivatedState(); - window_->set_update_visual_size_immediately(false); + window_->set_update_visual_size_immediately_for_testing(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(Eq(kNormalBounds))); - EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds.width(), - kNormalBounds.height())) + EXPECT_CALL(delegate_, OnBoundsChanged(Eq(kDefaultBoundsChange))); + EXPECT_CALL(*xdg_surface_, SetWindowGeometry(gfx::Rect(kNormalBounds.size()))) .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()); + SendConfigureEvent(xdg_surface_, kNormalBounds.size(), ++serial, state.get()); Sync(); - EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds.width(), - kNormalBounds.height())); + EXPECT_CALL(*xdg_surface_, + SetWindowGeometry(gfx::Rect(kNormalBounds.size()))); EXPECT_CALL(*xdg_surface_, AckConfigure(1)); EXPECT_CALL(*mock_surface, SetOpaqueRegion(_)); EXPECT_CALL(*mock_surface, SetInputRegion(_)); - window_->UpdateVisualSize(kNormalBounds.size(), 1.0f); + window_->UpdateVisualSize(kNormalBounds.size()); } // WaylandSurface state changes are sent to wayland compositor when // ApplyPendingState() is called. TEST_P(WaylandWindowTest, ApplyPendingStatesAndCommit) { - window_->set_update_visual_size_immediately(false); - window_->set_apply_pending_state_on_update_visual_size(false); + window_->set_update_visual_size_immediately_for_testing(false); + window_->set_apply_pending_state_on_update_visual_size_for_testing(false); auto* mock_surface = server_.GetObject<wl::MockSurface>( window_->root_surface()->GetSurfaceId()); @@ -350,7 +387,7 @@ TEST_P(WaylandWindowTest, ApplyPendingStatesAndCommit) { EXPECT_CALL(*mock_surface, SetInputRegion(_)).Times(0); EXPECT_CALL(*mock_surface, SetBufferScale(2)).Times(0); - std::vector<gfx::Rect> region_px = {gfx::Rect{0, 0, 500, 300}}; + std::vector<gfx::Rect> region_px = {gfx::Rect{500, 300}}; window_->root_surface()->SetOpaqueRegion(®ion_px); window_->root_surface()->SetInputRegion(region_px.data()); window_->root_surface()->SetSurfaceBufferScale(2); @@ -374,11 +411,14 @@ TEST_P(WaylandWindowTest, ApplyPendingStatesAndCommit) { // WaylandToplevelWindow::HandleToplevelConfigure does correct rounding when // some sides of insets divides by 2 with remainder. TEST_P(WaylandWindowTest, SetDecorationInsets) { - const auto kNormalBounds = gfx::Rect{0, 0, 956, 556}; + constexpr gfx::Rect kNormalBounds{956, 556}; const auto kHiDpiScale = 2; - const auto kHiDpiBounds = gfx::ScaleToRoundedRect(kNormalBounds, kHiDpiScale); + const gfx::Size kHiDpiSize = + gfx::ScaleToRoundedRect(kNormalBounds, kHiDpiScale).size(); + const BoundsChange kHiDpiBounds{true}; - window_->SetBoundsInPixels(kNormalBounds); + // TODO(crbug.com/1306688): Change this to SetBoundsInDIP. + window_->SetBoundsInDIP(kNormalBounds); uint32_t serial = 0; auto state = InitializeWlArrayWithActivatedState(); @@ -399,29 +439,24 @@ TEST_P(WaylandWindowTest, SetDecorationInsets) { auto bounds_with_insets = kNormalBounds; bounds_with_insets.Inset(kDecorationInsets); EXPECT_CALL(delegate_, OnBoundsChanged(_)).Times(0); - EXPECT_CALL(*xdg_surface_, - SetWindowGeometry(bounds_with_insets.x(), bounds_with_insets.y(), - bounds_with_insets.width(), - bounds_with_insets.height())); + EXPECT_CALL(*xdg_surface_, SetWindowGeometry(bounds_with_insets)); window_->SetDecorationInsets(&kDecorationInsets); // Setting the decoration insets does not trigger the immediate update of the // window geometry. Emulate updating the visual size (sending the frame // update) for that. - window_->UpdateVisualSize(kNormalBounds.size(), 1.0f); + window_->UpdateVisualSize(kNormalBounds.size()); Sync(); EXPECT_CALL(delegate_, OnBoundsChanged(_)).Times(0); - EXPECT_CALL(*xdg_surface_, - SetWindowGeometry(bounds_with_insets.x(), bounds_with_insets.y(), - bounds_with_insets.width(), - bounds_with_insets.height())); - SendConfigureEvent(xdg_surface_, bounds_with_insets.width(), - bounds_with_insets.height(), ++serial, state.get()); + EXPECT_CALL(*xdg_surface_, SetWindowGeometry(bounds_with_insets)); + SendConfigureEvent(xdg_surface_, bounds_with_insets.size(), ++serial, + state.get()); Sync(); - // Change scale. This is the only time when we expect the bounds to change. + // Change scale. This is the only time when we expect the pixel position to + // change. EXPECT_CALL(delegate_, OnBoundsChanged(Eq(kHiDpiBounds))).Times(1); output->SetScale(kHiDpiScale); output->Flush(); @@ -432,170 +467,164 @@ TEST_P(WaylandWindowTest, SetDecorationInsets) { window_->root_surface()->SetSurfaceBufferScale(kHiDpiScale); // Set new insets so that rounding does not result in integer. - const auto kDecorationInsets_2x = gfx::Insets::TLBR(48, 55, 63, 55); - EXPECT_CALL(*xdg_surface_, - SetWindowGeometry(bounds_with_insets.x(), bounds_with_insets.y(), - bounds_with_insets.width(), - bounds_with_insets.height())); + constexpr auto kDecorationInsets_2x = gfx::Insets::TLBR(48, 55, 63, 55); + EXPECT_CALL(*xdg_surface_, SetWindowGeometry(bounds_with_insets)); window_->SetDecorationInsets(&kDecorationInsets_2x); // Setting the decoration insets does not trigger the immediate update of the // window geometry. Emulate updating the visual size (sending the frame // update) for that. - window_->UpdateVisualSize(kHiDpiBounds.size(), kHiDpiScale); + window_->UpdateVisualSize(kHiDpiSize); Sync(); // Now send configure events many times - bounds mustn't change. for (size_t i = 0; i < 10; i++) { EXPECT_CALL(delegate_, OnBoundsChanged(_)).Times(0); - EXPECT_CALL(*xdg_surface_, SetWindowGeometry(bounds_with_insets.x(), - bounds_with_insets.y(), - bounds_with_insets.width(), - bounds_with_insets.height())); - SendConfigureEvent(xdg_surface_, bounds_with_insets.width(), - bounds_with_insets.height(), ++serial, state.get()); + EXPECT_CALL(*xdg_surface_, SetWindowGeometry(bounds_with_insets)); + SendConfigureEvent(xdg_surface_, bounds_with_insets.size(), ++serial, + state.get()); Sync(); } } TEST_P(WaylandWindowTest, DisregardUnpassedWindowConfigure) { - 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}; + constexpr gfx::Rect kNormalBounds1{500, 300}; + constexpr gfx::Rect kNormalBounds2{800, 600}; + constexpr gfx::Rect kNormalBounds3{700, 400}; uint32_t serial = 1; - window_->set_update_visual_size_immediately(false); + window_->set_update_visual_size_immediately_for_testing(false); // Send 3 configures, and call UpdateVisualSize out of order. The out-of-order // UpdateVisualSize(kNormalBounds2) should disregarded b/c kNormalBounds2 // never reached UI Compositor when UpdateVisualSize(kNormalBounds2) is // called. - EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds1.width(), - kNormalBounds1.height())); + EXPECT_CALL(*xdg_surface_, + SetWindowGeometry(gfx::Rect(kNormalBounds1.size()))); EXPECT_CALL(*xdg_surface_, AckConfigure(2)); - EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds2.width(), - kNormalBounds2.height())) + EXPECT_CALL(*xdg_surface_, + SetWindowGeometry(gfx::Rect(kNormalBounds2.size()))) .Times(0); EXPECT_CALL(*xdg_surface_, AckConfigure(3)).Times(0); - EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds3.width(), - kNormalBounds3.height())); + EXPECT_CALL(*xdg_surface_, + SetWindowGeometry(gfx::Rect(kNormalBounds3.size()))); EXPECT_CALL(*xdg_surface_, AckConfigure(4)); auto state = InitializeWlArrayWithActivatedState(); - SendConfigureEvent(xdg_surface_, kNormalBounds1.width(), - kNormalBounds1.height(), ++serial, state.get()); + SendConfigureEvent(xdg_surface_, kNormalBounds1.size(), ++serial, + state.get()); state = InitializeWlArrayWithActivatedState(); - SendConfigureEvent(xdg_surface_, kNormalBounds2.width(), - kNormalBounds2.height(), ++serial, state.get()); + SendConfigureEvent(xdg_surface_, kNormalBounds2.size(), ++serial, + state.get()); state = InitializeWlArrayWithActivatedState(); - SendConfigureEvent(xdg_surface_, kNormalBounds3.width(), - kNormalBounds3.height(), ++serial, state.get()); + SendConfigureEvent(xdg_surface_, kNormalBounds3.size(), ++serial, + state.get()); Sync(); - window_->UpdateVisualSize(kNormalBounds2.size(), 1.0f); - window_->UpdateVisualSize(kNormalBounds1.size(), 1.0f); - window_->UpdateVisualSize(kNormalBounds3.size(), 1.0f); + 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}; + constexpr gfx::Rect kNormalBounds1{500, 300}; + constexpr gfx::Rect kNormalBounds2{800, 600}; + constexpr gfx::Rect kNormalBounds3{700, 400}; uint32_t serial = 1; - window_->set_update_visual_size_immediately(false); + window_->set_update_visual_size_immediately_for_testing(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_, 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()); + SendConfigureEvent(xdg_surface_, kNormalBounds1.size(), ++serial, + state.get()); state = InitializeWlArrayWithActivatedState(); - SendConfigureEvent(xdg_surface_, kNormalBounds2.width(), - kNormalBounds2.height(), ++serial, state.get()); + SendConfigureEvent(xdg_surface_, kNormalBounds2.size(), ++serial, + state.get()); state = InitializeWlArrayWithActivatedState(); - SendConfigureEvent(xdg_surface_, kNormalBounds3.width(), - kNormalBounds3.height(), ++serial, state.get()); + SendConfigureEvent(xdg_surface_, kNormalBounds3.size(), ++serial, + state.get()); Sync(); - window_->UpdateVisualSize({100, 100}, 1.0f); + 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}; + constexpr gfx::Rect kNormalBounds1{500, 300}; + constexpr gfx::Rect kNormalBounds2{800, 600}; + constexpr gfx::Rect kNormalBounds3{700, 400}; uint32_t serial = 1; auto state = InitializeWlArrayWithActivatedState(); - window_->set_update_visual_size_immediately(false); + window_->set_update_visual_size_immediately_for_testing(false); // Send 3 configures. Calling UpdateVisualSize(kNormalBounds3) will cause the // kNormalBounds3 to be passed onto UI compositor. Hence, kNormalBounds1/2/3 // configs will be acknowledgeable. The next UpdateVisualSize(kNormalBounds3) - // wiil ack kNormalBounds3 and skip kNormalBounds1/2. - EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds1.width(), - kNormalBounds1.height())) + // will ack kNormalBounds3 and skip kNormalBounds1/2. + EXPECT_CALL(*xdg_surface_, + SetWindowGeometry(gfx::Rect(kNormalBounds1.size()))) .Times(0); EXPECT_CALL(*xdg_surface_, AckConfigure(2)).Times(0); - SendConfigureEvent(xdg_surface_, kNormalBounds1.width(), - kNormalBounds1.height(), ++serial, state.get()); + SendConfigureEvent(xdg_surface_, kNormalBounds1.size(), ++serial, + state.get()); Sync(); - EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds2.width(), - kNormalBounds2.height())) + EXPECT_CALL(*xdg_surface_, + SetWindowGeometry(gfx::Rect(kNormalBounds2.size()))) .Times(0); EXPECT_CALL(*xdg_surface_, AckConfigure(3)).Times(0); state = InitializeWlArrayWithActivatedState(); - SendConfigureEvent(xdg_surface_, kNormalBounds2.width(), - kNormalBounds2.height(), ++serial, state.get()); + SendConfigureEvent(xdg_surface_, kNormalBounds2.size(), ++serial, + state.get()); Sync(); - EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds3.width(), - kNormalBounds3.height())); + EXPECT_CALL(*xdg_surface_, + SetWindowGeometry(gfx::Rect(kNormalBounds3.size()))); EXPECT_CALL(*xdg_surface_, AckConfigure(4)); state = InitializeWlArrayWithActivatedState(); - SendConfigureEvent(xdg_surface_, kNormalBounds3.width(), - kNormalBounds3.height(), ++serial, state.get()); + SendConfigureEvent(xdg_surface_, kNormalBounds3.size(), ++serial, + state.get()); Sync(); - window_->UpdateVisualSize(kNormalBounds3.size(), 1.0f); - window_->UpdateVisualSize(kNormalBounds3.size(), 1.0f); + window_->UpdateVisualSize(kNormalBounds3.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}; + constexpr gfx::Rect kNormalBounds{500, 300}; + constexpr gfx::Rect kMaximizedBounds{800, 600}; uint32_t serial = 0; // Make sure the window has normal state initially. - EXPECT_CALL(delegate_, OnBoundsChanged(Eq(kNormalBounds))); - window_->SetBoundsInPixels(kNormalBounds); + EXPECT_CALL(delegate_, OnBoundsChanged(Eq(kDefaultBoundsChange))); + window_->SetBoundsInDIP(gfx::Rect(kNormalBounds.size())); EXPECT_EQ(PlatformWindowState::kNormal, window_->GetPlatformWindowState()); VerifyAndClearExpectations(); // Deactivate the surface. auto empty_state = MakeStateArray({}); - SendConfigureEvent(xdg_surface_, 0, 0, ++serial, empty_state.get()); + SendConfigureEvent(xdg_surface_, {0, 0}, ++serial, empty_state.get()); Sync(); auto active_maximized = MakeStateArray( {XDG_TOPLEVEL_STATE_ACTIVATED, XDG_TOPLEVEL_STATE_MAXIMIZED}); EXPECT_CALL(*GetXdgToplevel(), SetMaximized()); - EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kMaximizedBounds.width(), - kMaximizedBounds.height())); + EXPECT_CALL(*xdg_surface_, + SetWindowGeometry(gfx::Rect(kMaximizedBounds.size()))); EXPECT_CALL(delegate_, OnActivationChanged(Eq(true))); - EXPECT_CALL(delegate_, OnBoundsChanged(Eq(kMaximizedBounds))); + EXPECT_CALL(delegate_, OnBoundsChanged(Eq(kDefaultBoundsChange))); // Emulate a piece of behaviour of BrowserDesktopWindowTreeHostLinux, which is // the real delegate. Its OnWindowStateChanged() may (through some chain of // calls) invoke SetWindowGeometry(), but that should not happen during the @@ -606,35 +635,32 @@ TEST_P(WaylandWindowTest, MaximizeAndRestore) { .WillOnce( testing::Invoke([this]() { window_->SetDecorationInsets({}); })); window_->Maximize(); - SendConfigureEvent(xdg_surface_, kMaximizedBounds.width(), - kMaximizedBounds.height(), ++serial, + SendConfigureEvent(xdg_surface_, kMaximizedBounds.size(), ++serial, active_maximized.get()); Sync(); VerifyAndClearExpectations(); auto inactive_maximized = MakeStateArray({XDG_TOPLEVEL_STATE_MAXIMIZED}); - EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kMaximizedBounds.width(), - kMaximizedBounds.height())); + EXPECT_CALL(*xdg_surface_, + SetWindowGeometry(gfx::Rect(kMaximizedBounds.size()))); EXPECT_CALL(delegate_, OnActivationChanged(Eq(false))); EXPECT_CALL(delegate_, OnBoundsChanged(_)).Times(0); - SendConfigureEvent(xdg_surface_, kMaximizedBounds.width(), - kMaximizedBounds.height(), ++serial, + SendConfigureEvent(xdg_surface_, kMaximizedBounds.size(), ++serial, inactive_maximized.get()); Sync(); VerifyAndClearExpectations(); - EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kMaximizedBounds.width(), - kMaximizedBounds.height())); + EXPECT_CALL(*xdg_surface_, + SetWindowGeometry(gfx::Rect(kMaximizedBounds.size()))); EXPECT_CALL(delegate_, OnActivationChanged(Eq(true))); EXPECT_CALL(delegate_, OnBoundsChanged(_)).Times(0); - SendConfigureEvent(xdg_surface_, kMaximizedBounds.width(), - kMaximizedBounds.height(), ++serial, + SendConfigureEvent(xdg_surface_, kMaximizedBounds.size(), ++serial, active_maximized.get()); Sync(); VerifyAndClearExpectations(); - EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds.width(), - kNormalBounds.height())); + EXPECT_CALL(*xdg_surface_, + SetWindowGeometry(gfx::Rect(kNormalBounds.size()))); // Emulate a piece of behaviour of BrowserDesktopWindowTreeHostLinux, which is // the real delegate. Its OnWindowStateChanged() may (through some chain of // calls) invoke SetWindowGeometry(), but that should not happen during the @@ -645,12 +671,12 @@ TEST_P(WaylandWindowTest, MaximizeAndRestore) { .WillOnce( testing::Invoke([this]() { window_->SetDecorationInsets({}); })); EXPECT_CALL(delegate_, OnActivationChanged(_)).Times(0); - EXPECT_CALL(delegate_, OnBoundsChanged(Eq(kNormalBounds))); + EXPECT_CALL(delegate_, OnBoundsChanged(Eq(kDefaultBoundsChange))); EXPECT_CALL(*GetXdgToplevel(), UnsetMaximized()); window_->Restore(); // Reinitialize wl_array, which removes previous old states. auto active = InitializeWlArrayWithActivatedState(); - SendConfigureEvent(xdg_surface_, 0, 0, ++serial, active.get()); + SendConfigureEvent(xdg_surface_, {0, 0}, ++serial, active.get()); Sync(); } @@ -659,7 +685,7 @@ TEST_P(WaylandWindowTest, Minimize) { // Make sure the window is initialized to normal state from the beginning. EXPECT_EQ(PlatformWindowState::kNormal, window_->GetPlatformWindowState()); - SendConfigureEvent(xdg_surface_, 0, 0, 1, states.get()); + SendConfigureEvent(xdg_surface_, {0, 0}, 1, states.get()); Sync(); EXPECT_CALL(*GetXdgToplevel(), SetMinimized()); @@ -669,7 +695,7 @@ TEST_P(WaylandWindowTest, Minimize) { // Reinitialize wl_array, which removes previous old states. states = ScopedWlArray(); - SendConfigureEvent(xdg_surface_, 0, 0, 2, states.get()); + SendConfigureEvent(xdg_surface_, {0, 0}, 2, states.get()); Sync(); // Wayland compositor doesn't notify clients about minimized state, but rather @@ -688,11 +714,11 @@ TEST_P(WaylandWindowTest, Minimize) { .WillRepeatedly(DoAll(SaveArg<0>(&state), InvokeWithoutArgs([&]() { EXPECT_EQ(state, PlatformWindowState::kMinimized); }))); - SendConfigureEvent(xdg_surface_, 0, 0, 3, states.get()); + SendConfigureEvent(xdg_surface_, {0, 0}, 3, states.get()); Sync(); // And one last time to ensure the behaviour. - SendConfigureEvent(xdg_surface_, 0, 0, 4, states.get()); + SendConfigureEvent(xdg_surface_, {0, 0}, 4, states.get()); Sync(); } @@ -701,7 +727,7 @@ TEST_P(WaylandWindowTest, SetFullscreenAndRestore) { EXPECT_EQ(PlatformWindowState::kNormal, window_->GetPlatformWindowState()); ScopedWlArray states = InitializeWlArrayWithActivatedState(); - SendConfigureEvent(xdg_surface_, 0, 0, 1, states.get()); + SendConfigureEvent(xdg_surface_, {0, 0}, 1, states.get()); Sync(); AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, states.get()); @@ -713,7 +739,7 @@ TEST_P(WaylandWindowTest, SetFullscreenAndRestore) { // comment in the WaylandWindow::ToggleFullscreen. EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kFullScreen); - SendConfigureEvent(xdg_surface_, 0, 0, 2, states.get()); + SendConfigureEvent(xdg_surface_, {0, 0}, 2, states.get()); Sync(); EXPECT_CALL(*GetXdgToplevel(), UnsetFullscreen()); @@ -722,7 +748,7 @@ TEST_P(WaylandWindowTest, SetFullscreenAndRestore) { EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kNormal); // Reinitialize wl_array, which removes previous old states. states = InitializeWlArrayWithActivatedState(); - SendConfigureEvent(xdg_surface_, 0, 0, 3, states.get()); + SendConfigureEvent(xdg_surface_, {0, 0}, 3, states.get()); Sync(); EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kNormal); } @@ -730,7 +756,7 @@ TEST_P(WaylandWindowTest, SetFullscreenAndRestore) { TEST_P(WaylandWindowTest, StartWithFullscreen) { MockWaylandPlatformWindowDelegate delegate; PlatformWindowInitProperties properties; - properties.bounds = gfx::Rect(0, 0, 100, 100); + properties.bounds = gfx::Rect(100, 100); properties.type = PlatformWindowType::kWindow; // We need to create a window avoid calling Show() on it as it is what upper // views layer does - when Widget initialize DesktopWindowTreeHost, the Show() @@ -764,7 +790,7 @@ TEST_P(WaylandWindowTest, StartWithFullscreen) { // Activate the surface. ScopedWlArray states = InitializeWlArrayWithActivatedState(); AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, states.get()); - SendConfigureEvent(xdg_surface_, 0, 0, 1, states.get()); + SendConfigureEvent(xdg_surface_, {0, 0}, 1, states.get()); Sync(); @@ -775,7 +801,7 @@ TEST_P(WaylandWindowTest, StartWithFullscreen) { TEST_P(WaylandWindowTest, StartMaximized) { MockWaylandPlatformWindowDelegate delegate; PlatformWindowInitProperties properties; - properties.bounds = gfx::Rect(0, 0, 100, 100); + properties.bounds = gfx::Rect(100, 100); properties.type = PlatformWindowType::kWindow; // We need to create a window avoid calling Show() on it as it is what upper // views layer does - when Widget initialize DesktopWindowTreeHost, the Show() @@ -810,7 +836,7 @@ TEST_P(WaylandWindowTest, StartMaximized) { // Activate the surface. ScopedWlArray states = InitializeWlArrayWithActivatedState(); AddStateToWlArray(XDG_TOPLEVEL_STATE_MAXIMIZED, states.get()); - SendConfigureEvent(xdg_surface_, 0, 0, 1, states.get()); + SendConfigureEvent(xdg_surface_, {0, 0}, 1, states.get()); Sync(); @@ -820,7 +846,7 @@ TEST_P(WaylandWindowTest, StartMaximized) { TEST_P(WaylandWindowTest, CompositorSideStateChanges) { // Real insets used by default on HiDPI. const auto kInsets = gfx::Insets::TLBR(38, 44, 55, 44); - const auto kNormalBounds = window_->GetBoundsInPixels(); + const auto kNormalBounds = window_->GetBoundsInDIP(); EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kNormal); @@ -831,12 +857,12 @@ TEST_P(WaylandWindowTest, CompositorSideStateChanges) { ScopedWlArray states = InitializeWlArrayWithActivatedState(); AddStateToWlArray(XDG_TOPLEVEL_STATE_MAXIMIZED, states.get()); - SendConfigureEvent(xdg_surface_, 2000, 2000, 1, states.get()); + SendConfigureEvent(xdg_surface_, {2000, 2000}, 1, states.get()); EXPECT_CALL(delegate_, OnWindowStateChanged(_, Eq(PlatformWindowState::kMaximized))) .Times(1); - EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, 2000, 2000)); + EXPECT_CALL(*xdg_surface_, SetWindowGeometry(gfx::Rect{2000, 2000})); Sync(); @@ -844,110 +870,112 @@ TEST_P(WaylandWindowTest, CompositorSideStateChanges) { // Unmaximize states = InitializeWlArrayWithActivatedState(); - SendConfigureEvent(xdg_surface_, 0, 0, 2, states.get()); + SendConfigureEvent(xdg_surface_, {0, 0}, 2, states.get()); EXPECT_CALL(delegate_, OnWindowStateChanged(_, Eq(PlatformWindowState::kNormal))) .Times(1); - EXPECT_CALL(*xdg_surface_, - SetWindowGeometry( - kInsets.left(), kInsets.top(), - kNormalBounds.width() - (kInsets.left() + kInsets.right()), - kNormalBounds.height() - (kInsets.top() + kInsets.bottom()))); + EXPECT_CALL( + *xdg_surface_, + SetWindowGeometry(gfx::Rect( + kInsets.left(), kInsets.top(), + kNormalBounds.width() - (kInsets.left() + kInsets.right()), + kNormalBounds.height() - (kInsets.top() + kInsets.bottom())))); Sync(); // Now, set to fullscreen. AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, states.get()); - SendConfigureEvent(xdg_surface_, 2005, 2005, 3, states.get()); + SendConfigureEvent(xdg_surface_, {2005, 2005}, 3, states.get()); EXPECT_CALL(delegate_, OnWindowStateChanged(_, Eq(PlatformWindowState::kFullScreen))) .Times(1); - EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, 2005, 2005)); + EXPECT_CALL(*xdg_surface_, SetWindowGeometry(gfx::Rect(2005, 2005))); Sync(); // Unfullscreen states = InitializeWlArrayWithActivatedState(); - SendConfigureEvent(xdg_surface_, 0, 0, 4, states.get()); + SendConfigureEvent(xdg_surface_, {0, 0}, 4, states.get()); EXPECT_CALL(delegate_, OnWindowStateChanged(_, Eq(PlatformWindowState::kNormal))) .Times(1); - EXPECT_CALL(*xdg_surface_, - SetWindowGeometry( - kInsets.left(), kInsets.top(), - kNormalBounds.width() - (kInsets.left() + kInsets.right()), - kNormalBounds.height() - (kInsets.top() + kInsets.bottom()))); + EXPECT_CALL( + *xdg_surface_, + SetWindowGeometry(gfx::Rect( + kInsets.left(), kInsets.top(), + kNormalBounds.width() - (kInsets.left() + kInsets.right()), + kNormalBounds.height() - (kInsets.top() + kInsets.bottom())))); Sync(); // Now, maximize, fullscreen and restore. states = InitializeWlArrayWithActivatedState(); AddStateToWlArray(XDG_TOPLEVEL_STATE_MAXIMIZED, states.get()); - SendConfigureEvent(xdg_surface_, 2000, 2000, 1, states.get()); + SendConfigureEvent(xdg_surface_, {2000, 2000}, 1, states.get()); EXPECT_CALL(delegate_, OnWindowStateChanged(_, Eq(PlatformWindowState::kMaximized))) .Times(1); - EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, 2000, 2000)); + EXPECT_CALL(*xdg_surface_, SetWindowGeometry(gfx::Rect(2000, 2000))); Sync(); AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, states.get()); - SendConfigureEvent(xdg_surface_, 2005, 2005, 1, states.get()); + SendConfigureEvent(xdg_surface_, {2005, 2005}, 1, states.get()); EXPECT_CALL(delegate_, OnWindowStateChanged(_, Eq(PlatformWindowState::kFullScreen))) .Times(1); - EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, 2005, 2005)); + EXPECT_CALL(*xdg_surface_, SetWindowGeometry(gfx::Rect(2005, 2005))); // Restore states = InitializeWlArrayWithActivatedState(); - SendConfigureEvent(xdg_surface_, 0, 0, 4, states.get()); + SendConfigureEvent(xdg_surface_, {0, 0}, 4, states.get()); EXPECT_CALL(delegate_, OnWindowStateChanged(_, Eq(PlatformWindowState::kNormal))) .Times(1); - EXPECT_CALL(*xdg_surface_, - SetWindowGeometry( - kInsets.left(), kInsets.top(), - kNormalBounds.width() - (kInsets.left() + kInsets.right()), - kNormalBounds.height() - (kInsets.top() + kInsets.bottom()))); + EXPECT_CALL( + *xdg_surface_, + SetWindowGeometry(gfx::Rect( + kInsets.left(), kInsets.top(), + kNormalBounds.width() - (kInsets.left() + kInsets.right()), + kNormalBounds.height() - (kInsets.top() + kInsets.bottom())))); Sync(); } TEST_P(WaylandWindowTest, SetMaximizedFullscreenAndRestore) { - const auto kNormalBounds = gfx::Rect{0, 0, 500, 300}; - const auto kMaximizedBounds = gfx::Rect{0, 0, 800, 600}; + constexpr gfx::Rect kNormalBounds{500, 300}; + constexpr gfx::Rect kMaximizedBounds{800, 600}; uint32_t serial = 0; // Make sure the window has normal state initially. - EXPECT_CALL(delegate_, OnBoundsChanged(Eq(kNormalBounds))); - window_->SetBoundsInPixels(kNormalBounds); + EXPECT_CALL(delegate_, OnBoundsChanged(Eq(kDefaultBoundsChange))); + window_->SetBoundsInDIP(gfx::Rect(kNormalBounds.size())); EXPECT_EQ(PlatformWindowState::kNormal, window_->GetPlatformWindowState()); VerifyAndClearExpectations(); // Deactivate the surface. ScopedWlArray empty_state; - SendConfigureEvent(xdg_surface_, 0, 0, ++serial, empty_state.get()); + SendConfigureEvent(xdg_surface_, {0, 0}, ++serial, empty_state.get()); Sync(); auto active_maximized = MakeStateArray( {XDG_TOPLEVEL_STATE_ACTIVATED, XDG_TOPLEVEL_STATE_MAXIMIZED}); EXPECT_CALL(*GetXdgToplevel(), SetMaximized()); - EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kMaximizedBounds.width(), - kMaximizedBounds.height())); + EXPECT_CALL(*xdg_surface_, + SetWindowGeometry(gfx::Rect(kMaximizedBounds.size()))); EXPECT_CALL(delegate_, OnActivationChanged(Eq(true))); - EXPECT_CALL(delegate_, OnBoundsChanged(Eq(kMaximizedBounds))); + EXPECT_CALL(delegate_, OnBoundsChanged(Eq(kDefaultBoundsChange))); EXPECT_CALL(delegate_, OnWindowStateChanged(_, _)).Times(1); window_->Maximize(); // State changes are synchronous. EXPECT_EQ(PlatformWindowState::kMaximized, window_->GetPlatformWindowState()); - SendConfigureEvent(xdg_surface_, kMaximizedBounds.width(), - kMaximizedBounds.height(), ++serial, + SendConfigureEvent(xdg_surface_, kMaximizedBounds.size(), ++serial, active_maximized.get()); Sync(); // Verify that the state has not been changed. @@ -955,8 +983,8 @@ TEST_P(WaylandWindowTest, SetMaximizedFullscreenAndRestore) { VerifyAndClearExpectations(); EXPECT_CALL(*GetXdgToplevel(), SetFullscreen()); - EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kMaximizedBounds.width(), - kMaximizedBounds.height())); + EXPECT_CALL(*xdg_surface_, + SetWindowGeometry(gfx::Rect(kMaximizedBounds.size()))); EXPECT_CALL(delegate_, OnBoundsChanged(_)).Times(0); EXPECT_CALL(delegate_, OnWindowStateChanged(_, _)).Times(1); window_->ToggleFullscreen(); @@ -964,8 +992,7 @@ TEST_P(WaylandWindowTest, SetMaximizedFullscreenAndRestore) { EXPECT_EQ(PlatformWindowState::kFullScreen, window_->GetPlatformWindowState()); AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, active_maximized.get()); - SendConfigureEvent(xdg_surface_, kMaximizedBounds.width(), - kMaximizedBounds.height(), ++serial, + SendConfigureEvent(xdg_surface_, kMaximizedBounds.size(), ++serial, active_maximized.get()); Sync(); // Verify that the state has not been changed. @@ -973,167 +1000,161 @@ TEST_P(WaylandWindowTest, SetMaximizedFullscreenAndRestore) { window_->GetPlatformWindowState()); VerifyAndClearExpectations(); - EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds.width(), - kNormalBounds.height())); + EXPECT_CALL(*xdg_surface_, + SetWindowGeometry(gfx::Rect(kNormalBounds.size()))); EXPECT_CALL(*GetXdgToplevel(), UnsetFullscreen()); - EXPECT_CALL(delegate_, OnBoundsChanged(Eq(kNormalBounds))); + EXPECT_CALL(delegate_, OnBoundsChanged(Eq(kDefaultBoundsChange))); EXPECT_CALL(delegate_, OnWindowStateChanged(_, _)).Times(1); window_->Restore(); EXPECT_EQ(PlatformWindowState::kNormal, window_->GetPlatformWindowState()); // Reinitialize wl_array, which removes previous old states. auto active = InitializeWlArrayWithActivatedState(); - SendConfigureEvent(xdg_surface_, 0, 0, ++serial, active.get()); + SendConfigureEvent(xdg_surface_, {0, 0}, ++serial, active.get()); Sync(); EXPECT_EQ(PlatformWindowState::kNormal, window_->GetPlatformWindowState()); } TEST_P(WaylandWindowTest, RestoreBoundsAfterMaximize) { - const gfx::Rect current_bounds = window_->GetBoundsInPixels(); + const gfx::Rect current_bounds = window_->GetBoundsInDIP(); ScopedWlArray states = InitializeWlArrayWithActivatedState(); gfx::Rect restored_bounds = window_->GetRestoredBoundsInDIP(); EXPECT_TRUE(restored_bounds.IsEmpty()); - gfx::Rect bounds = window_->GetBoundsInPixels(); + gfx::Rect bounds = window_->GetBoundsInDIP(); - const gfx::Rect maximized_bounds = gfx::Rect(0, 0, 1024, 768); - EXPECT_CALL(delegate_, OnBoundsChanged(Eq(maximized_bounds))); + constexpr gfx::Rect kMaximizedBounds(1024, 768); + EXPECT_CALL(delegate_, OnBoundsChanged(Eq(kDefaultBoundsChange))); window_->Maximize(); AddStateToWlArray(XDG_TOPLEVEL_STATE_MAXIMIZED, states.get()); - SendConfigureEvent(xdg_surface_, maximized_bounds.width(), - maximized_bounds.height(), 1, states.get()); + SendConfigureEvent(xdg_surface_, kMaximizedBounds.size(), 1, states.get()); Sync(); restored_bounds = window_->GetRestoredBoundsInDIP(); EXPECT_EQ(bounds, restored_bounds); - EXPECT_CALL(delegate_, OnBoundsChanged(Eq(current_bounds))); + EXPECT_CALL(delegate_, OnBoundsChanged(Eq(kDefaultBoundsChange))); // Both in XdgV5 and XdgV6, surfaces implement SetWindowGeometry method. // Thus, using a toplevel object in XdgV6 case is not right thing. Use a // surface here instead. - EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, current_bounds.width(), - current_bounds.height())); + EXPECT_CALL(*xdg_surface_, + SetWindowGeometry(gfx::Rect{current_bounds.size()})); window_->Restore(); // Reinitialize wl_array, which removes previous old states. states = InitializeWlArrayWithActivatedState(); - SendConfigureEvent(xdg_surface_, 0, 0, 2, states.get()); + SendConfigureEvent(xdg_surface_, {0, 0}, 2, states.get()); Sync(); - bounds = window_->GetBoundsInPixels(); + bounds = window_->GetBoundsInDIP(); EXPECT_EQ(bounds, restored_bounds); restored_bounds = window_->GetRestoredBoundsInDIP(); EXPECT_EQ(restored_bounds, gfx::Rect()); } TEST_P(WaylandWindowTest, RestoreBoundsAfterFullscreen) { - const gfx::Rect current_bounds = window_->GetBoundsInPixels(); + const gfx::Rect current_bounds = window_->GetBoundsInDIP(); ScopedWlArray states = InitializeWlArrayWithActivatedState(); - SendConfigureEvent(xdg_surface_, 0, 0, 1, states.get()); + SendConfigureEvent(xdg_surface_, {0, 0}, 1, states.get()); Sync(); gfx::Rect restored_bounds = window_->GetRestoredBoundsInDIP(); EXPECT_EQ(restored_bounds, gfx::Rect()); - gfx::Rect bounds = window_->GetBoundsInPixels(); + gfx::Rect bounds = window_->GetBoundsInDIP(); - const gfx::Rect fullscreen_bounds = gfx::Rect(0, 0, 1280, 720); - EXPECT_CALL(delegate_, OnBoundsChanged(Eq(fullscreen_bounds))); + constexpr gfx::Rect kFullscreenBounds(1280, 720); + EXPECT_CALL(delegate_, OnBoundsChanged(Eq(kDefaultBoundsChange))); window_->ToggleFullscreen(); AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, states.get()); - SendConfigureEvent(xdg_surface_, fullscreen_bounds.width(), - fullscreen_bounds.height(), 2, states.get()); + SendConfigureEvent(xdg_surface_, kFullscreenBounds.size(), 2, states.get()); Sync(); restored_bounds = window_->GetRestoredBoundsInDIP(); EXPECT_EQ(bounds, restored_bounds); - EXPECT_CALL(delegate_, OnBoundsChanged(Eq(current_bounds))); + EXPECT_CALL(delegate_, OnBoundsChanged(Eq(kDefaultBoundsChange))); // Both in XdgV5 and XdgV6, surfaces implement SetWindowGeometry method. // Thus, using a toplevel object in XdgV6 case is not right thing. Use a // surface here instead. - EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, current_bounds.width(), - current_bounds.height())); + EXPECT_CALL(*xdg_surface_, + SetWindowGeometry(gfx::Rect(current_bounds.size()))); window_->Restore(); // Reinitialize wl_array, which removes previous old states. states = InitializeWlArrayWithActivatedState(); - SendConfigureEvent(xdg_surface_, 0, 0, 3, states.get()); + SendConfigureEvent(xdg_surface_, {0, 0}, 3, states.get()); Sync(); - bounds = window_->GetBoundsInPixels(); + bounds = window_->GetBoundsInDIP(); EXPECT_EQ(bounds, restored_bounds); restored_bounds = window_->GetRestoredBoundsInDIP(); EXPECT_EQ(restored_bounds, gfx::Rect()); } TEST_P(WaylandWindowTest, RestoreBoundsAfterMaximizeAndFullscreen) { - const gfx::Rect current_bounds = window_->GetBoundsInPixels(); + const gfx::Rect current_bounds = window_->GetBoundsInDIP(); ScopedWlArray states = InitializeWlArrayWithActivatedState(); gfx::Rect restored_bounds = window_->GetRestoredBoundsInDIP(); EXPECT_EQ(restored_bounds, gfx::Rect()); - gfx::Rect bounds = window_->GetBoundsInPixels(); + gfx::Rect bounds = window_->GetBoundsInDIP(); - const gfx::Rect maximized_bounds = gfx::Rect(0, 0, 1024, 768); - EXPECT_CALL(delegate_, OnBoundsChanged(Eq(maximized_bounds))); + constexpr gfx::Rect kMaximizedBounds(1024, 768); + EXPECT_CALL(delegate_, OnBoundsChanged(Eq(kDefaultBoundsChange))); window_->Maximize(); AddStateToWlArray(XDG_TOPLEVEL_STATE_MAXIMIZED, states.get()); - SendConfigureEvent(xdg_surface_, maximized_bounds.width(), - maximized_bounds.height(), 1, states.get()); + SendConfigureEvent(xdg_surface_, kMaximizedBounds.size(), 1, states.get()); Sync(); restored_bounds = window_->GetRestoredBoundsInDIP(); EXPECT_EQ(bounds, restored_bounds); - const gfx::Rect fullscreen_bounds = gfx::Rect(0, 0, 1280, 720); - EXPECT_CALL(delegate_, OnBoundsChanged(Eq(fullscreen_bounds))); + constexpr gfx::Rect kFullscreenBounds(1280, 720); + EXPECT_CALL(delegate_, OnBoundsChanged(Eq(kDefaultBoundsChange))); window_->ToggleFullscreen(); AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, states.get()); - SendConfigureEvent(xdg_surface_, fullscreen_bounds.width(), - fullscreen_bounds.height(), 2, states.get()); + SendConfigureEvent(xdg_surface_, kFullscreenBounds.size(), 2, states.get()); Sync(); gfx::Rect fullscreen_restore_bounds = window_->GetRestoredBoundsInDIP(); EXPECT_EQ(restored_bounds, fullscreen_restore_bounds); - EXPECT_CALL(delegate_, OnBoundsChanged(Eq(maximized_bounds))); + EXPECT_CALL(delegate_, OnBoundsChanged(Eq(kDefaultBoundsChange))); window_->Maximize(); // Reinitialize wl_array, which removes previous old states. states = InitializeWlArrayWithActivatedState(); AddStateToWlArray(XDG_TOPLEVEL_STATE_MAXIMIZED, states.get()); - SendConfigureEvent(xdg_surface_, maximized_bounds.width(), - maximized_bounds.height(), 3, states.get()); + SendConfigureEvent(xdg_surface_, kMaximizedBounds.size(), 3, states.get()); Sync(); restored_bounds = window_->GetRestoredBoundsInDIP(); EXPECT_EQ(restored_bounds, fullscreen_restore_bounds); - EXPECT_CALL(delegate_, OnBoundsChanged(Eq(current_bounds))); + EXPECT_CALL(delegate_, OnBoundsChanged(Eq(kDefaultBoundsChange))); // Both in XdgV5 and XdgV6, surfaces implement SetWindowGeometry method. // Thus, using a toplevel object in XdgV6 case is not right thing. Use a // surface here instead. - EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, current_bounds.width(), - current_bounds.height())); + EXPECT_CALL(*xdg_surface_, + SetWindowGeometry(gfx::Rect(current_bounds.size()))); window_->Restore(); // Reinitialize wl_array, which removes previous old states. states = InitializeWlArrayWithActivatedState(); - SendConfigureEvent(xdg_surface_, 0, 0, 4, states.get()); + SendConfigureEvent(xdg_surface_, {0, 0}, 4, states.get()); Sync(); - bounds = window_->GetBoundsInPixels(); + bounds = window_->GetBoundsInDIP(); EXPECT_EQ(bounds, restored_bounds); restored_bounds = window_->GetRestoredBoundsInDIP(); EXPECT_EQ(restored_bounds, gfx::Rect()); } TEST_P(WaylandWindowTest, SendsBoundsOnRequest) { - const gfx::Rect initial_bounds = window_->GetBoundsInPixels(); + const gfx::Rect initial_bounds = window_->GetBoundsInDIP(); - const gfx::Rect new_bounds = gfx::Rect(0, 0, initial_bounds.width() + 10, - initial_bounds.height() + 10); - EXPECT_CALL(delegate_, OnBoundsChanged(Eq(new_bounds))); - window_->SetBoundsInPixels(new_bounds); + const gfx::Rect new_bounds = + gfx::Rect(initial_bounds.width() + 10, initial_bounds.height() + 10); + EXPECT_CALL(delegate_, OnBoundsChanged(kDefaultBoundsChange)); + window_->SetBoundsInDIP(new_bounds); ScopedWlArray states = InitializeWlArrayWithActivatedState(); // First case is when Wayland sends a configure event with 0,0 height and // width. - EXPECT_CALL(*xdg_surface_, - SetWindowGeometry(0, 0, new_bounds.width(), new_bounds.height())) + EXPECT_CALL(*xdg_surface_, SetWindowGeometry(gfx::Rect(new_bounds.size()))) .Times(2); - SendConfigureEvent(xdg_surface_, 0, 0, 2, states.get()); + SendConfigureEvent(xdg_surface_, {0, 0}, 2, states.get()); Sync(); // Restored bounds should keep empty value. @@ -1143,7 +1164,7 @@ TEST_P(WaylandWindowTest, SendsBoundsOnRequest) { // Second case is when Wayland sends a configure event with 1, 1 height and // width. It looks more like a bug in Gnome Shell with Wayland as long as the // documentation says it must be set to 0, 0, when wayland requests bounds. - SendConfigureEvent(xdg_surface_, 0, 0, 3, states.get()); + SendConfigureEvent(xdg_surface_, {0, 0}, 3, states.get()); Sync(); // Restored bounds should keep empty value. @@ -1156,12 +1177,12 @@ TEST_P(WaylandWindowTest, UpdateWindowRegion) { window_->root_surface()->GetSurfaceId()); // Change bounds. - const gfx::Rect initial_bounds = window_->GetBoundsInPixels(); - const gfx::Rect new_bounds = gfx::Rect(0, 0, initial_bounds.width() + 10, - initial_bounds.height() + 10); + const gfx::Rect initial_bounds = window_->GetBoundsInDIP(); + const gfx::Rect new_bounds = + gfx::Rect(initial_bounds.width() + 10, initial_bounds.height() + 10); EXPECT_CALL(*mock_surface, SetOpaqueRegion(_)).Times(1); EXPECT_CALL(*mock_surface, SetInputRegion(_)).Times(1); - window_->SetBoundsInPixels(new_bounds); + window_->SetBoundsInDIP(new_bounds); Sync(); VerifyAndClearExpectations(); EXPECT_EQ(mock_surface->opaque_region(), new_bounds); @@ -1171,15 +1192,14 @@ TEST_P(WaylandWindowTest, UpdateWindowRegion) { 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); + constexpr gfx::Rect kMaximizedBounds(1024, 768); window_->Maximize(); AddStateToWlArray(XDG_TOPLEVEL_STATE_MAXIMIZED, states.get()); - SendConfigureEvent(xdg_surface_, maximized_bounds.width(), - maximized_bounds.height(), 1, states.get()); + SendConfigureEvent(xdg_surface_, kMaximizedBounds.size(), 1, states.get()); Sync(); VerifyAndClearExpectations(); - EXPECT_EQ(mock_surface->opaque_region(), maximized_bounds); - EXPECT_EQ(mock_surface->input_region(), maximized_bounds); + EXPECT_EQ(mock_surface->opaque_region(), kMaximizedBounds); + EXPECT_EQ(mock_surface->input_region(), kMaximizedBounds); // Restore. const gfx::Rect restored_bounds = window_->GetRestoredBoundsInDIP(); @@ -1188,7 +1208,7 @@ TEST_P(WaylandWindowTest, UpdateWindowRegion) { window_->Restore(); // Reinitialize wl_array, which removes previous old states. auto active = InitializeWlArrayWithActivatedState(); - SendConfigureEvent(xdg_surface_, 0, 0, 2, active.get()); + SendConfigureEvent(xdg_surface_, {0, 0}, 2, active.get()); Sync(); VerifyAndClearExpectations(); @@ -1196,25 +1216,17 @@ TEST_P(WaylandWindowTest, UpdateWindowRegion) { EXPECT_EQ(mock_surface->input_region(), restored_bounds); } -TEST_P(WaylandWindowTest, CanDispatchMouseEventDefault) { - EXPECT_FALSE(window_->CanDispatchEvent(&test_mouse_event_)); -} - TEST_P(WaylandWindowTest, CanDispatchMouseEventFocus) { - // SetPointerFocus(true) requires a WaylandPointer. + // SetPointerFocusedWindow requires a WaylandPointer. wl_seat_send_capabilities(server_.seat()->resource(), WL_SEAT_CAPABILITY_POINTER); Sync(); ASSERT_TRUE(connection_->seat()->pointer()); - window_->SetPointerFocus(true); + SetPointerFocusedWindow(window_.get()); + Event::DispatcherApi(&test_mouse_event_).set_target(window_.get()); EXPECT_TRUE(window_->CanDispatchEvent(&test_mouse_event_)); } -TEST_P(WaylandWindowTest, CanDispatchMouseEventUnfocus) { - EXPECT_FALSE(window_->has_pointer_focus()); - EXPECT_FALSE(window_->CanDispatchEvent(&test_mouse_event_)); -} - TEST_P(WaylandWindowTest, SetCursorUsesZcrCursorShapesForCommonTypes) { MockZcrCursorShapes* mock_cursor_shapes = InstallMockZcrCursorShapes(); @@ -1268,7 +1280,7 @@ TEST_P(WaylandWindowTest, SetCursorDoesNotUseZcrCursorShapesForCustomCursors) { } ACTION_P(CloneEvent, ptr) { - *ptr = Event::Clone(*arg0); + *ptr = arg0->Clone(); } TEST_P(WaylandWindowTest, DispatchEvent) { @@ -1292,23 +1304,25 @@ TEST_P(WaylandWindowTest, ConfigureEvent) { // The surface must react on each configure event and send bounds to its // delegate. + constexpr gfx::Size kSize{1000, 1000}; - EXPECT_CALL(delegate_, OnBoundsChanged(Eq(gfx::Rect(0, 0, 1000, 1000)))); + EXPECT_CALL(delegate_, OnBoundsChanged(Eq(kDefaultBoundsChange))); // Responding to a configure event, the window geometry in here must respect // the sizing negotiations specified by the configure event. // |xdg_surface_| must receive the following calls in both xdg_shell_v5 and // xdg_shell_v6. Other calls like SetTitle or SetMaximized are recieved by // xdg_toplevel in xdg_shell_v6 and by xdg_surface_ in xdg_shell_v5. - EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, 1000, 1000)).Times(1); + EXPECT_CALL(*xdg_surface_, SetWindowGeometry(gfx::Rect(kSize))).Times(1); EXPECT_CALL(*xdg_surface_, AckConfigure(12)); - SendConfigureEvent(xdg_surface_, 1000, 1000, 12, states.get()); + SendConfigureEvent(xdg_surface_, kSize, 12, states.get()); Sync(); + constexpr gfx::Size kNewSize{1500, 1000}; - EXPECT_CALL(delegate_, OnBoundsChanged(Eq(gfx::Rect(0, 0, 1500, 1000)))); - EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, 1500, 1000)).Times(1); + EXPECT_CALL(delegate_, OnBoundsChanged(Eq(kDefaultBoundsChange))); + EXPECT_CALL(*xdg_surface_, SetWindowGeometry(gfx::Rect(kNewSize))).Times(1); EXPECT_CALL(*xdg_surface_, AckConfigure(13)); - SendConfigureEvent(xdg_surface_, 1500, 1000, 13, states.get()); + SendConfigureEvent(xdg_surface_, kNewSize, 13, states.get()); } TEST_P(WaylandWindowTest, ConfigureEventWithNulledSize) { @@ -1317,11 +1331,11 @@ TEST_P(WaylandWindowTest, ConfigureEventWithNulledSize) { // If Wayland sends configure event with 0 width and 0 size, client should // call back with desired sizes. In this case, that's the actual size of // the window. - SendConfigureEvent(xdg_surface_, 0, 0, 14, states.get()); + SendConfigureEvent(xdg_surface_, {0, 0}, 14, states.get()); // |xdg_surface_| must receive the following calls in both xdg_shell_v5 and // xdg_shell_v6. Other calls like SetTitle or SetMaximized are recieved by // xdg_toplevel in xdg_shell_v6 and by xdg_surface_ in xdg_shell_v5. - EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, 800, 600)); + EXPECT_CALL(*xdg_surface_, SetWindowGeometry(gfx::Rect(800, 600))); EXPECT_CALL(*xdg_surface_, AckConfigure(14)); } @@ -1330,19 +1344,19 @@ TEST_P(WaylandWindowTest, OnActivationChanged) { // Deactivate the surface. ScopedWlArray empty_state; - SendConfigureEvent(xdg_surface_, 0, 0, ++serial, empty_state.get()); + SendConfigureEvent(xdg_surface_, {0, 0}, ++serial, empty_state.get()); Sync(); { ScopedWlArray states = InitializeWlArrayWithActivatedState(); EXPECT_CALL(delegate_, OnActivationChanged(Eq(true))); - SendConfigureEvent(xdg_surface_, 0, 0, ++serial, states.get()); + SendConfigureEvent(xdg_surface_, {0, 0}, ++serial, states.get()); Sync(); } ScopedWlArray states; EXPECT_CALL(delegate_, OnActivationChanged(Eq(false))); - SendConfigureEvent(xdg_surface_, 0, 0, ++serial, states.get()); + SendConfigureEvent(xdg_surface_, {0, 0}, ++serial, states.get()); Sync(); } @@ -1361,23 +1375,23 @@ TEST_P(WaylandWindowTest, CanCreateMenuWindow) { WL_SEAT_CAPABILITY_POINTER | WL_SEAT_CAPABILITY_TOUCH); Sync(); ASSERT_TRUE(connection_->seat()->pointer() && connection_->seat()->touch()); - window_->SetPointerFocus(true); + SetPointerFocusedWindow(window_.get()); std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams( - PlatformWindowType::kMenu, gfx::kNullAcceleratedWidget, - gfx::Rect(0, 0, 10, 10), &menu_window_delegate); + PlatformWindowType::kMenu, gfx::kNullAcceleratedWidget, gfx::Rect(10, 10), + &menu_window_delegate); EXPECT_TRUE(menu_window); Sync(); - window_->SetPointerFocus(false); + SetPointerFocusedWindow(window_.get()); window_->set_touch_focus(false); // Given that there is no parent passed and we don't have any focused windows, // Wayland must still create a window. menu_window = CreateWaylandWindowWithParams( - PlatformWindowType::kMenu, gfx::kNullAcceleratedWidget, - gfx::Rect(0, 0, 10, 10), &menu_window_delegate); + PlatformWindowType::kMenu, gfx::kNullAcceleratedWidget, gfx::Rect(10, 10), + &menu_window_delegate); EXPECT_TRUE(menu_window); Sync(); @@ -1385,8 +1399,8 @@ TEST_P(WaylandWindowTest, CanCreateMenuWindow) { window_->set_touch_focus(true); menu_window = CreateWaylandWindowWithParams( - PlatformWindowType::kMenu, gfx::kNullAcceleratedWidget, - gfx::Rect(0, 0, 10, 10), &menu_window_delegate); + PlatformWindowType::kMenu, gfx::kNullAcceleratedWidget, gfx::Rect(10, 10), + &menu_window_delegate); EXPECT_TRUE(menu_window); Sync(); @@ -1400,9 +1414,9 @@ TEST_P(WaylandWindowTest, CreateAndDestroyNestedMenuWindow) { EXPECT_CALL(menu_window_delegate, GetMenuType()) .WillRepeatedly(Return(MenuType::kRootContextMenu)); - std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams( - PlatformWindowType::kMenu, widget_, gfx::Rect(0, 0, 10, 10), - &menu_window_delegate); + std::unique_ptr<WaylandWindow> menu_window = + CreateWaylandWindowWithParams(PlatformWindowType::kMenu, widget_, + gfx::Rect(10, 10), &menu_window_delegate); EXPECT_TRUE(menu_window); ASSERT_NE(menu_window_widget, gfx::kNullAcceleratedWidget); @@ -1431,10 +1445,10 @@ TEST_P(WaylandWindowTest, DispatchesLocatedEventsToCapturedWindow) { WL_SEAT_CAPABILITY_POINTER); Sync(); ASSERT_TRUE(connection_->seat()->pointer()); - window_->SetPointerFocus(true); + SetPointerFocusedWindow(window_.get()); // Make sure the events are handled by the window that has the pointer focus. - VerifyCanDispatchMouseEvents({window_.get()}, {menu_window.get()}); + VerifyCanDispatchMouseEvents(window_.get(), {menu_window.get()}); // The |window_| that has the pointer focus must receive the event. EXPECT_CALL(menu_window_delegate, DispatchEvent(_)).Times(0); @@ -1456,7 +1470,7 @@ TEST_P(WaylandWindowTest, DispatchesLocatedEventsToCapturedWindow) { // It's still the |window_| that can dispatch the events, but it will reroute // the event to correct window and fix the location. - VerifyCanDispatchMouseEvents({window_.get()}, {menu_window.get()}); + VerifyCanDispatchMouseEvents(window_.get(), {menu_window.get()}); // The |window_| that has the pointer focus must receive the event. EXPECT_CALL(delegate_, DispatchEvent(_)).Times(0); @@ -1502,12 +1516,11 @@ TEST_P(WaylandWindowTest, DispatchesLocatedEventsToCapturedWindow) { Sync(); - window_->SetPointerFocus(false); - nested_menu_window->SetPointerFocus(true); + SetPointerFocusedWindow(nested_menu_window.get()); // The event is processed by the window that has the pointer focus, but // dispatched by the window that has the capture. - VerifyCanDispatchMouseEvents({nested_menu_window.get()}, + VerifyCanDispatchMouseEvents(nested_menu_window.get(), {window_.get(), menu_window.get()}); EXPECT_TRUE(menu_window->HasCapture()); @@ -1548,17 +1561,17 @@ TEST_P(WaylandWindowTest, std::unique_ptr<WaylandWindow> toplevel_window2 = CreateWaylandWindowWithParams( PlatformWindowType::kWindow, gfx::kNullAcceleratedWidget, - window_->GetBoundsInPixels(), &toplevel_window2_delegate); + window_->GetBoundsInDIP(), &toplevel_window2_delegate); EXPECT_TRUE(toplevel_window2); wl_seat_send_capabilities(server_.seat()->resource(), WL_SEAT_CAPABILITY_POINTER); Sync(); ASSERT_TRUE(connection_->seat()->pointer()); - window_->SetPointerFocus(true); + SetPointerFocusedWindow(window_.get()); // Make sure the events are handled by the window that has the pointer focus. - VerifyCanDispatchMouseEvents({window_.get()}, + VerifyCanDispatchMouseEvents(window_.get(), {menu_window.get(), toplevel_window2.get()}); menu_window->SetCapture(); @@ -1582,10 +1595,9 @@ TEST_P(WaylandWindowTest, // Now, pretend that the second toplevel window gets the pointer focus - the // event grabber must be disragerder now. - window_->SetPointerFocus(false); - toplevel_window2->SetPointerFocus(true); + SetPointerFocusedWindow(toplevel_window2.get()); - VerifyCanDispatchMouseEvents({toplevel_window2.get()}, + VerifyCanDispatchMouseEvents(toplevel_window2.get(), {menu_window.get(), window_.get()}); // The |toplevel_window2| that has capture and must receive the event. @@ -1620,7 +1632,7 @@ TEST_P(WaylandWindowTest, DispatchesKeyboardEventToToplevelWindow) { WL_SEAT_CAPABILITY_KEYBOARD); Sync(); ASSERT_TRUE(connection_->seat()->keyboard()); - menu_window->set_keyboard_focus(true); + SetKeyboardFocusedWindow(menu_window.get()); // Even though the menu window has the keyboard focus, the keyboard events are // dispatched by the root parent wayland window in the end. @@ -1664,9 +1676,9 @@ TEST_P(WaylandWindowTest, CanDispatchEvent) { EXPECT_CALL(menu_window_delegate, GetMenuType()) .WillOnce(Return(MenuType::kRootContextMenu)); - std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams( - PlatformWindowType::kMenu, widget_, gfx::Rect(0, 0, 10, 10), - &menu_window_delegate); + std::unique_ptr<WaylandWindow> menu_window = + CreateWaylandWindowWithParams(PlatformWindowType::kMenu, widget_, + gfx::Rect(10, 10), &menu_window_delegate); EXPECT_TRUE(menu_window); Sync(); @@ -1702,7 +1714,7 @@ TEST_P(WaylandWindowTest, CanDispatchEvent) { Sync(); // Only |window_| can dispatch MouseEvents. - VerifyCanDispatchMouseEvents({window_.get()}, + VerifyCanDispatchMouseEvents(window_.get(), {menu_window.get(), nested_menu_window.get()}); VerifyCanDispatchTouchEvents( {}, {window_.get(), menu_window.get(), nested_menu_window.get()}); @@ -1717,7 +1729,7 @@ TEST_P(WaylandWindowTest, CanDispatchEvent) { Sync(); // Only |window_| can dispatch MouseEvents and KeyEvents. - VerifyCanDispatchMouseEvents({window_.get()}, + VerifyCanDispatchMouseEvents(window_.get(), {menu_window.get(), nested_menu_window.get()}); VerifyCanDispatchTouchEvents( {}, {window_.get(), menu_window.get(), nested_menu_window.get()}); @@ -1732,7 +1744,7 @@ TEST_P(WaylandWindowTest, CanDispatchEvent) { Sync(); // Only |window_| can dispatch MouseEvents and KeyEvents. - VerifyCanDispatchMouseEvents({window_.get()}, + VerifyCanDispatchMouseEvents(window_.get(), {menu_window.get(), nested_menu_window.get()}); VerifyCanDispatchTouchEvents({window_.get()}, {menu_window.get(), nested_menu_window.get()}); @@ -1756,7 +1768,7 @@ TEST_P(WaylandWindowTest, CanDispatchEvent) { Sync(); // Only |menu_window| can dispatch MouseEvents. - VerifyCanDispatchMouseEvents({menu_window.get()}, + VerifyCanDispatchMouseEvents(menu_window.get(), {window_.get(), nested_menu_window.get()}); VerifyCanDispatchTouchEvents( {}, {window_.get(), menu_window.get(), nested_menu_window.get()}); @@ -1775,7 +1787,7 @@ TEST_P(WaylandWindowTest, CanDispatchEvent) { Sync(); // Only |nested_menu_window| can dispatch MouseEvents. - VerifyCanDispatchMouseEvents({nested_menu_window.get()}, + VerifyCanDispatchMouseEvents(nested_menu_window.get(), {window_.get(), menu_window.get()}); VerifyCanDispatchTouchEvents( {}, {window_.get(), menu_window.get(), nested_menu_window.get()}); @@ -1837,13 +1849,13 @@ TEST_P(WaylandWindowTest, ToplevelWindowUpdateWindowScale) { // Creating an output with scale 1. wl::TestOutput* output1 = server_.CreateAndInitializeOutput(); - output1->SetRect(gfx::Rect(0, 0, 1920, 1080)); + output1->SetRect(gfx::Rect(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->SetRect(gfx::Rect(1920, 1080)); output2->SetScale(2); Sync(); @@ -1856,7 +1868,8 @@ TEST_P(WaylandWindowTest, ToplevelWindowUpdateWindowScale) { // The window's scale and bounds must remain unchanged. EXPECT_EQ(1, window_->window_scale()); - EXPECT_EQ(gfx::Rect(0, 0, 800, 600), window_->GetBoundsInPixels()); + EXPECT_EQ(gfx::Size(800, 600), window_->size_px()); + EXPECT_EQ(gfx::Rect(800, 600), window_->GetBoundsInDIP()); // Simulating drag process from |output1| to |output2|. wl_surface_send_enter(surface->resource(), output2->resource()); @@ -1865,7 +1878,8 @@ TEST_P(WaylandWindowTest, ToplevelWindowUpdateWindowScale) { // The window must change its scale and bounds to keep DIP bounds the same. EXPECT_EQ(2, window_->window_scale()); - EXPECT_EQ(gfx::Rect(0, 0, 1600, 1200), window_->GetBoundsInPixels()); + EXPECT_EQ(gfx::Size(1600, 1200), window_->size_px()); + EXPECT_EQ(gfx::Rect(800, 600), window_->GetBoundsInDIP()); } TEST_P(WaylandWindowTest, WaylandPopupSurfaceScale) { @@ -1873,7 +1887,7 @@ TEST_P(WaylandWindowTest, WaylandPopupSurfaceScale) { // Creating an output with scale 1. wl::TestOutput* output1 = server_.CreateAndInitializeOutput(); - output1->SetRect(gfx::Rect(0, 0, 1920, 1080)); + output1->SetRect(gfx::Rect(1920, 1080)); output1->SetScale(1); Sync(); @@ -1894,7 +1908,7 @@ TEST_P(WaylandWindowTest, WaylandPopupSurfaceScale) { Sync(); // Creating a wayland_popup on |window_|. - window_->SetPointerFocus(true); + SetPointerFocusedWindow(window_.get()); gfx::Rect wayland_popup_bounds(15, 15, 10, 10); auto wayland_popup = CreateWaylandWindowWithParams( type, window_->GetWidget(), wayland_popup_bounds, &delegate_); @@ -1905,7 +1919,8 @@ TEST_P(WaylandWindowTest, WaylandPopupSurfaceScale) { // window. EXPECT_EQ(1, window_->window_scale()); EXPECT_EQ(window_->window_scale(), wayland_popup->window_scale()); - EXPECT_EQ(wayland_popup_bounds, wayland_popup->GetBoundsInPixels()); + EXPECT_EQ(wayland_popup_bounds.size(), wayland_popup->size_px()); + EXPECT_EQ(wayland_popup_bounds, wayland_popup->GetBoundsInDIP()); wayland_popup->Hide(); // Send the window to |output2|. @@ -1921,12 +1936,12 @@ TEST_P(WaylandWindowTest, WaylandPopupSurfaceScale) { // |wayland_popup|'s scale and bounds must change whenever its parents // scale is changed. EXPECT_EQ(window_->window_scale(), wayland_popup->window_scale()); - EXPECT_EQ(gfx::ScaleToRoundedRect(wayland_popup_bounds, - wayland_popup->window_scale()), - wayland_popup->GetBoundsInPixels()); + EXPECT_EQ(gfx::ScaleToCeiledSize(wayland_popup_bounds.size(), + wayland_popup->window_scale()), + wayland_popup->size_px()); wayland_popup->Hide(); - window_->SetPointerFocus(false); + SetPointerFocusedWindow(nullptr); wl_surface_send_leave(surface->resource(), output2->resource()); Sync(); @@ -1941,7 +1956,7 @@ TEST_P(WaylandWindowTest, WaylandPopupInitialBufferScale) { VerifyAndClearExpectations(); wl::TestOutput* main_output = server_.CreateAndInitializeOutput(); - main_output->SetRect(gfx::Rect(0, 0, 1920, 1080)); + main_output->SetRect(gfx::Rect(1920, 1080)); main_output->SetScale(1); Sync(); @@ -1955,7 +1970,7 @@ TEST_P(WaylandWindowTest, WaylandPopupInitialBufferScale) { ASSERT_TRUE(surface); struct { - wl::TestOutput* output; + raw_ptr<wl::TestOutput> output; const char* label; } screen[] = {{main_output, "main output"}, {secondary_output, "secondary output"}}; @@ -1980,7 +1995,7 @@ TEST_P(WaylandWindowTest, WaylandPopupInitialBufferScale) { // DesktopWindowTreeHostPlatform uses the scale of the current display // of the parent window to translate initial bounds of the popup to // pixels. - const auto effective_scale = entered_output.output->GetScale(); + const int32_t effective_scale = entered_output.output->GetScale(); gfx::Transform transform; transform.Scale(effective_scale, effective_scale); gfx::RectF rect_in_pixels = gfx::RectF(bounds_dip); @@ -1989,19 +2004,19 @@ TEST_P(WaylandWindowTest, WaylandPopupInitialBufferScale) { std::unique_ptr<WaylandWindow> wayland_popup = CreateWaylandWindowWithParams(PlatformWindowType::kMenu, - window_->GetWidget(), - wayland_popup_bounds, &delegate_); + window_->GetWidget(), bounds_dip, + &delegate_); EXPECT_TRUE(wayland_popup); wayland_popup->Show(false); - gfx::Rect expected_bounds = wayland_popup_bounds; + gfx::Size expected_px_size = wayland_popup_bounds.size(); if (entered_output.output == secondary_output) { - expected_bounds = - gfx::ScaleToRoundedRect(bounds_dip, secondary_output_scale); + expected_px_size = + gfx::ScaleToCeiledSize(bounds_dip.size(), secondary_output_scale); } - EXPECT_EQ(expected_bounds, wayland_popup->GetBoundsInPixels()) + EXPECT_EQ(expected_px_size, wayland_popup->size_px()) << " when the window is on " << entered_output.label << " that has scale " << entered_output.output->GetScale(); } @@ -2012,18 +2027,12 @@ TEST_P(WaylandWindowTest, WaylandPopupInitialBufferScale) { } } -// Verifies that when the forced scale factor is set, bounds are always the same -// regardless of the scale of the display. -TEST_P(WaylandWindowTest, WaylandPopupInitialBufferScaleForcedScale) { +TEST_P(WaylandWindowTest, WaylandPopupInitialBufferUsesParentScale) { VerifyAndClearExpectations(); - const auto forced_scale = 1.2; - - display::Display::SetForceDeviceScaleFactor(forced_scale); - // Creating an output with scale 1. wl::TestOutput* main_output = server_.CreateAndInitializeOutput(); - main_output->SetRect(gfx::Rect(0, 0, 1920, 1080)); + main_output->SetRect(gfx::Rect(1920, 1080)); main_output->SetScale(1); Sync(); @@ -2041,30 +2050,17 @@ TEST_P(WaylandWindowTest, WaylandPopupInitialBufferScaleForcedScale) { wl_surface_send_enter(surface->resource(), secondary_output->resource()); Sync(); - const gfx::Rect bounds_dip{50, 50, 100, 100}; - const gfx::Rect expected_bounds_px = - gfx::ScaleToRoundedRect(bounds_dip, forced_scale); - - // DesktopWindowTreeHostPlatform has always to use a primary display's - // scale to translate initial bounds to pixels. However, the primary display - // will use forced device scale factor and ignore wl_output's scale. Thus, use - // primary output's scale to make initial bounds. This code snippet is a copy - // of DesktopWindowTreeHostPlatform::ToPixelRect. - gfx::Transform transform; - transform.Scale(display::Display::GetForcedDeviceScaleFactor(), - display::Display::GetForcedDeviceScaleFactor()); - gfx::RectF rect_in_pixels = gfx::RectF(bounds_dip); - transform.TransformRect(&rect_in_pixels); - gfx::Rect wayland_popup_bounds = gfx::ToEnclosingRect(rect_in_pixels); + constexpr gfx::Rect kBoundsDip{50, 50, 100, 100}; + const gfx::Size expected_size_px = + gfx::ScaleToCeiledSize(kBoundsDip.size(), secondary_output->GetScale()); std::unique_ptr<WaylandWindow> wayland_popup = CreateWaylandWindowWithParams( - PlatformWindowType::kMenu, window_->GetWidget(), wayland_popup_bounds, - &delegate_); + PlatformWindowType::kMenu, window_->GetWidget(), kBoundsDip, &delegate_); EXPECT_TRUE(wayland_popup); wayland_popup->Show(false); - EXPECT_EQ(expected_bounds_px, wayland_popup->GetBoundsInPixels()); + EXPECT_EQ(expected_size_px, wayland_popup->size_px()); wl_surface_send_leave(surface->resource(), secondary_output->resource()); Sync(); @@ -2081,7 +2077,7 @@ TEST_P(WaylandWindowTest, GetPreferredOutput) { // Creating an output with scale 1. wl::TestOutput* output1 = server_.CreateAndInitializeOutput(); - output1->SetRect(gfx::Rect(0, 0, 1920, 1080)); + output1->SetRect(gfx::Rect(1920, 1080)); Sync(); // Creating an output with scale 2. @@ -2190,7 +2186,7 @@ TEST_P(WaylandWindowTest, GetChildrenPreferredOutput) { // Creating an output with scale 1. wl::TestOutput* output1 = server_.CreateAndInitializeOutput(); - output1->SetRect(gfx::Rect(0, 0, 1920, 1080)); + output1->SetRect(gfx::Rect(1920, 1080)); Sync(); // Creating an output with scale 2. @@ -2290,7 +2286,7 @@ TEST_P(WaylandWindowTest, PopupPassesDefaultAnchorInformation) { } auto* toplevel_window = window_.get(); - toplevel_window->SetBoundsInPixels(gfx::Rect(0, 0, 739, 574)); + toplevel_window->SetBoundsInDIP(gfx::Rect(739, 574)); // Case 1: properties are not provided. In this case, bounds' origin must // be used as anchor rect and anchor position, gravity and constraints should @@ -2298,7 +2294,7 @@ TEST_P(WaylandWindowTest, PopupPassesDefaultAnchorInformation) { MockWaylandPlatformWindowDelegate menu_window_delegate; EXPECT_CALL(menu_window_delegate, GetMenuType()) .WillOnce(Return(MenuType::kRootMenu)); - EXPECT_CALL(menu_window_delegate, GetOwnedWindowAnchorAndRectInPx()) + EXPECT_CALL(menu_window_delegate, GetOwnedWindowAnchorAndRectInDIP()) .WillOnce(Return(absl::nullopt)); gfx::Rect menu_window_bounds(gfx::Point(439, 46), menu_window_positioner.size); @@ -2316,7 +2312,7 @@ TEST_P(WaylandWindowTest, PopupPassesDefaultAnchorInformation) { Sync(); - EXPECT_EQ(menu_window->GetBoundsInPixels(), menu_window_bounds); + EXPECT_EQ(menu_window->GetBoundsInDIP(), menu_window_bounds); // Case 2: the nested menu window is positioned normally. MockWaylandPlatformWindowDelegate nested_menu_window_delegate; @@ -2368,7 +2364,7 @@ TEST_P(WaylandWindowTest, PopupPassesSetAnchorInformation) { } auto* toplevel_window = window_.get(); - toplevel_window->SetBoundsInPixels(gfx::Rect(0, 0, 508, 212)); + toplevel_window->SetBoundsInDIP(gfx::Rect(508, 212)); MockWaylandPlatformWindowDelegate menu_window_delegate; EXPECT_CALL(menu_window_delegate, GetMenuType()) @@ -2378,7 +2374,7 @@ TEST_P(WaylandWindowTest, PopupPassesSetAnchorInformation) { OwnedWindowAnchorPosition::kBottomRight, OwnedWindowAnchorGravity::kBottomLeft, OwnedWindowConstraintAdjustment::kAdjustmentFlipY}; - EXPECT_CALL(menu_window_delegate, GetOwnedWindowAnchorAndRectInPx()) + EXPECT_CALL(menu_window_delegate, GetOwnedWindowAnchorAndRectInDIP()) .WillOnce(Return(anchor)); gfx::Rect menu_window_bounds(gfx::Point(176, 74), menu_window_positioner.size); @@ -2401,7 +2397,7 @@ TEST_P(WaylandWindowTest, PopupPassesSetAnchorInformation) { OwnedWindowAnchorGravity::kBottomRight, OwnedWindowConstraintAdjustment::kAdjustmentFlipY | OwnedWindowConstraintAdjustment::kAdjustmentFlipX}; - EXPECT_CALL(nested_menu_window_delegate, GetOwnedWindowAnchorAndRectInPx()) + EXPECT_CALL(nested_menu_window_delegate, GetOwnedWindowAnchorAndRectInDIP()) .WillOnce(Return(anchor)); gfx::Rect nested_menu_window_bounds(gfx::Point(492, 157), nested_menu_window_positioner.size); @@ -2426,10 +2422,9 @@ TEST_P(WaylandWindowTest, SetOpaqueRegion) { wl::MockSurface* mock_surface = server_.GetObject<wl::MockSurface>( window_->root_surface()->GetSurfaceId()); - gfx::Rect new_bounds(0, 0, 500, 600); + gfx::Rect new_bounds(500, 600); auto state_array = MakeStateArray({XDG_TOPLEVEL_STATE_ACTIVATED}); - SendConfigureEvent(xdg_surface_, new_bounds.width(), new_bounds.height(), 1, - state_array.get()); + SendConfigureEvent(xdg_surface_, new_bounds.size(), 1, state_array.get()); SkIRect rect = SkIRect::MakeXYWH(0, 0, new_bounds.width(), new_bounds.height()); @@ -2441,8 +2436,7 @@ TEST_P(WaylandWindowTest, SetOpaqueRegion) { 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, - state_array.get()); + SendConfigureEvent(xdg_surface_, new_bounds.size(), 2, state_array.get()); rect = SkIRect::MakeXYWH(0, 0, new_bounds.width(), new_bounds.height()); EXPECT_CALL(*mock_surface, SetOpaqueRegion(_)).WillOnce(VerifyRegion(&rect)); @@ -2491,7 +2485,6 @@ TEST_P(WaylandWindowTest, WaylandPopupSimpleParent) { gfx::Rect(wayland_popup_bounds.size())); wayland_popup->Hide(); - window_->SetPointerFocus(false); } TEST_P(WaylandWindowTest, WaylandPopupNestedParent) { @@ -2504,7 +2497,7 @@ TEST_P(WaylandWindowTest, WaylandPopupNestedParent) { EXPECT_TRUE(menu_window); VerifyAndClearExpectations(); - menu_window->SetPointerFocus(true); + SetPointerFocusedWindow(menu_window.get()); std::vector<PlatformWindowType> window_types{PlatformWindowType::kMenu, PlatformWindowType::kTooltip}; @@ -2533,43 +2526,41 @@ TEST_P(WaylandWindowTest, WaylandPopupNestedParent) { EXPECT_EQ(mock_surface_nested->opaque_region(), gfx::Rect(nested_wayland_popup_bounds.size())); - menu_window->SetPointerFocus(false); + SetPointerFocusedWindow(nullptr); nested_wayland_popup->Hide(); } } // Tests that size constraints returned by the `ui::PlatformWindowDelegate` are // obeyed by the window when its bounds are set internally via its -// SetBoundsInPixels() implementation. +// SetBoundsInDIP() implementation. TEST_P(WaylandWindowTest, SizeConstraintsInternal) { - const gfx::Rect kMinBounds{0, 0, 100, 100}; - const gfx::Rect kMaxBounds{0, 0, 300, 300}; + constexpr gfx::Size kMinSize{100, 100}; + constexpr gfx::Size kMaxSize{300, 300}; - window_->SetBoundsInPixels({0, 0, 200, 200}); + window_->SetBoundsInDIP({0, 0, 200, 200}); Sync(); - auto even_smaller_bounds = kMinBounds; + gfx::Rect even_smaller_bounds(kMinSize); even_smaller_bounds.Inset(10); even_smaller_bounds.set_origin({0, 0}); - EXPECT_CALL(delegate_, GetMinimumSizeForWindow()) - .WillOnce(Return(kMinBounds.size())); - EXPECT_CALL(delegate_, OnBoundsChanged(Eq(kMinBounds))); + EXPECT_CALL(delegate_, GetMinimumSizeForWindow()).WillOnce(Return(kMinSize)); + EXPECT_CALL(delegate_, OnBoundsChanged(Eq(kDefaultBoundsChange))); - window_->SetBoundsInPixels(even_smaller_bounds); + window_->SetBoundsInDIP(even_smaller_bounds); Sync(); VerifyAndClearExpectations(); - auto even_greater_bounds = kMaxBounds; + gfx::Rect even_greater_bounds(kMaxSize); even_greater_bounds.Outset(10); even_greater_bounds.set_origin({0, 0}); - EXPECT_CALL(delegate_, GetMaximumSizeForWindow()) - .WillOnce(Return(kMaxBounds.size())); - EXPECT_CALL(delegate_, OnBoundsChanged(Eq(kMaxBounds))); + EXPECT_CALL(delegate_, GetMaximumSizeForWindow()).WillOnce(Return(kMaxSize)); + EXPECT_CALL(delegate_, OnBoundsChanged(Eq(kDefaultBoundsChange))); - window_->SetBoundsInPixels(even_greater_bounds); + window_->SetBoundsInDIP(even_greater_bounds); Sync(); } @@ -2577,45 +2568,45 @@ TEST_P(WaylandWindowTest, SizeConstraintsInternal) { // obeyed by the window when its bounds are set externally via the configure // event sent by the compositor. TEST_P(WaylandWindowTest, SizeConstraintsExternal) { - const gfx::Rect kMinBounds{0, 0, 100, 100}; - const gfx::Rect kMaxBounds{0, 0, 300, 300}; + constexpr gfx::Size kMinSize{100, 100}; + constexpr gfx::Size kMaxSize{300, 300}; EXPECT_CALL(delegate_, GetMinimumSizeForWindow()) - .WillRepeatedly(Return(kMinBounds.size())); + .WillRepeatedly(Return(kMinSize)); EXPECT_CALL(delegate_, GetMaximumSizeForWindow()) - .WillRepeatedly(Return(kMaxBounds.size())); + .WillRepeatedly(Return(kMaxSize)); - window_->SetBoundsInPixels({0, 0, 200, 200}); + window_->SetBoundsInDIP({0, 0, 200, 200}); Sync(); uint32_t serial = 0; auto state = InitializeWlArrayWithActivatedState(); - auto even_smaller_bounds = kMinBounds; + gfx::Rect even_smaller_bounds(kMinSize); even_smaller_bounds.Inset(10); even_smaller_bounds.set_origin({0, 0}); - EXPECT_CALL(delegate_, OnBoundsChanged(Eq(kMinBounds))); + EXPECT_CALL(delegate_, OnBoundsChanged(Eq(kDefaultBoundsChange))); - SendConfigureEvent(xdg_surface_, even_smaller_bounds.width(), - even_smaller_bounds.height(), ++serial, state.get()); + SendConfigureEvent(xdg_surface_, even_smaller_bounds.size(), ++serial, + state.get()); Sync(); VerifyAndClearExpectations(); EXPECT_CALL(delegate_, GetMinimumSizeForWindow()) - .WillRepeatedly(Return(kMinBounds.size())); + .WillRepeatedly(Return(kMinSize)); EXPECT_CALL(delegate_, GetMaximumSizeForWindow()) - .WillRepeatedly(Return(kMaxBounds.size())); + .WillRepeatedly(Return(kMaxSize)); - auto even_greater_bounds = kMaxBounds; + gfx::Rect even_greater_bounds(kMaxSize); even_greater_bounds.Outset(10); even_greater_bounds.set_origin({0, 0}); - EXPECT_CALL(delegate_, OnBoundsChanged(Eq(kMaxBounds))); + EXPECT_CALL(delegate_, OnBoundsChanged(Eq(kDefaultBoundsChange))); - SendConfigureEvent(xdg_surface_, even_greater_bounds.width(), - even_greater_bounds.height(), ++serial, state.get()); + SendConfigureEvent(xdg_surface_, even_greater_bounds.size(), ++serial, + state.get()); Sync(); } @@ -2649,9 +2640,9 @@ TEST_P(WaylandWindowTest, OnSizeConstraintsChanged) { TEST_P(WaylandWindowTest, DestroysCreatesSurfaceOnHideShow) { MockWaylandPlatformWindowDelegate delegate; - auto window = CreateWaylandWindowWithParams( - PlatformWindowType::kWindow, gfx::kNullAcceleratedWidget, - gfx::Rect(0, 0, 100, 100), &delegate); + auto window = CreateWaylandWindowWithParams(PlatformWindowType::kWindow, + gfx::kNullAcceleratedWidget, + gfx::Rect(100, 100), &delegate); ASSERT_TRUE(window); Sync(); @@ -2681,9 +2672,9 @@ TEST_P(WaylandWindowTest, DestroysCreatesPopupsOnHideShow) { MockWaylandPlatformWindowDelegate delegate; EXPECT_CALL(delegate, GetMenuType()) .WillRepeatedly(Return(MenuType::kRootContextMenu)); - auto window = CreateWaylandWindowWithParams( - PlatformWindowType::kMenu, window_->GetWidget(), gfx::Rect(0, 0, 50, 50), - &delegate); + auto window = CreateWaylandWindowWithParams(PlatformWindowType::kMenu, + window_->GetWidget(), + gfx::Rect(50, 50), &delegate); ASSERT_TRUE(window); Sync(); @@ -2730,9 +2721,9 @@ TEST_P(WaylandWindowTest, ReattachesBackgroundOnShow) { // Create window. MockWaylandPlatformWindowDelegate delegate; - auto window = CreateWaylandWindowWithParams( - PlatformWindowType::kWindow, gfx::kNullAcceleratedWidget, - gfx::Rect(0, 0, 100, 100), &delegate); + auto window = CreateWaylandWindowWithParams(PlatformWindowType::kWindow, + gfx::kNullAcceleratedWidget, + gfx::Rect(100, 100), &delegate); ASSERT_TRUE(window); auto states = InitializeWlArrayWithActivatedState(); @@ -2743,7 +2734,7 @@ TEST_P(WaylandWindowTest, ReattachesBackgroundOnShow) { window->root_surface()->GetSurfaceId()); EXPECT_TRUE(mock_surface->xdg_surface()); EXPECT_TRUE(mock_surface->xdg_surface()->xdg_toplevel()); - SendConfigureEvent(mock_surface->xdg_surface(), 100, 100, 1, states.get()); + SendConfigureEvent(mock_surface->xdg_surface(), {100, 100}, 1, states.get()); // Commit a frame with only background. std::vector<wl::WaylandOverlayConfig> overlays; @@ -2769,7 +2760,7 @@ TEST_P(WaylandWindowTest, ReattachesBackgroundOnShow) { Sync(); - SendConfigureEvent(mock_surface->xdg_surface(), 100, 100, 2, states.get()); + SendConfigureEvent(mock_surface->xdg_surface(), {100, 100}, 2, states.get()); // Expects to receive an attach request on next frame. EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(1); @@ -2796,7 +2787,7 @@ TEST_P(WaylandWindowTest, SetsPropertiesOnShow) { const std::u16string kTitle(u"WaylandWindowTest"); PlatformWindowInitProperties properties; - properties.bounds = gfx::Rect(0, 0, 100, 100); + properties.bounds = gfx::Rect(100, 100); properties.type = PlatformWindowType::kWindow; properties.wm_class_class = kAppId; @@ -2875,16 +2866,22 @@ TEST_P(WaylandWindowTest, CreatesPopupOnButtonPressSerial) { Sync(); - constexpr uint32_t enter_serial = 1; - constexpr uint32_t button_press_serial = 2; - constexpr uint32_t button_release_serial = 3; + constexpr uint32_t keyboard_enter_serial = 1; + constexpr uint32_t pointer_enter_serial = 2; + constexpr uint32_t button_press_serial = 3; + constexpr uint32_t button_release_serial = 4; wl::MockSurface* toplevel_surface = server_.GetObject<wl::MockSurface>( window_->root_surface()->GetSurfaceId()); struct wl_array empty; wl_array_init(&empty); - wl_keyboard_send_enter(server_.seat()->keyboard()->resource(), enter_serial, - toplevel_surface->resource(), &empty); + wl_keyboard_send_enter(server_.seat()->keyboard()->resource(), + keyboard_enter_serial, toplevel_surface->resource(), + &empty); + + wl_pointer_send_enter(server_.seat()->pointer()->resource(), + pointer_enter_serial, toplevel_surface->resource(), + wl_fixed_from_int(0), wl_fixed_from_int(0)); // Send two events - button down and button up. wl_pointer_send_button(server_.seat()->pointer()->resource(), @@ -2899,9 +2896,9 @@ TEST_P(WaylandWindowTest, CreatesPopupOnButtonPressSerial) { MockWaylandPlatformWindowDelegate delegate; EXPECT_CALL(delegate, GetMenuType()) .WillOnce(Return(MenuType::kRootContextMenu)); - auto popup = CreateWaylandWindowWithParams( - PlatformWindowType::kMenu, window_->GetWidget(), - gfx::Rect(0, 0, 50, 50), &delegate); + auto popup = CreateWaylandWindowWithParams(PlatformWindowType::kMenu, + window_->GetWidget(), + gfx::Rect(50, 50), &delegate); ASSERT_TRUE(popup); Sync(); @@ -2966,9 +2963,9 @@ TEST_P(WaylandWindowTest, CreatesPopupOnTouchDownSerial) { MockWaylandPlatformWindowDelegate delegate; EXPECT_CALL(delegate, GetMenuType()) .WillRepeatedly(Return(MenuType::kRootContextMenu)); - auto popup = CreateWaylandWindowWithParams( - PlatformWindowType::kMenu, window_->GetWidget(), - gfx::Rect(0, 0, 50, 50), &delegate); + auto popup = CreateWaylandWindowWithParams(PlatformWindowType::kMenu, + window_->GetWidget(), + gfx::Rect(50, 50), &delegate); ASSERT_TRUE(popup); Sync(); @@ -3065,9 +3062,9 @@ TEST_P(WaylandWindowTest, DoesNotGrabPopupIfNoSeat) { MockWaylandPlatformWindowDelegate delegate; EXPECT_CALL(delegate, GetMenuType()) .WillOnce(Return(MenuType::kRootContextMenu)); - auto popup = CreateWaylandWindowWithParams( - PlatformWindowType::kMenu, window_->GetWidget(), gfx::Rect(0, 0, 50, 50), - &delegate); + auto popup = CreateWaylandWindowWithParams(PlatformWindowType::kMenu, + window_->GetWidget(), + gfx::Rect(50, 50), &delegate); ASSERT_TRUE(popup); Sync(); @@ -3083,7 +3080,7 @@ TEST_P(WaylandWindowTest, DoesNotGrabPopupUnlessParentHasGrab) { WL_SEAT_CAPABILITY_POINTER); Sync(); ASSERT_TRUE(connection_->seat()->pointer()); - window_->SetPointerFocus(true); + SetPointerFocusedWindow(window_.get()); // Emulate a root menu creation with no serial available and ensure // ozone/wayland does not attempt to grab it. @@ -3113,6 +3110,7 @@ TEST_P(WaylandWindowTest, DoesNotGrabPopupUnlessParentHasGrab) { auto* pointer_resource = server_.seat()->pointer()->resource(); wl_pointer_send_enter(pointer_resource, 3u /*serial*/, server_root_menu_surface->resource(), 0, 0); + wl_pointer_send_frame(pointer_resource); wl_pointer_send_button(pointer_resource, 4u /*serial*/, 1, BTN_LEFT, WL_POINTER_BUTTON_STATE_PRESSED); EXPECT_CALL(delegate, DispatchEvent(_)).Times(2); @@ -3136,6 +3134,7 @@ TEST_P(WaylandWindowTest, DoesNotGrabPopupUnlessParentHasGrab) { wl_pointer_send_leave(pointer_resource, 5u /*serial*/, server_root_menu_surface->resource()); + wl_pointer_send_frame(pointer_resource); Sync(); } @@ -3143,10 +3142,10 @@ TEST_P(WaylandWindowTest, InitialBounds) { testing::NiceMock<MockWaylandPlatformWindowDelegate> delegate_2; auto toplevel = CreateWaylandWindowWithParams( PlatformWindowType::kWindow, 0, gfx::Rect(10, 10, 200, 200), &delegate_2); - toplevel->HandleAuraToplevelConfigure(20, 20, 0, 0, false, false, true); + toplevel->HandleAuraToplevelConfigure(0, 0, 0, 0, false, false, true); toplevel->HandleSurfaceConfigure(2); static_cast<WaylandToplevelWindow*>(toplevel.get())->ApplyPendingBounds(); - EXPECT_EQ(gfx::Rect(20, 20, 200, 200), toplevel->GetBoundsInDIP()); + EXPECT_EQ(gfx::Rect(10, 10, 200, 200), toplevel->GetBoundsInDIP()); } namespace { @@ -3164,7 +3163,7 @@ class WaylandSubsurfaceTest : public WaylandWindowTest { std::unique_ptr<WaylandWindow> window = CreateWaylandWindowWithParams( PlatformWindowType::kWindow, gfx::kNullAcceleratedWidget, - gfx::Rect(0, 0, 640, 480), &delegate_); + gfx::Rect(640, 480), &delegate_); EXPECT_TRUE(window); bool result = window->RequestSubsurface(); @@ -3419,11 +3418,11 @@ TEST_P(WaylandWindowTest, RepositionPopups) { VerifyAndClearExpectations(); - const gfx::Rect damage_rect = {0, 0, menu_window_bounds.width(), - menu_window_bounds.height()}; + const gfx::Rect damage_rect{menu_window_bounds.width(), + menu_window_bounds.height()}; EXPECT_CALL(delegate_, OnDamageRect(Eq(damage_rect))).Times(1); menu_window_bounds.set_origin({10, 10}); - menu_window->SetBoundsInPixels(menu_window_bounds); + menu_window->SetBoundsInDIP(menu_window_bounds); Sync(); @@ -3440,7 +3439,7 @@ TEST_P(WaylandWindowTest, RepositionPopups) { // This will send a configure event for the xdg_surface that backs the // xdg_popup. Size and state are not used there. - SendConfigureEvent(mock_surface_popup->xdg_surface(), 0, 0, 1, nullptr); + SendConfigureEvent(mock_surface_popup->xdg_surface(), {0, 0}, 1, nullptr); // Call sync so that server's configuration event is received by // Ozone/Wayland. @@ -3463,7 +3462,7 @@ TEST_P(WaylandWindowTest, StartWithMinimized) { EXPECT_EQ(PlatformWindowState::kNormal, window_->GetPlatformWindowState()); ScopedWlArray states = InitializeWlArrayWithActivatedState(); - SendConfigureEvent(xdg_surface_, 0, 0, 1, states.get()); + SendConfigureEvent(xdg_surface_, {0, 0}, 1, states.get()); Sync(); EXPECT_CALL(delegate_, OnWindowStateChanged(_, _)).Times(1); @@ -3483,12 +3482,12 @@ TEST_P(WaylandWindowTest, StartWithMinimized) { }))); // The window geometry has to be set to the current bounds of the window for // minimized state. - gfx::Rect bounds = window_->GetBoundsInPixels(); - EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, bounds.width(), bounds.height())); + gfx::Rect bounds = window_->GetBoundsInDIP(); + EXPECT_CALL(*xdg_surface_, SetWindowGeometry(gfx::Rect(bounds.size()))); // Send one additional empty configuration event for minimized state. // (which means the surface is not maximized, fullscreen or activated) states = ScopedWlArray(); - SendConfigureEvent(xdg_surface_, 0, 0, 2, states.get()); + SendConfigureEvent(xdg_surface_, {0, 0}, 2, states.get()); Sync(); } @@ -3499,14 +3498,13 @@ class BlockableWaylandToplevelWindow : public WaylandToplevelWindow { : WaylandToplevelWindow(delegate, connection) {} static std::unique_ptr<BlockableWaylandToplevelWindow> Create( - const gfx::Rect bounds, + const gfx::Rect& bounds, WaylandConnection* connection, MockWaylandPlatformWindowDelegate* delegate) { auto window = std::make_unique<BlockableWaylandToplevelWindow>(delegate, connection); - window->set_update_visual_size_immediately(/*update_immediately=*/true); - window->set_apply_pending_state_on_update_visual_size( - /*apply_immediately=*/true); + window->set_update_visual_size_immediately_for_testing(true); + window->set_apply_pending_state_on_update_visual_size_for_testing(true); PlatformWindowInitProperties properties; properties.bounds = bounds; @@ -3557,7 +3555,7 @@ TEST_P(WaylandWindowTest, DISABLED_BlockingTouchDownUp_NoCrash) { MockWaylandPlatformWindowDelegate delegate; auto window = BlockableWaylandToplevelWindow::Create( - gfx::Rect(0, 0, 800, 600), connection_.get(), &delegate); + gfx::Rect(800, 600), connection_.get(), &delegate); wl_seat_send_capabilities( server_.seat()->resource(), @@ -3600,6 +3598,117 @@ TEST_P(WaylandWindowTest, DISABLED_BlockingTouchDownUp_NoCrash) { Sync(); } +// Make sure that changing focus during dispatch will not re-dispatch the event +// to the newly focused window. (crbug.com/1339082); +// Flaky on device/VM: https://crbug.com/1348046 +#if BUILDFLAG(IS_CHROMEOS_DEVICE) +#define MAYBE_ChangeFocusDuringDispatch DISABLED_ChangeFocusDuringDispatch +#else +#define MAYBE_ChangeFocusDuringDispatch ChangeFocusDuringDispatch +#endif +TEST_P(WaylandWindowTest, MAYBE_ChangeFocusDuringDispatch) { + MockPlatformWindowDelegate other_delegate; + gfx::AcceleratedWidget other_widget = gfx::kNullAcceleratedWidget; + EXPECT_CALL(other_delegate, OnAcceleratedWidgetAvailable(_)) + .WillOnce(SaveArg<0>(&other_widget)); + + PlatformWindowInitProperties properties; + properties.bounds = gfx::Rect(10, 10); + properties.type = PlatformWindowType::kWindow; + auto other_window = WaylandWindow::Create(&other_delegate, connection_.get(), + std::move(properties)); + ASSERT_NE(other_widget, gfx::kNullAcceleratedWidget); + + wl_seat_send_capabilities(server_.seat()->resource(), + WL_SEAT_CAPABILITY_POINTER); + Sync(); + + wl::MockSurface* other_surface = server_.GetObject<wl::MockSurface>( + other_window->root_surface()->GetSurfaceId()); + ASSERT_TRUE(other_surface); + auto* pointer = server_.seat()->pointer(); + + wl_pointer_send_enter(pointer->resource(), 1, surface_->resource(), 0, 0); + // The Enter event is coupled with the frame event. + wl_pointer_send_frame(pointer->resource()); + wl_pointer_send_button(pointer->resource(), 2, 1004, BTN_LEFT, + WL_POINTER_BUTTON_STATE_PRESSED); + + int count = 0; + EXPECT_CALL(delegate_, DispatchEvent(_)).WillRepeatedly([&](Event* event) { + count++; + if (event->type() == ui::ET_MOUSE_PRESSED) { + wl_pointer_send_leave(pointer->resource(), 3, surface_->resource()); + wl_pointer_send_enter(pointer->resource(), 4, other_surface->resource(), + 0, 0); + wl_pointer_send_frame(pointer->resource()); + Sync(); + } + }); + EXPECT_CALL(other_delegate, DispatchEvent(_)).Times(1); + + Sync(); + EXPECT_EQ(count, 3); +} + +TEST_P(WaylandWindowTest, WindowMovedResized) { + const gfx::Rect initial_bounds = window_->GetBoundsInDIP(); + + gfx::Rect new_bounds(initial_bounds); + new_bounds.set_x(new_bounds.origin().x() + 10); + new_bounds.set_y(new_bounds.origin().y() + 10); + // Configure is not necessary to just move. + EXPECT_CALL(delegate_, OnBoundsChanged(BoundsChange(true))); + EXPECT_CALL(*xdg_surface_, SetWindowGeometry(gfx::Rect(new_bounds.size()))) + .Times(0); + window_->SetBoundsInDIP(new_bounds); + + // Resize and move. + new_bounds.Inset(5); + EXPECT_CALL(delegate_, OnBoundsChanged(Eq(BoundsChange(true)))).Times(1); + EXPECT_CALL(*xdg_surface_, SetWindowGeometry(gfx::Rect(new_bounds.size()))) + .Times(0); + window_->SetBoundsInDIP(new_bounds); + + // Xdg configure event will reset the origin. + EXPECT_CALL(delegate_, OnBoundsChanged(Eq(BoundsChange(true)))).Times(1); + EXPECT_CALL(*xdg_surface_, SetWindowGeometry(gfx::Rect(new_bounds.size()))) + .Times(1); + ScopedWlArray states = InitializeWlArrayWithActivatedState(); + SendConfigureEvent(xdg_surface_, new_bounds.size(), 1, states.get()); + Sync(); +} + +// Make sure that creating a window with DIP bounds creates a window with +// the same DIP bounds with various fractional scales. +TEST_P(WaylandWindowTest, NoRoundingErrorInDIP) { + VerifyAndClearExpectations(); + auto* primary_output = + connection_->wayland_output_manager()->GetPrimaryOutput(); + constexpr float kScales[] = {display::kDsf_1_777, display::kDsf_2_252, + display::kDsf_2_666, display::kDsf_1_8}; + for (float scale : kScales) { + primary_output->SetScaleFactorForTesting(scale); + // Update to delegate to use the correct scale; + window_->UpdateWindowScale(true); + + testing::NiceMock<MockWaylandPlatformWindowDelegate> delegate; + std::unique_ptr<WaylandWindow> wayland_window = + CreateWaylandWindowWithParams(PlatformWindowType::kWindow, + gfx::kNullAcceleratedWidget, + gfx::Rect(20, 0, 100, 100), &delegate); + for (int i = 100; i < 3000; i++) { + const gfx::Rect kBoundsDip{20, 0, i, 3000 - i}; + const gfx::Rect bounds_in_px = delegate_.ConvertRectToPixels(kBoundsDip); + wayland_window->SetBoundsInDIP(kBoundsDip); + EXPECT_EQ(bounds_in_px.size(), wayland_window->size_px()); + EXPECT_EQ(kBoundsDip, wayland_window->GetBoundsInDIP()); + Sync(); + } + } + VerifyAndClearExpectations(); +} + INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest, WaylandWindowTest, Values(wl::ServerConfig{ diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_zaura_output_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_zaura_output_unittest.cc index a29d9c68e10..9873d164022 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_zaura_output_unittest.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_zaura_output_unittest.cc @@ -8,6 +8,7 @@ #include <aura-shell-server-protocol.h> #include <wayland-server-protocol.h> +#include "base/memory/raw_ptr.h" #include "base/run_loop.h" #include "base/test/task_environment.h" #include "testing/gtest/include/gtest/gtest.h" @@ -71,7 +72,7 @@ class WaylandZAuraOutputTest : public ::testing::Test { wl::MockZAuraShell mock_zaura_shell_; WaylandConnection connection_; - WaylandOutputManager* output_manager_ = nullptr; + raw_ptr<WaylandOutputManager> output_manager_ = nullptr; std::unique_ptr<WaylandScreen> platform_screen_; }; 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 6c8b645452b..b6d3e3543dd 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_zaura_shell.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_zaura_shell.cc @@ -20,7 +20,7 @@ namespace ui { namespace { constexpr uint32_t kMinVersion = 1; -constexpr uint32_t kMaxVersion = 34; +constexpr uint32_t kMaxVersion = 40; } // static @@ -100,7 +100,7 @@ void WaylandZAuraShell::OnLayoutMode(void* data, struct zaura_shell* zaura_shell, uint32_t layout_mode) { auto* self = static_cast<WaylandZAuraShell*>(data); - auto* connection = self->connection_; + auto* connection = self->connection_.get(); auto* screen = connection->wayland_output_manager()->wayland_screen(); // |screen| is null in some unit test suites. if (!screen) 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 56b7e9c4979..496e964e2b5 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_zaura_shell.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_zaura_shell.h @@ -6,6 +6,7 @@ #define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_ZAURA_SHELL_H_ #include "base/containers/flat_set.h" +#include "base/memory/raw_ptr.h" #include "ui/ozone/platform/wayland/common/wayland_object.h" namespace ui { @@ -58,7 +59,7 @@ class WaylandZAuraShell : public wl::GlobalObjectRegistrar<WaylandZAuraShell> { struct wl_surface* lost_active); wl::Object<zaura_shell> obj_; - WaylandConnection* const connection_; + const raw_ptr<WaylandConnection> connection_; base::flat_set<uint32_t> bug_fix_ids_; std::vector<std::string> desks_; int active_desk_index_ = 0; 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 index 676086acd83..93e77bd746f 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_zaura_shell_unittest.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_zaura_shell_unittest.cc @@ -22,8 +22,7 @@ TEST(WaylandZAuraShellTest, BugFix) { base::test::SingleThreadTaskEnvironment::MainThreadType::UI); wl::TestWaylandServerThread server; ASSERT_TRUE(server.Start({.shell_version = wl::ShellVersion::kStable})); - wl::MockZAuraShell zaura_shell_obj; - zaura_shell_obj.Initialize(server.display()); + wl::MockZAuraShell* zaura_shell = server.zaura_shell(); WaylandConnection connection; ASSERT_TRUE(connection.Initialize()); @@ -32,8 +31,9 @@ TEST(WaylandZAuraShellTest, BugFix) { 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); + ASSERT_TRUE(server.zaura_shell()->resource()); + zaura_shell_send_bug_fix(zaura_shell->resource(), 1); + zaura_shell_send_bug_fix(zaura_shell->resource(), 3); server.Resume(); base::RunLoop().RunUntilIdle(); diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_zcr_color_management_output.cc b/chromium/ui/ozone/platform/wayland/host/wayland_zcr_color_management_output.cc new file mode 100644 index 00000000000..687618dfbb3 --- /dev/null +++ b/chromium/ui/ozone/platform/wayland/host/wayland_zcr_color_management_output.cc @@ -0,0 +1,64 @@ +// Copyright 2022 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_zcr_color_management_output.h" + +#include <chrome-color-management-client-protocol.h> +#include <memory> + +#include "base/notreached.h" +#include "ui/ozone/platform/wayland/host/wayland_connection.h" +#include "ui/ozone/platform/wayland/host/wayland_output.h" + +namespace ui { + +WaylandZcrColorManagementOutput::WaylandZcrColorManagementOutput( + zcr_color_management_output_v1* color_management_output) + : zcr_color_management_output_(color_management_output) { + DCHECK(color_management_output); + static const zcr_color_management_output_v1_listener listener = { + &WaylandZcrColorManagementOutput::OnColorSpaceChanged, + &WaylandZcrColorManagementOutput::OnExtendedDynamicRange, + }; + + zcr_color_management_output_v1_add_listener( + zcr_color_management_output_.get(), &listener, this); +} + +WaylandZcrColorManagementOutput::~WaylandZcrColorManagementOutput() = default; + +// static +void WaylandZcrColorManagementOutput::OnColorSpaceChanged( + void* data, + struct zcr_color_management_output_v1* cmo) { + WaylandZcrColorManagementOutput* zcr_color_management_output = + static_cast<WaylandZcrColorManagementOutput*>(data); + DCHECK(zcr_color_management_output); + + // request new color space + zcr_color_management_output->color_space_ = + std::make_unique<WaylandZcrColorSpace>( + zcr_color_management_output_v1_get_color_space( + zcr_color_management_output->zcr_color_management_output_.get())); + + zcr_color_management_output->color_space_->SetColorSpaceDoneCallback( + base::BindOnce(&WaylandZcrColorManagementOutput::OnColorSpaceDone, + zcr_color_management_output->weak_factory_.GetWeakPtr())); +} + +// static +void WaylandZcrColorManagementOutput::OnColorSpaceDone( + const gfx::ColorSpace& color_space) { + gfx_color_space_ = std::make_unique<gfx::ColorSpace>(color_space); +} + +// static +void WaylandZcrColorManagementOutput::OnExtendedDynamicRange( + void* data, + struct zcr_color_management_output_v1* cmo, + uint32_t value) { + NOTIMPLEMENTED_LOG_ONCE(); +} + +} // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_zcr_color_management_output.h b/chromium/ui/ozone/platform/wayland/host/wayland_zcr_color_management_output.h new file mode 100644 index 00000000000..c9cc767ff9a --- /dev/null +++ b/chromium/ui/ozone/platform/wayland/host/wayland_zcr_color_management_output.h @@ -0,0 +1,47 @@ +// Copyright 2022 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_ZCR_COLOR_MANAGEMENT_OUTPUT_H_ +#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_ZCR_COLOR_MANAGEMENT_OUTPUT_H_ + +#include "base/memory/weak_ptr.h" +#include "ui/gfx/color_space.h" +#include "ui/ozone/platform/wayland/host/wayland_zcr_color_space.h" + +namespace ui { + +// WaylandZcrColorManagementOutput tracks the color space of its associated +// Wayland Output. +class WaylandZcrColorManagementOutput { + public: + explicit WaylandZcrColorManagementOutput( + struct zcr_color_management_output_v1* management_output); + WaylandZcrColorManagementOutput(const WaylandZcrColorManagementOutput&) = + delete; + WaylandZcrColorManagementOutput& operator=( + const WaylandZcrColorManagementOutput&) = delete; + ~WaylandZcrColorManagementOutput(); + + gfx::ColorSpace* gfx_color_space() const { return gfx_color_space_.get(); } + WaylandZcrColorSpace* color_space() const { return color_space_.get(); } + + private: + // zcr_color_management_output_v1_listener + static void OnColorSpaceChanged(void* data, + struct zcr_color_management_output_v1* cmo); + static void OnExtendedDynamicRange(void* data, + struct zcr_color_management_output_v1* cmo, + uint32_t value); + + void OnColorSpaceDone(const gfx::ColorSpace& color_space); + + wl::Object<zcr_color_management_output_v1> zcr_color_management_output_; + std::unique_ptr<gfx::ColorSpace> gfx_color_space_; + std::unique_ptr<WaylandZcrColorSpace> color_space_; + base::WeakPtrFactory<WaylandZcrColorManagementOutput> weak_factory_{this}; +}; + +} // namespace ui + +#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_ZCR_COLOR_MANAGEMENT_OUTPUT_H_ diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_zcr_color_management_surface.cc b/chromium/ui/ozone/platform/wayland/host/wayland_zcr_color_management_surface.cc new file mode 100644 index 00000000000..b757fe7a3b3 --- /dev/null +++ b/chromium/ui/ozone/platform/wayland/host/wayland_zcr_color_management_surface.cc @@ -0,0 +1,48 @@ +// Copyright 2022 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_zcr_color_management_surface.h" + +#include <chrome-color-management-client-protocol.h> +#include <memory> + +#include "base/notreached.h" +#include "ui/ozone/platform/wayland/host/wayland_connection.h" + +namespace ui { + +WaylandZcrColorManagementSurface::WaylandZcrColorManagementSurface( + zcr_color_management_surface_v1* color_management_surface, + WaylandConnection* connection) + : zcr_color_management_surface_(color_management_surface), + connection_(connection) { + DCHECK(color_management_surface); + static const zcr_color_management_surface_v1_listener listener = { + &WaylandZcrColorManagementSurface::OnPreferredColorSpace, + }; + + zcr_color_management_surface_v1_add_listener( + zcr_color_management_surface_.get(), &listener, this); +} + +WaylandZcrColorManagementSurface::~WaylandZcrColorManagementSurface() = default; + +void WaylandZcrColorManagementSurface::SetDefaultColorSpace() { + NOTIMPLEMENTED_LOG_ONCE(); +} + +void WaylandZcrColorManagementSurface::SetColorSpace( + gfx::ColorSpace color_space) { + NOTIMPLEMENTED_LOG_ONCE(); +} + +// static +void WaylandZcrColorManagementSurface::OnPreferredColorSpace( + void* data, + struct zcr_color_management_surface_v1* cms, + struct wl_output* output) { + NOTIMPLEMENTED_LOG_ONCE(); +} + +} // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_zcr_color_management_surface.h b/chromium/ui/ozone/platform/wayland/host/wayland_zcr_color_management_surface.h new file mode 100644 index 00000000000..958df8a41bd --- /dev/null +++ b/chromium/ui/ozone/platform/wayland/host/wayland_zcr_color_management_surface.h @@ -0,0 +1,43 @@ +// Copyright 2022 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_ZCR_COLOR_MANAGEMENT_SURFACE_H_ +#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_ZCR_COLOR_MANAGEMENT_SURFACE_H_ + +#include "ui/gfx/color_space.h" +#include "ui/ozone/platform/wayland/host/wayland_zcr_color_space.h" + +namespace ui { + +class WaylandConnection; + +// TODO(b/237094484): merge into wayland_surface.h along with +// color_space_creator zcr_color_mangement_surface_v1 +class WaylandZcrColorManagementSurface { + public: + explicit WaylandZcrColorManagementSurface( + struct zcr_color_management_surface_v1* management_surface, + WaylandConnection* connection); + WaylandZcrColorManagementSurface(const WaylandZcrColorManagementSurface&) = + delete; + WaylandZcrColorManagementSurface& operator=( + const WaylandZcrColorManagementSurface&) = delete; + ~WaylandZcrColorManagementSurface(); + + void SetDefaultColorSpace(); + void SetColorSpace(gfx::ColorSpace color_space); + + private: + // zcr_color_management_surface_v1_listener + static void OnPreferredColorSpace(void* data, + struct zcr_color_management_surface_v1* cms, + struct wl_output* output); + + wl::Object<zcr_color_management_surface_v1> zcr_color_management_surface_; + const raw_ptr<WaylandConnection> connection_; +}; + +} // namespace ui + +#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_ZCR_COLOR_MANAGEMENT_SURFACE_H_ diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_zcr_color_manager.cc b/chromium/ui/ozone/platform/wayland/host/wayland_zcr_color_manager.cc new file mode 100644 index 00000000000..c3ff81d7a4a --- /dev/null +++ b/chromium/ui/ozone/platform/wayland/host/wayland_zcr_color_manager.cc @@ -0,0 +1,60 @@ +// Copyright 2022 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_zcr_color_manager.h" + +#include <chrome-color-management-client-protocol.h> + +#include "base/logging.h" +#include "ui/ozone/platform/wayland/host/wayland_connection.h" +#include "ui/ozone/platform/wayland/host/wayland_output_manager.h" + +namespace ui { + +namespace { +constexpr uint32_t kMinVersion = 1; +constexpr uint32_t kMaxVersion = 1; +} // namespace + +// static +constexpr char WaylandZcrColorManager::kInterfaceName[]; + +// static +void WaylandZcrColorManager::Instantiate(WaylandConnection* connection, + wl_registry* registry, + uint32_t name, + const std::string& interface, + uint32_t version) { + DCHECK_EQ(interface, kInterfaceName); + + if (connection->zcr_color_manager_) + return; + + auto color_manager = wl::Bind<struct zcr_color_manager_v1>( + registry, name, std::min(kMinVersion, kMaxVersion)); + if (!color_manager) { + LOG(ERROR) << "Failed to bind zcr_color_manager_v1"; + return; + } + connection->zcr_color_manager_ = std::make_unique<WaylandZcrColorManager>( + color_manager.release(), connection); + if (connection->wayland_output_manager()) + connection->wayland_output_manager()->InitializeAllColorManagementOutputs(); +} + +WaylandZcrColorManager::WaylandZcrColorManager( + zcr_color_manager_v1* zcr_color_manager, + WaylandConnection* connection) + : zcr_color_manager_(zcr_color_manager), connection_(connection) {} + +WaylandZcrColorManager::~WaylandZcrColorManager() = default; + +wl::Object<zcr_color_management_output_v1> +WaylandZcrColorManager::CreateColorManagementOutput(wl_output* output) { + return wl::Object<zcr_color_management_output_v1>( + zcr_color_manager_v1_get_color_management_output(zcr_color_manager_.get(), + output)); +} + +} // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_zcr_color_manager.h b/chromium/ui/ozone/platform/wayland/host/wayland_zcr_color_manager.h new file mode 100644 index 00000000000..56907a84f19 --- /dev/null +++ b/chromium/ui/ozone/platform/wayland/host/wayland_zcr_color_manager.h @@ -0,0 +1,52 @@ +// Copyright 2022 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_ZCR_COLOR_MANAGER_H_ +#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_ZCR_COLOR_MANAGER_H_ + +#include "base/memory/raw_ptr.h" +#include "third_party/abseil-cpp/absl/types/optional.h" +#include "ui/ozone/platform/wayland/common/wayland_object.h" +#include "ui/ozone/platform/wayland/common/wayland_util.h" + +struct zcr_color_manager_v1; + +namespace ui { + +class WaylandConnection; + +// Wrapper around |zcr_color_manager_v1| Wayland factory +class WaylandZcrColorManager + : public wl::GlobalObjectRegistrar<WaylandZcrColorManager> { + public: + static constexpr char kInterfaceName[] = "zcr_color_manager_v1"; + + static void Instantiate(WaylandConnection* connection, + wl_registry* registry, + uint32_t name, + const std::string& interface, + uint32_t version); + + WaylandZcrColorManager(zcr_color_manager_v1* zcr_color_manager_, + WaylandConnection* connection); + + WaylandZcrColorManager(const WaylandZcrColorManager&) = delete; + WaylandZcrColorManager& operator=(const WaylandZcrColorManager&) = delete; + + ~WaylandZcrColorManager(); + + wl::Object<zcr_color_management_output_v1> CreateColorManagementOutput( + wl_output* output); + + private: + // Holds pointer to the zcr_color_manager_v1 Wayland factory. + const wl::Object<zcr_color_manager_v1> zcr_color_manager_; + + // Non-owned. + const raw_ptr<WaylandConnection> connection_; +}; + +} // namespace ui + +#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_ZCR_COLOR_MANAGER_H_ diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_zcr_color_space.cc b/chromium/ui/ozone/platform/wayland/host/wayland_zcr_color_space.cc new file mode 100644 index 00000000000..08aa952a384 --- /dev/null +++ b/chromium/ui/ozone/platform/wayland/host/wayland_zcr_color_space.cc @@ -0,0 +1,128 @@ +// Copyright 2022 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_zcr_color_space.h" + +#include <chrome-color-management-client-protocol.h> +#include <cstdint> + +#include "base/logging.h" +#include "base/notreached.h" +#include "base/strings/stringprintf.h" +#include "third_party/skia/include/core/SkColorSpace.h" +#include "ui/base/wayland/color_manager_util.h" +#include "ui/gfx/color_space.h" +#include "ui/ozone/platform/wayland/host/wayland_connection.h" +#include "ui/ozone/platform/wayland/wayland_utils.h" + +namespace ui { + +WaylandZcrColorSpace::WaylandZcrColorSpace( + struct zcr_color_space_v1* color_space) + : zcr_color_space_(color_space) { + DCHECK(color_space); + static const zcr_color_space_v1_listener listener = { + &WaylandZcrColorSpace::OnIccFile, + &WaylandZcrColorSpace::OnNames, + &WaylandZcrColorSpace::OnParams, + &WaylandZcrColorSpace::OnDone, + }; + + zcr_color_space_v1_add_listener(zcr_color_space_.get(), &listener, this); + zcr_color_space_v1_get_information(zcr_color_space_.get()); +} + +WaylandZcrColorSpace::~WaylandZcrColorSpace() = default; + +// static +void WaylandZcrColorSpace::OnIccFile(void* data, + struct zcr_color_space_v1* cs, + int32_t icc, + uint32_t icc_size) { + WaylandZcrColorSpace* zcr_color_space = + static_cast<WaylandZcrColorSpace*>(data); + DCHECK(zcr_color_space); + // TODO(b/192562912): construct a color space from an icc file. +} + +// static +void WaylandZcrColorSpace::OnNames(void* data, + struct zcr_color_space_v1* cs, + uint32_t eotf, + uint32_t chromaticity, + uint32_t whitepoint) { + WaylandZcrColorSpace* zcr_color_space = + static_cast<WaylandZcrColorSpace*>(data); + DCHECK(zcr_color_space); + auto primaryID = ui::wayland::kChromaticityMap.contains(chromaticity) + ? ui::wayland::kChromaticityMap.at(chromaticity) + : gfx::ColorSpace::PrimaryID::INVALID; + auto transferID = ui::wayland::kEotfMap.contains(eotf) + ? ui::wayland::kEotfMap.at(eotf) + : gfx::ColorSpace::TransferID::INVALID; + zcr_color_space + ->gathered_information[static_cast<uint8_t>(InformationType::kNames)] = + gfx::ColorSpace(primaryID, transferID, gfx::ColorSpace::MatrixID::RGB, + gfx::ColorSpace::RangeID::FULL); +} + +// static +void WaylandZcrColorSpace::OnParams(void* data, + struct zcr_color_space_v1* cs, + uint32_t eotf, + uint32_t primary_r_x, + uint32_t primary_r_y, + uint32_t primary_g_x, + uint32_t primary_g_y, + uint32_t primary_b_x, + uint32_t primary_b_y, + uint32_t whitepoint_x, + uint32_t whitepoint_y) { + WaylandZcrColorSpace* zcr_color_space = + static_cast<WaylandZcrColorSpace*>(data); + DCHECK(zcr_color_space); + auto transferID = ui::wayland::kEotfMap.contains(eotf) + ? ui::wayland::kEotfMap.at(eotf) + : gfx::ColorSpace::TransferID::INVALID; + SkColorSpacePrimaries primaries = { + PARAM_TO_FLOAT(primary_r_x), PARAM_TO_FLOAT(primary_r_y), + PARAM_TO_FLOAT(primary_g_x), PARAM_TO_FLOAT(primary_g_y), + PARAM_TO_FLOAT(primary_b_x), PARAM_TO_FLOAT(primary_b_y), + PARAM_TO_FLOAT(whitepoint_x), PARAM_TO_FLOAT(whitepoint_y)}; + + skcms_Matrix3x3 xyzd50 = {}; + if (!primaries.toXYZD50(&xyzd50)) { + DLOG(ERROR) << base::StringPrintf( + "Unable to translate color space primaries to XYZD50: " + "{%f, %f, %f, %f, %f, %f, %f, %f}", + primaries.fRX, primaries.fRY, primaries.fGX, primaries.fGY, + primaries.fBX, primaries.fBY, primaries.fWX, primaries.fWY); + return; + } + zcr_color_space + ->gathered_information[static_cast<uint8_t>(InformationType::kParams)] = + gfx::ColorSpace::CreateCustom(xyzd50, transferID); +} + +gfx::ColorSpace WaylandZcrColorSpace::GetPriorityInformationType() { + for (auto maybe_colorspace : gathered_information) { + if (maybe_colorspace.has_value()) + return maybe_colorspace.value(); + } + DLOG(ERROR) << "No color space information gathered"; + return gfx::ColorSpace::CreateSRGB(); +} + +// static +void WaylandZcrColorSpace::OnDone(void* data, struct zcr_color_space_v1* cs) { + WaylandZcrColorSpace* zcr_color_space = + static_cast<WaylandZcrColorSpace*>(data); + DCHECK(zcr_color_space); + if (zcr_color_space->HasColorSpaceDoneCallback()) + std::move(zcr_color_space->color_space_done_callback_) + .Run(zcr_color_space->GetPriorityInformationType()); + zcr_color_space->gathered_information.fill({}); +} + +} // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_zcr_color_space.h b/chromium/ui/ozone/platform/wayland/host/wayland_zcr_color_space.h new file mode 100644 index 00000000000..ed8381d5307 --- /dev/null +++ b/chromium/ui/ozone/platform/wayland/host/wayland_zcr_color_space.h @@ -0,0 +1,85 @@ +// Copyright 2022 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_ZCR_COLOR_SPACE_H_ +#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_ZCR_COLOR_SPACE_H_ + +#include <array> +#include <memory> +#include <utility> + +#include "base/callback.h" +#include "ui/gfx/color_space.h" +#include "ui/ozone/platform/wayland/common/wayland_object.h" + +namespace ui { + +// ZcrColorSpace is used to send color space information over wayland protocol. +// its requests and events are specified in chrome-color-management.xml. +// The ui::gfx::ColorSpace equivalent of ZcrColorSpace can be gotten with +// gfx_color_space(). +class WaylandZcrColorSpace { + public: + using WaylandZcrColorSpaceDoneCallback = + base::OnceCallback<void(const gfx::ColorSpace&)>; + explicit WaylandZcrColorSpace(zcr_color_space_v1* color_space); + WaylandZcrColorSpace(const WaylandZcrColorSpace&) = delete; + WaylandZcrColorSpace& operator=(const WaylandZcrColorSpace&) = delete; + ~WaylandZcrColorSpace(); + + zcr_color_space_v1* zcr_color_space() const { return zcr_color_space_.get(); } + bool HasColorSpaceDoneCallback() const { + return !color_space_done_callback_.is_null(); + } + void SetColorSpaceDoneCallback(WaylandZcrColorSpaceDoneCallback callback) { + color_space_done_callback_ = std::move(callback); + } + + private: + // InformationType is an enumeration of the possible events following a + // get_information request in order of their priority (0 is highest). + enum class InformationType : uint8_t { + kNames = 0, + kIccFile = 1, + kParams = 2, + kMaxValue = kParams, + }; + + gfx::ColorSpace GetPriorityInformationType(); + // zcr_color_space_v1_listener + static void OnIccFile(void* data, + struct zcr_color_space_v1* cs, + int32_t icc, + uint32_t icc_size); + static void OnNames(void* data, + struct zcr_color_space_v1* cs, + uint32_t eotf, + uint32_t chromaticity, + uint32_t whitepoint); + static void OnDone(void* data, struct zcr_color_space_v1* cs); + static void OnParams(void* data, + struct zcr_color_space_v1* cs, + uint32_t eotf, + uint32_t primary_r_x, + uint32_t primary_r_y, + uint32_t primary_g_x, + uint32_t primary_g_y, + uint32_t primary_b_x, + uint32_t primary_b_y, + uint32_t whitepoint_x, + uint32_t whitepoint_y); + + // Information events should store color space info at their enum index in + // this array. Cleared on the OnDone event. Choosing the highest priority + // InformationType available is simple with forward iteration. + std::array<absl::optional<gfx::ColorSpace>, + static_cast<uint8_t>(InformationType::kMaxValue) + 1> + gathered_information; + wl::Object<zcr_color_space_v1> zcr_color_space_; + WaylandZcrColorSpaceDoneCallback color_space_done_callback_; +}; + +} // namespace ui + +#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_ZCR_COLOR_SPACE_H_ diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_zcr_color_space_creator.cc b/chromium/ui/ozone/platform/wayland/host/wayland_zcr_color_space_creator.cc new file mode 100644 index 00000000000..b0467cb69c2 --- /dev/null +++ b/chromium/ui/ozone/platform/wayland/host/wayland_zcr_color_space_creator.cc @@ -0,0 +1,48 @@ +// Copyright 2022 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_zcr_color_space_creator.h" + +#include <chrome-color-management-client-protocol.h> +#include <memory> + +#include "base/check.h" +#include "base/notreached.h" + +namespace ui { + +WaylandZcrColorSpaceCreator::WaylandZcrColorSpaceCreator( + struct zcr_color_space_creator_v1* color_space_creator, + struct zcr_color_management_surface_v1* management_surface) + : zcr_color_space_creator_(color_space_creator), + zcr_color_management_surface_(management_surface) { + DCHECK(color_space_creator); + static const zcr_color_space_creator_v1_listener listener = { + &WaylandZcrColorSpaceCreator::OnCreated, + &WaylandZcrColorSpaceCreator::OnError, + }; + DCHECK(zcr_color_management_surface_); + zcr_color_space_creator_v1_add_listener(zcr_color_space_creator_.get(), + &listener, this); +} + +WaylandZcrColorSpaceCreator::~WaylandZcrColorSpaceCreator() = default; + +// static +void WaylandZcrColorSpaceCreator::OnCreated( + void* data, + struct zcr_color_space_creator_v1* css, + struct zcr_color_space_v1* color_space) { + NOTIMPLEMENTED_LOG_ONCE(); +} + +// static +void WaylandZcrColorSpaceCreator::OnError( + void* data, + struct zcr_color_space_creator_v1* css, + uint32_t error) { + NOTIMPLEMENTED_LOG_ONCE(); +} + +} // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_zcr_color_space_creator.h b/chromium/ui/ozone/platform/wayland/host/wayland_zcr_color_space_creator.h new file mode 100644 index 00000000000..14276472092 --- /dev/null +++ b/chromium/ui/ozone/platform/wayland/host/wayland_zcr_color_space_creator.h @@ -0,0 +1,40 @@ +// Copyright 2022 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_ZCR_COLOR_SPACE_CREATOR_H_ +#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_ZCR_COLOR_SPACE_CREATOR_H_ + +#include "ui/gfx/color_space.h" +#include "ui/ozone/platform/wayland/host/wayland_zcr_color_space.h" + +namespace ui { + +// WaylandZcrColorSpaceCreator is used to create a zcr_color_space_v1 object +// that can be sent to exo over wayland protocol. +class WaylandZcrColorSpaceCreator { + public: + WaylandZcrColorSpaceCreator( + struct zcr_color_space_creator_v1* creator, + struct zcr_color_management_surface_v1* management_surface); + WaylandZcrColorSpaceCreator(const WaylandZcrColorSpaceCreator&) = delete; + WaylandZcrColorSpaceCreator& operator=(const WaylandZcrColorSpaceCreator&) = + delete; + ~WaylandZcrColorSpaceCreator(); + + private: + // zcr_color_space_creator_v1_listener + static void OnCreated(void* data, + struct zcr_color_space_creator_v1* css, + struct zcr_color_space_v1* color_space); + static void OnError(void* data, + struct zcr_color_space_creator_v1* css, + uint32_t error); + + wl::Object<zcr_color_space_creator_v1> zcr_color_space_creator_; + zcr_color_management_surface_v1* zcr_color_management_surface_; +}; + +} // namespace ui + +#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_ZCR_COLOR_SPACE_CREATOR_H_ diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_zcr_cursor_shapes.h b/chromium/ui/ozone/platform/wayland/host/wayland_zcr_cursor_shapes.h index 29af2085b5d..2556483a44b 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_zcr_cursor_shapes.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_zcr_cursor_shapes.h @@ -5,6 +5,7 @@ #ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_ZCR_CURSOR_SHAPES_H_ #define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_ZCR_CURSOR_SHAPES_H_ +#include "base/memory/raw_ptr.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/base/cursor/mojom/cursor_type.mojom-forward.h" #include "ui/ozone/platform/wayland/common/wayland_object.h" @@ -43,7 +44,7 @@ class WaylandZcrCursorShapes private: wl::Object<zcr_cursor_shapes_v1> zcr_cursor_shapes_v1_; - WaylandConnection* const connection_; + const raw_ptr<WaylandConnection> connection_; }; } // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_zcr_touchpad_haptics.h b/chromium/ui/ozone/platform/wayland/host/wayland_zcr_touchpad_haptics.h index df306190c5e..d563b3a783d 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_zcr_touchpad_haptics.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_zcr_touchpad_haptics.h @@ -5,6 +5,7 @@ #ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_ZCR_TOUCHPAD_HAPTICS_H_ #define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_ZCR_TOUCHPAD_HAPTICS_H_ +#include "base/memory/raw_ptr.h" #include "ui/ozone/platform/wayland/common/wayland_object.h" namespace ui { @@ -44,7 +45,7 @@ class WaylandZcrTouchpadHaptics struct zcr_touchpad_haptics_v1* zcr_touchpad_haptics_v1); wl::Object<zcr_touchpad_haptics_v1> obj_; - WaylandConnection* const connection_; + const raw_ptr<WaylandConnection> connection_; }; } // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.cc b/chromium/ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.cc index 6b4ec3871d1..01ef1ae7d7b 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.cc @@ -9,6 +9,7 @@ #include "base/logging.h" #include "ui/gfx/linux/drm_util_linux.h" +#include "ui/ozone/platform/wayland/host/wayland_buffer_factory.h" #include "ui/ozone/platform/wayland/host/wayland_connection.h" namespace ui { @@ -28,8 +29,8 @@ void WaylandZwpLinuxDmabuf::Instantiate(WaylandConnection* connection, const std::string& interface, uint32_t version) { DCHECK_EQ(interface, kInterfaceName); - - if (connection->zwp_dmabuf() || + auto* buffer_factory = connection->wayland_buffer_factory(); + if (buffer_factory->wayland_zwp_dmabuf_ || !wl::CanBind(interface, version, kMinVersion, kMaxVersion)) { return; } @@ -40,7 +41,7 @@ void WaylandZwpLinuxDmabuf::Instantiate(WaylandConnection* connection, LOG(ERROR) << "Failed to bind zwp_linux_dmabuf_v1"; return; } - connection->zwp_dmabuf_ = std::make_unique<WaylandZwpLinuxDmabuf>( + buffer_factory->wayland_zwp_dmabuf_ = std::make_unique<WaylandZwpLinuxDmabuf>( zwp_linux_dmabuf.release(), connection); } @@ -87,8 +88,7 @@ void WaylandZwpLinuxDmabuf::CreateBuffer(const base::ScopedFD& fd, // It's possible to avoid waiting until the buffer is created and have it // immediately. This method is only available since the protocol version 2. - if (wl::get_version_of_object(zwp_linux_dmabuf_.get()) >= - ZWP_LINUX_BUFFER_PARAMS_V1_CREATE_IMMED_SINCE_VERSION) { + if (CanCreateBufferImmed()) { wl::Object<wl_buffer> buffer(zwp_linux_buffer_params_v1_create_immed( params.get(), size.width(), size.height(), format, 0)); std::move(callback).Run(std::move(buffer)); @@ -105,6 +105,11 @@ void WaylandZwpLinuxDmabuf::CreateBuffer(const base::ScopedFD& fd, connection_->ScheduleFlush(); } +bool WaylandZwpLinuxDmabuf::CanCreateBufferImmed() const { + return wl::get_version_of_object(zwp_linux_dmabuf_.get()) >= + ZWP_LINUX_BUFFER_PARAMS_V1_CREATE_IMMED_SINCE_VERSION; +} + void WaylandZwpLinuxDmabuf::AddSupportedFourCCFormatAndModifier( uint32_t fourcc_format, absl::optional<uint64_t> modifier) { diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.h b/chromium/ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.h index e6bc80ea803..03bdc70eb2d 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.h @@ -8,6 +8,7 @@ #include <vector> #include "base/files/scoped_file.h" +#include "base/memory/raw_ptr.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/ozone/platform/wayland/common/wayland_object.h" #include "ui/ozone/platform/wayland/common/wayland_util.h" @@ -63,6 +64,10 @@ class WaylandZwpLinuxDmabuf return supported_buffer_formats_with_modifiers_; } + // Says if a new buffer can be created immediately. Depends on the version of + // the |zwp_linux_dmabuf| object. + bool CanCreateBufferImmed() const; + private: // Receives supported |fourcc_format| from either ::Modifers or ::Format call // (depending on the protocol version), and stores it as gfx::BufferFormat to @@ -100,7 +105,7 @@ class WaylandZwpLinuxDmabuf const wl::Object<zwp_linux_dmabuf_v1> zwp_linux_dmabuf_; // Non-owned. - WaylandConnection* const connection_; + const raw_ptr<WaylandConnection> connection_; // Holds supported DRM formats translated to gfx::BufferFormat. wl::BufferFormatsWithModifiersMap supported_buffer_formats_with_modifiers_; diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_zwp_pointer_constraints.h b/chromium/ui/ozone/platform/wayland/host/wayland_zwp_pointer_constraints.h index 3ad33bbe194..756a03132c4 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_zwp_pointer_constraints.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_zwp_pointer_constraints.h @@ -5,6 +5,7 @@ #ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_ZWP_POINTER_CONSTRAINTS_H_ #define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_ZWP_POINTER_CONSTRAINTS_H_ +#include "base/memory/raw_ptr.h" #include "ui/ozone/platform/wayland/common/wayland_object.h" namespace ui { @@ -44,7 +45,7 @@ class WaylandZwpPointerConstraints wl::Object<zwp_pointer_constraints_v1> obj_; wl::Object<zwp_locked_pointer_v1> locked_pointer_; - WaylandConnection* const connection_; + const raw_ptr<WaylandConnection> connection_; }; } // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_zwp_pointer_gestures.h b/chromium/ui/ozone/platform/wayland/host/wayland_zwp_pointer_gestures.h index de8e4e2d8f0..dbd6c75a8b2 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_zwp_pointer_gestures.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_zwp_pointer_gestures.h @@ -5,6 +5,7 @@ #ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_ZWP_POINTER_GESTURES_H_ #define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_ZWP_POINTER_GESTURES_H_ +#include "base/memory/raw_ptr.h" #include "base/time/time.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/events/types/event_type.h" @@ -71,8 +72,8 @@ class WaylandZwpPointerGestures wl::Object<zwp_pointer_gestures_v1> obj_; wl::Object<zwp_pointer_gesture_pinch_v1> pinch_; double current_scale_ = 1; - WaylandConnection* const connection_; - Delegate* const delegate_; + const raw_ptr<WaylandConnection> connection_; + const raw_ptr<Delegate> delegate_; }; class WaylandZwpPointerGestures::Delegate { diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_zwp_pointer_gestures_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_zwp_pointer_gestures_unittest.cc index 318e1d77f16..cecfac489ba 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_zwp_pointer_gestures_unittest.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_zwp_pointer_gestures_unittest.cc @@ -10,6 +10,7 @@ #include "ui/events/platform/platform_event_observer.h" #include "ui/ozone/platform/wayland/host/wayland_event_source.h" #include "ui/ozone/platform/wayland/host/wayland_zwp_pointer_gestures.h" +#include "ui/ozone/platform/wayland/test/mock_pointer.h" #include "ui/ozone/platform/wayland/test/mock_surface.h" #include "ui/ozone/platform/wayland/test/wayland_test.h" @@ -75,14 +76,6 @@ class WaylandPointerGesturesTest : public WaylandTest { } }; -// TODO(crbug.com/1298099): Reenable test when exo has been fixed and the -// libinput behavior has been restored. -#if BUILDFLAG(IS_CHROMEOS_LACROS) -#define MAYBE(x) DISABLED_##x -#else -#define MAYBE(x) x -#endif - // Tests that scale in pinch zoom events is fixed to the progression expected by // the compositor. // @@ -94,15 +87,20 @@ class WaylandPointerGesturesTest : public WaylandTest { // WaylandZwpPointerGestures methods. // // See https://crbug.com/1283652 -TEST_P(WaylandPointerGesturesTest, MAYBE(PinchZoomScale)) { +TEST_P(WaylandPointerGesturesTest, PinchZoomScale) { auto* const mock_surface = server_.GetObject<wl::MockSurface>( window_->root_surface()->GetSurfaceId()); + uint32_t serial = 0; + auto* pointer = server_.seat()->pointer(); + wl_pointer_send_enter(pointer->resource(), ++serial, mock_surface->resource(), + wl_fixed_from_int(50), wl_fixed_from_int(50)); + wl_pointer_send_frame(pointer->resource()); + PinchEventScaleRecorder observer; auto* pinch_resource = server_.wp_pointer_gestures().pinch()->resource(); - zwp_pointer_gesture_pinch_v1_send_begin(pinch_resource, - /* serial */ 0, + zwp_pointer_gesture_pinch_v1_send_begin(pinch_resource, ++serial, /* time */ 0, mock_surface->resource(), /* fingers */ 2); @@ -111,18 +109,13 @@ TEST_P(WaylandPointerGesturesTest, MAYBE(PinchZoomScale)) { constexpr double kScales[] = {1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.4, 1.3, 1.2, 1.1, 1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0}; - auto previous_scale = kScales[0]; for (auto scale : kScales) { zwp_pointer_gesture_pinch_v1_send_update( pinch_resource, /* time */ 0, /* dx */ 0, /* dy */ 0, wl_fixed_from_double(scale), /* rotation */ 0); Sync(); - // The conversion from double to fixed and back is necessary because it - // happens during the roundtrip, and it creates significant error. - EXPECT_FLOAT_EQ( - observer.latest_scale_update(), - wl_fixed_to_double(wl_fixed_from_double(scale)) / previous_scale); - previous_scale = wl_fixed_to_double(wl_fixed_from_double(scale)); + EXPECT_FLOAT_EQ(observer.latest_scale_update(), + wl_fixed_to_double(wl_fixed_from_double(scale))); } } diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_zwp_relative_pointer_manager.h b/chromium/ui/ozone/platform/wayland/host/wayland_zwp_relative_pointer_manager.h index 014829a0a54..6a86996da95 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_zwp_relative_pointer_manager.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_zwp_relative_pointer_manager.h @@ -5,6 +5,7 @@ #ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_ZWP_RELATIVE_POINTER_MANAGER_H_ #define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_ZWP_RELATIVE_POINTER_MANAGER_H_ +#include "base/memory/raw_ptr.h" #include "ui/ozone/platform/wayland/common/wayland_object.h" namespace gfx { @@ -55,8 +56,8 @@ class WaylandZwpRelativePointerManager wl::Object<zwp_relative_pointer_manager_v1> obj_; wl::Object<zwp_relative_pointer_v1> relative_pointer_; - WaylandConnection* const connection_; - Delegate* const delegate_; + const raw_ptr<WaylandConnection> connection_; + const raw_ptr<Delegate> delegate_; }; class WaylandZwpRelativePointerManager::Delegate { diff --git a/chromium/ui/ozone/platform/wayland/host/xdg_activation.cc b/chromium/ui/ozone/platform/wayland/host/xdg_activation.cc new file mode 100644 index 00000000000..ad964e91cf9 --- /dev/null +++ b/chromium/ui/ozone/platform/wayland/host/xdg_activation.cc @@ -0,0 +1,144 @@ +// Copyright 2022 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_activation.h" + +#include <xdg-activation-v1-client-protocol.h> + +#include <memory> + +#include "base/bind.h" +#include "base/callback.h" +#include "base/check_op.h" +#include "base/logging.h" +#include "ui/ozone/platform/wayland/host/wayland_connection.h" +#include "ui/ozone/platform/wayland/host/wayland_seat.h" +#include "ui/ozone/platform/wayland/host/wayland_serial_tracker.h" +#include "ui/ozone/platform/wayland/host/wayland_window.h" + +namespace ui { + +namespace { +constexpr uint32_t kMaxVersion = 1; +} + +using ActivationDoneCallback = base::OnceCallback<void(std::string token)>; + +// Wraps the actual activation token. +class XdgActivation::Token { + public: + Token(wl::Object<xdg_activation_token_v1> token, + wl_surface* surface, + wl_seat* seat, + absl::optional<wl::Serial> serial, + ActivationDoneCallback callback); + Token(const Token&) = delete; + Token& operator=(const Token&) = delete; + ~Token(); + + private: + static void Done(void* data, + struct xdg_activation_token_v1* xdg_activation_token_v1, + const char* token); + + wl::Object<xdg_activation_token_v1> token_; + + ActivationDoneCallback callback_; +}; + +// static +constexpr char XdgActivation::kInterfaceName[]; + +// static +void XdgActivation::Instantiate(WaylandConnection* connection, + wl_registry* registry, + uint32_t name, + const std::string& interface, + uint32_t version) { + DCHECK_EQ(interface, kInterfaceName); + + if (connection->xdg_activation_) + return; + + auto instance = wl::Bind<::xdg_activation_v1>(registry, name, + std::min(version, kMaxVersion)); + if (!instance) { + LOG(ERROR) << "Failed to bind " << kInterfaceName; + return; + } + connection->xdg_activation_ = + std::make_unique<XdgActivation>(std::move(instance), connection); +} + +XdgActivation::XdgActivation(wl::Object<xdg_activation_v1> xdg_activation_v1, + WaylandConnection* connection) + : xdg_activation_v1_(std::move(xdg_activation_v1)), + connection_(connection) {} + +XdgActivation::~XdgActivation() = default; + +void XdgActivation::Activate(wl_surface* surface) const { + const WaylandWindow* const active_window = + connection_->wayland_window_manager()->GetCurrentActiveWindow(); + if (!active_window) { + LOG(WARNING) << "Cannot activate a window because no active windows found!"; + return; + } + + if (token_.get() != nullptr) { + // TODO(crbug.com/1175327): chain the incoming request and try to serve it + // after the current one is done. + LOG(WARNING) << "Another activation request is in progress!"; + return; + } + + auto* const token = + xdg_activation_v1_get_activation_token(xdg_activation_v1_.get()); + if (!token) { + LOG(WARNING) << "Could not get an XDG activation token!"; + return; + } + + token_ = std::make_unique<Token>( + wl::Object<xdg_activation_token_v1>(token), + active_window->root_surface()->surface(), + connection_->seat()->wl_object(), + connection_->serial_tracker().GetSerial( + {wl::SerialType::kTouchPress, wl::SerialType::kMousePress, + wl::SerialType::kMouseEnter, wl::SerialType::kKeyPress}), + base::BindOnce(&XdgActivation::OnActivateDone, weak_factory_.GetWeakPtr(), + surface)); +} + +void XdgActivation::OnActivateDone(wl_surface* surface, std::string token) { + xdg_activation_v1_activate(xdg_activation_v1_.get(), token.c_str(), surface); + token_.reset(); +} + +XdgActivation::Token::Token(wl::Object<xdg_activation_token_v1> token, + wl_surface* surface, + wl_seat* seat, + absl::optional<wl::Serial> serial, + ActivationDoneCallback callback) + : token_(std::move(token)), callback_(std::move(callback)) { + static constexpr xdg_activation_token_v1_listener kListener = {&Done}; + xdg_activation_token_v1_add_listener(token_.get(), &kListener, this); + xdg_activation_token_v1_set_surface(token_.get(), surface); + if (serial) + xdg_activation_token_v1_set_serial(token_.get(), serial->value, seat); + xdg_activation_token_v1_commit(token_.get()); +} + +XdgActivation::Token::~Token() = default; + +// static +void XdgActivation::Token::Done( + void* data, + struct xdg_activation_token_v1* xdg_activation_token_v1, + const char* token) { + auto* const self = static_cast<XdgActivation::Token*>(data); + std::move(self->callback_).Run(token); +} + +} // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/host/xdg_activation.h b/chromium/ui/ozone/platform/wayland/host/xdg_activation.h new file mode 100644 index 00000000000..3256996bd2c --- /dev/null +++ b/chromium/ui/ozone/platform/wayland/host/xdg_activation.h @@ -0,0 +1,55 @@ +// Copyright 2022 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_ACTIVATION_H_ +#define UI_OZONE_PLATFORM_WAYLAND_HOST_XDG_ACTIVATION_H_ + +#include "base/memory/raw_ptr.h" +#include "base/memory/weak_ptr.h" +#include "ui/ozone/platform/wayland/common/wayland_object.h" + +namespace ui { + +// Implements the XDG activation Wayland protocol extension. +class XdgActivation : public wl::GlobalObjectRegistrar<XdgActivation> { + public: + static constexpr char kInterfaceName[] = "xdg_activation_v1"; + + static void Instantiate(WaylandConnection* connection, + wl_registry* registry, + uint32_t name, + const std::string& interface, + uint32_t version); + + XdgActivation(wl::Object<xdg_activation_v1> xdg_activation_v1, + WaylandConnection* connection); + XdgActivation(const XdgActivation&) = delete; + XdgActivation& operator=(const XdgActivation&) = delete; + ~XdgActivation(); + + // Requests activation of the `surface`. + // The actual activation happens asynchronously, after a round trip to the + // server. + // Does nothing if no other window is currently active, or if there is already + // an unfinished activation request. + void Activate(wl_surface* surface) const; + + private: + class Token; + + void OnActivateDone(wl_surface* surface, std::string token); + + // Wayland object wrapped by this class. + wl::Object<xdg_activation_v1> xdg_activation_v1_; + // The actual activation token. + mutable std::unique_ptr<Token> token_; + + const raw_ptr<WaylandConnection> connection_; + + base::WeakPtrFactory<XdgActivation> weak_factory_{this}; +}; + +} // namespace ui + +#endif // UI_OZONE_PLATFORM_WAYLAND_HOST_XDG_ACTIVATION_H_ diff --git a/chromium/ui/ozone/platform/wayland/host/xdg_foreign_wrapper.cc b/chromium/ui/ozone/platform/wayland/host/xdg_foreign_wrapper.cc index 2586adf9b85..be5f2846f66 100644 --- a/chromium/ui/ozone/platform/wayland/host/xdg_foreign_wrapper.cc +++ b/chromium/ui/ozone/platform/wayland/host/xdg_foreign_wrapper.cc @@ -8,6 +8,7 @@ #include <xdg-foreign-unstable-v2-client-protocol.h> #include "base/logging.h" +#include "base/memory/raw_ptr.h" #include "ui/ozone/platform/wayland/host/wayland_connection.h" #include "ui/ozone/platform/wayland/host/wayland_window.h" #include "ui/platform_window/platform_window_init_properties.h" @@ -52,7 +53,7 @@ struct ExportedSurface { ~ExportedSurface() = default; // Surface that is exported. - wl_surface* surface_for_export = nullptr; + raw_ptr<wl_surface> surface_for_export = nullptr; // Exported |surface|. wl::Object<ExportedType> exported; @@ -148,7 +149,7 @@ class XdgForeignWrapperImpl exported_surface_it->callbacks.clear(); } - WaylandConnection* const connection_; + const raw_ptr<WaylandConnection> connection_; wl::Object<ExporterType> exporter_; std::vector<ExportedSurface<ExportedType>> exported_surfaces_; }; diff --git a/chromium/ui/ozone/platform/wayland/host/xdg_output.cc b/chromium/ui/ozone/platform/wayland/host/xdg_output.cc index e0326739f62..f9f09074acd 100644 --- a/chromium/ui/ozone/platform/wayland/host/xdg_output.cc +++ b/chromium/ui/ozone/platform/wayland/host/xdg_output.cc @@ -51,11 +51,20 @@ void XDGOutput::OutputHandleDone(void* data, // static void XDGOutput::OutputHandleName(void* data, struct zxdg_output_v1* zxdg_output_v1, - const char* name) {} + const char* name) { + if (XDGOutput* xdg_output = static_cast<XDGOutput*>(data)) { + xdg_output->name_ = name ? std::string(name) : std::string(); + } +} // static void XDGOutput::OutputHandleDescription(void* data, struct zxdg_output_v1* zxdg_output_v1, - const char* description) {} + const char* description) { + if (XDGOutput* xdg_output = static_cast<XDGOutput*>(data)) { + xdg_output->description_ = + description ? std::string(description) : std::string(); + } +} } // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/host/xdg_output.h b/chromium/ui/ozone/platform/wayland/host/xdg_output.h index 441db6853d0..72a3d3eccbb 100644 --- a/chromium/ui/ozone/platform/wayland/host/xdg_output.h +++ b/chromium/ui/ozone/platform/wayland/host/xdg_output.h @@ -25,6 +25,8 @@ class XDGOutput { return logical_position_; } gfx::Size logical_size() const { return logical_size_; } + const std::string& description() const { return description_; } + const std::string& name() const { return name_; } private: static void OutputHandleLogicalPosition(void* data, @@ -47,6 +49,8 @@ class XDGOutput { wl::Object<zxdg_output_v1> xdg_output_; absl::optional<gfx::Point> logical_position_; gfx::Size logical_size_; + std::string description_; + std::string name_; }; } // 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 dd032a8ced4..bcd64d228a4 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 @@ -172,6 +172,8 @@ bool XDGPopupWrapperImpl::Initialize(const ShellPopupParams& params) { positioner.get())); if (!xdg_popup_) return false; + connection_->wayland_window_manager()->NotifyWindowRoleAssigned( + wayland_window_); if (connection_->zaura_shell()) { uint32_t version = @@ -184,6 +186,10 @@ bool XDGPopupWrapperImpl::Initialize(const ShellPopupParams& params) { ZAURA_POPUP_SURFACE_SUBMISSION_IN_PIXEL_COORDINATES_SINCE_VERSION) { zaura_popup_surface_submission_in_pixel_coordinates(aura_popup_.get()); } + if (version >= ZAURA_POPUP_SET_MENU_SINCE_VERSION && + wayland_window_->type() == PlatformWindowType::kMenu) { + zaura_popup_set_menu(aura_popup_.get()); + } } } @@ -238,6 +244,18 @@ void XDGPopupWrapperImpl::Grab(uint32_t serial) { xdg_popup_grab(xdg_popup_.get(), connection_->seat()->wl_object(), serial); } +bool XDGPopupWrapperImpl::SupportsDecoration() { + if (!aura_popup_) + return false; + uint32_t version = zaura_popup_get_version(aura_popup_.get()); + return version >= ZAURA_POPUP_SET_DECORATION_SINCE_VERSION; +} + +void XDGPopupWrapperImpl::Decorate() { + zaura_popup_set_decoration(aura_popup_.get(), + ZAURA_POPUP_DECORATION_TYPE_SHADOW); +} + wl::Object<xdg_positioner> XDGPopupWrapperImpl::CreatePositioner() { wl::Object<xdg_positioner> positioner( xdg_wm_base_create_positioner(connection_->shell())); 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 49d4da7737e..adad069a9b4 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 @@ -7,6 +7,7 @@ #include <memory> +#include "base/memory/raw_ptr.h" #include "ui/ozone/platform/wayland/host/shell_popup_wrapper.h" namespace ui { @@ -27,13 +28,15 @@ class XDGPopupWrapperImpl : public ShellPopupWrapper { ~XDGPopupWrapperImpl() override; - // XDGPopupWrapper: + // ShellPopupWrapper overrides: bool Initialize(const ShellPopupParams& params) override; void AckConfigure(uint32_t serial) override; bool IsConfigured() override; bool SetBounds(const gfx::Rect& new_bounds) override; void SetWindowGeometry(const gfx::Rect& bounds) override; void Grab(uint32_t serial) override; + bool SupportsDecoration() override; + void Decorate() override; private: wl::Object<xdg_positioner> CreatePositioner(); @@ -53,8 +56,8 @@ class XDGPopupWrapperImpl : public ShellPopupWrapper { XDGSurfaceWrapperImpl* xdg_surface_wrapper() const; // Non-owned WaylandWindow that uses this popup. - WaylandWindow* const wayland_window_; - WaylandConnection* const connection_; + const raw_ptr<WaylandWindow> wayland_window_; + const raw_ptr<WaylandConnection> connection_; // Ground surface for this popup. std::unique_ptr<XDGSurfaceWrapperImpl> xdg_surface_wrapper_; 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 32c9079069f..2d175c926ab 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 @@ -74,10 +74,10 @@ void XDGSurfaceWrapperImpl::Configure(void* data, // toplevel window, and deleting this object. auto weak_window = surface->wayland_window_->AsWeakPtr(); weak_window->HandleSurfaceConfigure(serial); - + if (!weak_window) return; - + weak_window->OnSurfaceConfigureEvent(); } 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 a44a5d82d0e..c73848afc5b 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 @@ -5,6 +5,7 @@ #ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_XDG_SURFACE_WRAPPER_IMPL_H_ #define UI_OZONE_PLATFORM_WAYLAND_HOST_XDG_SURFACE_WRAPPER_IMPL_H_ +#include "base/memory/raw_ptr.h" #include "ui/ozone/platform/wayland/host/shell_surface_wrapper.h" #include <cstdint> @@ -44,8 +45,8 @@ class XDGSurfaceWrapperImpl : public ShellSurfaceWrapper { uint32_t serial); // Non-owing WaylandWindow that uses this surface wrapper. - WaylandWindow* const wayland_window_; - WaylandConnection* const connection_; + const raw_ptr<WaylandWindow> wayland_window_; + const raw_ptr<WaylandConnection> connection_; bool is_configured_ = false; 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 index 9935ab94cd7..9e06965fd2d 100644 --- a/chromium/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.cc +++ b/chromium/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.cc @@ -62,6 +62,23 @@ absl::optional<wl::Serial> GetSerialForMoveResize( wl::SerialType::kKeyPress}); } +zaura_toplevel_z_order_level ToZauraToplevelZOrderLevel( + ZOrderLevel z_order_level) { + switch (z_order_level) { + case ZOrderLevel::kNormal: + return ZAURA_TOPLEVEL_Z_ORDER_LEVEL_NORMAL; + case ZOrderLevel::kFloatingWindow: + return ZAURA_TOPLEVEL_Z_ORDER_LEVEL_FLOATING_WINDOW; + case ZOrderLevel::kFloatingUIElement: + return ZAURA_TOPLEVEL_Z_ORDER_LEVEL_FLOATING_UI_ELEMENT; + case ZOrderLevel::kSecuritySurface: + return ZAURA_TOPLEVEL_Z_ORDER_LEVEL_SECURITY_SURFACE; + } + + NOTREACHED(); + return ZAURA_TOPLEVEL_Z_ORDER_LEVEL_NORMAL; +} + } // namespace XDGToplevelWrapperImpl::XDGToplevelWrapperImpl( @@ -84,6 +101,10 @@ bool XDGToplevelWrapperImpl::Initialize() { static constexpr xdg_toplevel_listener xdg_toplevel_listener = { &ConfigureTopLevel, &CloseTopLevel, + // Since v4 + &ConfigureBounds, + // Since v5 + &WmCapabilities, }; if (!xdg_surface_wrapper_) @@ -95,6 +116,8 @@ bool XDGToplevelWrapperImpl::Initialize() { LOG(ERROR) << "Failed to create xdg_toplevel"; return false; } + connection_->wayland_window_manager()->NotifyWindowRoleAssigned( + wayland_window_); if (connection_->zaura_shell()) { uint32_t version = @@ -278,6 +301,21 @@ void XDGToplevelWrapperImpl::CloseTopLevel(void* data, surface->wayland_window_->OnCloseRequest(); } +// static +void XDGToplevelWrapperImpl::ConfigureBounds(void* data, + struct xdg_toplevel* xdg_toplevel, + int32_t width, + int32_t height) { + NOTIMPLEMENTED_LOG_ONCE(); +} + +// static +void XDGToplevelWrapperImpl::WmCapabilities(void* data, + struct xdg_toplevel* xdg_toplevel, + struct wl_array* capabilities) { + NOTIMPLEMENTED_LOG_ONCE(); +} + void XDGToplevelWrapperImpl::SetTopLevelDecorationMode( DecorationMode requested_mode) { if (!zxdg_toplevel_decoration_ || requested_mode == decoration_mode_) @@ -369,9 +407,12 @@ void XDGToplevelWrapperImpl::RequestWindowBounds(const gfx::Rect& bounds) { // `output` can be null in unit tests where it doesn't wait for output events. if (!output) return; - zaura_toplevel_set_window_bounds(aura_toplevel_.get(), bounds.x(), bounds.y(), - bounds.width(), bounds.height(), - output->get_output()); + if (aura_toplevel_ && zaura_toplevel_get_version(aura_toplevel_.get()) >= + ZAURA_TOPLEVEL_SET_WINDOW_BOUNDS_SINCE_VERSION) { + zaura_toplevel_set_window_bounds(aura_toplevel_.get(), bounds.x(), + bounds.y(), bounds.width(), + bounds.height(), output->get_output()); + } } void XDGToplevelWrapperImpl::SetSystemModal(bool modal) { @@ -410,6 +451,14 @@ void XDGToplevelWrapperImpl::EnableScreenCoordinates() { this); } +void XDGToplevelWrapperImpl::SetZOrder(ZOrderLevel z_order) { + if (aura_toplevel_ && zaura_toplevel_get_version(aura_toplevel_.get()) >= + ZAURA_TOPLEVEL_SET_Z_ORDER_SINCE_VERSION) { + zaura_toplevel_set_z_order(aura_toplevel_.get(), + ToZauraToplevelZOrderLevel(z_order)); + } +} + void XDGToplevelWrapperImpl::SetRestoreInfo(int32_t restore_session_id, int32_t restore_window_id) { if (aura_toplevel_ && zaura_toplevel_get_version(aura_toplevel_.get()) >= @@ -431,4 +480,18 @@ void XDGToplevelWrapperImpl::SetRestoreInfoWithWindowIdSource( } } +void XDGToplevelWrapperImpl::SetFloat() { + if (aura_toplevel_ && zaura_toplevel_get_version(aura_toplevel_.get()) >= + ZAURA_TOPLEVEL_SET_FLOAT_SINCE_VERSION) { + zaura_toplevel_set_float(aura_toplevel_.get()); + } +} + +void XDGToplevelWrapperImpl::UnSetFloat() { + if (aura_toplevel_ && zaura_toplevel_get_version(aura_toplevel_.get()) >= + ZAURA_TOPLEVEL_UNSET_FLOAT_SINCE_VERSION) { + zaura_toplevel_unset_float(aura_toplevel_.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 index c8d7830b9b4..7e3116b4b48 100644 --- a/chromium/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.h +++ b/chromium/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.h @@ -7,6 +7,7 @@ #include <memory> +#include "base/memory/raw_ptr.h" #include "ui/ozone/platform/wayland/host/shell_toplevel_wrapper.h" namespace ui { @@ -50,6 +51,9 @@ class XDGToplevelWrapperImpl : public ShellToplevelWrapper { void SetSystemModal(bool modal) override; bool SupportsScreenCoordinates() const override; void EnableScreenCoordinates() override; + void SetFloat() override; + void UnSetFloat() override; + void SetZOrder(ZOrderLevel z_order) override; XDGSurfaceWrapperImpl* xdg_surface_wrapper() const; @@ -61,6 +65,13 @@ class XDGToplevelWrapperImpl : public ShellToplevelWrapper { int32_t height, struct wl_array* states); static void CloseTopLevel(void* data, struct xdg_toplevel* xdg_toplevel); + static void ConfigureBounds(void* data, + struct xdg_toplevel* xdg_toplevel, + int32_t width, + int32_t height); + static void WmCapabilities(void* data, + struct xdg_toplevel* xdg_toplevel, + struct wl_array* capabilities); // zxdg_decoration_listener static void ConfigureDecoration( @@ -92,8 +103,8 @@ class XDGToplevelWrapperImpl : public ShellToplevelWrapper { std::unique_ptr<XDGSurfaceWrapperImpl> xdg_surface_wrapper_; // Non-owing WaylandWindow that uses this toplevel wrapper. - WaylandWindow* const wayland_window_; - WaylandConnection* const connection_; + const raw_ptr<WaylandWindow> wayland_window_; + const raw_ptr<WaylandConnection> connection_; // XDG Shell Stable object. wl::Object<xdg_toplevel> xdg_toplevel_; 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 053105ad509..019869a2624 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 @@ -7,6 +7,7 @@ #include <memory> +#include "base/memory/raw_ptr.h" #include "ui/ozone/platform/wayland/common/wayland_object.h" #include "ui/ozone/platform/wayland/host/wayland_data_source.h" @@ -46,7 +47,7 @@ class ZwpPrimarySelectionDeviceManager private: wl::Object<zwp_primary_selection_device_manager_v1> device_manager_; - WaylandConnection* const connection_; + const raw_ptr<WaylandConnection> connection_; std::unique_ptr<ZwpPrimarySelectionDevice> device_; }; diff --git a/chromium/ui/ozone/platform/wayland/host/zwp_text_input_wrapper.h b/chromium/ui/ozone/platform/wayland/host/zwp_text_input_wrapper.h index 0d245fe5994..f8852306ec0 100644 --- a/chromium/ui/ozone/platform/wayland/host/zwp_text_input_wrapper.h +++ b/chromium/ui/ozone/platform/wayland/host/zwp_text_input_wrapper.h @@ -11,6 +11,7 @@ #include <vector> #include "base/strings/string_piece.h" +#include "ui/base/ime/grammar_fragment.h" #include "ui/base/ime/text_input_mode.h" #include "ui/base/ime/text_input_type.h" @@ -47,6 +48,11 @@ class ZWPTextInputWrapperClient { // result of some composing (pre-edit). virtual void OnCommitString(base::StringPiece text) = 0; + // Called when the cursor position or selection should be modified. The new + // cursor position is applied on the next OnCommitString. |index| and |anchor| + // are measured in UTF-8 bytes. + virtual void OnCursorPosition(int32_t index, int32_t anchor) = 0; + // Called when client needs to delete all or part of the text surrounding // the cursor. |index| and |length| are expected to be a byte offset of |text| // passed via ZWPTextInputWrapper::SetSurroundingText. @@ -68,6 +74,23 @@ class ZWPTextInputWrapperClient { uint32_t length, const std::vector<SpanStyle>& spans) = 0; + // Called when client needs to clear all grammar fragments in |range|. All + // indices are measured in UTF-8 bytes. + virtual void OnClearGrammarFragments(const gfx::Range& range) = 0; + + // Called when client requests to add a new grammar marker. All indices are + // measured in UTF-8 bytes. + virtual void OnAddGrammarFragment(const ui::GrammarFragment& fragment) = 0; + + // Sets the autocorrect range in the text input client. + // |range| is in UTF-16 code range. + virtual void OnSetAutocorrectRange(const gfx::Range& range) = 0; + + // Called when the virtual keyboard's occluded bounds is updated. + // The bounds are in screen DIP. + virtual void OnSetVirtualKeyboardOccludedBounds( + const gfx::Rect& screen_bounds) = 0; + // Called when the visibility state of the input panel changed. // There's no detailed spec of |state|, and no actual implementor except // components/exo is found in the world at this moment. @@ -107,6 +130,11 @@ class ZWPTextInputWrapper { ui::TextInputMode mode, uint32_t flags, bool should_do_learning) = 0; + + virtual void SetGrammarFragmentAtCursor( + const ui::GrammarFragment& fragment) = 0; + virtual void SetAutocorrectInfo(const gfx::Range& autocorrect_range, + const gfx::Rect& autocorrect_bounds) = 0; }; } // 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 da1971cc1b1..97eda7d684a 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 @@ -121,7 +121,11 @@ ZWPTextInputWrapperV1::ZWPTextInputWrapperV1( static constexpr zcr_extended_text_input_v1_listener extended_text_input_listener = { - &OnSetPreeditRegion, // extended_text_input_set_preedit_region, + &OnSetPreeditRegion, // extended_text_input_set_preedit_region, + &OnClearGrammarFragments, // extended_text_input_clear_grammar_fragments, + &OnAddGrammarFragment, // extended_text_input_add_grammar_fragment, + &OnSetAutocorrectRange, // extended_text_input_set_autocorrect_range, + &OnSetVirtualKeyboardOccludedBounds, // extended_text_input_set_virtual_keyboard_occluded_bounds, }; auto* text_input = @@ -208,6 +212,30 @@ void ZWPTextInputWrapperV1::SetContentType(ui::TextInputType type, zwp_text_input_v1_set_content_type(obj_.get(), content_hint, content_purpose); } +void ZWPTextInputWrapperV1::SetGrammarFragmentAtCursor( + const ui::GrammarFragment& fragment) { + if (extended_obj_.get() && + wl::get_version_of_object(extended_obj_.get()) >= + ZCR_EXTENDED_TEXT_INPUT_V1_SET_GRAMMAR_FRAGMENT_AT_CURSOR_SINCE_VERSION) { + zcr_extended_text_input_v1_set_grammar_fragment_at_cursor( + extended_obj_.get(), fragment.range.start(), fragment.range.end(), + fragment.suggestion.c_str()); + } +} + +void ZWPTextInputWrapperV1::SetAutocorrectInfo( + const gfx::Range& autocorrect_range, + const gfx::Rect& autocorrect_bounds) { + if (extended_obj_.get() && + wl::get_version_of_object(extended_obj_.get()) >= + ZCR_EXTENDED_TEXT_INPUT_V1_SET_AUTOCORRECT_INFO_SINCE_VERSION) { + zcr_extended_text_input_v1_set_autocorrect_info( + extended_obj_.get(), autocorrect_range.start(), autocorrect_range.end(), + autocorrect_bounds.x(), autocorrect_bounds.y(), + autocorrect_bounds.width(), autocorrect_bounds.height()); + } +} + void ZWPTextInputWrapperV1::ResetInputEventState() { spans_.clear(); preedit_cursor_ = -1; @@ -294,7 +322,8 @@ void ZWPTextInputWrapperV1::OnCursorPosition( struct zwp_text_input_v1* text_input, int32_t index, int32_t anchor) { - NOTIMPLEMENTED_LOG_ONCE(); + auto* self = static_cast<ZWPTextInputWrapperV1*>(data); + self->client_->OnCursorPosition(index, anchor); } // static @@ -348,4 +377,49 @@ void ZWPTextInputWrapperV1::OnSetPreeditRegion( self->client_->OnSetPreeditRegion(index, length, spans); } +// static +void ZWPTextInputWrapperV1::OnClearGrammarFragments( + void* data, + struct zcr_extended_text_input_v1* extended_text_input, + uint32_t start, + uint32_t end) { + auto* self = static_cast<ZWPTextInputWrapperV1*>(data); + self->client_->OnClearGrammarFragments(gfx::Range(start, end)); +} + +// static +void ZWPTextInputWrapperV1::OnAddGrammarFragment( + void* data, + struct zcr_extended_text_input_v1* extended_text_input, + uint32_t start, + uint32_t end, + const char* suggestion) { + auto* self = static_cast<ZWPTextInputWrapperV1*>(data); + self->client_->OnAddGrammarFragment( + ui::GrammarFragment(gfx::Range(start, end), suggestion)); +} + +// static +void ZWPTextInputWrapperV1::OnSetAutocorrectRange( + void* data, + struct zcr_extended_text_input_v1* extended_text_input, + uint32_t start, + uint32_t end) { + auto* self = static_cast<ZWPTextInputWrapperV1*>(data); + self->client_->OnSetAutocorrectRange(gfx::Range(start, end)); +} + +// static +void ZWPTextInputWrapperV1::OnSetVirtualKeyboardOccludedBounds( + void* data, + struct zcr_extended_text_input_v1* extended_text_input, + int32_t x, + int32_t y, + int32_t width, + int32_t height) { + auto* self = static_cast<ZWPTextInputWrapperV1*>(data); + gfx::Rect screen_bounds(x, y, width, height); + self->client_->OnSetVirtualKeyboardOccludedBounds(screen_bounds); +} + } // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1.h b/chromium/ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1.h index 7daa3f90b72..fd17d52d2f2 100644 --- a/chromium/ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1.h +++ b/chromium/ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1.h @@ -12,6 +12,7 @@ #include <text-input-extension-unstable-v1-client-protocol.h> #include <text-input-unstable-v1-client-protocol.h> +#include "base/memory/raw_ptr.h" #include "ui/ozone/platform/wayland/common/wayland_object.h" #include "ui/ozone/platform/wayland/host/zwp_text_input_wrapper.h" @@ -50,6 +51,9 @@ class ZWPTextInputWrapperV1 : public ZWPTextInputWrapper { TextInputMode mode, uint32_t flags, bool should_do_learning) override; + void SetGrammarFragmentAtCursor(const ui::GrammarFragment& fragment) override; + void SetAutocorrectInfo(const gfx::Range& autocorrect_range, + const gfx::Rect& autocorrect_bounds) override; private: void ResetInputEventState(); @@ -112,11 +116,34 @@ class ZWPTextInputWrapperV1 : public ZWPTextInputWrapper { struct zcr_extended_text_input_v1* extended_text_input, int32_t index, uint32_t length); + static void OnClearGrammarFragments( + void* data, + struct zcr_extended_text_input_v1* extended_text_input, + uint32_t start, + uint32_t end); + static void OnAddGrammarFragment( + void* data, + struct zcr_extended_text_input_v1* extended_text_input, + uint32_t start, + uint32_t end, + const char* suggestion); + static void OnSetAutocorrectRange( + void* data, + struct zcr_extended_text_input_v1* extended_text_input, + uint32_t start, + uint32_t end); + static void OnSetVirtualKeyboardOccludedBounds( + void* data, + struct zcr_extended_text_input_v1* extended_text_input, + int32_t x, + int32_t y, + int32_t width, + int32_t height); - WaylandConnection* const connection_; + const raw_ptr<WaylandConnection> connection_; wl::Object<zwp_text_input_v1> obj_; wl::Object<zcr_extended_text_input_v1> extended_obj_; - ZWPTextInputWrapperClient* const client_; + const raw_ptr<ZWPTextInputWrapperClient> client_; std::vector<ZWPTextInputWrapperClient::SpanStyle> spans_; int32_t preedit_cursor_ = -1; 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 index f9b7719e1ad..ff62ad8fb24 100644 --- 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 @@ -168,6 +168,8 @@ bool ZXDGPopupV6WrapperImpl::Initialize(const ShellPopupParams& params) { parent_xdg_surface->zxdg_surface(), positioner.get())); if (!zxdg_popup_v6_) return false; + connection_->wayland_window_manager()->NotifyWindowRoleAssigned( + wayland_window_); GrabIfPossible(connection_, wayland_window_->parent_window()); @@ -207,6 +209,15 @@ void ZXDGPopupV6WrapperImpl::Grab(uint32_t serial) { serial); } +bool ZXDGPopupV6WrapperImpl::SupportsDecoration() { + // zxdg_popup_v6 doesn't support frame configuration. + return false; +} + +void ZXDGPopupV6WrapperImpl::Decorate() { + NOTREACHED(); +} + wl::Object<zxdg_positioner_v6> ZXDGPopupV6WrapperImpl::CreatePositioner() { wl::Object<zxdg_positioner_v6> positioner( zxdg_shell_v6_create_positioner(connection_->shell_v6())); 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 index c1ba2bab46d..2b91335f452 100644 --- 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 @@ -7,6 +7,7 @@ #include <memory> +#include "base/memory/raw_ptr.h" #include "ui/ozone/platform/wayland/host/shell_popup_wrapper.h" namespace ui { @@ -34,6 +35,8 @@ class ZXDGPopupV6WrapperImpl : public ShellPopupWrapper { bool SetBounds(const gfx::Rect& new_bounds) override; void SetWindowGeometry(const gfx::Rect& bounds) override; void Grab(uint32_t serial) override; + bool SupportsDecoration() override; + void Decorate() override; private: wl::Object<zxdg_positioner_v6> CreatePositioner(); @@ -50,9 +53,9 @@ class ZXDGPopupV6WrapperImpl : public ShellPopupWrapper { ZXDGSurfaceV6WrapperImpl* zxdg_surface_v6_wrapper() const; // Non-owned WaylandWindow that uses this popup. - WaylandWindow* const wayland_window_; + const raw_ptr<WaylandWindow> wayland_window_; // Non-owned WaylandConnection. - WaylandConnection* const connection_; + const raw_ptr<WaylandConnection> connection_; // Ground surface for this popup. std::unique_ptr<ZXDGSurfaceV6WrapperImpl> zxdg_surface_v6_wrapper_; 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 index 33786ef73f7..b02b46a9f7f 100644 --- 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 @@ -74,8 +74,15 @@ void ZXDGSurfaceV6WrapperImpl::Configure( auto* surface = static_cast<ZXDGSurfaceV6WrapperImpl*>(data); DCHECK(surface); - surface->wayland_window_->HandleSurfaceConfigure(serial); - surface->wayland_window_->OnSurfaceConfigureEvent(); + // Calls to HandleSurfaceConfigure() might end up hiding the enclosing + // toplevel window, and deleting this object. + auto weak_window = surface->wayland_window_->AsWeakPtr(); + weak_window->HandleSurfaceConfigure(serial); + + if (!weak_window) + return; + + weak_window->OnSurfaceConfigureEvent(); } zxdg_surface_v6* ZXDGSurfaceV6WrapperImpl::zxdg_surface() const { 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 index 2794969b6ad..e5aa3da587e 100644 --- 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 @@ -5,6 +5,7 @@ #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 "base/memory/raw_ptr.h" #include "ui/ozone/platform/wayland/host/shell_surface_wrapper.h" #include <cstdint> @@ -44,8 +45,8 @@ class ZXDGSurfaceV6WrapperImpl : public ShellSurfaceWrapper { private: // Non-owing WaylandWindow that uses this surface wrapper. - WaylandWindow* const wayland_window_; - WaylandConnection* const connection_; + const raw_ptr<WaylandWindow> wayland_window_; + const raw_ptr<WaylandConnection> connection_; bool is_configured_ = false; 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 index 4ddb3a61341..b48a5e67cb1 100644 --- 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 @@ -63,6 +63,8 @@ bool ZXDGToplevelV6WrapperImpl::Initialize() { LOG(ERROR) << "Failed to create zxdg_toplevel"; return false; } + connection_->wayland_window_manager()->NotifyWindowRoleAssigned( + wayland_window_); zxdg_toplevel_v6_add_listener(zxdg_toplevel_v6_.get(), &zxdg_toplevel_v6_listener, this); @@ -213,4 +215,10 @@ bool ZXDGToplevelV6WrapperImpl::SupportsScreenCoordinates() const { void ZXDGToplevelV6WrapperImpl::EnableScreenCoordinates() {} +void ZXDGToplevelV6WrapperImpl::SetFloat() {} + +void ZXDGToplevelV6WrapperImpl::UnSetFloat() {} + +void ZXDGToplevelV6WrapperImpl::SetZOrder(ZOrderLevel z_order) {} + } // 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 index 140c677889d..2d66a7992f4 100644 --- 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 @@ -7,6 +7,7 @@ #include <memory> +#include "base/memory/raw_ptr.h" #include "ui/ozone/platform/wayland/host/shell_toplevel_wrapper.h" namespace ui { @@ -54,6 +55,9 @@ class ZXDGToplevelV6WrapperImpl : public ShellToplevelWrapper { void SetSystemModal(bool modal) override; bool SupportsScreenCoordinates() const override; void EnableScreenCoordinates() override; + void SetFloat() override; + void UnSetFloat() override; + void SetZOrder(ZOrderLevel z_order) override; ZXDGSurfaceV6WrapperImpl* zxdg_surface_v6_wrapper() const; @@ -71,8 +75,8 @@ class ZXDGToplevelV6WrapperImpl : public ShellToplevelWrapper { std::unique_ptr<ZXDGSurfaceV6WrapperImpl> zxdg_surface_v6_wrapper_; // Non-owing WaylandWindow that uses this toplevel wrapper. - WaylandWindow* const wayland_window_; - WaylandConnection* const connection_; + const raw_ptr<WaylandWindow> wayland_window_; + const raw_ptr<WaylandConnection> connection_; // XDG Shell V6 object. wl::Object<zxdg_toplevel_v6> zxdg_toplevel_v6_; diff --git a/chromium/ui/ozone/platform/wayland/mojom/DEPS b/chromium/ui/ozone/platform/wayland/mojom/DEPS index ad262d08a11..78b4871c7f4 100644 --- a/chromium/ui/ozone/platform/wayland/mojom/DEPS +++ b/chromium/ui/ozone/platform/wayland/mojom/DEPS @@ -1,6 +1,6 @@ specific_include_rules = { "wayland_overlay_config_mojom_traits.*" : [ "+components/crash/core/common/crash_key.h", - "+skia/public/mojom/skcolor_mojom_traits.h", + "+skia/public/mojom/skcolor4f_mojom_traits.h", ], } diff --git a/chromium/ui/ozone/platform/wayland/mojom/wayland_buffer_manager.mojom b/chromium/ui/ozone/platform/wayland/mojom/wayland_buffer_manager.mojom index 52cbbec45ae..39fd913ac48 100644 --- a/chromium/ui/ozone/platform/wayland/mojom/wayland_buffer_manager.mojom +++ b/chromium/ui/ozone/platform/wayland/mojom/wayland_buffer_manager.mojom @@ -5,7 +5,7 @@ module ui.ozone.mojom; import "mojo/public/mojom/base/file_path.mojom"; -import "skia/public/mojom/skcolor.mojom"; +import "skia/public/mojom/skcolor4f.mojom"; import "ui/gfx/geometry/mojom/geometry.mojom"; import "ui/gfx/mojom/accelerated_widget.mojom"; import "ui/gfx/mojom/buffer_types.mojom"; @@ -68,7 +68,7 @@ interface WaylandBufferManagerHost { // used to identify imported wl_buffers on the browser process side and map // them with the buffer objects on the gpu process side. CreateSolidColorBuffer(gfx.mojom.Size size, - skia.mojom.SkColor color, + skia.mojom.SkColor4f color, uint32 buffer_id); // These two methods are independent from the type of rendering. diff --git a/chromium/ui/ozone/platform/wayland/mojom/wayland_overlay_config.mojom b/chromium/ui/ozone/platform/wayland/mojom/wayland_overlay_config.mojom index c3fb2a10400..8edc8071978 100644 --- a/chromium/ui/ozone/platform/wayland/mojom/wayland_overlay_config.mojom +++ b/chromium/ui/ozone/platform/wayland/mojom/wayland_overlay_config.mojom @@ -5,11 +5,12 @@ module wl.mojom; import "ui/gfx/geometry/mojom/geometry.mojom"; +import "ui/gfx/mojom/color_space.mojom"; import "ui/gfx/mojom/gpu_fence_handle.mojom"; import "ui/gfx/mojom/overlay_transform.mojom"; import "ui/gfx/mojom/overlay_priority_hint.mojom"; import "ui/gfx/mojom/rrect_f.mojom"; -import "skia/public/mojom/skcolor.mojom"; +import "skia/public/mojom/skcolor4f.mojom"; // This is not a mirror of ui::OverlayPlane, it only contains things that are // useful to ozone/wayland. @@ -18,6 +19,9 @@ struct WaylandOverlayConfig { // plane. int32 z_order; + // Specifies the color space data of the wayland config. + gfx.mojom.ColorSpace color_space; + // Specifies how the buffer is to be transformed during composition. gfx.mojom.OverlayTransform transform; @@ -64,5 +68,5 @@ struct WaylandOverlayConfig { gfx.mojom.RRectF rounded_clip_bounds; // Optional: background color of this overlay plane. - skia.mojom.SkColor? background_color; + skia.mojom.SkColor4f? background_color; }; diff --git a/chromium/ui/ozone/platform/wayland/mojom/wayland_overlay_config_mojom_traits.cc b/chromium/ui/ozone/platform/wayland/mojom/wayland_overlay_config_mojom_traits.cc index 2a8f04e167d..63694c27757 100644 --- a/chromium/ui/ozone/platform/wayland/mojom/wayland_overlay_config_mojom_traits.cc +++ b/chromium/ui/ozone/platform/wayland/mojom/wayland_overlay_config_mojom_traits.cc @@ -24,6 +24,9 @@ bool StructTraits<wl::mojom::WaylandOverlayConfigDataView, wl::WaylandOverlayConfig* out) { out->z_order = data.z_order(); + if (!data.ReadColorSpace(&out->color_space)) + return false; + if (!data.ReadTransform(&out->transform)) return false; diff --git a/chromium/ui/ozone/platform/wayland/mojom/wayland_overlay_config_mojom_traits.h b/chromium/ui/ozone/platform/wayland/mojom/wayland_overlay_config_mojom_traits.h index 933edd9bb59..a0aaf07a1cf 100644 --- a/chromium/ui/ozone/platform/wayland/mojom/wayland_overlay_config_mojom_traits.h +++ b/chromium/ui/ozone/platform/wayland/mojom/wayland_overlay_config_mojom_traits.h @@ -5,7 +5,8 @@ #ifndef UI_OZONE_PLATFORM_WAYLAND_MOJOM_WAYLAND_OVERLAY_CONFIG_MOJOM_TRAITS_H_ #define UI_OZONE_PLATFORM_WAYLAND_MOJOM_WAYLAND_OVERLAY_CONFIG_MOJOM_TRAITS_H_ -#include "skia/public/mojom/skcolor_mojom_traits.h" +#include "skia/public/mojom/skcolor4f_mojom_traits.h" +#include "ui/gfx/mojom/color_space_mojom_traits.h" #include "ui/gfx/mojom/gpu_fence_handle_mojom_traits.h" #include "ui/gfx/mojom/overlay_priority_hint_mojom_traits.h" #include "ui/gfx/mojom/overlay_transform_mojom_traits.h" @@ -22,6 +23,11 @@ struct StructTraits<wl::mojom::WaylandOverlayConfigDataView, return input.z_order; } + static const gfx::ColorSpace color_space( + const wl::WaylandOverlayConfig& input) { + return input.color_space; + } + static const gfx::OverlayTransform& transform( const wl::WaylandOverlayConfig& input) { return input.transform; @@ -70,7 +76,7 @@ struct StructTraits<wl::mojom::WaylandOverlayConfigDataView, return input.rounded_clip_bounds; } - static const absl::optional<SkColor>& background_color( + static const absl::optional<SkColor4f>& background_color( const wl::WaylandOverlayConfig& input) { return input.background_color; } diff --git a/chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc b/chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc index 8d82c2df694..ff630dc28cc 100644 --- a/chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc +++ b/chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc @@ -20,6 +20,7 @@ #include "ui/base/cursor/cursor_factory.h" #include "ui/base/dragdrop/os_exchange_data_provider_factory_ozone.h" #include "ui/base/ime/linux/input_method_auralinux.h" +#include "ui/base/ime/linux/linux_input_method_context_factory.h" #include "ui/base/ui_base_features.h" #include "ui/display/display_switches.h" #include "ui/events/devices/device_data_manager.h" @@ -38,9 +39,10 @@ #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_event_source.h" #include "ui/ozone/platform/wayland/host/wayland_exchange_data_provider.h" #include "ui/ozone/platform/wayland/host/wayland_input_controller.h" -#include "ui/ozone/platform/wayland/host/wayland_input_method_context_factory.h" +#include "ui/ozone/platform/wayland/host/wayland_input_method_context.h" #include "ui/ozone/platform/wayland/host/wayland_menu_utils.h" #include "ui/ozone/platform/wayland/host/wayland_output_manager.h" #include "ui/ozone/platform/wayland/host/wayland_window.h" @@ -100,6 +102,7 @@ class OzonePlatformWayland : public OzonePlatform, ~OzonePlatformWayland() override { KeyEvent::SetSynthesizeKeyRepeatEnabled(old_synthesize_key_repeat_enabled_); + GetInputMethodContextFactoryForOzone() = LinuxInputMethodContextFactory(); } // OzonePlatform @@ -165,19 +168,9 @@ class OzonePlatformWayland : public OzonePlatform, } std::unique_ptr<InputMethod> CreateInputMethod( - internal::InputMethodDelegate* delegate, + ImeKeyEventDispatcher* ime_key_event_dispatcher, gfx::AcceleratedWidget widget) override { - // Instantiate and set LinuxInputMethodContextFactory unless it is already - // set (e.g: tests may have already set it). - if (!LinuxInputMethodContextFactory::instance() && - !input_method_context_factory_) { - input_method_context_factory_ = - std::make_unique<WaylandInputMethodContextFactory>(connection_.get()); - LinuxInputMethodContextFactory::SetInstance( - input_method_context_factory_.get()); - } - - return std::make_unique<InputMethodAuraLinux>(delegate); + return std::make_unique<InputMethodAuraLinux>(ime_key_event_dispatcher); } PlatformMenuUtils* GetPlatformMenuUtils() override { @@ -248,6 +241,17 @@ class OzonePlatformWayland : public OzonePlatform, menu_utils_ = std::make_unique<WaylandMenuUtils>(connection_.get()); wayland_utils_ = std::make_unique<WaylandUtils>(connection_.get()); + GetInputMethodContextFactoryForOzone() = base::BindRepeating( + [](WaylandConnection* connection, + WaylandKeyboard::Delegate* key_delegate, + LinuxInputMethodContextDelegate* ime_delegate) + -> std::unique_ptr<LinuxInputMethodContext> { + return std::make_unique<WaylandInputMethodContext>( + connection, key_delegate, ime_delegate); + }, + base::Unretained(connection_.get()), + base::Unretained(connection_->event_source())); + return true; } @@ -399,8 +403,6 @@ class OzonePlatformWayland : public OzonePlatform, std::unique_ptr<CursorFactory> cursor_factory_; std::unique_ptr<InputController> input_controller_; std::unique_ptr<GpuPlatformSupportHost> gpu_platform_support_host_; - std::unique_ptr<WaylandInputMethodContextFactory> - input_method_context_factory_; std::unique_ptr<WaylandBufferManagerConnector> buffer_manager_connector_; std::unique_ptr<WaylandMenuUtils> menu_utils_; std::unique_ptr<WaylandUtils> wayland_utils_; diff --git a/chromium/ui/ozone/platform/wayland/test/global_object.h b/chromium/ui/ozone/platform/wayland/test/global_object.h index e3c99cb68ab..2e241e21e1c 100644 --- a/chromium/ui/ozone/platform/wayland/test/global_object.h +++ b/chromium/ui/ozone/platform/wayland/test/global_object.h @@ -7,6 +7,8 @@ #include <memory> +#include "base/memory/raw_ptr.h" + struct wl_client; struct wl_display; struct wl_global; @@ -56,10 +58,10 @@ class GlobalObject { std::unique_ptr<wl_global, Deleter> global_; - const wl_interface* interface_; - const void* implementation_; + raw_ptr<const wl_interface> interface_; + raw_ptr<const void> implementation_; const uint32_t version_; - wl_resource* resource_ = nullptr; + raw_ptr<wl_resource> resource_ = nullptr; }; } // namespace wl diff --git a/chromium/ui/ozone/platform/wayland/test/mock_surface.h b/chromium/ui/ozone/platform/wayland/test/mock_surface.h index fb4fedbf5a4..c2dd7c85f04 100644 --- a/chromium/ui/ozone/platform/wayland/test/mock_surface.h +++ b/chromium/ui/ozone/platform/wayland/test/mock_surface.h @@ -9,6 +9,7 @@ #include <wayland-server-protocol.h> #include "base/containers/flat_map.h" +#include "base/memory/raw_ptr.h" #include "testing/gmock/include/gmock/gmock.h" #include "ui/gfx/gpu_fence_handle.h" #include "ui/ozone/platform/wayland/test/mock_xdg_surface.h" @@ -114,20 +115,20 @@ class MockSurface : public ServerObject { void set_buffer_scale(int32_t buffer_scale) { buffer_scale_ = buffer_scale; } private: - MockXdgSurface* xdg_surface_ = nullptr; - TestSubSurface* sub_surface_ = nullptr; - TestViewport* viewport_ = nullptr; - TestAlphaBlending* blending_ = nullptr; - TestOverlayPrioritizedSurface* prioritized_surface_ = nullptr; - TestAugmentedSurface* augmented_surface_ = nullptr; + raw_ptr<MockXdgSurface> xdg_surface_ = nullptr; + raw_ptr<TestSubSurface> sub_surface_ = nullptr; + raw_ptr<TestViewport> viewport_ = nullptr; + raw_ptr<TestAlphaBlending> blending_ = nullptr; + raw_ptr<TestOverlayPrioritizedSurface> prioritized_surface_ = nullptr; + raw_ptr<TestAugmentedSurface> augmented_surface_ = nullptr; gfx::Rect opaque_region_ = {-1, -1, 0, 0}; gfx::Rect input_region_ = {-1, -1, 0, 0}; - wl_resource* frame_callback_ = nullptr; + raw_ptr<wl_resource> frame_callback_ = nullptr; base::flat_map<wl_resource*, wl_resource*> linux_buffer_releases_; - wl_resource* attached_buffer_ = nullptr; - wl_resource* prev_attached_buffer_ = nullptr; + raw_ptr<wl_resource> attached_buffer_ = nullptr; + raw_ptr<wl_resource> prev_attached_buffer_ = nullptr; int32_t buffer_scale_ = -1; }; diff --git a/chromium/ui/ozone/platform/wayland/test/mock_wayland_platform_window_delegate.h b/chromium/ui/ozone/platform/wayland/test/mock_wayland_platform_window_delegate.h index b4f462a434e..904f172b313 100644 --- a/chromium/ui/ozone/platform/wayland/test/mock_wayland_platform_window_delegate.h +++ b/chromium/ui/ozone/platform/wayland/test/mock_wayland_platform_window_delegate.h @@ -5,6 +5,7 @@ #ifndef UI_OZONE_PLATFORM_WAYLAND_TEST_MOCK_WAYLAND_PLATFORM_WINDOW_DELEGATE_H_ #define UI_OZONE_PLATFORM_WAYLAND_TEST_MOCK_WAYLAND_PLATFORM_WINDOW_DELEGATE_H_ +#include "base/memory/raw_ptr.h" #include "ui/ozone/test/mock_platform_window_delegate.h" namespace ui { @@ -32,7 +33,7 @@ class MockWaylandPlatformWindowDelegate : public MockPlatformWindowDelegate { gfx::Rect ConvertRectToDIP(const gfx::Rect& rect_in_pixels) const override; private: - WaylandWindow* wayland_window_ = nullptr; + raw_ptr<WaylandWindow> wayland_window_ = nullptr; }; } // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/test/mock_wp_presentation.cc b/chromium/ui/ozone/platform/wayland/test/mock_wp_presentation.cc index cd87cb8aafc..d4117d99e46 100644 --- a/chromium/ui/ozone/platform/wayland/test/mock_wp_presentation.cc +++ b/chromium/ui/ozone/platform/wayland/test/mock_wp_presentation.cc @@ -37,7 +37,7 @@ MockWpPresentation::MockWpPresentation() MockWpPresentation::~MockWpPresentation() {} wl_resource* MockWpPresentation::ReleasePresentationCallback() { - auto* presentation_callback = presentation_callback_; + auto* presentation_callback = presentation_callback_.get(); presentation_callback_ = nullptr; return presentation_callback; } diff --git a/chromium/ui/ozone/platform/wayland/test/mock_wp_presentation.h b/chromium/ui/ozone/platform/wayland/test/mock_wp_presentation.h index 5230ceabee7..2ae53bf94f2 100644 --- a/chromium/ui/ozone/platform/wayland/test/mock_wp_presentation.h +++ b/chromium/ui/ozone/platform/wayland/test/mock_wp_presentation.h @@ -8,6 +8,7 @@ #include <presentation-time-server-protocol.h> #include "base/check.h" +#include "base/memory/raw_ptr.h" #include "testing/gmock/include/gmock/gmock.h" #include "ui/ozone/platform/wayland/test/global_object.h" @@ -43,7 +44,7 @@ class MockWpPresentation : public GlobalObject { void SendPresentationCallbackDiscarded(); private: - wl_resource* presentation_callback_ = nullptr; + raw_ptr<wl_resource> presentation_callback_ = nullptr; }; } // namespace wl diff --git a/chromium/ui/ozone/platform/wayland/test/mock_xdg_surface.cc b/chromium/ui/ozone/platform/wayland/test/mock_xdg_surface.cc index 7ffadf1e148..46d3bd879dc 100644 --- a/chromium/ui/ozone/platform/wayland/test/mock_xdg_surface.cc +++ b/chromium/ui/ozone/platform/wayland/test/mock_xdg_surface.cc @@ -52,8 +52,8 @@ void SetWindowGeometry(wl_client* client, int32_t y, int32_t width, int32_t height) { - GetUserDataAs<MockXdgSurface>(resource)->SetWindowGeometry(x, y, width, - height); + GetUserDataAs<MockXdgSurface>(resource)->SetWindowGeometry( + {x, y, width, height}); } void SetMaximized(wl_client* client, wl_resource* resource) { @@ -113,8 +113,9 @@ void GetTopLevel(wl_client* client, wl_resource* resource, uint32_t id) { wl_client_post_no_memory(client); return; } - surface->set_xdg_toplevel(std::make_unique<MockXdgTopLevel>( - xdg_toplevel_resource, &kMockXdgToplevelImpl)); + surface->set_xdg_toplevel( + std::make_unique<testing::NiceMock<MockXdgTopLevel>>( + xdg_toplevel_resource, &kMockXdgToplevelImpl)); } void GetTopLevelV6(wl_client* client, wl_resource* resource, uint32_t id) { @@ -130,8 +131,9 @@ void GetTopLevelV6(wl_client* client, wl_resource* resource, uint32_t id) { wl_client_post_no_memory(client); return; } - surface->set_xdg_toplevel(std::make_unique<MockXdgTopLevel>( - xdg_toplevel_resource, &kMockZxdgToplevelV6Impl)); + surface->set_xdg_toplevel( + std::make_unique<testing::NiceMock<MockXdgTopLevel>>( + xdg_toplevel_resource, &kMockZxdgToplevelV6Impl)); } void GetXdgPopup(struct wl_client* client, diff --git a/chromium/ui/ozone/platform/wayland/test/mock_xdg_surface.h b/chromium/ui/ozone/platform/wayland/test/mock_xdg_surface.h index 2eacf1f3e66..71c984e570b 100644 --- a/chromium/ui/ozone/platform/wayland/test/mock_xdg_surface.h +++ b/chromium/ui/ozone/platform/wayland/test/mock_xdg_surface.h @@ -11,6 +11,7 @@ #include <xdg-shell-server-protocol.h> #include <xdg-shell-unstable-v6-server-protocol.h> +#include "base/memory/raw_ptr.h" #include "testing/gmock/include/gmock/gmock.h" #include "ui/ozone/platform/wayland/test/server_object.h" #include "ui/ozone/platform/wayland/test/test_xdg_popup.h" @@ -38,8 +39,7 @@ class MockXdgSurface : public ServerObject { ~MockXdgSurface() override; MOCK_METHOD1(AckConfigure, void(uint32_t serial)); - MOCK_METHOD4(SetWindowGeometry, - void(int32_t x, int32_t y, int32_t width, int32_t height)); + MOCK_METHOD1(SetWindowGeometry, void(const gfx::Rect&)); void set_xdg_toplevel(std::unique_ptr<MockXdgTopLevel> xdg_toplevel) { xdg_toplevel_ = std::move(xdg_toplevel); @@ -53,10 +53,10 @@ class MockXdgSurface : public ServerObject { // Has either toplevel role.. std::unique_ptr<MockXdgTopLevel> xdg_toplevel_; // Or popup role. - TestXdgPopup* xdg_popup_ = nullptr; + raw_ptr<TestXdgPopup> xdg_popup_ = nullptr; // MockSurface that is the ground for this xdg_surface. - wl_resource* surface_ = nullptr; + raw_ptr<wl_resource> surface_ = nullptr; }; // Manage zxdg_toplevel for providing desktop UI. diff --git a/chromium/ui/ozone/platform/wayland/test/mock_zaura_shell.cc b/chromium/ui/ozone/platform/wayland/test/mock_zaura_shell.cc index 7bad5c3adb5..9acb0dcc864 100644 --- a/chromium/ui/ozone/platform/wayland/test/mock_zaura_shell.cc +++ b/chromium/ui/ozone/platform/wayland/test/mock_zaura_shell.cc @@ -4,37 +4,74 @@ #include "ui/ozone/platform/wayland/test/mock_zaura_shell.h" +#include "base/notreached.h" #include "ui/ozone/platform/wayland/test/server_object.h" #include "ui/ozone/platform/wayland/test/test_output.h" #include "ui/ozone/platform/wayland/test/test_zaura_output.h" +#include "ui/ozone/platform/wayland/test/test_zaura_popup.h" +#include "ui/ozone/platform/wayland/test/test_zaura_surface.h" +#include "ui/ozone/platform/wayland/test/test_zaura_toplevel.h" namespace wl { namespace { -constexpr uint32_t kZAuraShellVersion = 34; -constexpr uint32_t kZAuraOutputVersion = 34; +constexpr uint32_t kZAuraShellVersion = 40; +constexpr uint32_t kZAuraOutputVersion = 38; void GetAuraSurface(wl_client* client, wl_resource* resource, uint32_t id, - wl_resource* surface_resource) {} + wl_resource* surface_resource) { + CreateResourceWithImpl<TestZAuraSurface>(client, &zaura_surface_interface, + kZAuraShellVersion, + &kTestZAuraSurfaceImpl, id); +} void GetAuraOutput(wl_client* client, wl_resource* resource, uint32_t id, wl_resource* output_resource) { wl_resource* zaura_output_resource = CreateResourceWithImpl<TestZAuraOutput>( - client, &zaura_output_interface, kZAuraOutputVersion, nullptr, id); + client, &zaura_output_interface, kZAuraOutputVersion, + &kTestZAuraToplevelImpl, id); auto* output = GetUserDataAs<TestOutput>(output_resource); output->SetAuraOutput(GetUserDataAs<TestZAuraOutput>(zaura_output_resource)); } void SurfaceSubmissionInPixelCoordinates(wl_client* client, - wl_resource* resource) {} + wl_resource* resource) { + // TODO(crbug.com/1346347): Implement zaura-shell protocol requests and test + // their usage. + NOTIMPLEMENTED_LOG_ONCE(); +} + +void GetAuraToplevelForXdgToplevel(wl_client* client, + wl_resource* resource, + uint32_t id, + wl_resource* toplevel) { + CreateResourceWithImpl<TestZAuraToplevel>(client, &zaura_toplevel_interface, + kZAuraShellVersion, + &kTestZAuraToplevelImpl, id); +} + +void GetAuraPopupForXdgPopup(wl_client* client, + wl_resource* resource, + uint32_t id, + wl_resource* popup) { + CreateResourceWithImpl<TestZAuraPopup>(client, &zaura_popup_interface, + kZAuraShellVersion, + &kTestZAuraPopupImpl, id); +} const struct zaura_shell_interface kMockZAuraShellImpl = { - &GetAuraSurface, &GetAuraOutput, &SurfaceSubmissionInPixelCoordinates}; + &GetAuraSurface, + &GetAuraOutput, + &SurfaceSubmissionInPixelCoordinates, + &GetAuraToplevelForXdgToplevel, + &GetAuraPopupForXdgPopup, + &DestroyResource, +}; } // namespace diff --git a/chromium/ui/ozone/platform/wayland/test/server_object.h b/chromium/ui/ozone/platform/wayland/test/server_object.h index 24e5410dc61..87555cba6ba 100644 --- a/chromium/ui/ozone/platform/wayland/test/server_object.h +++ b/chromium/ui/ozone/platform/wayland/test/server_object.h @@ -11,6 +11,8 @@ #include <wayland-server-core.h> +#include "base/memory/raw_ptr.h" + struct wl_client; struct wl_resource; @@ -31,7 +33,7 @@ class ServerObject { static void OnResourceDestroyed(wl_resource* resource); private: - wl_resource* resource_; + raw_ptr<wl_resource> resource_; }; template <class T> diff --git a/chromium/ui/ozone/platform/wayland/test/test_alpha_blending.h b/chromium/ui/ozone/platform/wayland/test/test_alpha_blending.h index 296990d71a3..70c339003a0 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_alpha_blending.h +++ b/chromium/ui/ozone/platform/wayland/test/test_alpha_blending.h @@ -7,6 +7,7 @@ #include <alpha-compositing-unstable-v1-server-protocol.h> +#include "base/memory/raw_ptr.h" #include "ui/ozone/platform/wayland/test/server_object.h" struct wl_resource; @@ -24,7 +25,7 @@ class TestAlphaBlending : public ServerObject { private: // Surface resource that is the ground for this Viewport. - wl_resource* surface_ = nullptr; + raw_ptr<wl_resource> surface_ = nullptr; }; } // namespace wl diff --git a/chromium/ui/ozone/platform/wayland/test/test_augmented_subsurface.h b/chromium/ui/ozone/platform/wayland/test/test_augmented_subsurface.h index 33c594c686f..2ff51062d03 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_augmented_subsurface.h +++ b/chromium/ui/ozone/platform/wayland/test/test_augmented_subsurface.h @@ -7,6 +7,7 @@ #include <surface-augmenter-server-protocol.h> +#include "base/memory/raw_ptr.h" #include "ui/ozone/platform/wayland/test/server_object.h" namespace wl { @@ -27,7 +28,7 @@ class TestAugmentedSubSurface : public ServerObject { private: // Subsurface resource that is the ground for this augmented surface. - wl_resource* sub_surface_ = nullptr; + raw_ptr<wl_resource> sub_surface_ = nullptr; }; } // namespace wl diff --git a/chromium/ui/ozone/platform/wayland/test/test_augmented_surface.h b/chromium/ui/ozone/platform/wayland/test/test_augmented_surface.h index 709ce10a0f3..b8a618f59c1 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_augmented_surface.h +++ b/chromium/ui/ozone/platform/wayland/test/test_augmented_surface.h @@ -7,6 +7,7 @@ #include <surface-augmenter-server-protocol.h> +#include "base/memory/raw_ptr.h" #include "ui/gfx/geometry/rrect_f.h" #include "ui/ozone/platform/wayland/test/server_object.h" @@ -32,7 +33,7 @@ class TestAugmentedSurface : public ServerObject { private: // Surface resource that is the ground for this augmented surface. - wl_resource* surface_ = nullptr; + raw_ptr<wl_resource> surface_ = nullptr; gfx::RRectF rounded_clip_bounds_; }; diff --git a/chromium/ui/ozone/platform/wayland/test/test_data_device.cc b/chromium/ui/ozone/platform/wayland/test/test_data_device.cc index ee3fc397545..286181779ec 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_data_device.cc +++ b/chromium/ui/ozone/platform/wayland/test/test_data_device.cc @@ -8,6 +8,7 @@ #include <cstdint> +#include "base/memory/raw_ptr.h" #include "base/notreached.h" #include "ui/ozone/platform/wayland/test/mock_surface.h" #include "ui/ozone/platform/wayland/test/server_object.h" @@ -67,7 +68,7 @@ struct WlDataDeviceImpl : public TestSelectionDevice::Delegate { void OnDestroying() override { delete this; } private: - TestDataDevice* const device_; + const raw_ptr<TestDataDevice> device_; }; } // namespace diff --git a/chromium/ui/ozone/platform/wayland/test/test_data_device.h b/chromium/ui/ozone/platform/wayland/test/test_data_device.h index 16242fb49ca..69f506691ff 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_data_device.h +++ b/chromium/ui/ozone/platform/wayland/test/test_data_device.h @@ -9,6 +9,7 @@ #include <cstdint> +#include "base/memory/raw_ptr.h" #include "ui/ozone/platform/wayland/test/mock_surface.h" #include "ui/ozone/platform/wayland/test/test_selection_device_manager.h" @@ -60,10 +61,10 @@ class TestDataDevice : public TestSelectionDevice { wl_client* client() { return client_; } private: - wl_client* client_ = nullptr; - DragDelegate* drag_delegate_ = nullptr; + raw_ptr<wl_client> client_ = nullptr; + raw_ptr<DragDelegate> drag_delegate_ = nullptr; - TestDataDeviceManager* const manager_; + const raw_ptr<TestDataDeviceManager> manager_; }; } // namespace wl diff --git a/chromium/ui/ozone/platform/wayland/test/test_data_device_manager.h b/chromium/ui/ozone/platform/wayland/test/test_data_device_manager.h index 650e84589ee..86d67101d8e 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_data_device_manager.h +++ b/chromium/ui/ozone/platform/wayland/test/test_data_device_manager.h @@ -7,6 +7,7 @@ #include <wayland-server-protocol.h> +#include "base/memory/raw_ptr.h" #include "ui/ozone/platform/wayland/test/global_object.h" namespace wl { @@ -37,8 +38,8 @@ class TestDataDeviceManager : public GlobalObject { } private: - TestDataDevice* data_device_ = nullptr; - TestDataSource* data_source_ = nullptr; + raw_ptr<TestDataDevice> data_device_ = nullptr; + raw_ptr<TestDataSource> data_source_ = nullptr; }; } // namespace wl 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 fbafddb2214..48387b84995 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_data_offer.cc +++ b/chromium/ui/ozone/platform/wayland/test/test_data_offer.cc @@ -9,6 +9,7 @@ #include "base/bind.h" #include "base/logging.h" +#include "base/memory/raw_ptr.h" #include "ui/ozone/platform/wayland/test/test_selection_device_manager.h" namespace wl { @@ -52,7 +53,7 @@ struct WlDataOfferImpl : public TestSelectionOffer::Delegate { void OnDestroying() override { delete this; } private: - TestDataOffer* const offer_; + const raw_ptr<TestDataOffer> offer_; }; } // namespace diff --git a/chromium/ui/ozone/platform/wayland/test/test_data_source.cc b/chromium/ui/ozone/platform/wayland/test/test_data_source.cc index 8970cb82dc6..f0a92572acf 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_data_source.cc +++ b/chromium/ui/ozone/platform/wayland/test/test_data_source.cc @@ -9,6 +9,7 @@ #include <string> #include "base/logging.h" +#include "base/memory/raw_ptr.h" #include "ui/ozone/platform/wayland/test/test_selection_device_manager.h" namespace wl { @@ -50,7 +51,7 @@ struct WlDataSourceImpl : public TestSelectionSource::Delegate { void OnDestroying() override { delete this; } private: - TestDataSource* const source_; + const raw_ptr<TestDataSource> source_; }; } // namespace diff --git a/chromium/ui/ozone/platform/wayland/test/test_output.h b/chromium/ui/ozone/platform/wayland/test/test_output.h index 5b90dc06b2f..7f78bf74e08 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_output.h +++ b/chromium/ui/ozone/platform/wayland/test/test_output.h @@ -8,6 +8,7 @@ #include <wayland-server-protocol.h> #include <cstdint> +#include "base/memory/raw_ptr.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/geometry/rect.h" #include "ui/ozone/platform/wayland/test/global_object.h" @@ -48,7 +49,7 @@ class TestOutput : public GlobalObject { absl::optional<int32_t> pending_scale_ = absl::nullopt; absl::optional<wl_output_transform> pending_transform_ = absl::nullopt; - TestZAuraOutput* aura_output_ = nullptr; + raw_ptr<TestZAuraOutput> aura_output_ = nullptr; }; } // namespace wl diff --git a/chromium/ui/ozone/platform/wayland/test/test_overlay_prioritized_surface.h b/chromium/ui/ozone/platform/wayland/test/test_overlay_prioritized_surface.h index 3d52c8dc3e8..fe6462a625d 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_overlay_prioritized_surface.h +++ b/chromium/ui/ozone/platform/wayland/test/test_overlay_prioritized_surface.h @@ -7,6 +7,7 @@ #include <overlay-prioritizer-server-protocol.h> +#include "base/memory/raw_ptr.h" #include "ui/ozone/platform/wayland/test/server_object.h" struct wl_resource; @@ -30,7 +31,7 @@ class TestOverlayPrioritizedSurface : public ServerObject { private: // Surface resource that is the ground for this prioritized surface. - wl_resource* surface_ = nullptr; + raw_ptr<wl_resource> surface_ = nullptr; uint32_t overlay_priority_ = OVERLAY_PRIORITIZED_SURFACE_OVERLAY_PRIORITY_NONE; diff --git a/chromium/ui/ozone/platform/wayland/test/test_seat.h b/chromium/ui/ozone/platform/wayland/test/test_seat.h index 94b85ab2b59..ec30c24b936 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_seat.h +++ b/chromium/ui/ozone/platform/wayland/test/test_seat.h @@ -7,6 +7,7 @@ #include <wayland-server-protocol.h> +#include "base/memory/raw_ptr.h" #include "ui/ozone/platform/wayland/test/global_object.h" namespace wl { @@ -42,9 +43,9 @@ class TestSeat : public GlobalObject { TestTouch* touch() const { return touch_; } private: - MockPointer* pointer_; - TestKeyboard* keyboard_; - TestTouch* touch_; + raw_ptr<MockPointer> pointer_; + raw_ptr<TestKeyboard> keyboard_; + raw_ptr<TestTouch> touch_; }; } // namespace wl diff --git a/chromium/ui/ozone/platform/wayland/test/test_selection_device_manager.h b/chromium/ui/ozone/platform/wayland/test/test_selection_device_manager.h index bf4c9578f00..b514fa5cb0c 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_selection_device_manager.h +++ b/chromium/ui/ozone/platform/wayland/test/test_selection_device_manager.h @@ -11,6 +11,7 @@ #include "base/callback_forward.h" #include "base/files/scoped_file.h" +#include "base/memory/raw_ptr.h" #include "base/memory/scoped_refptr.h" #include "base/threading/thread.h" #include "ui/ozone/platform/wayland/test/global_object.h" @@ -72,10 +73,10 @@ class TestSelectionDeviceManager : public GlobalObject { wl_resource* seat_resource); private: - Delegate* const delegate_; + const raw_ptr<Delegate> delegate_; - TestSelectionDevice* device_ = nullptr; - TestSelectionSource* source_ = nullptr; + raw_ptr<TestSelectionDevice> device_ = nullptr; + raw_ptr<TestSelectionSource> source_ = nullptr; }; class TestSelectionOffer : public ServerObject { @@ -103,7 +104,7 @@ class TestSelectionOffer : public ServerObject { int fd); private: - Delegate* const delegate_; + const raw_ptr<Delegate> delegate_; const scoped_refptr<base::SequencedTaskRunner> task_runner_; ui::PlatformClipboard::DataMap data_to_offer_; @@ -139,7 +140,7 @@ class TestSelectionSource : public ServerObject { const char* mime_type); private: - Delegate* const delegate_; + const raw_ptr<Delegate> delegate_; std::vector<std::string> mime_types_; const scoped_refptr<base::SequencedTaskRunner> task_runner_; @@ -178,11 +179,11 @@ class TestSelectionDevice : public ServerObject { uint32_t selection_serial() const { return selection_serial_; } private: - Delegate* const delegate_; + const raw_ptr<Delegate> delegate_; uint32_t selection_serial_ = 0; - TestSelectionDeviceManager* manager_ = nullptr; + raw_ptr<TestSelectionDeviceManager> manager_ = nullptr; }; } // namespace wl diff --git a/chromium/ui/ozone/platform/wayland/test/test_subsurface.h b/chromium/ui/ozone/platform/wayland/test/test_subsurface.h index 833248e4d4a..0c713f442ef 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_subsurface.h +++ b/chromium/ui/ozone/platform/wayland/test/test_subsurface.h @@ -7,7 +7,7 @@ #include <wayland-server-protocol.h> - +#include "base/memory/raw_ptr.h" #include "testing/gmock/include/gmock/gmock.h" #include "ui/gfx/geometry/point_f.h" #include "ui/ozone/platform/wayland/test/server_object.h" @@ -53,12 +53,12 @@ class TestSubSurface : public ServerObject { bool sync_ = false; // Surface resource that is the ground for this subsurface. - wl_resource* surface_ = nullptr; + raw_ptr<wl_resource> surface_ = nullptr; // Parent surface resource. - wl_resource* parent_resource_ = nullptr; + raw_ptr<wl_resource> parent_resource_ = nullptr; - TestAugmentedSubSurface* augmented_subsurface_ = nullptr; + raw_ptr<TestAugmentedSubSurface> augmented_subsurface_ = nullptr; }; } // namespace wl diff --git a/chromium/ui/ozone/platform/wayland/test/test_touch.h b/chromium/ui/ozone/platform/wayland/test/test_touch.h index 7da05200ae7..ac21cb0a9ae 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_touch.h +++ b/chromium/ui/ozone/platform/wayland/test/test_touch.h @@ -7,6 +7,7 @@ #include <wayland-server-protocol.h> +#include "base/memory/raw_ptr.h" #include "ui/ozone/platform/wayland/test/server_object.h" struct wl_resource; @@ -32,7 +33,7 @@ class TestTouch : public ServerObject { MockZcrTouchStylus* touch_stylus() const { return touch_stylus_; } private: - MockZcrTouchStylus* touch_stylus_ = nullptr; + raw_ptr<MockZcrTouchStylus> touch_stylus_ = nullptr; }; } // namespace wl diff --git a/chromium/ui/ozone/platform/wayland/test/test_viewport.h b/chromium/ui/ozone/platform/wayland/test/test_viewport.h index 4ac792a0c24..1f24dfded9b 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_viewport.h +++ b/chromium/ui/ozone/platform/wayland/test/test_viewport.h @@ -7,6 +7,7 @@ #include <viewporter-server-protocol.h> +#include "base/memory/raw_ptr.h" #include "testing/gmock/include/gmock/gmock.h" #include "ui/gfx/geometry/size_f.h" #include "ui/ozone/platform/wayland/test/server_object.h" @@ -32,7 +33,7 @@ class TestViewport : public ServerObject { private: // Surface resource that is the ground for this Viewport. - wl_resource* surface_ = nullptr; + raw_ptr<wl_resource> surface_ = nullptr; gfx::SizeF destination_size_; }; 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 00860dd76a0..e1e729ba902 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 @@ -92,6 +92,8 @@ bool TestWaylandServerThread::Start(const ServerConfig& config) { } else { if (!xdg_shell_.Initialize(display_.get())) return false; + if (!zaura_shell_.Initialize(display_.get())) + return false; } if (!zcr_stylus_.Initialize(display_.get())) return false; diff --git a/chromium/ui/ozone/platform/wayland/test/test_wayland_server_thread.h b/chromium/ui/ozone/platform/wayland/test/test_wayland_server_thread.h index b08b191e0c4..3583d5d57f3 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_wayland_server_thread.h +++ b/chromium/ui/ozone/platform/wayland/test/test_wayland_server_thread.h @@ -11,12 +11,14 @@ #include <memory> #include <vector> +#include "base/memory/raw_ptr.h" #include "base/message_loop/message_pump_libevent.h" #include "base/synchronization/waitable_event.h" #include "base/threading/thread.h" #include "ui/ozone/platform/wayland/test/global_object.h" #include "ui/ozone/platform/wayland/test/mock_wp_presentation.h" #include "ui/ozone/platform/wayland/test/mock_xdg_shell.h" +#include "ui/ozone/platform/wayland/test/mock_zaura_shell.h" #include "ui/ozone/platform/wayland/test/mock_zwp_linux_dmabuf.h" #include "ui/ozone/platform/wayland/test/test_alpha_compositing.h" #include "ui/ozone/platform/wayland/test/test_compositor.h" @@ -111,6 +113,7 @@ class TestWaylandServerThread : public base::Thread, TestDataDeviceManager* data_device_manager() { return &data_device_manager_; } TestSeat* seat() { return &seat_; } MockXdgShell* xdg_shell() { return &xdg_shell_; } + MockZAuraShell* zaura_shell() { return &zaura_shell_; } TestOutput* output() { return &output_; } TestZcrTextInputExtensionV1* text_input_extension_v1() { return &zcr_text_input_extension_v1_; @@ -152,8 +155,8 @@ class TestWaylandServerThread : public base::Thread, void OnFileCanWriteWithoutBlocking(int fd) override; std::unique_ptr<wl_display, DisplayDeleter> display_; - wl_client* client_ = nullptr; - wl_event_loop* event_loop_ = nullptr; + raw_ptr<wl_client> client_ = nullptr; + raw_ptr<wl_event_loop> event_loop_ = nullptr; base::WaitableEvent pause_event_; base::WaitableEvent resume_event_; @@ -175,6 +178,7 @@ class TestWaylandServerThread : public base::Thread, TestSeat seat_; MockXdgShell xdg_shell_; MockZxdgShellV6 zxdg_shell_v6_; + MockZAuraShell zaura_shell_; TestZcrStylus zcr_stylus_; TestZcrTextInputExtensionV1 zcr_text_input_extension_v1_; TestZwpTextInputManagerV1 zwp_text_input_manager_v1_; @@ -188,7 +192,7 @@ class TestWaylandServerThread : public base::Thread, base::MessagePumpLibevent::FdWatchController controller_; - OutputDelegate* output_delegate_ = nullptr; + raw_ptr<OutputDelegate> output_delegate_ = nullptr; }; class TestWaylandServerThread::OutputDelegate { diff --git a/chromium/ui/ozone/platform/wayland/test/test_wp_pointer_gestures.h b/chromium/ui/ozone/platform/wayland/test/test_wp_pointer_gestures.h index d275dee9569..e5a9ce1081f 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_wp_pointer_gestures.h +++ b/chromium/ui/ozone/platform/wayland/test/test_wp_pointer_gestures.h @@ -5,6 +5,7 @@ #ifndef UI_OZONE_PLATFORM_WAYLAND_TEST_TEST_WP_POINTER_GESTURES_H_ #define UI_OZONE_PLATFORM_WAYLAND_TEST_TEST_WP_POINTER_GESTURES_H_ +#include "base/memory/raw_ptr.h" #include "ui/ozone/platform/wayland/test/global_object.h" #include "ui/ozone/platform/wayland/test/server_object.h" @@ -42,7 +43,7 @@ class TestWpPointerGestures : public GlobalObject { struct wl_resource* pointer); private: - TestPinchGesture* pinch_; + raw_ptr<TestPinchGesture> pinch_; }; } // namespace wl diff --git a/chromium/ui/ozone/platform/wayland/test/test_xdg_popup.h b/chromium/ui/ozone/platform/wayland/test/test_xdg_popup.h index 0beecc56664..6e4ba0d75d2 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_xdg_popup.h +++ b/chromium/ui/ozone/platform/wayland/test/test_xdg_popup.h @@ -10,6 +10,7 @@ #include <xdg-shell-server-protocol.h> #include <xdg-shell-unstable-v6-server-protocol.h> +#include "base/memory/raw_ptr.h" #include "ui/ozone/platform/wayland/test/server_object.h" #include "ui/ozone/platform/wayland/test/test_positioner.h" @@ -50,7 +51,7 @@ class TestXdgPopup : public ServerObject { struct TestPositioner::PopupPosition position_; // Ground surface for this popup. - wl_resource* surface_ = nullptr; + raw_ptr<wl_resource> surface_ = nullptr; uint32_t grab_serial_ = 0; }; diff --git a/chromium/ui/ozone/platform/wayland/test/test_zaura_popup.cc b/chromium/ui/ozone/platform/wayland/test/test_zaura_popup.cc new file mode 100644 index 00000000000..7aec2056b3b --- /dev/null +++ b/chromium/ui/ozone/platform/wayland/test/test_zaura_popup.cc @@ -0,0 +1,46 @@ +// Copyright 2022 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/test_zaura_popup.h" + +#include <aura-shell-server-protocol.h> + +#include "base/notreached.h" + +namespace wl { + +namespace { + +void SurfaceSubmissionInPixelCoordinates(struct wl_client* client, + struct wl_resource* resource) { + // TODO(crbug.com/1346347): Implement zaura-shell protocol requests and test + // their usage. + NOTIMPLEMENTED_LOG_ONCE(); +} + +void SetDecoration(struct wl_client* client, + struct wl_resource* resource, + uint32_t type) { + NOTIMPLEMENTED_LOG_ONCE(); +} + +void SetMenu(struct wl_client* client, struct wl_resource* resource) { + NOTIMPLEMENTED_LOG_ONCE(); +} + +} // namespace + +TestZAuraPopup::TestZAuraPopup(wl_resource* resource) + : ServerObject(resource) {} + +TestZAuraPopup::~TestZAuraPopup() = default; + +const struct zaura_popup_interface kTestZAuraPopupImpl = { + &SurfaceSubmissionInPixelCoordinates, + &SetDecoration, + &SetMenu, + &DestroyResource, +}; + +} // namespace wl diff --git a/chromium/ui/ozone/platform/wayland/test/test_zaura_popup.h b/chromium/ui/ozone/platform/wayland/test/test_zaura_popup.h new file mode 100644 index 00000000000..3398dc5f179 --- /dev/null +++ b/chromium/ui/ozone/platform/wayland/test/test_zaura_popup.h @@ -0,0 +1,29 @@ +// Copyright 2022 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_TEST_ZAURA_POPUP_H_ +#define UI_OZONE_PLATFORM_WAYLAND_TEST_TEST_ZAURA_POPUP_H_ + +#include <aura-shell-server-protocol.h> + +#include "ui/ozone/platform/wayland/test/server_object.h" + +namespace wl { + +extern const struct zaura_popup_interface kTestZAuraPopupImpl; + +// Manages zaura_popup object. +class TestZAuraPopup : public ServerObject { + public: + explicit TestZAuraPopup(wl_resource* resource); + + TestZAuraPopup(const TestZAuraPopup&) = delete; + TestZAuraPopup& operator=(const TestZAuraPopup&) = delete; + + ~TestZAuraPopup() override; +}; + +} // namespace wl + +#endif // UI_OZONE_PLATFORM_WAYLAND_TEST_TEST_ZAURA_POPUP_H_ diff --git a/chromium/ui/ozone/platform/wayland/test/test_zaura_surface.cc b/chromium/ui/ozone/platform/wayland/test/test_zaura_surface.cc new file mode 100644 index 00000000000..f5dff2bde15 --- /dev/null +++ b/chromium/ui/ozone/platform/wayland/test/test_zaura_surface.cc @@ -0,0 +1,170 @@ +// Copyright 2022 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/test_zaura_surface.h" + +#include <aura-shell-server-protocol.h> + +#include "base/notreached.h" +#include "ui/ozone/platform/wayland/test/server_object.h" + +namespace wl { + +namespace { + +void set_frame(struct wl_client* client, + struct wl_resource* resource, + uint32_t type) { + NOTREACHED(); +} +void set_parent(struct wl_client* client, + struct wl_resource* resource, + struct wl_resource* parent, + int32_t x, + int32_t y) { + NOTREACHED(); +} +void set_frame_colors(struct wl_client* client, + struct wl_resource* resource, + uint32_t active_color, + uint32_t inactive_color) { + NOTREACHED(); +} +void set_startup_id(struct wl_client* client, + struct wl_resource* resource, + const char* startup_id) { + NOTREACHED(); +} +void set_application_id(struct wl_client* client, + struct wl_resource* resource, + const char* application_id) { + NOTREACHED(); +} +void set_client_surface_id(struct wl_client* client, + struct wl_resource* resource, + int32_t client_surface_id) { + NOTREACHED(); +} +void set_occlusion_tracking(struct wl_client* client, + struct wl_resource* resource) { + NOTIMPLEMENTED_LOG_ONCE(); +} +void unset_occlusion_tracking(struct wl_client* client, + struct wl_resource* resource) { + NOTREACHED(); +} +void activate(struct wl_client* client, struct wl_resource* resource) { + NOTREACHED(); +} +void draw_attention(struct wl_client* client, struct wl_resource* resource) { + NOTREACHED(); +} +void set_fullscreen_mode(struct wl_client* client, + struct wl_resource* resource, + uint32_t mode) { + NOTIMPLEMENTED_LOG_ONCE(); +} +void set_client_surface_str_id(struct wl_client* client, + struct wl_resource* resource, + const char* client_surface_id) { + NOTREACHED(); +} +void set_server_start_resize(struct wl_client* client, + struct wl_resource* resource) { + NOTIMPLEMENTED_LOG_ONCE(); +} +void intent_to_snap(struct wl_client* client, + struct wl_resource* resource, + uint32_t direction) { + NOTREACHED(); +} +void set_snap_left(struct wl_client* client, struct wl_resource* resource) { + NOTREACHED(); +} +void set_snap_right(struct wl_client* client, struct wl_resource* resource) { + NOTREACHED(); +} +void unset_snap(struct wl_client* client, struct wl_resource* resource) { + NOTREACHED(); +} +void set_window_session_id(struct wl_client* client, + struct wl_resource* resource, + int32_t id) { + NOTREACHED(); +} +void set_can_go_back(struct wl_client* client, struct wl_resource* resource) { + NOTREACHED(); +} +void unset_can_go_back(struct wl_client* client, struct wl_resource* resource) { + NOTREACHED(); +} +void set_pip(struct wl_client* client, struct wl_resource* resource) { + NOTREACHED(); +} +void unset_pip(struct wl_client* client, struct wl_resource* resource) { + NOTREACHED(); +} +void set_aspect_ratio(struct wl_client* client, + struct wl_resource* resource, + int32_t width, + int32_t height) { + NOTREACHED(); +} +void move_to_desk(struct wl_client* client, + struct wl_resource* resource, + int32_t index) { + NOTREACHED(); +} +void set_initial_workspace(struct wl_client* client, + struct wl_resource* resource, + const char* initial_workspace) { + NOTREACHED(); +} +void set_pin(struct wl_client* client, + struct wl_resource* resource, + int32_t trusted) { + NOTREACHED(); +} +void unset_pin(struct wl_client* client, struct wl_resource* resource) { + NOTREACHED(); +} +} // namespace + +TestZAuraSurface::TestZAuraSurface(wl_resource* resource) + : ServerObject(resource) {} + +TestZAuraSurface::~TestZAuraSurface() = default; + +const struct zaura_surface_interface kTestZAuraSurfaceImpl = { + &set_frame, + &set_parent, + &set_frame_colors, + &set_startup_id, + &set_application_id, + &set_client_surface_id, + &set_occlusion_tracking, + &unset_occlusion_tracking, + &activate, + &draw_attention, + &set_fullscreen_mode, + &set_client_surface_str_id, + &set_server_start_resize, + &intent_to_snap, + &set_snap_left, + &set_snap_right, + &unset_snap, + &set_window_session_id, + &set_can_go_back, + &unset_can_go_back, + &set_pip, + &unset_pip, + &set_aspect_ratio, + &move_to_desk, + &set_initial_workspace, + &set_pin, + &unset_pin, + &DestroyResource, +}; + +} // namespace wl diff --git a/chromium/ui/ozone/platform/wayland/test/test_zaura_surface.h b/chromium/ui/ozone/platform/wayland/test/test_zaura_surface.h new file mode 100644 index 00000000000..773bf02cfbd --- /dev/null +++ b/chromium/ui/ozone/platform/wayland/test/test_zaura_surface.h @@ -0,0 +1,29 @@ +// Copyright 2022 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_TEST_ZAURA_SURFACE_H_ +#define UI_OZONE_PLATFORM_WAYLAND_TEST_TEST_ZAURA_SURFACE_H_ + +#include <aura-shell-server-protocol.h> + +#include "ui/ozone/platform/wayland/test/server_object.h" + +namespace wl { + +extern const struct zaura_surface_interface kTestZAuraSurfaceImpl; + +// Manages zaura_surface object. +class TestZAuraSurface : public ServerObject { + public: + explicit TestZAuraSurface(wl_resource* resource); + + TestZAuraSurface(const TestZAuraSurface&) = delete; + TestZAuraSurface& operator=(const TestZAuraSurface&) = delete; + + ~TestZAuraSurface() override; +}; + +} // namespace wl + +#endif // UI_OZONE_PLATFORM_WAYLAND_TEST_TEST_ZAURA_SURFACE_H_ diff --git a/chromium/ui/ozone/platform/wayland/test/test_zaura_toplevel.cc b/chromium/ui/ozone/platform/wayland/test/test_zaura_toplevel.cc new file mode 100644 index 00000000000..392fbdf78c0 --- /dev/null +++ b/chromium/ui/ozone/platform/wayland/test/test_zaura_toplevel.cc @@ -0,0 +1,108 @@ +// Copyright 2022 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/test_zaura_toplevel.h" + +#include <aura-shell-server-protocol.h> + +#include "base/notreached.h" + +namespace wl { + +namespace { + +void SetOrientationLock(struct wl_client* client, + struct wl_resource* resource, + uint32_t orientation_lock) { + NOTIMPLEMENTED_LOG_ONCE(); +} + +void SurfaceSubmissionInPixelCoordinates(struct wl_client* client, + struct wl_resource* resource) { + // TODO(crbug.com/1346347): Implement zaura-shell protocol requests and test + // their usage. + NOTIMPLEMENTED_LOG_ONCE(); +} + +void SetSupportsScreenCoordinates(struct wl_client* client, + struct wl_resource* resource) { + NOTIMPLEMENTED_LOG_ONCE(); +} + +void SetWindowBounds(struct wl_client* client, + struct wl_resource* resource, + int32_t x, + int32_t y, + int32_t width, + int32_t height, + struct wl_resource* output) { + NOTIMPLEMENTED_LOG_ONCE(); +} + +void SetRestoreInfo(struct wl_client* client, + struct wl_resource* resource, + int32_t restore_session_id, + int32_t restore_window_id) { + NOTREACHED(); +} + +void SetSystemModal(struct wl_client* client, struct wl_resource* resource) { + NOTREACHED(); +} + +void UnsetSystemModal(struct wl_client* client, struct wl_resource* resource) { + NOTIMPLEMENTED_LOG_ONCE(); +} + +void SetRestoreInfoWithWindowIdSource(struct wl_client* client, + struct wl_resource* resource, + int32_t restore_session_id, + const char* restore_window_id_source) { + NOTREACHED(); +} + +void SetDecoration(struct wl_client* client, + struct wl_resource* resource, + uint32_t type) { + NOTREACHED(); +} + +void SetFloat(struct wl_client* client, struct wl_resource* resource) { + NOTREACHED(); +} + +void UnSetFloat(struct wl_client* client, struct wl_resource* resource) { + NOTREACHED(); +} + +void SetZOrder(struct wl_client* client, + struct wl_resource* resource, + uint32_t z_order) { + NOTIMPLEMENTED_LOG_ONCE(); +} + +} // namespace + +TestZAuraToplevel::TestZAuraToplevel(wl_resource* resource) + : ServerObject(resource) {} + +TestZAuraToplevel::~TestZAuraToplevel() = default; + +const struct zaura_toplevel_interface kTestZAuraToplevelImpl = { + &SetOrientationLock, + &SurfaceSubmissionInPixelCoordinates, + &SetSupportsScreenCoordinates, + &SetWindowBounds, + &SetRestoreInfo, + &SetSystemModal, + &UnsetSystemModal, + &SetRestoreInfoWithWindowIdSource, + &SetDecoration, + &DestroyResource, + &SetFloat, + &UnSetFloat, + &SetZOrder, +}; + +} // namespace wl diff --git a/chromium/ui/ozone/platform/wayland/test/test_zaura_toplevel.h b/chromium/ui/ozone/platform/wayland/test/test_zaura_toplevel.h new file mode 100644 index 00000000000..86a023a5086 --- /dev/null +++ b/chromium/ui/ozone/platform/wayland/test/test_zaura_toplevel.h @@ -0,0 +1,29 @@ +// Copyright 2022 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_TEST_ZAURA_TOPLEVEL_H_ +#define UI_OZONE_PLATFORM_WAYLAND_TEST_TEST_ZAURA_TOPLEVEL_H_ + +#include <aura-shell-server-protocol.h> + +#include "ui/ozone/platform/wayland/test/server_object.h" + +namespace wl { + +extern const struct zaura_toplevel_interface kTestZAuraToplevelImpl; + +// Manages zaura_toplevel object. +class TestZAuraToplevel : public ServerObject { + public: + explicit TestZAuraToplevel(wl_resource* resource); + + TestZAuraToplevel(const TestZAuraToplevel&) = delete; + TestZAuraToplevel& operator=(const TestZAuraToplevel&) = delete; + + ~TestZAuraToplevel() override; +}; + +} // namespace wl + +#endif // UI_OZONE_PLATFORM_WAYLAND_TEST_TEST_ZAURA_TOPLEVEL_H_ diff --git a/chromium/ui/ozone/platform/wayland/test/test_zcr_text_input_extension.h b/chromium/ui/ozone/platform/wayland/test/test_zcr_text_input_extension.h index c0eff201f77..9f9b9b1ffd3 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_zcr_text_input_extension.h +++ b/chromium/ui/ozone/platform/wayland/test/test_zcr_text_input_extension.h @@ -7,6 +7,7 @@ #include <text-input-extension-unstable-v1-server-protocol.h> +#include "base/memory/raw_ptr.h" #include "ui/ozone/platform/wayland/test/global_object.h" namespace wl { @@ -33,7 +34,7 @@ class TestZcrTextInputExtensionV1 : public GlobalObject { } private: - MockZcrExtendedTextInput* extended_text_input_; + raw_ptr<MockZcrExtendedTextInput> extended_text_input_; }; } // namespace wl diff --git a/chromium/ui/ozone/platform/wayland/test/test_zwp_linux_buffer_params.h b/chromium/ui/ozone/platform/wayland/test/test_zwp_linux_buffer_params.h index bd518fee56d..40829b78ab6 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_zwp_linux_buffer_params.h +++ b/chromium/ui/ozone/platform/wayland/test/test_zwp_linux_buffer_params.h @@ -8,6 +8,7 @@ #include <linux-dmabuf-unstable-v1-server-protocol.h> #include "base/files/scoped_file.h" +#include "base/memory/raw_ptr.h" #include "testing/gmock/include/gmock/gmock.h" #include "ui/ozone/platform/wayland/test/server_object.h" @@ -70,11 +71,11 @@ class TestZwpLinuxBufferParamsV1 : public ServerObject { // Non-owned pointer to the linux dmabuf object, which created this params // resource and holds a pointer to it. On destruction, must notify it about // going out of scope. - MockZwpLinuxDmabufV1* linux_dmabuf_ = nullptr; + raw_ptr<MockZwpLinuxDmabufV1> linux_dmabuf_ = nullptr; // A buffer resource, which is created on Create or CreateImmed call. Can be // null if not created/failed to be created. - wl_resource* buffer_resource_ = nullptr; + raw_ptr<wl_resource> buffer_resource_ = nullptr; }; } // namespace wl diff --git a/chromium/ui/ozone/platform/wayland/test/test_zwp_linux_explicit_synchronization.h b/chromium/ui/ozone/platform/wayland/test/test_zwp_linux_explicit_synchronization.h index 4b817fa76d8..f4fe0af4976 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_zwp_linux_explicit_synchronization.h +++ b/chromium/ui/ozone/platform/wayland/test/test_zwp_linux_explicit_synchronization.h @@ -5,6 +5,7 @@ #ifndef UI_OZONE_PLATFORM_WAYLAND_TEST_TEST_ZWP_LINUX_EXPLICIT_SYNCHRONIZATION_H_ #define UI_OZONE_PLATFORM_WAYLAND_TEST_TEST_ZWP_LINUX_EXPLICIT_SYNCHRONIZATION_H_ +#include "base/memory/raw_ptr.h" #include "ui/ozone/platform/wayland/test/global_object.h" #include "ui/ozone/platform/wayland/test/server_object.h" @@ -20,7 +21,7 @@ class TestLinuxSurfaceSynchronization : public ServerObject { wl_resource* surface_resource() const { return surface_resource_; } private: - wl_resource* surface_resource_; + raw_ptr<wl_resource> surface_resource_; }; // Manage wl_viewporter object. diff --git a/chromium/ui/ozone/platform/wayland/test/test_zwp_text_input_manager.h b/chromium/ui/ozone/platform/wayland/test/test_zwp_text_input_manager.h index 44cbdd1129b..4a04634cdfb 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_zwp_text_input_manager.h +++ b/chromium/ui/ozone/platform/wayland/test/test_zwp_text_input_manager.h @@ -7,6 +7,7 @@ #include <text-input-unstable-v1-server-protocol.h> +#include "base/memory/raw_ptr.h" #include "ui/ozone/platform/wayland/test/global_object.h" namespace wl { @@ -33,7 +34,7 @@ class TestZwpTextInputManagerV1 : public GlobalObject { MockZwpTextInput* text_input() const { return text_input_; } private: - MockZwpTextInput* text_input_; + raw_ptr<MockZwpTextInput> text_input_; }; } // namespace wl 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 index 9c1397c0bc1..e1c390ffebc 100644 --- a/chromium/ui/ozone/platform/wayland/test/wayland_drag_drop_test.cc +++ b/chromium/ui/ozone/platform/wayland/test/wayland_drag_drop_test.cc @@ -71,6 +71,7 @@ void WaylandDragDropTest::SendPointerEnter( window->root_surface()->GetSurfaceId()); wl_pointer_send_enter(pointer_->resource(), NextSerial(), surface->resource(), 0, 0); + wl_pointer_send_frame(pointer_->resource()); } void WaylandDragDropTest::SendPointerLeave( @@ -80,6 +81,7 @@ void WaylandDragDropTest::SendPointerLeave( window->root_surface()->GetSurfaceId()); wl_pointer_send_leave(pointer_->resource(), NextSerial(), surface->resource()); + wl_pointer_send_frame(pointer_->resource()); } void WaylandDragDropTest::SendPointerButton( 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 index eaf4c633886..460068e06f9 100644 --- a/chromium/ui/ozone/platform/wayland/test/wayland_drag_drop_test.h +++ b/chromium/ui/ozone/platform/wayland/test/wayland_drag_drop_test.h @@ -8,6 +8,7 @@ #include <cstdint> #include "base/callback_forward.h" +#include "base/memory/raw_ptr.h" #include "testing/gmock/include/gmock/gmock.h" #include "ui/ozone/platform/wayland/test/test_data_device.h" #include "ui/ozone/platform/wayland/test/test_data_source.h" @@ -92,10 +93,10 @@ class WaylandDragDropTest : public WaylandTest, } // Server objects - wl::TestDataDeviceManager* data_device_manager_; - wl::TestDataSource* data_source_; - wl::MockPointer* pointer_; - wl::TestTouch* touch_; + raw_ptr<wl::TestDataDeviceManager> data_device_manager_; + raw_ptr<wl::TestDataSource> data_source_; + raw_ptr<wl::MockPointer> pointer_; + raw_ptr<wl::TestTouch> touch_; uint32_t current_serial_; }; diff --git a/chromium/ui/ozone/platform/wayland/test/wayland_ozone_ui_controls_test_helper.cc b/chromium/ui/ozone/platform/wayland/test/wayland_ozone_ui_controls_test_helper.cc index 90a26c0bd89..5fb61caf255 100644 --- a/chromium/ui/ozone/platform/wayland/test/wayland_ozone_ui_controls_test_helper.cc +++ b/chromium/ui/ozone/platform/wayland/test/wayland_ozone_ui_controls_test_helper.cc @@ -3,9 +3,11 @@ // found in the LICENSE file. #include "ui/ozone/platform/wayland/test/wayland_ozone_ui_controls_test_helper.h" +#include "base/memory/raw_ptr.h" #include <linux/input.h> +#include "base/run_loop.h" #include "base/threading/thread_task_runner_handle.h" #include "ui/events/keycodes/dom/keycode_converter.h" #include "ui/events/keycodes/keyboard_code_conversion.h" @@ -28,39 +30,14 @@ class WaylandGlobalEventWaiter : public WaylandInputEmulate::Observer { kMotion, kButton, kKey, + kTouch, kUnknown, }; - static WaylandGlobalEventWaiter* Create(WaylandEventType event_type, - int button, - bool pressed, - base::OnceClosure closure, - WaylandInputEmulate* emulate) { - DCHECK_NE(event_type, WaylandEventType::kUnknown); - return closure.is_null() - ? nullptr - : new WaylandGlobalEventWaiter(event_type, button, pressed, - std::move(closure), emulate); - } - - static WaylandGlobalEventWaiter* Create(WaylandEventType event_type, - const gfx::Point& screen_point, - base::OnceClosure closure, - WaylandInputEmulate* emulate) { - DCHECK_NE(event_type, WaylandEventType::kUnknown); - return closure.is_null() - ? nullptr - : new WaylandGlobalEventWaiter(event_type, screen_point, - std::move(closure), emulate); - } - - private: WaylandGlobalEventWaiter(WaylandEventType event_type, const gfx::Point& screen_point, - base::OnceClosure closure, WaylandInputEmulate* emulate) : event_type_(event_type), - closure_(std::move(closure)), emulate_(emulate), screen_point_(screen_point) { Initialize(); @@ -69,57 +46,94 @@ class WaylandGlobalEventWaiter : public WaylandInputEmulate::Observer { WaylandGlobalEventWaiter(WaylandEventType event_type, int button, bool pressed, - base::OnceClosure closure, WaylandInputEmulate* emulate) : event_type_(event_type), - closure_(std::move(closure)), emulate_(emulate), button_or_key_(button), pressed_(pressed) { Initialize(); } + ~WaylandGlobalEventWaiter() override = default; + + // This method assumes that a request has already been queued, with metadata + // for the expected response stored on the WaylandGlobalEventWaiter. This: + // * Flushes queued requests. + // * Spins a nested run loop waiting for the expected response (event). + // * When the event is received, synchronously flushes all pending + // requests and events via wl_display_roundtrip_queue. See + // https://crbug.com/1336706#c11 for why this is necessary. + // * Dispatches the QuitClosure to avoid re-entrancy. + void Wait() { + // There's no guarantee that a flush has been scheduled. Given that we're + // waiting for a response, we must manually flush. + wl::WaylandProxy::GetInstance()->FlushForTesting(); + + // We disallow nestable tasks as that can result in re-entrancy if the test + // is listening for side-effects from a wayland-event and then calls + // PostTask. By using a non-nestable run loop we are relying on the + // assumption that the ozone-wayland implementation does not rely on + // PostTask. + base::RunLoop run_loop; + + // This will be invoked causing the run-loop to quit once the expected event + // is received. + quit_closure_ = run_loop.QuitClosure(); + run_loop.Run(); + } - ~WaylandGlobalEventWaiter() override { emulate_->RemoveObserver(this); } - + private: void Initialize() { DCHECK_NE(event_type_, WaylandEventType::kUnknown); - DCHECK(!closure_.is_null()); emulate_->AddObserver(this); } void OnPointerMotionGlobal(const gfx::Point& screen_position) override { if (event_type_ == WaylandEventType::kMotion) { - ExecuteClosure(); + QuitRunLoop(); } } void OnPointerButtonGlobal(int32_t button, bool pressed) override { if (event_type_ == WaylandEventType::kButton && button_or_key_ == button && pressed == pressed_) { - ExecuteClosure(); + QuitRunLoop(); } } void OnKeyboardKey(int32_t key, bool pressed) override { if (event_type_ == WaylandEventType::kKey && button_or_key_ == key && pressed == pressed_) { - ExecuteClosure(); + QuitRunLoop(); } } - void ExecuteClosure() { - DCHECK(!closure_.is_null()); - base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - std::move(closure_)); - delete this; + void OnTouchReceived(const gfx::Point& screen_position) override { + if (event_type_ == WaylandEventType::kTouch) { + QuitRunLoop(); + } + } + + void QuitRunLoop() { + // Immediately remove the observer so that no further callbacks are posted. + emulate_->RemoveObserver(this); + + // The weston-test protocol does not map cleanly onto ui controls semantics. + // We need to wait for a wayland round-trip to ensure that all side-effects + // have been processed. See https://crbug.com/1336706#c11 for details. + wl::WaylandProxy::GetInstance()->RoundTripQueue(); + + // We're in a nested run-loop that doesn't support re-entrancy. Directly + // invoke the quit closure. + std::move(quit_closure_).Run(); } // Expected event type. WaylandEventType event_type_ = WaylandEventType::kUnknown; - base::OnceClosure closure_; + // Internal closure used to quit the nested run loop. + base::RepeatingClosure quit_closure_; - WaylandInputEmulate* const emulate_; + const raw_ptr<WaylandInputEmulate> emulate_; // Expected pointer location on screen. gfx::Point screen_point_; @@ -159,13 +173,20 @@ void WaylandOzoneUIControlsTestHelper::SendKeyPressEvent( void WaylandOzoneUIControlsTestHelper::SendMouseMotionNotifyEvent( gfx::AcceleratedWidget widget, const gfx::Point& mouse_loc, - const gfx::Point& mouse_root_loc, + const gfx::Point& mouse_screen_loc_in_px, base::OnceClosure closure) { - WaylandGlobalEventWaiter::Create( + WaylandGlobalEventWaiter waiter( WaylandGlobalEventWaiter::WaylandEventType::kMotion, mouse_loc, - std::move(closure), input_emulate_.get()); + input_emulate_.get()); + input_emulate_->EmulatePointerMotion(widget, mouse_loc, + mouse_screen_loc_in_px); + waiter.Wait(); - input_emulate_->EmulatePointerMotion(widget, mouse_loc); + if (!closure.is_null()) { + // PostTask to avoid re-entrancy. + base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, + std::move(closure)); + } } void WaylandOzoneUIControlsTestHelper::SendMouseEvent( @@ -174,7 +195,7 @@ void WaylandOzoneUIControlsTestHelper::SendMouseEvent( int button_state, int accelerator_state, const gfx::Point& mouse_loc, - const gfx::Point& mouse_root_loc, + const gfx::Point& mouse_screen_loc_in_px, base::OnceClosure closure) { uint32_t changed_button = 0; switch (type) { @@ -191,6 +212,8 @@ void WaylandOzoneUIControlsTestHelper::SendMouseEvent( NOTREACHED(); } + SendMouseMotionNotifyEvent(widget, mouse_loc, mouse_screen_loc_in_px, {}); + // Press accelerator keys. if (accelerator_state) { SendKeyPressInternal(widget, ui::KeyboardCode::VKEY_UNKNOWN, @@ -200,21 +223,23 @@ void WaylandOzoneUIControlsTestHelper::SendMouseEvent( accelerator_state & ui_controls::kCommand, {}, true); } - SendMouseMotionNotifyEvent(widget, mouse_loc, mouse_root_loc, {}); - - WaylandGlobalEventWaiter::Create( - WaylandGlobalEventWaiter::WaylandEventType::kButton, changed_button, - button_state & DOWN, std::move(closure), input_emulate_.get()); - if (button_state & DOWN) { + WaylandGlobalEventWaiter waiter( + WaylandGlobalEventWaiter::WaylandEventType::kButton, changed_button, + /*pressed=*/true, input_emulate_.get()); input_emulate_->EmulatePointerButton( widget, ui::EventType::ET_MOUSE_PRESSED, changed_button); button_down_mask_ |= changed_button; + waiter.Wait(); } if (button_state & UP) { + WaylandGlobalEventWaiter waiter( + WaylandGlobalEventWaiter::WaylandEventType::kButton, changed_button, + /*pressed=*/false, input_emulate_.get()); input_emulate_->EmulatePointerButton( widget, ui::EventType::ET_MOUSE_RELEASED, changed_button); button_down_mask_ = (button_down_mask_ | changed_button) ^ changed_button; + waiter.Wait(); } // Depress accelerator keys. @@ -225,8 +250,47 @@ void WaylandOzoneUIControlsTestHelper::SendMouseEvent( accelerator_state & ui_controls::kAlt, accelerator_state & ui_controls::kCommand, {}, false); } + if (!closure.is_null()) { + // PostTask to avoid re-entrancy. + base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, + std::move(closure)); + } } +#if BUILDFLAG(IS_CHROMEOS_LACROS) +void WaylandOzoneUIControlsTestHelper::SendTouchEvent( + gfx::AcceleratedWidget widget, + int action, + int id, + const gfx::Point& touch_loc, + base::OnceClosure closure) { + // TODO(rivr): ui_controls::TouchType is a bitmask, do we need to handle the + // case where multiple actions are requested together? + ui::EventType event_type; + switch (action) { + case ui_controls::PRESS: + event_type = ui::EventType::ET_TOUCH_PRESSED; + break; + case ui_controls::RELEASE: + event_type = ui::EventType::ET_TOUCH_RELEASED; + break; + default: + event_type = ui::EventType::ET_TOUCH_MOVED; + } + + WaylandGlobalEventWaiter waiter( + WaylandGlobalEventWaiter::WaylandEventType::kTouch, touch_loc, + input_emulate_.get()); + input_emulate_->EmulateTouch(widget, event_type, id, touch_loc); + waiter.Wait(); + if (!closure.is_null()) { + // PostTask to avoid re-entrancy. + base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, + std::move(closure)); + } +} +#endif + void WaylandOzoneUIControlsTestHelper::RunClosureAfterAllPendingUIEvents( base::OnceClosure closure) { NOTREACHED(); @@ -247,39 +311,45 @@ void WaylandOzoneUIControlsTestHelper::SendKeyPressInternal( bool press_key) { auto dom_code = UsLayoutKeyboardCodeToDomCode(key); - WaylandGlobalEventWaiter::Create( - WaylandGlobalEventWaiter::WaylandEventType::kKey, - ui::KeycodeConverter::DomCodeToEvdevCode(dom_code), press_key, - std::move(closure), input_emulate_.get()); - if (press_key) { - if (control) + if (control) { DispatchKeyPress(widget, ui::EventType::ET_KEY_PRESSED, ui::DomCode::CONTROL_LEFT); + } - if (shift) + if (shift) { DispatchKeyPress(widget, ui::EventType::ET_KEY_PRESSED, ui::DomCode::SHIFT_LEFT); + } - if (alt) + if (alt) { DispatchKeyPress(widget, ui::EventType::ET_KEY_PRESSED, ui::DomCode::ALT_LEFT); + } DispatchKeyPress(widget, ui::EventType::ET_KEY_PRESSED, dom_code); } else { DispatchKeyPress(widget, ui::EventType::ET_KEY_RELEASED, dom_code); - if (alt) - DispatchKeyPress(widget, ui::EventType::ET_KEY_RELEASED, + if (alt) { + DispatchKeyPress(/*widget=*/0, ui::EventType::ET_KEY_RELEASED, ui::DomCode::ALT_LEFT); + } - if (shift) - DispatchKeyPress(widget, ui::EventType::ET_KEY_RELEASED, + if (shift) { + DispatchKeyPress(/*widget=*/0, ui::EventType::ET_KEY_RELEASED, ui::DomCode::SHIFT_LEFT); + } - if (control) - DispatchKeyPress(widget, ui::EventType::ET_KEY_RELEASED, + if (control) { + DispatchKeyPress(/*widget=*/0, ui::EventType::ET_KEY_RELEASED, ui::DomCode::CONTROL_LEFT); + } + } + if (!closure.is_null()) { + // PostTask to avoid re-entrancy. + base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, + std::move(closure)); } } @@ -287,7 +357,13 @@ void WaylandOzoneUIControlsTestHelper::DispatchKeyPress( gfx::AcceleratedWidget widget, ui::EventType event_type, ui::DomCode dom_code) { + WaylandGlobalEventWaiter waiter( + WaylandGlobalEventWaiter::WaylandEventType::kKey, + ui::KeycodeConverter::DomCodeToEvdevCode(dom_code), + /*press_key=*/event_type == ui::EventType::ET_KEY_PRESSED, + input_emulate_.get()); input_emulate_->EmulateKeyboardKey(widget, event_type, dom_code); + waiter.Wait(); } } // namespace wl diff --git a/chromium/ui/ozone/platform/wayland/test/wayland_ozone_ui_controls_test_helper.h b/chromium/ui/ozone/platform/wayland/test/wayland_ozone_ui_controls_test_helper.h index e89aff57835..2264adf1196 100644 --- a/chromium/ui/ozone/platform/wayland/test/wayland_ozone_ui_controls_test_helper.h +++ b/chromium/ui/ozone/platform/wayland/test/wayland_ozone_ui_controls_test_helper.h @@ -41,6 +41,13 @@ class WaylandOzoneUIControlsTestHelper : public ui::OzoneUIControlsTestHelper { const gfx::Point& mouse_loc, const gfx::Point& mouse_root_loc, base::OnceClosure closure) override; +#if BUILDFLAG(IS_CHROMEOS_LACROS) + void SendTouchEvent(gfx::AcceleratedWidget widget, + int action, + int id, + const gfx::Point& touch_loc, + base::OnceClosure closure) override; +#endif void RunClosureAfterAllPendingUIEvents(base::OnceClosure closure) override; bool MustUseUiControlsForMoveCursorTo() override; diff --git a/chromium/ui/ozone/platform/wayland/test/wayland_test.cc b/chromium/ui/ozone/platform/wayland/test/wayland_test.cc index ef738bf62b8..bf061055f76 100644 --- a/chromium/ui/ozone/platform/wayland/test/wayland_test.cc +++ b/chromium/ui/ozone/platform/wayland/test/wayland_test.cc @@ -50,6 +50,9 @@ WaylandTest::WaylandTest() WaylandTest::~WaylandTest() {} void WaylandTest::SetUp() { + disabled_features_.push_back(ui::kWaylandSurfaceSubmissionInPixelCoordinates); + disabled_features_.push_back(features::kWaylandScreenCoordinatesEnabled); + feature_list_.InitWithFeatures(enabled_features_, disabled_features_); if (DeviceDataManager::HasInstance()) { @@ -115,11 +118,20 @@ void WaylandTest::Sync() { server_.Pause(); } +void WaylandTest::SetPointerFocusedWindow(WaylandWindow* window) { + connection_->wayland_window_manager()->SetPointerFocusedWindow(window); +} + +void WaylandTest::SetKeyboardFocusedWindow(WaylandWindow* window) { + connection_->wayland_window_manager()->SetKeyboardFocusedWindow(window); +} + void WaylandTest::SendConfigureEvent(wl::MockXdgSurface* xdg_surface, - int width, - int height, + const gfx::Size& size, uint32_t serial, struct wl_array* states) { + const int32_t width = size.width(); + const int32_t height = size.height(); // In xdg_shell_v6+, both surfaces send serial configure event and toplevel // surfaces send other data like states, heights and widths. // Please note that toplevel surfaces may not exist if the surface was created @@ -128,12 +140,20 @@ void WaylandTest::SendConfigureEvent(wl::MockXdgSurface* xdg_surface, if (xdg_surface->xdg_toplevel()) { zxdg_toplevel_v6_send_configure(xdg_surface->xdg_toplevel()->resource(), width, height, states); + } else { + ASSERT_TRUE(xdg_surface->xdg_popup()->resource()); + zxdg_popup_v6_send_configure(xdg_surface->xdg_popup()->resource(), 0, 0, + width, height); } zxdg_surface_v6_send_configure(xdg_surface->resource(), serial); } else { if (xdg_surface->xdg_toplevel()) { xdg_toplevel_send_configure(xdg_surface->xdg_toplevel()->resource(), width, height, states); + } else { + ASSERT_TRUE(xdg_surface->xdg_popup()->resource()); + xdg_popup_send_configure(xdg_surface->xdg_popup()->resource(), 0, 0, + width, height); } xdg_surface_send_configure(xdg_surface->resource(), serial); } @@ -141,7 +161,7 @@ void WaylandTest::SendConfigureEvent(wl::MockXdgSurface* xdg_surface, void WaylandTest::ActivateSurface(wl::MockXdgSurface* xdg_surface) { wl::ScopedWlArray state({XDG_TOPLEVEL_STATE_ACTIVATED}); - SendConfigureEvent(xdg_surface, 0, 0, 1, state.get()); + SendConfigureEvent(xdg_surface, {0, 0}, 1, state.get()); } void WaylandTest::InitializeSurfaceAugmenter() { diff --git a/chromium/ui/ozone/platform/wayland/test/wayland_test.h b/chromium/ui/ozone/platform/wayland/test/wayland_test.h index a27417c19b9..cb7ee9fceab 100644 --- a/chromium/ui/ozone/platform/wayland/test/wayland_test.h +++ b/chromium/ui/ozone/platform/wayland/test/wayland_test.h @@ -7,6 +7,7 @@ #include <memory> +#include "base/memory/raw_ptr.h" #include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" #include "testing/gtest/include/gtest/gtest.h" @@ -51,10 +52,12 @@ class WaylandTest : public ::testing::TestWithParam<wl::ServerConfig> { void Sync(); protected: + void SetPointerFocusedWindow(WaylandWindow* window); + void SetKeyboardFocusedWindow(WaylandWindow* window); + // Sends configure event for the |xdg_surface|. void SendConfigureEvent(wl::MockXdgSurface* xdg_surface, - int width, - int height, + const gfx::Size& size, uint32_t serial, struct wl_array* states); @@ -69,7 +72,7 @@ class WaylandTest : public ::testing::TestWithParam<wl::ServerConfig> { base::test::TaskEnvironment task_environment_; wl::TestWaylandServerThread server_; - wl::MockSurface* surface_; + raw_ptr<wl::MockSurface> surface_; MockWaylandPlatformWindowDelegate delegate_; std::unique_ptr<ScopedKeyboardLayoutEngine> scoped_keyboard_layout_engine_; 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 2d5b889f437..58804a06caf 100644 --- a/chromium/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc +++ b/chromium/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc @@ -10,10 +10,12 @@ #include "base/files/file_path.h" #include "base/files/file_util.h" +#include "base/memory/raw_ptr.h" #include "base/test/mock_callback.h" #include "mojo/public/cpp/system/platform_handle.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/rect_conversions.h" #include "ui/gfx/geometry/rect_f.h" #include "ui/gfx/geometry/rounded_corners_f.h" @@ -26,6 +28,7 @@ #include "ui/ozone/platform/wayland/common/wayland_overlay_config.h" #include "ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.h" #include "ui/ozone/platform/wayland/gpu/wayland_surface_gpu.h" +#include "ui/ozone/platform/wayland/host/wayland_buffer_factory.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_subsurface.h" @@ -36,6 +39,7 @@ #include "ui/ozone/platform/wayland/test/test_overlay_prioritized_surface.h" #include "ui/ozone/platform/wayland/test/test_zwp_linux_buffer_params.h" #include "ui/ozone/platform/wayland/test/wayland_test.h" +#include "ui/platform_window/platform_window_init_properties.h" using testing::_; using testing::Truly; @@ -89,7 +93,7 @@ class MockSurfaceGpu : public WaylandSurfaceGpu { const gfx::PresentationFeedback& feedback)); private: - WaylandBufferManagerGpu* const buffer_manager_; + const raw_ptr<WaylandBufferManagerGpu> buffer_manager_; const gfx::AcceleratedWidget widget_; }; @@ -118,8 +122,8 @@ class WaylandBufferManagerTest : public WaylandTest { false, kAugmentedSurfaceNotSupportedVersion); - window_->set_update_visual_size_immediately(false); - window_->set_apply_pending_state_on_update_visual_size(false); + window_->set_update_visual_size_immediately_for_testing(false); + window_->set_apply_pending_state_on_update_visual_size_for_testing(false); } protected: @@ -147,22 +151,23 @@ class WaylandBufferManagerTest : public WaylandTest { } else { EXPECT_CALL(*callback, Run(_)) .Times(1) - .WillRepeatedly(::testing::Invoke([this, callback]( - std::string error_string) { - channel_destroyed_error_message_ = error_string; - - manager_host_->OnChannelDestroyed(); - - manager_host_->SetTerminateGpuCallback(callback->Get()); - - auto interface_ptr = manager_host_->BindInterface(); - // 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), {}, false, true, false, - kAugmentedSurfaceNotSupportedVersion); - })); + .WillRepeatedly( + ::testing::Invoke([this, callback](std::string error_string) { + channel_destroyed_error_message_ = error_string; + + manager_host_->OnChannelDestroyed(); + + manager_host_->SetTerminateGpuCallback(callback->Get()); + + auto interface_ptr = manager_host_->BindInterface(); + // 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), {}, false, true, false, + kAugmentedSurfaceNotSupportedVersion); + })); } } @@ -265,7 +270,7 @@ class WaylandBufferManagerTest : public WaylandTest { } MockTerminateGpuCallback callback_; - WaylandBufferManagerHost* manager_host_; + raw_ptr<WaylandBufferManagerHost> manager_host_; // Error message that is received when the manager_host destroys the channel. std::string channel_destroyed_error_message_; }; @@ -299,7 +304,8 @@ TEST_P(WaylandBufferManagerTest, VerifyModifiers) { Sync(); - auto buffer_formats = connection_->zwp_dmabuf()->supported_buffer_formats(); + auto buffer_formats = + connection_->wayland_buffer_factory()->GetSupportedBufferFormats(); DCHECK_EQ(buffer_formats.size(), 1u); DCHECK_EQ(buffer_formats.begin()->first, GetBufferFormatFromFourCCFormat(kFourccFormatR8)); @@ -398,7 +404,7 @@ TEST_P(WaylandBufferManagerTest, CreateAndDestroyBuffer) { buffer_manager_gpu_->CommitBuffer( widget, kBufferId1, kBufferId1, window_->GetBoundsInPixels(), - kDefaultScale, window_->GetBoundsInPixels()); + gfx::RoundedCornersF(), kDefaultScale, gfx::Rect(window_->size_px())); CreateDmabufBasedBufferAndSetTerminateExpectation(true /*fail*/, kBufferId1); @@ -421,7 +427,7 @@ TEST_P(WaylandBufferManagerTest, CreateAndDestroyBuffer) { buffer_manager_gpu_->CommitBuffer( widget, kBufferId1, kBufferId1, window_->GetBoundsInPixels(), - kDefaultScale, window_->GetBoundsInPixels()); + gfx::RoundedCornersF(), kDefaultScale, gfx::Rect(window_->size_px())); DestroyBufferAndSetTerminateExpectation(kBufferId1, false /*fail*/); } @@ -443,7 +449,7 @@ TEST_P(WaylandBufferManagerTest, CreateAndDestroyBuffer) { // Attach to a surface. buffer_manager_gpu_->CommitBuffer( widget, kBufferId1, kBufferId1, window_->GetBoundsInPixels(), - kDefaultScale, window_->GetBoundsInPixels()); + gfx::RoundedCornersF(), kDefaultScale, gfx::Rect(window_->size_px())); // Created non-attached buffer as well. CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/, @@ -482,9 +488,9 @@ TEST_P(WaylandBufferManagerTest, CommitBufferNonExistingBufferId) { EXPECT_CALL(*mock_surface, Frame(_)).Times(kNumberOfCommits); EXPECT_CALL(*mock_surface, Commit()).Times(kNumberOfCommits); - buffer_manager_gpu_->CommitBuffer(window_->GetWidget(), 1u, 5u, - window_->GetBoundsInPixels(), kDefaultScale, - window_->GetBoundsInPixels()); + buffer_manager_gpu_->CommitBuffer( + window_->GetWidget(), 1u, 5u, window_->GetBoundsInPixels(), + gfx::RoundedCornersF(), kDefaultScale, gfx::Rect(window_->size_px())); Sync(); } @@ -549,9 +555,9 @@ TEST_P(WaylandBufferManagerTest, CommitBufferNullWidget) { // Can't commit for non-existing widget. SetTerminateCallbackExpectationAndDestroyChannel(&callback_, true /*fail*/); - buffer_manager_gpu_->CommitBuffer(gfx::kNullAcceleratedWidget, 1u, kBufferId, - window_->GetBoundsInPixels(), kDefaultScale, - window_->GetBoundsInPixels()); + buffer_manager_gpu_->CommitBuffer( + gfx::kNullAcceleratedWidget, 1u, kBufferId, window_->GetBoundsInPixels(), + gfx::RoundedCornersF(), kDefaultScale, gfx::Rect(window_->size_px())); Sync(); } @@ -594,7 +600,7 @@ TEST_P(WaylandBufferManagerTest, EnsureCorrectOrderOfCallbacks) { const gfx::AcceleratedWidget widget = window_->GetWidget(); const gfx::Rect bounds = gfx::Rect({0, 0}, kDefaultSize); - window_->SetBoundsInPixels(bounds); + window_->SetBoundsInDIP(bounds); MockSurfaceGpu mock_surface_gpu(buffer_manager_gpu_.get(), widget_); @@ -627,7 +633,8 @@ TEST_P(WaylandBufferManagerTest, EnsureCorrectOrderOfCallbacks) { EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId1, _)).Times(1); buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, kBufferId1, bounds, - kDefaultScale, bounds); + gfx::RoundedCornersF(), kDefaultScale, + bounds); Sync(); @@ -639,7 +646,8 @@ TEST_P(WaylandBufferManagerTest, EnsureCorrectOrderOfCallbacks) { // Commit second buffer now. buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, kBufferId2, bounds, - kDefaultScale, bounds); + gfx::RoundedCornersF(), kDefaultScale, + bounds); Sync(); @@ -669,7 +677,8 @@ TEST_P(WaylandBufferManagerTest, EnsureCorrectOrderOfCallbacks) { // Commit second buffer now. buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, kBufferId1, bounds, - kDefaultScale, bounds); + gfx::RoundedCornersF(), kDefaultScale, + bounds); Sync(); @@ -706,7 +715,7 @@ TEST_P(WaylandBufferManagerTest, const gfx::AcceleratedWidget widget = window_->GetWidget(); const gfx::Rect bounds = gfx::Rect({0, 0}, kDefaultSize); - window_->SetBoundsInPixels(bounds); + window_->SetBoundsInDIP(bounds); MockSurfaceGpu mock_surface_gpu(buffer_manager_gpu_.get(), widget_); @@ -747,7 +756,8 @@ TEST_P(WaylandBufferManagerTest, OnSubmission(kBufferId1, gfx::SwapResult::SWAP_ACK, _)) .Times(1); buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, kBufferId1, bounds, - kDefaultScale, bounds); + gfx::RoundedCornersF(), kDefaultScale, + bounds); mock_surface->SendFrameCallback(); Sync(); @@ -757,7 +767,8 @@ TEST_P(WaylandBufferManagerTest, // Commit second buffer now. buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, kBufferId2, bounds, - kDefaultScale, bounds); + gfx::RoundedCornersF(), kDefaultScale, + bounds); mock_surface->SendFrameCallback(); Sync(); @@ -779,7 +790,8 @@ TEST_P(WaylandBufferManagerTest, // not call OnPresentation as OnSubmission hasn't been called yet. EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(0); buffer_manager_gpu_->CommitBuffer(widget, kBufferId3, kBufferId3, bounds, - kDefaultScale, bounds); + gfx::RoundedCornersF(), kDefaultScale, + bounds); mock_surface->SendFrameCallback(); mock_wp_presentation->SendPresentationCallback(); Sync(); @@ -830,7 +842,7 @@ TEST_P(WaylandBufferManagerTest, const gfx::AcceleratedWidget widget = window_->GetWidget(); const gfx::Rect bounds = gfx::Rect({0, 0}, kDefaultSize); - window_->SetBoundsInPixels(bounds); + window_->SetBoundsInDIP(bounds); MockSurfaceGpu mock_surface_gpu(buffer_manager_gpu_.get(), widget_); @@ -862,7 +874,8 @@ TEST_P(WaylandBufferManagerTest, // Commit first buffer buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, kBufferId1, bounds, - kDefaultScale, bounds); + gfx::RoundedCornersF(), kDefaultScale, + bounds); Sync(); @@ -881,7 +894,8 @@ TEST_P(WaylandBufferManagerTest, // Commit second buffer buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, kBufferId2, bounds, - kDefaultScale, bounds); + gfx::RoundedCornersF(), kDefaultScale, + bounds); Sync(); @@ -902,7 +916,8 @@ TEST_P(WaylandBufferManagerTest, // Commit third buffer buffer_manager_gpu_->CommitBuffer(widget, kBufferId3, kBufferId3, bounds, - kDefaultScale, bounds); + gfx::RoundedCornersF(), kDefaultScale, + bounds); Sync(); @@ -986,9 +1001,9 @@ TEST_P(WaylandBufferManagerTest, TestCommitBufferConditions) { EXPECT_CALL(*mock_surface, Frame(_)).Times(0); EXPECT_CALL(*mock_surface, Commit()).Times(0); - buffer_manager_gpu_->CommitBuffer(widget, kDmabufBufferId, kDmabufBufferId, - window_->GetBoundsInPixels(), kDefaultScale, - window_->GetBoundsInPixels()); + buffer_manager_gpu_->CommitBuffer( + widget, kDmabufBufferId, kDmabufBufferId, window_->GetBoundsInPixels(), + gfx::RoundedCornersF(), kDefaultScale, gfx::Rect(window_->size_px())); Sync(); EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(1); @@ -1020,9 +1035,9 @@ TEST_P(WaylandBufferManagerTest, TestCommitBufferConditions) { EXPECT_CALL(*mock_surface, Frame(_)).Times(0); EXPECT_CALL(*mock_surface, Commit()).Times(0); - buffer_manager_gpu_->CommitBuffer(widget, kDmabufBufferId2, kDmabufBufferId2, - window_->GetBoundsInPixels(), kDefaultScale, - window_->GetBoundsInPixels()); + buffer_manager_gpu_->CommitBuffer( + widget, kDmabufBufferId2, kDmabufBufferId2, window_->GetBoundsInPixels(), + gfx::RoundedCornersF(), kDefaultScale, gfx::Rect(window_->size_px())); Sync(); @@ -1074,28 +1089,36 @@ TEST_P(WaylandBufferManagerTest, TestCommitBufferConditionsAckConfigured) { Sync(); + auto* xdg_surface = mock_surface->xdg_surface(); + ASSERT_TRUE(xdg_surface); + ASSERT_FALSE(temp_window->IsSurfaceConfigured()); + ProcessCreatedBufferResourcesWithExpectation(1u /* expected size */, false /* fail */); + EXPECT_CALL(*xdg_surface, SetWindowGeometry(_)).Times(0); + EXPECT_CALL(*xdg_surface, AckConfigure(_)).Times(0); EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(0); EXPECT_CALL(*mock_surface, Frame(_)).Times(0); EXPECT_CALL(*mock_surface, Commit()).Times(0); buffer_manager_gpu_->CommitBuffer( widget, kDmabufBufferId, kDmabufBufferId, window_->GetBoundsInPixels(), - kDefaultScale, window_->GetBoundsInPixels()); + gfx::RoundedCornersF(), kDefaultScale, window_->GetBoundsInPixels()); Sync(); + testing::Mock::VerifyAndClearExpectations(mock_surface); - DCHECK(mock_surface->xdg_surface()); - ActivateSurface(mock_surface->xdg_surface()); - + EXPECT_CALL(*xdg_surface, SetWindowGeometry(gfx::Rect(800, 600))).Times(1); + EXPECT_CALL(*xdg_surface, AckConfigure(_)).Times(1); EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(1); EXPECT_CALL(*mock_surface, Frame(_)).Times(1); EXPECT_CALL(*mock_surface, Commit()).Times(1); + ActivateSurface(mock_surface->xdg_surface()); Sync(); + testing::Mock::VerifyAndClearExpectations(mock_surface); - window_->SetPointerFocus(false); + SetPointerFocusedWindow(nullptr); temp_window.reset(); DestroyBufferAndSetTerminateExpectation(kDmabufBufferId, false /*fail*/); @@ -1103,6 +1126,107 @@ TEST_P(WaylandBufferManagerTest, TestCommitBufferConditionsAckConfigured) { } } +// Verifies toplevel surfaces do not have buffers attached until configured, +// even when the initial configure sequence is not acked in response to +// xdg_surface.configure event, i.e: done asynchronously when UpdateVisualSize() +// is called by they FrameManager). +// +// Regression test for https://crbug.com/1313023. +TEST_P(WaylandBufferManagerTest, + CommitBufferConditionsWithDeferredAckConfigure) { + constexpr gfx::Rect kNormalBounds{800, 800}; + constexpr gfx::Rect kRestoredBounds{500, 500}; + constexpr uint32_t kDmabufBufferId = 1; + + testing::Mock::VerifyAndClearExpectations(&delegate_); + PlatformWindowInitProperties properties; + properties.type = PlatformWindowType::kWindow; + properties.bounds = kNormalBounds; + auto window = WaylandWindow::Create(&delegate_, connection_.get(), + std::move(properties)); + ASSERT_TRUE(window); + ASSERT_NE(window->GetWidget(), gfx::kNullAcceleratedWidget); + auto widget = window->GetWidget(); + + // Set restored bounds to a value different from the initial window bounds in + // order to force WaylandWindow::ProcessPendingBoundsDip() to defer the very + // first configure ack to be done in the subsequent UpdateVisualSize() call. + window->SetRestoredBoundsInDIP(kRestoredBounds); + + // Disable auto immediate visual size update (when, for example, calling into + // WaylandWindow::SetBoundsInPixels) so that we can emulate deferred call to + // WaylandToplevelWindow::UpdateVisualSize() with mismatching parameters, when + // processing initial frame sent by the GPU. + window->set_update_visual_size_immediately_for_testing(false); + window->set_apply_pending_state_on_update_visual_size_for_testing(false); + + Sync(); + + gfx::Insets insets; + window->SetDecorationInsets(&insets); + window->Show(false); + Sync(); + + auto* mock_surface = server_.GetObject<wl::MockSurface>( + window->root_surface()->GetSurfaceId()); + MockSurfaceGpu mock_surface_gpu(buffer_manager_gpu_.get(), widget); + + auto* linux_dmabuf = server_.zwp_linux_dmabuf_v1(); + EXPECT_CALL(*linux_dmabuf, CreateParams(_, _, _)).Times(1); + + CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/, + kDmabufBufferId); + + Sync(); + + auto* xdg_surface = mock_surface->xdg_surface(); + ASSERT_TRUE(xdg_surface); + ASSERT_FALSE(window->IsSurfaceConfigured()); + + ProcessCreatedBufferResourcesWithExpectation(1u /* expected size */, + false /* fail */); + + // Emulate the following steps: + // + // 1. A CommitBuffer request coming from the GPU service, with frame + // bounds that do not match the one stored in |pending_configures_| at Host + // side (filled when processing 0x0 initial configure sequence sent by the + // Wayland compositor. + // 2. The initial configure sequence (i.e: with 0x0 size which means the + // client must suggest the initial geometry of the surface. + // 3. And then a CommitBuffer with the expected bounds (ie: suggested to the + // Wayland compositor through a set_geometry/ack_configure sequence when + // processing (2). + // + // And ensures the xdg and wl_surface objects received the correct requests + // amount. I.e: No buffer attaches before setting geometry + acking initial + // configure sequence, etc. + + EXPECT_CALL(*xdg_surface, SetWindowGeometry(kRestoredBounds)).Times(1); + EXPECT_CALL(*xdg_surface, AckConfigure(1)).Times(1); + EXPECT_CALL(*mock_surface, Attach(_, 0, 0)).Times(1); + EXPECT_CALL(*mock_surface, Frame(_)).Times(1); + EXPECT_CALL(*mock_surface, Commit()).Times(1); + + buffer_manager_gpu_->CommitBuffer(widget, kDmabufBufferId, kDmabufBufferId, + gfx::Rect{55, 55}, gfx::RoundedCornersF(), + kDefaultScale, gfx::Rect{55, 55}); + ActivateSurface(mock_surface->xdg_surface()); + + Sync(); + + buffer_manager_gpu_->CommitBuffer(widget, kDmabufBufferId, kDmabufBufferId, + kRestoredBounds, gfx::RoundedCornersF(), + kDefaultScale, kRestoredBounds); + Sync(); + + SetPointerFocusedWindow(nullptr); + window.reset(); + DestroyBufferAndSetTerminateExpectation(kDmabufBufferId, false /*fail*/); + + Sync(); +} + // The buffer that is not originally attached to any of the surfaces, // must be attached when a commit request comes. Also, it must setup a buffer // release listener and OnSubmission must be called for that buffer if it is @@ -1114,7 +1238,7 @@ TEST_P(WaylandBufferManagerTest, AnonymousBufferAttachedAndReleased) { const gfx::AcceleratedWidget widget = window_->GetWidget(); const gfx::Rect bounds = gfx::Rect({0, 0}, kDefaultSize); - window_->SetBoundsInPixels(bounds); + window_->SetBoundsInDIP(bounds); MockSurfaceGpu mock_surface_gpu(buffer_manager_gpu_.get(), widget_); @@ -1144,7 +1268,8 @@ TEST_P(WaylandBufferManagerTest, AnonymousBufferAttachedAndReleased) { // Commit second buffer now. buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, kBufferId1, bounds, - kDefaultScale, bounds); + gfx::RoundedCornersF(), kDefaultScale, + bounds); Sync(); @@ -1169,7 +1294,8 @@ TEST_P(WaylandBufferManagerTest, AnonymousBufferAttachedAndReleased) { // Commit second buffer now. buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, kBufferId2, bounds, - kDefaultScale, bounds); + gfx::RoundedCornersF(), kDefaultScale, + bounds); Sync(); @@ -1194,7 +1320,8 @@ TEST_P(WaylandBufferManagerTest, AnonymousBufferAttachedAndReleased) { EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId3, _)).Times(0); buffer_manager_gpu_->CommitBuffer(widget, kBufferId3, kBufferId3, bounds, - kDefaultScale, bounds); + gfx::RoundedCornersF(), kDefaultScale, + bounds); Sync(); @@ -1232,7 +1359,7 @@ TEST_P(WaylandBufferManagerTest, DestroyBufferForDestroyedWindow) { buffer_manager_gpu_->CommitBuffer( widget, kBufferId, kBufferId, temp_window->GetBoundsInPixels(), - kDefaultScale, temp_window->GetBoundsInPixels()); + gfx::RoundedCornersF(), kDefaultScale, temp_window->GetBoundsInPixels()); Sync(); @@ -1265,7 +1392,8 @@ TEST_P(WaylandBufferManagerTest, DestroyedWindowNoSubmissionSingleBuffer) { temp_window.reset(); buffer_manager_gpu_->CommitBuffer(widget, kBufferId, kBufferId, bounds, - kDefaultScale, bounds); + gfx::RoundedCornersF(), kDefaultScale, + bounds); Sync(); @@ -1307,7 +1435,8 @@ TEST_P(WaylandBufferManagerTest, DestroyedWindowNoSubmissionMultipleBuffers) { EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(1); buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, kBufferId1, bounds, - kDefaultScale, bounds); + gfx::RoundedCornersF(), kDefaultScale, + bounds); Sync(); @@ -1328,7 +1457,8 @@ TEST_P(WaylandBufferManagerTest, DestroyedWindowNoSubmissionMultipleBuffers) { EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId2, _)).Times(1); buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, kBufferId2, bounds, - kDefaultScale, bounds); + gfx::RoundedCornersF(), kDefaultScale, + bounds); Sync(); @@ -1341,7 +1471,8 @@ TEST_P(WaylandBufferManagerTest, DestroyedWindowNoSubmissionMultipleBuffers) { temp_window.reset(); buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, kBufferId1, bounds, - kDefaultScale, bounds); + gfx::RoundedCornersF(), kDefaultScale, + bounds); Sync(); @@ -1378,7 +1509,8 @@ TEST_P(WaylandBufferManagerTest, DestroyBufferCommittedTwiceInARow) { EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId1, _)).Times(1); buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, kBufferId1, bounds, - kDefaultScale, bounds); + gfx::RoundedCornersF(), kDefaultScale, + bounds); mock_surface->SendFrameCallback(); Sync(); testing::Mock::VerifyAndClearExpectations(&mock_surface_gpu); @@ -1388,12 +1520,14 @@ TEST_P(WaylandBufferManagerTest, DestroyBufferCommittedTwiceInARow) { EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(0); buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, kBufferId2, bounds, - kDefaultScale, bounds); + gfx::RoundedCornersF(), kDefaultScale, + bounds); mock_surface->SendFrameCallback(); Sync(); buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, kBufferId2, bounds, - kDefaultScale, bounds); + gfx::RoundedCornersF(), kDefaultScale, + bounds); mock_surface->SendFrameCallback(); Sync(); @@ -1445,7 +1579,8 @@ TEST_P(WaylandBufferManagerTest, ReleaseBufferCommittedTwiceInARow) { EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId1, _)).Times(1); buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, kBufferId1, bounds, - kDefaultScale, bounds); + gfx::RoundedCornersF(), kDefaultScale, + bounds); mock_surface->SendFrameCallback(); Sync(); testing::Mock::VerifyAndClearExpectations(&mock_surface_gpu); @@ -1456,12 +1591,14 @@ TEST_P(WaylandBufferManagerTest, ReleaseBufferCommittedTwiceInARow) { EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(0); buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, kBufferId2, bounds, - kDefaultScale, bounds); + gfx::RoundedCornersF(), kDefaultScale, + bounds); mock_surface->SendFrameCallback(); Sync(); buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, kBufferId2, bounds, - kDefaultScale, bounds); + gfx::RoundedCornersF(), kDefaultScale, + bounds); mock_surface->SendFrameCallback(); Sync(); @@ -1513,7 +1650,8 @@ TEST_P(WaylandBufferManagerTest, ReleaseOrderDifferentToCommitOrder) { EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(1); buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, kBufferId1, bounds, - kDefaultScale, bounds); + gfx::RoundedCornersF(), kDefaultScale, + bounds); mock_surface->SendFrameCallback(); Sync(); testing::Mock::VerifyAndClearExpectations(&mock_surface_gpu); @@ -1525,13 +1663,15 @@ TEST_P(WaylandBufferManagerTest, ReleaseOrderDifferentToCommitOrder) { EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(2); buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, kBufferId2, bounds, - kDefaultScale, bounds); + gfx::RoundedCornersF(), kDefaultScale, + bounds); mock_surface->SendFrameCallback(); Sync(); auto* wl_buffer2 = mock_surface->attached_buffer(); buffer_manager_gpu_->CommitBuffer(widget, kBufferId3, kBufferId3, bounds, - kDefaultScale, bounds); + gfx::RoundedCornersF(), kDefaultScale, + bounds); mock_surface->SendFrameCallback(); Sync(); @@ -1602,7 +1742,8 @@ TEST_P(WaylandBufferManagerTest, EXPECT_CALL(*mock_surface, Commit()).Times(1); buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, kBufferId1, bounds, - kDefaultScale, bounds); + gfx::RoundedCornersF(), kDefaultScale, + bounds); Sync(); @@ -1625,7 +1766,8 @@ TEST_P(WaylandBufferManagerTest, // Commit second buffer now. buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, kBufferId2, bounds, - kDefaultScale, bounds); + gfx::RoundedCornersF(), kDefaultScale, + bounds); Sync(); @@ -1667,7 +1809,8 @@ TEST_P(WaylandBufferManagerTest, // Commit second buffer now. buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, kBufferId2, bounds, - kDefaultScale, bounds); + gfx::RoundedCornersF(), kDefaultScale, + bounds); Sync(); @@ -1702,7 +1845,8 @@ TEST_P(WaylandBufferManagerTest, EXPECT_CALL(*mock_surface, Commit()).Times(1); buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, kBufferId1, bounds, - kDefaultScale, bounds); + gfx::RoundedCornersF(), kDefaultScale, + bounds); Sync(); @@ -1752,7 +1896,8 @@ TEST_P(WaylandBufferManagerTest, OnSubmissionCalledForSingleBuffer) { EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId1, _)).Times(1); buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, kBufferId1, bounds, - kDefaultScale, bounds); + gfx::RoundedCornersF(), kDefaultScale, + bounds); Sync(); DestroyBufferAndSetTerminateExpectation(kBufferId1, false /*fail*/); @@ -1830,7 +1975,7 @@ TEST_P(WaylandBufferManagerTest, FencedRelease) { const gfx::AcceleratedWidget widget = window_->GetWidget(); const gfx::Rect bounds = gfx::Rect({0, 0}, kDefaultSize); - window_->SetBoundsInPixels(bounds); + window_->SetBoundsInDIP(bounds); MockSurfaceGpu mock_surface_gpu(buffer_manager_gpu_.get(), widget_); @@ -1864,13 +2009,15 @@ TEST_P(WaylandBufferManagerTest, FencedRelease) { Truly([](const auto& fence) { return fence.is_null(); }))) .Times(1); buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, kBufferId1, bounds, - kDefaultScale, bounds); + gfx::RoundedCornersF(), kDefaultScale, + bounds); mock_surface->SendFrameCallback(); Sync(); // Commit the second buffer now. buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, kBufferId2, bounds, - kDefaultScale, bounds); + gfx::RoundedCornersF(), kDefaultScale, + bounds); mock_surface->SendFrameCallback(); Sync(); @@ -1891,7 +2038,8 @@ TEST_P(WaylandBufferManagerTest, FencedRelease) { // Commit the third buffer now. buffer_manager_gpu_->CommitBuffer(widget, kBufferId3, kBufferId3, bounds, - kDefaultScale, bounds); + gfx::RoundedCornersF(), kDefaultScale, + bounds); mock_surface->SendFrameCallback(); Sync(); @@ -1947,7 +2095,8 @@ TEST_P(WaylandBufferManagerTest, EXPECT_CALL(*mock_surface_gpu.get(), OnPresentation(kBufferId1, _)).Times(1); buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, kBufferId1, bounds, - kDefaultScale, bounds); + gfx::RoundedCornersF(), kDefaultScale, + bounds); Sync(); // The root surface shouldn't get null buffer attached. @@ -1997,7 +2146,8 @@ TEST_P(WaylandBufferManagerTest, EXPECT_CALL(*mock_surface_gpu.get(), OnPresentation(kBufferId1, _)).Times(1); buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, kBufferId1, bounds, - kDefaultScale, bounds); + gfx::RoundedCornersF(), kDefaultScale, + bounds); Sync(); DestroyBufferAndSetTerminateExpectation(kBufferId1, false /*fail*/); @@ -2302,7 +2452,7 @@ TEST_P(WaylandBufferManagerTest, FeedbacksAreDiscardedIfClientMisbehaves) { const gfx::AcceleratedWidget widget = window_->GetWidget(); const gfx::Rect bounds = gfx::Rect({0, 0}, kDefaultSize); - window_->SetBoundsInPixels(bounds); + window_->SetBoundsInDIP(bounds); MockSurfaceGpu mock_surface_gpu(buffer_manager_gpu_.get(), widget_); @@ -2362,9 +2512,9 @@ TEST_P(WaylandBufferManagerTest, FeedbacksAreDiscardedIfClientMisbehaves) { EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(0); } - buffer_manager_gpu_->CommitBuffer(widget, next_buffer_id_commit, - next_buffer_id_commit, bounds, - kDefaultScale, bounds); + buffer_manager_gpu_->CommitBuffer( + widget, next_buffer_id_commit, next_buffer_id_commit, bounds, + gfx::RoundedCornersF(), kDefaultScale, bounds); Sync(); @@ -2396,10 +2546,10 @@ TEST_P(WaylandBufferManagerTest, ExecutesTasksAfterInitialization) { constexpr uint32_t kDmabufBufferId = 1; CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/, kDmabufBufferId); - buffer_manager_gpu_->CommitBuffer(window_->GetWidget(), kDmabufBufferId, - kDmabufBufferId, - window_->GetBoundsInPixels(), kDefaultScale, - window_->GetBoundsInPixels()); + buffer_manager_gpu_->CommitBuffer( + window_->GetWidget(), kDmabufBufferId, kDmabufBufferId, + window_->GetBoundsInPixels(), gfx::RoundedCornersF(), kDefaultScale, + window_->GetBoundsInPixels()); DestroyBufferAndSetTerminateExpectation(kDmabufBufferId, false /*fail*/); base::RunLoop().RunUntilIdle(); diff --git a/chromium/ui/ozone/platform/wayland/wayland_utils.h b/chromium/ui/ozone/platform/wayland/wayland_utils.h index 52e1e4b37d6..8c7cadb22d2 100644 --- a/chromium/ui/ozone/platform/wayland/wayland_utils.h +++ b/chromium/ui/ozone/platform/wayland/wayland_utils.h @@ -5,10 +5,14 @@ #ifndef UI_OZONE_PLATFORM_WAYLAND_WAYLAND_UTILS_H_ #define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_UTILS_H_ +#include "base/memory/raw_ptr.h" #include "ui/ozone/public/platform_utils.h" namespace ui { +#define PARAM_TO_FLOAT(x) (x / 10000.f) +#define FLOAT_TO_PARAM(x) static_cast<uint32_t>(x * 10000) + class WaylandConnection; class WaylandUtils : public PlatformUtils { @@ -25,7 +29,7 @@ class WaylandUtils : public PlatformUtils { void OnUnhandledKeyEvent(const KeyEvent& key_event) override; private: - WaylandConnection* const connection_; + const raw_ptr<WaylandConnection> connection_; }; } // namespace ui |