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

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

Issue 2860663006: Remove WebTouchEvent from TouchEventManager APIs (Closed)
Patch Set: Add TODO for clarification of the fields Created 3 years, 6 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
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 6f6476f60c4d100c5cb68e7b6be1f0963f8a3882..b46e3cfd5e340b4e1063f69e9641978d37e19dd3 100644
--- a/third_party/WebKit/Source/core/input/TouchEventManager.cpp
+++ b/third_party/WebKit/Source/core/input/TouchEventManager.cpp
@@ -37,19 +37,17 @@ bool HasTouchHandlers(const EventHandlerRegistry& registry) {
EventHandlerRegistry::kTouchEndOrCancelEventPassive);
}
-const AtomicString& TouchEventNameForTouchPointState(
- WebTouchPoint::State state) {
- switch (state) {
- case WebTouchPoint::kStateReleased:
+const AtomicString& TouchEventNameForPointerEventType(
+ WebInputEvent::Type type) {
+ switch (type) {
+ case WebInputEvent::kPointerUp:
return EventTypeNames::touchend;
- case WebTouchPoint::kStateCancelled:
+ case WebInputEvent::kPointerCancel:
return EventTypeNames::touchcancel;
- case WebTouchPoint::kStatePressed:
+ case WebInputEvent::kPointerDown:
return EventTypeNames::touchstart;
- case WebTouchPoint::kStateMoved:
+ case WebInputEvent::kPointerMove:
return EventTypeNames::touchmove;
- case WebTouchPoint::kStateStationary:
- // Fall through to default
default:
NOTREACHED();
return g_empty_atom;
@@ -62,19 +60,55 @@ enum TouchEventDispatchResultType {
kTouchEventDispatchResultTypeMax,
};
-bool IsTouchSequenceStart(const WebTouchEvent& event) {
- if (!event.touches_length)
- return false;
- if (event.GetType() != WebInputEvent::kTouchStart)
- return false;
- for (size_t i = 0; i < event.touches_length; ++i) {
- if (event.touches[i].state != blink::WebTouchPoint::kStatePressed)
- return false;
+WebTouchPoint::State TouchPointStateFromPointerEventType(
+ WebInputEvent::Type type,
+ bool stale) {
+ if (stale)
+ return WebTouchPoint::kStateStationary;
+ switch (type) {
+ case WebInputEvent::Type::kPointerUp:
+ return WebTouchPoint::kStateReleased;
+ case WebInputEvent::Type::kPointerCancel:
+ return WebTouchPoint::kStateCancelled;
+ case WebInputEvent::Type::kPointerDown:
+ return WebTouchPoint::kStatePressed;
+ case WebInputEvent::Type::kPointerMove:
+ return WebTouchPoint::kStateMoved;
+ default:
+ NOTREACHED();
+ return WebTouchPoint::kStateUndefined;
}
- return true;
}
-// Defining this class type local to dispatchTouchEvents() and annotating
+WebTouchPoint CreateWebTouchPointFromWebPointerEvent(
+ const WebPointerEvent& web_pointer_event,
+ bool stale) {
+ WebTouchPoint web_touch_point(web_pointer_event);
+ web_touch_point.state =
+ TouchPointStateFromPointerEventType(web_pointer_event.GetType(), stale);
+ // TODO(crbug.com/731725): This mapping needs a division by 2.
+ web_touch_point.radius_x = web_pointer_event.width;
+ web_touch_point.radius_y = web_pointer_event.height;
+ web_touch_point.rotation_angle = web_pointer_event.rotation_angle;
+ return web_touch_point;
+}
+
+void SetWebTouchEventAttributesFromWebPointerEvent(
+ WebTouchEvent* web_touch_event,
+ const WebPointerEvent& web_pointer_event) {
+ web_touch_event->dispatch_type = web_pointer_event.dispatch_type;
+ web_touch_event->touch_start_or_first_touch_move =
+ web_pointer_event.touch_start_or_first_touch_move;
+ web_touch_event->moved_beyond_slop_region =
+ web_pointer_event.moved_beyond_slop_region;
+ web_touch_event->SetFrameScale(web_pointer_event.FrameScale());
+ web_touch_event->SetFrameTranslate(web_pointer_event.FrameTranslate());
+ web_touch_event->SetTimeStampSeconds(web_pointer_event.TimeStampSeconds());
+ web_touch_event->SetModifiers(web_pointer_event.GetModifiers());
+}
+
+// Defining this class type local to
+// DispatchTouchEventFromAccumulatdTouchPoints() and annotating
// it with STACK_ALLOCATED(), runs into MSVC(VS 2013)'s C4822 warning
// that the local class doesn't provide a local definition for 'operator new'.
// Which it intentionally doesn't and shouldn't.
@@ -92,10 +126,70 @@ class ChangedTouches final {
using EventTargetSet = HeapHashSet<Member<EventTarget>>;
// Set of targets involved in m_touches.
EventTargetSet targets_;
-
- WebPointerProperties::PointerType pointer_type_;
};
+void ReportMetricsForTouch(const WebPointerEvent& event,
+ DispatchEventResult dom_dispatch_result,
+ bool prevent_default_called_on_uncancelable_event,
+ bool is_frame_loaded) {
+ int64_t latency_in_micros =
+ (TimeTicks::Now() - TimeTicks::FromSeconds(event.TimeStampSeconds()))
+ .InMicroseconds();
+ if (event.IsCancelable()) {
+ if (is_frame_loaded) {
+ DEFINE_STATIC_LOCAL(EnumerationHistogram,
+ touch_dispositions_after_page_load_histogram,
+ ("Event.Touch.TouchDispositionsAfterPageLoad",
+ kTouchEventDispatchResultTypeMax));
+ touch_dispositions_after_page_load_histogram.Count(
+ (dom_dispatch_result != DispatchEventResult::kNotCanceled)
+ ? kHandledTouches
+ : kUnhandledTouches);
+
+ DEFINE_STATIC_LOCAL(
+ CustomCountHistogram, event_latency_after_page_load_histogram,
+ ("Event.Touch.TouchLatencyAfterPageLoad", 1, 100000000, 50));
+ event_latency_after_page_load_histogram.Count(latency_in_micros);
+ } else {
+ DEFINE_STATIC_LOCAL(EnumerationHistogram,
+ touch_dispositions_before_page_load_histogram,
+ ("Event.Touch.TouchDispositionsBeforePageLoad",
+ kTouchEventDispatchResultTypeMax));
+ touch_dispositions_before_page_load_histogram.Count(
+ (dom_dispatch_result != DispatchEventResult::kNotCanceled)
+ ? kHandledTouches
+ : kUnhandledTouches);
+
+ DEFINE_STATIC_LOCAL(
+ CustomCountHistogram, event_latency_before_page_load_histogram,
+ ("Event.Touch.TouchLatencyBeforePageLoad", 1, 100000000, 50));
+ event_latency_before_page_load_histogram.Count(latency_in_micros);
+ }
+ // Report the touch disposition there is no active fling animation.
+ DEFINE_STATIC_LOCAL(EnumerationHistogram,
+ touch_dispositions_outside_fling_histogram,
+ ("Event.Touch.TouchDispositionsOutsideFling2",
+ kTouchEventDispatchResultTypeMax));
+ touch_dispositions_outside_fling_histogram.Count(
+ (dom_dispatch_result != DispatchEventResult::kNotCanceled)
+ ? kHandledTouches
+ : kUnhandledTouches);
+ }
+
+ // Report the touch disposition when there is an active fling
+ // animation.
+ if (event.dispatch_type ==
+ WebInputEvent::kListenersForcedNonBlockingDueToFling) {
+ DEFINE_STATIC_LOCAL(EnumerationHistogram,
+ touch_dispositions_during_fling_histogram,
+ ("Event.Touch.TouchDispositionsDuringFling2",
+ kTouchEventDispatchResultTypeMax));
+ touch_dispositions_during_fling_histogram.Count(
+ prevent_default_called_on_uncancelable_event ? kHandledTouches
+ : kUnhandledTouches);
+ }
+}
+
} // namespace
TouchEventManager::TouchEventManager(LocalFrame& frame) : frame_(frame) {
@@ -104,9 +198,8 @@ TouchEventManager::TouchEventManager(LocalFrame& frame) : frame_(frame) {
void TouchEventManager::Clear() {
touch_sequence_document_.Clear();
- target_for_touch_id_.clear();
- region_for_touch_id_.clear();
- touch_pressed_ = false;
+ touch_attribute_map_.clear();
+ last_coalesced_touch_event_ = WebTouchEvent();
suppressing_touchmoves_within_slop_ = false;
current_touch_action_ = TouchAction::kTouchActionAuto;
}
@@ -114,31 +207,18 @@ void TouchEventManager::Clear() {
DEFINE_TRACE(TouchEventManager) {
visitor->Trace(frame_);
visitor->Trace(touch_sequence_document_);
- visitor->Trace(target_for_touch_id_);
+ visitor->Trace(touch_attribute_map_);
}
-Touch* TouchEventManager::CreateDomTouch(const WebTouchPoint& point,
- bool* known_target) {
- Node* touch_node = nullptr;
- String region_id;
+Touch* TouchEventManager::CreateDomTouch(
+ const TouchEventManager::TouchPointAttributes* point_attr,
+ bool* known_target) {
+ Node* touch_node = point_attr->target_;
+ String region_id = point_attr->region_;
*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();
@@ -169,40 +249,193 @@ Touch* TouchEventManager::CreateDomTouch(const WebTouchPoint& point,
}
DCHECK(target_frame);
+ WebPointerEvent transformed_event =
+ point_attr->event_.WebPointerEventInRootFrame();
// pagePoint should always be in the target element's document coordinates.
- FloatPoint page_point =
- target_frame->View()->RootFrameToContents(point.PositionInWidget());
+ FloatPoint page_point = target_frame->View()->RootFrameToContents(
+ transformed_event.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);
+ adjusted_radius = FloatSize(transformed_event.width, transformed_event.height)
+ .ScaledBy(scale_factor);
+
+ return Touch::Create(target_frame, touch_node, point_attr->event_.id,
+ transformed_event.PositionInScreen(), content_point,
+ adjusted_radius, transformed_event.rotation_angle,
+ transformed_event.force, region_id);
+}
+
+WebCoalescedInputEvent TouchEventManager::GenerateWebCoalescedInputEvent() {
+ DCHECK(!touch_attribute_map_.IsEmpty());
+
+ WebTouchEvent event;
+
+ const auto& first_touch_pointer_event =
+ touch_attribute_map_.begin()->value->event_;
+
+ SetWebTouchEventAttributesFromWebPointerEvent(&event,
+ first_touch_pointer_event);
+ SetWebTouchEventAttributesFromWebPointerEvent(&last_coalesced_touch_event_,
+ first_touch_pointer_event);
+ WebInputEvent::Type touch_event_type = WebInputEvent::kTouchMove;
+ Vector<WebPointerEvent> all_coalesced_events;
+ Vector<int> available_ids;
+ for (const auto& id : touch_attribute_map_.Keys())
+ available_ids.push_back(id);
+ std::sort(available_ids.begin(), available_ids.end());
+ for (const int& touch_point_id : available_ids) {
+ const auto& touch_point_attribute = touch_attribute_map_.at(touch_point_id);
+ const WebPointerEvent& touch_pointer_event = touch_point_attribute->event_;
+ event.touches[event.touches_length++] =
+ CreateWebTouchPointFromWebPointerEvent(touch_pointer_event,
+ touch_point_attribute->stale_);
+
+ // Only change the touch event type from move. So if we have two pointers
+ // in up and down state we just set the touch event type to the first one
+ // we see.
+ // TODO(crbug.com/732842): Note that event sender API allows sending any
+ // mix of input and as long as we don't crash or anything we should be good
+ // for now.
+ if (touch_event_type == WebInputEvent::kTouchMove) {
+ if (touch_pointer_event.GetType() == WebInputEvent::kPointerDown)
+ touch_event_type = WebInputEvent::kTouchStart;
+ else if (touch_pointer_event.GetType() == WebInputEvent::kPointerCancel)
+ touch_event_type = WebInputEvent::kTouchCancel;
+ else if (touch_pointer_event.GetType() == WebInputEvent::kPointerUp)
+ touch_event_type = WebInputEvent::kTouchEnd;
+ }
+
+ for (const WebPointerEvent& coalesced_event :
+ touch_point_attribute->coalesced_events_) {
+ all_coalesced_events.push_back(coalesced_event);
+ }
+ }
+ event.SetType(touch_event_type);
+ last_coalesced_touch_event_.SetType(touch_event_type);
- return Touch::Create(target_frame, touch_node, point.id,
- point.PositionInScreen(), content_point, adjusted_radius,
- point.rotation_angle, point.force, region_id);
+ // Create all coalesced touch events based on pointerevents
+ struct {
+ bool operator()(const WebPointerEvent& a, const WebPointerEvent& b) {
+ return a.TimeStampSeconds() < b.TimeStampSeconds();
+ }
+ } timestamp_based_event_comparison;
+ std::sort(all_coalesced_events.begin(), all_coalesced_events.end(),
+ timestamp_based_event_comparison);
+ WebCoalescedInputEvent result(event, std::vector<const WebInputEvent*>());
+ for (const auto& web_pointer_event : all_coalesced_events) {
+ if (web_pointer_event.GetType() == WebInputEvent::kPointerDown) {
+ // TODO(crbug.com/732842): Technically we should never receive the
+ // pointerdown twice for the same touch point. But event sender API allows
+ // that. So we should handle it gracefully.
+ WebTouchPoint web_touch_point(web_pointer_event);
+ bool found_existing_id = false;
+ for (unsigned i = 0; i < last_coalesced_touch_event_.touches_length;
+ ++i) {
+ if (last_coalesced_touch_event_.touches[i].id == web_pointer_event.id) {
+ last_coalesced_touch_event_.touches[i] =
+ CreateWebTouchPointFromWebPointerEvent(web_pointer_event, false);
+ found_existing_id = true;
+ break;
+ }
+ }
+ // If the pointerdown point didn't exist add a new point to the array.
+ if (!found_existing_id) {
+ last_coalesced_touch_event_
+ .touches[last_coalesced_touch_event_.touches_length++] =
+ CreateWebTouchPointFromWebPointerEvent(web_pointer_event, false);
+ }
+ struct {
+ bool operator()(const WebTouchPoint& a, const WebTouchPoint& b) {
+ return a.id < b.id;
+ }
+ } id_based_event_comparison;
+ std::sort(last_coalesced_touch_event_.touches,
+ last_coalesced_touch_event_.touches +
+ last_coalesced_touch_event_.touches_length,
+ id_based_event_comparison);
+ result.AddCoalescedEvent(last_coalesced_touch_event_);
+ } else {
+ for (unsigned i = 0; i < last_coalesced_touch_event_.touches_length;
+ ++i) {
+ if (last_coalesced_touch_event_.touches[i].id == web_pointer_event.id) {
+ last_coalesced_touch_event_.touches[i].movement_x =
jkwang 2017/07/10 23:49:39 Why not call "CreateWebTouchPointFromWebPointerEve
Navid Zolghadr 2017/07/11 02:21:28 I cannot think of any reason not to. Calling "Crea
+ web_pointer_event.movement_x;
+ last_coalesced_touch_event_.touches[i].movement_y =
+ web_pointer_event.movement_y;
+ last_coalesced_touch_event_.SetTimeStampSeconds(
+ web_pointer_event.TimeStampSeconds());
+ last_coalesced_touch_event_.touches[i].state =
+ TouchPointStateFromPointerEventType(web_pointer_event.GetType(),
+ false);
+ result.AddCoalescedEvent(last_coalesced_touch_event_);
+
+ // Remove up and canceled points.
+ unsigned result_size = 0;
+ for (unsigned j = 0; j < last_coalesced_touch_event_.touches_length;
+ j++) {
+ if (last_coalesced_touch_event_.touches[j].state !=
+ WebTouchPoint::kStateCancelled &&
+ last_coalesced_touch_event_.touches[j].state !=
+ WebTouchPoint::kStateReleased) {
+ last_coalesced_touch_event_.touches[result_size++] =
+ last_coalesced_touch_event_.touches[j];
+ }
+ }
+ last_coalesced_touch_event_.touches_length = result_size;
+ break;
+ }
+ }
+ }
+
+ for (unsigned i = 0; i < event.touches_length; ++i) {
+ event.touches[i].state = blink::WebTouchPoint::kStateStationary;
+ event.touches[i].movement_x = 0;
+ event.touches[i].movement_y = 0;
+ }
+ }
+
+ return result;
}
-WebInputEventResult TouchEventManager::DispatchTouchEvents(
- const WebTouchEvent& event,
- const Vector<WebTouchEvent>& coalesced_events,
- bool all_touches_released) {
+WebInputEventResult
+TouchEventManager::DispatchTouchEventFromAccumulatdTouchPoints() {
// Build up the lists to use for the |touches|, |targetTouches| and
// |changedTouches| attributes in the JS event. See
// http://www.w3.org/TR/touch-events/#touchevent-interface for how these
// lists fit together.
- if (event.GetType() == WebInputEvent::kTouchEnd ||
- event.GetType() == WebInputEvent::kTouchCancel ||
- event.touches_length > 1) {
- suppressing_touchmoves_within_slop_ = false;
+ bool new_touch_point_since_last_dispatch = false;
+ bool any_touch_canceled_or_ended = false;
+ bool all_touch_points_pressed = true;
+
+ for (const auto& attr : touch_attribute_map_.Values()) {
+ if (!attr->stale_)
+ new_touch_point_since_last_dispatch = true;
+ if (attr->event_.GetType() == WebInputEvent::kPointerUp ||
+ attr->event_.GetType() == WebInputEvent::kPointerCancel)
+ any_touch_canceled_or_ended = true;
+ if (attr->event_.GetType() != WebInputEvent::kPointerDown)
+ all_touch_points_pressed = false;
}
- if (suppressing_touchmoves_within_slop_ &&
- event.GetType() == WebInputEvent::kTouchMove) {
- if (!event.moved_beyond_slop_region)
- return WebInputEventResult::kHandledSuppressed;
+ if (!new_touch_point_since_last_dispatch)
+ return WebInputEventResult::kNotHandled;
+
+ if (any_touch_canceled_or_ended || touch_attribute_map_.size() > 1)
suppressing_touchmoves_within_slop_ = false;
+
+ if (suppressing_touchmoves_within_slop_) {
+ // There is exactly one touch point here otherwise
+ // |suppressing_touchmoves_within_slop_| would have been false.
+ DCHECK_EQ(1U, touch_attribute_map_.size());
+ const auto& touch_point_attribute = touch_attribute_map_.begin()->value;
+ if (touch_point_attribute->event_.GetType() ==
+ WebInputEvent::kPointerMove) {
+ if (!touch_point_attribute->event_.moved_beyond_slop_region)
+ return WebInputEventResult::kHandledSuppressed;
+ suppressing_touchmoves_within_slop_ = false;
+ }
}
// Holds the complete set of touches on the screen.
@@ -214,15 +447,19 @@ WebInputEventResult TouchEventManager::DispatchTouchEvents(
TargetTouchesHeapMap touches_by_target;
// Array of touches per state, used to assemble the |changedTouches| list.
- ChangedTouches changed_touches[WebTouchPoint::kStateMax + 1];
-
- 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;
+ ChangedTouches changed_touches[WebInputEvent::kPointerTypeLast -
+ WebInputEvent::kPointerTypeFirst + 1];
+
+ Vector<int> available_ids;
+ for (const auto& id : touch_attribute_map_.Keys())
+ available_ids.push_back(id);
+ std::sort(available_ids.begin(), available_ids.end());
+ for (const int& touch_point_id : available_ids) {
+ const auto& touch_point_attribute = touch_attribute_map_.at(touch_point_id);
+ WebInputEvent::Type event_type = touch_point_attribute->event_.GetType();
bool known_target;
- Touch* touch = CreateDomTouch(point, &known_target);
+ Touch* touch = CreateDomTouch(touch_point_attribute, &known_target);
EventTarget* touch_target = touch->target();
// Ensure this target's touch list exists, even if it ends up empty, so
@@ -237,8 +474,8 @@ WebInputEventResult TouchEventManager::DispatchTouchEvents(
// |touches| and |targetTouches| should only contain information about
// touches still on the screen, so if this point is released or
// cancelled it will only appear in the |changedTouches| list.
- if (point_state != WebTouchPoint::kStateReleased &&
- point_state != WebTouchPoint::kStateCancelled) {
+ if (event_type != WebInputEvent::kPointerUp &&
+ event_type != WebInputEvent::kPointerCancel) {
touches->Append(touch);
target_touches_iterator->value->Append(touch);
}
@@ -249,43 +486,37 @@ 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 && 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_target);
- changed_touches[point_state].pointer_type_ = point.pointer_type;
+ if (!touch_point_attribute->stale_ && known_target) {
+ size_t event_type_idx = event_type - WebInputEvent::kPointerTypeFirst;
+ if (!changed_touches[event_type_idx].touches_)
+ changed_touches[event_type_idx].touches_ = TouchList::Create();
+ changed_touches[event_type_idx].touches_->Append(touch);
+ changed_touches[event_type_idx].targets_.insert(touch_target);
}
}
- if (all_touches_released) {
- touch_sequence_document_.Clear();
- current_touch_action_ = TouchAction::kTouchActionAuto;
- }
-
WebInputEventResult event_result = WebInputEventResult::kNotHandled;
- // First we construct the webcoalescedinputevent contains all the coalesced
+
+ // First we construct the webcoalescedinputevent containing all the coalesced
// touch event.
- std::vector<const WebInputEvent*> coalesced_touches;
- for (size_t i = 0; i < coalesced_events.size(); ++i) {
- coalesced_touches.push_back(&coalesced_events[i]);
- }
- WebCoalescedInputEvent coalesced_event(event, coalesced_touches);
+ WebCoalescedInputEvent coalesced_event = GenerateWebCoalescedInputEvent();
// Now iterate through the |changedTouches| list and |m_targets| within it,
// sending TouchEvents to the targets as required.
- for (unsigned state = 0; state <= WebTouchPoint::kStateMax; ++state) {
- if (!changed_touches[state].touches_)
+ for (unsigned action = WebInputEvent::kPointerTypeFirst;
+ action <= WebInputEvent::kPointerTypeLast; ++action) {
+ size_t action_idx = action - WebInputEvent::kPointerTypeFirst;
+ if (!changed_touches[action_idx].touches_)
continue;
- const AtomicString& event_name(TouchEventNameForTouchPointState(
- static_cast<WebTouchPoint::State>(state)));
- for (const auto& event_target : changed_touches[state].targets_) {
+ const AtomicString& event_name(TouchEventNameForPointerEventType(
+ static_cast<WebInputEvent::Type>(action)));
+
+ for (const auto& event_target : changed_touches[action_idx].targets_) {
EventTarget* touch_event_target = event_target;
TouchEvent* touch_event = TouchEvent::Create(
coalesced_event, touches, touches_by_target.at(touch_event_target),
- changed_touches[state].touches_.Get(), event_name,
+ changed_touches[action_idx].touches_.Get(), event_name,
touch_event_target->ToNode()->GetDocument().domWindow(),
current_touch_action_);
@@ -294,66 +525,15 @@ 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 && 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.
- int64_t latency_in_micros =
- (TimeTicks::Now() -
- TimeTicks::FromSeconds(event.TimeStampSeconds()))
- .InMicroseconds();
- if (event.IsCancelable()) {
- if (frame_->GetDocument()->IsLoadCompleted()) {
- DEFINE_STATIC_LOCAL(EnumerationHistogram,
- touch_dispositions_after_page_load_histogram,
- ("Event.Touch.TouchDispositionsAfterPageLoad",
- kTouchEventDispatchResultTypeMax));
- touch_dispositions_after_page_load_histogram.Count(
- (dom_dispatch_result != DispatchEventResult::kNotCanceled)
- ? kHandledTouches
- : kUnhandledTouches);
-
- DEFINE_STATIC_LOCAL(
- CustomCountHistogram, event_latency_after_page_load_histogram,
- ("Event.Touch.TouchLatencyAfterPageLoad", 1, 100000000, 50));
- event_latency_after_page_load_histogram.Count(latency_in_micros);
- } else {
- DEFINE_STATIC_LOCAL(EnumerationHistogram,
- touch_dispositions_before_page_load_histogram,
- ("Event.Touch.TouchDispositionsBeforePageLoad",
- kTouchEventDispatchResultTypeMax));
- touch_dispositions_before_page_load_histogram.Count(
- (dom_dispatch_result != DispatchEventResult::kNotCanceled)
- ? kHandledTouches
- : kUnhandledTouches);
-
- DEFINE_STATIC_LOCAL(
- CustomCountHistogram, event_latency_before_page_load_histogram,
- ("Event.Touch.TouchLatencyBeforePageLoad", 1, 100000000, 50));
- event_latency_before_page_load_histogram.Count(latency_in_micros);
- }
- // Report the touch disposition there is no active fling animation.
- DEFINE_STATIC_LOCAL(EnumerationHistogram,
- touch_dispositions_outside_fling_histogram,
- ("Event.Touch.TouchDispositionsOutsideFling2",
- kTouchEventDispatchResultTypeMax));
- touch_dispositions_outside_fling_histogram.Count(
- (dom_dispatch_result != DispatchEventResult::kNotCanceled)
- ? kHandledTouches
- : kUnhandledTouches);
- }
-
- // Report the touch disposition when there is an active fling animation.
- if (event.dispatch_type ==
- WebInputEvent::kListenersForcedNonBlockingDueToFling) {
- DEFINE_STATIC_LOCAL(EnumerationHistogram,
- touch_dispositions_during_fling_histogram,
- ("Event.Touch.TouchDispositionsDuringFling2",
- kTouchEventDispatchResultTypeMax));
- touch_dispositions_during_fling_histogram.Count(
- touch_event->PreventDefaultCalledOnUncancelableEvent()
- ? kHandledTouches
- : kUnhandledTouches);
+ if (touch_attribute_map_.size() == 1 && frame_->IsMainFrame()) {
+ const auto& event = touch_attribute_map_.begin()->value->event_;
+ if (event.touch_start_or_first_touch_move) {
+ // Record the disposition and latency of touch starts and first touch
+ // moves before and after the page is fully loaded respectively.
+ ReportMetricsForTouch(
+ event, dom_dispatch_result,
+ touch_event->PreventDefaultCalledOnUncancelableEvent(),
+ frame_->GetDocument()->IsLoadCompleted());
}
}
event_result = EventHandlingUtil::MergeEventResult(
@@ -362,8 +542,9 @@ WebInputEventResult TouchEventManager::DispatchTouchEvents(
}
}
- // Do not suppress any touchmoves if the touchstart is consumed.
- if (IsTouchSequenceStart(event) &&
+ // Suppress following touchmoves within the slop region if the touchstart is
+ // not consumed.
+ if (all_touch_points_pressed &&
event_result == WebInputEventResult::kNotHandled) {
suppressing_touchmoves_within_slop_ = true;
}
@@ -371,14 +552,22 @@ WebInputEventResult TouchEventManager::DispatchTouchEvents(
return event_result;
}
-void TouchEventManager::UpdateTargetAndRegionMapsForTouchStart(
- const WebTouchPoint& touch_point,
+void TouchEventManager::UpdateTouchAttributeMapsForPointerDown(
+ const WebPointerEvent& event,
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);
+ DCHECK(event.GetType() == WebInputEvent::kPointerDown);
+ // Ideally we'd DCHECK(!touch_attribute_map_.Contains(event.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.
+ touch_attribute_map_.Set(event.id, new TouchPointAttributes(event));
+
Node* touch_node = pointer_event_target.target_node;
String region = pointer_event_target.region;
@@ -398,7 +587,7 @@ void TouchEventManager::UpdateTargetAndRegionMapsForTouchStart(
if (touch_sequence_document_->GetFrame()) {
LayoutPoint frame_point = LayoutPoint(
touch_sequence_document_->GetFrame()->View()->RootFrameToContents(
- touch_point.PositionInWidget()));
+ event.PositionInWidget()));
result = EventHandlingUtil::HitTestResultInFrame(
touch_sequence_document_->GetFrame(), frame_point, hit_type);
Node* node = result.InnerNode();
@@ -430,15 +619,9 @@ void TouchEventManager::UpdateTargetAndRegionMapsForTouchStart(
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_point.id, touch_node);
-
- region_for_touch_id_.Set(touch_point.id, region);
+ TouchPointAttributes* attributes = touch_attribute_map_.at(event.id);
+ attributes->target_ = touch_node;
+ attributes->region_ = region;
TouchAction effective_touch_action =
TouchActionUtil::ComputeEffectiveTouchAction(*touch_node);
@@ -452,28 +635,20 @@ void TouchEventManager::UpdateTargetAndRegionMapsForTouchStart(
}
}
-bool TouchEventManager::HitTestTouchPointsIfNeeded(
- const WebTouchEvent& event,
- const HeapVector<EventHandlingUtil::PointerEventTarget>&
- pointer_event_targets) {
- bool new_touch_sequence = true;
- bool all_touches_released = true;
-
- for (unsigned i = 0; i < event.touches_length; ++i) {
- WebTouchPoint::State state = event.touches[i].state;
- if (state != WebTouchPoint::kStatePressed)
- new_touch_sequence = false;
- if (state != WebTouchPoint::kStateReleased &&
- state != WebTouchPoint::kStateCancelled)
- all_touches_released = false;
- }
- if (new_touch_sequence) {
+void TouchEventManager::HandleTouchPoint(
+ const WebPointerEvent& event,
+ const Vector<WebPointerEvent>& coalesced_events,
+ const EventHandlingUtil::PointerEventTarget& pointer_event_target) {
+ DCHECK_GE(event.GetType(), WebInputEvent::kPointerTypeFirst);
+ DCHECK_LE(event.GetType(), WebInputEvent::kPointerTypeLast);
+
+ if (touch_attribute_map_.IsEmpty()) {
// Ideally we'd DCHECK(!m_touchSequenceDocument) here since we should
// have cleared the active document when we saw the last release. But we
// have some tests that violate this, ClusterFuzz could trigger it, and
// there may be cases where the browser doesn't reliably release all
// touches. http://crbug.com/345372 tracks this.
- touch_sequence_document_.Clear();
+ AllTouchesReleasedCleanup();
}
DCHECK(frame_->View());
@@ -482,59 +657,74 @@ bool TouchEventManager::HitTestTouchPointsIfNeeded(
!touch_sequence_document_->GetFrame()->View())) {
// If the active touch document has no frame or view, it's probably being
// destroyed so we can't dispatch events.
- return false;
+ return;
}
- 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]);
- }
+ // In touch event model only touch starts can set the target and after that
+ // the touch event always goes to that target.
+ if (event.GetType() == WebInputEvent::kPointerDown) {
+ UpdateTouchAttributeMapsForPointerDown(event, pointer_event_target);
}
- touch_pressed_ = !all_touches_released;
-
- // If there's no document receiving touch events, or no handlers on the
- // document set to receive the events, then we can skip all the rest of
- // this work.
- if (!touch_sequence_document_ || !touch_sequence_document_->GetPage() ||
- !HasTouchHandlers(
- touch_sequence_document_->GetPage()->GetEventHandlerRegistry()) ||
- !touch_sequence_document_->GetFrame()) {
- if (all_touches_released) {
- touch_sequence_document_.Clear();
- }
- return false;
+ // We might not receive the down action for a touch point. In that case we
+ // would have never added them to |touch_attribute_map_| or hit-tested
+ // them. For those just keep them in the map with a null target. Later they
+ // will be targeted at the |touch_sequence_document_|.
+ if (!touch_attribute_map_.Contains(event.id)) {
+ touch_attribute_map_.insert(event.id, new TouchPointAttributes(event));
}
- return true;
+ TouchPointAttributes* attributes = touch_attribute_map_.at(event.id);
+ attributes->event_ = event;
+ attributes->coalesced_events_ = coalesced_events;
+ attributes->stale_ = false;
}
-WebInputEventResult TouchEventManager::HandleTouchEvent(
- const WebTouchEvent& event,
- const Vector<WebTouchEvent>& coalesced_events,
- const HeapVector<EventHandlingUtil::PointerEventTarget>&
- pointer_event_targets) {
- DCHECK(event.touches_length == pointer_event_targets.size());
+WebInputEventResult TouchEventManager::FlushEvents() {
+ WebInputEventResult result = WebInputEventResult::kNotHandled;
- if (!HitTestTouchPointsIfNeeded(event, pointer_event_targets))
- return WebInputEventResult::kNotHandled;
+ // If there's no document receiving touch events, or no handlers on the
+ // document set to receive the events, then we can skip all the rest of
+ // sending the event.
+ if (touch_sequence_document_ && touch_sequence_document_->GetPage() &&
+ HasTouchHandlers(
+ touch_sequence_document_->GetPage()->GetEventHandlerRegistry()) &&
+ touch_sequence_document_->GetFrame() &&
+ touch_sequence_document_->GetFrame()->View()) {
+ result = DispatchTouchEventFromAccumulatdTouchPoints();
+ }
+
+ // Cleanup the |touch_attribute_map_| map from released and canceled
+ // touch points.
+ Vector<int> released_canceled_points;
+ for (auto& attributes : touch_attribute_map_.Values()) {
+ if (attributes->event_.GetType() == WebInputEvent::kPointerUp ||
+ attributes->event_.GetType() == WebInputEvent::kPointerCancel) {
+ released_canceled_points.push_back(attributes->event_.id);
+ } else {
+ attributes->stale_ = true;
+ attributes->event_.movement_x = 0;
+ attributes->event_.movement_y = 0;
+ attributes->coalesced_events_.clear();
+ }
+ }
+ touch_attribute_map_.RemoveAll(released_canceled_points);
- bool all_touches_released = true;
- for (unsigned i = 0; i < event.touches_length; ++i) {
- WebTouchPoint::State state = event.touches[i].state;
- if (state != WebTouchPoint::kStateReleased &&
- state != WebTouchPoint::kStateCancelled)
- all_touches_released = false;
+ if (touch_attribute_map_.IsEmpty()) {
+ AllTouchesReleasedCleanup();
}
- return DispatchTouchEvents(event, coalesced_events, all_touches_released);
+ return result;
+}
+
+void TouchEventManager::AllTouchesReleasedCleanup() {
+ touch_sequence_document_.Clear();
+ current_touch_action_ = TouchAction::kTouchActionAuto;
+ last_coalesced_touch_event_ = WebTouchEvent();
}
bool TouchEventManager::IsAnyTouchActive() const {
- return touch_pressed_;
+ return !touch_attribute_map_.IsEmpty();
}
} // namespace blink
« no previous file with comments | « third_party/WebKit/Source/core/input/TouchEventManager.h ('k') | third_party/WebKit/Source/platform/BUILD.gn » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698