| Index: cc/trees/property_tree.cc
|
| diff --git a/cc/trees/property_tree.cc b/cc/trees/property_tree.cc
|
| index f1dd7cad45cf797129406ddc3732832eb40774de..1f84d3e85199953f5b147e6701acc0fe0f2de539 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"
|
| @@ -346,10 +347,11 @@ void TransformTree::UpdateLocalTransform(TransformNode* node) {
|
| else if (node->affected_by_outer_viewport_bounds_delta_y)
|
| fixed_position_adjustment.set_y(outer_viewport_bounds_delta.y());
|
|
|
| - transform.Translate(node->source_to_parent.x() - node->scroll_offset.x() +
|
| - fixed_position_adjustment.x(),
|
| - node->source_to_parent.y() - node->scroll_offset.y() +
|
| - fixed_position_adjustment.y());
|
| + transform.Translate(
|
| + node->source_to_parent.x() - node->scroll_offset_with_overscroll.x() +
|
| + fixed_position_adjustment.x(),
|
| + node->source_to_parent.y() - node->scroll_offset_with_overscroll.y() +
|
| + fixed_position_adjustment.y());
|
| transform.PreconcatTransform(node->local);
|
| transform.PreconcatTransform(node->pre_local);
|
| node->set_to_parent(transform);
|
| @@ -1028,6 +1030,11 @@ void EffectTree::FromProtobuf(
|
| }
|
| }
|
|
|
| +ScrollTree::ScrollWithOverscroll::ScrollWithOverscroll() {}
|
| +ScrollTree::ScrollWithOverscroll::ScrollWithOverscroll(
|
| + ScrollWithOverscroll&& rhs) = default;
|
| +ScrollTree::ScrollWithOverscroll::~ScrollWithOverscroll() {}
|
| +
|
| ScrollTree::ScrollTree()
|
| : currently_scrolling_node_id_(-1),
|
| layer_id_to_scroll_offset_map_(ScrollTree::ScrollOffsetMap()) {}
|
| @@ -1036,7 +1043,13 @@ ScrollTree::~ScrollTree() {}
|
|
|
| ScrollTree& ScrollTree::operator=(const ScrollTree& from) {
|
| PropertyTree::operator=(from);
|
| - currently_scrolling_node_id_ = -1;
|
| +
|
| + // Keep |currently_scrolling_node_id_| as-is. If it's cleared, the scrolling
|
| + // node in the ScrollTree will get out of sync with what's done in
|
| + // LayerTreeImpl::SetCurrentlyScrollingLayer() whenever triggering a
|
| + // FinishCommitOnImplThread(), which would require every scroll event to
|
| + // perform another hit-test.
|
| +
|
| // 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.
|
| @@ -1048,15 +1061,16 @@ ScrollTree& ScrollTree::operator=(const ScrollTree& from) {
|
| }
|
|
|
| bool ScrollTree::operator==(const ScrollTree& other) const {
|
| - const ScrollTree::ScrollOffsetMap& other_scroll_offset_map =
|
| - other.scroll_offset_map();
|
| + const ScrollOffsetMap& other_scroll_offset_map =
|
| + other.layer_id_to_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_) {
|
| + for (const 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))
|
| + auto other_entry_it = other_scroll_offset_map.find(key);
|
| + if (other_entry_it == other_scroll_offset_map.end() ||
|
| + map_entry.second != other_entry_it->second)
|
| return false;
|
| }
|
|
|
| @@ -1078,13 +1092,15 @@ 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_) {
|
| + for (const 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());
|
| + SyncedScrollOffsetToProto(*i.second.synced_offset.get(),
|
| + entry->mutable_scroll_offset());
|
| + ScrollOffsetToProto(i.second.overscroll, entry->mutable_overscroll());
|
| }
|
| }
|
|
|
| @@ -1105,10 +1121,11 @@ void ScrollTree::FromProtobuf(
|
| 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());
|
| + ScrollWithOverscroll* scroll = GetOrCreate(entry.layer_id());
|
| + scroll->synced_offset = new SyncedScrollOffset();
|
| + ProtoToSyncedScrollOffset(entry.scroll_offset(),
|
| + scroll->synced_offset.get());
|
| + scroll->overscroll = ProtoToScrollOffset(entry.overscroll());
|
| }
|
| }
|
|
|
| @@ -1205,27 +1222,43 @@ gfx::Transform ScrollTree::ScreenSpaceTransform(int scroll_node_id) const {
|
| return screen_space_transform;
|
| }
|
|
|
| -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;
|
| +ScrollTree::ScrollWithOverscroll* ScrollTree::GetOrCreate(int layer_id) {
|
| + auto it = layer_id_to_scroll_offset_map_.find(layer_id);
|
| + if (it == layer_id_to_scroll_offset_map_.end()) {
|
| + it =
|
| + layer_id_to_scroll_offset_map_.emplace(layer_id, ScrollWithOverscroll())
|
| + .first;
|
| + it->second.synced_offset = new SyncedScrollOffset;
|
| }
|
| - return layer_id_to_scroll_offset_map_[layer_id].get();
|
| + return &it->second;
|
| }
|
|
|
| -const SyncedScrollOffset* ScrollTree::synced_scroll_offset(int layer_id) const {
|
| - if (layer_id_to_scroll_offset_map_.find(layer_id) ==
|
| - layer_id_to_scroll_offset_map_.end()) {
|
| +const ScrollTree::ScrollWithOverscroll* ScrollTree::GetOrNull(
|
| + int layer_id) const {
|
| + auto it = layer_id_to_scroll_offset_map_.find(layer_id);
|
| + if (it == layer_id_to_scroll_offset_map_.end())
|
| return nullptr;
|
| - }
|
| - return layer_id_to_scroll_offset_map_.at(layer_id).get();
|
| + return &it->second;
|
| +}
|
| +
|
| +SyncedScrollOffset* ScrollTree::synced_scroll_offset(int layer_id) {
|
| + return GetOrCreate(layer_id)->synced_offset.get();
|
| +}
|
| +
|
| +const SyncedScrollOffset* ScrollTree::synced_scroll_offset(int layer_id) const {
|
| + const ScrollWithOverscroll* scroll = GetOrNull(layer_id);
|
| + return scroll ? scroll->synced_offset.get() : nullptr;
|
| }
|
|
|
| const gfx::ScrollOffset ScrollTree::current_scroll_offset(int layer_id) const {
|
| - return synced_scroll_offset(layer_id)
|
| - ? synced_scroll_offset(layer_id)->Current(
|
| - property_trees()->is_active)
|
| - : gfx::ScrollOffset();
|
| + const ScrollWithOverscroll* scroll = GetOrNull(layer_id);
|
| + return scroll ? scroll->synced_offset->Current(property_trees()->is_active)
|
| + : gfx::ScrollOffset();
|
| +}
|
| +
|
| +const gfx::ScrollOffset ScrollTree::current_overscroll(int layer_id) const {
|
| + const ScrollWithOverscroll* scroll = GetOrNull(layer_id);
|
| + return scroll ? scroll->overscroll : gfx::ScrollOffset();
|
| }
|
|
|
| gfx::ScrollOffset ScrollTree::PullDeltaForMainThread(
|
| @@ -1249,64 +1282,72 @@ gfx::ScrollOffset ScrollTree::PullDeltaForMainThread(
|
|
|
| void ScrollTree::CollectScrollDeltas(ScrollAndScaleSet* scroll_info,
|
| int inner_viewport_layer_id) {
|
| - for (auto map_entry : layer_id_to_scroll_offset_map_) {
|
| + for (const auto& map_entry : layer_id_to_scroll_offset_map_) {
|
| gfx::ScrollOffset scroll_delta =
|
| - PullDeltaForMainThread(map_entry.second.get());
|
| -
|
| + PullDeltaForMainThread(map_entry.second.synced_offset.get());
|
| + gfx::ScrollOffset overscroll = map_entry.second.overscroll;
|
| gfx::Vector2d scroll_delta_vector(scroll_delta.x(), scroll_delta.y());
|
| int layer_id = map_entry.first;
|
|
|
| - if (!scroll_delta.IsZero()) {
|
| + if (!scroll_delta.IsZero() || !overscroll.IsZero()) {
|
| if (layer_id == inner_viewport_layer_id) {
|
| // Inner (visual) viewport is stored separately.
|
| scroll_info->inner_viewport_scroll.layer_id = layer_id;
|
| scroll_info->inner_viewport_scroll.scroll_delta = scroll_delta_vector;
|
| + scroll_info->inner_viewport_scroll.overscroll = overscroll;
|
| } else {
|
| LayerTreeHostCommon::ScrollUpdateInfo scroll;
|
| scroll.layer_id = layer_id;
|
| scroll.scroll_delta = scroll_delta_vector;
|
| - scroll_info->scrolls.push_back(scroll);
|
| + scroll.overscroll = overscroll;
|
| + scroll_info->scrolls.push_back(std::move(scroll));
|
| }
|
| }
|
| }
|
| }
|
|
|
| void ScrollTree::CollectScrollDeltasForTesting() {
|
| - for (auto map_entry : layer_id_to_scroll_offset_map_) {
|
| - PullDeltaForMainThread(map_entry.second.get());
|
| + for (const auto& map_entry : layer_id_to_scroll_offset_map_) {
|
| + PullDeltaForMainThread(map_entry.second.synced_offset.get());
|
| }
|
| }
|
|
|
| void ScrollTree::UpdateScrollOffsetMapEntry(
|
| int key,
|
| - ScrollTree::ScrollOffsetMap* new_scroll_offset_map,
|
| + 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.
|
| + ScrollWithOverscroll& other_scroll = new_scroll_offset_map->at(key);
|
| if (!property_trees()->is_active) {
|
| - changed = synced_scroll_offset(key)->PushFromMainThread(
|
| - new_scroll_offset_map->at(key)->PendingBase());
|
| + ScrollWithOverscroll& this_scroll = *GetOrCreate(key);
|
| + changed = this_scroll.synced_offset->PushFromMainThread(
|
| + other_scroll.synced_offset->PendingBase());
|
|
|
| - if (new_scroll_offset_map->at(key)->clobber_active_value()) {
|
| - synced_scroll_offset(key)->set_clobber_active_value();
|
| + if (other_scroll.synced_offset->clobber_active_value()) {
|
| + this_scroll.synced_offset->set_clobber_active_value();
|
| }
|
| + changed |= this_scroll.overscroll != other_scroll.overscroll;
|
| + this_scroll.overscroll = other_scroll.overscroll;
|
| if (changed) {
|
| layer_tree_impl->DidUpdateScrollOffset(key, -1);
|
| }
|
| } else {
|
| - layer_id_to_scroll_offset_map_[key] = new_scroll_offset_map->at(key);
|
| - changed |= synced_scroll_offset(key)->PushPendingToActive();
|
| - if (changed) {
|
| + ScrollWithOverscroll& this_scroll = layer_id_to_scroll_offset_map_[key];
|
| + this_scroll.synced_offset = other_scroll.synced_offset;
|
| + // Nothing to do for overscroll.
|
| + changed |= this_scroll.synced_offset->PushPendingToActive();
|
| + if (changed)
|
| layer_tree_impl->DidUpdateScrollOffset(key, -1);
|
| - }
|
| }
|
| }
|
|
|
| -void ScrollTree::UpdateScrollOffsetMap(
|
| - ScrollTree::ScrollOffsetMap* new_scroll_offset_map,
|
| - LayerTreeImpl* layer_tree_impl) {
|
| +void ScrollTree::UpdateScrollOffsetMap(ScrollTree* scroll_tree,
|
| + LayerTreeImpl* layer_tree_impl) {
|
| + ScrollOffsetMap* new_scroll_offset_map =
|
| + &scroll_tree->layer_id_to_scroll_offset_map_;
|
| if (layer_tree_impl && !layer_tree_impl->LayerListIsEmpty()) {
|
| DCHECK(!property_trees()->is_main_thread);
|
| for (auto map_entry = layer_id_to_scroll_offset_map_.begin();
|
| @@ -1329,32 +1370,41 @@ void ScrollTree::UpdateScrollOffsetMap(
|
| }
|
| }
|
|
|
| -ScrollTree::ScrollOffsetMap& ScrollTree::scroll_offset_map() {
|
| - return layer_id_to_scroll_offset_map_;
|
| -}
|
| -
|
| -const ScrollTree::ScrollOffsetMap& ScrollTree::scroll_offset_map() const {
|
| +const ScrollTree::ScrollOffsetMap& ScrollTree::scroll_offset_map_for_test()
|
| + 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();
|
| + map_entry.second.synced_offset->AbortCommit();
|
| }
|
|
|
| -bool ScrollTree::SetBaseScrollOffset(int layer_id,
|
| - const gfx::ScrollOffset& scroll_offset) {
|
| - return synced_scroll_offset(layer_id)->PushFromMainThread(scroll_offset);
|
| +void ScrollTree::SetBaseScrollOffset(int layer_id,
|
| + const gfx::ScrollOffset& scroll_offset,
|
| + const gfx::ScrollOffset& overscroll) {
|
| + ScrollWithOverscroll* scroll = GetOrCreate(layer_id);
|
| + scroll->overscroll = overscroll;
|
| + scroll->synced_offset->PushFromMainThread(scroll_offset);
|
| }
|
|
|
| bool ScrollTree::SetScrollOffset(int layer_id,
|
| - const gfx::ScrollOffset& scroll_offset) {
|
| + const gfx::ScrollOffset& scroll_offset,
|
| + const gfx::ScrollOffset& overscroll) {
|
| + ScrollWithOverscroll* scroll = GetOrCreate(layer_id);
|
| + bool change = scroll->overscroll != overscroll;
|
| + scroll->overscroll = overscroll;
|
| +
|
| if (property_trees()->is_main_thread)
|
| - return synced_scroll_offset(layer_id)->PushFromMainThread(scroll_offset);
|
| + change |= 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;
|
| + change |= synced_scroll_offset(layer_id)->SetCurrent(scroll_offset);
|
| + return change;
|
| +}
|
| +
|
| +void ScrollTree::SetScrollOffsetClobberActiveValue(int layer_id) {
|
| + GetOrCreate(layer_id)->synced_offset->set_clobber_active_value();
|
| }
|
|
|
| bool ScrollTree::UpdateScrollOffsetBaseForTesting(
|
| @@ -1426,9 +1476,11 @@ gfx::Vector2dF ScrollTree::ScrollBy(ScrollNode* scroll_node,
|
| gfx::ScrollOffset old_offset = current_scroll_offset(scroll_node->owner_id);
|
| gfx::ScrollOffset new_offset =
|
| ClampScrollOffsetToLimits(old_offset + adjusted_scroll, scroll_node);
|
| - if (SetScrollOffset(scroll_node->owner_id, new_offset))
|
| + gfx::ScrollOffset overscroll = current_overscroll(scroll_node->owner_id);
|
| + if (SetScrollOffset(scroll_node->owner_id, new_offset, overscroll)) {
|
| layer_tree_impl->DidUpdateScrollOffset(scroll_node->owner_id,
|
| scroll_node->transform_id);
|
| + }
|
|
|
| gfx::ScrollOffset unscrolled =
|
| old_offset + gfx::ScrollOffset(scroll) - new_offset;
|
|
|