chromium/ui/aura/window_event_dispatcher_unittest.cc

// Copyright 2012 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/aura/window_event_dispatcher.h"

#include <stddef.h>

#include <utility>
#include <vector>

#include "base/containers/contains.h"
#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/types/cxx23_to_underlying.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/client/capture_client.h"
#include "ui/aura/client/event_client.h"
#include "ui/aura/client/focus_client.h"
#include "ui/aura/env.h"
#include "ui/aura/test/aura_test_base.h"
#include "ui/aura/test/env_test_helper.h"
#include "ui/aura/test/test_cursor_client.h"
#include "ui/aura/test/test_screen.h"
#include "ui/aura/test/test_window_delegate.h"
#include "ui/aura/test/test_windows.h"
#include "ui/aura/window.h"
#include "ui/aura/window_targeter.h"
#include "ui/aura/window_tracker.h"
#include "ui/base/hit_test.h"
#include "ui/base/ime/mock_input_method.h"
#include "ui/base/ui_base_features.h"
#include "ui/display/screen.h"
#include "ui/events/event.h"
#include "ui/events/event_handler.h"
#include "ui/events/event_utils.h"
#include "ui/events/gesture_detection/gesture_configuration.h"
#include "ui/events/keycodes/dom/dom_code.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/events/test/event_generator.h"
#include "ui/events/test/test_event_handler.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/transform.h"
#include "ui/platform_window/platform_window_init_properties.h"
#include "ui/wm/core/capture_controller.h"

#if BUILDFLAG(IS_OZONE)
#include "ui/events/ozone/events_ozone.h"
#endif

namespace aura {
namespace {

// A delegate that always returns a non-client component for hit tests.
class NonClientDelegate : public test::TestWindowDelegate {};

// A simple event handler that consumes key events.
class ConsumeKeyHandler : public ui::test::TestEventHandler {};

// ImeKeyEventDispatcher that tracks the events passed to PostIME phase.
class TestImeKeyEventDispatcher : public ui::ImeKeyEventDispatcher {};

bool IsFocusedWindow(aura::Window* window) {}

gfx::Point GetLastTouchPoint(
    aura::Window* window,
    std::optional<gfx::Point> fallback = std::nullopt) {}

}  // namespace

WindowEventDispatcherTest;

TEST_F(WindowEventDispatcherTest, OnHostMouseEvent) {}

TEST_F(WindowEventDispatcherTest, RepostEvent) {}

// Check that we correctly track whether any touch devices are down in response
// to touch press and release events with two WindowTreeHost.
TEST_F(WindowEventDispatcherTest, TouchDownState) {}

// Check that we correctly track the state of the mouse buttons in response to
// button press and release events.
TEST_F(WindowEventDispatcherTest, MouseButtonState) {}

TEST_F(WindowEventDispatcherTest, TranslatedEvent) {}

namespace {

class TestEventClient : public client::EventClient {};

}  // namespace

TEST_F(WindowEventDispatcherTest, GetCanProcessEventsWithinSubtree) {}

TEST_F(WindowEventDispatcherTest, DontIgnoreUnknownKeys) {}

TEST_F(WindowEventDispatcherTest, NoDelegateWindowReceivesKeyEvents) {}

// Tests that touch-events that are beyond the bounds of the root-window do get
// propagated to the event filters correctly with the root as the target.
TEST_F(WindowEventDispatcherTest, TouchEventsOutsideBounds) {}

// Tests that scroll events are dispatched correctly.
TEST_F(WindowEventDispatcherTest, ScrollEventDispatch) {}

TEST_F(WindowEventDispatcherTest, PreDispatchKeyEventToIme) {}

namespace {

// ui::EventHandler that tracks the types of events it's seen.
class EventFilterRecorder : public ui::EventHandler {};

// Converts an EventType to a string.
std::string EventTypeToString(ui::EventType type) {}

std::string EventTypesToString(const EventFilterRecorder::Events& events) {}

}  // namespace

#if BUILDFLAG(IS_WIN) && defined(ARCH_CPU_X86)
#define MAYBE
#else
#define MAYBE(x)
#endif

// Verifies a repost mouse event targets the window with capture (if there is
// one).
// Flaky on 32-bit Windows bots.  http://crbug.com/388290
TEST_F(WindowEventDispatcherTest, MAYBE(RepostTargetsCaptureWindow)) {}

TEST_F(WindowEventDispatcherTest, MouseMovesHeld) {}

TEST_F(WindowEventDispatcherTest, TouchMovesHeld) {}

// Tests that mouse move event has a right location
// when there isn't the target window
TEST_F(WindowEventDispatcherTest, MouseEventWithoutTargetWindow) {}

// Tests that a mouse exit is dispatched to the last mouse location when
// the window is hiddden.
TEST_F(WindowEventDispatcherTest, DispatchMouseExitWhenHidingWindow) {}

TEST_F(WindowEventDispatcherTest, HeldMovesDispatchMouseExitWhenHidingWindow) {}

// Tests that a mouse-exit event is not synthesized during shutdown.
TEST_F(WindowEventDispatcherTest, NoMouseExitInShutdown) {}

// Verifies that a direct call to ProcessedTouchEvent() does not cause a crash.
TEST_F(WindowEventDispatcherTest, CallToProcessedTouchEvent) {}

// This event handler requests the dispatcher to start holding pointer-move
// events when it receives the first scroll-update gesture.
class HoldPointerOnScrollHandler : public ui::test::TestEventHandler {};

// Tests that touch-move events don't contribute to an in-progress scroll
// gesture if touch-move events are being held by the dispatcher.
TEST_F(WindowEventDispatcherTest, TouchMovesHeldOnScroll) {}

// Tests that a 'held' touch-event does contribute to gesture event when it is
// dispatched.
TEST_F(WindowEventDispatcherTest, HeldTouchMoveContributesToGesture) {}

// Tests that synthetic mouse events are ignored when mouse
// events are disabled.
TEST_F(WindowEventDispatcherTest, DispatchSyntheticMouseEvents) {}

// Tests that a mouse-move event is not synthesized when a mouse-button is down.
TEST_F(WindowEventDispatcherTest, DoNotSynthesizeWhileButtonDown) {}

// Tests that a mouse-press event is not dispatched during shutdown.
TEST_F(WindowEventDispatcherTest, DoNotDispatchInShutdown) {}

#if BUILDFLAG(IS_WIN) && defined(ARCH_CPU_X86)
#define MAYBE
#else
#define MAYBE(x)
#endif

// Tests synthetic mouse events generated when window bounds changes such that
// the cursor previously outside the window becomes inside, or vice versa.
// Do not synthesize events if the window ignores events or is invisible.
// Flaky on 32-bit Windows bots.  http://crbug.com/388272
TEST_F(WindowEventDispatcherTest,
       MAYBE(SynthesizeMouseEventsOnWindowBoundsChanged)) {}

// Tests that a mouse exit is dispatched to the last known cursor location
// when the cursor becomes invisible.
TEST_F(WindowEventDispatcherTest, DispatchMouseExitWhenCursorHidden) {}

// Tests that a synthetic mouse exit is dispatched to the last known cursor
// location after mouse events are disabled on the cursor client.
TEST_F(WindowEventDispatcherTest,
       DispatchSyntheticMouseExitAfterMouseEventsDisabled) {}

class DeletingEventFilter : public ui::EventHandler {};

class DeletingWindowDelegate : public test::TestWindowDelegate {};

TEST_F(WindowEventDispatcherTest, DeleteWindowDuringDispatch) {}

namespace {

// A window delegate that detaches the parent of the target's parent window when
// it receives a tap event.
class DetachesParentOnTapDelegate : public test::TestWindowDelegate {};

}  // namespace

// Tests that the gesture recognizer is reset for all child windows when a
// window hides. No expectations, just checks that the test does not crash.
TEST_F(WindowEventDispatcherTest,
       GestureRecognizerResetsTargetWhenParentHides) {}

namespace {

// A window delegate that processes nested gestures on tap.
class NestedGestureDelegate : public test::TestWindowDelegate {};

}  // namespace

// Tests that gesture end is delivered after nested gesture processing.
TEST_F(WindowEventDispatcherTest, GestureEndDeliveredAfterNestedGestures) {}

// Tests whether we can repost the Tap down gesture event.
TEST_F(WindowEventDispatcherTest, RepostTapdownGestureTest) {}

// This class inherits from the EventFilterRecorder class which provides a
// facility to record events. This class additionally provides a facility to
// repost the EventType::kGestureTapDown gesture to the target window and
// records events after that.
class RepostGestureEventRecorder : public EventFilterRecorder {};

// Tests whether events which are generated after the reposted gesture event
// are received after that. In this case the scroll sequence events should
// be received after the reposted gesture event.
TEST_F(WindowEventDispatcherTest, GestureRepostEventOrder) {}

// An event filter that deletes the specified object when sees a mouse-exited
// event.
template <class T>
class OnMouseExitDeletingEventFilter : public EventFilterRecorder {};

// Tests that RootWindow drops mouse-moved event that is supposed to be sent to
// a child, but the child is destroyed because of the synthesized mouse-exit
// event generated on the previous mouse_moved_handler_.
TEST_F(WindowEventDispatcherTest, DeleteWindowDuringMouseMovedDispatch) {}

// Tests the case where the event dispatcher is deleted during the pre-dispatch
// phase of dispatching and event.
TEST_F(WindowEventDispatcherTest, DeleteDispatcherDuringPreDispatch) {}

namespace {

// Used to track if OnWindowDestroying() is invoked and if there is a valid
// RootWindow at such time.
class ValidRootDuringDestructionWindowObserver : public aura::WindowObserver {};

}  // namespace

// Verifies GetRootWindow() from ~Window returns a valid root.
TEST_F(WindowEventDispatcherTest, ValidRootDuringDestruction) {}

namespace {

// See description above DontResetHeldEvent for details.
class DontResetHeldEventWindowDelegate : public test::TestWindowDelegate {};

}  // namespace

// Verifies RootWindow doesn't reset |RootWindow::held_repostable_event_| after
// dispatching. This is done by using DontResetHeldEventWindowDelegate, which
// tracks the number of events with ui::EF_SHIFT_DOWN set (all reposted events
// have EF_SHIFT_DOWN). When the first event is seen RepostEvent() is used to
// schedule another reposted event.
TEST_F(WindowEventDispatcherTest, DontResetHeldEvent) {}

namespace {

// See description above DeleteHostFromHeldMouseEvent for details.
class DeleteHostFromHeldMouseEventDelegate : public test::TestWindowDelegate {};

}  // namespace

// Verifies if a WindowTreeHost is deleted from dispatching a held mouse event
// we don't crash.
TEST_F(WindowEventDispatcherTest, DeleteHostFromHeldMouseEvent) {}

TEST_F(WindowEventDispatcherTest, WindowHideCancelsActiveTouches) {}

TEST_F(WindowEventDispatcherTest, WindowHideCancelsActiveGestures) {}

// Places two windows side by side.  Starts a pinch in one window, then sets
// capture to the other window.  Ensures that subsequent pinch events are
// sent to the window which gained capture.
TEST_F(WindowEventDispatcherTest, TouchpadPinchEventsRetargetOnCapture) {}

// Places two windows side by side. Presses down on one window, and starts a
// scroll. Sets capture on the other window and ensures that the "ending" events
// aren't sent to the window which gained capture.
TEST_F(WindowEventDispatcherTest, EndingEventDoesntRetarget) {}

namespace {

// This class creates and manages a window which is destroyed as soon as
// capture is lost. This is the case for the drag and drop capture window.
class CaptureWindowTracker : public test::TestWindowDelegate {};

}  // namespace

// Verifies handling loss of capture by the capture window being hidden.
TEST_F(WindowEventDispatcherTest, CaptureWindowHidden) {}

// Verifies handling loss of capture by the capture window being destroyed.
TEST_F(WindowEventDispatcherTest, CaptureWindowDestroyed) {}

namespace {

class RunLoopHandler : public ui::EventHandler {};

}  // namespace

TEST_F(WindowEventDispatcherTest, HeldTouchMoveWithRunLoop) {}

class ExitMessageLoopOnMousePress : public ui::test::TestEventHandler {};

class WindowEventDispatcherTestWithMessageLoop
    : public WindowEventDispatcherTest {};

TEST_F(WindowEventDispatcherTestWithMessageLoop, EventRepostedInNonNestedLoop) {}

class WindowEventDispatcherTestInHighDPI : public WindowEventDispatcherTest {};

TEST_F(WindowEventDispatcherTestInHighDPI, EventLocationTransform) {}

TEST_F(WindowEventDispatcherTestInHighDPI, TouchMovesHeldOnScroll) {}

// This handler triggers a nested run loop when it receives a right click
// event, and runs a single callback in the nested run loop.
class TriggerNestedLoopOnRightMousePress : public ui::test::TestEventHandler {};

// Tests that if dispatching a 'held' event triggers a nested run loop, then
// the events that are dispatched from the nested run loop are transformed
// correctly.
TEST_F(WindowEventDispatcherTestInHighDPI,
       EventsTransformedInRepostedEventTriggeredNestedLoop) {}

class SelfDestructDelegate : public test::TestWindowDelegate {};

TEST_F(WindowEventDispatcherTest, SynthesizedLocatedEvent) {}

// Tests that the window which has capture can get destroyed as a result of
// ui::EventType::kMouseCaptureChanged event dispatched in
// WindowEventDispatcher::UpdateCapture without causing a "use after free".
TEST_F(WindowEventDispatcherTest, DestroyWindowOnCaptureChanged) {}

class StaticFocusClient : public client::FocusClient {};

// Tests that host-cancel-mode event can be dispatched to a dispatcher safely
// when the focused window does not live in the dispatcher's tree.
TEST_F(WindowEventDispatcherTest, HostCancelModeWithFocusedWindowOutside) {}

// Dispatches a mouse-move event to |target| when it receives a mouse-move
// event.
class DispatchEventHandler : public ui::EventHandler {};

// Moves |window| to |root_window| when it receives a mouse-move event.
class MoveWindowHandler : public ui::EventHandler {};

// Tests that nested event dispatch works correctly if the target of the older
// event being dispatched is moved to a different dispatcher in response to an
// event in the inner loop.
TEST_F(WindowEventDispatcherTest, NestedEventDispatchTargetMoved) {}

class AlwaysMouseDownInputStateLookup : public InputStateLookup {};

TEST_F(WindowEventDispatcherTest,
       CursorVisibilityChangedWhileCaptureWindowInAnotherDispatcher) {}

TEST_F(WindowEventDispatcherTest,
       RedirectedEventToDifferentDispatcherLocation) {}

class AsyncWindowDelegate : public test::TestWindowDelegate {};

// Tests that gesture events dispatched through the asynchronous flow have
// co-ordinates in the right co-ordinate space.
TEST_F(WindowEventDispatcherTest, GestureEventCoordinates) {}

// Tests that a scroll-generating touch-event is marked as such.
TEST_F(WindowEventDispatcherTest, TouchMovesMarkedWhenCausingScroll) {}

// OnCursorMovedToRootLocation() is sometimes called instead of
// WindowTreeHost::MoveCursorTo() when the cursor did not move but the
// cursor's position in root coordinates has changed (e.g. when the displays's
// scale factor changed). Test that hover effects are properly updated.
TEST_F(WindowEventDispatcherTest, OnCursorMovedToRootLocationUpdatesHover) {}

TEST_F(WindowEventDispatcherTest, TouchEventWithScaledWindow) {}

// A test case for crbug.com/1099985
TEST_F(WindowEventDispatcherTest, TargetIsDestroyedByHeldEvent) {}

// Tests that touch event can be filtered by `StopPropagation`, but can still
// be processed by GestureRecogtnizer with `ForceProcessGesture`.
TEST_F(WindowEventDispatcherTest, FilteredTouchProcessGesture) {}

TEST_F(WindowEventDispatcherTest, LastTouchPoint) {}

}  // namespace aura