| Index: cc/trees/property_tree.cc
|
| diff --git a/cc/trees/property_tree.cc b/cc/trees/property_tree.cc
|
| index f2ab5a895fc40bf658a38665b434cf088aad3400..3c0d0ee907c83d0e7a79fc4d6f26db2c566c4508 100644
|
| --- a/cc/trees/property_tree.cc
|
| +++ b/cc/trees/property_tree.cc
|
| @@ -13,6 +13,7 @@
|
| #include "cc/animation/animation_host.h"
|
| #include "cc/layers/layer_impl.h"
|
| #include "cc/output/copy_output_request.h"
|
| +#include "cc/proto/gfx_conversions.h"
|
| #include "cc/proto/property_tree.pb.h"
|
| #include "cc/proto/synced_property_conversions.h"
|
| #include "cc/trees/clip_node.h"
|
| @@ -23,7 +24,6 @@
|
| #include "cc/trees/scroll_node.h"
|
| #include "cc/trees/transform_node.h"
|
| #include "ui/gfx/geometry/vector2d_conversions.h"
|
| -
|
| namespace cc {
|
|
|
| template <typename T>
|
| @@ -131,6 +131,20 @@ template class PropertyTree<ClipNode>;
|
| template class PropertyTree<EffectNode>;
|
| template class PropertyTree<ScrollNode>;
|
|
|
| +void StickyPositionNodeData::ToProtobuf(
|
| + proto::StickyPositionNodeData* proto) const {
|
| + proto->set_scroll_ancestor(scroll_ancestor);
|
| + constraints.ToProtobuf(proto->mutable_constraints());
|
| + Vector2dFToProto(main_thread_offset, proto->mutable_main_thread_offset());
|
| +}
|
| +
|
| +void StickyPositionNodeData::FromProtobuf(
|
| + const proto::StickyPositionNodeData& proto) {
|
| + scroll_ancestor = proto.scroll_ancestor();
|
| + constraints.FromProtobuf(proto.constraints());
|
| + main_thread_offset = ProtoToVector2dF(proto.main_thread_offset());
|
| +}
|
| +
|
| int TransformTree::Insert(const TransformNode& tree_node, int parent_id) {
|
| int node_id = PropertyTree<TransformNode>::Insert(tree_node, parent_id);
|
| DCHECK_EQ(node_id, static_cast<int>(cached_data_.size()));
|
| @@ -149,6 +163,7 @@ void TransformTree::clear() {
|
| nodes_affected_by_outer_viewport_bounds_delta_.clear();
|
| cached_data_.clear();
|
| cached_data_.push_back(TransformCachedNodeData());
|
| + sticky_position_data_.clear();
|
|
|
| #if DCHECK_IS_ON()
|
| TransformTree tree;
|
| @@ -250,10 +265,13 @@ void TransformTree::UpdateTransforms(int id) {
|
| TransformNode* target_node = Node(TargetId(id));
|
| TransformNode* source_node = Node(node->source_node_id);
|
| property_trees()->UpdateCachedNumber();
|
| - if (node->needs_local_transform_update || NeedsSourceToParentUpdate(node))
|
| + // TODO(flackr): Only dirty when scroll offset changes.
|
| + if (node->sticky_position_constraint_id >= 0 ||
|
| + node->needs_local_transform_update || NeedsSourceToParentUpdate(node)) {
|
| UpdateLocalTransform(node);
|
| - else
|
| + } else {
|
| UndoSnapping(node);
|
| + }
|
| UpdateScreenSpaceTransform(node, parent_node, target_node);
|
| UpdateSurfaceContentsScale(node);
|
| UpdateAnimationProperties(node, parent_node);
|
| @@ -399,6 +417,86 @@ bool TransformTree::CombineInversesBetween(int source_id,
|
| return all_are_invertible;
|
| }
|
|
|
| +gfx::Vector2dF StickyPositionOffset(TransformTree* tree, TransformNode* node) {
|
| + if (node->sticky_position_constraint_id == -1)
|
| + return gfx::Vector2dF();
|
| + const StickyPositionNodeData* sticky_data =
|
| + tree->StickyPositionData(node->id);
|
| + const LayerStickyPositionConstraint& constraint = sticky_data->constraints;
|
| + ScrollNode* scroll_node =
|
| + tree->property_trees()->scroll_tree.Node(sticky_data->scroll_ancestor);
|
| + gfx::ScrollOffset scroll_offset =
|
| + tree->property_trees()->scroll_tree.current_scroll_offset(
|
| + scroll_node->owner_id);
|
| +
|
| + gfx::RectF clip(gfx::PointF(scroll_offset.x(), scroll_offset.y()),
|
| + gfx::SizeF(scroll_node->scroll_clip_layer_bounds));
|
| + gfx::Vector2dF sticky_offset(
|
| + constraint.scroll_container_relative_sticky_box_rect.OffsetFromOrigin());
|
| + gfx::Vector2dF layer_offset(sticky_data->main_thread_offset);
|
| +
|
| + // In each of the following cases, we measure the limit which is the point
|
| + // that the element should stick to, clamping on one side to 0 (because sticky
|
| + // only pushes elements in one direction). Then we clamp to how far we can
|
| + // push the element in that direction without being pushed outside of its
|
| + // containing block.
|
| + //
|
| + // Note: The order of applying the sticky constraints is applied such that
|
| + // left offset takes precedence over right offset, and top takes precedence
|
| + // over bottom offset.
|
| + if (constraint.is_anchored_right) {
|
| + float right_limit = clip.right() - constraint.right_offset;
|
| + float right_delta = std::min<float>(
|
| + 0, right_limit -
|
| + constraint.scroll_container_relative_sticky_box_rect.right());
|
| + float available_space = std::min<float>(
|
| + 0, constraint.scroll_container_relative_containing_block_rect.x() -
|
| + constraint.scroll_container_relative_sticky_box_rect.x());
|
| + if (right_delta < available_space)
|
| + right_delta = available_space;
|
| + sticky_offset.set_x(sticky_offset.x() + right_delta);
|
| + }
|
| + if (constraint.is_anchored_left) {
|
| + float left_limit = clip.x() + constraint.left_offset;
|
| + float left_delta = std::max<float>(
|
| + 0,
|
| + left_limit - constraint.scroll_container_relative_sticky_box_rect.x());
|
| + float available_space = std::max<float>(
|
| + 0, constraint.scroll_container_relative_containing_block_rect.right() -
|
| + constraint.scroll_container_relative_sticky_box_rect.right());
|
| + if (left_delta > available_space)
|
| + left_delta = available_space;
|
| + sticky_offset.set_x(sticky_offset.x() + left_delta);
|
| + }
|
| + if (constraint.is_anchored_bottom) {
|
| + float bottom_limit = clip.bottom() - constraint.bottom_offset;
|
| + float bottom_delta = std::min<float>(
|
| + 0, bottom_limit -
|
| + constraint.scroll_container_relative_sticky_box_rect.bottom());
|
| + float available_space = std::min<float>(
|
| + 0, constraint.scroll_container_relative_containing_block_rect.y() -
|
| + constraint.scroll_container_relative_sticky_box_rect.y());
|
| + if (bottom_delta < available_space)
|
| + bottom_delta = available_space;
|
| + sticky_offset.set_y(sticky_offset.y() + bottom_delta);
|
| + }
|
| + if (constraint.is_anchored_top) {
|
| + float top_limit = clip.y() + constraint.top_offset;
|
| + float top_delta = std::max<float>(
|
| + 0,
|
| + top_limit - constraint.scroll_container_relative_sticky_box_rect.y());
|
| + float available_space = std::max<float>(
|
| + 0, constraint.scroll_container_relative_containing_block_rect.bottom() -
|
| + constraint.scroll_container_relative_sticky_box_rect.bottom());
|
| + if (top_delta > available_space)
|
| + top_delta = available_space;
|
| + sticky_offset.set_y(sticky_offset.y() + top_delta);
|
| + }
|
| + return sticky_offset - layer_offset -
|
| + constraint.scroll_container_relative_sticky_box_rect
|
| + .OffsetFromOrigin();
|
| +}
|
| +
|
| void TransformTree::UpdateLocalTransform(TransformNode* node) {
|
| gfx::Transform transform = node->post_local;
|
| if (NeedsSourceToParentUpdate(node)) {
|
| @@ -448,8 +546,10 @@ void TransformTree::UpdateLocalTransform(TransformNode* node) {
|
| fixed_position_adjustment.x(),
|
| node->source_to_parent.y() - node->scroll_offset.y() +
|
| fixed_position_adjustment.y());
|
| + transform.Translate(StickyPositionOffset(this, node));
|
| transform.PreconcatTransform(node->local);
|
| transform.PreconcatTransform(node->pre_local);
|
| +
|
| node->set_to_parent(transform);
|
| node->needs_local_transform_update = false;
|
| }
|
| @@ -759,6 +859,15 @@ bool TransformTree::operator==(const TransformTree& other) const {
|
| cached_data_ == other.cached_data();
|
| }
|
|
|
| +StickyPositionNodeData* TransformTree::StickyPositionData(int node_id) {
|
| + TransformNode* node = Node(node_id);
|
| + if (node->sticky_position_constraint_id == -1) {
|
| + node->sticky_position_constraint_id = sticky_position_data_.size();
|
| + sticky_position_data_.push_back(StickyPositionNodeData());
|
| + }
|
| + return &sticky_position_data_[node->sticky_position_constraint_id];
|
| +}
|
| +
|
| void TransformTree::ToProtobuf(proto::PropertyTree* proto) const {
|
| DCHECK(!proto->has_property_type());
|
| proto->set_property_type(proto::PropertyTree::Transform);
|
| @@ -779,6 +888,9 @@ void TransformTree::ToProtobuf(proto::PropertyTree* proto) const {
|
|
|
| for (int i = 0; i < static_cast<int>(cached_data_.size()); ++i)
|
| cached_data_[i].ToProtobuf(data->add_cached_data());
|
| +
|
| + for (int i = 0; i < static_cast<int>(sticky_position_data_.size()); ++i)
|
| + sticky_position_data_[i].ToProtobuf(data->add_sticky_position_data());
|
| }
|
|
|
| void TransformTree::FromProtobuf(
|
| @@ -815,6 +927,12 @@ void TransformTree::FromProtobuf(
|
| cached_data_.push_back(TransformCachedNodeData());
|
| cached_data_.back().FromProtobuf(data.cached_data(i));
|
| }
|
| +
|
| + DCHECK(static_cast<int>(sticky_position_data_.empty()));
|
| + for (int i = 0; i < data.sticky_position_data_size(); ++i) {
|
| + sticky_position_data_.push_back(StickyPositionNodeData());
|
| + sticky_position_data_.back().FromProtobuf(data.sticky_position_data(i));
|
| + }
|
| }
|
|
|
| EffectTree::EffectTree() {}
|
|
|