Commit b9e5ed2a authored by Kevin McNee's avatar Kevin McNee Committed by Commit Bot

Refactor OOPIF scroll bubbling state and cancellation

Whether or not a child is bubbling scroll was being tracked in both
CrossProcessFrameConnector and RenderWidgetHostViewChildFrame. It's
simpler to just have it in RWHVCF.

There are several cases where we generate fake scroll updates when
cancelling scroll bubbling. This is a relic from the non-scroll latching
code paths and has been removed. We also deduplicate the scroll bubbling
cancellation code.

We were tracking the view from which scroll events are bubbled by keeping
a reference to that view's parent. We now just keep a reference to the
originating view directly.

We also now properly cancel scroll bubbling when a child detaches.

Bug: 828422, 897216
Change-Id: Iee983bd9ea05b324d556c66320a1bc5e544de057
Reviewed-on: https://chromium-review.googlesource.com/c/1357563Reviewed-by: default avatarKen Buchanan <kenrb@chromium.org>
Commit-Queue: Kevin McNee <mcnee@chromium.org>
Cr-Commit-Position: refs/heads/master@{#615184}
parent 0f1396ae
...@@ -68,8 +68,7 @@ RenderFrameHostImpl* RootRenderFrameHost(RenderFrameHostImpl* frame) { ...@@ -68,8 +68,7 @@ RenderFrameHostImpl* RootRenderFrameHost(RenderFrameHostImpl* frame) {
CrossProcessFrameConnector::CrossProcessFrameConnector( CrossProcessFrameConnector::CrossProcessFrameConnector(
RenderFrameProxyHost* frame_proxy_in_parent_renderer) RenderFrameProxyHost* frame_proxy_in_parent_renderer)
: FrameConnectorDelegate(IsUseZoomForDSFEnabled()), : FrameConnectorDelegate(IsUseZoomForDSFEnabled()),
frame_proxy_in_parent_renderer_(frame_proxy_in_parent_renderer), frame_proxy_in_parent_renderer_(frame_proxy_in_parent_renderer) {
is_scroll_bubbling_(false) {
frame_proxy_in_parent_renderer->frame_tree_node() frame_proxy_in_parent_renderer->frame_tree_node()
->render_manager() ->render_manager()
->current_frame_host() ->current_frame_host()
...@@ -119,14 +118,13 @@ void CrossProcessFrameConnector::SetView(RenderWidgetHostViewChildFrame* view) { ...@@ -119,14 +118,13 @@ void CrossProcessFrameConnector::SetView(RenderWidgetHostViewChildFrame* view) {
// The RenderWidgetHostDelegate needs to be checked because SetView() can // The RenderWidgetHostDelegate needs to be checked because SetView() can
// be called during nested WebContents destruction. See // be called during nested WebContents destruction. See
// https://crbug.com/644306. // https://crbug.com/644306.
if (is_scroll_bubbling_ && GetParentRenderWidgetHostView() && if (GetParentRenderWidgetHostView() &&
GetParentRenderWidgetHostView()->host()->delegate()) { GetParentRenderWidgetHostView()->host()->delegate()) {
GetParentRenderWidgetHostView() GetParentRenderWidgetHostView()
->host() ->host()
->delegate() ->delegate()
->GetInputEventRouter() ->GetInputEventRouter()
->CancelScrollBubbling(view_); ->WillDetachChildView(view_);
is_scroll_bubbling_ = false;
} }
view_->SetFrameConnectorDelegate(nullptr); view_->SetFrameConnectorDelegate(nullptr);
} }
...@@ -298,14 +296,7 @@ void CrossProcessFrameConnector::BubbleScrollEvent( ...@@ -298,14 +296,7 @@ void CrossProcessFrameConnector::BubbleScrollEvent(
// action of the parent frame to Auto so that this gesture event is allowed. // action of the parent frame to Auto so that this gesture event is allowed.
parent_view->host()->input_router()->ForceSetTouchActionAuto(); parent_view->host()->input_router()->ForceSetTouchActionAuto();
if (event.GetType() == blink::WebInputEvent::kGestureScrollBegin) { event_router->BubbleScrollEvent(parent_view, view_, resent_gesture_event);
event_router->BubbleScrollEvent(parent_view, resent_gesture_event, view_);
is_scroll_bubbling_ = true;
} else if (is_scroll_bubbling_) {
event_router->BubbleScrollEvent(parent_view, resent_gesture_event, view_);
}
if (event.GetType() == blink::WebInputEvent::kGestureScrollEnd)
is_scroll_bubbling_ = false;
} }
bool CrossProcessFrameConnector::HasFocus() { bool CrossProcessFrameConnector::HasFocus() {
......
...@@ -202,8 +202,6 @@ class CONTENT_EXPORT CrossProcessFrameConnector ...@@ -202,8 +202,6 @@ class CONTENT_EXPORT CrossProcessFrameConnector
// which is set through CSS. // which is set through CSS.
bool is_hidden_ = false; bool is_hidden_ = false;
bool is_scroll_bubbling_;
// Used to make sure we only log UMA once per renderer crash. // Used to make sure we only log UMA once per renderer crash.
bool is_crash_already_logged_ = false; bool is_crash_already_logged_ = false;
......
...@@ -43,15 +43,6 @@ void TransformEventTouchPositions(blink::WebTouchEvent* event, ...@@ -43,15 +43,6 @@ void TransformEventTouchPositions(blink::WebTouchEvent* event,
} }
} }
blink::WebGestureEvent DummyGestureScrollUpdate(
base::TimeTicks time_stamp,
blink::WebGestureDevice source_device =
blink::kWebGestureDeviceUninitialized) {
return blink::WebGestureEvent(blink::WebInputEvent::kGestureScrollUpdate,
blink::WebInputEvent::kNoModifiers, time_stamp,
source_device);
}
gfx::PointF ComputePointInRootInPixels( gfx::PointF ComputePointInRootInPixels(
const gfx::PointF& point, const gfx::PointF& point,
content::RenderWidgetHostViewBase* root_view, content::RenderWidgetHostViewBase* root_view,
...@@ -272,11 +263,11 @@ void RenderWidgetHostInputEventRouter::OnRenderWidgetHostViewBaseDestroyed( ...@@ -272,11 +263,11 @@ void RenderWidgetHostInputEventRouter::OnRenderWidgetHostViewBaseDestroyed(
if (view == touchpad_gesture_target_.target) if (view == touchpad_gesture_target_.target)
touchpad_gesture_target_.target = nullptr; touchpad_gesture_target_.target = nullptr;
if (view == bubbling_gesture_scroll_target_.target) { if (view == bubbling_gesture_scroll_target_) {
bubbling_gesture_scroll_target_.target = nullptr; bubbling_gesture_scroll_target_ = nullptr;
first_bubbling_scroll_target_.target = nullptr; bubbling_gesture_scroll_origin_ = nullptr;
} else if (view == first_bubbling_scroll_target_.target) { } else if (view == bubbling_gesture_scroll_origin_) {
first_bubbling_scroll_target_.target = nullptr; bubbling_gesture_scroll_origin_ = nullptr;
} }
if (view == last_mouse_move_target_) { if (view == last_mouse_move_target_) {
...@@ -593,17 +584,11 @@ void RenderWidgetHostInputEventRouter::DispatchMouseWheelEvent( ...@@ -593,17 +584,11 @@ void RenderWidgetHostInputEventRouter::DispatchMouseWheelEvent(
blink::WebMouseWheelEvent::kPhaseEnded || blink::WebMouseWheelEvent::kPhaseEnded ||
mouse_wheel_event.momentum_phase == mouse_wheel_event.momentum_phase ==
blink::WebMouseWheelEvent::kPhaseEnded) && blink::WebMouseWheelEvent::kPhaseEnded) &&
bubbling_gesture_scroll_target_.target) { bubbling_gesture_scroll_target_) {
// Send a GSE to the bubbling target and cancel scroll bubbling since // Send a GSE to the bubbling target and cancel scroll bubbling since
// the wheel target view is destroyed and the wheel end event won't get // the wheel target view is destroyed and the wheel end event won't get
// processed. // processed.
blink::WebGestureEvent fake_scroll_update = CancelScrollBubbling();
DummyGestureScrollUpdate(mouse_wheel_event.TimeStamp(),
bubbling_gesture_scroll_source_device_);
SendGestureScrollEnd(bubbling_gesture_scroll_target_.target,
fake_scroll_update);
bubbling_gesture_scroll_target_.target = nullptr;
first_bubbling_scroll_target_.target = nullptr;
} }
} }
} }
...@@ -789,13 +774,7 @@ void RenderWidgetHostInputEventRouter::DispatchTouchEvent( ...@@ -789,13 +774,7 @@ void RenderWidgetHostInputEventRouter::DispatchTouchEvent(
} }
if (is_sequence_start) { if (is_sequence_start) {
if (touch_target_.target == bubbling_gesture_scroll_target_.target) { CancelScrollBubblingIfConflicting(touch_target_.target);
SendGestureScrollEnd(
bubbling_gesture_scroll_target_.target,
DummyGestureScrollUpdate(touch_event.TimeStamp(),
bubbling_gesture_scroll_source_device_));
CancelScrollBubbling(bubbling_gesture_scroll_target_.target);
}
} }
touch_event_ack_queue_->Add(touch_event.unique_touch_event_id, touch_event_ack_queue_->Add(touch_event.unique_touch_event_id,
...@@ -987,6 +966,28 @@ void RenderWidgetHostInputEventRouter::ReportBubblingScrollToSameView( ...@@ -987,6 +966,28 @@ void RenderWidgetHostInputEventRouter::ReportBubblingScrollToSameView(
namespace { namespace {
// Returns true if |target_view| is one of |starting_view|'s ancestors.
// If |stay_within| is provided, we only consider ancestors within that
// sub-tree.
bool IsAncestorView(RenderWidgetHostViewChildFrame* starting_view,
const RenderWidgetHostViewBase* target_view,
const RenderWidgetHostViewBase* stay_within = nullptr) {
RenderWidgetHostViewBase* cur_view = starting_view->GetParentView();
while (cur_view) {
if (cur_view == target_view)
return true;
if (stay_within && cur_view == stay_within)
return false;
cur_view = cur_view->IsRenderWidgetHostViewChildFrame()
? static_cast<RenderWidgetHostViewChildFrame*>(cur_view)
->GetParentView()
: nullptr;
}
return false;
}
// Given |event| in root coordinates, return an event in |target_view|'s // Given |event| in root coordinates, return an event in |target_view|'s
// coordinates. // coordinates.
blink::WebGestureEvent GestureEventInTarget( blink::WebGestureEvent GestureEventInTarget(
...@@ -1003,8 +1004,8 @@ blink::WebGestureEvent GestureEventInTarget( ...@@ -1003,8 +1004,8 @@ blink::WebGestureEvent GestureEventInTarget(
void RenderWidgetHostInputEventRouter::BubbleScrollEvent( void RenderWidgetHostInputEventRouter::BubbleScrollEvent(
RenderWidgetHostViewBase* target_view, RenderWidgetHostViewBase* target_view,
const blink::WebGestureEvent& event, RenderWidgetHostViewChildFrame* resending_view,
const RenderWidgetHostViewBase* resending_view) { const blink::WebGestureEvent& event) {
DCHECK(target_view); DCHECK(target_view);
DCHECK(event.GetType() == blink::WebInputEvent::kGestureScrollBegin || DCHECK(event.GetType() == blink::WebInputEvent::kGestureScrollBegin ||
event.GetType() == blink::WebInputEvent::kGestureScrollUpdate || event.GetType() == blink::WebInputEvent::kGestureScrollUpdate ||
...@@ -1018,6 +1019,9 @@ void RenderWidgetHostInputEventRouter::BubbleScrollEvent( ...@@ -1018,6 +1019,9 @@ void RenderWidgetHostInputEventRouter::BubbleScrollEvent(
// If target_view has unrelated gesture events in progress, do // If target_view has unrelated gesture events in progress, do
// not proceed. This could cause confusion between independent // not proceed. This could cause confusion between independent
// scrolls. // scrolls.
// TODO(mcnee): If we are unable to bubble this gesture sequence, we
// should inform the child view, so that it does not go on to send us
// the updates. See https://crbug.com/828422
if (target_view == touchscreen_gesture_target_.target || if (target_view == touchscreen_gesture_target_.target ||
target_view == touchpad_gesture_target_.target || target_view == touchpad_gesture_target_.target ||
target_view == touch_target_.target) { target_view == touch_target_.target) {
...@@ -1029,18 +1033,18 @@ void RenderWidgetHostInputEventRouter::BubbleScrollEvent( ...@@ -1029,18 +1033,18 @@ void RenderWidgetHostInputEventRouter::BubbleScrollEvent(
// event ack which didn't consume any scroll delta, and so another level // event ack which didn't consume any scroll delta, and so another level
// of bubbling is needed. This requires a GestureScrollEnd be sent to the // of bubbling is needed. This requires a GestureScrollEnd be sent to the
// last view, which will no longer be the scroll target. // last view, which will no longer be the scroll target.
if (bubbling_gesture_scroll_target_.target) { if (bubbling_gesture_scroll_target_) {
SendGestureScrollEnd( SendGestureScrollEnd(
bubbling_gesture_scroll_target_.target, bubbling_gesture_scroll_target_,
GestureEventInTarget(event, bubbling_gesture_scroll_target_.target)); GestureEventInTarget(event, bubbling_gesture_scroll_target_));
} else { } else {
first_bubbling_scroll_target_.target = target_view; bubbling_gesture_scroll_origin_ = resending_view;
} }
bubbling_gesture_scroll_target_.target = target_view; bubbling_gesture_scroll_target_ = target_view;
bubbling_gesture_scroll_source_device_ = event.SourceDevice(); bubbling_gesture_scroll_source_device_ = event.SourceDevice();
} else { // !(event.GetType() == blink::WebInputEvent::kGestureScrollBegin) } else { // !(event.GetType() == blink::WebInputEvent::kGestureScrollBegin)
if (!bubbling_gesture_scroll_target_.target) { if (!bubbling_gesture_scroll_target_) {
// The GestureScrollBegin event is not bubbled, don't bubble the rest of // The GestureScrollBegin event is not bubbled, don't bubble the rest of
// the scroll events. // the scroll events.
return; return;
...@@ -1049,34 +1053,31 @@ void RenderWidgetHostInputEventRouter::BubbleScrollEvent( ...@@ -1049,34 +1053,31 @@ void RenderWidgetHostInputEventRouter::BubbleScrollEvent(
// Don't bubble the GSE events that are generated and sent to intermediate // Don't bubble the GSE events that are generated and sent to intermediate
// bubbling targets. // bubbling targets.
if (event.GetType() == blink::WebInputEvent::kGestureScrollEnd && if (event.GetType() == blink::WebInputEvent::kGestureScrollEnd &&
target_view != first_bubbling_scroll_target_.target) { resending_view != bubbling_gesture_scroll_origin_) {
return; return;
} }
} }
// If the router tries to resend a gesture scroll event back to the same // If the router tries to resend a gesture scroll event back to the same
// view, we could hang. // view, we could hang.
DCHECK_NE(resending_view, bubbling_gesture_scroll_target_.target); DCHECK_NE(resending_view, bubbling_gesture_scroll_target_);
// We've seen reports of this, but don't know the cause yet. For now, // We've seen reports of this, but don't know the cause yet. For now,
// instead of CHECKing or hanging, we'll report the issue and abort scroll // instead of CHECKing or hanging, we'll report the issue and abort scroll
// bubbling. // bubbling.
// TODO(828422): Remove once this issue no longer occurs. // TODO(828422): Remove once this issue no longer occurs.
if (resending_view == bubbling_gesture_scroll_target_.target) { if (resending_view == bubbling_gesture_scroll_target_) {
ReportBubblingScrollToSameView(event, resending_view); ReportBubblingScrollToSameView(event, resending_view);
first_bubbling_scroll_target_.target = nullptr; CancelScrollBubbling();
bubbling_gesture_scroll_target_.target = nullptr;
bubbling_gesture_scroll_source_device_ =
blink::kWebGestureDeviceUninitialized;
return; return;
} }
bubbling_gesture_scroll_target_.target->ProcessGestureEvent( bubbling_gesture_scroll_target_->ProcessGestureEvent(
GestureEventInTarget(event, bubbling_gesture_scroll_target_.target), GestureEventInTarget(event, bubbling_gesture_scroll_target_),
latency_info); latency_info);
if (event.GetType() == blink::WebInputEvent::kGestureScrollEnd) { if (event.GetType() == blink::WebInputEvent::kGestureScrollEnd) {
first_bubbling_scroll_target_.target = nullptr; bubbling_gesture_scroll_origin_ = nullptr;
bubbling_gesture_scroll_target_.target = nullptr; bubbling_gesture_scroll_target_ = nullptr;
bubbling_gesture_scroll_source_device_ = bubbling_gesture_scroll_source_device_ =
blink::kWebGestureDeviceUninitialized; blink::kWebGestureDeviceUninitialized;
} }
...@@ -1085,29 +1086,18 @@ void RenderWidgetHostInputEventRouter::BubbleScrollEvent( ...@@ -1085,29 +1086,18 @@ void RenderWidgetHostInputEventRouter::BubbleScrollEvent(
void RenderWidgetHostInputEventRouter::SendGestureScrollBegin( void RenderWidgetHostInputEventRouter::SendGestureScrollBegin(
RenderWidgetHostViewBase* view, RenderWidgetHostViewBase* view,
const blink::WebGestureEvent& event) { const blink::WebGestureEvent& event) {
DCHECK_EQ(blink::WebInputEvent::kGesturePinchBegin, event.GetType());
DCHECK_EQ(blink::kWebGestureDeviceTouchscreen, event.SourceDevice());
blink::WebGestureEvent scroll_begin(event); blink::WebGestureEvent scroll_begin(event);
scroll_begin.SetType(blink::WebInputEvent::kGestureScrollBegin); scroll_begin.SetType(blink::WebInputEvent::kGestureScrollBegin);
switch (event.GetType()) {
case blink::WebInputEvent::kGestureScrollUpdate:
scroll_begin.data.scroll_begin.delta_x_hint =
event.data.scroll_update.delta_x;
scroll_begin.data.scroll_begin.delta_y_hint =
event.data.scroll_update.delta_y;
scroll_begin.data.scroll_begin.delta_hint_units =
event.data.scroll_update.delta_units;
break;
case blink::WebInputEvent::kGesturePinchBegin:
scroll_begin.data.scroll_begin.delta_x_hint = 0; scroll_begin.data.scroll_begin.delta_x_hint = 0;
scroll_begin.data.scroll_begin.delta_y_hint = 0; scroll_begin.data.scroll_begin.delta_y_hint = 0;
scroll_begin.data.scroll_begin.delta_hint_units = scroll_begin.data.scroll_begin.delta_hint_units =
blink::WebGestureEvent::kPrecisePixels; blink::WebGestureEvent::kPrecisePixels;
break;
default:
NOTREACHED();
}
view->ProcessGestureEvent( view->ProcessGestureEvent(
scroll_begin, scroll_begin,
ui::WebInputEventTraits::CreateLatencyInfoForWebGestureEvent(event)); ui::WebInputEventTraits::CreateLatencyInfoForWebGestureEvent(
scroll_begin));
} }
void RenderWidgetHostInputEventRouter::SendGestureScrollEnd( void RenderWidgetHostInputEventRouter::SendGestureScrollEnd(
...@@ -1123,13 +1113,8 @@ void RenderWidgetHostInputEventRouter::SendGestureScrollEnd( ...@@ -1123,13 +1113,8 @@ void RenderWidgetHostInputEventRouter::SendGestureScrollEnd(
scroll_end.data.scroll_end.delta_units = scroll_end.data.scroll_end.delta_units =
event.data.scroll_begin.delta_hint_units; event.data.scroll_begin.delta_hint_units;
break; break;
case blink::WebInputEvent::kGestureScrollUpdate:
scroll_end.data.scroll_end.inertial_phase =
event.data.scroll_update.inertial_phase;
scroll_end.data.scroll_end.delta_units =
event.data.scroll_update.delta_units;
break;
case blink::WebInputEvent::kGesturePinchEnd: case blink::WebInputEvent::kGesturePinchEnd:
DCHECK_EQ(blink::kWebGestureDeviceTouchscreen, event.SourceDevice());
scroll_end.data.scroll_end.inertial_phase = scroll_end.data.scroll_end.inertial_phase =
blink::WebGestureEvent::kUnknownMomentumPhase; blink::WebGestureEvent::kUnknownMomentumPhase;
scroll_end.data.scroll_end.delta_units = scroll_end.data.scroll_end.delta_units =
...@@ -1140,22 +1125,82 @@ void RenderWidgetHostInputEventRouter::SendGestureScrollEnd( ...@@ -1140,22 +1125,82 @@ void RenderWidgetHostInputEventRouter::SendGestureScrollEnd(
} }
view->ProcessGestureEvent( view->ProcessGestureEvent(
scroll_end, scroll_end,
ui::WebInputEventTraits::CreateLatencyInfoForWebGestureEvent(event)); ui::WebInputEventTraits::CreateLatencyInfoForWebGestureEvent(scroll_end));
} }
void RenderWidgetHostInputEventRouter::CancelScrollBubbling( void RenderWidgetHostInputEventRouter::SendGestureScrollEnd(
RenderWidgetHostViewBase* target_view) { RenderWidgetHostViewBase* view,
DCHECK(target_view); blink::WebGestureDevice source_device) {
if (target_view == first_bubbling_scroll_target_.target) { blink::WebGestureEvent scroll_end(blink::WebInputEvent::kGestureScrollEnd,
first_bubbling_scroll_target_.target = nullptr; blink::WebInputEvent::kNoModifiers,
bubbling_gesture_scroll_target_.target = nullptr; base::TimeTicks::Now(), source_device);
scroll_end.data.scroll_end.inertial_phase =
blink::WebGestureEvent::kUnknownMomentumPhase;
scroll_end.data.scroll_end.delta_units =
blink::WebGestureEvent::kPrecisePixels;
view->ProcessGestureEvent(
scroll_end,
ui::WebInputEventTraits::CreateLatencyInfoForWebGestureEvent(scroll_end));
}
void RenderWidgetHostInputEventRouter::WillDetachChildView(
const RenderWidgetHostViewChildFrame* detaching_view) {
// If necessary, cancel ongoing scroll bubbling in response to a frame
// connector change.
if (!bubbling_gesture_scroll_target_ || !bubbling_gesture_scroll_origin_)
return;
// We cancel bubbling only when the child view affects the current scroll
// bubbling sequence.
if (detaching_view == bubbling_gesture_scroll_origin_ ||
IsAncestorView(bubbling_gesture_scroll_origin_, detaching_view)) {
CancelScrollBubbling();
}
}
void RenderWidgetHostInputEventRouter::CancelScrollBubbling() {
DCHECK(bubbling_gesture_scroll_target_);
SendGestureScrollEnd(bubbling_gesture_scroll_target_,
bubbling_gesture_scroll_source_device_);
// TODO(mcnee): We should also inform |bubbling_gesture_scroll_origin_| that
// we are no longer bubbling its events, otherwise it could continue to send
// them and interfere with a new scroll gesture being bubbled.
// See https://crbug.com/828422
bubbling_gesture_scroll_origin_ = nullptr;
bubbling_gesture_scroll_target_ = nullptr;
bubbling_gesture_scroll_source_device_ =
blink::kWebGestureDeviceUninitialized;
}
void RenderWidgetHostInputEventRouter::CancelScrollBubblingIfConflicting(
const RenderWidgetHostViewBase* target) {
if (!target)
return;
if (!bubbling_gesture_scroll_target_ || !bubbling_gesture_scroll_origin_)
return;
const RenderWidgetHostViewBase* first_bubbling_scroll_target =
bubbling_gesture_scroll_origin_->GetParentView();
// TODO(mcnee): This seems wrong. We should not be sending an independent
// gesture sequence to any of |bubbling_gesture_scroll_origin_|'s ancestors
// up to and including |bubbling_gesture_scroll_target_|.
// See https://crbug.com/828422
if (target == bubbling_gesture_scroll_target_) {
// TODO(mcnee): We shouldn't send the scroll end if we're not actually
// cancelling.
SendGestureScrollEnd(bubbling_gesture_scroll_target_,
bubbling_gesture_scroll_source_device_);
if (bubbling_gesture_scroll_target_ == first_bubbling_scroll_target) {
bubbling_gesture_scroll_origin_ = nullptr;
bubbling_gesture_scroll_target_ = nullptr;
bubbling_gesture_scroll_source_device_ = bubbling_gesture_scroll_source_device_ =
blink::kWebGestureDeviceUninitialized; blink::kWebGestureDeviceUninitialized;
} }
}
} }
void RenderWidgetHostInputEventRouter::StopFling() { void RenderWidgetHostInputEventRouter::StopFling() {
if (!bubbling_gesture_scroll_target_.target) if (!bubbling_gesture_scroll_target_)
return; return;
if (!last_fling_start_target_ || !last_fling_start_target_->host()) if (!last_fling_start_target_ || !last_fling_start_target_->host())
...@@ -1390,15 +1435,7 @@ void RenderWidgetHostInputEventRouter::DispatchTouchscreenGestureEvent( ...@@ -1390,15 +1435,7 @@ void RenderWidgetHostInputEventRouter::DispatchTouchscreenGestureEvent(
IsViewInMap(touchscreen_gesture_target_.target); IsViewInMap(touchscreen_gesture_target_.target);
// Abort any scroll bubbling in progress to avoid double entry. // Abort any scroll bubbling in progress to avoid double entry.
if (touchscreen_gesture_target_.target && CancelScrollBubblingIfConflicting(touchscreen_gesture_target_.target);
touchscreen_gesture_target_.target ==
bubbling_gesture_scroll_target_.target) {
SendGestureScrollEnd(
bubbling_gesture_scroll_target_.target,
DummyGestureScrollUpdate(gesture_event.TimeStamp(),
bubbling_gesture_scroll_source_device_));
CancelScrollBubbling(bubbling_gesture_scroll_target_.target);
}
} }
// If we set a target and it's not in the map, we won't get notified if the // If we set a target and it's not in the map, we won't get notified if the
...@@ -1522,15 +1559,7 @@ void RenderWidgetHostInputEventRouter::DispatchTouchpadGestureEvent( ...@@ -1522,15 +1559,7 @@ void RenderWidgetHostInputEventRouter::DispatchTouchpadGestureEvent(
target_location.value() - touchpad_gesture_event.PositionInWidget(); target_location.value() - touchpad_gesture_event.PositionInWidget();
// Abort any scroll bubbling in progress to avoid double entry. // Abort any scroll bubbling in progress to avoid double entry.
if (touchpad_gesture_target_.target && CancelScrollBubblingIfConflicting(touchpad_gesture_target_.target);
touchpad_gesture_target_.target ==
bubbling_gesture_scroll_target_.target) {
SendGestureScrollEnd(
bubbling_gesture_scroll_target_.target,
DummyGestureScrollUpdate(touchpad_gesture_event.TimeStamp(),
bubbling_gesture_scroll_source_device_));
CancelScrollBubbling(bubbling_gesture_scroll_target_.target);
}
} }
if (!touchpad_gesture_target_.target) { if (!touchpad_gesture_target_.target) {
......
...@@ -55,6 +55,7 @@ namespace content { ...@@ -55,6 +55,7 @@ namespace content {
class RenderWidgetHostImpl; class RenderWidgetHostImpl;
class RenderWidgetHostView; class RenderWidgetHostView;
class RenderWidgetHostViewBase; class RenderWidgetHostViewBase;
class RenderWidgetHostViewChildFrame;
class RenderWidgetTargeter; class RenderWidgetTargeter;
class TouchEmulator; class TouchEmulator;
class TouchEventAckQueue; class TouchEventAckQueue;
...@@ -100,9 +101,10 @@ class CONTENT_EXPORT RenderWidgetHostInputEventRouter ...@@ -100,9 +101,10 @@ class CONTENT_EXPORT RenderWidgetHostInputEventRouter
// |event| is in root coordinates. // |event| is in root coordinates.
void BubbleScrollEvent(RenderWidgetHostViewBase* target_view, void BubbleScrollEvent(RenderWidgetHostViewBase* target_view,
const blink::WebGestureEvent& event, RenderWidgetHostViewChildFrame* resending_view,
const RenderWidgetHostViewBase* resending_view); const blink::WebGestureEvent& event);
void CancelScrollBubbling(RenderWidgetHostViewBase* target_view); void WillDetachChildView(
const RenderWidgetHostViewChildFrame* detaching_view);
void AddFrameSinkIdOwner(const viz::FrameSinkId& id, void AddFrameSinkIdOwner(const viz::FrameSinkId& id,
RenderWidgetHostViewBase* owner); RenderWidgetHostViewBase* owner);
...@@ -224,13 +226,24 @@ class CONTENT_EXPORT RenderWidgetHostInputEventRouter ...@@ -224,13 +226,24 @@ class CONTENT_EXPORT RenderWidgetHostInputEventRouter
RenderWidgetHostViewBase* target, RenderWidgetHostViewBase* target,
RenderWidgetHostViewBase* root_view); RenderWidgetHostViewBase* root_view);
// The following methods take a GestureScrollUpdate event and send a void CancelScrollBubbling();
// GestureScrollBegin or GestureScrollEnd for wrapping it. This is needed
// when GestureScrollUpdates are being forwarded for scroll bubbling. // Cancels scroll bubbling if it is unsafe to send a gesture event sequence
// to |target| considering the views involved in an ongoing scroll.
void CancelScrollBubblingIfConflicting(
const RenderWidgetHostViewBase* target);
// Wraps a touchscreen GesturePinchBegin in a GestureScrollBegin.
void SendGestureScrollBegin(RenderWidgetHostViewBase* view, void SendGestureScrollBegin(RenderWidgetHostViewBase* view,
const blink::WebGestureEvent& event); const blink::WebGestureEvent& event);
// Used to end a scroll sequence during scroll bubbling or as part of a
// wrapped pinch gesture.
void SendGestureScrollEnd(RenderWidgetHostViewBase* view, void SendGestureScrollEnd(RenderWidgetHostViewBase* view,
const blink::WebGestureEvent& event); const blink::WebGestureEvent& event);
// Used when scroll bubbling is canceled to indicate to |view| that it should
// consider the scroll sequence to have ended.
void SendGestureScrollEnd(RenderWidgetHostViewBase* view,
blink::WebGestureDevice source_device);
// Helper functions to implement RenderWidgetTargeter::Delegate functions. // Helper functions to implement RenderWidgetTargeter::Delegate functions.
RenderWidgetTargetResult FindMouseEventTarget( RenderWidgetTargetResult FindMouseEventTarget(
...@@ -315,8 +328,8 @@ class CONTENT_EXPORT RenderWidgetHostInputEventRouter ...@@ -315,8 +328,8 @@ class CONTENT_EXPORT RenderWidgetHostInputEventRouter
// https://crbug.com/824774. // https://crbug.com/824774.
bool touchscreen_gesture_target_in_map_; bool touchscreen_gesture_target_in_map_;
TargetData touchpad_gesture_target_; TargetData touchpad_gesture_target_;
TargetData bubbling_gesture_scroll_target_; RenderWidgetHostViewBase* bubbling_gesture_scroll_target_ = nullptr;
TargetData first_bubbling_scroll_target_; RenderWidgetHostViewChildFrame* bubbling_gesture_scroll_origin_ = nullptr;
// Used to target wheel events for the duration of a scroll. // Used to target wheel events for the duration of a scroll.
TargetData wheel_target_; TargetData wheel_target_;
// Maintains the same target between mouse down and mouse up. // Maintains the same target between mouse down and mouse up.
......
...@@ -539,28 +539,25 @@ void RenderWidgetHostViewChildFrame::GestureEventAck( ...@@ -539,28 +539,25 @@ void RenderWidgetHostViewChildFrame::GestureEventAck(
if (event.IsTouchpadZoomEvent()) if (event.IsTouchpadZoomEvent())
ProcessTouchpadZoomEventAckInRoot(event, ack_result); ProcessTouchpadZoomEventAckInRoot(event, ack_result);
const bool should_bubble = // GestureScrollBegin is a blocking event; It is forwarded for bubbling if
// its ack is not consumed. For the rest of the scroll events
// (GestureScrollUpdate, GestureScrollEnd) are bubbled if the
// GestureScrollBegin was bubbled.
if (event.GetType() == blink::WebInputEvent::kGestureScrollBegin) {
DCHECK(!is_scroll_sequence_bubbling_);
is_scroll_sequence_bubbling_ =
ack_result == INPUT_EVENT_ACK_STATE_NOT_CONSUMED || ack_result == INPUT_EVENT_ACK_STATE_NOT_CONSUMED ||
ack_result == INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS || ack_result == INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS ||
ack_result == INPUT_EVENT_ACK_STATE_CONSUMED_SHOULD_BUBBLE; ack_result == INPUT_EVENT_ACK_STATE_CONSUMED_SHOULD_BUBBLE;
if ((event.GetType() == blink::WebInputEvent::kGestureScrollBegin) &&
should_bubble) {
DCHECK(!is_scroll_sequence_bubbling_);
is_scroll_sequence_bubbling_ = true;
} else if (event.GetType() == blink::WebInputEvent::kGestureScrollEnd) {
is_scroll_sequence_bubbling_ = false;
} }
// GestureScrollBegin is a blocking event; It is forwarded for bubbling if if (is_scroll_sequence_bubbling_ &&
// its ack is not consumed. For the rest of the scroll events (event.GetType() == blink::WebInputEvent::kGestureScrollBegin ||
// (GestureScrollUpdate, GestureScrollEnd) the frame_connector_ decides to
// forward them for bubbling if the GestureScrollBegin event is forwarded.
if ((event.GetType() == blink::WebInputEvent::kGestureScrollBegin &&
should_bubble) ||
event.GetType() == blink::WebInputEvent::kGestureScrollUpdate || event.GetType() == blink::WebInputEvent::kGestureScrollUpdate ||
event.GetType() == blink::WebInputEvent::kGestureScrollEnd) { event.GetType() == blink::WebInputEvent::kGestureScrollEnd)) {
frame_connector_->BubbleScrollEvent(event); frame_connector_->BubbleScrollEvent(event);
if (event.GetType() == blink::WebInputEvent::kGestureScrollEnd)
is_scroll_sequence_bubbling_ = false;
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment