Commit 77904f25 authored by Ian Vollick's avatar Ian Vollick Committed by Commit Bot

[vr] Support content resizing

With this change, a user may both resize and reposition the content
quad when in "repositioning" mode.

Bug: 799270
Cq-Include-Trybots: master.tryserver.chromium.android:android_optional_gpu_tests_rel;master.tryserver.chromium.linux:linux_optional_gpu_tests_rel;master.tryserver.chromium.linux:linux_vr;master.tryserver.chromium.mac:mac_optional_gpu_tests_rel;master.tryserver.chromium.win:win_optional_gpu_tests_rel
Change-Id: I86aed8d83db82998c64e982922e21298c6a243ec
Reviewed-on: https://chromium-review.googlesource.com/956499
Commit-Queue: Ian Vollick <vollick@chromium.org>
Reviewed-by: default avatarChristopher Grant <cjgrant@chromium.org>
Reviewed-by: default avatarBiao She <bshe@chromium.org>
Cr-Commit-Position: refs/heads/master@{#542224}
parent 78a058bc
......@@ -82,6 +82,8 @@ static_library("vr_common") {
"elements/render_text_wrapper.h",
"elements/repositioner.cc",
"elements/repositioner.h",
"elements/resizer.cc",
"elements/resizer.h",
"elements/reticle.cc",
"elements/reticle.h",
"elements/scaled_depth_adjuster.cc",
......@@ -258,6 +260,7 @@ test("vr_common_unittests") {
"elements/omnibox_text_field_unittest.cc",
"elements/rect_unittest.cc",
"elements/repositioner_unittest.cc",
"elements/resizer_unittest.cc",
"elements/scaled_depth_adjuster_unittest.cc",
"elements/shadow_unittest.cc",
"elements/spinner_unittest.cc",
......
......@@ -9,7 +9,6 @@
#include "base/macros.h"
#include "chrome/browser/vr/elements/ui_element.h"
#include "chrome/browser/vr/model/reticle_model.h"
#include "ui/gfx/transform.h"
namespace vr {
......
// Copyright 2018 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 "chrome/browser/vr/elements/resizer.h"
#include "base/numerics/math_constants.h"
#include "base/numerics/ranges.h"
#include "chrome/browser/vr/pose_util.h"
#include "chrome/browser/vr/ui_scene_constants.h"
#include "ui/gfx/animation/tween.h"
#include "ui/gfx/geometry/angle_conversions.h"
#include "ui/gfx/geometry/quaternion.h"
namespace vr {
namespace {
// Fraction here is in reference to "time fraction" terminology in web
// animations.
constexpr float kDefaultFraction = 0.5f;
static_assert(0.5f * (kMinResizerScale + kMaxResizerScale) == 1.0f,
"1.0 must be the midpoint of the min and max scale");
} // namespace
Resizer::Resizer() : t_(kDefaultFraction), initial_t_(kDefaultFraction) {
set_bounds_contain_children(true);
}
Resizer::~Resizer() = default;
gfx::Transform Resizer::LocalTransform() const {
return transform_;
}
gfx::Transform Resizer::GetTargetLocalTransform() const {
return transform_;
}
void Resizer::SetTouchingTouchpad(bool touching) {
if (enabled_ && touching) {
initial_t_ = t_;
initial_touchpad_position_ = touchpad_position_;
}
}
void Resizer::SetEnabled(bool enabled) {
enabled_ = enabled;
if (enabled) {
initial_t_ = t_;
initial_touchpad_position_ = touchpad_position_;
}
}
void Resizer::Reset() {
transform_.MakeIdentity();
t_ = initial_t_ = kDefaultFraction;
}
void Resizer::UpdateTransform(const gfx::Transform& head_pose) {
float delta = touchpad_position_.y() - initial_touchpad_position_.y();
t_ = base::ClampToRange(initial_t_ - delta, 0.0f, 1.0f);
float scale =
gfx::Tween::FloatValueBetween(t_, kMinResizerScale, kMaxResizerScale);
transform_.MakeIdentity();
transform_.Scale(scale, scale);
}
bool Resizer::OnBeginFrame(const base::TimeTicks& time,
const gfx::Transform& head_pose) {
if (enabled_) {
UpdateTransform(head_pose);
return true;
}
return false;
}
} // namespace vr
// Copyright 2018 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.
#ifndef CHROME_BROWSER_VR_ELEMENTS_RESIZER_H_
#define CHROME_BROWSER_VR_ELEMENTS_RESIZER_H_
#include <sstream>
#include "base/macros.h"
#include "chrome/browser/vr/elements/ui_element.h"
#include "ui/gfx/transform.h"
namespace vr {
// When enabled, a resizer scales its descendant elements in response to
// trackpad use.
class Resizer : public UiElement {
public:
Resizer();
~Resizer() override;
void set_touch_position(const gfx::PointF& position) {
touchpad_position_ = position;
}
void SetTouchingTouchpad(bool touching);
void SetEnabled(bool enabled);
void Reset();
private:
gfx::Transform LocalTransform() const override;
gfx::Transform GetTargetLocalTransform() const override;
void UpdateTransform(const gfx::Transform& head_pose);
bool OnBeginFrame(const base::TimeTicks& time,
const gfx::Transform& head_pose) override;
bool enabled_ = false;
// Initialized via constants.
float t_;
float initial_t_;
gfx::Transform transform_;
gfx::PointF touchpad_position_;
gfx::PointF initial_touchpad_position_;
DISALLOW_COPY_AND_ASSIGN(Resizer);
};
} // namespace vr
#endif // CHROME_BROWSER_VR_ELEMENTS_RESIZER_H_
// Copyright 2018 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 "chrome/browser/vr/elements/resizer.h"
#include <memory>
#include "base/strings/stringprintf.h"
#include "cc/test/geometry_test_utils.h"
#include "chrome/browser/vr/test/animation_utils.h"
#include "chrome/browser/vr/test/constants.h"
#include "chrome/browser/vr/ui_scene.h"
#include "chrome/browser/vr/ui_scene_constants.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/transform.h"
namespace vr {
namespace {
class ResizerTest : public testing::Test {
public:
ResizerTest() {}
~ResizerTest() override {}
void SetUp() override {
auto resizer = std::make_unique<Resizer>();
resizer->set_touch_position({0.5f, 0.5f});
resizer->SetEnabled(true);
resizer_ = resizer.get();
scene_.AddUiElement(kRoot, std::move(resizer));
}
void Move(const gfx::PointF& from, const gfx::PointF& to) {
resizer_->set_touch_position(from);
resizer_->SetTouchingTouchpad(true);
scene_.OnBeginFrame(MsToTicks(1), gfx::Transform());
resizer_->set_touch_position(to);
scene_.OnBeginFrame(MsToTicks(1), gfx::Transform());
resizer_->SetTouchingTouchpad(false);
}
float ComputeScale() {
gfx::Vector3dF v = {1.0f, 0.0f, 0.0f};
static_cast<UiElement*>(resizer_)->LocalTransform().TransformVector(&v);
return v.x();
}
void CheckScale(float scale) { EXPECT_FLOAT_EQ(scale, ComputeScale()); }
protected:
Resizer* resizer_ = nullptr;
UiScene scene_;
};
} // namespace
TEST_F(ResizerTest, HorizontalMove) {
Move({0.5f, 0.5f}, {1.0f, 0.5f});
CheckScale(1.0f);
}
TEST_F(ResizerTest, UpwardMove) {
Move({0.5f, 0.5f}, {0.5f, 1.0f});
CheckScale(kMinResizerScale);
}
TEST_F(ResizerTest, DownwardMove) {
Move({0.5f, 0.5f}, {0.5f, 0.0f});
CheckScale(kMaxResizerScale);
}
TEST_F(ResizerTest, AccumulatedMove) {
Move({0.5f, 0.5f}, {0.5f, 0.25f});
float scale = ComputeScale();
EXPECT_LT(1.0f, scale);
EXPECT_GT(kMaxResizerScale, scale);
Move({0.5f, 0.5f}, {0.5f, 0.25f});
CheckScale(kMaxResizerScale);
}
} // namespace vr
......@@ -149,6 +149,12 @@ void Shadow::LayOutChildren() {
set_corner_radius(children().front()->corner_radii().MaxRadius());
}
gfx::SizeF Shadow::ContributedSize() const {
gfx::RectF bounds(size());
bounds.Inset(x_padding(), y_padding());
return bounds.size();
}
Shadow::Renderer::Renderer()
: BaseQuadRenderer(kVertexShader, kFragmentShader) {
model_view_proj_matrix_handle_ =
......
......@@ -25,6 +25,8 @@ class Shadow : public UiElement {
void LayOutChildren() override;
void set_intensity(float intensity) { intensity_ = intensity; }
gfx::SizeF ContributedSize() const override;
class Renderer : public BaseQuadRenderer {
public:
Renderer();
......@@ -55,6 +57,7 @@ class Shadow : public UiElement {
private:
float depth_;
float intensity_ = 1.0f;
gfx::SizeF contributed_size_;
DISALLOW_COPY_AND_ASSIGN(Shadow);
};
......
......@@ -248,6 +248,10 @@ void UiElement::SetSize(float width, float height) {
void UiElement::OnSetSize(const gfx::SizeF& size) {}
gfx::SizeF UiElement::ContributedSize() const {
return size();
}
void UiElement::SetVisible(bool visible) {
SetOpacity(visible ? opacity_when_visible_ : 0.0);
}
......@@ -665,13 +669,13 @@ void UiElement::DoLayOutChildren() {
gfx::RectF bounds;
for (auto& child : children_) {
if (!child->IsVisible() || child->size().IsEmpty() ||
gfx::SizeF size = child->ContributedSize();
if (!child->IsVisible() || size.IsEmpty() ||
!child->contributes_to_parent_bounds()) {
continue;
}
gfx::Point3F child_center(child->local_origin());
gfx::Vector3dF corner_offset(child->size().width(), child->size().height(),
0);
gfx::Vector3dF corner_offset(size.width(), size.height(), 0);
corner_offset.Scale(-0.5);
gfx::Point3F child_upper_left = child_center + corner_offset;
gfx::Point3F child_lower_right = child_center - corner_offset;
......
......@@ -223,6 +223,12 @@ class UiElement : public cc::AnimationTarget {
void SetSize(float width, float hight);
virtual void OnSetSize(const gfx::SizeF& size);
// Elements may report a different size to parents that resize to contain
// their children. Eg, for shadows.
// TODO(crbug.com/820507): change this to LayoutSize and update all layout
// code to make use of this instead of size().
virtual gfx::SizeF ContributedSize() const;
gfx::PointF local_origin() const { return local_origin_; }
// These are convenience functions for setting the transform operations. They
......
......@@ -24,6 +24,7 @@ static const char* g_ui_element_name_strings[] = {
"k2dBrowsingViewportAwareRoot",
"kWebVrRoot",
"kWebVrViewportAwareRoot",
"kContentResizer",
"kContentQuad",
"kContentQuadShadow",
"kContentQuadRepositionButton",
......@@ -41,6 +42,7 @@ static const char* g_ui_element_name_strings[] = {
"kFloor",
"kStars",
"kUpdateKeyboardPrompt",
"kUrlBarPositioner",
"kUrlBarDmmRoot",
"kUrlBar",
"kUrlBarLayout",
......
......@@ -23,6 +23,7 @@ enum UiElementName {
k2dBrowsingViewportAwareRoot,
kWebVrRoot,
kWebVrViewportAwareRoot,
kContentResizer,
kContentQuad,
kContentQuadShadow,
kContentQuadRepositionButton,
......@@ -40,6 +41,7 @@ enum UiElementName {
kFloor,
kStars,
kUpdateKeyboardPrompt,
kUrlBarPositioner,
kUrlBarDmmRoot,
kUrlBar,
kUrlBarLayout,
......
......@@ -57,6 +57,8 @@ constexpr float kPageLoadTimeMilliseconds = 500;
constexpr gfx::Point3F kDefaultLaserOrigin = {0.5f, -0.5f, 0.f};
constexpr gfx::Vector3dF kLaserLocalOffset = {0.f, -0.0075f, -0.05f};
constexpr float kControllerScaleFactor = 1.5f;
constexpr float kTouchpadPositionDelta = 0.05f;
constexpr gfx::PointF kInitialTouchPosition = {0.5f, 0.5f};
void RotateToward(const gfx::Vector3dF& fwd, gfx::Transform* transform) {
gfx::Quaternion quat(kForwardVector, fwd);
......@@ -102,6 +104,8 @@ VrTestContext::VrTestContext() : view_scale_factor_(kDefaultViewScaleFactor) {
base::Unretained(keyboard_delegate_.get())));
keyboard_delegate_->SetUiInterface(ui_.get());
touchpad_touch_position_ = kInitialTouchPosition;
model_ = ui_->model_for_test();
CycleOrigin();
......@@ -201,6 +205,9 @@ void VrTestContext::HandleInput(ui::Event* event) {
case ui::DomCode::US_X:
ui_->OnAppButtonClicked();
break;
case ui::DomCode::US_T:
touching_touchpad_ = !touching_touchpad_;
break;
case ui::DomCode::US_Q:
model_->active_modal_prompt_type =
kModalPromptTypeGenericUnsupportedFeature;
......@@ -214,9 +221,15 @@ void VrTestContext::HandleInput(ui::Event* event) {
if (event->IsMouseWheelEvent()) {
int direction =
base::ClampToRange(event->AsMouseWheelEvent()->y_offset(), -1, 1);
if (event->IsControlDown()) {
touchpad_touch_position_.set_y(base::ClampToRange(
touchpad_touch_position_.y() + kTouchpadPositionDelta * direction,
0.0f, 1.0f));
} else {
view_scale_factor_ *= (1 + direction * kViewScaleAdjustmentFactor);
view_scale_factor_ = base::ClampToRange(
view_scale_factor_, kMinViewScaleFactor, kMaxViewScaleFactor);
}
return;
}
......@@ -300,6 +313,8 @@ ControllerModel VrTestContext::UpdateController(const RenderInfo& render_info) {
ControllerModel controller_model;
controller_model.touchpad_button_state =
touchpad_pressed_ ? UiInputManager::DOWN : UiInputManager::UP;
controller_model.touchpad_touch_position = touchpad_touch_position_;
controller_model.touching_touchpad = touching_touchpad_;
controller_model.laser_origin = mouse_point_near;
controller_model.laser_direction = mouse_point_far - mouse_point_near;
......
......@@ -80,6 +80,7 @@ class VrTestContext : public vr::UiBrowserInterface {
int last_drag_y_pixels_ = 0;
gfx::Point last_mouse_point_;
bool touchpad_pressed_ = false;
gfx::PointF touchpad_touch_position_;
float view_scale_factor_ = 1.f;
......@@ -90,6 +91,7 @@ class VrTestContext : public vr::UiBrowserInterface {
bool incognito_ = false;
bool show_web_vr_splash_screen_ = false;
bool voice_search_enabled_ = false;
bool touching_touchpad_ = false;
base::TimeTicks page_load_start_;
ControllerModel last_controller_model_;
......
......@@ -56,6 +56,10 @@ static constexpr float kExitPromptVerticalOffset = -0.09f * kContentDistance;
static constexpr float kUrlBarDistance = 2.4f;
static constexpr float kUrlBarWidthDMM = 0.672f;
static constexpr float kUrlBarHeightDMM = 0.088f;
// This is the non-DMM relative offset of the URL bar. It is used to position
// the DMM root of the URL bar.
static constexpr float kUrlBarRelativeOffset = -0.45f;
// This is the absolute offset of the URL bar's neutral position in DMM.
static constexpr float kUrlBarVerticalOffsetDMM = -0.516f;
static constexpr float kUrlBarRotationRad = gfx::DegToRad(-10.0f);
static constexpr float kUrlBarFontHeightDMM = 0.027f;
......@@ -299,6 +303,9 @@ static constexpr float kPromptVerticalOffsetDMM = -0.1f;
static constexpr float kPromptShadowOffsetDMM = 0.1f;
static constexpr float kPromptDistance = 2.4f;
static constexpr float kMinResizerScale = 0.5f;
static constexpr float kMaxResizerScale = 1.5f;
} // namespace vr
#endif // CHROME_BROWSER_VR_UI_SCENE_CONSTANTS_H_
This diff is collapsed.
......@@ -1225,17 +1225,24 @@ TEST_F(UiTest, RepositionButton) {
TEST_F(UiTest, ResetRepositioner) {
CreateScene(kNotInCct, kNotInWebVr);
Repositioner* repositioner = static_cast<Repositioner*>(
scene_->GetUiElementByName(k2dBrowsingRepositioner));
OnBeginFrame();
gfx::Transform original = repositioner->world_space_transform();
repositioner->set_laser_direction(kForwardVector);
repositioner->SetEnabled(true);
repositioner->set_laser_direction({0, 1, 0});
OnBeginFrame();
EXPECT_FALSE(repositioner->world_space_transform().IsIdentity());
EXPECT_NE(original, repositioner->world_space_transform());
repositioner->SetEnabled(false);
model_->controller.recentered = true;
OnBeginFrame();
EXPECT_TRUE(repositioner->world_space_transform().IsIdentity());
EXPECT_EQ(original, repositioner->world_space_transform());
}
// No element in the controller root's subtree should be hit testable.
......@@ -1246,4 +1253,20 @@ TEST_F(UiTest, ControllerHitTest) {
EXPECT_FALSE(child.IsHitTestable());
}
TEST_F(UiTest, BrowsingRootBounds) {
CreateScene(kNotInCct, kNotInWebVr);
auto* elem = scene_->GetUiElementByName(k2dBrowsingContentGroup);
auto* root = scene_->GetUiElementByName(k2dBrowsingRepositioner);
for (; elem; elem = elem->parent()) {
int num_bounds_contributors = 0;
for (auto& child : elem->children()) {
if (child->contributes_to_parent_bounds())
num_bounds_contributors++;
}
EXPECT_EQ(1, num_bounds_contributors);
if (elem == root)
break;
}
}
} // namespace vr
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