// Copyright 2013 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "ui/views/widget/root_view.h" #include <memory> #include <utility> #include "base/functional/bind.h" #include "base/functional/callback.h" #include "base/functional/callback_forward.h" #include "base/memory/ptr_util.h" #include "base/memory/raw_ptr.h" #include "build/build_config.h" #include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_node_data.h" #include "ui/base/metadata/metadata_header_macros.h" #include "ui/base/metadata/metadata_impl_macros.h" #include "ui/base/mojom/dialog_button.mojom.h" #include "ui/events/event_utils.h" #include "ui/events/keycodes/dom/dom_code.h" #include "ui/views/accessibility/view_accessibility.h" #include "ui/views/context_menu_controller.h" #include "ui/views/test/test_views.h" #include "ui/views/test/views_test_base.h" #include "ui/views/test/views_test_utils.h" #include "ui/views/view_targeter.h" #include "ui/views/widget/widget_deletion_observer.h" #include "ui/views/window/dialog_delegate.h" #if BUILDFLAG(IS_MAC) #include "base/mac/mac_util.h" #endif namespace views::test { namespace { struct RootViewTestStateInit { … }; class RootViewTestState { … }; class DeleteOnKeyEventView : public View { … }; BEGIN_METADATA(…) } // namespace RootViewTest; // Verifies deleting a View in OnKeyPressed() doesn't crash and that the // target is marked as destroyed in the returned EventDispatchDetails. TEST_F(RootViewTest, DeleteViewDuringKeyEventDispatch) { … } // Tracks whether a context menu is shown. class TestContextMenuController : public ContextMenuController { … }; // Tests that context menus are shown for certain key events (Shift+F10 // and VKEY_APPS) by the pre-target handler installed on RootView. TEST_F(RootViewTest, ContextMenuFromKeyEvent) { … } // View which handles all gesture events. class GestureHandlingView : public View { … }; BEGIN_METADATA(…) // View which handles all mouse events. class MouseHandlingView : public View { … }; BEGIN_METADATA(…) TEST_F(RootViewTest, EventHandlersResetWhenDeleted) { … } TEST_F(RootViewTest, EventHandlersNotResetWhenReparented) { … } // Verifies that the gesture handler stored in the root view is reset after // mouse is released. Note that during mouse event handling, // `RootView::SetMouseAndGestureHandler()` may be called to set the gesture // handler. Therefore we should reset the gesture handler when mouse is // released. We may remove this test in the future if the implementation of the // product code changes. TEST_F(RootViewTest, GestureHandlerResetAfterMouseReleased) { … } // Tests that context menus are shown for long press by the post-target handler // installed on the RootView only if the event is targetted at a view which can // show a context menu. TEST_F(RootViewTest, ContextMenuFromLongPress) { … } // Tests that context menus are not shown for disabled views on a long press. TEST_F(RootViewTest, ContextMenuFromLongPressOnDisabledView) { … } namespace { // View class which destroys itself when it gets an event of type // |delete_event_type|. class DeleteViewOnEvent : public View { … }; BEGIN_METADATA(…) // View class which remove itself when it gets an event of type // |remove_event_type|. class RemoveViewOnEvent : public View { … }; BEGIN_METADATA(…) // View class which generates a nested event the first time it gets an event of // type |nested_event_type|. This is used to simulate nested event loops which // can cause |RootView::mouse_event_handler_| to get reset. class NestedEventOnEvent : public View { … }; BEGIN_METADATA(…) } // namespace // Verifies deleting a View in OnMouseExited() doesn't crash. TEST_F(RootViewTest, DeleteViewOnMouseExitDispatch) { … } // Verifies deleting a View in OnMouseEntered() doesn't crash. TEST_F(RootViewTest, DeleteViewOnMouseEnterDispatch) { … } // Verifies removing a View in OnMouseEntered() doesn't crash. TEST_F(RootViewTest, RemoveViewOnMouseEnterDispatch) { … } // Verifies clearing the root view's |mouse_move_handler_| in OnMouseExited() // doesn't crash. TEST_F(RootViewTest, ClearMouseMoveHandlerOnMouseExitDispatch) { … } // Verifies clearing the root view's |mouse_move_handler_| in OnMouseExited() // doesn't crash, in the case where the root view is targeted, because // it's the first enabled view encountered walking up the target tree. TEST_F(RootViewTest, ClearMouseMoveHandlerOnMouseExitDispatchWithContentViewDisabled) { … } // Verifies clearing the root view's |mouse_move_handler_| in OnMouseEntered() // doesn't crash. TEST_F(RootViewTest, ClearMouseMoveHandlerOnMouseEnterDispatch) { … } namespace { // View class which deletes its owning Widget when it gets a mouse exit event. class DeleteWidgetOnMouseExit : public View { … }; BEGIN_METADATA(…) } // namespace // Test that there is no crash if a View deletes its parent Widget in // View::OnMouseExited(). TEST_F(RootViewTest, DeleteWidgetOnMouseExitDispatch) { … } // Test that there is no crash if a View deletes its parent widget as a result // of a mouse exited event which was propagated from one of its children. TEST_F(RootViewTest, DeleteWidgetOnMouseExitDispatchFromChild) { … } namespace { class RootViewTestDialogDelegate : public DialogDelegateView { … }; } // namespace // Ensure only one layout happens during Widget initialization, and ensure it // happens at the ContentView's preferred size. TEST_F(RootViewTest, SingleLayoutDuringInit) { … } RootViewDesktopNativeWidgetTest; // Also test Aura desktop Widget codepaths. TEST_F(RootViewDesktopNativeWidgetTest, SingleLayoutDuringInit) { … } #if !BUILDFLAG(IS_MAC) // Tests that AnnounceAlert sets up the correct text value on the hidden // view, and that the resulting hidden view actually stays hidden. TEST_F(RootViewTest, AnnounceTextAsTest) { … } #endif // !BUILDFLAG(IS_MAC) TEST_F(RootViewTest, MouseEventDispatchedToClosestEnabledView) { … } // If RootView::OnMousePressed() receives a double-click event that isn't // handled by any views, it should still report it as handled if the first click // was handled. However, it should *not* if the first click was unhandled. // Regression test for https://crbug.com/1055674. TEST_F(RootViewTest, DoubleClickHandledIffFirstClickHandled) { … } TEST_F(RootViewTest, AccessibleProperties) { … } } // namespace views::test