summaryrefslogtreecommitdiffstats
path: root/cc/trees
diff options
context:
space:
mode:
authorsunxd <sunxd@chromium.org>2016-03-03 14:31:10 -0800
committerCommit bot <commit-bot@chromium.org>2016-03-03 22:32:28 +0000
commitc36713a0336c00a0971fe33514adc01f4df693fa (patch)
tree8e9b76bd9b79b76e1418aecaab20960597fe8c33 /cc/trees
parent1f8acc51c0c5d9fea66917884b927eff8f3e570e (diff)
downloadchromium_src-c36713a0336c00a0971fe33514adc01f4df693fa.zip
chromium_src-c36713a0336c00a0971fe33514adc01f4df693fa.tar.gz
chromium_src-c36713a0336c00a0971fe33514adc01f4df693fa.tar.bz2
cc: Move SyncedScrollOffset to scroll tree
Now updating scrolling information on impl side can be independent of layer impl. There are still some left-over changes corresponding to NoteLayerPropertiesChanged. SyncedScrollOffset of scrollable layers are now stored in property trees instead of layer impl. The main thread property tree has one copy while pending and active share one. BUG=568830 CQ_INCLUDE_TRYBOTS=tryserver.blink:linux_blink_rel Review URL: https://codereview.chromium.org/1736073002 Cr-Commit-Position: refs/heads/master@{#379116}
Diffstat (limited to 'cc/trees')
-rw-r--r--cc/trees/layer_tree_host.cc4
-rw-r--r--cc/trees/layer_tree_host_common_unittest.cc9
-rw-r--r--cc/trees/layer_tree_host_impl.cc13
-rw-r--r--cc/trees/layer_tree_host_impl_unittest.cc27
-rw-r--r--cc/trees/layer_tree_impl.cc6
-rw-r--r--cc/trees/layer_tree_impl.h8
-rw-r--r--cc/trees/property_tree.cc197
-rw-r--r--cc/trees/property_tree.h31
-rw-r--r--cc/trees/property_tree_builder.cc9
-rw-r--r--cc/trees/property_tree_unittest.cc7
-rw-r--r--cc/trees/tree_synchronizer_unittest.cc115
11 files changed, 399 insertions, 27 deletions
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index 268e93b..d5f9b58 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -495,6 +495,10 @@ void LayerTreeHost::FinishCommitOnImplThread(LayerTreeHostImpl* host_impl) {
// properties, which updates property tree indices.
sync_tree->UpdatePropertyTreeScrollingAndAnimationFromMainThread();
+ // This must happen after synchronizing property trees and after pushing
+ // properties, which updates the clobber_active_value flag.
+ sync_tree->UpdatePropertyTreeScrollOffset(&property_trees_);
+
micro_benchmark_controller_.ScheduleImplBenchmarks(host_impl);
// We don't track changes to effect tree on main thread. But, to preserve any
// change tracking done on active tree's effect tree, we copy it to the main
diff --git a/cc/trees/layer_tree_host_common_unittest.cc b/cc/trees/layer_tree_host_common_unittest.cc
index fae38ae..d2c1f55 100644
--- a/cc/trees/layer_tree_host_common_unittest.cc
+++ b/cc/trees/layer_tree_host_common_unittest.cc
@@ -10056,7 +10056,8 @@ TEST_F(LayerTreeHostCommonTest, ScrollTreeBuilderTest) {
// Property tree root
ScrollTree scroll_tree = host()->property_trees()->scroll_tree;
- ScrollTree expected_scroll_tree;
+ PropertyTrees property_trees;
+ ScrollTree expected_scroll_tree = property_trees.scroll_tree;
ScrollNode* property_tree_root = expected_scroll_tree.Node(0);
property_tree_root->id = kRootPropertyTreeNodeId;
property_tree_root->parent_id = kInvalidPropertyTreeNodeId;
@@ -10139,6 +10140,12 @@ TEST_F(LayerTreeHostCommonTest, ScrollTreeBuilderTest) {
scroll_parent5.data.transform_id = parent5->transform_tree_index();
expected_scroll_tree.Insert(scroll_parent5, 1);
+ expected_scroll_tree.synced_scroll_offset(parent2->id())
+ ->PushFromMainThread(gfx::ScrollOffset(0, 0));
+ expected_scroll_tree.synced_scroll_offset(child7->id())
+ ->PushFromMainThread(gfx::ScrollOffset(0, 0));
+ expected_scroll_tree.synced_scroll_offset(grand_child11->id())
+ ->PushFromMainThread(gfx::ScrollOffset(0, 0));
expected_scroll_tree.set_needs_update(false);
EXPECT_EQ(expected_scroll_tree, scroll_tree);
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index dfa3c3f..c7bcf2c 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -3249,16 +3249,9 @@ static void CollectScrollDeltas(ScrollAndScaleSet* scroll_info,
if (!root_layer)
return;
- for (auto* layer : *root_layer->layer_tree_impl()) {
- gfx::ScrollOffset scroll_delta = layer->PullDeltaForMainThread();
-
- if (!scroll_delta.IsZero()) {
- LayerTreeHostCommon::ScrollUpdateInfo scroll;
- scroll.layer_id = layer->id();
- scroll.scroll_delta = gfx::Vector2d(scroll_delta.x(), scroll_delta.y());
- scroll_info->scrolls.push_back(scroll);
- }
- }
+ return root_layer->layer_tree_impl()
+ ->property_trees()
+ ->scroll_tree.CollectScrollDeltas(scroll_info);
}
scoped_ptr<ScrollAndScaleSet> LayerTreeHostImpl::ProcessScrollDeltas() {
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 32e461186..8ecfcdf 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -2033,7 +2033,7 @@ TEST_F(LayerTreeHostImplTest, PinchGesture) {
host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, min_page_scale,
max_page_scale);
scroll_layer->SetScrollDelta(gfx::Vector2d());
- scroll_layer->PullDeltaForMainThread();
+ scroll_layer->synced_scroll_offset()->PullDeltaForMainThread();
scroll_layer->PushScrollOffsetFromMainThread(gfx::ScrollOffset(50, 50));
float page_scale_delta = 0.1f;
@@ -2056,7 +2056,7 @@ TEST_F(LayerTreeHostImplTest, PinchGesture) {
host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, min_page_scale,
max_page_scale);
scroll_layer->SetScrollDelta(gfx::Vector2d());
- scroll_layer->PullDeltaForMainThread();
+ scroll_layer->synced_scroll_offset()->PullDeltaForMainThread();
scroll_layer->PushScrollOffsetFromMainThread(gfx::ScrollOffset(20, 20));
float page_scale_delta = 1.f;
@@ -2079,7 +2079,7 @@ TEST_F(LayerTreeHostImplTest, PinchGesture) {
host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, min_page_scale,
max_page_scale);
scroll_layer->SetScrollDelta(gfx::Vector2d());
- scroll_layer->PullDeltaForMainThread();
+ scroll_layer->synced_scroll_offset()->PullDeltaForMainThread();
scroll_layer->PushScrollOffsetFromMainThread(gfx::ScrollOffset(20, 20));
float page_scale_delta = 1.f;
@@ -2104,7 +2104,7 @@ TEST_F(LayerTreeHostImplTest, PinchGesture) {
{
host_impl_->active_tree()->PushPageScaleFromMainThread(0.5f, 0.5f, 4.f);
scroll_layer->SetScrollDelta(gfx::Vector2d());
- scroll_layer->PullDeltaForMainThread();
+ scroll_layer->synced_scroll_offset()->PullDeltaForMainThread();
scroll_layer->PushScrollOffsetFromMainThread(gfx::ScrollOffset(0, 0));
host_impl_->ScrollBegin(BeginState(gfx::Point(0, 0)).get(),
@@ -10192,12 +10192,27 @@ TEST_F(LayerTreeHostImplTest, JitterTest) {
LayerTreeImpl* pending_tree = host_impl_->pending_tree();
pending_tree->PushPageScaleFromMainThread(1.f, 1.f, 1.f);
+ LayerImpl* last_scrolled_layer = pending_tree->LayerById(
+ host_impl_->active_tree()->LastScrolledLayerId());
+
+ // When building property trees from impl side, the builder uses the scroll
+ // offset of layer_impl to initialize the scroll offset in scroll tree:
+ // scroll_tree.synced_scroll_offset.PushFromMainThread(
+ // layer->CurrentScrollOffset()).
+ // However, layer_impl does not store scroll_offset, so it is using scroll
+ // tree's scroll offset to initialize itself. Usually this approach works
+ // because this is a simple assignment. However if scroll_offset's pending
+ // delta is not zero, the delta would be counted twice.
+ // This hacking here is to restore the damaged scroll offset.
+ gfx::ScrollOffset pending_base =
+ last_scrolled_layer->synced_scroll_offset()->PendingBase();
pending_tree->property_trees()->needs_rebuild = true;
pending_tree->BuildPropertyTreesForTesting();
+ last_scrolled_layer->synced_scroll_offset()->PushFromMainThread(
+ pending_base);
+
pending_tree->set_needs_update_draw_properties();
pending_tree->UpdateDrawProperties(false);
- LayerImpl* last_scrolled_layer = pending_tree->LayerById(
- host_impl_->active_tree()->LastScrolledLayerId());
float jitter =
LayerTreeHostCommon::CalculateFrameJitter(last_scrolled_layer);
// There should not be any jitter measured till we hit the fixed point hits
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc
index 78cd744..89567a5 100644
--- a/cc/trees/layer_tree_impl.cc
+++ b/cc/trees/layer_tree_impl.cc
@@ -320,6 +320,7 @@ void LayerTreeImpl::PushPropertiesTo(LayerTreeImpl* target_tree) {
LayerImpl* layer = target_tree->CurrentlyScrollingLayer();
target_tree->SetPropertyTrees(property_trees_);
target_tree->SetCurrentlyScrollingLayer(layer);
+ target_tree->UpdatePropertyTreeScrollOffset(&property_trees_);
if (next_activation_forces_redraw_) {
target_tree->ForceRedrawNextActivation();
@@ -687,10 +688,7 @@ void LayerTreeImpl::ApplySentScrollAndScaleDeltasFromAbortedCommit() {
if (!root_layer())
return;
- LayerTreeHostCommon::CallFunctionForSubtree(
- root_layer(), [](LayerImpl* layer) {
- layer->ApplySentScrollDeltasFromAbortedCommit();
- });
+ property_trees()->scroll_tree.ApplySentScrollDeltasFromAbortedCommit();
}
void LayerTreeImpl::SetViewportLayersFromIds(
diff --git a/cc/trees/layer_tree_impl.h b/cc/trees/layer_tree_impl.h
index 07ab83e..9f20b13 100644
--- a/cc/trees/layer_tree_impl.h
+++ b/cc/trees/layer_tree_impl.h
@@ -135,8 +135,10 @@ class CC_EXPORT LayerTreeImpl {
void SetRootLayer(scoped_ptr<LayerImpl>);
scoped_ptr<LayerImpl> DetachLayerTree();
- void SetPropertyTrees(const PropertyTrees& property_trees) {
+ void SetPropertyTrees(const PropertyTrees property_trees) {
property_trees_ = property_trees;
+ property_trees_.is_main_thread = false;
+ property_trees_.is_active = IsActiveTree();
property_trees_.transform_tree.set_source_to_parent_updates_allowed(false);
}
PropertyTrees* property_trees() { return &property_trees_; }
@@ -216,6 +218,10 @@ class CC_EXPORT LayerTreeImpl {
}
void UpdatePropertyTreeScrollingAndAnimationFromMainThread();
+ void UpdatePropertyTreeScrollOffset(PropertyTrees* property_trees) {
+ property_trees_.scroll_tree.UpdateScrollOffsetMap(
+ &property_trees->scroll_tree.scroll_offset_map(), this);
+ }
void SetPageScaleOnActiveTree(float active_page_scale);
void PushPageScaleFromMainThread(float page_scale_factor,
float min_page_scale_factor,
diff --git a/cc/trees/property_tree.cc b/cc/trees/property_tree.cc
index 27819d9..4738e01 100644
--- a/cc/trees/property_tree.cc
+++ b/cc/trees/property_tree.cc
@@ -10,11 +10,15 @@
#include "base/logging.h"
#include "cc/base/math_util.h"
#include "cc/input/main_thread_scrolling_reason.h"
+#include "cc/layers/layer_impl.h"
#include "cc/proto/gfx_conversions.h"
#include "cc/proto/property_tree.pb.h"
#include "cc/proto/scroll_offset.pb.h"
+#include "cc/proto/synced_property_conversions.h"
#include "cc/proto/transform.pb.h"
#include "cc/proto/vector2df.pb.h"
+#include "cc/trees/layer_tree_host_common.h"
+#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/property_tree.h"
#include "ui/gfx/geometry/vector2d_conversions.h"
@@ -1302,13 +1306,46 @@ void EffectTree::FromProtobuf(const proto::PropertyTree& proto) {
PropertyTree::FromProtobuf(proto);
}
-ScrollTree::ScrollTree() : currently_scrolling_node_id_(-1) {}
+ScrollTree::ScrollTree()
+ : currently_scrolling_node_id_(-1),
+ layer_id_to_scroll_offset_map_(ScrollTree::ScrollOffsetMap()) {}
ScrollTree::~ScrollTree() {}
+ScrollTree& ScrollTree::operator=(const ScrollTree& from) {
+ PropertyTree::operator=(from);
+ currently_scrolling_node_id_ = -1;
+ // layer_id_to_scroll_offset_map_ is intentionally omitted in operator=,
+ // because we do not want to simply copy the map when property tree is
+ // propagating from pending to active.
+ // In the main to pending case, we do want to copy it, but this can be done by
+ // calling UpdateScrollOffsetMap after the assignment;
+ // In the other case, we want pending and active property trees to share the
+ // same map.
+ return *this;
+}
+
bool ScrollTree::operator==(const ScrollTree& other) const {
- return PropertyTree::operator==(other) &&
- CurrentlyScrollingNode() == other.CurrentlyScrollingNode();
+ const ScrollTree::ScrollOffsetMap& other_scroll_offset_map =
+ other.scroll_offset_map();
+ if (layer_id_to_scroll_offset_map_.size() != other_scroll_offset_map.size())
+ return false;
+
+ for (auto map_entry : layer_id_to_scroll_offset_map_) {
+ int key = map_entry.first;
+ if (other_scroll_offset_map.find(key) == other_scroll_offset_map.end() ||
+ map_entry.second != layer_id_to_scroll_offset_map_.at(key))
+ return false;
+ }
+
+ bool is_currently_scrolling_node_equal =
+ (currently_scrolling_node_id_ == -1)
+ ? (!other.CurrentlyScrollingNode())
+ : (other.CurrentlyScrollingNode() &&
+ currently_scrolling_node_id_ ==
+ other.CurrentlyScrollingNode()->id);
+
+ return PropertyTree::operator==(other) && is_currently_scrolling_node_equal;
}
void ScrollTree::ToProtobuf(proto::PropertyTree* proto) const {
@@ -1319,6 +1356,14 @@ void ScrollTree::ToProtobuf(proto::PropertyTree* proto) const {
proto::ScrollTreeData* data = proto->mutable_scroll_tree_data();
data->set_currently_scrolling_node_id(currently_scrolling_node_id_);
+ for (auto i : layer_id_to_scroll_offset_map_) {
+ data->add_layer_id_to_scroll_offset_map();
+ proto::ScrollOffsetMapEntry* entry =
+ data->mutable_layer_id_to_scroll_offset_map(
+ data->layer_id_to_scroll_offset_map_size() - 1);
+ entry->set_layer_id(i.first);
+ SyncedScrollOffsetToProto(*i.second.get(), entry->mutable_scroll_offset());
+ }
}
void ScrollTree::FromProtobuf(const proto::PropertyTree& proto) {
@@ -1329,6 +1374,24 @@ void ScrollTree::FromProtobuf(const proto::PropertyTree& proto) {
const proto::ScrollTreeData& data = proto.scroll_tree_data();
currently_scrolling_node_id_ = data.currently_scrolling_node_id();
+
+ for (int i = 0; i < data.layer_id_to_scroll_offset_map_size(); ++i) {
+ const proto::ScrollOffsetMapEntry entry =
+ data.layer_id_to_scroll_offset_map(i);
+ layer_id_to_scroll_offset_map_[entry.layer_id()] = new SyncedScrollOffset();
+ ProtoToSyncedScrollOffset(
+ entry.scroll_offset(),
+ layer_id_to_scroll_offset_map_[entry.layer_id()].get());
+ }
+}
+
+void ScrollTree::clear() {
+ PropertyTree<ScrollNode>::clear();
+
+ if (property_trees()->is_main_thread) {
+ currently_scrolling_node_id_ = -1;
+ layer_id_to_scroll_offset_map_.clear();
+ }
}
gfx::ScrollOffset ScrollTree::MaxScrollOffset(int scroll_node_id) const {
@@ -1414,12 +1477,130 @@ gfx::Transform ScrollTree::ScreenSpaceTransform(int scroll_node_id) const {
return screen_space_transform;
}
+// TODO(sunxd): Make this function private once scroll offset access is fully
+// directed to scroll tree.
+SyncedScrollOffset* ScrollTree::synced_scroll_offset(int layer_id) {
+ if (layer_id_to_scroll_offset_map_.find(layer_id) ==
+ layer_id_to_scroll_offset_map_.end()) {
+ layer_id_to_scroll_offset_map_[layer_id] = new SyncedScrollOffset;
+ }
+ return layer_id_to_scroll_offset_map_[layer_id].get();
+}
+
+gfx::ScrollOffset ScrollTree::PullDeltaForMainThread(
+ SyncedScrollOffset* scroll_offset) {
+ // TODO(miletus): Remove all this temporary flooring machinery when
+ // Blink fully supports fractional scrolls.
+ gfx::ScrollOffset current_offset =
+ scroll_offset->Current(property_trees()->is_active);
+ gfx::ScrollOffset current_delta = property_trees()->is_active
+ ? scroll_offset->Delta()
+ : scroll_offset->PendingDelta().get();
+ gfx::ScrollOffset floored_delta(floor(current_delta.x()),
+ floor(current_delta.y()));
+ gfx::ScrollOffset diff_delta = floored_delta - current_delta;
+ gfx::ScrollOffset tmp_offset = current_offset + diff_delta;
+ scroll_offset->SetCurrent(tmp_offset);
+ gfx::ScrollOffset delta = scroll_offset->PullDeltaForMainThread();
+ scroll_offset->SetCurrent(current_offset);
+ return delta;
+}
+
+void ScrollTree::CollectScrollDeltas(ScrollAndScaleSet* scroll_info) {
+ for (auto map_entry : layer_id_to_scroll_offset_map_) {
+ gfx::ScrollOffset scroll_delta =
+ PullDeltaForMainThread(map_entry.second.get());
+
+ if (!scroll_delta.IsZero()) {
+ LayerTreeHostCommon::ScrollUpdateInfo scroll;
+ scroll.layer_id = map_entry.first;
+ scroll.scroll_delta = gfx::Vector2d(scroll_delta.x(), scroll_delta.y());
+ scroll_info->scrolls.push_back(scroll);
+ }
+ }
+}
+
+void ScrollTree::UpdateScrollOffsetMapEntry(
+ int key,
+ ScrollTree::ScrollOffsetMap* new_scroll_offset_map,
+ LayerTreeImpl* layer_tree_impl) {
+ bool changed = false;
+ // If we are pushing scroll offset from main to pending tree, we create a new
+ // instance of synced scroll offset; if we are pushing from pending to active,
+ // we reuse the pending tree's value in the map.
+ if (!property_trees()->is_active) {
+ changed = synced_scroll_offset(key)->PushFromMainThread(
+ new_scroll_offset_map->at(key)->PendingBase());
+
+ if (new_scroll_offset_map->at(key)->clobber_active_value()) {
+ synced_scroll_offset(key)->set_clobber_active_value();
+ }
+ if (changed)
+ layer_tree_impl->LayerById(key)->DidUpdateScrollOffset();
+ } else {
+ layer_id_to_scroll_offset_map_[key] = new_scroll_offset_map->at(key);
+ changed |= synced_scroll_offset(key)->PushPendingToActive();
+ if (changed)
+ layer_tree_impl->LayerById(key)->DidUpdateScrollOffset();
+ }
+}
+
+void ScrollTree::UpdateScrollOffsetMap(
+ ScrollTree::ScrollOffsetMap* new_scroll_offset_map,
+ LayerTreeImpl* layer_tree_impl) {
+ if (layer_tree_impl && layer_tree_impl->root_layer()) {
+ DCHECK(!property_trees()->is_main_thread);
+ for (auto map_entry = layer_id_to_scroll_offset_map_.begin();
+ map_entry != layer_id_to_scroll_offset_map_.end();) {
+ int key = map_entry->first;
+ if (new_scroll_offset_map->find(key) != new_scroll_offset_map->end()) {
+ UpdateScrollOffsetMapEntry(key, new_scroll_offset_map, layer_tree_impl);
+ ++map_entry;
+ } else {
+ map_entry = layer_id_to_scroll_offset_map_.erase(map_entry);
+ }
+ }
+
+ for (auto& map_entry : *new_scroll_offset_map) {
+ int key = map_entry.first;
+ if (layer_id_to_scroll_offset_map_.find(key) ==
+ layer_id_to_scroll_offset_map_.end())
+ UpdateScrollOffsetMapEntry(key, new_scroll_offset_map, layer_tree_impl);
+ }
+ }
+}
+
+ScrollTree::ScrollOffsetMap& ScrollTree::scroll_offset_map() {
+ return layer_id_to_scroll_offset_map_;
+}
+
+const ScrollTree::ScrollOffsetMap& ScrollTree::scroll_offset_map() const {
+ return layer_id_to_scroll_offset_map_;
+}
+
+void ScrollTree::ApplySentScrollDeltasFromAbortedCommit() {
+ DCHECK(property_trees()->is_active);
+ for (auto& map_entry : layer_id_to_scroll_offset_map_)
+ map_entry.second->AbortCommit();
+}
+
+bool ScrollTree::SetScrollOffset(int layer_id,
+ const gfx::ScrollOffset& scroll_offset) {
+ if (property_trees()->is_main_thread)
+ return synced_scroll_offset(layer_id)->PushFromMainThread(scroll_offset);
+ else if (property_trees()->is_active)
+ return synced_scroll_offset(layer_id)->SetCurrent(scroll_offset);
+ return false;
+}
+
PropertyTrees::PropertyTrees()
: needs_rebuild(true),
non_root_surfaces_enabled(true),
changed(false),
full_tree_damaged(false),
- sequence_number(0) {
+ sequence_number(0),
+ is_main_thread(true),
+ is_active(false) {
transform_tree.SetPropertyTrees(this);
effect_tree.SetPropertyTrees(this);
clip_tree.SetPropertyTrees(this);
@@ -1434,6 +1615,8 @@ bool PropertyTrees::operator==(const PropertyTrees& other) const {
scroll_tree == other.scroll_tree &&
needs_rebuild == other.needs_rebuild && changed == other.changed &&
full_tree_damaged == other.full_tree_damaged &&
+ is_main_thread == other.is_main_thread &&
+ is_active == other.is_active &&
non_root_surfaces_enabled == other.non_root_surfaces_enabled &&
sequence_number == other.sequence_number;
}
@@ -1448,6 +1631,8 @@ PropertyTrees& PropertyTrees::operator=(const PropertyTrees& from) {
full_tree_damaged = from.full_tree_damaged;
non_root_surfaces_enabled = from.non_root_surfaces_enabled;
sequence_number = from.sequence_number;
+ is_main_thread = from.is_main_thread;
+ is_active = from.is_active;
inner_viewport_container_bounds_delta_ =
from.inner_viewport_container_bounds_delta();
outer_viewport_container_bounds_delta_ =
@@ -1472,6 +1657,8 @@ void PropertyTrees::ToProtobuf(proto::PropertyTrees* proto) const {
proto->set_changed(changed);
proto->set_full_tree_damaged(full_tree_damaged);
proto->set_non_root_surfaces_enabled(non_root_surfaces_enabled);
+ proto->set_is_main_thread(is_main_thread);
+ proto->set_is_active(is_active);
// TODO(khushalsagar): Consider using the sequence number to decide if
// property trees need to be serialized again for a commit. See crbug/555370.
@@ -1490,6 +1677,8 @@ void PropertyTrees::FromProtobuf(const proto::PropertyTrees& proto) {
full_tree_damaged = proto.full_tree_damaged();
non_root_surfaces_enabled = proto.non_root_surfaces_enabled();
sequence_number = proto.sequence_number();
+ is_main_thread = proto.is_main_thread();
+ is_active = proto.is_active();
transform_tree.SetPropertyTrees(this);
effect_tree.SetPropertyTrees(this);
diff --git a/cc/trees/property_tree.h b/cc/trees/property_tree.h
index c35ec8d..c57ad75 100644
--- a/cc/trees/property_tree.h
+++ b/cc/trees/property_tree.h
@@ -7,9 +7,11 @@
#include <stddef.h>
+#include <unordered_map>
#include <vector>
#include "cc/base/cc_export.h"
+#include "cc/base/synced_property.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/geometry/scroll_offset.h"
#include "ui/gfx/transform.h"
@@ -27,6 +29,9 @@ class TransformTreeData;
class TreeNode;
}
+class LayerTreeImpl;
+struct ScrollAndScaleSet;
+
// ------------------------------*IMPORTANT*---------------------------------
// Each class declared here has a corresponding proto defined in
// cc/proto/property_tree.proto. When making any changes to a class structure
@@ -34,6 +39,8 @@ class TreeNode;
// change to its proto and the ToProtobuf and FromProtobuf methods for that
// class.
+typedef SyncedProperty<AdditionGroup<gfx::ScrollOffset>> SyncedScrollOffset;
+
template <typename T>
struct CC_EXPORT TreeNode {
TreeNode() : id(-1), parent_id(-1), owner_id(-1), data() {}
@@ -551,11 +558,17 @@ class CC_EXPORT ScrollTree final : public PropertyTree<ScrollNode> {
ScrollTree();
~ScrollTree() override;
+ ScrollTree& operator=(const ScrollTree& from);
bool operator==(const ScrollTree& other) const;
void ToProtobuf(proto::PropertyTree* proto) const;
void FromProtobuf(const proto::PropertyTree& proto);
+ void clear() override;
+
+ typedef std::unordered_map<int, scoped_refptr<SyncedScrollOffset>>
+ ScrollOffsetMap;
+
gfx::ScrollOffset MaxScrollOffset(int scroll_node_id) const;
gfx::Size scroll_clip_layer_bounds(int scroll_node_id) const;
ScrollNode* CurrentlyScrollingNode();
@@ -563,8 +576,24 @@ class CC_EXPORT ScrollTree final : public PropertyTree<ScrollNode> {
void set_currently_scrolling_node(int scroll_node_id);
gfx::Transform ScreenSpaceTransform(int scroll_node_id) const;
+ // synced_scroll_offset is supposed to be called by Layer/LayerImpl only
+ SyncedScrollOffset* synced_scroll_offset(int layer_id);
+ void CollectScrollDeltas(ScrollAndScaleSet* scroll_info);
+ void UpdateScrollOffsetMap(ScrollOffsetMap* new_scroll_offset_map,
+ LayerTreeImpl* layer_tree_impl);
+ ScrollOffsetMap& scroll_offset_map();
+ const ScrollOffsetMap& scroll_offset_map() const;
+ void ApplySentScrollDeltasFromAbortedCommit();
+ bool SetScrollOffset(int layer_id, const gfx::ScrollOffset& scroll_offset);
+
private:
int currently_scrolling_node_id_;
+ ScrollOffsetMap layer_id_to_scroll_offset_map_;
+
+ gfx::ScrollOffset PullDeltaForMainThread(SyncedScrollOffset* scroll_offset);
+ void UpdateScrollOffsetMapEntry(int key,
+ ScrollOffsetMap* new_scroll_offset_map,
+ LayerTreeImpl* layer_tree_impl);
};
class CC_EXPORT PropertyTrees final {
@@ -596,6 +625,8 @@ class CC_EXPORT PropertyTrees final {
// individual nodes.
bool full_tree_damaged;
int sequence_number;
+ bool is_main_thread;
+ bool is_active;
enum ResetFlags { EFFECT_TREE, TRANSFORM_TREE, ALL_TREES };
void SetInnerViewportContainerBoundsDelta(gfx::Vector2dF bounds_delta);
diff --git a/cc/trees/property_tree_builder.cc b/cc/trees/property_tree_builder.cc
index 976e076..14338a4 100644
--- a/cc/trees/property_tree_builder.cc
+++ b/cc/trees/property_tree_builder.cc
@@ -715,6 +715,11 @@ void AddScrollNodeIfNeeded(
node.data.main_thread_scrolling_reasons;
data_for_children->scroll_tree_parent_created_by_uninheritable_criteria =
scroll_node_uninheritable_criteria;
+
+ if (node.data.scrollable) {
+ data_for_children->scroll_tree->synced_scroll_offset(layer->id())
+ ->PushFromMainThread(layer->CurrentScrollOffset());
+ }
}
layer->SetScrollTreeIndex(data_for_children->scroll_tree_parent);
@@ -959,6 +964,8 @@ void PropertyTreeBuilder::BuildPropertyTrees(
const gfx::Rect& viewport,
const gfx::Transform& device_transform,
PropertyTrees* property_trees) {
+ property_trees->is_main_thread = true;
+ property_trees->is_active = false;
SkColor color = root_layer->layer_tree_host()->background_color();
if (SkColorGetA(color) != 255)
color = SkColorSetA(color, 255);
@@ -981,6 +988,8 @@ void PropertyTreeBuilder::BuildPropertyTrees(
const gfx::Rect& viewport,
const gfx::Transform& device_transform,
PropertyTrees* property_trees) {
+ property_trees->is_main_thread = false;
+ property_trees->is_active = root_layer->IsActive();
SkColor color = root_layer->layer_tree_impl()->background_color();
if (SkColorGetA(color) != 255)
color = SkColorSetA(color, 255);
diff --git a/cc/trees/property_tree_unittest.cc b/cc/trees/property_tree_unittest.cc
index cf682a9..0d70672 100644
--- a/cc/trees/property_tree_unittest.cc
+++ b/cc/trees/property_tree_unittest.cc
@@ -260,7 +260,9 @@ TEST(PropertyTreeSerializationTest, ScrollNodeSerialization) {
}
TEST(PropertyTreeSerializationTest, ScrollTreeSerialization) {
- ScrollTree original;
+ PropertyTrees property_trees;
+ property_trees.is_main_thread = true;
+ ScrollTree& original = property_trees.scroll_tree;
ScrollNode second;
second.data.scrollable = true;
second.data.bounds = gfx::Size(15, 15);
@@ -270,6 +272,9 @@ TEST(PropertyTreeSerializationTest, ScrollTreeSerialization) {
original.Insert(second, 0);
original.Insert(third, 1);
+ original.set_currently_scrolling_node(1);
+ original.synced_scroll_offset(1)->PushFromMainThread(gfx::ScrollOffset(1, 2));
+
proto::PropertyTree proto;
original.ToProtobuf(&proto);
ScrollTree result;
diff --git a/cc/trees/tree_synchronizer_unittest.cc b/cc/trees/tree_synchronizer_unittest.cc
index 95f5f9c..417cda5 100644
--- a/cc/trees/tree_synchronizer_unittest.cc
+++ b/cc/trees/tree_synchronizer_unittest.cc
@@ -219,6 +219,24 @@ class TreeSynchronizerTest : public testing::Test {
TestTaskGraphRunner task_graph_runner_;
scoped_ptr<FakeLayerTreeHost> host_;
LayerSettings layer_settings_;
+
+ bool is_equal(ScrollTree::ScrollOffsetMap map,
+ ScrollTree::ScrollOffsetMap other) {
+ if (map.size() != other.size())
+ return false;
+ for (auto& map_entry : map) {
+ if (other.find(map_entry.first) == other.end())
+ return false;
+ SyncedScrollOffset& from_map = *map_entry.second.get();
+ SyncedScrollOffset& from_other = *other[map_entry.first].get();
+ if (from_map.PendingBase() != from_other.PendingBase() ||
+ from_map.ActiveBase() != from_other.ActiveBase() ||
+ from_map.Delta() != from_other.Delta() ||
+ from_map.PendingDelta().get() != from_other.PendingDelta().get())
+ return false;
+ }
+ return true;
+ }
};
// Attempts to synchronizes a null tree. This should not crash, and should
@@ -800,5 +818,102 @@ TEST_F(TreeSynchronizerTest, SynchronizeCurrentlyScrollingNode) {
host_impl->active_tree()->CurrentlyScrollingLayer()->id());
}
+TEST_F(TreeSynchronizerTest, SynchronizeScrollTreeScrollOffsetMap) {
+ host_->InitializeSingleThreaded(&client_, base::ThreadTaskRunnerHandle::Get(),
+ nullptr);
+ LayerTreeSettings settings;
+ FakeLayerTreeHostImplClient client;
+ FakeImplTaskRunnerProvider task_runner_provider;
+ FakeRenderingStatsInstrumentation stats_instrumentation;
+ TestSharedBitmapManager shared_bitmap_manager;
+ TestTaskGraphRunner task_graph_runner;
+ FakeLayerTreeHostImpl* host_impl = host_->host_impl();
+ host_impl->CreatePendingTree();
+
+ scoped_refptr<Layer> layer_tree_root = Layer::Create(layer_settings_);
+ scoped_refptr<Layer> scroll_clip_layer = Layer::Create(layer_settings_);
+ scoped_refptr<Layer> scroll_layer = Layer::Create(layer_settings_);
+ scoped_refptr<Layer> transient_scroll_clip_layer =
+ Layer::Create(layer_settings_);
+ scoped_refptr<Layer> transient_scroll_layer = Layer::Create(layer_settings_);
+
+ layer_tree_root->AddChild(transient_scroll_clip_layer);
+ transient_scroll_clip_layer->AddChild(transient_scroll_layer);
+ transient_scroll_layer->AddChild(scroll_clip_layer);
+ scroll_clip_layer->AddChild(scroll_layer);
+
+ transient_scroll_layer->SetScrollClipLayerId(
+ transient_scroll_clip_layer->id());
+ scroll_layer->SetScrollClipLayerId(scroll_clip_layer->id());
+ transient_scroll_layer->SetScrollOffset(gfx::ScrollOffset(1, 2));
+ scroll_layer->SetScrollOffset(gfx::ScrollOffset(10, 20));
+
+ host_->SetRootLayer(layer_tree_root);
+ host_->BuildPropertyTreesForTesting();
+ host_->CommitAndCreatePendingTree();
+ host_impl->ActivateSyncTree();
+
+ ExpectTreesAreIdentical(layer_tree_root.get(),
+ host_impl->active_tree()->root_layer(),
+ host_impl->active_tree());
+
+ // After the initial commit, scroll_offset_map in scroll_tree is expected to
+ // have one entry for scroll_layer and one entry for transient_scroll_layer,
+ // the pending base and active base must be the same at this stage.
+ ScrollTree::ScrollOffsetMap scroll_offset_map;
+ scroll_offset_map[scroll_layer->id()] = new SyncedScrollOffset;
+ scroll_offset_map[transient_scroll_layer->id()] = new SyncedScrollOffset;
+ scroll_offset_map[scroll_layer->id()]->PushFromMainThread(
+ scroll_layer->scroll_offset());
+ scroll_offset_map[scroll_layer->id()]->PushPendingToActive();
+ scroll_offset_map[transient_scroll_layer->id()]->PushFromMainThread(
+ transient_scroll_layer->scroll_offset());
+ scroll_offset_map[transient_scroll_layer->id()]->PushPendingToActive();
+ EXPECT_TRUE(
+ is_equal(scroll_offset_map, host_impl->active_tree()
+ ->property_trees()
+ ->scroll_tree.scroll_offset_map()));
+
+ // Set ScrollOffset active delta: gfx::ScrollOffset(10, 10)
+ LayerImpl* scroll_layer_impl =
+ host_impl->active_tree()->LayerById(scroll_layer->id());
+ ScrollTree& scroll_tree =
+ host_impl->active_tree()->property_trees()->scroll_tree;
+ scroll_tree.synced_scroll_offset(scroll_layer_impl->id())
+ ->SetCurrent(gfx::ScrollOffset(20, 30));
+
+ // Pull ScrollOffset delta for main thread, and change offset on main thread
+ scoped_ptr<ScrollAndScaleSet> scroll_info(new ScrollAndScaleSet());
+ scroll_tree.CollectScrollDeltas(scroll_info.get());
+ host_->proxy()->SetNeedsCommit();
+ host_->ApplyScrollAndScale(scroll_info.get());
+ EXPECT_EQ(gfx::ScrollOffset(20, 30), scroll_layer->scroll_offset());
+ scroll_layer->SetScrollOffset(gfx::ScrollOffset(100, 100));
+
+ // More update to ScrollOffset active delta: gfx::ScrollOffset(20, 20)
+ scroll_tree.synced_scroll_offset(scroll_layer_impl->id())
+ ->SetCurrent(gfx::ScrollOffset(40, 50));
+ host_impl->active_tree()->SetCurrentlyScrollingLayer(scroll_layer_impl);
+
+ // Make one layer unscrollable so that scroll tree topology changes
+ transient_scroll_layer->SetScrollClipLayerId(Layer::INVALID_ID);
+ host_->BuildPropertyTreesForTesting();
+
+ host_impl->CreatePendingTree();
+ host_->CommitAndCreatePendingTree();
+ host_impl->ActivateSyncTree();
+
+ EXPECT_EQ(scroll_layer->id(),
+ host_impl->active_tree()->CurrentlyScrollingLayer()->id());
+ scroll_offset_map.erase(transient_scroll_layer->id());
+ scroll_offset_map[scroll_layer->id()]->SetCurrent(gfx::ScrollOffset(20, 30));
+ scroll_offset_map[scroll_layer->id()]->PullDeltaForMainThread();
+ scroll_offset_map[scroll_layer->id()]->SetCurrent(gfx::ScrollOffset(40, 50));
+ scroll_offset_map[scroll_layer->id()]->PushFromMainThread(
+ gfx::ScrollOffset(100, 100));
+ scroll_offset_map[scroll_layer->id()]->PushPendingToActive();
+ EXPECT_TRUE(is_equal(scroll_offset_map, scroll_tree.scroll_offset_map()));
+}
+
} // namespace
} // namespace cc