Update InnerViewportContainerLayer size when top controls move.
At present, when Clank's top controls move, the InnerViewportContainerLayer
size is not updated immediately, leading to incorrect results from
LayerImpl::MaxScrollOffset() until the resize occurs. This allows scrolling
past the end of the page in the case where the top-controls are hidden
during a single scroll that reaches the bottom of the document.
This CL updates the InnerViewportContainerLayer size on the impl thread
each time the top controls move in order to eliminate this problem. The
mechanism for computing scrollbar vertical adjust has also been updated
to account for this.
Also, this CL makes the previous FixedPositionContainerSizeDelta
computation redundant, and it has been removed.
BUG=342857
Review URL: https://codereview.chromium.org/171813008
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@253743 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc
index c5b0f1cc..204d907 100644
--- a/cc/layers/layer.cc
+++ b/cc/layers/layer.cc
@@ -944,7 +944,6 @@
layer->SetPosition(position_);
layer->SetIsContainerForFixedPositionLayers(
IsContainerForFixedPositionLayers());
- layer->SetFixedContainerSizeDelta(gfx::Vector2dF());
layer->SetPositionConstraint(position_constraint_);
layer->SetShouldFlattenTransform(should_flatten_transform_);
layer->SetIs3dSorted(is_3d_sorted_);
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc
index 731aaab..2167341 100644
--- a/cc/layers/layer_impl.cc
+++ b/cc/layers/layer_impl.cc
@@ -31,6 +31,7 @@
#include "ui/gfx/point_conversions.h"
#include "ui/gfx/quad_f.h"
#include "ui/gfx/rect_conversions.h"
+#include "ui/gfx/size_conversions.h"
namespace cc {
LayerImpl::LayerImpl(LayerTreeImpl* tree_impl, int id)
@@ -552,7 +553,6 @@
layer->SetPosition(position_);
layer->SetIsContainerForFixedPositionLayers(
is_container_for_fixed_position_layers_);
- layer->SetFixedContainerSizeDelta(fixed_container_size_delta_);
layer->SetPositionConstraint(position_constraint_);
layer->SetShouldFlattenTransform(should_flatten_transform_);
layer->SetIs3dSorted(is_3d_sorted_);
@@ -614,6 +614,30 @@
num_dependents_need_push_properties_ = 0;
}
+gfx::Vector2dF LayerImpl::FixedContainerSizeDelta() const {
+ if (!scroll_clip_layer_)
+ return gfx::Vector2dF();
+
+ float scale_delta = layer_tree_impl()->page_scale_delta();
+ float scale = layer_tree_impl()->page_scale_factor();
+
+ gfx::Vector2dF delta_from_scroll = scroll_clip_layer_->BoundsDelta();
+ delta_from_scroll.Scale(1.f / scale);
+
+ // The delta-from-pinch component requires some explanation: A viewport of
+ // size (w,h) will appear to be size (w/s,h/s) under scale s in the content
+ // space. If s -> s' on the impl thread, where s' = s * ds, then the apparent
+ // viewport size change in the content space due to ds is:
+ //
+ // (w/s',h/s') - (w/s,h/s) = (w,h)(1/s' - 1/s) = (w,h)(1 - ds)/(s ds)
+ //
+ gfx::Vector2dF delta_from_pinch =
+ gfx::Rect(scroll_clip_layer_->bounds()).bottom_right() - gfx::PointF();
+ delta_from_pinch.Scale((1.f - scale_delta) / (scale * scale_delta));
+
+ return delta_from_scroll + delta_from_pinch;
+}
+
base::DictionaryValue* LayerImpl::LayerTreeAsJson() const {
base::DictionaryValue* result = new base::DictionaryValue;
result->SetString("LayerType", LayerTypeAsString());
@@ -757,11 +781,30 @@
return layer_tree_impl_->IsActiveTree();
}
+// TODO(wjmaclean) Convert so that bounds returns SizeF.
+gfx::Size LayerImpl::bounds() const {
+ return ToFlooredSize(temporary_impl_bounds_);
+}
+
void LayerImpl::SetBounds(const gfx::Size& bounds) {
if (bounds_ == bounds)
return;
bounds_ = bounds;
+ temporary_impl_bounds_ = bounds;
+
+ ScrollbarParametersDidChange();
+ if (masks_to_bounds())
+ NoteLayerPropertyChangedForSubtree();
+ else
+ NoteLayerPropertyChanged();
+}
+
+void LayerImpl::SetTemporaryImplBounds(const gfx::SizeF& bounds) {
+ if (temporary_impl_bounds_ == bounds)
+ return;
+
+ temporary_impl_bounds_ = bounds;
ScrollbarParametersDidChange();
if (masks_to_bounds())
@@ -1178,10 +1221,6 @@
scaled_scroll_bounds.SetSize(scale_factor * scaled_scroll_bounds.width(),
scale_factor * scaled_scroll_bounds.height());
- gfx::RectF clip_rect(gfx::PointF(), scroll_clip_layer_->bounds());
- if (this == layer_tree_impl()->InnerViewportScrollLayer())
- clip_rect =
- gfx::RectF(gfx::PointF(), layer_tree_impl()->ScrollableViewportSize());
gfx::Vector2dF max_offset(
scaled_scroll_bounds.width() - scroll_clip_layer_->bounds().width(),
scaled_scroll_bounds.height() - scroll_clip_layer_->bounds().height());
diff --git a/cc/layers/layer_impl.h b/cc/layers/layer_impl.h
index 26c23c9..c86c5543 100644
--- a/cc/layers/layer_impl.h
+++ b/cc/layers/layer_impl.h
@@ -248,12 +248,7 @@
return is_container_for_fixed_position_layers_;
}
- void SetFixedContainerSizeDelta(const gfx::Vector2dF& delta) {
- fixed_container_size_delta_ = delta;
- }
- gfx::Vector2dF fixed_container_size_delta() const {
- return fixed_container_size_delta_;
- }
+ gfx::Vector2dF FixedContainerSizeDelta() const;
void SetPositionConstraint(const LayerPositionConstraint& constraint) {
position_constraint_ = constraint;
@@ -342,7 +337,12 @@
// them from the other values.
void SetBounds(const gfx::Size& bounds);
- gfx::Size bounds() const { return bounds_; }
+ void SetTemporaryImplBounds(const gfx::SizeF& bounds);
+ gfx::Size bounds() const;
+ gfx::Vector2dF BoundsDelta() const {
+ return gfx::Vector2dF(temporary_impl_bounds_.width() - bounds_.width(),
+ temporary_impl_bounds_.height() - bounds_.height());
+ }
void SetContentBounds(const gfx::Size& content_bounds);
gfx::Size content_bounds() const { return draw_properties_.content_bounds; }
@@ -385,6 +385,7 @@
gfx::Vector2dF ScrollBy(const gfx::Vector2dF& scroll);
void SetScrollClipLayer(int scroll_clip_layer_id);
+ LayerImpl* scroll_clip_layer() const { return scroll_clip_layer_; }
bool scrollable() const { return !!scroll_clip_layer_; }
void set_user_scrollable_horizontal(bool scrollable) {
@@ -575,6 +576,7 @@
gfx::PointF anchor_point_;
float anchor_point_z_;
gfx::Size bounds_;
+ gfx::SizeF temporary_impl_bounds_;
gfx::Vector2d scroll_offset_;
LayerScrollOffsetDelegate* scroll_offset_delegate_;
LayerImpl* scroll_clip_layer_;
@@ -612,10 +614,6 @@
gfx::PointF position_;
gfx::Transform transform_;
- // This property is effective when
- // is_container_for_fixed_position_layers_ == true,
- gfx::Vector2dF fixed_container_size_delta_;
-
LayerPositionConstraint position_constraint_;
gfx::Vector2dF scroll_delta_;
diff --git a/cc/layers/layer_position_constraint_unittest.cc b/cc/layers/layer_position_constraint_unittest.cc
index 4a41c79..84bf9446 100644
--- a/cc/layers/layer_position_constraint_unittest.cc
+++ b/cc/layers/layer_position_constraint_unittest.cc
@@ -143,6 +143,21 @@
LayerPositionConstraint fixed_to_bottom_right_;
};
+namespace {
+
+void SetFixedContainerSizeDelta(LayerImpl* scroll_layer,
+ const gfx::Vector2d& delta) {
+ DCHECK(scroll_layer);
+ DCHECK(scroll_layer->scrollable());
+
+ LayerImpl* container_layer = scroll_layer->scroll_clip_layer();
+ gfx::Size container_size(container_layer->bounds());
+ gfx::Size new_container_size(container_size.width() + delta.x(),
+ container_size.height() + delta.y());
+ container_layer->SetTemporaryImplBounds(new_container_size);
+}
+} // namespace
+
TEST_F(LayerPositionConstraintTest,
ScrollCompensationForFixedPositionLayerWithDirectContainer) {
// This test checks for correct scroll compensation when the fixed-position
@@ -180,7 +195,7 @@
grand_child->draw_transform());
// Case 3: fixed-container size delta of 20, 20
- child->SetFixedContainerSizeDelta(gfx::Vector2d(20, 20));
+ SetFixedContainerSizeDelta(child, gfx::Vector2d(20, 20));
ExecuteCalculateDrawProperties(root_.get());
// Top-left fixed-position layer should not be affected by container size.
@@ -257,7 +272,7 @@
grand_child->draw_transform());
// Case 3: fixed-container size delta of 20, 20
- child->SetFixedContainerSizeDelta(gfx::Vector2d(20, 20));
+ SetFixedContainerSizeDelta(child, gfx::Vector2d(20, 20));
ExecuteCalculateDrawProperties(root_.get());
// Top-left fixed-position layer should not be affected by container size.
@@ -331,7 +346,7 @@
great_grand_child->draw_transform());
// Case 3: fixed-container size delta of 20, 20
- child->SetFixedContainerSizeDelta(gfx::Vector2d(20, 20));
+ SetFixedContainerSizeDelta(child, gfx::Vector2d(20, 20));
ExecuteCalculateDrawProperties(root_.get());
// Top-left fixed-position layer should not be affected by container size.
@@ -435,7 +450,7 @@
great_grand_child->draw_transform());
// Case 3: fixed-container size delta of 20, 20
- child->SetFixedContainerSizeDelta(gfx::Vector2d(20, 20));
+ SetFixedContainerSizeDelta(child, gfx::Vector2d(20, 20));
ExecuteCalculateDrawProperties(root_.get());
// Top-left fixed-position layer should not be affected by container size.
@@ -550,7 +565,7 @@
great_grand_child->draw_transform());
// Case 3: fixed-container size delta of 20, 20
- child->SetFixedContainerSizeDelta(gfx::Vector2d(20, 20));
+ SetFixedContainerSizeDelta(child, gfx::Vector2d(20, 20));
ExecuteCalculateDrawProperties(root_.get());
// Top-left fixed-position layer should not be affected by container size.
@@ -669,7 +684,7 @@
great_grand_child->draw_transform());
// Case 3: fixed-container size delta of 20, 20
- child->SetFixedContainerSizeDelta(gfx::Vector2d(20, 20));
+ SetFixedContainerSizeDelta(child, gfx::Vector2d(20, 20));
ExecuteCalculateDrawProperties(root_.get());
// Top-left fixed-position layer should not be affected by container size.
@@ -855,7 +870,7 @@
// Case 3: fixed-container size delta of 20, 20
- child->SetFixedContainerSizeDelta(gfx::Vector2d(20, 20));
+ SetFixedContainerSizeDelta(child, gfx::Vector2d(20, 20));
ExecuteCalculateDrawProperties(root_.get());
// Top-left fixed-position layer should not be affected by container size.
@@ -946,7 +961,7 @@
grand_child->draw_transform());
// Case 3: fixed-container size delta of 20, 20
- child->SetFixedContainerSizeDelta(gfx::Vector2d(20, 20));
+ SetFixedContainerSizeDelta(child, gfx::Vector2d(20, 20));
ExecuteCalculateDrawProperties(root_.get());
// Top-left fixed-position layer should not be affected by container size.
@@ -1014,7 +1029,7 @@
grand_child->draw_transform());
// Case 3: fixed-container size delta of 20, 20
- child->SetFixedContainerSizeDelta(gfx::Vector2d(20, 20));
+ SetFixedContainerSizeDelta(child, gfx::Vector2d(20, 20));
ExecuteCalculateDrawProperties(root_.get());
// Top-left fixed-position layer should not be affected by container size.
@@ -1079,7 +1094,7 @@
// Case 2: sizeDelta
child->SetScrollDelta(gfx::Vector2d(0, 0));
- child->SetFixedContainerSizeDelta(gfx::Vector2d(20, 20));
+ SetFixedContainerSizeDelta(child, gfx::Vector2d(20, 20));
ExecuteCalculateDrawProperties(root_.get());
expected_child_transform.MakeIdentity();
diff --git a/cc/trees/layer_tree_host_common.cc b/cc/trees/layer_tree_host_common.cc
index 587a285..41f7ee7 100644
--- a/cc/trees/layer_tree_host_common.cc
+++ b/cc/trees/layer_tree_host_common.cc
@@ -755,7 +755,7 @@
layer->position_constraint().is_fixed_to_right_edge();
bool fixed_to_bottom_edge =
layer->position_constraint().is_fixed_to_bottom_edge();
- gfx::Vector2dF position_offset = container->fixed_container_size_delta();
+ gfx::Vector2dF position_offset = container->FixedContainerSizeDelta();
position_offset.set_x(fixed_to_right_edge ? position_offset.x() : 0);
position_offset.set_y(fixed_to_bottom_edge ? position_offset.y() : 0);
if (position_offset.IsZero())
diff --git a/cc/trees/layer_tree_host_common_perftest.cc b/cc/trees/layer_tree_host_common_perftest.cc
index 03327af..7e50e367 100644
--- a/cc/trees/layer_tree_host_common_perftest.cc
+++ b/cc/trees/layer_tree_host_common_perftest.cc
@@ -131,7 +131,7 @@
host_impl->DrawTransform(),
active_tree->device_scale_factor(),
active_tree->total_page_scale_factor(),
- active_tree->RootContainerLayer(),
+ active_tree->InnerViewportContainerLayer(),
max_texture_size,
host_impl->settings().can_use_lcd_text,
can_render_to_separate_surface,
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index d090ddc3..ad930477 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -1485,23 +1485,43 @@
output_surface_->SetNeedsBeginImplFrame(enable);
}
+gfx::SizeF LayerTreeHostImpl::ComputeInnerViewportContainerSize() const {
+ gfx::SizeF dip_size =
+ gfx::ScaleSize(device_viewport_size_, 1.f / device_scale_factor());
+
+ float top_offset =
+ top_controls_manager_ ? top_controls_manager_->content_top_offset() : 0.f;
+
+ return gfx::SizeF(dip_size.width(),
+ dip_size.height() - top_offset - overdraw_bottom_height_);
+}
+
+void LayerTreeHostImpl::UpdateInnerViewportContainerSize() {
+ LayerImpl* container_layer = active_tree_->InnerViewportContainerLayer();
+ if (!container_layer)
+ return;
+
+ container_layer->SetTemporaryImplBounds(ComputeInnerViewportContainerSize());
+}
+
gfx::SizeF LayerTreeHostImpl::UnscaledScrollableViewportSize() const {
// Use the root container layer bounds if it clips to them, otherwise, the
// true viewport size should be used.
- LayerImpl* container_layer = active_tree_->RootContainerLayer();
+ LayerImpl* container_layer = active_tree_->InnerViewportContainerLayer();
if (container_layer && container_layer->masks_to_bounds()) {
DCHECK(!top_controls_manager_);
DCHECK_EQ(0, overdraw_bottom_height_);
return container_layer->bounds();
}
- gfx::SizeF dip_size =
- gfx::ScaleSize(device_viewport_size_, 1.f / device_scale_factor());
+ return ComputeInnerViewportContainerSize();
+}
- float top_offset =
- top_controls_manager_ ? top_controls_manager_->content_top_offset() : 0.f;
- return gfx::SizeF(dip_size.width(),
- dip_size.height() - top_offset - overdraw_bottom_height_);
+float LayerTreeHostImpl::VerticalAdjust() const {
+ if (!active_tree_->InnerViewportContainerLayer())
+ return 0;
+
+ return active_tree_->InnerViewportContainerLayer()->BoundsDelta().y();
}
void LayerTreeHostImpl::DidLoseOutputSurface() {
@@ -1631,6 +1651,7 @@
stats.impl_stats.rasterize_time);
}
+ UpdateInnerViewportContainerSize();
client_->DidActivatePendingTree();
if (!tree_activation_callback_.is_null())
tree_activation_callback_.Run();
@@ -1937,6 +1958,7 @@
device_viewport_size_ = device_viewport_size;
+ UpdateInnerViewportContainerSize();
client_->OnCanDrawStateChanged(CanDraw());
SetFullRootLayerDamage();
}
@@ -1946,6 +1968,7 @@
return;
overdraw_bottom_height_ = overdraw_bottom_height;
+ UpdateInnerViewportContainerSize();
SetFullRootLayerDamage();
}
@@ -1961,6 +1984,7 @@
return;
device_scale_factor_ = device_scale_factor;
+ UpdateInnerViewportContainerSize();
SetFullRootLayerDamage();
}
@@ -1987,6 +2011,7 @@
}
void LayerTreeHostImpl::DidChangeTopControlsPosition() {
+ UpdateInnerViewportContainerSize();
SetNeedsRedraw();
active_tree_->set_needs_update_draw_properties();
SetFullRootLayerDamage();
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index 4e716b5e..29b2cef8 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -213,6 +213,7 @@
// excludes the URL bar and non-overlay scrollbars and is in DIP (and
// invariant relative to page scale).
gfx::SizeF UnscaledScrollableViewportSize() const;
+ float VerticalAdjust() const;
// RendererClient implementation.
virtual void SetFullRootLayerDamage() OVERRIDE;
@@ -443,6 +444,9 @@
SharedBitmapManager* manager,
int id);
+ gfx::SizeF ComputeInnerViewportContainerSize() const;
+ void UpdateInnerViewportContainerSize();
+
// Virtual for testing.
virtual void AnimateLayers(base::TimeTicks monotonic_time,
base::Time wall_clock_time);
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 9d921e6..2333d97 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -837,25 +837,38 @@
DrawFrame();
EXPECT_EQ(scroll_layer, host_impl_->InnerViewportScrollLayer());
+ LayerImpl* container_layer = scroll_layer->scroll_clip_layer();
+ EXPECT_EQ(gfx::Size(50, 50), container_layer->bounds());
float min_page_scale = 1.f, max_page_scale = 4.f;
+ float page_scale_factor = 1.f;
// The impl-based pinch zoom should adjust the max scroll position.
{
- host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f,
- min_page_scale,
- max_page_scale);
+ host_impl_->active_tree()->SetPageScaleFactorAndLimits(
+ page_scale_factor, min_page_scale, max_page_scale);
host_impl_->active_tree()->SetPageScaleDelta(1.f);
scroll_layer->SetScrollDelta(gfx::Vector2d());
float page_scale_delta = 2.f;
+ gfx::Vector2dF expected_container_size_delta(
+ container_layer->bounds().width(), container_layer->bounds().height());
+ expected_container_size_delta.Scale((1.f - page_scale_delta) /
+ (page_scale_factor * page_scale_delta));
+
host_impl_->ScrollBegin(gfx::Point(50, 50), InputHandler::Gesture);
host_impl_->PinchGestureBegin();
host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(50, 50));
+ // While the gesture is still active, the scroll layer should have a
+ // container size delta = container->bounds() * ((1.f -
+ // page_scale_delta)/())
+ EXPECT_EQ(expected_container_size_delta,
+ scroll_layer->FixedContainerSizeDelta());
host_impl_->PinchGestureEnd();
host_impl_->ScrollEnd();
EXPECT_TRUE(did_request_redraw_);
EXPECT_TRUE(did_request_commit_);
+ EXPECT_EQ(gfx::Size(50, 50), container_layer->bounds());
scoped_ptr<ScrollAndScaleSet> scroll_info =
host_impl_->ProcessScrollDeltas();
@@ -868,9 +881,8 @@
// Scrolling after a pinch gesture should always be in local space. The
// scroll deltas do not have the page scale factor applied.
{
- host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f,
- min_page_scale,
- max_page_scale);
+ host_impl_->active_tree()->SetPageScaleFactorAndLimits(
+ page_scale_factor, min_page_scale, max_page_scale);
host_impl_->active_tree()->SetPageScaleDelta(1.f);
scroll_layer->SetScrollDelta(gfx::Vector2d());
@@ -1906,30 +1918,114 @@
EXPECT_FALSE(did_request_commit_);
}
-TEST_F(LayerTreeHostImplTest, ScrollNonScrollableRootWithTopControls) {
- LayerTreeSettings settings;
- settings.calculate_top_controls_position = true;
- settings.top_controls_height = 50;
+class LayerTreeHostImplTopControlsTest : public LayerTreeHostImplTest {
+ public:
+ LayerTreeHostImplTopControlsTest()
+ // Make the clip size the same as the layer (content) size so the layer is
+ // non-scrollable.
+ : layer_size_(10, 10),
+ clip_size_(layer_size_) {
+ settings_.calculate_top_controls_position = true;
+ settings_.top_controls_height = 50;
- CreateHostImpl(settings, CreateOutputSurface());
+ viewport_size_ =
+ gfx::Size(clip_size_.width(),
+ clip_size_.height() + settings_.top_controls_height);
+ }
- gfx::Size layer_size(10, 10);
- gfx::Size clip_size(5, 5);
- scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1);
- scoped_ptr<LayerImpl> root_clip =
- LayerImpl::Create(host_impl_->active_tree(), 2);
- root_clip->SetBounds(clip_size);
- root->SetScrollClipLayer(root_clip->id());
- root->SetBounds(layer_size);
- root->SetContentBounds(layer_size);
- root->SetPosition(gfx::PointF());
- root->SetAnchorPoint(gfx::PointF());
- root->SetDrawsContent(false);
- int root_id = root->id();
- root_clip->AddChild(root.Pass());
- host_impl_->active_tree()->SetRootLayer(root_clip.Pass());
- host_impl_->active_tree()->SetViewportLayersFromIds(
- root_id, root_id, Layer::INVALID_ID);
+ void SetupTopControlsAndScrollLayer() {
+ CreateHostImpl(settings_, CreateOutputSurface());
+
+ scoped_ptr<LayerImpl> root =
+ LayerImpl::Create(host_impl_->active_tree(), 1);
+ scoped_ptr<LayerImpl> root_clip =
+ LayerImpl::Create(host_impl_->active_tree(), 2);
+ root_clip->SetBounds(clip_size_);
+ root->SetScrollClipLayer(root_clip->id());
+ root->SetBounds(layer_size_);
+ root->SetContentBounds(layer_size_);
+ root->SetPosition(gfx::PointF());
+ root->SetAnchorPoint(gfx::PointF());
+ root->SetDrawsContent(false);
+ root->SetIsContainerForFixedPositionLayers(true);
+ int inner_viewport_scroll_layer_id = root->id();
+ int page_scale_layer_id = root_clip->id();
+ root_clip->AddChild(root.Pass());
+ host_impl_->active_tree()->SetRootLayer(root_clip.Pass());
+ host_impl_->active_tree()->SetViewportLayersFromIds(
+ page_scale_layer_id, inner_viewport_scroll_layer_id, Layer::INVALID_ID);
+ // Set a viewport size that is large enough to contain both the top controls
+ // and some content.
+ host_impl_->SetViewportSize(viewport_size_);
+ LayerImpl* root_clip_ptr = host_impl_->active_tree()->root_layer();
+ EXPECT_EQ(clip_size_, root_clip_ptr->bounds());
+ }
+
+ protected:
+ gfx::Size layer_size_;
+ gfx::Size clip_size_;
+ gfx::Size viewport_size_;
+
+ LayerTreeSettings settings_;
+}; // class LayerTreeHostImplTopControlsTest
+
+TEST_F(LayerTreeHostImplTopControlsTest, ScrollTopControlsByFractionalAmount) {
+ SetupTopControlsAndScrollLayer();
+ DrawFrame();
+
+ EXPECT_EQ(InputHandler::ScrollStarted,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+
+ // Make the test scroll delta a fractional amount, to verify that the
+ // fixed container size delta is (1) non-zero, and (2) fractional, and
+ // (3) matches the movement of the top controls.
+ gfx::Vector2dF top_controls_scroll_delta(0.f, 5.25f);
+ host_impl_->top_controls_manager()->ScrollBegin();
+ host_impl_->top_controls_manager()->ScrollBy(top_controls_scroll_delta);
+ host_impl_->top_controls_manager()->ScrollEnd();
+
+ LayerImpl* inner_viewport_scroll_layer =
+ host_impl_->active_tree()->InnerViewportScrollLayer();
+ DCHECK(inner_viewport_scroll_layer);
+ host_impl_->ScrollEnd();
+ EXPECT_EQ(top_controls_scroll_delta,
+ inner_viewport_scroll_layer->FixedContainerSizeDelta());
+}
+
+TEST_F(LayerTreeHostImplTopControlsTest, ScrollTopControlsWithPageScale) {
+ SetupTopControlsAndScrollLayer();
+ DrawFrame();
+
+ EXPECT_EQ(InputHandler::ScrollStarted,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+
+ float page_scale = 1.5f;
+ host_impl_->active_tree()->SetPageScaleFactorAndLimits(page_scale, 1.f, 2.f);
+
+ gfx::Vector2dF top_controls_scroll_delta(0.f, 5.f);
+ gfx::Vector2dF expected_container_size_delta =
+ ScaleVector2d(top_controls_scroll_delta, 1.f / page_scale);
+ host_impl_->top_controls_manager()->ScrollBegin();
+ host_impl_->top_controls_manager()->ScrollBy(top_controls_scroll_delta);
+ host_impl_->top_controls_manager()->ScrollEnd();
+
+ LayerImpl* inner_viewport_scroll_layer =
+ host_impl_->active_tree()->InnerViewportScrollLayer();
+ DCHECK(inner_viewport_scroll_layer);
+ host_impl_->ScrollEnd();
+
+ // Use a tolerance that requires the container size delta to be within 0.01
+ // pixels.
+ double tolerance = 0.0001;
+ EXPECT_LT(
+ (expected_container_size_delta -
+ inner_viewport_scroll_layer->FixedContainerSizeDelta()).LengthSquared(),
+ tolerance);
+}
+
+TEST_F(LayerTreeHostImplTopControlsTest,
+ ScrollNonScrollableRootWithTopControls) {
+ SetupTopControlsAndScrollLayer();
DrawFrame();
EXPECT_EQ(InputHandler::ScrollStarted,
@@ -1938,13 +2034,44 @@
host_impl_->top_controls_manager()->ScrollBegin();
host_impl_->top_controls_manager()->ScrollBy(gfx::Vector2dF(0.f, 50.f));
host_impl_->top_controls_manager()->ScrollEnd();
- EXPECT_EQ(host_impl_->top_controls_manager()->content_top_offset(), 0.f);
+ EXPECT_EQ(0.f, host_impl_->top_controls_manager()->content_top_offset());
+ // Now that top controls have moved, expect the clip to resize.
+ LayerImpl* root_clip_ptr = host_impl_->active_tree()->root_layer();
+ EXPECT_EQ(viewport_size_, root_clip_ptr->bounds());
host_impl_->ScrollEnd();
EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(),
- InputHandler::Gesture));
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+
+ float scroll_increment_y = -25.f;
+ host_impl_->top_controls_manager()->ScrollBegin();
+ host_impl_->top_controls_manager()->ScrollBy(
+ gfx::Vector2dF(0.f, scroll_increment_y));
+ EXPECT_EQ(-scroll_increment_y,
+ host_impl_->top_controls_manager()->content_top_offset());
+ // Now that top controls have moved, expect the clip to resize.
+ EXPECT_EQ(gfx::Size(viewport_size_.width(),
+ viewport_size_.height() + scroll_increment_y),
+ root_clip_ptr->bounds());
+
+ host_impl_->top_controls_manager()->ScrollBy(
+ gfx::Vector2dF(0.f, scroll_increment_y));
+ host_impl_->top_controls_manager()->ScrollEnd();
+ EXPECT_EQ(-2 * scroll_increment_y,
+ host_impl_->top_controls_manager()->content_top_offset());
+ // Now that top controls have moved, expect the clip to resize.
+ EXPECT_EQ(clip_size_, root_clip_ptr->bounds());
+
+ host_impl_->ScrollEnd();
+
+ // Verify the layer is once-again non-scrollable.
+ EXPECT_EQ(
+ gfx::Vector2d(),
+ host_impl_->active_tree()->InnerViewportScrollLayer()->MaxScrollOffset());
+
+ EXPECT_EQ(InputHandler::ScrollStarted,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
}
TEST_F(LayerTreeHostImplTest, ScrollNonCompositedRoot) {
@@ -2080,12 +2207,14 @@
TEST_F(LayerTreeHostImplTest, ScrollRootAndChangePageScaleOnMainThread) {
gfx::Size surface_size(20, 20);
+ gfx::Size viewport_size(10, 10);
float page_scale = 2.f;
scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1);
scoped_ptr<LayerImpl> root_clip =
LayerImpl::Create(host_impl_->active_tree(), 2);
scoped_ptr<LayerImpl> root_scrolling =
CreateScrollableLayer(3, surface_size, root_clip.get());
+ EXPECT_EQ(viewport_size, root_clip->bounds());
root_scrolling->SetIsContainerForFixedPositionLayers(true);
root_clip->AddChild(root_scrolling.Pass());
root->AddChild(root_clip.Pass());
@@ -2094,11 +2223,12 @@
// above the clip layer.
host_impl_->active_tree()->SetViewportLayersFromIds(1, 3, Layer::INVALID_ID);
host_impl_->active_tree()->DidBecomeActive();
- host_impl_->SetViewportSize(surface_size);
+ host_impl_->SetViewportSize(viewport_size);
DrawFrame();
LayerImpl* root_scroll =
host_impl_->active_tree()->InnerViewportScrollLayer();
+ EXPECT_EQ(viewport_size, root_scroll->scroll_clip_layer()->bounds());
gfx::Vector2d scroll_delta(0, 10);
gfx::Vector2d expected_scroll_delta = scroll_delta;
@@ -2127,12 +2257,14 @@
TEST_F(LayerTreeHostImplTest, ScrollRootAndChangePageScaleOnImplThread) {
gfx::Size surface_size(20, 20);
+ gfx::Size viewport_size(10, 10);
float page_scale = 2.f;
scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1);
scoped_ptr<LayerImpl> root_clip =
LayerImpl::Create(host_impl_->active_tree(), 2);
scoped_ptr<LayerImpl> root_scrolling =
CreateScrollableLayer(3, surface_size, root_clip.get());
+ EXPECT_EQ(viewport_size, root_clip->bounds());
root_scrolling->SetIsContainerForFixedPositionLayers(true);
root_clip->AddChild(root_scrolling.Pass());
root->AddChild(root_clip.Pass());
@@ -2141,12 +2273,13 @@
// above the clip layer.
host_impl_->active_tree()->SetViewportLayersFromIds(1, 3, Layer::INVALID_ID);
host_impl_->active_tree()->DidBecomeActive();
- host_impl_->SetViewportSize(surface_size);
+ host_impl_->SetViewportSize(viewport_size);
host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f, 1.f, page_scale);
DrawFrame();
LayerImpl* root_scroll =
host_impl_->active_tree()->InnerViewportScrollLayer();
+ EXPECT_EQ(viewport_size, root_scroll->scroll_clip_layer()->bounds());
gfx::Vector2d scroll_delta(0, 10);
gfx::Vector2d expected_scroll_delta = scroll_delta;
@@ -2338,6 +2471,7 @@
// Scroll a child layer beyond its maximum scroll range and make sure the
// the scroll doesn't bubble up to the parent layer.
gfx::Size surface_size(20, 20);
+ gfx::Size viewport_size(10, 10);
scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1);
scoped_ptr<LayerImpl> root_scrolling =
CreateScrollableLayer(2, surface_size, root.get());
@@ -2354,10 +2488,11 @@
LayerImpl* child_layer = child.get();
root_scrolling->AddChild(child.Pass());
root->AddChild(root_scrolling.Pass());
+ EXPECT_EQ(viewport_size, root->bounds());
host_impl_->active_tree()->SetRootLayer(root.Pass());
host_impl_->active_tree()->SetViewportLayersFromIds(1, 2, Layer::INVALID_ID);
host_impl_->active_tree()->DidBecomeActive();
- host_impl_->SetViewportSize(surface_size);
+ host_impl_->SetViewportSize(viewport_size);
grand_child_layer->SetScrollOffset(gfx::Vector2d(0, 2));
child_layer->SetScrollOffset(gfx::Vector2d(0, 3));
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc
index 99129ee..d76d8df 100644
--- a/cc/trees/layer_tree_impl.cc
+++ b/cc/trees/layer_tree_impl.cc
@@ -237,9 +237,10 @@
target_tree->set_hud_layer(NULL);
}
-LayerImpl* LayerTreeImpl::RootContainerLayer() const {
- return inner_viewport_scroll_layer_ ? inner_viewport_scroll_layer_->parent()
- : NULL;
+LayerImpl* LayerTreeImpl::InnerViewportContainerLayer() const {
+ return inner_viewport_scroll_layer_
+ ? inner_viewport_scroll_layer_->scroll_clip_layer()
+ : NULL;
}
LayerImpl* LayerTreeImpl::CurrentlyScrollingLayer() const {
@@ -267,11 +268,10 @@
float LayerTreeImpl::VerticalAdjust(const LayerImpl* layer) const {
DCHECK(layer);
- if (layer->parent() != RootContainerLayer())
+ if (layer->parent() != InnerViewportContainerLayer())
return 0.f;
- return layer_tree_host_impl_->UnscaledScrollableViewportSize().height() -
- RootContainerLayer()->bounds().height();
+ return layer_tree_host_impl_->VerticalAdjust();
}
namespace {
@@ -433,9 +433,6 @@
}
void LayerTreeImpl::UpdateDrawProperties() {
- if (IsActiveTree() && RootContainerLayer())
- UpdateRootScrollLayerSizeDelta();
-
needs_update_draw_properties_ = false;
render_surface_layer_list_.clear();
@@ -454,7 +451,7 @@
"SourceFrameNumber",
source_frame_number_);
LayerImpl* page_scale_layer =
- page_scale_layer_ ? page_scale_layer_ : RootContainerLayer();
+ page_scale_layer_ ? page_scale_layer_ : InnerViewportContainerLayer();
bool can_render_to_separate_surface =
!output_surface()->ForcedDrawToSoftwareDevice();
LayerTreeHostCommon::CalcDrawPropsImplInputs inputs(
@@ -860,29 +857,6 @@
return inner_viewport_offset;
}
-// TODO(wjmaclean) Rename this function, as we no longer have a
-// "RootScrollLayer".
-void LayerTreeImpl::UpdateRootScrollLayerSizeDelta() {
- // TODO(wjmaclean) verify this is really the right thing to do in cases where
- // the pinch virtual viewport is active.
- LayerImpl* root_scroll = InnerViewportScrollLayer();
- LayerImpl* root_container = RootContainerLayer();
- DCHECK(root_scroll);
- DCHECK(root_container);
- DCHECK(IsActiveTree());
-
- gfx::Vector2dF scrollable_viewport_size =
- gfx::RectF(ScrollableViewportSize()).bottom_right() - gfx::PointF();
-
- gfx::Vector2dF original_viewport_size =
- gfx::RectF(root_container->bounds()).bottom_right() -
- gfx::PointF();
- original_viewport_size.Scale(1 / page_scale_factor());
-
- root_scroll->SetFixedContainerSizeDelta(
- scrollable_viewport_size - original_viewport_size);
-}
-
void LayerTreeImpl::QueueSwapPromise(scoped_ptr<SwapPromise> swap_promise) {
DCHECK(swap_promise);
if (swap_promise_list_.size() > kMaxQueuedSwapPromiseNumber)
diff --git a/cc/trees/layer_tree_impl.h b/cc/trees/layer_tree_impl.h
index 9815c13..3da5dae 100644
--- a/cc/trees/layer_tree_impl.h
+++ b/cc/trees/layer_tree_impl.h
@@ -123,7 +123,7 @@
gfx::Vector2dF TotalMaxScrollOffset() const;
gfx::Vector2dF TotalScrollDelta() const;
- LayerImpl* RootContainerLayer() const;
+ LayerImpl* InnerViewportContainerLayer() const;
LayerImpl* CurrentlyScrollingLayer() const;
void SetCurrentlyScrollingLayer(LayerImpl* layer);
void ClearCurrentlyScrollingLayer();
@@ -246,8 +246,6 @@
protected:
explicit LayerTreeImpl(LayerTreeHostImpl* layer_tree_host_impl);
- void UpdateRootScrollLayerSizeDelta();
-
LayerTreeHostImpl* layer_tree_host_impl_;
int source_frame_number_;
scoped_ptr<LayerImpl> root_layer_;