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

Unified Diff: chrome/browser/android/vr_shell/vr_shell_gl.cc

Issue 2878543002: Refactor VR Shell Input. Locks input to click/scroll targets. (Closed)
Patch Set: Address comments 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 | « chrome/browser/android/vr_shell/vr_shell_gl.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/android/vr_shell/vr_shell_gl.cc
diff --git a/chrome/browser/android/vr_shell/vr_shell_gl.cc b/chrome/browser/android/vr_shell/vr_shell_gl.cc
index 4b8914729602795bc1710a2731e8f178a00fe065..c980a0dccae84b2ceee81455f9d91c2b84daad2b 100644
--- a/chrome/browser/android/vr_shell/vr_shell_gl.cc
+++ b/chrome/browser/android/vr_shell/vr_shell_gl.cc
@@ -28,6 +28,7 @@
#include "device/vr/android/gvr/gvr_device.h"
#include "device/vr/android/gvr/gvr_gamepad_data_provider.h"
#include "device/vr/vr_math.h"
+#include "third_party/WebKit/public/platform/WebGestureEvent.h"
#include "third_party/WebKit/public/platform/WebInputEvent.h"
#include "third_party/WebKit/public/platform/WebMouseEvent.h"
#include "ui/gl/android/scoped_java_surface.h"
@@ -137,14 +138,14 @@ gvr::Mat4f PerspectiveMatrixFromView(const gvr::Rectf& fov,
return result;
}
-std::unique_ptr<blink::WebMouseEvent> MakeMouseEvent(WebInputEvent::Type type,
- double timestamp,
- float x,
- float y) {
+std::unique_ptr<blink::WebMouseEvent> MakeMouseEvent(
+ blink::WebInputEvent::Type type,
+ double timestamp,
+ const gfx::Point& loc) {
std::unique_ptr<blink::WebMouseEvent> mouse_event(new blink::WebMouseEvent(
type, blink::WebInputEvent::kNoModifiers, timestamp));
mouse_event->pointer_type = blink::WebPointerProperties::PointerType::kMouse;
- mouse_event->SetPositionInWidget(x, y);
+ mouse_event->SetPositionInWidget(loc.x(), loc.y());
mouse_event->click_count = 1;
return mouse_event;
@@ -183,6 +184,10 @@ gfx::RectF GfxRectFromUV(gvr::Rectf rect) {
rect.top - rect.bottom);
}
+double NowSeconds() {
+ return (base::TimeTicks::Now() - base::TimeTicks()).InSecondsF();
+}
+
} // namespace
VrShellGl::VrShellGl(VrBrowserInterface* browser,
@@ -504,23 +509,7 @@ void VrShellGl::UpdateController(const gfx::Vector3dF& head_direction) {
}
void VrShellGl::HandleControllerInput(const gfx::Vector3dF& head_direction) {
- if (ShouldDrawWebVr()) {
- // Process screen touch events for Cardboard button compatibility.
- // Also send tap events for controller "touchpad click" events.
- if (touch_pending_ ||
- controller_->ButtonUpHappened(
- gvr::ControllerButton::GVR_CONTROLLER_BUTTON_CLICK)) {
- touch_pending_ = false;
- std::unique_ptr<WebGestureEvent> gesture(new WebGestureEvent(
- WebInputEvent::kGestureTapDown, WebInputEvent::kNoModifiers,
- (base::TimeTicks::Now() - base::TimeTicks()).InSecondsF()));
- gesture->source_device = blink::kWebGestureDeviceTouchpad;
- gesture->x = 0;
- gesture->y = 0;
- SendGestureToContent(std::move(gesture));
- DVLOG(1) << __FUNCTION__ << ": sent CLICK gesture";
- }
- }
+ HandleWebVrCompatibilityClick();
gfx::Vector3dF ergo_neutral_pose;
if (!controller_->IsConnected()) {
@@ -540,10 +529,254 @@ void VrShellGl::HandleControllerInput(const gfx::Vector3dF& head_direction) {
HandleControllerAppButtonActivity(controller_direction);
- if (ShouldDrawWebVr()) {
+ if (ShouldDrawWebVr())
+ return;
+ gfx::PointF target_local_point;
+ gfx::Vector3dF eye_to_target;
+ cursor_render_target_ = nullptr;
+ GetVisualTargetElement(controller_direction, eye_to_target, target_point_,
+ &cursor_render_target_, target_local_point);
+
+ UiElement* target_element = nullptr;
+ if (input_locked_element_) {
+ gfx::Point3F plane_intersection_point;
+ float distance_to_plane;
+ GetTargetLocalPoint(eye_to_target, *input_locked_element_,
+ 2 * scene_->GetBackgroundDistance(), target_local_point,
+ plane_intersection_point, distance_to_plane);
+ target_element = input_locked_element_;
+ } else if (!in_scroll_ && !in_click_) {
+ target_element = cursor_render_target_;
+ }
+
+ // Handle input targeting on the content quad, ignoring any other elements.
+ // Content is treated specially to accomodate scrolling, flings, etc.
+ gfx::Point local_point_pixels;
+ if (target_element && (target_element->fill() == Fill::CONTENT)) {
+ gfx::RectF pixel_rect(0, 0, content_tex_css_width_,
+ content_tex_css_height_);
+ local_point_pixels.set_x(pixel_rect.x() +
+ pixel_rect.width() * target_local_point.x());
+ local_point_pixels.set_y(pixel_rect.y() +
+ pixel_rect.height() * target_local_point.y());
+ }
+ std::unique_ptr<GestureList> gesture_list_ptr = controller_->DetectGestures();
+ GestureList& gesture_list = *gesture_list_ptr;
+ for (const std::unique_ptr<blink::WebGestureEvent>& gesture : gesture_list) {
+ gesture->x = local_point_pixels.x();
+ gesture->y = local_point_pixels.y();
+ }
+ SendFlingCancel(gesture_list);
+ // For simplicity, don't allow scrolling while clicking until we need to.
+ if (!in_click_) {
+ SendScrollEnd(gesture_list);
+ if (!SendScrollBegin(target_element, gesture_list)) {
+ SendScrollUpdate(gesture_list);
+ }
+ }
+ // If we're still scrolling, don't hover (and we can't be clicking, because
+ // click ends scroll).
+ if (in_scroll_)
+ return;
+ SendHoverLeave(target_element);
+ if (!SendHoverEnter(target_element, target_local_point, local_point_pixels)) {
+ SendHoverMove(target_local_point, local_point_pixels);
+ }
+ SendButtonDown(target_element, target_local_point);
+ if (!SendButtonUp(target_element, target_local_point))
+ SendTap(target_element, target_local_point, local_point_pixels);
+}
+
+void VrShellGl::HandleWebVrCompatibilityClick() {
+ if (!ShouldDrawWebVr())
return;
+
+ // Process screen touch events for Cardboard button compatibility.
+ // Also send tap events for controller "touchpad click" events.
+ if (touch_pending_ ||
+ controller_->ButtonUpHappened(gvr::kControllerButtonClick)) {
+ touch_pending_ = false;
+ std::unique_ptr<blink::WebGestureEvent> gesture(new blink::WebGestureEvent(
+ blink::WebInputEvent::kGestureTapDown,
+ blink::WebInputEvent::kNoModifiers, NowSeconds()));
+ gesture->source_device = blink::kWebGestureDeviceTouchpad;
+ gesture->x = 0;
+ gesture->y = 0;
+ SendGestureToContent(std::move(gesture));
+ DVLOG(1) << __FUNCTION__ << ": sent CLICK gesture";
}
+}
+
+void VrShellGl::SendFlingCancel(GestureList& gesture_list) {
+ if (!fling_target_)
+ return;
+ if (gesture_list.empty() || (gesture_list.front()->GetType() !=
+ blink::WebInputEvent::kGestureFlingCancel))
+ return;
+ // Scrolling currently only supported on content window.
+ DCHECK_EQ(fling_target_->fill(), Fill::CONTENT);
+ SendGestureToContent(std::move(gesture_list.front()));
+ gesture_list.erase(gesture_list.begin());
+}
+
+void VrShellGl::SendScrollEnd(GestureList& gesture_list) {
+ if (!in_scroll_)
+ return;
+ DCHECK_NE(input_locked_element_, nullptr);
+ if (controller_->ButtonDownHappened(gvr::kControllerButtonClick)) {
+ DCHECK_GT(gesture_list.size(), 0LU);
+ DCHECK_EQ(gesture_list.front()->GetType(),
+ blink::WebInputEvent::kGestureScrollEnd);
+ }
+ // Scrolling currently only supported on content window.
+ DCHECK_EQ(input_locked_element_->fill(), Fill::CONTENT);
+ if (gesture_list.empty() || (gesture_list.front()->GetType() !=
+ blink::WebInputEvent::kGestureScrollEnd))
+ return;
+ DCHECK_LE(gesture_list.size(), 2LU);
+ SendGestureToContent(std::move(gesture_list.front()));
+ gesture_list.erase(gesture_list.begin());
+ if (!gesture_list.empty()) {
+ DCHECK_EQ(gesture_list.front()->GetType(),
+ blink::WebInputEvent::kGestureFlingStart);
+ SendGestureToContent(std::move(gesture_list.front()));
+ fling_target_ = input_locked_element_;
+ gesture_list.erase(gesture_list.begin());
+ }
+ input_locked_element_ = nullptr;
+ in_scroll_ = false;
+}
+
+bool VrShellGl::SendScrollBegin(UiElement* target, GestureList& gesture_list) {
+ if (in_scroll_ || !target)
+ return false;
+ // Scrolling currently only supported on content window.
+ if (target->fill() != Fill::CONTENT)
+ return false;
+ if (gesture_list.empty() || (gesture_list.front()->GetType() !=
+ blink::WebInputEvent::kGestureScrollBegin))
+ return false;
+ input_locked_element_ = target;
+ in_scroll_ = true;
+
+ SendGestureToContent(std::move(gesture_list.front()));
+ gesture_list.erase(gesture_list.begin());
+ return true;
+}
+
+void VrShellGl::SendScrollUpdate(GestureList& gesture_list) {
+ if (!in_scroll_)
+ return;
+ DCHECK(input_locked_element_);
+ if (gesture_list.empty() || (gesture_list.front()->GetType() !=
+ blink::WebInputEvent::kGestureScrollUpdate))
+ return;
+ // Scrolling currently only supported on content window.
+ DCHECK_EQ(input_locked_element_->fill(), Fill::CONTENT);
+ SendGestureToContent(std::move(gesture_list.front()));
+ gesture_list.erase(gesture_list.begin());
+}
+
+void VrShellGl::SendHoverLeave(UiElement* target) {
+ if (!hover_target_ || (target == hover_target_))
+ return;
+ if (hover_target_->fill() == Fill::CONTENT) {
+ SendGestureToContent(MakeMouseEvent(blink::WebInputEvent::kMouseLeave,
+ NowSeconds(), gfx::Point()));
+ } else {
+ hover_target_->OnHoverLeave();
+ }
+ hover_target_ = nullptr;
+}
+
+bool VrShellGl::SendHoverEnter(UiElement* target,
+ const gfx::PointF& target_point,
+ const gfx::Point& local_point_pixels) {
+ if (!target || target == hover_target_)
+ return false;
+ if (target->fill() == Fill::CONTENT) {
+ SendGestureToContent(MakeMouseEvent(blink::WebInputEvent::kMouseEnter,
+ NowSeconds(), local_point_pixels));
+ } else {
+ target->OnHoverEnter(target_point);
+ }
+ hover_target_ = target;
+ return true;
+}
+
+void VrShellGl::SendHoverMove(const gfx::PointF& target_point,
+ const gfx::Point& local_point_pixels) {
+ if (!hover_target_)
+ return;
+ if (hover_target_->fill() == Fill::CONTENT) {
+ SendGestureToContent(MakeMouseEvent(blink::WebInputEvent::kMouseMove,
+ NowSeconds(), local_point_pixels));
+ } else {
+ hover_target_->OnMove(target_point);
+ }
+}
+void VrShellGl::SendButtonDown(UiElement* target,
+ const gfx::PointF& target_point) {
+ if (in_click_)
+ return;
+ if (!controller_->ButtonDownHappened(gvr::kControllerButtonClick))
+ return;
+ input_locked_element_ = target;
+ in_click_ = true;
+ // We don't support down/up for content yet.
+ if (!target || target->fill() == Fill::CONTENT)
+ return;
+ target->OnButtonDown(target_point);
+}
+
+bool VrShellGl::SendButtonUp(UiElement* target,
+ const gfx::PointF& target_point) {
+ if (!in_click_)
+ return false;
+ if (!controller_->ButtonUpHappened(gvr::kControllerButtonClick))
+ return false;
+ DCHECK(input_locked_element_ == target);
+ input_locked_element_ = nullptr;
+ in_click_ = false;
+ // We don't support down/up for content yet.
+ if (target->fill() == Fill::CONTENT)
+ return false;
+ target->OnButtonUp(target_point);
+ return true;
+}
+
+void VrShellGl::SendTap(UiElement* target,
+ const gfx::PointF& target_point,
+ const gfx::Point& local_point_pixels) {
+ if (!target)
+ return;
+ if (controller_->ButtonUpHappened(gvr::kControllerButtonClick) &&
+ target->fill() == Fill::CONTENT)
+ touch_pending_ = true;
+ if (!touch_pending_)
+ return;
+ touch_pending_ = false;
+ if (target->fill() == Fill::CONTENT) {
+ auto gesture = base::MakeUnique<blink::WebGestureEvent>(
+ blink::WebInputEvent::kGestureTapDown,
+ blink::WebInputEvent::kNoModifiers, NowSeconds());
+ gesture->source_device = blink::kWebGestureDeviceTouchpad;
+ gesture->x = local_point_pixels.x();
+ gesture->y = local_point_pixels.y();
+ SendGestureToContent(std::move(gesture));
+ } else {
+ target->OnButtonDown(target_point);
+ target->OnButtonUp(target_point);
+ }
+}
+
+void VrShellGl::GetVisualTargetElement(
+ const gfx::Vector3dF& controller_direction,
+ gfx::Vector3dF& eye_to_target,
+ gfx::Point3F& target_point,
+ UiElement** target_element,
+ gfx::PointF& target_local_point) const {
// If we place the reticle based on elements intersecting the controller beam,
// we can end up with the reticle hiding behind elements, or jumping laterally
// in the field of view. This is physically correct, but hard to use. For
@@ -559,63 +792,55 @@ void VrShellGl::HandleControllerInput(const gfx::Vector3dF& head_direction) {
// that the sphere is centered at the controller, rather than the eye, for
// simplicity.
float distance = scene_->GetBackgroundDistance();
- target_point_ =
+ target_point =
vr::GetRayPoint(pointer_start_, controller_direction, distance);
- gfx::Vector3dF eye_to_target = target_point_ - kOrigin;
+ eye_to_target = target_point - kOrigin;
vr::NormalizeVector(&eye_to_target);
// Determine which UI element (if any) intersects the line between the eyes
// and the controller target position.
- float closest_element_distance = (target_point_ - kOrigin).Length();
- previous_target_element_ = target_element_;
- target_element_ = nullptr;
- float target_x;
- float target_y;
-
- for (auto& plane : scene_->GetUiElements()) {
- if (!plane->IsHitTestable())
- continue;
+ float closest_element_distance = (target_point - kOrigin).Length();
- float distance_to_plane;
- if (!plane->GetRayDistance(kOrigin, eye_to_target, &distance_to_plane))
+ for (auto& element : scene_->GetUiElements()) {
+ if (!element->IsHitTestable())
continue;
-
- if (distance_to_plane < 0 || distance_to_plane >= closest_element_distance)
+ gfx::PointF local_point;
+ gfx::Point3F plane_intersection_point;
+ float distance_to_plane;
+ if (!GetTargetLocalPoint(eye_to_target, *element.get(),
+ closest_element_distance, local_point,
+ plane_intersection_point, distance_to_plane))
continue;
- gfx::Point3F plane_intersection_point =
- vr::GetRayPoint(kOrigin, eye_to_target, distance_to_plane);
- gfx::PointF unit_xy_point =
- plane->GetUnitRectangleCoordinates(plane_intersection_point);
-
- float x = 0.5f + unit_xy_point.x();
- float y = 0.5f - unit_xy_point.y();
- if (x < 0.0f || x >= 1.0f || y < 0.0f || y >= 1.0f)
+ if (local_point.x() < 0.0f || local_point.x() >= 1.0f ||
+ local_point.y() < 0.0f || local_point.y() >= 1.0f)
continue;
closest_element_distance = distance_to_plane;
- target_point_ = plane_intersection_point;
- target_element_ = plane.get();
- target_x = x;
- target_y = y;
+ target_point = plane_intersection_point;
+ *target_element = element.get();
+ target_local_point = local_point;
}
+}
- // Handle input targeting on the content quad, ignoring any other elements.
- // Content is treated specially to accomodate scrolling, flings, etc.
- InputTarget input_target = InputTarget::NONE;
- int pixel_x = 0;
- int pixel_y = 0;
- if (target_element_ != nullptr && target_element_->fill() == Fill::CONTENT) {
- input_target = InputTarget::CONTENT;
- gfx::RectF pixel_rect(0, 0, content_tex_css_width_,
- content_tex_css_height_);
- pixel_x = pixel_rect.x() + pixel_rect.width() * target_x;
- pixel_y = pixel_rect.y() + pixel_rect.height() * target_y;
- }
- SendInputToContent(input_target, pixel_x, pixel_y);
+bool VrShellGl::GetTargetLocalPoint(const gfx::Vector3dF& eye_to_target,
+ const UiElement& element,
+ float max_distance_to_plane,
+ gfx::PointF& target_local_point,
+ gfx::Point3F& target_point,
+ float& distance_to_plane) const {
+ if (!element.GetRayDistance(kOrigin, eye_to_target, &distance_to_plane))
+ return false;
- // Handle input targeting on all non-content elements.
- SendInputToUiElements(target_element_);
+ if (distance_to_plane < 0 || distance_to_plane >= max_distance_to_plane)
+ return false;
+
+ target_point = vr::GetRayPoint(kOrigin, eye_to_target, distance_to_plane);
+ gfx::PointF unit_xy_point = element.GetUnitRectangleCoordinates(target_point);
+
+ target_local_point.set_x(0.5f + unit_xy_point.x());
+ target_local_point.set_y(0.5f - unit_xy_point.y());
+ return true;
}
void VrShellGl::HandleControllerAppButtonActivity(
@@ -648,125 +873,6 @@ void VrShellGl::HandleControllerAppButtonActivity(
}
}
-void VrShellGl::SendInputToContent(InputTarget input_target,
- int pixel_x,
- int pixel_y) {
- std::vector<std::unique_ptr<WebGestureEvent>> gesture_list =
- controller_->DetectGestures();
- double timestamp = gesture_list.front()->TimeStampSeconds();
-
- if (touch_pending_) {
- touch_pending_ = false;
- std::unique_ptr<WebGestureEvent> event(
- new WebGestureEvent(WebInputEvent::kGestureTapDown,
- WebInputEvent::kNoModifiers, timestamp));
- event->source_device = blink::kWebGestureDeviceTouchpad;
- event->x = pixel_x;
- event->y = pixel_y;
- gesture_list.push_back(std::move(event));
- }
-
- for (auto& gesture : gesture_list) {
- gesture->x = pixel_x;
- gesture->y = pixel_y;
- auto movableGesture = base::MakeUnique<WebGestureEvent>(*gesture);
-
- switch (gesture->GetType()) {
- // Once the user starts scrolling send all the scroll events to this
- // element until the scrolling stops.
- case WebInputEvent::kGestureScrollBegin:
- current_scroll_target_ = input_target;
- if (current_scroll_target_ != InputTarget::NONE) {
- SendGestureToContent(std::move(movableGesture));
- }
- break;
- case WebInputEvent::kGestureScrollEnd:
- if (current_scroll_target_ != InputTarget::NONE) {
- SendGestureToContent(std::move(movableGesture));
- }
- current_fling_target_ = current_scroll_target_;
- current_scroll_target_ = InputTarget::NONE;
- break;
- case WebInputEvent::kGestureScrollUpdate:
- if (current_scroll_target_ != InputTarget::NONE) {
- SendGestureToContent(std::move(movableGesture));
- }
- break;
- case WebInputEvent::kGestureFlingStart:
- if (current_fling_target_ != InputTarget::NONE) {
- SendGestureToContent(std::move(movableGesture));
- }
- current_fling_target_ = InputTarget::NONE;
- break;
- case WebInputEvent::kGestureFlingCancel:
- current_fling_target_ = InputTarget::NONE;
- if (input_target != InputTarget::NONE) {
- SendGestureToContent(std::move(movableGesture));
- }
- break;
- case WebInputEvent::kGestureTapDown:
- current_fling_target_ = InputTarget::NONE;
- if (input_target != InputTarget::NONE) {
- SendGestureToContent(std::move(movableGesture));
- }
- break;
- case WebInputEvent::kUndefined:
- break;
- default:
- NOTREACHED();
- }
- }
-
- // Hover support
- bool new_target = input_target != current_input_target_;
- if (new_target && current_input_target_ != InputTarget::NONE) {
- // Send a move event indicating that the pointer moved off of an element.
- SendGestureToContent(
- MakeMouseEvent(WebInputEvent::kMouseLeave, timestamp, 0, 0));
- }
- current_input_target_ = input_target;
- if (current_input_target_ != InputTarget::NONE) {
- WebInputEvent::Type type =
- new_target ? WebInputEvent::kMouseEnter : WebInputEvent::kMouseMove;
- SendGestureToContent(MakeMouseEvent(type, timestamp, pixel_x, pixel_y));
- }
-}
-
-void VrShellGl::SendInputToUiElements(UiElement* target_element) {
- if (target_element != previous_target_element_) {
- if (previous_target_element_ &&
- previous_target_element_->fill() != Fill::CONTENT) {
- task_runner_->PostTask(
- FROM_HERE, base::Bind(&UiElement::OnHoverLeave,
- base::Unretained(previous_target_element_)));
- }
- if (target_element && target_element->fill() != Fill::CONTENT) {
- task_runner_->PostTask(FROM_HERE,
- base::Bind(&UiElement::OnHoverEnter,
- base::Unretained(target_element)));
- }
- click_target_element_ = nullptr;
- }
- if (target_element && target_element->fill() != Fill::CONTENT) {
- if (controller_->ButtonDownHappened(
- gvr::ControllerButton::GVR_CONTROLLER_BUTTON_CLICK)) {
- task_runner_->PostTask(FROM_HERE,
- base::Bind(&UiElement::OnButtonDown,
- base::Unretained(target_element)));
- click_target_element_ = target_element;
- }
- if (controller_->ButtonUpHappened(
- gvr::ControllerButton::GVR_CONTROLLER_BUTTON_CLICK)) {
- if (click_target_element_ == target_element) {
- task_runner_->PostTask(FROM_HERE,
- base::Bind(&UiElement::OnButtonUp,
- base::Unretained(target_element)));
- }
- click_target_element_ = nullptr;
- }
- }
-}
-
void VrShellGl::SendGestureToContent(
std::unique_ptr<blink::WebInputEvent> event) {
browser_->ProcessContentGesture(std::move(event));
@@ -1077,9 +1183,9 @@ void VrShellGl::DrawCursor(const vr::Mat4f& render_matrix) {
&mat);
vr::Quatf rotation;
- if (target_element_ != nullptr) {
+ if (cursor_render_target_ != nullptr) {
// Make the reticle planar to the element it's hitting.
- rotation = GetRotationFromZAxis(target_element_->GetNormal());
+ rotation = GetRotationFromZAxis(cursor_render_target_->GetNormal());
} else {
// Rotate the cursor to directly face the eyes.
rotation = GetRotationFromZAxis(target_point_ - kOrigin);
« no previous file with comments | « chrome/browser/android/vr_shell/vr_shell_gl.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698