diff options
| author | wjmaclean <wjmaclean@chromium.org> | 2016-03-04 13:49:19 -0800 |
|---|---|---|
| committer | Commit bot <commit-bot@chromium.org> | 2016-03-04 21:50:23 +0000 |
| commit | 4446423513e9f2da52e156bc93b5228e6a3d6e08 (patch) | |
| tree | cc86b950425ee48726f3bc57c58d7249b744523d /content | |
| parent | 9a995c82fd5c1d186ebd3d0a30d5a78b29dd5e82 (diff) | |
| download | chromium_src-4446423513e9f2da52e156bc93b5228e6a3d6e08.zip chromium_src-4446423513e9f2da52e156bc93b5228e6a3d6e08.tar.gz chromium_src-4446423513e9f2da52e156bc93b5228e6a3d6e08.tar.bz2 | |
Implement Gesture event hit testing/forwarding for OOPIF.
This CL implements plumbing to forward gesture events to OOPIF frames.
Scroll bubbling will be handled in a follow-on CL.
BUG=587023
CQ_INCLUDE_TRYBOTS=tryserver.chromium.linux:linux_site_isolation
Review URL: https://codereview.chromium.org/1752833002
Cr-Commit-Position: refs/heads/master@{#379367}
Diffstat (limited to 'content')
11 files changed, 399 insertions, 20 deletions
diff --git a/content/browser/frame_host/render_widget_host_view_child_frame.cc b/content/browser/frame_host/render_widget_host_view_child_frame.cc index 35749e9..7c60d9c 100644 --- a/content/browser/frame_host/render_widget_host_view_child_frame.cc +++ b/content/browser/frame_host/render_widget_host_view_child_frame.cc @@ -426,6 +426,12 @@ void RenderWidgetHostViewChildFrame::ProcessTouchEvent( host_->ForwardTouchEventWithLatencyInfo(event, latency); } +void RenderWidgetHostViewChildFrame::ProcessGestureEvent( + const blink::WebGestureEvent& event, + const ui::LatencyInfo& latency) { + host_->ForwardGestureEventWithLatencyInfo(event, latency); +} + gfx::Point RenderWidgetHostViewChildFrame::TransformPointToRootCoordSpace( const gfx::Point& point) { if (!frame_connector_) diff --git a/content/browser/frame_host/render_widget_host_view_child_frame.h b/content/browser/frame_host/render_widget_host_view_child_frame.h index 615028f..f6cba54 100644 --- a/content/browser/frame_host/render_widget_host_view_child_frame.h +++ b/content/browser/frame_host/render_widget_host_view_child_frame.h @@ -141,6 +141,8 @@ class CONTENT_EXPORT RenderWidgetHostViewChildFrame void ProcessMouseWheelEvent(const blink::WebMouseWheelEvent& event) override; void ProcessTouchEvent(const blink::WebTouchEvent& event, const ui::LatencyInfo& latency) override; + void ProcessGestureEvent(const blink::WebGestureEvent& event, + const ui::LatencyInfo& latency) override; gfx::Point TransformPointToRootCoordSpace(const gfx::Point& point) override; #if defined(OS_MACOSX) diff --git a/content/browser/renderer_host/render_widget_host_input_event_router.cc b/content/browser/renderer_host/render_widget_host_input_event_router.cc index 355a358..0343bd9 100644 --- a/content/browser/renderer_host/render_widget_host_input_event_router.cc +++ b/content/browser/renderer_host/render_widget_host_input_event_router.cc @@ -38,10 +38,24 @@ void RenderWidgetHostInputEventRouter::OnRenderWidgetHostViewBaseDestroyed( } } - if (view == current_touch_target_) { - current_touch_target_ = nullptr; + if (view == touch_target_) { + touch_target_ = nullptr; + touch_delta_ = gfx::Vector2d(); active_touches_ = 0; } + + // If the target that's being destroyed is in the gesture target queue, we + // replace it with nullptr so that we maintain the 1:1 correspondence between + // queue entries and the touch sequences that underly them. + for (size_t i = 0; i < gesture_target_queue_.size(); ++i) { + if (gesture_target_queue_[i].target == view) + gesture_target_queue_[i].target = nullptr; + } + + if (view == gesture_target_) { + gesture_target_ = nullptr; + gesture_delta_ = gfx::Vector2d(); + } } void RenderWidgetHostInputEventRouter::ClearAllObserverRegistrations() { @@ -74,7 +88,9 @@ bool RenderWidgetHostInputEventRouter::HittestDelegate::AcceptHitTarget( } RenderWidgetHostInputEventRouter::RenderWidgetHostInputEventRouter() - : current_touch_target_(nullptr), active_touches_(0) {} + : touch_target_(nullptr), + gesture_target_(nullptr), + active_touches_(0) {} RenderWidgetHostInputEventRouter::~RenderWidgetHostInputEventRouter() { // We may be destroyed before some of the owners in the map, so we must @@ -144,6 +160,31 @@ void RenderWidgetHostInputEventRouter::RouteMouseWheelEvent( target->ProcessMouseWheelEvent(*event); } +void RenderWidgetHostInputEventRouter::RouteGestureEvent( + RenderWidgetHostViewBase* root_view, + blink::WebGestureEvent* event, + const ui::LatencyInfo& latency) { + // We use GestureTapDown to detect the start of a gesture sequence since there + // is no WebGestureEvent equivalent for ET_GESTURE_BEGIN. Note that this + // means the GestureFlingCancel that always comes between ET_GESTURE_BEGIN and + // GestureTapDown is sent to the previous target, in case it is still in a + // fling. + if (event->type == blink::WebInputEvent::GestureTapDown) { + DCHECK(!gesture_target_queue_.empty()); + const GestureTargetData& data = gesture_target_queue_.front(); + gesture_target_ = data.target; + gesture_delta_ = data.delta; + gesture_target_queue_.pop_front(); + } + + if (!gesture_target_) + return; + + event->x += gesture_delta_.x(); + event->y += gesture_delta_.y(); + gesture_target_->ProcessGestureEvent(*event, latency); +} + void RenderWidgetHostInputEventRouter::RouteTouchEvent( RenderWidgetHostViewBase* root_view, blink::WebTouchEvent* event, @@ -153,46 +194,48 @@ void RenderWidgetHostInputEventRouter::RouteTouchEvent( if (!active_touches_) { // Since this is the first touch, it defines the target for the rest // of this sequence. - DCHECK(!current_touch_target_); + DCHECK(!touch_target_); gfx::Point transformed_point; gfx::Point original_point(event->touches[0].position.x, event->touches[0].position.y); - current_touch_target_ = + touch_target_ = FindEventTarget(root_view, original_point, &transformed_point); - if (!current_touch_target_) - return; // TODO(wjmaclean): Instead of just computing a delta, we should extract // the complete transform. We assume it doesn't change for the duration // of the touch sequence, though this could be wrong; a better approach - // might be to always transform each point to the current_touch_target_ + // might be to always transform each point to the touch_target_ // for the duration of the sequence. touch_delta_ = transformed_point - original_point; + gesture_target_queue_.emplace_back(touch_target_, touch_delta_); + + if (!touch_target_) + return; } ++active_touches_; - if (current_touch_target_) { + if (touch_target_) { TransformEventTouchPositions(event, touch_delta_); - current_touch_target_->ProcessTouchEvent(*event, latency); + touch_target_->ProcessTouchEvent(*event, latency); } break; } case blink::WebInputEvent::TouchMove: - if (current_touch_target_) { + if (touch_target_) { TransformEventTouchPositions(event, touch_delta_); - current_touch_target_->ProcessTouchEvent(*event, latency); + touch_target_->ProcessTouchEvent(*event, latency); } break; case blink::WebInputEvent::TouchEnd: case blink::WebInputEvent::TouchCancel: - if (!current_touch_target_) + if (!touch_target_) break; DCHECK(active_touches_); TransformEventTouchPositions(event, touch_delta_); - current_touch_target_->ProcessTouchEvent(*event, latency); + touch_target_->ProcessTouchEvent(*event, latency); --active_touches_; if (!active_touches_) { - current_touch_target_ = nullptr; + touch_target_ = nullptr; touch_delta_ = gfx::Vector2d(); } break; diff --git a/content/browser/renderer_host/render_widget_host_input_event_router.h b/content/browser/renderer_host/render_widget_host_input_event_router.h index 5aba015..b4123539 100644 --- a/content/browser/renderer_host/render_widget_host_input_event_router.h +++ b/content/browser/renderer_host/render_widget_host_input_event_router.h @@ -6,9 +6,12 @@ #define CONTENT_BROWSER_RENDERER_HOST_RENDER_WIDGET_HOST_INPUT_EVENT_ROUTER_H_ #include <stdint.h> + +#include <deque> #include <unordered_map> #include "base/containers/hash_tables.h" +#include "base/gtest_prod_util.h" #include "base/macros.h" #include "cc/surfaces/surface_hittest_delegate.h" #include "cc/surfaces/surface_id.h" @@ -19,6 +22,7 @@ struct FrameHostMsg_HittestData_Params; namespace blink { +class WebGestureEvent; class WebMouseEvent; class WebMouseWheelEvent; class WebTouchEvent; @@ -55,6 +59,9 @@ class CONTENT_EXPORT RenderWidgetHostInputEventRouter blink::WebMouseEvent* event); void RouteMouseWheelEvent(RenderWidgetHostViewBase* root_view, blink::WebMouseWheelEvent* event); + void RouteGestureEvent(RenderWidgetHostViewBase* root_view, + blink::WebGestureEvent* event, + const ui::LatencyInfo& latency); void RouteTouchEvent(RenderWidgetHostViewBase* root_view, blink::WebTouchEvent *event, const ui::LatencyInfo& latency); @@ -89,6 +96,14 @@ class CONTENT_EXPORT RenderWidgetHostInputEventRouter using SurfaceIdNamespaceOwnerMap = base::hash_map<uint32_t, RenderWidgetHostViewBase*>; + struct GestureTargetData { + RenderWidgetHostViewBase* target; + const gfx::Vector2d delta; + + GestureTargetData(RenderWidgetHostViewBase* target, gfx::Vector2d delta) + : target(target), delta(delta) {} + }; + using GestureTargetQueue = std::deque<GestureTargetData>; void ClearAllObserverRegistrations(); @@ -97,13 +112,18 @@ class CONTENT_EXPORT RenderWidgetHostInputEventRouter gfx::Point* transformed_point); SurfaceIdNamespaceOwnerMap owner_map_; - RenderWidgetHostViewBase* current_touch_target_; + GestureTargetQueue gesture_target_queue_; + RenderWidgetHostViewBase* touch_target_; + RenderWidgetHostViewBase* gesture_target_; gfx::Vector2d touch_delta_; + gfx::Vector2d gesture_delta_; int active_touches_; std::unordered_map<cc::SurfaceId, HittestData, cc::SurfaceIdHash> hittest_data_; DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostInputEventRouter); + FRIEND_TEST_ALL_PREFIXES(SitePerProcessBrowserTest, + InputEventRouterGestureTargetQueueTest); }; } // namespace content diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc index 6963b21..3a46b4c 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.cc +++ b/content/browser/renderer_host/render_widget_host_view_aura.cc @@ -481,6 +481,7 @@ RenderWidgetHostViewAura::RenderWidgetHostViewAura(RenderWidgetHost* host, begin_frame_observer_proxy_(this), set_focus_on_mouse_down_or_key_event_(false), device_scale_factor_(0.0f), + disable_input_event_router_for_testing_(false), weak_ptr_factory_(this) { if (!is_guest_view_hack_) host_->SetView(this); @@ -869,7 +870,8 @@ bool RenderWidgetHostViewAura::ShouldRouteEvent(const ui::Event* event) const { // frame. TODO(wjmaclean): At present, this doesn't work for OOPIF, but // it should be a simple extension to modify RenderWidgetHostViewChildFrame // in a similar manner to RenderWidgetHostViewGuest. - bool result = host_->delegate() && host_->delegate()->GetInputEventRouter(); + bool result = host_->delegate() && host_->delegate()->GetInputEventRouter() && + !disable_input_event_router_for_testing_; if (event->IsMouseEvent()) result = result && SiteIsolationPolicy::AreCrossProcessFramesPossible(); return result; @@ -2260,6 +2262,12 @@ void RenderWidgetHostViewAura::ProcessTouchEvent( host_->ForwardTouchEventWithLatencyInfo(event, latency); } +void RenderWidgetHostViewAura::ProcessGestureEvent( + const blink::WebGestureEvent& event, + const ui::LatencyInfo& latency) { + host_->ForwardGestureEventWithLatencyInfo(event, latency); +} + void RenderWidgetHostViewAura::TransformPointToLocalCoordSpace( const gfx::Point& point, cc::SurfaceId original_surface, @@ -2368,11 +2376,21 @@ void RenderWidgetHostViewAura::OnGestureEvent(ui::GestureEvent* event) { blink::WebGestureEvent fling_cancel = gesture; fling_cancel.type = blink::WebInputEvent::GestureFlingCancel; fling_cancel.sourceDevice = blink::WebGestureDeviceTouchscreen; - host_->ForwardGestureEvent(fling_cancel); + if (ShouldRouteEvent(event)) { + host_->delegate()->GetInputEventRouter()->RouteGestureEvent( + this, &fling_cancel, ui::LatencyInfo()); + } else { + host_->ForwardGestureEvent(fling_cancel); + } } if (gesture.type != blink::WebInputEvent::Undefined) { - host_->ForwardGestureEventWithLatencyInfo(gesture, *event->latency()); + if (ShouldRouteEvent(event)) { + host_->delegate()->GetInputEventRouter()->RouteGestureEvent( + this, &gesture, *event->latency()); + } else { + host_->ForwardGestureEventWithLatencyInfo(gesture, *event->latency()); + } if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN || event->type() == ui::ET_GESTURE_SCROLL_UPDATE || @@ -2738,6 +2756,7 @@ void RenderWidgetHostViewAura::SetSelectionControllerClientForTest( scoped_ptr<TouchSelectionControllerClientAura> client) { selection_controller_client_.swap(client); CreateSelectionController(); + disable_input_event_router_for_testing_ = true; } void RenderWidgetHostViewAura::InternalSetBounds(const gfx::Rect& rect) { diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h index 76e402f..7e9b2b3 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.h +++ b/content/browser/renderer_host/render_widget_host_view_aura.h @@ -202,6 +202,8 @@ class CONTENT_EXPORT RenderWidgetHostViewAura void ProcessMouseWheelEvent(const blink::WebMouseWheelEvent& event) override; void ProcessTouchEvent(const blink::WebTouchEvent& event, const ui::LatencyInfo& latency) override; + void ProcessGestureEvent(const blink::WebGestureEvent& event, + const ui::LatencyInfo& latency) override; void TransformPointToLocalCoordSpace(const gfx::Point& point, cc::SurfaceId original_surface, gfx::Point* transformed_point) override; @@ -703,6 +705,11 @@ class CONTENT_EXPORT RenderWidgetHostViewAura float device_scale_factor_; + // Allows tests to send gesture events for testing without first sending a + // corresponding touch sequence, as would be required by + // RenderWidgetHostInputEventRouter. + bool disable_input_event_router_for_testing_; + base::WeakPtrFactory<RenderWidgetHostViewAura> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewAura); diff --git a/content/browser/renderer_host/render_widget_host_view_base.h b/content/browser/renderer_host/render_widget_host_view_base.h index 94fbbb6..1cace30 100644 --- a/content/browser/renderer_host/render_widget_host_view_base.h +++ b/content/browser/renderer_host/render_widget_host_view_base.h @@ -221,7 +221,9 @@ class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView, virtual void ProcessMouseEvent(const blink::WebMouseEvent& event) {} virtual void ProcessMouseWheelEvent(const blink::WebMouseWheelEvent& event) {} virtual void ProcessTouchEvent(const blink::WebTouchEvent& event, - const ui::LatencyInfo& latency) {} + const ui::LatencyInfo& latency) {} + virtual void ProcessGestureEvent(const blink::WebGestureEvent& event, + const ui::LatencyInfo& latency) {} // Transform a point that is in the coordinate space of a Surface that is // embedded within the RenderWidgetHostViewBase's Surface to the diff --git a/content/browser/renderer_host/render_widget_host_view_mac.h b/content/browser/renderer_host/render_widget_host_view_mac.h index 46d1813..20579a5 100644 --- a/content/browser/renderer_host/render_widget_host_view_mac.h +++ b/content/browser/renderer_host/render_widget_host_view_mac.h @@ -362,6 +362,8 @@ class CONTENT_EXPORT RenderWidgetHostViewMac void ProcessMouseWheelEvent(const blink::WebMouseWheelEvent& event) override; void ProcessTouchEvent(const blink::WebTouchEvent& event, const ui::LatencyInfo& latency) override; + void ProcessGestureEvent(const blink::WebGestureEvent& event, + const ui::LatencyInfo& latency) override; void TransformPointToLocalCoordSpace(const gfx::Point& point, cc::SurfaceId original_surface, gfx::Point* transformed_point) override; diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm index e1a196b..62b0b38 100644 --- a/content/browser/renderer_host/render_widget_host_view_mac.mm +++ b/content/browser/renderer_host/render_widget_host_view_mac.mm @@ -1615,6 +1615,12 @@ void RenderWidgetHostViewMac::ProcessTouchEvent( render_widget_host_->ForwardTouchEventWithLatencyInfo(event, latency); } +void RenderWidgetHostViewMac::ProcessGestureEvent( + const blink::WebGestureEvent& event, + const ui::LatencyInfo& latency) { + render_widget_host_->ForwardGestureEventWithLatencyInfo(event, latency); +} + void RenderWidgetHostViewMac::TransformPointToLocalCoordSpace( const gfx::Point& point, cc::SurfaceId original_surface, diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc index 4031eec..1482436 100644 --- a/content/browser/site_per_process_browsertest.cc +++ b/content/browser/site_per_process_browsertest.cc @@ -26,10 +26,13 @@ #include "content/browser/frame_host/render_frame_proxy_host.h" #include "content/browser/frame_host/render_widget_host_view_child_frame.h" #include "content/browser/gpu/compositor_util.h" +#include "content/browser/renderer_host/input/synthetic_tap_gesture.h" #include "content/browser/renderer_host/render_view_host_impl.h" #include "content/browser/renderer_host/render_widget_host_input_event_router.h" +#include "content/browser/renderer_host/render_widget_host_view_aura.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/common/frame_messages.h" +#include "content/common/input/synthetic_tap_gesture_params.h" #include "content/common/view_messages.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_service.h" @@ -4576,6 +4579,239 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, "window.domAutomationController.send(getLastTouchEvent());", &result)); EXPECT_EQ("touchstart", result); } + +namespace { + +// Declared here to be close to the SubframeGestureEventRouting test. +void OnSyntheticGestureCompleted(scoped_refptr<MessageLoopRunner> runner, + SyntheticGesture::Result result) { + EXPECT_EQ(SyntheticGesture::GESTURE_FINISHED, result); + runner->Quit(); +} + +} // namespace anonymous + +IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, + SubframeGestureEventRouting) { + GURL main_url(embedded_test_server()->GetURL( + "/frame_tree/page_with_positioned_nested_frames.html")); + EXPECT_TRUE(NavigateToURL(shell(), main_url)); + + WebContentsImpl* web_contents = + static_cast<WebContentsImpl*>(shell()->web_contents()); + FrameTreeNode* root = web_contents->GetFrameTree()->root(); + ASSERT_EQ(1U, root->child_count()); + + GURL frame_url( + embedded_test_server()->GetURL("b.com", "/page_with_click_handler.html")); + NavigateFrameToURL(root->child_at(0), frame_url); + auto child_frame_host = root->child_at(0)->current_frame_host(); + EXPECT_TRUE(WaitForRenderFrameReady(child_frame_host)); + + // Synchronize with the child and parent renderers to guarantee that the + // surface information required for event hit testing is ready. + RenderWidgetHostViewBase* child_rwhv = static_cast<RenderWidgetHostViewBase*>( + child_frame_host->GetView()); + SurfaceHitTestReadyNotifier notifier( + static_cast<RenderWidgetHostViewChildFrame*>(child_rwhv)); + notifier.WaitForSurfaceReady(); + + // There have been no GestureTaps sent yet. + { + std::string result; + EXPECT_TRUE(ExecuteScriptAndExtractString( + child_frame_host, + "window.domAutomationController.send(getClickStatus());", &result)); + EXPECT_EQ("0 clicks received", result); + } + + // Simulate touch sequence to send GestureTap to sub-frame. + SyntheticTapGestureParams params; + params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT; + gfx::Point center(150, 150); + params.position = gfx::PointF(center.x(), center.y()); + params.duration_ms = 100; + scoped_ptr<SyntheticTapGesture> gesture(new SyntheticTapGesture(params)); + + scoped_refptr<MessageLoopRunner> runner = new MessageLoopRunner(); + + RenderWidgetHostImpl* render_widget_host = + root->current_frame_host()->GetRenderWidgetHost(); + // TODO(wjmaclean): Convert the call to base::Bind() to a lambda someday. + render_widget_host->QueueSyntheticGesture( + std::move(gesture), base::Bind(OnSyntheticGestureCompleted, runner)); + + // We need to run the message loop while we wait for the synthetic gesture + // to be processed; the callback registered above will get us out of the + // message loop when that happens. + runner->Run(); + runner = nullptr; + + // Verify click handler in subframe was invoked + { + std::string result; + EXPECT_TRUE(ExecuteScriptAndExtractString( + child_frame_host, + "window.domAutomationController.send(getClickStatus());", &result)); + EXPECT_EQ("1 click received", result); + } +} + +namespace { + +// Defined here to be close to +// SitePerProcessBrowserTest.InputEventRouterGestureTargetQueueTest. +void SendTouchTapWithExpectedTarget( + RenderWidgetHostViewBase* root_view, + const gfx::Point& touch_point, + RenderWidgetHostViewBase*& router_touch_target, + const RenderWidgetHostViewBase* expected_target) { + auto root_view_aura = static_cast<RenderWidgetHostViewAura*>(root_view); + ui::TouchEvent touch_event_pressed(ui::ET_TOUCH_PRESSED, touch_point, 0, + 0, ui::EventTimeForNow(), 30.f, 30.f, 0.f, + 0.f); + root_view_aura->OnTouchEvent(&touch_event_pressed); + EXPECT_EQ(expected_target, router_touch_target); + ui::TouchEvent touch_event_released(ui::ET_TOUCH_RELEASED, touch_point, + 0, 0, ui::EventTimeForNow(), 30.f, 30.f, + 0.f, 0.f); + root_view_aura->OnTouchEvent(&touch_event_released); + EXPECT_EQ(nullptr, router_touch_target); +} + +void SendGestureTapSequenceWithExpectedTarget( + RenderWidgetHostViewBase* root_view, + gfx::Point gesture_point, + RenderWidgetHostViewBase*& router_gesture_target, + const RenderWidgetHostViewBase* old_expected_target, + const RenderWidgetHostViewBase* expected_target) { + auto root_view_aura = static_cast<RenderWidgetHostViewAura*>(root_view); + + ui::GestureEvent gesture_begin_event( + gesture_point.x(), gesture_point.y(), 0, ui::EventTimeForNow(), + ui::GestureEventDetails(ui::ET_GESTURE_BEGIN)); + root_view_aura->OnGestureEvent(&gesture_begin_event); + // We expect to still have the old gesture target in place for the + // GestureFlingCancel that will be inserted before GestureTapDown. + // Note: the GestureFlingCancel is inserted by RenderWidgetHostViewAura:: + // OnGestureEvent() when it sees ui::ET_GESTURE_TAP_DOWN, so we don't + // explicitly add it here. + EXPECT_EQ(old_expected_target, router_gesture_target); + + ui::GestureEvent gesture_tap_down_event( + gesture_point.x(), gesture_point.y(), 0, ui::EventTimeForNow(), + ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN)); + root_view_aura->OnGestureEvent(&gesture_tap_down_event); + EXPECT_EQ(expected_target, router_gesture_target); + + ui::GestureEvent gesture_show_press_event( + gesture_point.x(), gesture_point.y(), 0, ui::EventTimeForNow(), + ui::GestureEventDetails(ui::ET_GESTURE_SHOW_PRESS)); + root_view_aura->OnGestureEvent(&gesture_show_press_event); + EXPECT_EQ(expected_target, router_gesture_target); + + ui::GestureEventDetails gesture_tap_details(ui::ET_GESTURE_TAP); + gesture_tap_details.set_tap_count(1); + ui::GestureEvent gesture_tap_event( + gesture_point.x(), gesture_point.y(), 0, ui::EventTimeForNow(), + gesture_tap_details); + root_view_aura->OnGestureEvent(&gesture_tap_event); + EXPECT_EQ(expected_target, router_gesture_target); + + ui::GestureEvent gesture_end_event( + gesture_point.x(), gesture_point.y(), 0, ui::EventTimeForNow(), + ui::GestureEventDetails(ui::ET_GESTURE_END)); + root_view_aura->OnGestureEvent(&gesture_end_event); + EXPECT_EQ(expected_target, router_gesture_target); +} + +} // namespace anonymous + +IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, + InputEventRouterGestureTargetQueueTest) { + GURL main_url(embedded_test_server()->GetURL( + "/frame_tree/page_with_positioned_nested_frames.html")); + EXPECT_TRUE(NavigateToURL(shell(), main_url)); + + WebContentsImpl* web_contents = + static_cast<WebContentsImpl*>(shell()->web_contents()); + FrameTreeNode* root = web_contents->GetFrameTree()->root(); + ASSERT_EQ(1U, root->child_count()); + + GURL frame_url( + embedded_test_server()->GetURL("b.com", "/page_with_click_handler.html")); + NavigateFrameToURL(root->child_at(0), frame_url); + auto child_frame_host = root->child_at(0)->current_frame_host(); + EXPECT_TRUE(WaitForRenderFrameReady(child_frame_host)); + + // Synchronize with the child and parent renderers to guarantee that the + // surface information required for event hit testing is ready. + auto rwhv_child = + static_cast<RenderWidgetHostViewBase*>(child_frame_host->GetView()); + SurfaceHitTestReadyNotifier notifier( + static_cast<RenderWidgetHostViewChildFrame*>(rwhv_child)); + notifier.WaitForSurfaceReady(); + + // All touches & gestures are sent to the main frame's view, and should be + // routed appropriately from there. + auto rwhv_parent = static_cast<RenderWidgetHostViewBase*>( + web_contents->GetRenderWidgetHostView()); + + RenderWidgetHostInputEventRouter* router = + web_contents->GetInputEventRouter(); + EXPECT_TRUE(router->gesture_target_queue_.empty()); + EXPECT_EQ(nullptr, router->gesture_target_); + + // Send touch sequence to main-frame. + gfx::Point main_frame_point(25, 25); + SendTouchTapWithExpectedTarget(rwhv_parent, main_frame_point, + router->touch_target_, rwhv_parent); + EXPECT_EQ(1LU, router->gesture_target_queue_.size()); + EXPECT_EQ(nullptr, router->gesture_target_); + + + // Send touch sequence to child. + gfx::Point child_center(150, 150); + SendTouchTapWithExpectedTarget(rwhv_parent, child_center, + router->touch_target_, rwhv_child); + EXPECT_EQ(2LU, router->gesture_target_queue_.size()); + EXPECT_EQ(nullptr, router->gesture_target_); + + // Send another touch sequence to main frame. + SendTouchTapWithExpectedTarget(rwhv_parent, main_frame_point, + router->touch_target_, rwhv_parent); + EXPECT_EQ(3LU, router->gesture_target_queue_.size()); + EXPECT_EQ(nullptr, router->gesture_target_); + + // Send Gestures to clear GestureTargetQueue. + + // The first touch sequence should generate a GestureTapDown, sent to the + // main frame. + SendGestureTapSequenceWithExpectedTarget(rwhv_parent, main_frame_point, + router->gesture_target_, nullptr, + rwhv_parent); + EXPECT_EQ(2LU, router->gesture_target_queue_.size()); + // Note: rwhv_parent is the target used for GestureFlingCancel sent by + // RenderWidgetHostViewAura::OnGestureEvent() at the start of the next gesture + // sequence; the sequence itself goes to rwhv_child. + EXPECT_EQ(rwhv_parent, router->gesture_target_); + + // The second touch sequence should generate a GestureTapDown, sent to the + // child frame. + SendGestureTapSequenceWithExpectedTarget(rwhv_parent, child_center, + router->gesture_target_, rwhv_parent, + rwhv_child); + EXPECT_EQ(1LU, router->gesture_target_queue_.size()); + EXPECT_EQ(rwhv_child, router->gesture_target_); + + // The third touch sequence should generate a GestureTapDown, sent to the + // main frame. + SendGestureTapSequenceWithExpectedTarget(rwhv_parent, main_frame_point, + router->gesture_target_, rwhv_child, + rwhv_parent); + EXPECT_EQ(0LU, router->gesture_target_queue_.size()); + EXPECT_EQ(rwhv_parent, router->gesture_target_); +} #endif // defined(USE_AURA) // Ensure that a cross-process subframe can receive keyboard events when in diff --git a/content/test/data/page_with_click_handler.html b/content/test/data/page_with_click_handler.html new file mode 100644 index 0000000..cebf4ec --- /dev/null +++ b/content/test/data/page_with_click_handler.html @@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html style="width: 100%; height: 100%"> +<head> + <script> + clicksReceived = 0; + + function clickHandler(e) { + var clickResult = document.getElementById("click-results"); + clicksReceived++; + if (clicksReceived == 1) + clickResult.textContent = "1 click received"; + else + clickResult.textContent = clicksReceived + " clicks received"; + } + + function getClickStatus() { + var clickResult = document.getElementById("click-results"); + return clickResult.textContent; + } + + window.addEventListener('load', function(){ + document.body.addEventListener('click', + function(e){ + clickHandler(e); + }, false); + }, false); + </script> +</head> + +<!-- Be sure to set 100% width/height so the test can determine an appropriate + screen region for targeting events. --> +<body style="width: 100%; height: 100%"> + Page with Click Handler + <div id="click-results">0 clicks received</div> +</body> +</html> |
