| // Copyright 2016 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "third_party/blink/renderer/core/events/pointer_event_factory.h" |
| |
| #include "third_party/blink/public/common/widget/screen_info.h" |
| #include "third_party/blink/renderer/bindings/core/v8/v8_pointer_event_init.h" |
| #include "third_party/blink/renderer/core/frame/local_dom_window.h" |
| #include "third_party/blink/renderer/core/frame/local_frame_view.h" |
| #include "third_party/blink/renderer/core/page/chrome_client.h" |
| #include "third_party/blink/renderer/core/page/page.h" |
| #include "third_party/blink/renderer/platform/geometry/float_size.h" |
| |
| namespace blink { |
| |
| namespace { |
| |
| inline int ToInt(WebPointerProperties::PointerType t) { |
| return static_cast<int>(t); |
| } |
| |
| const char* PointerTypeNameForWebPointPointerType( |
| WebPointerProperties::PointerType type) { |
| // TODO(mustaq): Fix when the spec starts supporting hovering erasers. |
| switch (type) { |
| case WebPointerProperties::PointerType::kUnknown: |
| return ""; |
| case WebPointerProperties::PointerType::kTouch: |
| return "touch"; |
| case WebPointerProperties::PointerType::kPen: |
| return "pen"; |
| case WebPointerProperties::PointerType::kMouse: |
| return "mouse"; |
| default: |
| NOTREACHED(); |
| return ""; |
| } |
| } |
| |
| uint16_t ButtonToButtonsBitfield(WebPointerProperties::Button button) { |
| #define CASE_BUTTON_TO_BUTTONS(enumLabel) \ |
| case WebPointerProperties::Button::enumLabel: \ |
| return static_cast<uint16_t>(WebPointerProperties::Buttons::enumLabel) |
| |
| switch (button) { |
| CASE_BUTTON_TO_BUTTONS(kNoButton); |
| CASE_BUTTON_TO_BUTTONS(kLeft); |
| CASE_BUTTON_TO_BUTTONS(kRight); |
| CASE_BUTTON_TO_BUTTONS(kMiddle); |
| CASE_BUTTON_TO_BUTTONS(kBack); |
| CASE_BUTTON_TO_BUTTONS(kForward); |
| CASE_BUTTON_TO_BUTTONS(kEraser); |
| } |
| |
| #undef CASE_BUTTON_TO_BUTTONS |
| |
| NOTREACHED(); |
| return 0; |
| } |
| |
| const AtomicString& PointerEventNameForEventType(WebInputEvent::Type type) { |
| switch (type) { |
| case WebInputEvent::Type::kPointerDown: |
| return event_type_names::kPointerdown; |
| case WebInputEvent::Type::kPointerUp: |
| return event_type_names::kPointerup; |
| case WebInputEvent::Type::kPointerMove: |
| return event_type_names::kPointermove; |
| case WebInputEvent::Type::kPointerRawUpdate: |
| return event_type_names::kPointerrawupdate; |
| case WebInputEvent::Type::kPointerCancel: |
| return event_type_names::kPointercancel; |
| default: |
| NOTREACHED(); |
| return g_empty_atom; |
| } |
| } |
| |
| float GetPointerEventPressure(float force, uint16_t buttons) { |
| if (!buttons) |
| return 0; |
| if (std::isnan(force)) |
| 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, |
| // and pointerType which is the same among the coalesced events and the |
| // dispatched event. |
| |
| WebPointerEvent web_pointer_event_in_root_frame = |
| web_pointer_event.WebPointerEventInRootFrame(); |
| |
| MouseEvent::SetCoordinatesFromWebPointerProperties( |
| web_pointer_event_in_root_frame, dom_window, pointer_event_init); |
| if (RuntimeEnabledFeatures::ConsolidatedMovementXYEnabled() && |
| !web_pointer_event.is_raw_movement_event && |
| (web_pointer_event.GetType() == WebInputEvent::Type::kPointerMove || |
| web_pointer_event.GetType() == WebInputEvent::Type::kPointerRawUpdate)) { |
| // TODO(crbug.com/907309): Current movementX/Y is in physical pixel when |
| // zoom-for-dsf is enabled. Here we apply the device-scale-factor to align |
| // with the current behavior. We need to figure out what is the best |
| // behavior here. |
| float device_scale_factor = 1; |
| if (dom_window && dom_window->GetFrame()) { |
| LocalFrame* frame = dom_window->GetFrame(); |
| if (frame->GetPage()->DeviceScaleFactorDeprecated() == 1) { |
| ChromeClient& chrome_client = frame->GetPage()->GetChromeClient(); |
| device_scale_factor = |
| chrome_client.GetScreenInfo(*frame).device_scale_factor; |
| } |
| } |
| |
| // movementX/Y is type int for pointerevent, so we still need to truncated |
| // the coordinates before calculate movement. |
| pointer_event_init->setMovementX( |
| base::saturated_cast<int>(web_pointer_event.PositionInScreen().x() * |
| device_scale_factor) - |
| base::saturated_cast<int>(last_global_position.X() * |
| device_scale_factor)); |
| pointer_event_init->setMovementY( |
| base::saturated_cast<int>(web_pointer_event.PositionInScreen().y() * |
| device_scale_factor) - |
| base::saturated_cast<int>(last_global_position.Y() * |
| device_scale_factor)); |
| } |
| |
| // 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() && |
| web_pointer_event_in_root_frame.HasHeight()) { |
| float scale_factor = 1.0f; |
| if (dom_window && dom_window->GetFrame()) |
| scale_factor = 1.0f / dom_window->GetFrame()->PageZoomFactor(); |
| |
| FloatSize point_shape = FloatSize(web_pointer_event_in_root_frame.width, |
| web_pointer_event_in_root_frame.height) |
| .ScaledBy(scale_factor); |
| pointer_event_init->setWidth(point_shape.Width()); |
| pointer_event_init->setHeight(point_shape.Height()); |
| } |
| pointer_event_init->setPressure(GetPointerEventPressure( |
| web_pointer_event.force, pointer_event_init->buttons())); |
| pointer_event_init->setTiltX(web_pointer_event.tilt_x); |
| pointer_event_init->setTiltY(web_pointer_event.tilt_y); |
| pointer_event_init->setTangentialPressure( |
| web_pointer_event.tangential_pressure); |
| pointer_event_init->setTwist(web_pointer_event.twist); |
| } |
| |
| } // 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(), web_pointer_event.GetType()); |
| |
| for (const auto& event : event_list) { |
| DCHECK_EQ(web_pointer_event.id, event.id); |
| DCHECK_EQ(web_pointer_event.GetType(), event.GetType()); |
| DCHECK_EQ(web_pointer_event.pointer_type, event.pointer_type); |
| |
| PointerEventInit* new_event_init = PointerEventInit::Create(); |
| if (pointer_event_init->hasButton()) |
| new_event_init->setButton(pointer_event_init->button()); |
| if (pointer_event_init->hasButtons()) |
| new_event_init->setButtons(pointer_event_init->buttons()); |
| if (pointer_event_init->hasIsPrimary()) |
| new_event_init->setIsPrimary(pointer_event_init->isPrimary()); |
| if (pointer_event_init->hasPointerId()) |
| new_event_init->setPointerId(pointer_event_init->pointerId()); |
| if (pointer_event_init->hasPointerType()) |
| new_event_init->setPointerType(pointer_event_init->pointerType()); |
| if (pointer_event_init->hasView()) |
| new_event_init->setView(pointer_event_init->view()); |
| |
| new_event_init->setCancelable(false); |
| new_event_init->setBubbles(false); |
| UpdateCommonPointerEventInit(event, last_global_position, view, |
| new_event_init); |
| UIEventWithKeyState::SetFromWebInputEventModifiers( |
| new_event_init, |
| static_cast<WebInputEvent::Modifiers>(event.GetModifiers())); |
| |
| last_global_position = FloatPoint(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. |
| pointer_event->SetTrusted(true); |
| result.push_back(pointer_event); |
| } |
| } |
| return result; |
| } |
| |
| const PointerId PointerEventFactory::kInvalidId = 0; |
| |
| // Mouse id is 1 to behave the same as MS Edge for compatibility reasons. |
| const PointerId PointerEventFactory::kMouseId = 1; |
| |
| PointerEventInit* PointerEventFactory::ConvertIdTypeButtonsEvent( |
| const WebPointerEvent& web_pointer_event) { |
| WebPointerProperties::PointerType pointer_type = |
| web_pointer_event.pointer_type; |
| |
| unsigned buttons; |
| if (web_pointer_event.hovering) { |
| buttons = MouseEvent::WebInputEventModifiersToButtons( |
| static_cast<WebInputEvent::Modifiers>( |
| web_pointer_event.GetModifiers())); |
| } else { |
| // TODO(crbug.com/816504): This is incorrect as we are assuming pointers |
| // that don't hover have no other buttons except left which represents |
| // touching the screen. This misconception comes from the touch devices and |
| // is not correct for stylus. |
| buttons = static_cast<unsigned>( |
| (web_pointer_event.GetType() == WebInputEvent::Type::kPointerUp || |
| web_pointer_event.GetType() == WebInputEvent::Type::kPointerCancel) |
| ? WebPointerProperties::Buttons::kNoButton |
| : WebPointerProperties::Buttons::kLeft); |
| } |
| // Tweak the |buttons| to reflect pen eraser mode only if the pen is in |
| // active buttons state w/o even considering the eraser button. |
| // TODO(mustaq): Fix when the spec starts supporting hovering erasers. |
| if (pointer_type == WebPointerProperties::PointerType::kEraser) { |
| if (buttons != 0) { |
| buttons |= static_cast<unsigned>(WebPointerProperties::Buttons::kEraser); |
| buttons &= ~static_cast<unsigned>(WebPointerProperties::Buttons::kLeft); |
| } |
| pointer_type = WebPointerProperties::PointerType::kPen; |
| } |
| |
| const IncomingId incoming_id(pointer_type, web_pointer_event.id); |
| PointerId pointer_id = AddIdAndActiveButtons(incoming_id, buttons != 0, |
| web_pointer_event.hovering, |
| web_pointer_event.GetType()); |
| if (pointer_id == kInvalidId) |
| return nullptr; |
| |
| PointerEventInit* pointer_event_init = PointerEventInit::Create(); |
| pointer_event_init->setButtons(buttons); |
| pointer_event_init->setPointerId(pointer_id); |
| pointer_event_init->setPointerType( |
| PointerTypeNameForWebPointPointerType(pointer_type)); |
| pointer_event_init->setIsPrimary(IsPrimary(pointer_id)); |
| |
| return pointer_event_init; |
| } |
| |
| void PointerEventFactory::SetEventSpecificFields( |
| PointerEventInit* pointer_event_init, |
| const AtomicString& type) { |
| pointer_event_init->setBubbles(type != event_type_names::kPointerenter && |
| type != event_type_names::kPointerleave); |
| pointer_event_init->setCancelable( |
| type != event_type_names::kPointerenter && |
| type != event_type_names::kPointerleave && |
| type != event_type_names::kPointercancel && |
| type != event_type_names::kPointerrawupdate && |
| type != event_type_names::kGotpointercapture && |
| type != event_type_names::kLostpointercapture); |
| |
| pointer_event_init->setComposed(true); |
| pointer_event_init->setDetail(0); |
| } |
| |
| PointerEvent* PointerEventFactory::Create( |
| const WebPointerEvent& web_pointer_event, |
| const Vector<WebPointerEvent>& coalesced_events, |
| const Vector<WebPointerEvent>& predicted_events, |
| LocalDOMWindow* view) { |
| const WebInputEvent::Type event_type = web_pointer_event.GetType(); |
| DCHECK(event_type == WebInputEvent::Type::kPointerDown || |
| event_type == WebInputEvent::Type::kPointerUp || |
| event_type == WebInputEvent::Type::kPointerMove || |
| event_type == WebInputEvent::Type::kPointerRawUpdate || |
| event_type == WebInputEvent::Type::kPointerCancel); |
| |
| PointerEventInit* pointer_event_init = |
| ConvertIdTypeButtonsEvent(web_pointer_event); |
| if (!pointer_event_init) |
| return nullptr; |
| |
| AtomicString type = PointerEventNameForEventType(event_type); |
| if (event_type == WebInputEvent::Type::kPointerDown || |
| event_type == WebInputEvent::Type::kPointerUp) { |
| WebPointerProperties::Button button = web_pointer_event.button; |
| // TODO(mustaq): Fix when the spec starts supporting hovering erasers. |
| if (web_pointer_event.pointer_type == |
| WebPointerProperties::PointerType::kEraser && |
| button == WebPointerProperties::Button::kLeft) |
| button = WebPointerProperties::Button::kEraser; |
| pointer_event_init->setButton(static_cast<int>(button)); |
| |
| // Make sure chorded buttons fire pointermove instead of pointerup/down. |
| if ((event_type == WebInputEvent::Type::kPointerDown && |
| (pointer_event_init->buttons() & ~ButtonToButtonsBitfield(button)) != |
| 0) || |
| (event_type == WebInputEvent::Type::kPointerUp && |
| pointer_event_init->buttons() != 0)) |
| type = event_type_names::kPointermove; |
| } else { |
| pointer_event_init->setButton( |
| static_cast<int16_t>(WebPointerProperties::Button::kNoButton)); |
| } |
| |
| pointer_event_init->setView(view); |
| UpdateCommonPointerEventInit( |
| web_pointer_event, |
| GetLastPointerPosition(pointer_event_init->pointerId(), web_pointer_event, |
| event_type), |
| view, pointer_event_init); |
| |
| UIEventWithKeyState::SetFromWebInputEventModifiers( |
| pointer_event_init, |
| static_cast<WebInputEvent::Modifiers>(web_pointer_event.GetModifiers())); |
| |
| SetEventSpecificFields(pointer_event_init, type); |
| |
| HeapVector<Member<PointerEvent>> coalesced_pointer_events, |
| predicted_pointer_events; |
| if (type == event_type_names::kPointermove || |
| type == event_type_names::kPointerrawupdate) { |
| coalesced_pointer_events = CreateEventSequence( |
| web_pointer_event, pointer_event_init, coalesced_events, view); |
| } |
| if (type == event_type_names::kPointermove) { |
| predicted_pointer_events = CreateEventSequence( |
| web_pointer_event, pointer_event_init, predicted_events, view); |
| } |
| pointer_event_init->setCoalescedEvents(coalesced_pointer_events); |
| pointer_event_init->setPredictedEvents(predicted_pointer_events); |
| |
| SetLastPosition(pointer_event_init->pointerId(), |
| FloatPoint(web_pointer_event.PositionInScreen()), event_type); |
| return PointerEvent::Create(type, pointer_event_init, |
| web_pointer_event.TimeStamp()); |
| } |
| |
| void PointerEventFactory::SetLastPosition(int pointer_id, |
| const FloatPoint& position_in_screen, |
| WebInputEvent::Type event_type) { |
| if (event_type == WebInputEvent::Type::kPointerRawUpdate) |
| pointerrawupdate_last_position_mapping_.Set(pointer_id, position_in_screen); |
| else |
| pointer_id_last_position_mapping_.Set(pointer_id, position_in_screen); |
| } |
| |
| void PointerEventFactory::RemoveLastPosition(const int pointer_id) { |
| pointer_id_last_position_mapping_.erase(pointer_id); |
| pointerrawupdate_last_position_mapping_.erase(pointer_id); |
| } |
| |
| FloatPoint PointerEventFactory::GetLastPointerPosition( |
| int pointer_id, |
| const WebPointerProperties& event, |
| WebInputEvent::Type event_type) const { |
| if (event_type == WebInputEvent::Type::kPointerRawUpdate) { |
| if (pointerrawupdate_last_position_mapping_.Contains(pointer_id)) |
| return pointerrawupdate_last_position_mapping_.at(pointer_id); |
| } else { |
| 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 FloatPoint(event.PositionInScreen()); |
| } |
| |
| PointerEvent* PointerEventFactory::CreatePointerCancelEvent( |
| const int pointer_id, |
| base::TimeTicks platfrom_time_stamp) { |
| DCHECK(pointer_id_mapping_.Contains(pointer_id)); |
| pointer_id_mapping_.Set( |
| pointer_id, |
| PointerAttributes(pointer_id_mapping_.at(pointer_id).incoming_id, false, |
| true)); |
| |
| PointerEventInit* pointer_event_init = PointerEventInit::Create(); |
| |
| pointer_event_init->setPointerId(pointer_id); |
| pointer_event_init->setPointerType(PointerTypeNameForWebPointPointerType( |
| pointer_id_mapping_.at(pointer_id).incoming_id.GetPointerType())); |
| pointer_event_init->setIsPrimary(IsPrimary(pointer_id)); |
| |
| SetEventSpecificFields(pointer_event_init, event_type_names::kPointercancel); |
| |
| return PointerEvent::Create(event_type_names::kPointercancel, |
| pointer_event_init, platfrom_time_stamp); |
| } |
| |
| PointerEvent* PointerEventFactory::CreatePointerEventFrom( |
| PointerEvent* pointer_event, |
| const AtomicString& type, |
| EventTarget* related_target) { |
| PointerEventInit* pointer_event_init = PointerEventInit::Create(); |
| |
| pointer_event_init->setPointerId(pointer_event->pointerId()); |
| pointer_event_init->setPointerType(pointer_event->pointerType()); |
| pointer_event_init->setIsPrimary(pointer_event->isPrimary()); |
| pointer_event_init->setWidth(pointer_event->width()); |
| pointer_event_init->setHeight(pointer_event->height()); |
| pointer_event_init->setScreenX(pointer_event->screenX()); |
| pointer_event_init->setScreenY(pointer_event->screenY()); |
| pointer_event_init->setClientX(pointer_event->clientX()); |
| pointer_event_init->setClientY(pointer_event->clientY()); |
| pointer_event_init->setButton(pointer_event->button()); |
| pointer_event_init->setButtons(pointer_event->buttons()); |
| pointer_event_init->setPressure(pointer_event->pressure()); |
| pointer_event_init->setTiltX(pointer_event->tiltX()); |
| pointer_event_init->setTiltY(pointer_event->tiltY()); |
| pointer_event_init->setTangentialPressure( |
| pointer_event->tangentialPressure()); |
| pointer_event_init->setTwist(pointer_event->twist()); |
| pointer_event_init->setView(pointer_event->view()); |
| |
| SetEventSpecificFields(pointer_event_init, type); |
| |
| if (const UIEventWithKeyState* key_state_event = |
| FindEventWithKeyState(pointer_event)) { |
| UIEventWithKeyState::SetFromWebInputEventModifiers( |
| pointer_event_init, key_state_event->GetModifiers()); |
| } |
| |
| if (related_target) |
| pointer_event_init->setRelatedTarget(related_target); |
| |
| return PointerEvent::Create(type, pointer_event_init, |
| pointer_event->PlatformTimeStamp()); |
| } |
| |
| PointerEvent* PointerEventFactory::CreatePointerRawUpdateEvent( |
| PointerEvent* pointer_event) { |
| // This function is for creating pointerrawupdate event from a pointerdown/up |
| // event that caused by chorded buttons and hence its type is changed to |
| // pointermove. |
| DCHECK(pointer_event->type() == event_type_names::kPointermove && |
| (pointer_event->buttons() & |
| ~ButtonToButtonsBitfield(static_cast<WebPointerProperties::Button>( |
| pointer_event->button()))) != 0 && |
| pointer_event->button() != 0); |
| |
| return CreatePointerEventFrom(pointer_event, |
| event_type_names::kPointerrawupdate, |
| pointer_event->relatedTarget()); |
| } |
| |
| PointerEvent* PointerEventFactory::CreatePointerCaptureEvent( |
| PointerEvent* pointer_event, |
| const AtomicString& type) { |
| DCHECK(type == event_type_names::kGotpointercapture || |
| type == event_type_names::kLostpointercapture); |
| |
| return CreatePointerEventFrom(pointer_event, type, |
| pointer_event->relatedTarget()); |
| } |
| |
| PointerEvent* PointerEventFactory::CreatePointerBoundaryEvent( |
| PointerEvent* pointer_event, |
| const AtomicString& type, |
| EventTarget* related_target) { |
| DCHECK(type == event_type_names::kPointerout || |
| type == event_type_names::kPointerleave || |
| type == event_type_names::kPointerover || |
| type == event_type_names::kPointerenter); |
| |
| return CreatePointerEventFrom(pointer_event, type, related_target); |
| } |
| |
| PointerEventFactory::PointerEventFactory() { |
| Clear(); |
| } |
| |
| PointerEventFactory::~PointerEventFactory() { |
| Clear(); |
| } |
| |
| void PointerEventFactory::Clear() { |
| for (int type = 0; |
| type <= ToInt(WebPointerProperties::PointerType::kMaxValue); type++) { |
| primary_id_[type] = kInvalidId; |
| id_count_[type] = 0; |
| } |
| 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 |pointer_incoming_id_mapping_| as it is not going to |
| // be used with the existing APIs |
| primary_id_[ToInt(WebPointerProperties::PointerType::kMouse)] = kMouseId; |
| pointer_id_mapping_.insert( |
| kMouseId, PointerAttributes( |
| IncomingId(WebPointerProperties::PointerType::kMouse, 0), |
| false, true)); |
| |
| current_id_ = PointerEventFactory::kMouseId + 1; |
| } |
| |
| PointerId PointerEventFactory::AddIdAndActiveButtons( |
| const IncomingId p, |
| bool is_active_buttons, |
| bool hovering, |
| WebInputEvent::Type event_type) { |
| // Do not add extra mouse pointer as it was added in initialization. |
| if (p.GetPointerType() == WebPointerProperties::PointerType::kMouse) { |
| pointer_id_mapping_.Set(kMouseId, |
| PointerAttributes(p, is_active_buttons, true)); |
| return kMouseId; |
| } |
| |
| if (pointer_incoming_id_mapping_.Contains(p)) { |
| PointerId mapped_id = pointer_incoming_id_mapping_.at(p); |
| pointer_id_mapping_.Set(mapped_id, |
| PointerAttributes(p, is_active_buttons, hovering)); |
| return mapped_id; |
| } |
| |
| // TODO(crbug.com/1141595): We should filter out bad pointercancel events |
| // further upstream. |
| if (event_type == WebInputEvent::Type::kPointerCancel) |
| return kInvalidId; |
| |
| int type_int = p.PointerTypeInt(); |
| // We do not handle the overflow of |current_id_| as it should be very rare. |
| PointerId mapped_id = current_id_++; |
| if (!id_count_[type_int]) |
| primary_id_[type_int] = mapped_id; |
| id_count_[type_int]++; |
| pointer_incoming_id_mapping_.insert(p, mapped_id); |
| pointer_id_mapping_.insert(mapped_id, |
| PointerAttributes(p, is_active_buttons, hovering)); |
| return mapped_id; |
| } |
| |
| bool PointerEventFactory::Remove(const PointerId mapped_id) { |
| // Do not remove mouse pointer id as it should always be there. |
| if (mapped_id == kMouseId || !pointer_id_mapping_.Contains(mapped_id)) |
| return false; |
| |
| IncomingId p = pointer_id_mapping_.at(mapped_id).incoming_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] = kInvalidId; |
| id_count_[type_int]--; |
| return true; |
| } |
| |
| Vector<PointerId> PointerEventFactory::GetPointerIdsOfNonHoveringPointers() |
| const { |
| Vector<PointerId> mapped_ids; |
| |
| for (auto iter = pointer_id_mapping_.begin(); |
| iter != pointer_id_mapping_.end(); ++iter) { |
| PointerId mapped_id = static_cast<PointerId>(iter->key); |
| if (!iter->value.hovering) |
| mapped_ids.push_back(mapped_id); |
| } |
| |
| // Sorting for a predictable ordering. |
| std::sort(mapped_ids.begin(), mapped_ids.end()); |
| return mapped_ids; |
| } |
| |
| bool PointerEventFactory::IsPrimary(PointerId mapped_id) const { |
| if (!pointer_id_mapping_.Contains(mapped_id)) |
| return false; |
| |
| IncomingId p = pointer_id_mapping_.at(mapped_id).incoming_id; |
| return primary_id_[p.PointerTypeInt()] == mapped_id; |
| } |
| |
| bool PointerEventFactory::IsActive(const PointerId pointer_id) const { |
| return pointer_id_mapping_.Contains(pointer_id); |
| } |
| |
| bool PointerEventFactory::IsPrimary( |
| const WebPointerProperties& properties) const { |
| // Mouse event is always primary. |
| if (properties.pointer_type == WebPointerProperties::PointerType::kMouse) |
| return true; |
| |
| // If !id_count, no pointer active, current WebPointerEvent will |
| // be primary pointer when added to map. |
| if (!id_count_[static_cast<int>(properties.pointer_type)]) |
| return true; |
| |
| PointerId pointer_id = GetPointerEventId(properties); |
| return (pointer_id != kInvalidId && IsPrimary(pointer_id)); |
| } |
| |
| bool PointerEventFactory::IsActiveButtonsState( |
| const PointerId pointer_id) const { |
| return pointer_id_mapping_.Contains(pointer_id) && |
| pointer_id_mapping_.at(pointer_id).is_active_buttons; |
| } |
| |
| WebPointerProperties::PointerType PointerEventFactory::GetPointerType( |
| PointerId pointer_id) const { |
| if (!IsActive(pointer_id)) |
| return WebPointerProperties::PointerType::kUnknown; |
| return pointer_id_mapping_.at(pointer_id).incoming_id.GetPointerType(); |
| } |
| |
| PointerId PointerEventFactory::GetPointerEventId( |
| const WebPointerProperties& properties) const { |
| if (properties.pointer_type == WebPointerProperties::PointerType::kMouse) |
| return PointerEventFactory::kMouseId; |
| IncomingId id(properties.pointer_type, properties.id); |
| if (pointer_incoming_id_mapping_.Contains(id)) |
| return pointer_incoming_id_mapping_.at(id); |
| return kInvalidId; |
| } |
| |
| } // namespace blink |