#ifndef CHROME_BROWSER_VR_ELEMENTS_UI_ELEMENT_H_
#define CHROME_BROWSER_VR_ELEMENTS_UI_ELEMENT_H_
#include <memory>
#include <sstream>
#include <string>
#include <vector>
#include "base/memory/raw_ptr.h"
#include "chrome/browser/vr/databinding/binding_base.h"
#include "chrome/browser/vr/elements/corner_radii.h"
#include "chrome/browser/vr/elements/draw_phase.h"
#include "chrome/browser/vr/elements/ui_element_name.h"
#include "chrome/browser/vr/elements/ui_element_type.h"
#include "chrome/browser/vr/frame_lifecycle.h"
#include "chrome/browser/vr/model/camera_model.h"
#include "chrome/browser/vr/target_property.h"
#include "chrome/browser/vr/vr_ui_export.h"
#include "ui/gfx/animation/keyframe/animation_curve.h"
#include "ui/gfx/animation/keyframe/keyframe_effect.h"
#include "ui/gfx/geometry/point3_f.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/transform.h"
#include "ui/gfx/geometry/transform_operations.h"
#include "ui/gfx/geometry/vector3d_f.h"
namespace base {
class TimeTicks;
}
namespace gfx {
class KeyframeModel;
}
namespace vr {
class SkiaSurfaceProvider;
class UiElementRenderer;
struct CameraModel;
enum LayoutAlignment {
NONE = 0,
LEFT,
RIGHT,
TOP,
BOTTOM,
};
class VR_UI_EXPORT UiElement : public gfx::FloatAnimationCurve::Target,
public gfx::TransformAnimationCurve::Target,
public gfx::SizeAnimationCurve::Target,
public gfx::ColorAnimationCurve::Target {
public:
UiElement();
UiElement(const UiElement&) = delete;
UiElement& operator=(const UiElement&) = delete;
~UiElement() override;
enum OperationIndex {
kTranslateIndex = 0,
kRotateIndex = 1,
kScaleIndex = 2,
};
UiElementName name() const { return name_; }
void SetName(UiElementName name);
UiElementName owner_name_for_test() const { return owner_name_for_test_; }
void set_owner_name_for_test(UiElementName name) {
owner_name_for_test_ = name;
}
UiElementType type() const { return type_; }
void SetType(UiElementType type);
DrawPhase draw_phase() const { return draw_phase_; }
void SetDrawPhase(DrawPhase draw_phase);
void UpdateBindings();
bool DoBeginFrame(const gfx::Transform& head_pose,
bool force_animations_to_completion);
virtual bool PrepareToDraw();
virtual bool HasDirtyTexture() const;
virtual void UpdateTexture();
virtual void Render(UiElementRenderer* renderer,
const CameraModel& model) const;
virtual void Initialize(SkiaSurfaceProvider* provider);
int id() const { return id_; }
bool IsVisible() const;
virtual void SetVisible(bool visible);
virtual void SetVisibleImmediately(bool visible);
void set_opacity_when_visible(float opacity) {
opacity_when_visible_ = opacity;
}
float opacity_when_visible() const { return opacity_when_visible_; }
bool requires_layout() const { return requires_layout_; }
void set_requires_layout(bool requires_layout) {
requires_layout_ = requires_layout;
}
gfx::SizeF size() const;
void SetSize(float width, float hight);
gfx::RectF GetClipRect() const;
void SetClipRect(const gfx::RectF& rect);
gfx::PointF local_origin() const { return local_origin_; }
void SetLayoutOffset(float x, float y);
void SetTranslate(float x, float y, float z);
void SetRotate(float x, float y, float z, float radians);
void SetScale(float x, float y, float z);
gfx::SizeF GetTargetSize() const;
gfx::TransformOperations GetTargetTransform() const;
float GetTargetOpacity() const;
float opacity() const { return opacity_; }
virtual void SetOpacity(float opacity);
CornerRadii corner_radii() const { return corner_radii_; }
void SetCornerRadii(const CornerRadii& radii);
float corner_radius() const {
DCHECK(corner_radii_.AllEqual());
return corner_radii_.upper_left;
}
void SetCornerRadius(float corner_radius) {
SetCornerRadii(
{corner_radius, corner_radius, corner_radius, corner_radius});
}
float computed_opacity() const;
void set_computed_opacity(float computed_opacity) {
computed_opacity_ = computed_opacity;
}
LayoutAlignment x_anchoring() const { return x_anchoring_; }
void set_x_anchoring(LayoutAlignment x_anchoring) {
DCHECK(x_anchoring == LEFT || x_anchoring == RIGHT || x_anchoring == NONE);
x_anchoring_ = x_anchoring;
}
LayoutAlignment y_anchoring() const { return y_anchoring_; }
void set_y_anchoring(LayoutAlignment y_anchoring) {
DCHECK(y_anchoring == TOP || y_anchoring == BOTTOM || y_anchoring == NONE);
y_anchoring_ = y_anchoring;
}
LayoutAlignment x_centering() const { return x_centering_; }
void set_x_centering(LayoutAlignment x_centering) {
DCHECK(x_centering == LEFT || x_centering == RIGHT || x_centering == NONE);
x_centering_ = x_centering;
}
LayoutAlignment y_centering() const { return y_centering_; }
void set_y_centering(LayoutAlignment y_centering) {
DCHECK(y_centering == TOP || y_centering == BOTTOM || y_centering == NONE);
y_centering_ = y_centering;
}
void set_bounds_contain_children(bool bounds_contain_children) {
bounds_contain_children_ = bounds_contain_children;
}
bool bounds_contain_padding() const { return bounds_contain_padding_; }
void set_bounds_contain_padding(bool bounds_contain_padding) {
bounds_contain_padding_ = bounds_contain_padding;
}
bool contributes_to_parent_bounds() const {
return contributes_to_parent_bounds_;
}
void set_contributes_to_parent_bounds(bool value) {
contributes_to_parent_bounds_ = value;
}
void set_padding(float x, float y) {
left_padding_ = x;
right_padding_ = x;
top_padding_ = y;
bottom_padding_ = y;
}
void set_padding(float left, float top, float right, float bottom) {
left_padding_ = left;
right_padding_ = right;
top_padding_ = top;
bottom_padding_ = bottom;
}
const gfx::Transform& inheritable_transform() const {
return inheritable_transform_;
}
void set_inheritable_transform(const gfx::Transform& transform) {
inheritable_transform_ = transform;
}
const gfx::Transform& world_space_transform() const;
void set_world_space_transform(const gfx::Transform& transform) {
world_space_transform_ = transform;
world_space_transform_dirty_ = false;
}
gfx::Transform ComputeTargetWorldSpaceTransform() const;
float ComputeTargetOpacity() const;
void AddChild(std::unique_ptr<UiElement> child);
std::unique_ptr<UiElement> RemoveChild(UiElement* to_remove);
std::unique_ptr<UiElement> ReplaceChild(UiElement* to_remove,
std::unique_ptr<UiElement> to_add);
UiElement* parent() { return parent_; }
const UiElement* parent() const { return parent_; }
void AddBinding(std::unique_ptr<BindingBase> binding);
gfx::Point3F GetCenter() const;
void OnFloatAnimated(const float& value,
int target_property_id,
gfx::KeyframeModel* keyframe_model) override;
void OnTransformAnimated(const gfx::TransformOperations& operations,
int target_property_id,
gfx::KeyframeModel* keyframe_model) override;
void OnSizeAnimated(const gfx::SizeF& size,
int target_property_id,
gfx::KeyframeModel* keyframe_model) override;
void OnColorAnimated(const SkColor& size,
int target_property_id,
gfx::KeyframeModel* keyframe_model) override;
void SetTransitionedProperties(const std::set<TargetProperty>& properties);
void AddKeyframeModel(std::unique_ptr<gfx::KeyframeModel> keyframe_model);
void RemoveKeyframeModels(int target_property);
bool IsAnimatingProperty(TargetProperty property) const;
bool SizeAndLayOut();
virtual void LayOutContributingChildren();
virtual void LayOutNonContributingChildren();
virtual gfx::Transform LocalTransform() const;
virtual gfx::Transform GetTargetLocalTransform() const;
void UpdateComputedOpacity();
bool UpdateWorldSpaceTransform(bool parent_changed);
std::vector<std::unique_ptr<UiElement>>& children() { return children_; }
const std::vector<std::unique_ptr<UiElement>>& children() const {
return children_;
}
void set_update_phase(UpdatePhase phase) { update_phase_ = phase; }
virtual bool IsWorldPositioned() const;
std::string DebugName() const;
#ifndef NDEBUG
void DumpHierarchy(std::vector<size_t> counts,
std::ostringstream* os,
bool include_bindings) const;
virtual void DumpGeometry(std::ostringstream* os) const;
#endif
bool descendants_updated() const { return descendants_updated_; }
void set_descendants_updated(bool updated) { descendants_updated_ = updated; }
base::TimeTicks last_frame_time() const { return last_frame_time_; }
void set_last_frame_time(const base::TimeTicks& time) {
last_frame_time_ = time;
}
protected:
gfx::KeyframeEffect& animator() { return animator_; }
void set_world_space_transform_dirty() {
world_space_transform_dirty_ = true;
}
private:
bool SizeAndLayOutChildren();
bool ShouldUpdateWorldSpaceTransform(bool parent_transform_changed) const;
virtual bool OnBeginFrame(const gfx::Transform& head_pose);
bool IsOrWillBeLocallyVisible() const;
virtual gfx::RectF ComputeContributingChildrenBounds();
int id_ = -1;
gfx::SizeF size_;
gfx::RectF clip_rect_ = {-0.5f, 0.5f, 1.0f, 1.0f};
gfx::PointF local_origin_ = {0.0f, 0.0f};
float opacity_ = 1.0f;
float opacity_when_visible_ = 1.0f;
bool requires_layout_ = true;
CornerRadii corner_radii_ = {0, 0, 0, 0};
float computed_opacity_ = 1.0f;
bool updated_bindings_this_frame_ = false;
bool updated_visibility_this_frame_ = false;
LayoutAlignment x_anchoring_ = LayoutAlignment::NONE;
LayoutAlignment y_anchoring_ = LayoutAlignment::NONE;
LayoutAlignment x_centering_ = LayoutAlignment::NONE;
LayoutAlignment y_centering_ = LayoutAlignment::NONE;
bool bounds_contain_children_ = false;
bool bounds_contain_padding_ = true;
bool contributes_to_parent_bounds_ = true;
float left_padding_ = 0.0f;
float right_padding_ = 0.0f;
float top_padding_ = 0.0f;
float bottom_padding_ = 0.0f;
gfx::KeyframeEffect animator_;
DrawPhase draw_phase_ = kPhaseNone;
base::TimeTicks last_frame_time_;
gfx::Transform inheritable_transform_;
UiElementName name_ = UiElementName::kNone;
UiElementName owner_name_for_test_ = UiElementName::kNone;
UiElementType type_ = UiElementType::kTypeNone;
gfx::TransformOperations transform_operations_;
gfx::Transform local_transform_;
gfx::TransformOperations layout_offset_;
gfx::Transform world_space_transform_;
bool world_space_transform_dirty_ = false;
raw_ptr<UiElement> parent_ = nullptr;
std::vector<std::unique_ptr<UiElement>> children_;
bool descendants_updated_ = false;
std::vector<std::unique_ptr<BindingBase>> bindings_;
UpdatePhase update_phase_ = kClean;
};
}
#endif