|  | // Copyright 2014 The Chromium Authors | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "content/browser/renderer_host/input/motion_event_web.h" | 
|  |  | 
|  | #include "base/check_op.h" | 
|  | #include "base/notreached.h" | 
|  | #include "base/numerics/math_constants.h" | 
|  | #include "content/common/input/web_touch_event_traits.h" | 
|  | #include "ui/events/blink/blink_event_util.h" | 
|  | #include "ui/gfx/geometry/angle_conversions.h" | 
|  |  | 
|  | using blink::WebInputEvent; | 
|  | using blink::WebPointerProperties; | 
|  | using blink::WebTouchEvent; | 
|  | using blink::WebTouchPoint; | 
|  |  | 
|  | namespace content { | 
|  | namespace { | 
|  |  | 
|  | ui::MotionEvent::Action GetActionFrom(const WebTouchEvent& event) { | 
|  | DCHECK(event.touches_length); | 
|  | switch (event.GetType()) { | 
|  | case WebInputEvent::Type::kTouchStart: | 
|  | if (WebTouchEventTraits::AllTouchPointsHaveState( | 
|  | event, WebTouchPoint::State::kStatePressed)) | 
|  | return ui::MotionEvent::Action::DOWN; | 
|  | else | 
|  | return ui::MotionEvent::Action::POINTER_DOWN; | 
|  | case WebInputEvent::Type::kTouchEnd: | 
|  | if (WebTouchEventTraits::AllTouchPointsHaveState( | 
|  | event, WebTouchPoint::State::kStateReleased)) | 
|  | return ui::MotionEvent::Action::UP; | 
|  | else | 
|  | return ui::MotionEvent::Action::POINTER_UP; | 
|  | case WebInputEvent::Type::kTouchCancel: | 
|  | DCHECK(WebTouchEventTraits::AllTouchPointsHaveState( | 
|  | event, WebTouchPoint::State::kStateCancelled)); | 
|  | return ui::MotionEvent::Action::CANCEL; | 
|  | case WebInputEvent::Type::kTouchMove: | 
|  | return ui::MotionEvent::Action::MOVE; | 
|  | default: | 
|  | break; | 
|  | }; | 
|  | NOTREACHED() | 
|  | << "Unable to derive a valid MotionEvent::Action from the WebTouchEvent."; | 
|  | return ui::MotionEvent::Action::CANCEL; | 
|  | } | 
|  |  | 
|  | int GetActionIndexFrom(const WebTouchEvent& event) { | 
|  | for (size_t i = 0; i < event.touches_length; ++i) { | 
|  | if (event.touches[i].state != WebTouchPoint::State::kStateUndefined && | 
|  | event.touches[i].state != WebTouchPoint::State::kStateStationary) | 
|  | return i; | 
|  | } | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | MotionEventWeb::MotionEventWeb(const WebTouchEvent& event) | 
|  | : event_(event), | 
|  | cached_action_(GetActionFrom(event)), | 
|  | cached_action_index_(GetActionIndexFrom(event)), | 
|  | unique_event_id_(event.unique_touch_event_id) { | 
|  | DCHECK_GT(GetPointerCount(), 0U); | 
|  | } | 
|  |  | 
|  | MotionEventWeb::~MotionEventWeb() {} | 
|  |  | 
|  | uint32_t MotionEventWeb::GetUniqueEventId() const { | 
|  | return unique_event_id_; | 
|  | } | 
|  |  | 
|  | MotionEventWeb::Action MotionEventWeb::GetAction() const { | 
|  | return cached_action_; | 
|  | } | 
|  |  | 
|  | int MotionEventWeb::GetActionIndex() const { | 
|  | DCHECK(cached_action_ == Action::POINTER_UP || | 
|  | cached_action_ == Action::POINTER_DOWN) | 
|  | << "Invalid action for GetActionIndex(): " << cached_action_; | 
|  | DCHECK_GE(cached_action_index_, 0); | 
|  | DCHECK_LT(cached_action_index_, static_cast<int>(event_.touches_length)); | 
|  | return cached_action_index_; | 
|  | } | 
|  |  | 
|  | size_t MotionEventWeb::GetPointerCount() const { | 
|  | return event_.touches_length; | 
|  | } | 
|  |  | 
|  | int MotionEventWeb::GetPointerId(size_t pointer_index) const { | 
|  | DCHECK_LT(pointer_index, GetPointerCount()); | 
|  | return event_.touches[pointer_index].id; | 
|  | } | 
|  |  | 
|  | float MotionEventWeb::GetX(size_t pointer_index) const { | 
|  | DCHECK_LT(pointer_index, GetPointerCount()); | 
|  | return event_.touches[pointer_index].PositionInWidget().x(); | 
|  | } | 
|  |  | 
|  | float MotionEventWeb::GetY(size_t pointer_index) const { | 
|  | DCHECK_LT(pointer_index, GetPointerCount()); | 
|  | return event_.touches[pointer_index].PositionInWidget().y(); | 
|  | } | 
|  |  | 
|  | float MotionEventWeb::GetRawX(size_t pointer_index) const { | 
|  | DCHECK_LT(pointer_index, GetPointerCount()); | 
|  | return event_.touches[pointer_index].PositionInScreen().x(); | 
|  | } | 
|  |  | 
|  | float MotionEventWeb::GetRawY(size_t pointer_index) const { | 
|  | DCHECK_LT(pointer_index, GetPointerCount()); | 
|  | return event_.touches[pointer_index].PositionInScreen().y(); | 
|  | } | 
|  |  | 
|  | float MotionEventWeb::GetTouchMajor(size_t pointer_index) const { | 
|  | DCHECK_LT(pointer_index, GetPointerCount()); | 
|  | return 2.f * std::max(event_.touches[pointer_index].radius_x, | 
|  | event_.touches[pointer_index].radius_y); | 
|  | } | 
|  |  | 
|  | float MotionEventWeb::GetTouchMinor(size_t pointer_index) const { | 
|  | DCHECK_LT(pointer_index, GetPointerCount()); | 
|  | return 2.f * std::min(event_.touches[pointer_index].radius_x, | 
|  | event_.touches[pointer_index].radius_y); | 
|  | } | 
|  |  | 
|  | float MotionEventWeb::GetOrientation(size_t pointer_index) const { | 
|  | DCHECK_LT(pointer_index, GetPointerCount()); | 
|  |  | 
|  | float orientation_rad = | 
|  | gfx::DegToRad(event_.touches[pointer_index].rotation_angle); | 
|  | DCHECK(0 <= orientation_rad && orientation_rad <= base::kPiFloat / 2) | 
|  | << "Unexpected touch rotation angle"; | 
|  |  | 
|  | if (GetToolType(pointer_index) == ToolType::STYLUS) { | 
|  | const WebPointerProperties& pointer = event_.touches[pointer_index]; | 
|  |  | 
|  | if (pointer.tilt_y <= 0 && pointer.tilt_x < 0) { | 
|  | // Stylus is tilted to the left away from the user or straight | 
|  | // to the left thus the orientation should be within [pi/2,pi). | 
|  | orientation_rad += base::kPiFloat / 2; | 
|  | } else if (pointer.tilt_y < 0 && pointer.tilt_x >= 0) { | 
|  | // Stylus is tilted to the right away from the user or straight away | 
|  | // from the user thus the orientation should be within [-pi,-pi/2). | 
|  | orientation_rad -= base::kPiFloat; | 
|  | } else if (pointer.tilt_y >= 0 && pointer.tilt_x > 0) { | 
|  | // Stylus is tilted to the right towards the user or straight | 
|  | // to the right thus the orientation should be within [-pi/2,0). | 
|  | orientation_rad -= base::kPiFloat / 2; | 
|  | } | 
|  | } else if (event_.touches[pointer_index].radius_x > | 
|  | event_.touches[pointer_index].radius_y) { | 
|  | // The case radiusX == radiusY is omitted from here on purpose: for circles, | 
|  | // we want to pass the angle (which could be any value in such cases but | 
|  | // always seems to be set to zero) unchanged. | 
|  | orientation_rad -= base::kPiFloat / 2; | 
|  | } | 
|  |  | 
|  | return orientation_rad; | 
|  | } | 
|  |  | 
|  | float MotionEventWeb::GetPressure(size_t pointer_index) const { | 
|  | return 0.f; | 
|  | } | 
|  |  | 
|  | float MotionEventWeb::GetTiltX(size_t pointer_index) const { | 
|  | DCHECK_LT(pointer_index, GetPointerCount()); | 
|  |  | 
|  | return event_.touches[pointer_index].tilt_x; | 
|  | } | 
|  |  | 
|  | float MotionEventWeb::GetTiltY(size_t pointer_index) const { | 
|  | DCHECK_LT(pointer_index, GetPointerCount()); | 
|  |  | 
|  | return event_.touches[pointer_index].tilt_y; | 
|  | } | 
|  |  | 
|  | float MotionEventWeb::GetTwist(size_t pointer_index) const { | 
|  | DCHECK_LT(pointer_index, GetPointerCount()); | 
|  |  | 
|  | return event_.touches[pointer_index].twist; | 
|  | } | 
|  |  | 
|  | float MotionEventWeb::GetTangentialPressure(size_t pointer_index) const { | 
|  | DCHECK_LT(pointer_index, GetPointerCount()); | 
|  |  | 
|  | return event_.touches[pointer_index].tangential_pressure; | 
|  | } | 
|  |  | 
|  | base::TimeTicks MotionEventWeb::GetEventTime() const { | 
|  | return event_.TimeStamp(); | 
|  | } | 
|  |  | 
|  | ui::MotionEvent::ToolType MotionEventWeb::GetToolType( | 
|  | size_t pointer_index) const { | 
|  | DCHECK_LT(pointer_index, GetPointerCount()); | 
|  |  | 
|  | const WebPointerProperties& pointer = event_.touches[pointer_index]; | 
|  |  | 
|  | switch (pointer.pointer_type) { | 
|  | case WebPointerProperties::PointerType::kUnknown: | 
|  | return ToolType::UNKNOWN; | 
|  | case WebPointerProperties::PointerType::kMouse: | 
|  | return ToolType::MOUSE; | 
|  | case WebPointerProperties::PointerType::kPen: | 
|  | return ToolType::STYLUS; | 
|  | case WebPointerProperties::PointerType::kEraser: | 
|  | return ToolType::ERASER; | 
|  | case WebPointerProperties::PointerType::kTouch: | 
|  | return ToolType::FINGER; | 
|  | } | 
|  | NOTREACHED() << "Unexpected pointerType"; | 
|  | return ToolType::UNKNOWN; | 
|  | } | 
|  |  | 
|  | int MotionEventWeb::GetButtonState() const { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int MotionEventWeb::GetFlags() const { | 
|  | return ui::WebEventModifiersToEventFlags(event_.GetModifiers()); | 
|  | } | 
|  |  | 
|  | }  // namespace content |