Commit a14e1e31 authored by Ian Vollick's avatar Ian Vollick Committed by Commit Bot

[vr] Support automatic sizing to contain children

With this change, I introduce the notion of element bounds. Previously,
the only non-inherited geometric info an element owned was its size.
Now we also store its position. The non-inherited, local size and
transform are stored jointly in a bounds rect.

I've also made the updating of layout a non-virtual function that calls
out to a virtual layout function in order to guarantee that the
UiElement has an opportunity to update its bounds following the layout
of its children.

Bug: None
Change-Id: Ia6bb9bda6008a8aaf9e5dc4c70940dec2f7d73b7
Reviewed-on: https://chromium-review.googlesource.com/763650
Commit-Queue: Ian Vollick <vollick@chromium.org>
Reviewed-by: default avatarBiao She <bshe@chromium.org>
Cr-Commit-Position: refs/heads/master@{#515734}
parent 9d4ac6ce
...@@ -89,8 +89,6 @@ static_library("vr_common") { ...@@ -89,8 +89,6 @@ static_library("vr_common") {
"elements/ui_element_iterator.h", "elements/ui_element_iterator.h",
"elements/ui_element_name.cc", "elements/ui_element_name.cc",
"elements/ui_element_name.h", "elements/ui_element_name.h",
"elements/ui_element_transform_operations.cc",
"elements/ui_element_transform_operations.h",
"elements/ui_texture.cc", "elements/ui_texture.cc",
"elements/ui_texture.h", "elements/ui_texture.h",
"elements/url_bar.cc", "elements/url_bar.cc",
......
...@@ -12,8 +12,6 @@ ...@@ -12,8 +12,6 @@
namespace vr { namespace vr {
class UiElementRenderer;
class ContentElement : public UiElement { class ContentElement : public UiElement {
public: public:
explicit ContentElement(ContentInputDelegate* delegate); explicit ContentElement(ContentInputDelegate* delegate);
......
...@@ -10,11 +10,11 @@ ...@@ -10,11 +10,11 @@
#include "base/numerics/ranges.h" #include "base/numerics/ranges.h"
#include "base/stl_util.h" #include "base/stl_util.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "chrome/browser/vr/elements/ui_element_transform_operations.h"
#include "third_party/WebKit/public/platform/WebGestureEvent.h" #include "third_party/WebKit/public/platform/WebGestureEvent.h"
#include "third_party/skia/include/core/SkRRect.h" #include "third_party/skia/include/core/SkRRect.h"
#include "third_party/skia/include/core/SkRect.h" #include "third_party/skia/include/core/SkRect.h"
#include "ui/gfx/geometry/angle_conversions.h" #include "ui/gfx/geometry/angle_conversions.h"
#include "ui/gfx/geometry/rect_f.h"
namespace vr { namespace vr {
...@@ -171,13 +171,6 @@ gfx::SizeF UiElement::size() const { ...@@ -171,13 +171,6 @@ gfx::SizeF UiElement::size() const {
return size_; return size_;
} }
void UiElement::SetTransformOperations(
const UiElementTransformOperations& ui_element_transform_operations) {
animation_player_.TransitionTransformOperationsTo(
last_frame_time_, TRANSFORM, transform_operations_,
ui_element_transform_operations.operations());
}
void UiElement::SetLayoutOffset(float x, float y) { void UiElement::SetLayoutOffset(float x, float y) {
if (x_centering() == LEFT) { if (x_centering() == LEFT) {
x += size_.width() / 2; x += size_.width() / 2;
...@@ -426,6 +419,40 @@ bool UiElement::IsAnimatingProperty(TargetProperty property) const { ...@@ -426,6 +419,40 @@ bool UiElement::IsAnimatingProperty(TargetProperty property) const {
return animation_player_.IsAnimatingProperty(static_cast<int>(property)); return animation_player_.IsAnimatingProperty(static_cast<int>(property));
} }
void UiElement::DoLayOutChildren() {
LayOutChildren();
if (!bounds_contain_children_) {
DCHECK_EQ(0.0f, x_padding_);
DCHECK_EQ(0.0f, y_padding_);
return;
}
gfx::RectF bounds;
bool first = false;
for (auto& child : children_) {
if (!child->IsVisible()) {
continue;
}
gfx::Point3F child_center;
child->LocalTransform().TransformPoint(&child_center);
gfx::RectF local_rect =
gfx::RectF(child_center.x() - 0.5 * child->size().width(),
child_center.y() - 0.5 * child->size().height(),
child->size().width(), child->size().height());
if (first) {
bounds = local_rect;
first = false;
} else {
bounds.Union(local_rect);
}
}
bounds.Inset(-x_padding_, -y_padding_);
bounds.set_origin(bounds.CenterPoint());
size_ = bounds.size();
local_origin_ = bounds.origin();
}
void UiElement::LayOutChildren() { void UiElement::LayOutChildren() {
DCHECK_LE(kUpdatedTexturesAndSizes, phase_); DCHECK_LE(kUpdatedTexturesAndSizes, phase_);
for (auto& child : children_) { for (auto& child : children_) {
...@@ -458,6 +485,7 @@ void UiElement::UpdateComputedOpacity() { ...@@ -458,6 +485,7 @@ void UiElement::UpdateComputedOpacity() {
void UiElement::UpdateWorldSpaceTransformRecursive() { void UiElement::UpdateWorldSpaceTransformRecursive() {
gfx::Transform transform; gfx::Transform transform;
transform.Translate(local_origin_.x(), local_origin_.y());
transform.Scale(size_.width(), size_.height()); transform.Scale(size_.width(), size_.height());
// Compute an inheritable transformation that can be applied to this element, // Compute an inheritable transformation that can be applied to this element,
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "third_party/skia/include/core/SkColor.h" #include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/geometry/point3_f.h" #include "ui/gfx/geometry/point3_f.h"
#include "ui/gfx/geometry/quaternion.h" #include "ui/gfx/geometry/quaternion.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/geometry/size_f.h" #include "ui/gfx/geometry/size_f.h"
#include "ui/gfx/geometry/vector3d_f.h" #include "ui/gfx/geometry/vector3d_f.h"
#include "ui/gfx/transform.h" #include "ui/gfx/transform.h"
...@@ -40,7 +41,6 @@ namespace vr { ...@@ -40,7 +41,6 @@ namespace vr {
class Animation; class Animation;
class SkiaSurfaceProvider; class SkiaSurfaceProvider;
class UiElementRenderer; class UiElementRenderer;
class UiElementTransformOperations;
enum LayoutAlignment { enum LayoutAlignment {
NONE = 0, NONE = 0,
...@@ -154,10 +154,7 @@ class UiElement : public cc::AnimationTarget { ...@@ -154,10 +154,7 @@ class UiElement : public cc::AnimationTarget {
gfx::SizeF size() const; gfx::SizeF size() const;
void SetSize(float width, float hight); void SetSize(float width, float hight);
// It is assumed that operations is of size 4 with a component for layout gfx::PointF local_origin() const { return local_origin_; }
// translation, translation, rotation and scale, in that order (see
// constructor and the DCHECKs in the implementation of this function).
void SetTransformOperations(const UiElementTransformOperations& operations);
// These are convenience functions for setting the transform operations. They // These are convenience functions for setting the transform operations. They
// will animate if you've set a transition. If you need to animate more than // will animate if you've set a transition. If you need to animate more than
...@@ -206,6 +203,18 @@ class UiElement : public cc::AnimationTarget { ...@@ -206,6 +203,18 @@ class UiElement : public cc::AnimationTarget {
y_centering_ = y_centering; y_centering_ = y_centering;
} }
bool bounds_contain_children() const { return bounds_contain_children_; }
void set_bounds_contain_children(bool bounds_contain_children) {
bounds_contain_children_ = bounds_contain_children;
}
float x_padding() const { return x_padding_; }
float y_padding() const { return y_padding_; }
void set_padding(float x_padding, float y_padding) {
x_padding_ = x_padding;
y_padding_ = y_padding;
}
int draw_phase() const { return draw_phase_; } int draw_phase() const { return draw_phase_; }
void set_draw_phase(int draw_phase) { draw_phase_ = draw_phase; } void set_draw_phase(int draw_phase) { draw_phase_ = draw_phase; }
...@@ -278,6 +287,8 @@ class UiElement : public cc::AnimationTarget { ...@@ -278,6 +287,8 @@ class UiElement : public cc::AnimationTarget {
void RemoveAnimation(int animation_id); void RemoveAnimation(int animation_id);
bool IsAnimatingProperty(TargetProperty property) const; bool IsAnimatingProperty(TargetProperty property) const;
void DoLayOutChildren();
// Handles positioning adjustments for children. This will be overridden by // Handles positioning adjustments for children. This will be overridden by
// UiElements providing custom layout modes. See the documentation of the // UiElements providing custom layout modes. See the documentation of the
// override for their particular functionality. The base implementation // override for their particular functionality. The base implementation
...@@ -357,6 +368,11 @@ class UiElement : public cc::AnimationTarget { ...@@ -357,6 +368,11 @@ class UiElement : public cc::AnimationTarget {
// The size of the object. This does not affect children. // The size of the object. This does not affect children.
gfx::SizeF size_ = {1.0f, 1.0f}; gfx::SizeF size_ = {1.0f, 1.0f};
// The local orgin of the element. This can be updated, say, so that an
// element can contain its children, even if they are not centered about its
// true origin.
gfx::PointF local_origin_ = {0.0f, 0.0f};
// The opacity of the object (between 0.0 and 1.0). // The opacity of the object (between 0.0 and 1.0).
float opacity_ = 1.0f; float opacity_ = 1.0f;
...@@ -391,6 +407,13 @@ class UiElement : public cc::AnimationTarget { ...@@ -391,6 +407,13 @@ class UiElement : public cc::AnimationTarget {
LayoutAlignment x_centering_ = LayoutAlignment::NONE; LayoutAlignment x_centering_ = LayoutAlignment::NONE;
LayoutAlignment y_centering_ = LayoutAlignment::NONE; LayoutAlignment y_centering_ = LayoutAlignment::NONE;
// If this is true, after laying out descendants, this element updates its
// size to accommodate all descendants, adding in the padding below along the
// x and y axes.
bool bounds_contain_children_ = false;
float x_padding_ = 0.0f;
float y_padding_ = 0.0f;
AnimationPlayer animation_player_; AnimationPlayer animation_player_;
int draw_phase_ = kPhaseNone; int draw_phase_ = kPhaseNone;
......
// Copyright 2017 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/ui_element_transform_operations.h"
#include "chrome/browser/vr/elements/ui_element.h"
namespace vr {
UiElementTransformOperations::UiElementTransformOperations() {
operations_.AppendTranslate(0, 0, 0);
operations_.AppendRotate(1, 0, 0, 0);
operations_.AppendScale(1, 1, 1);
}
UiElementTransformOperations::~UiElementTransformOperations() {}
void UiElementTransformOperations::SetTranslate(float x, float y, float z) {
cc::TransformOperation& op = operations_.at(UiElement::kTranslateIndex);
op.translate = {x, y, z};
op.Bake();
}
void UiElementTransformOperations::SetRotate(float x,
float y,
float z,
float degrees) {
cc::TransformOperation& op = operations_.at(UiElement::kRotateIndex);
op.rotate.axis = {x, y, z};
op.rotate.angle = degrees;
op.Bake();
}
void UiElementTransformOperations::SetScale(float x, float y, float z) {
cc::TransformOperation& op = operations_.at(UiElement::kScaleIndex);
op.scale = {x, y, z};
op.Bake();
}
} // namespace vr
// Copyright 2017 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_UI_ELEMENT_TRANSFORM_OPERATIONS_H_
#define CHROME_BROWSER_VR_ELEMENTS_UI_ELEMENT_TRANSFORM_OPERATIONS_H_
#include "base/macros.h"
#include "cc/animation/transform_operations.h"
namespace vr {
// This class should be used solely for setting translate / rotate / scale, etc
// on an element in unison to prevent those from triggering separate animations.
// It is also meant to hide the implementation detail of how we arrange our
// transformation operations in UiElement instances. By and large, you should be
// able to call the corresponding UiElement::SetXXX functions.
class UiElementTransformOperations {
public:
UiElementTransformOperations();
~UiElementTransformOperations();
void SetTranslate(float x, float y, float z);
void SetRotate(float x, float y, float z, float degrees);
void SetScale(float x, float y, float z);
const cc::TransformOperations& operations() const { return operations_; }
private:
cc::TransformOperations operations_;
};
} // namespace vr
#endif // CHROME_BROWSER_VR_ELEMENTS_UI_ELEMENT_TRANSFORM_OPERATIONS_H_
...@@ -18,6 +18,53 @@ ...@@ -18,6 +18,53 @@
namespace vr { namespace vr {
TEST(UiElement, BoundsContainChildren) {
const float epsilon = 1e-3f;
auto parent = base::MakeUnique<UiElement>();
parent->set_bounds_contain_children(true);
parent->set_padding(0.1, 0.2);
auto c1 = base::MakeUnique<UiElement>();
c1->SetSize(3.0f, 3.0f);
c1->SetTranslate(2.5f, 2.5f, 0.0f);
auto* c1_ptr = c1.get();
parent->AddChild(std::move(c1));
parent->DoLayOutChildren();
EXPECT_RECT_NEAR(gfx::RectF(2.5f, 2.5f, 3.2f, 3.4f),
gfx::RectF(parent->local_origin(), parent->size()), epsilon);
EXPECT_EQ(parent->GetCenter().ToString(), c1_ptr->GetCenter().ToString());
auto c2 = base::MakeUnique<UiElement>();
c2->SetSize(4.0f, 4.0f);
c2->SetTranslate(-3.0f, 0.0f, 0.0f);
parent->AddChild(std::move(c2));
parent->DoLayOutChildren();
EXPECT_RECT_NEAR(gfx::RectF(-0.5f, 1.0f, 9.2f, 6.4f),
gfx::RectF(parent->local_origin(), parent->size()), epsilon);
auto c3 = base::MakeUnique<UiElement>();
c3->SetSize(2.0f, 2.0f);
c3->SetTranslate(0.0f, -2.0f, 0.0f);
parent->AddChild(std::move(c3));
parent->DoLayOutChildren();
EXPECT_RECT_NEAR(gfx::RectF(-0.5f, 0.5f, 9.2f, 7.4f),
gfx::RectF(parent->local_origin(), parent->size()), epsilon);
auto c4 = base::MakeUnique<UiElement>();
c4->SetSize(2.0f, 2.0f);
c4->SetTranslate(20.0f, 20.0f, 0.0f);
c4->SetVisible(false);
parent->AddChild(std::move(c4));
// We expect no change due to an invisible child.
parent->DoLayOutChildren();
EXPECT_RECT_NEAR(gfx::RectF(-0.5f, 0.5f, 9.2f, 7.4f),
gfx::RectF(parent->local_origin(), parent->size()), epsilon);
}
TEST(UiElements, AnimateSize) { TEST(UiElements, AnimateSize) {
UiScene scene; UiScene scene;
auto rect = base::MakeUnique<UiElement>(); auto rect = base::MakeUnique<UiElement>();
......
...@@ -130,7 +130,7 @@ bool UiScene::OnBeginFrame(const base::TimeTicks& current_time, ...@@ -130,7 +130,7 @@ bool UiScene::OnBeginFrame(const base::TimeTicks& current_time,
// size of their children. This must be done in reverse order, such that // size of their children. This must be done in reverse order, such that
// children are correctly sized when laid out by their parent. // children are correctly sized when laid out by their parent.
for (auto& element : base::Reversed(*root_element_)) { for (auto& element : base::Reversed(*root_element_)) {
element.LayOutChildren(); element.DoLayOutChildren();
element.set_update_phase(UiElement::kUpdatedLayout); element.set_update_phase(UiElement::kUpdatedLayout);
} }
} }
......
...@@ -33,7 +33,6 @@ ...@@ -33,7 +33,6 @@
#include "chrome/browser/vr/elements/transient_element.h" #include "chrome/browser/vr/elements/transient_element.h"
#include "chrome/browser/vr/elements/ui_element.h" #include "chrome/browser/vr/elements/ui_element.h"
#include "chrome/browser/vr/elements/ui_element_name.h" #include "chrome/browser/vr/elements/ui_element_name.h"
#include "chrome/browser/vr/elements/ui_element_transform_operations.h"
#include "chrome/browser/vr/elements/ui_texture.h" #include "chrome/browser/vr/elements/ui_texture.h"
#include "chrome/browser/vr/elements/url_bar.h" #include "chrome/browser/vr/elements/url_bar.h"
#include "chrome/browser/vr/elements/vector_icon.h" #include "chrome/browser/vr/elements/vector_icon.h"
......
...@@ -8,13 +8,13 @@ ...@@ -8,13 +8,13 @@
#include <vector> #include <vector>
#include "base/memory/ptr_util.h" #include "base/memory/ptr_util.h"
#include "base/numerics/math_constants.h"
#include "base/test/gtest_util.h" #include "base/test/gtest_util.h"
#include "base/values.h" #include "base/values.h"
#include "chrome/browser/vr/databinding/binding.h" #include "chrome/browser/vr/databinding/binding.h"
#include "chrome/browser/vr/elements/draw_phase.h" #include "chrome/browser/vr/elements/draw_phase.h"
#include "chrome/browser/vr/elements/transient_element.h" #include "chrome/browser/vr/elements/transient_element.h"
#include "chrome/browser/vr/elements/ui_element.h" #include "chrome/browser/vr/elements/ui_element.h"
#include "chrome/browser/vr/elements/ui_element_transform_operations.h"
#include "chrome/browser/vr/elements/viewport_aware_root.h" #include "chrome/browser/vr/elements/viewport_aware_root.h"
#include "chrome/browser/vr/test/animation_utils.h" #include "chrome/browser/vr/test/animation_utils.h"
#include "chrome/browser/vr/test/constants.h" #include "chrome/browser/vr/test/constants.h"
...@@ -106,21 +106,17 @@ TEST(UiScene, ParentTransformAppliesToChild) { ...@@ -106,21 +106,17 @@ TEST(UiScene, ParentTransformAppliesToChild) {
UiElement* parent = element.get(); UiElement* parent = element.get();
element->SetSize(1000, 1000); element->SetSize(1000, 1000);
UiElementTransformOperations operations; element->SetTranslate(6, 1, 0);
operations.SetTranslate(6, 1, 0); element->SetRotate(0, 0, 1, 0.5f * base::kPiFloat);
operations.SetRotate(0, 0, 1, 90); element->SetScale(3, 3, 1);
operations.SetScale(3, 3, 1);
element->SetTransformOperations(operations);
element->set_draw_phase(0); element->set_draw_phase(0);
scene.AddUiElement(kRoot, std::move(element)); scene.AddUiElement(kRoot, std::move(element));
// Add a child to the parent, with different transformations. // Add a child to the parent, with different transformations.
element = base::MakeUnique<UiElement>(); element = base::MakeUnique<UiElement>();
UiElementTransformOperations child_operations; element->SetTranslate(3, 0, 0);
child_operations.SetTranslate(3, 0, 0); element->SetRotate(0, 0, 1, 0.5f * base::kPiFloat);
child_operations.SetRotate(0, 0, 1, 90); element->SetScale(2, 2, 1);
child_operations.SetScale(2, 2, 1);
element->SetTransformOperations(child_operations);
element->set_draw_phase(0); element->set_draw_phase(0);
UiElement* child = element.get(); UiElement* child = element.get();
parent->AddChild(std::move(element)); parent->AddChild(std::move(element));
......
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