Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(101)

Unified Diff: third_party/WebKit/Source/core/input/TouchEventManager.cpp

Issue 2914673002: Refactor TouchEventManager::TouchInfo class (Closed)
Patch Set: Rebase Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « third_party/WebKit/Source/core/input/TouchEventManager.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/WebKit/Source/core/input/TouchEventManager.cpp
diff --git a/third_party/WebKit/Source/core/input/TouchEventManager.cpp b/third_party/WebKit/Source/core/input/TouchEventManager.cpp
index 86c234e9b4c17a3bcbcdeda4a82bbce12b8bbb8b..6f6476f60c4d100c5cb68e7b6be1f0963f8a3882 100644
--- a/third_party/WebKit/Source/core/input/TouchEventManager.cpp
+++ b/third_party/WebKit/Source/core/input/TouchEventManager.cpp
@@ -117,10 +117,75 @@ DEFINE_TRACE(TouchEventManager) {
visitor->Trace(target_for_touch_id_);
}
+Touch* TouchEventManager::CreateDomTouch(const WebTouchPoint& point,
+ bool* known_target) {
+ Node* touch_node = nullptr;
+ String region_id;
+ *known_target = false;
+ FloatPoint content_point;
+ FloatSize adjusted_radius;
+
+ if (point.state == WebTouchPoint::kStateReleased ||
+ point.state == WebTouchPoint::kStateCancelled) {
+ // The target should be the original target for this touch, so get
+ // it from the hashmap. As it's a release or cancel we also remove
+ // it from the map.
+ touch_node = target_for_touch_id_.Take(point.id);
+ region_id = region_for_touch_id_.Take(point.id);
+ } else {
+ // No hittest is performed on move or stationary, since the target
+ // is not allowed to change anyway.
+ touch_node = target_for_touch_id_.at(point.id);
+ region_id = region_for_touch_id_.at(point.id);
+ }
+
+ LocalFrame* target_frame = nullptr;
+ if (touch_node) {
+ Document& doc = touch_node->GetDocument();
+ // If the target node has moved to a new document while it was being
+ // touched, we can't send events to the new document because that could
+ // leak nodes from one document to another. See http://crbug.com/394339.
+ if (&doc == touch_sequence_document_.Get()) {
+ target_frame = doc.GetFrame();
+ *known_target = true;
+ }
+ }
+ if (!(*known_target)) {
+ // If we don't have a target registered for the point it means we've
+ // missed our opportunity to do a hit test for it (due to some
+ // optimization that prevented blink from ever seeing the
+ // touchstart), or that the touch started outside the active touch
+ // sequence document. We should still include the touch in the
+ // Touches list reported to the application (eg. so it can
+ // differentiate between a one and two finger gesture), but we won't
+ // actually dispatch any events for it. Set the target to the
+ // Document so that there's some valid node here. Perhaps this
+ // should really be LocalDOMWindow, but in all other cases the target of
+ // a Touch is a Node so using the window could be a breaking change.
+ // Since we know there was no handler invoked, the specific target
+ // should be completely irrelevant to the application.
+ touch_node = touch_sequence_document_;
+ target_frame = touch_sequence_document_->GetFrame();
+ }
+ DCHECK(target_frame);
+
+ // pagePoint should always be in the target element's document coordinates.
+ FloatPoint page_point =
+ target_frame->View()->RootFrameToContents(point.PositionInWidget());
+ float scale_factor = 1.0f / target_frame->PageZoomFactor();
+
+ content_point = page_point.ScaledBy(scale_factor);
+ adjusted_radius =
+ FloatSize(point.radius_x, point.radius_y).ScaledBy(scale_factor);
+
+ return Touch::Create(target_frame, touch_node, point.id,
+ point.PositionInScreen(), content_point, adjusted_radius,
+ point.rotation_angle, point.force, region_id);
+}
+
WebInputEventResult TouchEventManager::DispatchTouchEvents(
const WebTouchEvent& event,
const Vector<WebTouchEvent>& coalesced_events,
- const HeapVector<TouchInfo>& touch_infos,
bool all_touches_released) {
// Build up the lists to use for the |touches|, |targetTouches| and
// |changedTouches| attributes in the JS event. See
@@ -151,24 +216,22 @@ WebInputEventResult TouchEventManager::DispatchTouchEvents(
// Array of touches per state, used to assemble the |changedTouches| list.
ChangedTouches changed_touches[WebTouchPoint::kStateMax + 1];
- for (auto touch_info : touch_infos) {
- const WebTouchPoint& point = touch_info.point;
+ for (unsigned touch_point_idx = 0; touch_point_idx < event.touches_length;
+ touch_point_idx++) {
+ const WebTouchPoint& point = event.TouchPointInRootFrame(touch_point_idx);
WebTouchPoint::State point_state = point.state;
+ bool known_target;
- Touch* touch = Touch::Create(
- touch_info.target_frame.Get(), touch_info.touch_node.Get(), point.id,
- point.PositionInScreen(), touch_info.content_point,
- touch_info.adjusted_radius, point.rotation_angle, point.force,
- touch_info.region);
+ Touch* touch = CreateDomTouch(point, &known_target);
+ EventTarget* touch_target = touch->target();
// Ensure this target's touch list exists, even if it ends up empty, so
// it can always be passed to TouchEvent::Create below.
TargetTouchesHeapMap::iterator target_touches_iterator =
- touches_by_target.find(touch_info.touch_node.Get());
+ touches_by_target.find(touch_target);
if (target_touches_iterator == touches_by_target.end()) {
- touches_by_target.Set(touch_info.touch_node.Get(), TouchList::Create());
- target_touches_iterator =
- touches_by_target.find(touch_info.touch_node.Get());
+ touches_by_target.Set(touch_target, TouchList::Create());
+ target_touches_iterator = touches_by_target.find(touch_target);
}
// |touches| and |targetTouches| should only contain information about
@@ -186,13 +249,12 @@ WebInputEventResult TouchEventManager::DispatchTouchEvents(
// never be in the |changedTouches| list so we do not handle them
// explicitly here. See https://bugs.webkit.org/show_bug.cgi?id=37609
// for further discussion about the TouchStationary state.
- if (point_state != WebTouchPoint::kStateStationary &&
- touch_info.known_target) {
+ if (point_state != WebTouchPoint::kStateStationary && known_target) {
DCHECK_LE(point_state, WebTouchPoint::kStateMax);
if (!changed_touches[point_state].touches_)
changed_touches[point_state].touches_ = TouchList::Create();
changed_touches[point_state].touches_->Append(touch);
- changed_touches[point_state].targets_.insert(touch_info.touch_node);
+ changed_touches[point_state].targets_.insert(touch_target);
changed_touches[point_state].pointer_type_ = point.pointer_type;
}
}
@@ -232,7 +294,7 @@ WebInputEventResult TouchEventManager::DispatchTouchEvents(
// Only report for top level documents with a single touch on
// touch-start or the first touch-move.
- if (event.touch_start_or_first_touch_move && touch_infos.size() == 1 &&
+ if (event.touch_start_or_first_touch_move && event.touches_length == 1 &&
frame_->IsMainFrame()) {
// Record the disposition and latency of touch starts and first touch
// moves before and after the page is fully loaded respectively.
@@ -309,158 +371,91 @@ WebInputEventResult TouchEventManager::DispatchTouchEvents(
return event_result;
}
-void TouchEventManager::UpdateTargetAndRegionMapsForTouchStarts(
- HeapVector<TouchInfo>& touch_infos) {
- for (auto& touch_info : touch_infos) {
- // Touch events implicitly capture to the touched node, and don't change
- // active/hover states themselves (Gesture events do). So we only need
- // to hit-test on touchstart and when the target could be different than
- // the corresponding pointer event target.
- if (touch_info.point.state == WebTouchPoint::kStatePressed) {
- HitTestRequest::HitTestRequestType hit_type =
- HitTestRequest::kTouchEvent | HitTestRequest::kReadOnly |
- HitTestRequest::kActive;
- HitTestResult result;
- // For the touchPressed points hit-testing is done in
- // PointerEventManager. If it was the second touch there is a
- // capturing documents for the touch and |m_touchSequenceDocument|
- // is not null. So if PointerEventManager should hit-test again
- // against |m_touchSequenceDocument| if the target set by
- // PointerEventManager was either null or not in
- // |m_touchSequenceDocument|.
- if (touch_sequence_document_ &&
- (!touch_info.touch_node ||
- &touch_info.touch_node->GetDocument() != touch_sequence_document_)) {
- if (touch_sequence_document_->GetFrame()) {
- LayoutPoint frame_point = LayoutPoint(
- touch_sequence_document_->GetFrame()->View()->RootFrameToContents(
- touch_info.point.PositionInWidget()));
- result = EventHandlingUtil::HitTestResultInFrame(
- touch_sequence_document_->GetFrame(), frame_point, hit_type);
- Node* node = result.InnerNode();
- if (!node)
- continue;
- if (isHTMLCanvasElement(node)) {
- HitTestCanvasResult* hit_test_canvas_result =
- toHTMLCanvasElement(node)->GetControlAndIdIfHitRegionExists(
- result.PointInInnerNodeFrame());
- if (hit_test_canvas_result->GetControl())
- node = hit_test_canvas_result->GetControl();
- touch_info.region = hit_test_canvas_result->GetId();
- }
- // Touch events should not go to text nodes.
- if (node->IsTextNode())
- node = FlatTreeTraversal::Parent(*node);
- touch_info.touch_node = node;
- } else {
- continue;
- }
- }
- if (!touch_info.touch_node)
- continue;
- if (!touch_sequence_document_) {
- // Keep track of which document should receive all touch events
- // in the active sequence. This must be a single document to
- // ensure we don't leak Nodes between documents.
- touch_sequence_document_ = &(touch_info.touch_node->GetDocument());
- DCHECK(touch_sequence_document_->GetFrame()->View());
- }
-
- // Ideally we'd DCHECK(!m_targetForTouchID.contains(point.id())
- // since we shouldn't get a touchstart for a touch that's already
- // down. However EventSender allows this to be violated and there's
- // some tests that take advantage of it. There may also be edge
- // cases in the browser where this happens.
- // See http://crbug.com/345372.
- target_for_touch_id_.Set(touch_info.point.id, touch_info.touch_node);
-
- region_for_touch_id_.Set(touch_info.point.id, touch_info.region);
-
- TouchAction effective_touch_action =
- TouchActionUtil::ComputeEffectiveTouchAction(*touch_info.touch_node);
- if (effective_touch_action != TouchAction::kTouchActionAuto) {
- frame_->GetPage()->GetChromeClient().SetTouchAction(
- frame_, effective_touch_action);
-
- // Combine the current touch action sequence with the touch action
- // for the current finger press.
- current_touch_action_ &= effective_touch_action;
+void TouchEventManager::UpdateTargetAndRegionMapsForTouchStart(
+ const WebTouchPoint& touch_point,
+ const EventHandlingUtil::PointerEventTarget& pointer_event_target) {
+ // Touch events implicitly capture to the touched node, and don't change
+ // active/hover states themselves (Gesture events do). So we only need
+ // to hit-test on touchstart and when the target could be different than
+ // the corresponding pointer event target.
+ DCHECK(touch_point.state == WebTouchPoint::kStatePressed);
+ Node* touch_node = pointer_event_target.target_node;
+ String region = pointer_event_target.region;
+
+ HitTestRequest::HitTestRequestType hit_type = HitTestRequest::kTouchEvent |
+ HitTestRequest::kReadOnly |
+ HitTestRequest::kActive;
+ HitTestResult result;
+ // For the touchPressed points hit-testing is done in
+ // PointerEventManager. If it was the second touch there is a
+ // capturing documents for the touch and |m_touchSequenceDocument|
+ // is not null. So if PointerEventManager should hit-test again
+ // against |m_touchSequenceDocument| if the target set by
+ // PointerEventManager was either null or not in
+ // |m_touchSequenceDocument|.
+ if (touch_sequence_document_ &&
+ (!touch_node || &touch_node->GetDocument() != touch_sequence_document_)) {
+ if (touch_sequence_document_->GetFrame()) {
+ LayoutPoint frame_point = LayoutPoint(
+ touch_sequence_document_->GetFrame()->View()->RootFrameToContents(
+ touch_point.PositionInWidget()));
+ result = EventHandlingUtil::HitTestResultInFrame(
+ touch_sequence_document_->GetFrame(), frame_point, hit_type);
+ Node* node = result.InnerNode();
+ if (!node)
+ return;
+ if (isHTMLCanvasElement(node)) {
+ HitTestCanvasResult* hit_test_canvas_result =
+ toHTMLCanvasElement(node)->GetControlAndIdIfHitRegionExists(
+ result.PointInInnerNodeFrame());
+ if (hit_test_canvas_result->GetControl())
+ node = hit_test_canvas_result->GetControl();
+ region = hit_test_canvas_result->GetId();
}
- }
- }
-}
-
-void TouchEventManager::SetAllPropertiesOfTouchInfos(
- HeapVector<TouchInfo>& touch_infos) {
- for (auto& touch_info : touch_infos) {
- WebTouchPoint::State point_state = touch_info.point.state;
- Node* touch_node = nullptr;
- String region_id;
-
- if (point_state == WebTouchPoint::kStateReleased ||
- point_state == WebTouchPoint::kStateCancelled) {
- // The target should be the original target for this touch, so get
- // it from the hashmap. As it's a release or cancel we also remove
- // it from the map.
- touch_node = target_for_touch_id_.Take(touch_info.point.id);
- region_id = region_for_touch_id_.Take(touch_info.point.id);
+ // Touch events should not go to text nodes.
+ if (node->IsTextNode())
+ node = FlatTreeTraversal::Parent(*node);
+ touch_node = node;
} else {
- // No hittest is performed on move or stationary, since the target
- // is not allowed to change anyway.
- touch_node = target_for_touch_id_.at(touch_info.point.id);
- region_id = region_for_touch_id_.at(touch_info.point.id);
+ return;
}
+ }
+ if (!touch_node)
+ return;
+ if (!touch_sequence_document_) {
+ // Keep track of which document should receive all touch events
+ // in the active sequence. This must be a single document to
+ // ensure we don't leak Nodes between documents.
+ touch_sequence_document_ = &(touch_node->GetDocument());
+ DCHECK(touch_sequence_document_->GetFrame()->View());
+ }
- LocalFrame* target_frame = nullptr;
- bool known_target = false;
- if (touch_node) {
- Document& doc = touch_node->GetDocument();
- // If the target node has moved to a new document while it was being
- // touched, we can't send events to the new document because that could
- // leak nodes from one document to another. See http://crbug.com/394339.
- if (&doc == touch_sequence_document_.Get()) {
- target_frame = doc.GetFrame();
- known_target = true;
- }
- }
- if (!known_target) {
- // If we don't have a target registered for the point it means we've
- // missed our opportunity to do a hit test for it (due to some
- // optimization that prevented blink from ever seeing the
- // touchstart), or that the touch started outside the active touch
- // sequence document. We should still include the touch in the
- // Touches list reported to the application (eg. so it can
- // differentiate between a one and two finger gesture), but we won't
- // actually dispatch any events for it. Set the target to the
- // Document so that there's some valid node here. Perhaps this
- // should really be LocalDOMWindow, but in all other cases the target of
- // a Touch is a Node so using the window could be a breaking change.
- // Since we know there was no handler invoked, the specific target
- // should be completely irrelevant to the application.
- touch_node = touch_sequence_document_;
- target_frame = touch_sequence_document_->GetFrame();
- }
- DCHECK(target_frame);
-
- // pagePoint should always be in the target element's document coordinates.
- FloatPoint page_point = target_frame->View()->RootFrameToContents(
- touch_info.point.PositionInWidget());
- float scale_factor = 1.0f / target_frame->PageZoomFactor();
-
- touch_info.touch_node = touch_node;
- touch_info.target_frame = target_frame;
- touch_info.content_point = page_point.ScaledBy(scale_factor);
- touch_info.adjusted_radius =
- FloatSize(touch_info.point.radius_x, touch_info.point.radius_y)
- .ScaledBy(scale_factor);
- touch_info.known_target = known_target;
- touch_info.region = region_id;
+ // Ideally we'd DCHECK(!m_targetForTouchID.contains(point.id())
+ // since we shouldn't get a touchstart for a touch that's already
+ // down. However EventSender allows this to be violated and there's
+ // some tests that take advantage of it. There may also be edge
+ // cases in the browser where this happens.
+ // See http://crbug.com/345372.
+ target_for_touch_id_.Set(touch_point.id, touch_node);
+
+ region_for_touch_id_.Set(touch_point.id, region);
+
+ TouchAction effective_touch_action =
+ TouchActionUtil::ComputeEffectiveTouchAction(*touch_node);
+ if (effective_touch_action != TouchAction::kTouchActionAuto) {
+ frame_->GetPage()->GetChromeClient().SetTouchAction(frame_,
+ effective_touch_action);
+
+ // Combine the current touch action sequence with the touch action
+ // for the current finger press.
+ current_touch_action_ &= effective_touch_action;
}
}
-bool TouchEventManager::ReHitTestTouchPointsIfNeeded(
+bool TouchEventManager::HitTestTouchPointsIfNeeded(
const WebTouchEvent& event,
- HeapVector<TouchInfo>& touch_infos) {
+ const HeapVector<EventHandlingUtil::PointerEventTarget>&
+ pointer_event_targets) {
bool new_touch_sequence = true;
bool all_touches_released = true;
@@ -490,7 +485,14 @@ bool TouchEventManager::ReHitTestTouchPointsIfNeeded(
return false;
}
- UpdateTargetAndRegionMapsForTouchStarts(touch_infos);
+ for (unsigned i = 0; i < event.touches_length; ++i) {
+ // In touch event model only touch starts can set the target and after that
+ // the touch event always goes to that target.
+ if (event.touches[i].state == WebTouchPoint::kStatePressed) {
+ UpdateTargetAndRegionMapsForTouchStart(event.TouchPointInRootFrame(i),
+ pointer_event_targets[i]);
+ }
+ }
touch_pressed_ = !all_touches_released;
@@ -507,16 +509,17 @@ bool TouchEventManager::ReHitTestTouchPointsIfNeeded(
return false;
}
- SetAllPropertiesOfTouchInfos(touch_infos);
-
return true;
}
WebInputEventResult TouchEventManager::HandleTouchEvent(
const WebTouchEvent& event,
const Vector<WebTouchEvent>& coalesced_events,
- HeapVector<TouchInfo>& touch_infos) {
- if (!ReHitTestTouchPointsIfNeeded(event, touch_infos))
+ const HeapVector<EventHandlingUtil::PointerEventTarget>&
+ pointer_event_targets) {
+ DCHECK(event.touches_length == pointer_event_targets.size());
+
+ if (!HitTestTouchPointsIfNeeded(event, pointer_event_targets))
return WebInputEventResult::kNotHandled;
bool all_touches_released = true;
@@ -527,8 +530,7 @@ WebInputEventResult TouchEventManager::HandleTouchEvent(
all_touches_released = false;
}
- return DispatchTouchEvents(event, coalesced_events, touch_infos,
- all_touches_released);
+ return DispatchTouchEvents(event, coalesced_events, all_touches_released);
}
bool TouchEventManager::IsAnyTouchActive() const {
« no previous file with comments | « third_party/WebKit/Source/core/input/TouchEventManager.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698