0

EventProcessor redispatch refactor

Add "GetNewEventSinkForEvent" for the case that event needs
to be re-dispatched to different event sink.

Bug: 1345952
Test: no functional change. All test should still pass

Change-Id: Iec36a20730b452e8bf0917057ed6581cc4f92e3c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3823599
Reviewed-by: Scott Violet <sky@chromium.org>
Commit-Queue: Mitsuru Oshima <oshima@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1120287}
This commit is contained in:
Mitsuru Oshima
2023-03-22 00:09:42 +00:00
committed by Chromium LUCI CQ
parent 053f68e1d9
commit 3f1cf2aa0f
6 changed files with 106 additions and 83 deletions

@ -12,7 +12,6 @@
#include "ash/host/root_window_transformer.h"
#include "base/check.h"
#include "base/containers/contains.h"
#include "base/memory/weak_ptr.h"
#include "base/notreached.h"
#include "base/ranges/algorithm.h"
#include "ui/aura/window.h"
@ -37,37 +36,36 @@ class UnifiedEventTargeter : public aura::WindowTargeter {
UnifiedEventTargeter& operator=(const UnifiedEventTargeter&) = delete;
~UnifiedEventTargeter() override { delegate_ = nullptr; }
// aura::WindowTargeter:
ui::EventTarget* FindTargetForEvent(ui::EventTarget* root,
ui::Event* event) override {
delegate_->SetCurrentEventTargeterSourceHost(nullptr);
if (root == src_root_ && !event->target()) {
delegate_->SetCurrentEventTargeterSourceHost(src_root_->GetHost());
if (event->IsLocatedEvent()) {
ui::LocatedEvent* located_event = static_cast<ui::LocatedEvent*>(event);
located_event->ConvertLocationToTarget(
static_cast<aura::Window*>(nullptr), dst_root_);
}
auto ptr = weak_ptr_factory_.GetWeakPtr();
std::ignore =
dst_root_->GetHost()->GetEventSink()->OnEventFromSource(event);
if (!ptr)
return nullptr;
// Reset the source host.
delegate_->SetCurrentEventTargeterSourceHost(nullptr);
return nullptr;
return root;
} else {
NOTREACHED() << "event type:" << event->type();
return aura::WindowTargeter::FindTargetForEvent(root, event);
}
}
ui::EventSink* GetNewEventSinkForEvent(const ui::EventTarget* current_root,
ui::EventTarget* target,
ui::Event* in_out_event) override {
if (current_root == src_root_ && !in_out_event->target()) {
delegate_->SetCurrentEventTargeterSourceHost(src_root_->GetHost());
if (in_out_event->IsLocatedEvent()) {
ui::LocatedEvent* located_event = in_out_event->AsLocatedEvent();
located_event->ConvertLocationToTarget(
static_cast<aura::Window*>(nullptr), dst_root_);
}
return dst_root_->GetHost()->GetEventSink();
}
return nullptr;
}
private:
aura::Window* src_root_;
aura::Window* dst_root_;
AshWindowTreeHostDelegate* delegate_; // Not owned.
base::WeakPtrFactory<UnifiedEventTargeter> weak_ptr_factory_{this};
};
AshWindowTreeHostUnified::AshWindowTreeHostUnified(

@ -150,46 +150,11 @@ Window* WindowTargeter::FindTargetInRootWindow(Window* root_window,
return nullptr;
}
bool WindowTargeter::ProcessEventIfTargetsDifferentRootWindow(
Window* root_window,
Window* target,
ui::Event* event) {
if (root_window->Contains(target))
return false;
// |window| is the root window, but |target| is not a descendent of
// |window|. So do not allow dispatching from here. Instead, dispatch the
// event through the WindowEventDispatcher that owns |target|.
Window* new_root = target->GetRootWindow();
DCHECK(new_root);
if (event->IsLocatedEvent()) {
// The event has been transformed to be in |target|'s coordinate system.
// But dispatching the event through the EventProcessor requires the event
// to be in the host's coordinate system. So, convert the event to be in
// the root's coordinate space, and then to the host's coordinate space by
// applying the host's transform.
ui::LocatedEvent* located_event = event->AsLocatedEvent();
located_event->ConvertLocationToTarget(target, new_root);
WindowTreeHost* window_tree_host = new_root->GetHost();
located_event->UpdateForRootTransform(
window_tree_host->GetRootTransform(),
window_tree_host->GetRootTransformForLocalEventCoordinates());
}
std::ignore = new_root->GetHost()->GetEventSink()->OnEventFromSource(event);
return true;
}
ui::EventTarget* WindowTargeter::FindTargetForEvent(ui::EventTarget* root,
ui::Event* event) {
Window* window = static_cast<Window*>(root);
Window* target = event->IsKeyEvent()
? FindTargetForKeyEvent(window)
: FindTargetForNonKeyEvent(window, event);
if (target && !window->parent() &&
ProcessEventIfTargetsDifferentRootWindow(window, target, event)) {
return nullptr;
}
return target;
return event->IsKeyEvent() ? FindTargetForKeyEvent(window)
: FindTargetForNonKeyEvent(window, event);
}
ui::EventTarget* WindowTargeter::FindNextBestTarget(
@ -251,6 +216,38 @@ Window* WindowTargeter::FindTargetForLocatedEvent(Window* window,
return FindTargetForLocatedEventRecursively(window, event);
}
ui::EventSink* WindowTargeter::GetNewEventSinkForEvent(
const ui::EventTarget* current_root,
ui::EventTarget* target,
ui::Event* in_out_event) {
const aura::Window* root_window = static_cast<const Window*>(current_root);
aura::Window* target_window = static_cast<Window*>(target);
if (!target_window || root_window->parent() ||
root_window->Contains(target_window)) {
// no need to re-target.
return nullptr;
}
// |window| is the root window, but |target| is not a descendent of
// |window|. So do not allow dispatching from here. Instead, dispatch the
// event through the WindowEventDispatcher that owns |target|.
Window* new_root = target_window->GetRootWindow();
DCHECK(new_root);
if (in_out_event->IsLocatedEvent()) {
// The event has been transformed to be in |target|'s coordinate system.
// But dispatching the event through the EventProcessor requires the event
// to be in the host's coordinate system. So, convert the event to be in
// the root's coordinate space, and then to the host's coordinate space by
// applying the host's transform.
ui::LocatedEvent* located_event = in_out_event->AsLocatedEvent();
located_event->ConvertLocationToTarget(target_window, new_root);
WindowTreeHost* window_tree_host = new_root->GetHost();
located_event->UpdateForRootTransform(
window_tree_host->GetRootTransform(),
window_tree_host->GetRootTransformForLocalEventCoordinates());
}
return new_root->GetHost()->GetEventSink();
}
bool WindowTargeter::SubtreeCanAcceptEvent(
Window* window,
const ui::LocatedEvent& event) const {

@ -78,18 +78,14 @@ class AURA_EXPORT WindowTargeter : public ui::EventTargeter {
Window* FindTargetInRootWindow(Window* root_window,
const ui::LocatedEvent& event);
// If |target| is not a child of |root_window|, then converts |event| to
// be relative to |root_window| and dispatches the event to |root_window|.
// Returns false if the |target| is a child of |root_window|.
bool ProcessEventIfTargetsDifferentRootWindow(Window* root_window,
Window* target,
ui::Event* event);
// ui::EventTargeter:
ui::EventTarget* FindTargetForEvent(ui::EventTarget* root,
ui::Event* event) override;
ui::EventTarget* FindNextBestTarget(ui::EventTarget* previous_target,
ui::Event* event) override;
ui::EventSink* GetNewEventSinkForEvent(const ui::EventTarget* current_root,
ui::EventTarget* target,
ui::Event* in_out_event) override;
Window* FindTargetForKeyEvent(Window* root_window);

@ -47,39 +47,55 @@ EventDispatchDetails EventProcessor::OnEventFromSource(Event* event) {
target = targeter->FindTargetForEvent(root, event_to_dispatch);
}
DCHECK(targeter);
// FindTargetForEvent may dispatch event, which may delete the event
// processor.
// processor or targeter.
// TODO(crbug.com/1345952): Remove these returns and change this to DCHECK.
if (!weak_this) {
details.dispatcher_destroyed = true;
return details;
}
if (!weak_targeter) {
return details;
}
while (target) {
details = DispatchEvent(target, event_to_dispatch);
if (!dispatch_original_event) {
if (event_to_dispatch->stopped_propagation())
event->StopPropagation();
else if (event_to_dispatch->handled())
event->SetHandled();
}
if (details.dispatcher_destroyed)
return details;
auto* new_event_sink =
targeter->GetNewEventSinkForEvent(root, target, event_to_dispatch);
if (new_event_sink) {
std::ignore = new_event_sink->OnEventFromSource(event_to_dispatch);
if (!weak_this) {
details.dispatcher_destroyed = true;
return details;
}
} else {
while (target) {
details = DispatchEvent(target, event_to_dispatch);
if (details.target_destroyed || event->handled() || !target ||
!weak_targeter) {
break;
if (!dispatch_original_event) {
if (event_to_dispatch->stopped_propagation()) {
event->StopPropagation();
} else if (event_to_dispatch->handled()) {
event->SetHandled();
}
}
if (details.dispatcher_destroyed) {
return details;
}
if (!weak_this) {
details.dispatcher_destroyed = true;
return details;
}
if (details.target_destroyed || event->handled() || !target ||
!weak_targeter) {
break;
}
DCHECK(targeter);
target = targeter->FindNextBestTarget(target, event_to_dispatch);
}
DCHECK(targeter);
target = targeter->FindNextBestTarget(target, event_to_dispatch);
}
}
OnEventProcessingFinished(event);

@ -10,4 +10,11 @@ EventTargeter::EventTargeter() = default;
EventTargeter::~EventTargeter() = default;
EventSink* EventTargeter::GetNewEventSinkForEvent(
const EventTarget* current_root,
EventTarget* target,
Event* in_out_event) {
return nullptr;
}
} // namespace ui

@ -11,6 +11,7 @@
namespace ui {
class Event;
class EventSink;
class EventTarget;
class EVENTS_EXPORT EventTargeter {
@ -36,6 +37,14 @@ class EVENTS_EXPORT EventTargeter {
virtual EventTarget* FindNextBestTarget(EventTarget* previous_target,
Event* event) = 0;
// Returns new event sink if the `in_out_event` should be dispatched to a
// different sink. The event will be updated so that it can be dispatched to
// the new sink correctly. Returns `nullptr` if the event do not have to be
// redirected.
virtual EventSink* GetNewEventSinkForEvent(const EventTarget* current_root,
EventTarget* target,
Event* in_out_event);
private:
friend class EventProcessor;