Chromium Code Reviews| Index: services/ui/ws/event_dispatcher.cc |
| diff --git a/services/ui/ws/event_dispatcher.cc b/services/ui/ws/event_dispatcher.cc |
| index 83e8b37f26e8aafdacbec4f0fc45566195c18068..3101bbebbc2ed1e95fdba76553c137abada058b2 100644 |
| --- a/services/ui/ws/event_dispatcher.cc |
| +++ b/services/ui/ws/event_dispatcher.cc |
| @@ -6,7 +6,9 @@ |
| #include <algorithm> |
| +#include "base/command_line.h" |
| #include "base/memory/ptr_util.h" |
| +#include "base/task_scheduler/post_task.h" |
| #include "base/time/time.h" |
| #include "services/ui/ws/accelerator.h" |
| #include "services/ui/ws/drag_controller.h" |
| @@ -41,6 +43,14 @@ bool IsOnlyOneMouseButtonDown(int flags) { |
| //////////////////////////////////////////////////////////////////////////////// |
| +EventDispatcher::HittestRequest::HittestRequest(gfx::Point location, |
| + HittestCallback callback) |
| + : hittest_location(location) { |
| + hittest_callback = std::move(callback); |
| +} |
| + |
| +EventDispatcher::HittestRequest::~HittestRequest() {} |
| + |
| EventDispatcher::EventDispatcher(EventDispatcherDelegate* delegate) |
| : delegate_(delegate), |
| capture_window_(nullptr), |
| @@ -48,7 +58,8 @@ EventDispatcher::EventDispatcher(EventDispatcherDelegate* delegate) |
| modal_window_controller_(this), |
| mouse_button_down_(false), |
| mouse_cursor_source_window_(nullptr), |
| - mouse_cursor_in_non_client_area_(false) {} |
| + mouse_cursor_in_non_client_area_(false), |
| + hittest_in_flight_(false) {} |
| EventDispatcher::~EventDispatcher() { |
| SetMouseCursorSourceWindow(nullptr); |
| @@ -80,7 +91,7 @@ void EventDispatcher::SetMousePointerScreenLocation( |
| const gfx::Point& screen_location) { |
| DCHECK(pointer_targets_.empty()); |
| mouse_pointer_last_location_ = screen_location; |
| - UpdateCursorProviderByLastKnownLocation(); |
| + UpdateCursorProviderByLastKnownLocation(base::Closure()); |
| // Write our initial location back to our shared screen coordinate. This |
| // shouldn't cause problems because we already read the cursor before we |
| // process any events in views during window construction. |
| @@ -145,7 +156,7 @@ bool EventDispatcher::SetCaptureWindow(ServerWindow* window, |
| } else { |
| delegate_->ReleaseNativeCapture(); |
| if (!mouse_button_down_) |
| - UpdateCursorProviderByLastKnownLocation(); |
| + UpdateCursorProviderByLastKnownLocation(base::Closure()); |
| } |
| return true; |
| } |
| @@ -217,30 +228,25 @@ const ServerWindow* EventDispatcher::GetWindowForMouseCursor() const { |
| return window; |
| } |
| -void EventDispatcher::UpdateNonClientAreaForCurrentWindow() { |
| +void EventDispatcher::UpdateNonClientAreaForCurrentWindow( |
| + const base::Closure& callback) { |
| if (mouse_cursor_source_window_) { |
| - DeepestWindow deepest_window = |
| - FindDeepestVisibleWindowForEvents(mouse_pointer_last_location_); |
| - if (deepest_window.window == mouse_cursor_source_window_) { |
| - mouse_cursor_in_non_client_area_ = mouse_cursor_source_window_ |
| - ? deepest_window.in_non_client_area |
| - : false; |
| - } |
| + FindDeepestVisibleWindowForEvents( |
| + mouse_pointer_last_location_, |
| + base::BindOnce( |
| + &EventDispatcher::UpdateNonClientAreaForCurrentWindowOnFoundWindow, |
| + base::Unretained(this), callback)); |
| } |
| } |
| -void EventDispatcher::UpdateCursorProviderByLastKnownLocation() { |
| +void EventDispatcher::UpdateCursorProviderByLastKnownLocation( |
| + const base::Closure& callback) { |
| if (!mouse_button_down_) { |
| - DeepestWindow deepest_window = |
| - FindDeepestVisibleWindowForEvents(mouse_pointer_last_location_); |
| - SetMouseCursorSourceWindow(deepest_window.window); |
| - if (mouse_cursor_source_window_) { |
| - mouse_cursor_in_non_client_area_ = deepest_window.in_non_client_area; |
| - } else { |
| - gfx::Point location = mouse_pointer_last_location_; |
| - SetMouseCursorSourceWindow(delegate_->GetRootWindowContaining(&location)); |
| - mouse_cursor_in_non_client_area_ = true; |
| - } |
| + FindDeepestVisibleWindowForEvents( |
| + mouse_pointer_last_location_, |
| + base::BindOnce(&EventDispatcher:: |
| + UpdateCursorProviderByLastKnownLocationOnFoundWindow, |
| + base::Unretained(this), callback)); |
| } |
| } |
| @@ -347,6 +353,16 @@ void EventDispatcher::ProcessKeyEvent(const ui::KeyEvent& event, |
| void EventDispatcher::ProcessPointerEvent(const ui::PointerEvent& event) { |
| DCHECK(event.IsPointerEvent()); |
| + PointerTargetForEvent( |
| + event, base::BindOnce(&EventDispatcher::ProcessPointerEventOnFoundTarget, |
| + base::Unretained(this), event)); |
| +} |
| + |
| +void EventDispatcher::ProcessPointerEventOnFoundTarget( |
| + const ui::PointerEvent& event, |
| + PointerTarget pointer_target_found) { |
| + ProcessNextHittesetRequestFromQueue(); |
| + |
| const bool is_mouse_event = event.IsMousePointerEvent(); |
| if (is_mouse_event) { |
| @@ -370,8 +386,8 @@ void EventDispatcher::ProcessPointerEvent(const ui::PointerEvent& event) { |
| } |
| if (drag_controller_) { |
| - const PointerTarget target = PointerTargetForEvent(event); |
| - if (drag_controller_->DispatchPointerEvent(event, target.window)) |
| + if (drag_controller_->DispatchPointerEvent(event, |
| + pointer_target_found.window)) |
| return; |
| } |
| @@ -385,7 +401,7 @@ void EventDispatcher::ProcessPointerEvent(const ui::PointerEvent& event) { |
| if (!IsTrackingPointer(pointer_id) || |
| !pointer_targets_[pointer_id].is_pointer_down) { |
| const bool any_pointers_down = AreAnyPointersDown(); |
| - UpdateTargetForPointer(pointer_id, event); |
| + UpdateTargetForPointer(pointer_id, event, pointer_target_found); |
| if (is_mouse_event) |
| SetMouseCursorSourceWindow(pointer_targets_[pointer_id].window); |
| @@ -412,7 +428,7 @@ void EventDispatcher::ProcessPointerEvent(const ui::PointerEvent& event) { |
| // before we perform dispatch because the Delegate is going to read this |
| // information from us. |
| if (is_pointer_going_up && is_mouse_event) |
| - UpdateCursorProviderByLastKnownLocation(); |
| + UpdateCursorProviderByLastKnownLocation(base::Closure()); |
| DispatchToPointerTarget(pointer_targets_[pointer_id], event); |
| @@ -443,20 +459,21 @@ void EventDispatcher::StopTrackingPointer(int32_t pointer_id) { |
| UnobserveWindow(window); |
| } |
| -void EventDispatcher::UpdateTargetForPointer(int32_t pointer_id, |
| - const ui::LocatedEvent& event) { |
| +void EventDispatcher::UpdateTargetForPointer( |
| + int32_t pointer_id, |
| + const ui::PointerEvent& event, |
| + const PointerTarget& pointer_target_found) { |
| if (!IsTrackingPointer(pointer_id)) { |
| - StartTrackingPointer(pointer_id, PointerTargetForEvent(event)); |
| + StartTrackingPointer(pointer_id, pointer_target_found); |
| return; |
| } |
| - const PointerTarget pointer_target = PointerTargetForEvent(event); |
| - if (pointer_target.window == pointer_targets_[pointer_id].window && |
| - pointer_target.in_nonclient_area == |
| + if (pointer_target_found.window == pointer_targets_[pointer_id].window && |
| + pointer_target_found.in_nonclient_area == |
| pointer_targets_[pointer_id].in_nonclient_area) { |
| // The targets are the same, only set the down state to true if necessary. |
| // Down going to up is handled by ProcessLocatedEvent(). |
| - if (pointer_target.is_pointer_down) |
| + if (pointer_target_found.is_pointer_down) |
| pointer_targets_[pointer_id].is_pointer_down = true; |
| return; |
| } |
| @@ -475,14 +492,23 @@ void EventDispatcher::UpdateTargetForPointer(int32_t pointer_id, |
| // Technically we're updating in place, but calling start then stop makes for |
| // simpler code. |
| StopTrackingPointer(pointer_id); |
| - StartTrackingPointer(pointer_id, pointer_target); |
| + StartTrackingPointer(pointer_id, pointer_target_found); |
| } |
| -EventDispatcher::PointerTarget EventDispatcher::PointerTargetForEvent( |
| - const ui::LocatedEvent& event) { |
| +void EventDispatcher::PointerTargetForEvent( |
| + const ui::PointerEvent& event, |
| + PointerTargetForEventCallback callback) { |
| + FindDeepestVisibleWindowForEvents( |
| + event.root_location(), |
| + base::BindOnce(&EventDispatcher::PointerTargetForEventOnFoundWindow, |
| + base::Unretained(this), event, std::move(callback))); |
| +} |
| + |
| +void EventDispatcher::PointerTargetForEventOnFoundWindow( |
| + const ui::PointerEvent& event, |
| + PointerTargetForEventCallback callback, |
| + DeepestWindow deepest_window) { |
| PointerTarget pointer_target; |
| - DeepestWindow deepest_window = |
| - FindDeepestVisibleWindowForEvents(event.root_location()); |
| pointer_target.window = |
| modal_window_controller_.GetTargetForWindow(deepest_window.window); |
| pointer_target.is_mouse_event = event.IsMousePointerEvent(); |
| @@ -490,7 +516,7 @@ EventDispatcher::PointerTarget EventDispatcher::PointerTargetForEvent( |
| deepest_window.window != pointer_target.window || |
| !pointer_target.window || deepest_window.in_non_client_area; |
| pointer_target.is_pointer_down = event.type() == ui::ET_POINTER_DOWN; |
| - return pointer_target; |
| + std::move(callback).Run(pointer_target); |
| } |
| bool EventDispatcher::AreAnyPointersDown() const { |
| @@ -540,7 +566,7 @@ void EventDispatcher::CancelPointerEventsToTarget(ServerWindow* window) { |
| // explicit capture. |
| delegate_->OnCaptureChanged(nullptr, window); |
| delegate_->ReleaseNativeCapture(); |
| - UpdateCursorProviderByLastKnownLocation(); |
| + UpdateCursorProviderByLastKnownLocation(base::Closure()); |
| return; |
| } |
| @@ -580,14 +606,92 @@ Accelerator* EventDispatcher::FindAccelerator( |
| return nullptr; |
| } |
| -DeepestWindow EventDispatcher::FindDeepestVisibleWindowForEvents( |
| - const gfx::Point& location) { |
| +void EventDispatcher::FindDeepestVisibleWindowForEvents( |
| + const gfx::Point& location, |
| + HittestCallback callback) { |
| + if (hittest_in_flight_ || !hittest_request_queue_.empty()) { |
| + std::unique_ptr<HittestRequest> hittest_request = |
| + base::MakeUnique<HittestRequest>(location, std::move(callback)); |
| + hittest_request_queue_.push(std::move(hittest_request)); |
| + return; |
| + } |
| + |
| + FindDeepestVisibleWindowForEventsImpl(location, std::move(callback)); |
| +} |
| + |
| +void EventDispatcher::FindDeepestVisibleWindowForEventsImpl( |
| + const gfx::Point& location, |
| + HittestCallback callback) { |
| + // TODO(riajiang): After HittestComponent is implemented, do synchronous |
| + // hit-test for most cases using shared memory and only ask Blink |
| + // asynchronously for hard cases. For now, assume all synchronous hit-tests |
| + // failed if the "enable-async-event-targeting" flag is turned on. |
| + if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
| + "enable-async-event-targeting")) { |
| + DCHECK(!hittest_in_flight_); |
| + hittest_in_flight_ = true; |
| + base::ThreadTaskRunnerHandle::Get()->PostTask( |
| + FROM_HERE, |
| + base::BindOnce(&EventDispatcher::FindDeepestVisibleWindowForEventsAsync, |
| + base::Unretained(this), location, std::move(callback))); |
|
sky
2017/05/14 15:59:05
What guarantees this is valid by the time the call
riajiang
2017/05/15 18:34:41
As discussed, changed to use WeakPtrFactory.
|
| + } else { |
| + FindDeepestVisibleWindowForEventsAsync(location, std::move(callback)); |
| + } |
| +} |
| + |
| +void EventDispatcher::FindDeepestVisibleWindowForEventsAsync( |
| + const gfx::Point& location, |
| + HittestCallback callback) { |
| gfx::Point relative_location(location); |
| - // For the case of no root. |
| ServerWindow* root = delegate_->GetRootWindowContaining(&relative_location); |
| - return root ? ui::ws::FindDeepestVisibleWindowForEvents(root, |
| - relative_location) |
| - : DeepestWindow(); |
| + if (root) { |
| + std::move(callback).Run( |
| + ui::ws::FindDeepestVisibleWindowForEvents(root, relative_location)); |
| + } else { |
| + std::move(callback).Run(DeepestWindow()); |
| + } |
| +} |
| + |
| +void EventDispatcher::UpdateNonClientAreaForCurrentWindowOnFoundWindow( |
| + const base::Closure& callback, |
| + DeepestWindow deepest_window) { |
| + ProcessNextHittesetRequestFromQueue(); |
| + |
| + if (deepest_window.window == mouse_cursor_source_window_) { |
| + mouse_cursor_in_non_client_area_ = |
| + mouse_cursor_source_window_ ? deepest_window.in_non_client_area : false; |
| + } |
| + if (callback) |
| + callback.Run(); |
| +} |
| + |
| +void EventDispatcher::UpdateCursorProviderByLastKnownLocationOnFoundWindow( |
| + const base::Closure& callback, |
| + DeepestWindow deepest_window) { |
| + ProcessNextHittesetRequestFromQueue(); |
| + |
| + SetMouseCursorSourceWindow(deepest_window.window); |
| + if (mouse_cursor_source_window_) { |
| + mouse_cursor_in_non_client_area_ = deepest_window.in_non_client_area; |
| + } else { |
| + gfx::Point location = mouse_pointer_last_location_; |
| + SetMouseCursorSourceWindow(delegate_->GetRootWindowContaining(&location)); |
| + mouse_cursor_in_non_client_area_ = true; |
| + } |
| + if (callback) |
| + callback.Run(); |
| +} |
| + |
| +void EventDispatcher::ProcessNextHittesetRequestFromQueue() { |
| + hittest_in_flight_ = false; |
| + if (hittest_request_queue_.empty()) |
| + return; |
| + std::unique_ptr<HittestRequest> hittest_request = |
| + std::move(hittest_request_queue_.front()); |
| + hittest_request_queue_.pop(); |
| + FindDeepestVisibleWindowForEventsImpl( |
| + hittest_request->hittest_location, |
| + std::move(hittest_request->hittest_callback)); |
| } |
| void EventDispatcher::CancelImplicitCaptureExcept(ServerWindow* window, |