Commit a6c1687b authored by Ella Ge's avatar Ella Ge Committed by Commit Bot

move unlocked state movementX/Y calculation to blink

This change is under a blink flag MovementXYInBlink.
With the flag on, MouseEvent and PointerEvent's movement_x/y is
calculated in blink instead of in browser.

The movement_x/y for pointerrawmove event is not set yet. And also this
CL does not handle the calculation when pointer is locked. These is
going to be done in the following changes. See the design doc:
https://docs.google.com/document/d/1jL93PMbNHLhr6jYd4AWkjB8wgS73C5EDUa_2kYOjOn4/

With the flag, movement_x/y is in dip (same scale with screenX/Y),
which is different the current behavior(physical pixel). The coordinate
space is discuss in this doc:
https://docs.google.com/document/d/1mYk4qMxBVsFweqFOku2FZvMajejp2Q7XWGIld9ivlXE/
It needs to be changed or clarified before we enable the flag.

Bug: 802067
Change-Id: I5abb71181702c3b5265985f6ff8d2537116c5e18
Reviewed-on: https://chromium-review.googlesource.com/c/1297744Reviewed-by: default avatarMustaq Ahmed <mustaq@chromium.org>
Reviewed-by: default avatarDavid Bokan <bokan@chromium.org>
Commit-Queue: Ella Ge <eirage@chromium.org>
Cr-Commit-Position: refs/heads/master@{#610148}
parent 9b1a9eb7
......@@ -190,7 +190,7 @@ MouseEvent::MouseEvent(const AtomicString& event_type,
screen_location_(
DoublePoint(initializer->screenX(), initializer->screenY())),
movement_delta_(
IntPoint(initializer->movementX(), initializer->movementY())),
DoublePoint(initializer->movementX(), initializer->movementY())),
position_type_(synthetic_event_type == kPositionless
? PositionType::kPositionless
: PositionType::kPosition),
......@@ -236,11 +236,13 @@ void MouseEvent::SetCoordinatesFromWebPointerProperties(
initializer->setClientX(client_point.X());
initializer->setClientY(client_point.Y());
// TODO(nzolghadr): We need to scale movement attrinutes as well. But if we do
// that here and round it to the int again it causes inconsistencies between
// screenX/Y and cumulative movementX/Y.
// TODO(nzolghadr): We need to scale movement attrinutes as well. But if we
// do that here and round it to the int again it causes inconsistencies
// between screenX/Y and cumulative movementX/Y.
if (!RuntimeEnabledFeatures::MovementXYInBlinkEnabled()) {
initializer->setMovementX(web_pointer_properties.movement_x);
initializer->setMovementY(web_pointer_properties.movement_y);
}
}
MouseEvent::~MouseEvent() = default;
......
......@@ -185,8 +185,8 @@ class CORE_EXPORT MouseEvent : public UIEventWithKeyState {
WebMenuSourceType GetMenuSourceType() const { return menu_source_type_; }
// Page point in "absolute" coordinates (i.e. post-zoomed, page-relative
// coords, usable with LayoutObject::absoluteToLocal) relative to view(), i.e.
// the local frame.
// coords, usable with LayoutObject::absoluteToLocal) relative to view(),
// i.e. the local frame.
const DoublePoint& AbsoluteLocation() const { return absolute_location_; }
DispatchEventResult DispatchEvent(EventDispatcher&) override;
......
......@@ -80,7 +80,9 @@ float GetPointerEventPressure(float force, int buttons) {
return 0.5;
return force;
}
void UpdateCommonPointerEventInit(const WebPointerEvent& web_pointer_event,
const FloatPoint& last_global_position,
LocalDOMWindow* dom_window,
PointerEventInit* pointer_event_init) {
// This function should not update attributes like pointerId, isPrimary,
......@@ -92,6 +94,15 @@ void UpdateCommonPointerEventInit(const WebPointerEvent& web_pointer_event,
MouseEvent::SetCoordinatesFromWebPointerProperties(
web_pointer_event_in_root_frame, dom_window, pointer_event_init);
if (RuntimeEnabledFeatures::MovementXYInBlinkEnabled() &&
web_pointer_event.GetType() == WebInputEvent::kPointerMove) {
// TODO(eirage): pointerrawmove event's movements are not calculated.
pointer_event_init->setMovementX(web_pointer_event.PositionInScreen().x -
last_global_position.X());
pointer_event_init->setMovementY(web_pointer_event.PositionInScreen().y -
last_global_position.Y());
}
// If width/height is unknown we let PointerEventInit set it to 1.
// See https://w3c.github.io/pointerevents/#dom-pointerevent-width
if (web_pointer_event_in_root_frame.HasWidth() &&
......@@ -115,13 +126,22 @@ void UpdateCommonPointerEventInit(const WebPointerEvent& web_pointer_event,
pointer_event_init->setTwist(web_pointer_event.twist);
}
HeapVector<Member<PointerEvent>> CreateEventSequence(
} // namespace
HeapVector<Member<PointerEvent>> PointerEventFactory::CreateEventSequence(
const WebPointerEvent& web_pointer_event,
const PointerEventInit* pointer_event_init,
const Vector<WebPointerEvent>& event_list,
LocalDOMWindow* view) {
AtomicString type = PointerEventNameForEventType(web_pointer_event.GetType());
HeapVector<Member<PointerEvent>> result;
if (!event_list.IsEmpty()) {
// Make a copy of LastPointerPosition so we can modify it after creating
// each coalesced event.
FloatPoint last_global_position = GetLastPointerPosition(
pointer_event_init->pointerId(), event_list.front());
for (const auto& event : event_list) {
DCHECK_EQ(web_pointer_event.id, event.id);
DCHECK_EQ(web_pointer_event.GetType(), event.GetType());
......@@ -143,21 +163,24 @@ HeapVector<Member<PointerEvent>> CreateEventSequence(
new_event_init->setCancelable(false);
new_event_init->setBubbles(false);
UpdateCommonPointerEventInit(event, view, new_event_init);
UpdateCommonPointerEventInit(event, last_global_position, view,
new_event_init);
last_global_position = event.PositionInScreen();
PointerEvent* pointer_event =
PointerEvent::Create(type, new_event_init, event.TimeStamp());
// Set the trusted flag for these events at the creation time as oppose to
// the normal events which is done at the dispatch time. This is because we
// don't want to go over all these events at every dispatch and add the
// implementation complexity while it has no sensible usecase at this time.
// the normal events which is done at the dispatch time. This is because
// we don't want to go over all these events at every dispatch and add the
// implementation complexity while it has no sensible usecase at this
// time.
pointer_event->SetTrusted(true);
result.push_back(pointer_event);
}
}
return result;
}
} // namespace
const int PointerEventFactory::kInvalidId = 0;
// Mouse id is 1 to behave the same as MS Edge for compatibility reasons.
......@@ -263,7 +286,11 @@ PointerEvent* PointerEventFactory::Create(
}
pointer_event_init->setView(view);
UpdateCommonPointerEventInit(web_pointer_event, view, pointer_event_init);
UpdateCommonPointerEventInit(
web_pointer_event,
GetLastPointerPosition(pointer_event_init->pointerId(),
web_pointer_event),
view, pointer_event_init);
UIEventWithKeyState::SetFromWebInputEventModifiers(
pointer_event_init,
......@@ -285,10 +312,30 @@ PointerEvent* PointerEventFactory::Create(
pointer_event_init->setCoalescedEvents(coalesced_pointer_events);
pointer_event_init->setPredictedEvents(predicted_pointer_events);
SetLastPosition(pointer_event_init->pointerId(), web_pointer_event);
return PointerEvent::Create(type, pointer_event_init,
web_pointer_event.TimeStamp());
}
void PointerEventFactory::SetLastPosition(int pointer_id,
const WebPointerProperties& event) {
pointer_id_last_position_mapping_.Set(pointer_id, event.PositionInScreen());
}
void PointerEventFactory::RemoveLastPosition(const int pointer_id) {
return pointer_id_last_position_mapping_.erase(pointer_id);
}
FloatPoint PointerEventFactory::GetLastPointerPosition(
int pointer_id,
const WebPointerProperties& event) const {
if (pointer_id_last_position_mapping_.Contains(pointer_id))
return pointer_id_last_position_mapping_.at(pointer_id);
// If pointer_id is not in the map, returns the current position so the
// movement will be zero.
return event.PositionInScreen();
}
PointerEvent* PointerEventFactory::CreatePointerCancelEvent(
const int pointer_id,
TimeTicks platfrom_time_stamp) {
......@@ -399,6 +446,7 @@ void PointerEventFactory::Clear() {
}
pointer_incoming_id_mapping_.clear();
pointer_id_mapping_.clear();
pointer_id_last_position_mapping_.clear();
// Always add mouse pointer in initialization and never remove it.
// No need to add it to m_pointerIncomingIdMapping as it is not going to be
......@@ -449,6 +497,7 @@ bool PointerEventFactory::Remove(const int mapped_id) {
int type_int = p.PointerTypeInt();
pointer_id_mapping_.erase(mapped_id);
pointer_incoming_id_mapping_.erase(p);
RemoveLastPosition(mapped_id);
if (primary_id_[type_int] == mapped_id)
primary_id_[type_int] = PointerEventFactory::kInvalidId;
id_count_[type_int]--;
......
......@@ -80,6 +80,15 @@ class CORE_EXPORT PointerEventFactory {
static const int kMouseId;
// Removes pointer_id from the map.
void RemoveLastPosition(const int pointer_id);
// Returns last_position of for the given pointerId if such id is active.
// Otherwise it returns the PositionInScreen of the given events, so we will
// get movement = 0 when there is no last position.
FloatPoint GetLastPointerPosition(int pointer_id,
const WebPointerProperties& event) const;
private:
typedef WTF::UnsignedWithZeroKeyHashTraits<int> UnsignedHash;
typedef struct IncomingId : public std::pair<int, int> {
......@@ -119,6 +128,14 @@ class CORE_EXPORT PointerEventFactory {
const AtomicString&,
EventTarget*);
HeapVector<Member<PointerEvent>> CreateEventSequence(
const WebPointerEvent& web_pointer_event,
const PointerEventInit* pointer_event_init,
const Vector<WebPointerEvent>& event_list,
LocalDOMWindow* view);
void SetLastPosition(int pointer_id, const WebPointerProperties& event);
static const int kInvalidId;
int current_id_;
......@@ -135,6 +152,9 @@ class CORE_EXPORT PointerEventFactory {
int id_count_[static_cast<int>(
WebPointerProperties::PointerType::kLastEntry) +
1];
HashMap<int, FloatPoint, WTF::IntHash<int>, UnsignedHash>
pointer_id_last_position_mapping_;
};
} // namespace blink
......
......@@ -807,6 +807,7 @@ void EventHandler::HandleMouseLeaveEvent(const WebMouseEvent& event) {
HandleMouseMoveOrLeaveEvent(event, Vector<WebMouseEvent>(),
Vector<WebMouseEvent>(), nullptr, nullptr, false,
true);
pointer_event_manager_->RemoveLastMousePosition();
}
WebInputEventResult EventHandler::HandleMouseMoveOrLeaveEvent(
......@@ -1899,7 +1900,7 @@ WebInputEventResult EventHandler::SendContextMenuEvent(
return mouse_event_manager_->DispatchMouseEvent(
EffectiveMouseEventTargetNode(target_node),
event_type_names::kContextmenu, event,
mev.GetHitTestResult().CanvasRegionId(), nullptr);
mev.GetHitTestResult().CanvasRegionId(), nullptr, nullptr);
}
static bool ShouldShowContextMenuAtSelection(const FrameSelection& selection) {
......
......@@ -61,6 +61,27 @@ String CanvasRegionId(Node* node, const WebMouseEvent& mouse_event) {
return canvas->GetIdFromControl(element);
}
void UpdateMouseMovementXY(const WebMouseEvent& mouse_event,
const FloatPoint* last_position,
MouseEventInit* initializer) {
if (RuntimeEnabledFeatures::MovementXYInBlinkEnabled() &&
mouse_event.GetType() == WebInputEvent::kMouseMove && last_position) {
if (RuntimeEnabledFeatures::FractionalMouseEventEnabled()) {
initializer->setMovementX(mouse_event.PositionInScreen().x -
last_position->X());
initializer->setMovementY(mouse_event.PositionInScreen().y -
last_position->Y());
} else {
initializer->setMovementX(
static_cast<int>(mouse_event.PositionInScreen().x) -
static_cast<int>(last_position->X()));
initializer->setMovementY(
static_cast<int>(mouse_event.PositionInScreen().y) -
static_cast<int>(last_position->Y()));
}
}
}
// The amount of time to wait before sending a fake mouse event triggered
// during a scroll.
constexpr TimeDelta kFakeMouseMoveIntervalDuringScroll =
......@@ -192,8 +213,8 @@ void MouseEventManager::MouseEventBoundaryEventDispatcher::Dispatch(
const WebMouseEvent& web_mouse_event,
bool check_for_listener) {
mouse_event_manager_->DispatchMouseEvent(target, type, web_mouse_event,
canvas_region_id, related_target,
check_for_listener);
canvas_region_id, nullptr,
related_target, check_for_listener);
}
void MouseEventManager::SendBoundaryEvents(EventTarget* exited_target,
......@@ -210,6 +231,7 @@ WebInputEventResult MouseEventManager::DispatchMouseEvent(
const AtomicString& mouse_event_type,
const WebMouseEvent& mouse_event,
const String& canvas_region_id,
const FloatPoint* last_position,
EventTarget* related_target,
bool check_for_listener) {
if (target && target->ToNode() &&
......@@ -232,6 +254,7 @@ WebInputEventResult MouseEventManager::DispatchMouseEvent(
MouseEvent::SetCoordinatesFromWebPointerProperties(
mouse_event.FlattenTransform(), target_node->GetDocument().domWindow(),
initializer);
UpdateMouseMovementXY(mouse_event, last_position, initializer);
initializer->setButton(static_cast<short>(mouse_event.button));
initializer->setButtons(MouseEvent::WebInputEventModifiersToButtons(
mouse_event.GetModifiers()));
......@@ -275,7 +298,7 @@ WebInputEventResult MouseEventManager::SetMousePositionAndDispatchMouseEvent(
SetNodeUnderMouse(target_node, canvas_region_id, web_mouse_event);
return DispatchMouseEvent(node_under_mouse_, event_type, web_mouse_event,
canvas_region_id, nullptr);
canvas_region_id, nullptr, nullptr);
}
WebInputEventResult MouseEventManager::DispatchMouseClickIfNeeded(
......@@ -340,7 +363,7 @@ WebInputEventResult MouseEventManager::DispatchMouseClickIfNeeded(
(mev.Event().button == WebPointerProperties::Button::kLeft)
? event_type_names::kClick
: event_type_names::kAuxclick,
mev.Event(), mev.CanvasRegionId(), nullptr);
mev.Event(), mev.CanvasRegionId(), nullptr, nullptr);
}
return WebInputEventResult::kNotHandled;
......
......@@ -49,6 +49,7 @@ class CORE_EXPORT MouseEventManager final
const AtomicString&,
const WebMouseEvent&,
const String& canvas_region_id,
const FloatPoint* last_position,
EventTarget* related_target,
bool check_for_listener = false);
......
......@@ -610,12 +610,18 @@ WebInputEventResult PointerEventManager::DirectDispatchMousePointerEvent(
const Vector<WebMouseEvent>& coalesced_events,
const Vector<WebMouseEvent>& predicted_events,
const String& canvas_region_id) {
// Fetch the last_mouse_position for creating MouseEvent before
// pointer_event_factory updates it.
FloatPoint last_mouse_position =
pointer_event_factory_.GetLastPointerPosition(
PointerEventFactory::kMouseId, event);
WebInputEventResult result = CreateAndDispatchPointerEvent(
target, mouse_event_type, event, coalesced_events, predicted_events);
result = event_handling_util::MergeEventResult(
result, mouse_event_manager_->DispatchMouseEvent(
target, mouse_event_type, event, canvas_region_id, nullptr));
target, mouse_event_type, event, canvas_region_id,
&last_mouse_position, nullptr));
return result;
}
......@@ -639,6 +645,12 @@ WebInputEventResult PointerEventManager::SendMousePointerEvent(
for (const WebMouseEvent& e : predicted_events)
pointer_predicted_events.push_back(WebPointerEvent(event_type, e));
// Fetch the last_mouse_position for creating MouseEvent before
// pointer_event_factory updates it.
FloatPoint last_mouse_position =
pointer_event_factory_.GetLastPointerPosition(
PointerEventFactory::kMouseId, mouse_event);
PointerEvent* pointer_event = pointer_event_factory_.Create(
web_pointer_event, pointer_coalesced_events, pointer_predicted_events,
frame_->GetDocument()->domWindow());
......@@ -714,7 +726,7 @@ WebInputEventResult PointerEventManager::SendMousePointerEvent(
result,
mouse_event_manager_->DispatchMouseEvent(
mouse_target, MouseEventNameForPointerEventInputType(event_type),
mouse_event, canvas_region_id, nullptr));
mouse_event, canvas_region_id, &last_mouse_position, nullptr));
}
if (pointer_event->type() == event_type_names::kPointerup ||
......@@ -958,4 +970,8 @@ bool PointerEventManager::PrimaryPointerdownCanceled(
return false;
}
void PointerEventManager::RemoveLastMousePosition() {
pointer_event_factory_.RemoveLastPosition(PointerEventFactory::kMouseId);
}
} // namespace blink
......@@ -107,6 +107,8 @@ class CORE_EXPORT PointerEventManager
void ProcessPendingPointerCaptureForPointerLock(const WebMouseEvent&);
void RemoveLastMousePosition();
// Sends any outstanding events. For example it notifies TouchEventManager
// to group any changes to touch since last FlushEvents and send the touch
// event out to js. Since after this function any outstanding event is sent,
......
......@@ -207,4 +207,71 @@ TEST_F(PointerEventManagerTest, PointerEventCoordinates) {
ASSERT_EQ(callback->last_movement_y_, 10);
}
TEST_F(PointerEventManagerTest, PointerEventMovements) {
WebView().Resize(WebSize(400, 400));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(
"<body style='padding: 0px; width: 400px; height: 400px;'>"
"</body>");
PointerEventCoordinateListenerCallback* callback =
PointerEventCoordinateListenerCallback::Create();
GetDocument().body()->addEventListener(event_type_names::kPointermove,
callback);
// Turn on the flag for test.
RuntimeEnabledFeatures::SetMovementXYInBlinkEnabled(true);
WebView().HandleInputEvent(WebCoalescedInputEvent(
CreateTestPointerEvent(WebInputEvent::kPointerMove,
WebPointerProperties::PointerType::kMouse,
WebFloatPoint(150, 210), WebFloatPoint(100, 50),
10, 10),
std::vector<WebPointerEvent>(), std::vector<WebPointerEvent>()));
// The first pointermove event has movement_x/y 0.
ASSERT_EQ(callback->last_screen_x_, 100);
ASSERT_EQ(callback->last_screen_y_, 50);
ASSERT_EQ(callback->last_movement_x_, 0);
ASSERT_EQ(callback->last_movement_y_, 0);
WebView().HandleInputEvent(WebCoalescedInputEvent(
CreateTestPointerEvent(WebInputEvent::kPointerMove,
WebPointerProperties::PointerType::kMouse,
WebFloatPoint(150, 200), WebFloatPoint(132, 29),
10, 10),
std::vector<WebPointerEvent>(), std::vector<WebPointerEvent>()));
// pointermove event movement = event.screenX/Y - last_event.screenX/Y.
ASSERT_EQ(callback->last_screen_x_, 132);
ASSERT_EQ(callback->last_screen_y_, 29);
ASSERT_EQ(callback->last_movement_x_, 32);
ASSERT_EQ(callback->last_movement_y_, -21);
WebView().HandleInputEvent(WebCoalescedInputEvent(
CreateTestPointerEvent(WebInputEvent::kPointerMove,
WebPointerProperties::PointerType::kMouse,
WebFloatPoint(150, 210),
WebFloatPoint(113.8, 32.7), 10, 10),
std::vector<WebPointerEvent>(), std::vector<WebPointerEvent>()));
// fractional screen coordinates result in fractional movement.
ASSERT_FLOAT_EQ(callback->last_screen_x_, 113.8);
ASSERT_FLOAT_EQ(callback->last_screen_y_, 32.7);
// TODO(eirage): These should be float value once mouse_event.idl change.
ASSERT_FLOAT_EQ(callback->last_movement_x_, -18);
ASSERT_FLOAT_EQ(callback->last_movement_y_, 3);
// When flag is off, movementX/Y follows the value in WebPointerProperties.
RuntimeEnabledFeatures::SetMovementXYInBlinkEnabled(false);
WebView().HandleInputEvent(WebCoalescedInputEvent(
CreateTestPointerEvent(WebInputEvent::kPointerMove,
WebPointerProperties::PointerType::kMouse,
WebFloatPoint(150, 210), WebFloatPoint(100, 16.25),
1024, -8765),
std::vector<WebPointerEvent>(), std::vector<WebPointerEvent>()));
ASSERT_EQ(callback->last_screen_x_, 100);
ASSERT_EQ(callback->last_screen_y_, 16.25);
ASSERT_EQ(callback->last_movement_x_, 1024);
ASSERT_EQ(callback->last_movement_y_, -8765);
}
} // namespace blink
......@@ -805,6 +805,9 @@
name: "MojoJSTest",
status: "test",
},
{
name: "MovementXYInBlink",
},
{
name: "NavigatorContentUtils",
},
......
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