diff options
author | wjmaclean@chromium.org <wjmaclean@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-01-29 13:54:33 +0000 |
---|---|---|
committer | wjmaclean@chromium.org <wjmaclean@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-01-29 13:54:33 +0000 |
commit | 610834cb98728532e1f296c77552f640f7c0ff7a (patch) | |
tree | ba2aee5588ed23c8ccfb0adf5be2ff14ddab29a4 | |
parent | 167f3c414c3d087653ac9d712add50b3b854fcbb (diff) | |
download | chromium_src-610834cb98728532e1f296c77552f640f7c0ff7a.zip chromium_src-610834cb98728532e1f296c77552f640f7c0ff7a.tar.gz chromium_src-610834cb98728532e1f296c77552f640f7c0ff7a.tar.bz2 |
Pinch/Zoom Infrastructure & Plumbing CL
This CL supplies the necessary changes to CC to support the
inner/outer viewport model for pinch-zoom and fixed-position
elements. The specification for these changes is contained in
the document "Layer-based Solution for Pinch Zoom / Fixed
Position".
It incorporates a change to how scrollbar parameters are
computed (removes the notion of max_scroll_offset as a
quantity set be the embedder, and instead inferred from the
relative sizes of a clip layer w.r.t. the scroll layer).
Scrollbars are generalized so that a layer may have more than
two scrollbars, and the parameters of the scrollbar are set
w.r.t. the sizes and positions of a clip and a scroll layer.
Further, changes to the scrip/scroll layer automatically
notify any attached scrollbars.
The CL also removes existing references to root_scroll_layer
from LTH, LTI and LTHI and replaces them with either
Inner/OuterViewportScrollLayer (dual-layer operation only
exists at present if the --enable-pinch-virtual-viewport flag
is specified, otherwise behavior is unchanged).
Logic is added to (i) combine scroll offsets for the two
viewports before passing it to the embedder, and (ii)
splitting any offsets received from the embedder
appropriately between the two viewports.
This CL relies on https://codereview.chromium.org/138453004/
for changes in Blink to support it.
BUG=148816
Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=246812
R=aelias@chromium.org, enne@chromium.org, joi@chromium.org, piman@chromium.org, sky@chromium.org
Review URL: https://codereview.chromium.org/23983047
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@247684 0039d316-1c4b-4281-b951-d872f2087c98
50 files changed, 1787 insertions, 876 deletions
diff --git a/cc/animation/scrollbar_animation_controller_linear_fade.cc b/cc/animation/scrollbar_animation_controller_linear_fade.cc index 863959b..049b873 100644 --- a/cc/animation/scrollbar_animation_controller_linear_fade.cc +++ b/cc/animation/scrollbar_animation_controller_linear_fade.cc @@ -112,15 +112,17 @@ float ScrollbarAnimationControllerLinearFade::OpacityAtTime( void ScrollbarAnimationControllerLinearFade::ApplyOpacityToScrollbars( float opacity) { - ScrollbarLayerImplBase* horizontal_scrollbar = - scroll_layer_->horizontal_scrollbar_layer(); - if (horizontal_scrollbar) - horizontal_scrollbar->SetOpacity(opacity); - - ScrollbarLayerImplBase* vertical_scrollbar = - scroll_layer_->vertical_scrollbar_layer(); - if (vertical_scrollbar) - vertical_scrollbar->SetOpacity(opacity); + if (!scroll_layer_->scrollbars()) + return; + + LayerImpl::ScrollbarSet* scrollbars = scroll_layer_->scrollbars(); + for (LayerImpl::ScrollbarSet::iterator it = scrollbars->begin(); + it != scrollbars->end(); + ++it) { + ScrollbarLayerImplBase* scrollbar = *it; + if (scrollbar->is_overlay_scrollbar()) + scrollbar->SetOpacity(opacity); + } } } // namespace cc diff --git a/cc/animation/scrollbar_animation_controller_linear_fade_unittest.cc b/cc/animation/scrollbar_animation_controller_linear_fade_unittest.cc index b4c1160..9fdb2e9 100644 --- a/cc/animation/scrollbar_animation_controller_linear_fade_unittest.cc +++ b/cc/animation/scrollbar_animation_controller_linear_fade_unittest.cc @@ -4,7 +4,7 @@ #include "cc/animation/scrollbar_animation_controller_linear_fade.h" -#include "cc/layers/painted_scrollbar_layer_impl.h" +#include "cc/layers/solid_color_scrollbar_layer_impl.h" #include "cc/test/fake_impl_proxy.h" #include "cc/test/fake_layer_tree_host_impl.h" #include "testing/gtest/include/gtest/gtest.h" @@ -18,16 +18,31 @@ class ScrollbarAnimationControllerLinearFadeTest : public testing::Test { protected: virtual void SetUp() { - scroll_layer_ = LayerImpl::Create(host_impl_.active_tree(), 1); - scrollbar_layer_ = PaintedScrollbarLayerImpl::Create( - host_impl_.active_tree(), 2, HORIZONTAL); - - scroll_layer_->SetMaxScrollOffset(gfx::Vector2d(50, 50)); - scroll_layer_->SetBounds(gfx::Size(50, 50)); - scroll_layer_->SetHorizontalScrollbarLayer(scrollbar_layer_.get()); + const int kThumbThickness = 10; + const bool kIsLeftSideVerticalScrollbar = false; + const bool kIsOverlayScrollbar = true; // Allow opacity animations. + + scoped_ptr<LayerImpl> scroll_layer = + LayerImpl::Create(host_impl_.active_tree(), 1); + scrollbar_layer_ = + SolidColorScrollbarLayerImpl::Create(host_impl_.active_tree(), + 2, + HORIZONTAL, + kThumbThickness, + kIsLeftSideVerticalScrollbar, + kIsOverlayScrollbar); + clip_layer_ = LayerImpl::Create(host_impl_.active_tree(), 3); + scroll_layer->SetScrollClipLayer(clip_layer_->id()); + LayerImpl* scroll_layer_ptr = scroll_layer.get(); + clip_layer_->AddChild(scroll_layer.Pass()); + + scrollbar_layer_->SetClipLayerById(clip_layer_->id()); + scrollbar_layer_->SetScrollLayerById(scroll_layer_ptr->id()); + clip_layer_->SetBounds(gfx::Size(100, 100)); + scroll_layer_ptr->SetBounds(gfx::Size(50, 50)); scrollbar_controller_ = ScrollbarAnimationControllerLinearFade::Create( - scroll_layer_.get(), + scroll_layer_ptr, base::TimeDelta::FromSeconds(2), base::TimeDelta::FromSeconds(3)); } @@ -35,8 +50,8 @@ class ScrollbarAnimationControllerLinearFadeTest : public testing::Test { FakeImplProxy proxy_; FakeLayerTreeHostImpl host_impl_; scoped_ptr<ScrollbarAnimationControllerLinearFade> scrollbar_controller_; - scoped_ptr<LayerImpl> scroll_layer_; - scoped_ptr<PaintedScrollbarLayerImpl> scrollbar_layer_; + scoped_ptr<LayerImpl> clip_layer_; + scoped_ptr<SolidColorScrollbarLayerImpl> scrollbar_layer_; }; TEST_F(ScrollbarAnimationControllerLinearFadeTest, HiddenInBegin) { diff --git a/cc/animation/scrollbar_animation_controller_thinning.cc b/cc/animation/scrollbar_animation_controller_thinning.cc index 3de7598..7c10d7a 100644 --- a/cc/animation/scrollbar_animation_controller_thinning.cc +++ b/cc/animation/scrollbar_animation_controller_thinning.cc @@ -180,28 +180,22 @@ float ScrollbarAnimationControllerThinning::AdjustScale( void ScrollbarAnimationControllerThinning::ApplyOpacityAndThumbThicknessScale( float opacity, float thumb_thickness_scale) { - ScrollbarLayerImplBase* horizontal_scrollbar = - scroll_layer_->horizontal_scrollbar_layer(); - if (horizontal_scrollbar) { - horizontal_scrollbar->SetOpacity( - AdjustScale(opacity, horizontal_scrollbar->opacity(), opacity_change_)); - horizontal_scrollbar->SetThumbThicknessScaleFactor( - AdjustScale( - thumb_thickness_scale, - horizontal_scrollbar->thumb_thickness_scale_factor(), - thickness_change_)); - } - - ScrollbarLayerImplBase* vertical_scrollbar = - scroll_layer_->vertical_scrollbar_layer(); - if (vertical_scrollbar) { - vertical_scrollbar->SetOpacity( - AdjustScale(opacity, vertical_scrollbar->opacity(), opacity_change_)); - vertical_scrollbar->SetThumbThicknessScaleFactor( - AdjustScale( - thumb_thickness_scale, - vertical_scrollbar->thumb_thickness_scale_factor(), - thickness_change_)); + if (!scroll_layer_->scrollbars()) + return; + + LayerImpl::ScrollbarSet* scrollbars = scroll_layer_->scrollbars(); + for (LayerImpl::ScrollbarSet::iterator it = scrollbars->begin(); + it != scrollbars->end(); + ++it) { + ScrollbarLayerImplBase* scrollbar = *it; + if (scrollbar->is_overlay_scrollbar()) { + scrollbar->SetOpacity( + AdjustScale(opacity, scrollbar->opacity(), opacity_change_)); + scrollbar->SetThumbThicknessScaleFactor( + AdjustScale(thumb_thickness_scale, + scrollbar->thumb_thickness_scale_factor(), + thickness_change_)); + } } } diff --git a/cc/animation/scrollbar_animation_controller_thinning_unittest.cc b/cc/animation/scrollbar_animation_controller_thinning_unittest.cc index c915632..7210ae2 100644 --- a/cc/animation/scrollbar_animation_controller_thinning_unittest.cc +++ b/cc/animation/scrollbar_animation_controller_thinning_unittest.cc @@ -18,20 +18,28 @@ class ScrollbarAnimationControllerThinningTest : public testing::Test { protected: virtual void SetUp() { - scroll_layer_ = LayerImpl::Create(host_impl_.active_tree(), 1); + scoped_ptr<LayerImpl> scroll_layer = + LayerImpl::Create(host_impl_.active_tree(), 1); + clip_layer_ = LayerImpl::Create(host_impl_.active_tree(), 3); + scroll_layer->SetScrollClipLayer(clip_layer_->id()); + LayerImpl* scroll_layer_ptr = scroll_layer.get(); + clip_layer_->AddChild(scroll_layer.Pass()); + const int kId = 2; const int kThumbThickness = 10; const bool kIsLeftSideVerticalScrollbar = false; + const bool kIsOverlayScrollbar = true; scrollbar_layer_ = SolidColorScrollbarLayerImpl::Create( host_impl_.active_tree(), kId, HORIZONTAL, kThumbThickness, - kIsLeftSideVerticalScrollbar); + kIsLeftSideVerticalScrollbar, kIsOverlayScrollbar); - scroll_layer_->SetMaxScrollOffset(gfx::Vector2d(50, 50)); - scroll_layer_->SetBounds(gfx::Size(50, 50)); - scroll_layer_->SetHorizontalScrollbarLayer(scrollbar_layer_.get()); + scrollbar_layer_->SetClipLayerById(clip_layer_->id()); + scrollbar_layer_->SetScrollLayerById(scroll_layer_ptr->id()); + clip_layer_->SetBounds(gfx::Size(100, 100)); + scroll_layer_ptr->SetBounds(gfx::Size(50, 50)); scrollbar_controller_ = ScrollbarAnimationControllerThinning::CreateForTest( - scroll_layer_.get(), + scroll_layer_ptr, base::TimeDelta::FromSeconds(2), base::TimeDelta::FromSeconds(3)); } @@ -39,7 +47,7 @@ class ScrollbarAnimationControllerThinningTest : public testing::Test { FakeImplProxy proxy_; FakeLayerTreeHostImpl host_impl_; scoped_ptr<ScrollbarAnimationControllerThinning> scrollbar_controller_; - scoped_ptr<LayerImpl> scroll_layer_; + scoped_ptr<LayerImpl> clip_layer_; scoped_ptr<SolidColorScrollbarLayerImpl> scrollbar_layer_; }; diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc index f585006..c2c4041 100644 --- a/cc/layers/layer.cc +++ b/cc/layers/layer.cc @@ -16,11 +16,13 @@ #include "cc/animation/layer_animation_controller.h" #include "cc/layers/layer_client.h" #include "cc/layers/layer_impl.h" +#include "cc/layers/scrollbar_layer_interface.h" #include "cc/output/copy_output_request.h" #include "cc/output/copy_output_result.h" #include "cc/trees/layer_tree_host.h" #include "cc/trees/layer_tree_impl.h" #include "third_party/skia/include/core/SkImageFilter.h" +#include "ui/gfx/geometry/vector2d_conversions.h" #include "ui/gfx/rect_conversions.h" namespace cc { @@ -39,7 +41,7 @@ Layer::Layer() ignore_set_needs_commit_(false), parent_(NULL), layer_tree_host_(NULL), - scrollable_(false), + scroll_clip_layer_(NULL), should_scroll_on_main_thread_(false), have_wheel_event_handlers_(false), user_scrollable_horizontal_(true), @@ -679,6 +681,12 @@ void Layer::RemoveClipChild(Layer* child) { void Layer::SetScrollOffset(gfx::Vector2d scroll_offset) { DCHECK(IsPropertyChangeAllowed()); + + if (layer_tree_host()) { + scroll_offset = layer_tree_host()->DistributeScrollOffsetToViewports( + scroll_offset, this); + } + if (scroll_offset_ == scroll_offset) return; scroll_offset_ = scroll_offset; @@ -700,19 +708,44 @@ void Layer::SetScrollOffsetFromImplSide(gfx::Vector2d scroll_offset) { // "this" may have been destroyed during the process. } -void Layer::SetMaxScrollOffset(gfx::Vector2d max_scroll_offset) { - DCHECK(IsPropertyChangeAllowed()); - if (max_scroll_offset_ == max_scroll_offset) - return; - max_scroll_offset_ = max_scroll_offset; - SetNeedsCommit(); +// TODO(wjmaclean) We should template this and put it into LayerTreeHostCommon +// so that both Layer and LayerImpl are using the same code. In order +// to template it we should avoid calling layer_tree_host() by giving +// Layer/LayerImpl local accessors for page_scale_layer() and +// page_scale_factor(). +gfx::Vector2d Layer::MaxScrollOffset() const { + if (!scroll_clip_layer_) + return gfx::Vector2d(); + + gfx::Size scaled_scroll_bounds(bounds()); + Layer const* current_layer = this; + Layer const* page_scale_layer = layer_tree_host()->page_scale_layer(); + float scale_factor = 1.f; + do { + if (current_layer == page_scale_layer) { + scale_factor = layer_tree_host()->page_scale_factor(); + scaled_scroll_bounds.SetSize( + scale_factor * scaled_scroll_bounds.width(), + scale_factor * scaled_scroll_bounds.height()); + } + current_layer = current_layer->parent(); + } while (current_layer && current_layer != scroll_clip_layer_); + DCHECK(current_layer == scroll_clip_layer_); + + gfx::Vector2dF max_offset( + scaled_scroll_bounds.width() - scroll_clip_layer_->bounds().width(), + scaled_scroll_bounds.height() - scroll_clip_layer_->bounds().height()); + // We need the final scroll offset to be in CSS coords. + max_offset.Scale(1.f / scale_factor); + max_offset.SetToMax(gfx::Vector2dF()); + return gfx::ToFlooredVector2d(max_offset); } -void Layer::SetScrollable(bool scrollable) { +void Layer::SetScrollClipLayer(Layer* clip_layer) { DCHECK(IsPropertyChangeAllowed()); - if (scrollable_ == scrollable) + if (scroll_clip_layer_ == clip_layer) return; - scrollable_ = scrollable; + scroll_clip_layer_ = clip_layer; SetNeedsCommit(); } @@ -911,10 +944,10 @@ void Layer::PushPropertiesTo(LayerImpl* layer) { layer->SetTransform(transform_); DCHECK(!(TransformIsAnimating() && layer->TransformIsAnimatingOnImplOnly())); - layer->SetScrollable(scrollable_); + layer->SetScrollClipLayer(scroll_clip_layer_ ? scroll_clip_layer_->id() + : Layer::INVALID_ID); layer->set_user_scrollable_horizontal(user_scrollable_horizontal_); layer->set_user_scrollable_vertical(user_scrollable_vertical_); - layer->SetMaxScrollOffset(max_scroll_offset_); LayerImpl* scroll_parent = NULL; if (scroll_parent_) diff --git a/cc/layers/layer.h b/cc/layers/layer.h index df358f2..68b67e25 100644 --- a/cc/layers/layer.h +++ b/cc/layers/layer.h @@ -269,11 +269,10 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, gfx::Vector2d scroll_offset() const { return scroll_offset_; } void SetScrollOffsetFromImplSide(gfx::Vector2d scroll_offset); - void SetMaxScrollOffset(gfx::Vector2d max_scroll_offset); - gfx::Vector2d max_scroll_offset() const { return max_scroll_offset_; } + gfx::Vector2d MaxScrollOffset() const; - void SetScrollable(bool scrollable); - bool scrollable() const { return scrollable_; } + void SetScrollClipLayer(Layer* clip_layer); + bool scrollable() const { return !!scroll_clip_layer_; } void SetUserScrollable(bool horizontal, bool vertical); bool user_scrollable_horizontal() const { @@ -565,7 +564,10 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, gfx::Size bounds_; gfx::Vector2d scroll_offset_; - gfx::Vector2d max_scroll_offset_; + // This variable indicates which ancestor layer (if any) whose size, + // transformed relative to this layer, defines the maximum scroll offset for + // this layer. + Layer* scroll_clip_layer_; bool scrollable_ : 1; bool should_scroll_on_main_thread_ : 1; bool have_wheel_event_handlers_ : 1; diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc index beb282d..64b7b39 100644 --- a/cc/layers/layer_impl.cc +++ b/cc/layers/layer_impl.cc @@ -27,6 +27,7 @@ #include "cc/trees/layer_tree_settings.h" #include "cc/trees/proxy.h" #include "ui/gfx/box_f.h" +#include "ui/gfx/geometry/vector2d_conversions.h" #include "ui/gfx/point_conversions.h" #include "ui/gfx/quad_f.h" #include "ui/gfx/rect_conversions.h" @@ -43,7 +44,7 @@ LayerImpl::LayerImpl(LayerTreeImpl* tree_impl, int id) anchor_point_(0.5f, 0.5f), anchor_point_z_(0.f), scroll_offset_delegate_(NULL), - scrollable_(false), + scroll_clip_layer_(NULL), should_scroll_on_main_thread_(false), have_wheel_event_handlers_(false), user_scrollable_horizontal_(true), @@ -67,9 +68,7 @@ LayerImpl::LayerImpl(LayerTreeImpl* tree_impl, int id) draw_depth_(0.f), needs_push_properties_(false), num_dependents_need_push_properties_(0), - current_draw_mode_(DRAW_MODE_NONE), - horizontal_scrollbar_layer_(NULL), - vertical_scrollbar_layer_(NULL) { + current_draw_mode_(DRAW_MODE_NONE) { DCHECK_GT(layer_id_, 0); DCHECK(layer_tree_impl_); layer_tree_impl_->RegisterLayer(this); @@ -381,7 +380,7 @@ void LayerImpl::SetSentScrollDelta(gfx::Vector2d sent_scroll_delta) { gfx::Vector2dF LayerImpl::ScrollBy(const gfx::Vector2dF& scroll) { DCHECK(scrollable()); gfx::Vector2dF min_delta = -scroll_offset_; - gfx::Vector2dF max_delta = max_scroll_offset_ - scroll_offset_; + gfx::Vector2dF max_delta = MaxScrollOffset() - scroll_offset_; // Clamp new_delta so that position + delta stays within scroll bounds. gfx::Vector2dF new_delta = (ScrollDelta() + scroll); new_delta.SetToMax(min_delta); @@ -389,9 +388,14 @@ gfx::Vector2dF LayerImpl::ScrollBy(const gfx::Vector2dF& scroll) { gfx::Vector2dF unscrolled = ScrollDelta() + scroll - new_delta; SetScrollDelta(new_delta); + return unscrolled; } +void LayerImpl::SetScrollClipLayer(int scroll_clip_layer_id) { + scroll_clip_layer_ = layer_tree_impl()->LayerById(scroll_clip_layer_id); +} + void LayerImpl::ApplySentScrollDeltasFromAbortedCommit() { // Pending tree never has sent scroll deltas DCHECK(layer_tree_impl()->IsActiveTree()); @@ -481,7 +485,8 @@ InputHandler::ScrollStatus LayerImpl::TryScroll( return InputHandler::ScrollIgnored; } - if (max_scroll_offset_.x() <= 0 && max_scroll_offset_.y() <= 0) { + gfx::Vector2d max_scroll_offset = MaxScrollOffset(); + if (max_scroll_offset.x() <= 0 && max_scroll_offset.y() <= 0) { TRACE_EVENT0("cc", "LayerImpl::tryScroll: Ignored. Technically scrollable," " but has no affordance in either direction."); @@ -552,15 +557,14 @@ void LayerImpl::PushPropertiesTo(LayerImpl* layer) { layer->SetSublayerTransform(sublayer_transform_); layer->SetTransform(transform_); - layer->SetScrollable(scrollable_); + layer->SetScrollClipLayer(scroll_clip_layer_ ? scroll_clip_layer_->id() + : Layer::INVALID_ID); layer->set_user_scrollable_horizontal(user_scrollable_horizontal_); layer->set_user_scrollable_vertical(user_scrollable_vertical_); layer->SetScrollOffsetAndDelta( scroll_offset_, layer->ScrollDelta() - layer->sent_scroll_delta()); layer->SetSentScrollDelta(gfx::Vector2d()); - layer->SetMaxScrollOffset(max_scroll_offset_); - LayerImpl* scroll_parent = NULL; if (scroll_parent_) scroll_parent = layer->layer_tree_impl()->LayerById(scroll_parent_->id()); @@ -634,8 +638,8 @@ base::DictionaryValue* LayerImpl::LayerTreeAsJson() const { result->SetDouble("Opacity", opacity()); result->SetBoolean("ContentsOpaque", contents_opaque_); - if (scrollable_) - result->SetBoolean("Scrollable", scrollable_); + if (scrollable()) + result->SetBoolean("Scrollable", true); if (have_wheel_event_handlers_) result->SetBoolean("WheelHandler", have_wheel_event_handlers_); @@ -757,6 +761,7 @@ void LayerImpl::SetBounds(gfx::Size bounds) { bounds_ = bounds; + ScrollbarParametersDidChange(); if (masks_to_bounds()) NoteLayerPropertyChangedForSubtree(); else @@ -1030,44 +1035,6 @@ void LayerImpl::CalculateContentsScale( *content_bounds = this->content_bounds(); } -void LayerImpl::UpdateScrollbarPositions() { - gfx::Vector2dF current_offset = scroll_offset_ + ScrollDelta(); - - gfx::RectF viewport(PointAtOffsetFromOrigin(current_offset), bounds_); - gfx::SizeF scrollable_size(max_scroll_offset_.x() + bounds_.width(), - max_scroll_offset_.y() + bounds_.height()); - if (horizontal_scrollbar_layer_) { - horizontal_scrollbar_layer_->SetCurrentPos(current_offset.x()); - horizontal_scrollbar_layer_->SetMaximum(max_scroll_offset_.x()); - horizontal_scrollbar_layer_->SetVisibleToTotalLengthRatio( - viewport.width() / scrollable_size.width()); - } - if (vertical_scrollbar_layer_) { - vertical_scrollbar_layer_->SetCurrentPos(current_offset.y()); - vertical_scrollbar_layer_->SetMaximum(max_scroll_offset_.y()); - vertical_scrollbar_layer_->SetVisibleToTotalLengthRatio( - viewport.height() / scrollable_size.height()); - } - - if (current_offset == last_scroll_offset_) - return; - last_scroll_offset_ = current_offset; - - if (scrollbar_animation_controller_) { - bool should_animate = scrollbar_animation_controller_->DidScrollUpdate( - layer_tree_impl_->CurrentPhysicalTimeTicks()); - if (should_animate) - layer_tree_impl_->StartScrollbarAnimation(); - } - - // Get the current_offset_.y() value for a sanity-check on scrolling - // benchmark metrics. Specifically, we want to make sure - // BasicMouseWheelSmoothScrollGesture has proper scroll curves. - if (layer_tree_impl()->IsActiveTree()) { - TRACE_COUNTER_ID1("gpu", "scroll_offset_y", this->id(), current_offset.y()); - } -} - void LayerImpl::SetScrollOffsetDelegate( LayerScrollOffsetDelegate* scroll_offset_delegate) { // Having both a scroll parent and a scroll offset delegate is unsupported. @@ -1078,10 +1045,8 @@ void LayerImpl::SetScrollOffsetDelegate( } gfx::Vector2dF total_offset = TotalScrollOffset(); scroll_offset_delegate_ = scroll_offset_delegate; - if (scroll_offset_delegate_) { - scroll_offset_delegate_->SetMaxScrollOffset(max_scroll_offset_); + if (scroll_offset_delegate_) scroll_offset_delegate_->SetTotalScrollOffset(total_offset); - } } bool LayerImpl::IsExternalFlingActive() const { @@ -1097,6 +1062,8 @@ void LayerImpl::SetScrollOffsetAndDelta(gfx::Vector2d scroll_offset, const gfx::Vector2dF& scroll_delta) { bool changed = false; + last_scroll_offset_ = scroll_offset; + if (scroll_offset_ != scroll_offset) { changed = true; scroll_offset_ = scroll_offset; @@ -1131,7 +1098,7 @@ void LayerImpl::SetScrollOffsetAndDelta(gfx::Vector2d scroll_offset, if (changed) { NoteLayerPropertyChangedForSubtree(); - UpdateScrollbarPositions(); + ScrollbarParametersDidChange(); } } @@ -1167,17 +1134,151 @@ void LayerImpl::DidBeginTracing() {} void LayerImpl::ReleaseResources() {} -void LayerImpl::SetMaxScrollOffset(gfx::Vector2d max_scroll_offset) { - if (max_scroll_offset_ == max_scroll_offset) +gfx::Vector2d LayerImpl::MaxScrollOffset() const { + if (!scroll_clip_layer_ || bounds().IsEmpty()) + return gfx::Vector2d(); + + LayerImpl const* page_scale_layer = layer_tree_impl()->page_scale_layer(); + DCHECK(this != page_scale_layer); + DCHECK(scroll_clip_layer_); + DCHECK(this != layer_tree_impl()->InnerViewportScrollLayer() || + IsContainerForFixedPositionLayers()); + + gfx::Size scaled_scroll_bounds(bounds()); + + float scale_factor = 1.f; + for (LayerImpl const* current_layer = this; + current_layer != scroll_clip_layer_; + current_layer = current_layer->parent()) { + DCHECK(current_layer); + float current_layer_scale = 1.f; + + const gfx::Transform& layer_transform = current_layer->transform(); + if (current_layer == page_scale_layer) { + DCHECK(layer_transform.IsIdentity()); + current_layer_scale = layer_tree_impl()->total_page_scale_factor(); + } else { + // TODO(wjmaclean) Should we allow for translation too? + DCHECK(layer_transform.IsScale2d()); + gfx::Vector2dF layer_scale = layer_transform.Scale2d(); + // TODO(wjmaclean) Allow for non-isotropic scales. + DCHECK(layer_scale.x() == layer_scale.y()); + current_layer_scale = layer_scale.x(); + } + + scale_factor *= current_layer_scale; + } + // TODO(wjmaclean) Once we move to a model where the two-viewport model is + // turned on in all builds, remove the next two lines. For now however, the + // page scale layer may coincide with the clip layer, and so this is + // necessary. + if (page_scale_layer == scroll_clip_layer_) + scale_factor *= layer_tree_impl()->total_page_scale_factor(); + + 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()); + // We need the final scroll offset to be in CSS coords. + max_offset.Scale(1 / scale_factor); + max_offset.SetToMax(gfx::Vector2dF()); + return gfx::ToFlooredVector2d(max_offset); +} + +gfx::Vector2dF LayerImpl::ClampScrollToMaxScrollOffset() { + gfx::Vector2dF max_offset = MaxScrollOffset(); + gfx::Vector2dF old_offset = TotalScrollOffset(); + gfx::Vector2dF clamped_offset = old_offset; + + clamped_offset.SetToMin(max_offset); + clamped_offset.SetToMax(gfx::Vector2d()); + gfx::Vector2dF delta = clamped_offset - old_offset; + if (!delta.IsZero()) + ScrollBy(delta); + + return delta; +} + +void LayerImpl::SetScrollbarPosition(ScrollbarLayerImplBase* scrollbar_layer, + LayerImpl* scrollbar_clip_layer) const { + DCHECK(scrollbar_layer); + LayerImpl* page_scale_layer = layer_tree_impl()->page_scale_layer(); + + DCHECK(this != page_scale_layer); + DCHECK(scrollbar_clip_layer); + DCHECK(this != layer_tree_impl()->InnerViewportScrollLayer() + || IsContainerForFixedPositionLayers()); + gfx::RectF clip_rect(gfx::PointF(), scrollbar_clip_layer->bounds()); + + // See comment in MaxScrollOffset() regarding the use of the content layer + // bounds here. + gfx::RectF scroll_rect(gfx::PointF(), bounds()); + + if (scroll_rect.size().IsEmpty()) return; - max_scroll_offset_ = max_scroll_offset; - if (scroll_offset_delegate_) - scroll_offset_delegate_->SetMaxScrollOffset(max_scroll_offset_); + // TODO(wjmaclean) This computation is nearly identical to the one in + // MaxScrollOffset. Find some way to combine these. + gfx::Vector2dF current_offset; + for (LayerImpl const* current_layer = this; + current_layer != scrollbar_clip_layer; + current_layer = current_layer->parent()) { + DCHECK(current_layer); + const gfx::Transform& layer_transform = current_layer->transform(); + if (current_layer == page_scale_layer) { + DCHECK(layer_transform.IsIdentity()); + float scale_factor = layer_tree_impl()->total_page_scale_factor(); + current_offset.Scale(scale_factor); + scroll_rect.Scale(scale_factor); + } else { + DCHECK(layer_transform.IsScale2d()); + gfx::Vector2dF layer_scale = layer_transform.Scale2d(); + DCHECK(layer_scale.x() == layer_scale.y()); + gfx::Vector2dF new_offset = + current_layer->scroll_offset() + current_layer->ScrollDelta(); + new_offset.Scale(layer_scale.x(), layer_scale.y()); + current_offset += new_offset; + } + } + // TODO(wjmaclean) Once we move to a model where the two-viewport model is + // turned on in all builds, remove the next two lines. For now however, the + // page scale layer may coincide with the clip layer, and so this is + // necessary. + if (page_scale_layer == scrollbar_clip_layer) + scroll_rect.Scale(layer_tree_impl()->total_page_scale_factor()); + + scrollbar_layer->SetVerticalAdjust(layer_tree_impl()->VerticalAdjust(this)); + if (scrollbar_layer->orientation() == HORIZONTAL) { + float visible_ratio = clip_rect.width() / scroll_rect.width(); + scrollbar_layer->SetCurrentPos(current_offset.x()); + scrollbar_layer->SetMaximum(scroll_rect.width() - clip_rect.width()); + scrollbar_layer->SetVisibleToTotalLengthRatio(visible_ratio); + } else { + float visible_ratio = clip_rect.height() / scroll_rect.height(); + scrollbar_layer->SetCurrentPos(current_offset.y()); + scrollbar_layer->SetMaximum(scroll_rect.height() - clip_rect.height()); + scrollbar_layer->SetVisibleToTotalLengthRatio(visible_ratio); + } layer_tree_impl()->set_needs_update_draw_properties(); - UpdateScrollbarPositions(); - SetNeedsPushProperties(); + // TODO(wjmaclean) Should the rest of this function be deleted? + // TODO(wjmaclean) The scrollbar animator for the pinch-zoom scrollbars should + // activate for every scroll on the main frame, not just the scrolls that move + // the pinch virtual viewport (i.e. trigger from either inner or outer + // viewport). + if (scrollbar_animation_controller_) { + bool should_animate = scrollbar_animation_controller_->DidScrollUpdate( + layer_tree_impl_->CurrentPhysicalTimeTicks()); + if (should_animate) + layer_tree_impl_->StartScrollbarAnimation(); + } } void LayerImpl::DidBecomeActive() { @@ -1186,8 +1287,7 @@ void LayerImpl::DidBecomeActive() { return; } - bool need_scrollbar_animation_controller = horizontal_scrollbar_layer_ || - vertical_scrollbar_layer_; + bool need_scrollbar_animation_controller = scrollable() && scrollbars_; if (!need_scrollbar_animation_controller) { scrollbar_animation_controller_.reset(); return; @@ -1221,18 +1321,51 @@ void LayerImpl::DidBecomeActive() { } } -void LayerImpl::SetHorizontalScrollbarLayer( - ScrollbarLayerImplBase* scrollbar_layer) { - horizontal_scrollbar_layer_ = scrollbar_layer; - if (horizontal_scrollbar_layer_) - horizontal_scrollbar_layer_->set_scroll_layer_id(id()); +void LayerImpl::ClearScrollbars() { + if (!scrollbars_) + return; + + scrollbars_.reset(NULL); +} + +void LayerImpl::AddScrollbar(ScrollbarLayerImplBase* layer) { + DCHECK(layer); + DCHECK(!scrollbars_ || scrollbars_->find(layer) == scrollbars_->end()); + if (!scrollbars_) + scrollbars_.reset(new ScrollbarSet()); + + scrollbars_->insert(layer); +} + +void LayerImpl::RemoveScrollbar(ScrollbarLayerImplBase* layer) { + DCHECK(scrollbars_); + DCHECK(layer); + DCHECK(scrollbars_->find(layer) != scrollbars_->end()); + + scrollbars_->erase(layer); + if (scrollbars_->empty()) + scrollbars_.reset(); +} + +bool LayerImpl::HasScrollbar(ScrollbarOrientation orientation) const { + if (!scrollbars_) + return false; + + for (ScrollbarSet::iterator it = scrollbars_->begin(); + it != scrollbars_->end(); ++it) + if ((*it)->orientation() == orientation) + return true; + + return false; } -void LayerImpl::SetVerticalScrollbarLayer( - ScrollbarLayerImplBase* scrollbar_layer) { - vertical_scrollbar_layer_ = scrollbar_layer; - if (vertical_scrollbar_layer_) - vertical_scrollbar_layer_->set_scroll_layer_id(id()); +void LayerImpl::ScrollbarParametersDidChange() { + if (!scrollbars_) + return; + + for (ScrollbarSet::iterator it = scrollbars_->begin(); + it != scrollbars_->end(); ++it) + (*it)->ScrollbarParametersDidChange(); } void LayerImpl::SetNeedsPushProperties() { diff --git a/cc/layers/layer_impl.h b/cc/layers/layer_impl.h index 66fa84b..ec2977b 100644 --- a/cc/layers/layer_impl.h +++ b/cc/layers/layer_impl.h @@ -367,8 +367,10 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver, const gfx::Vector2dF& scroll_delta); gfx::Vector2d scroll_offset() const { return scroll_offset_; } - void SetMaxScrollOffset(gfx::Vector2d max_scroll_offset); - gfx::Vector2d max_scroll_offset() const { return max_scroll_offset_; } + gfx::Vector2d MaxScrollOffset() const; + gfx::Vector2dF ClampScrollToMaxScrollOffset(); + void SetScrollbarPosition(ScrollbarLayerImplBase* scrollbar_layer, + LayerImpl* scrollbar_clip_layer) const; void SetScrollDelta(const gfx::Vector2dF& scroll_delta); gfx::Vector2dF ScrollDelta() const; @@ -382,8 +384,8 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver, // initial scroll gfx::Vector2dF ScrollBy(const gfx::Vector2dF& scroll); - void SetScrollable(bool scrollable) { scrollable_ = scrollable; } - bool scrollable() const { return scrollable_; } + void SetScrollClipLayer(int scroll_clip_layer_id); + bool scrollable() const { return !!scroll_clip_layer_; } void set_user_scrollable_horizontal(bool scrollable) { user_scrollable_horizontal_ = scrollable; @@ -477,14 +479,15 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver, return scrollbar_animation_controller_.get(); } - void SetHorizontalScrollbarLayer(ScrollbarLayerImplBase* scrollbar_layer); - ScrollbarLayerImplBase* horizontal_scrollbar_layer() { - return horizontal_scrollbar_layer_; - } - - void SetVerticalScrollbarLayer(ScrollbarLayerImplBase* scrollbar_layer); - ScrollbarLayerImplBase* vertical_scrollbar_layer() { - return vertical_scrollbar_layer_; + typedef std::set<ScrollbarLayerImplBase*> ScrollbarSet; + ScrollbarSet* scrollbars() { return scrollbars_.get(); } + void ClearScrollbars(); + void AddScrollbar(ScrollbarLayerImplBase* layer); + void RemoveScrollbar(ScrollbarLayerImplBase* layer); + bool HasScrollbar(ScrollbarOrientation orientation) const; + void ScrollbarParametersDidChange(); + int clip_height() { + return scroll_clip_layer_ ? scroll_clip_layer_->bounds().height() : 0; } gfx::Rect LayerRectToContentRect(const gfx::RectF& layer_rect) const; @@ -542,8 +545,6 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver, private: void NoteLayerPropertyChangedForDescendantsInternal(); - void UpdateScrollbarPositions(); - virtual const char* LayerTypeAsString() const; // Properties internal to LayerImpl @@ -576,6 +577,7 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver, gfx::Size bounds_; gfx::Vector2d scroll_offset_; LayerScrollOffsetDelegate* scroll_offset_delegate_; + LayerImpl* scroll_clip_layer_; bool scrollable_ : 1; bool should_scroll_on_main_thread_ : 1; bool have_wheel_event_handlers_ : 1; @@ -618,7 +620,6 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver, gfx::Vector2dF scroll_delta_; gfx::Vector2d sent_scroll_delta_; - gfx::Vector2d max_scroll_offset_; gfx::Vector2dF last_scroll_offset_; // The global depth value of the center of the layer. This value is used @@ -654,10 +655,7 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver, // Manages scrollbars for this layer scoped_ptr<ScrollbarAnimationController> scrollbar_animation_controller_; - // Weak pointers to this layer's scrollbars, if it has them. Updated during - // tree synchronization. - ScrollbarLayerImplBase* horizontal_scrollbar_layer_; - ScrollbarLayerImplBase* vertical_scrollbar_layer_; + scoped_ptr<ScrollbarSet> scrollbars_; ScopedPtrVector<CopyOutputRequest> copy_requests_; diff --git a/cc/layers/layer_impl_unittest.cc b/cc/layers/layer_impl_unittest.cc index f38809f..1dc36dd3 100644 --- a/cc/layers/layer_impl_unittest.cc +++ b/cc/layers/layer_impl_unittest.cc @@ -94,28 +94,32 @@ TEST(LayerImplTest, VerifyLayerChangesAreTrackedProperly) { FakeImplProxy proxy; FakeLayerTreeHostImpl host_impl(&proxy); EXPECT_TRUE(host_impl.InitializeRenderer(CreateFakeOutputSurface())); - scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl.active_tree(), 1); - - scoped_ptr<LayerImpl> scroll_parent = + scoped_ptr<LayerImpl> root_clip = + LayerImpl::Create(host_impl.active_tree(), 1); + scoped_ptr<LayerImpl> root_ptr = LayerImpl::Create(host_impl.active_tree(), 2); - LayerImpl* scroll_child = LayerImpl::Create(host_impl.active_tree(), 3).get(); + LayerImpl* root = root_ptr.get(); + root_clip->AddChild(root_ptr.Pass()); + scoped_ptr<LayerImpl> scroll_parent = + LayerImpl::Create(host_impl.active_tree(), 3); + LayerImpl* scroll_child = LayerImpl::Create(host_impl.active_tree(), 4).get(); std::set<LayerImpl*>* scroll_children = new std::set<LayerImpl*>(); scroll_children->insert(scroll_child); - scroll_children->insert(root.get()); + scroll_children->insert(root); scoped_ptr<LayerImpl> clip_parent = - LayerImpl::Create(host_impl.active_tree(), 4); - LayerImpl* clip_child = LayerImpl::Create(host_impl.active_tree(), 5).get(); + LayerImpl::Create(host_impl.active_tree(), 5); + LayerImpl* clip_child = LayerImpl::Create(host_impl.active_tree(), 6).get(); std::set<LayerImpl*>* clip_children = new std::set<LayerImpl*>(); clip_children->insert(clip_child); - clip_children->insert(root.get()); + clip_children->insert(root); - root->AddChild(LayerImpl::Create(host_impl.active_tree(), 6)); + root->AddChild(LayerImpl::Create(host_impl.active_tree(), 7)); LayerImpl* child = root->children()[0]; - child->AddChild(LayerImpl::Create(host_impl.active_tree(), 7)); + child->AddChild(LayerImpl::Create(host_impl.active_tree(), 8)); LayerImpl* grand_child = child->children()[0]; - root->SetScrollable(true); + root->SetScrollClipLayer(root_clip->id()); // Adding children is an internal operation and should not mark layers as // changed. @@ -142,8 +146,7 @@ TEST(LayerImplTest, VerifyLayerChangesAreTrackedProperly) { // they are used. EXECUTE_AND_VERIFY_NEEDS_PUSH_PROPERTIES_AND_SUBTREE_DID_NOT_CHANGE( root->SetUpdateRect(arbitrary_rect_f)); - EXECUTE_AND_VERIFY_NEEDS_PUSH_PROPERTIES_AND_SUBTREE_DID_NOT_CHANGE( - root->SetMaxScrollOffset(arbitrary_vector2d)); + EXECUTE_AND_VERIFY_ONLY_LAYER_CHANGED(root->SetBounds(arbitrary_size)); // Changing these properties affects the entire subtree of layers. EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetAnchorPoint(arbitrary_point_f)); @@ -151,11 +154,11 @@ TEST(LayerImplTest, VerifyLayerChangesAreTrackedProperly) { EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetFilters(arbitrary_filters)); EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetFilters(FilterOperations())); EXECUTE_AND_VERIFY_SUBTREE_CHANGED( - root->SetMaskLayer(LayerImpl::Create(host_impl.active_tree(), 8))); + root->SetMaskLayer(LayerImpl::Create(host_impl.active_tree(), 9))); EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetMasksToBounds(true)); EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetContentsOpaque(true)); EXECUTE_AND_VERIFY_SUBTREE_CHANGED( - root->SetReplicaLayer(LayerImpl::Create(host_impl.active_tree(), 9))); + root->SetReplicaLayer(LayerImpl::Create(host_impl.active_tree(), 10))); EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetPosition(arbitrary_point_f)); EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetPreserves3d(true)); EXECUTE_AND_VERIFY_SUBTREE_CHANGED( @@ -257,15 +260,18 @@ TEST(LayerImplTest, VerifyNeedsUpdateDrawProperties) { FakeImplProxy proxy; FakeLayerTreeHostImpl host_impl(&proxy); EXPECT_TRUE(host_impl.InitializeRenderer(CreateFakeOutputSurface())); - scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl.active_tree(), 1); - root->SetScrollable(true); + scoped_ptr<LayerImpl> root_clip = + LayerImpl::Create(host_impl.active_tree(), 1); + root_clip->AddChild(LayerImpl::Create(host_impl.active_tree(), 2)); + LayerImpl* root = root_clip->children()[0]; + root->SetScrollClipLayer(root_clip->id()); gfx::PointF arbitrary_point_f = gfx::PointF(0.125f, 0.25f); float arbitrary_number = 0.352f; gfx::Size arbitrary_size = gfx::Size(111, 222); gfx::Point arbitrary_point = gfx::Point(333, 444); gfx::Vector2d arbitrary_vector2d = gfx::Vector2d(111, 222); - gfx::Vector2d large_vector2d = gfx::Vector2d(1000, 1000); + gfx::Size large_size = gfx::Size(1000, 1000); gfx::Rect arbitrary_rect = gfx::Rect(arbitrary_point, arbitrary_size); gfx::RectF arbitrary_rect_f = gfx::RectF(arbitrary_point_f, gfx::SizeF(1.234f, 5.678f)); @@ -283,9 +289,9 @@ TEST(LayerImplTest, VerifyNeedsUpdateDrawProperties) { VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetFilters(arbitrary_filters)); // Related scrolling functions. - VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetMaxScrollOffset(large_vector2d)); + VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetBounds(large_size)); VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES( - root->SetMaxScrollOffset(large_vector2d)); + root->SetBounds(large_size)); VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(root->ScrollBy(arbitrary_vector2d)); VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(root->ScrollBy(gfx::Vector2d())); root->SetScrollDelta(gfx::Vector2d(0, 0)); @@ -391,10 +397,20 @@ class LayerImplScrollTest : public testing::Test { LayerImplScrollTest() : host_impl_(&proxy_), root_id_(7) { host_impl_.active_tree() ->SetRootLayer(LayerImpl::Create(host_impl_.active_tree(), root_id_)); - host_impl_.active_tree()->root_layer()->SetScrollable(true); + host_impl_.active_tree()->root_layer()->AddChild( + LayerImpl::Create(host_impl_.active_tree(), root_id_ + 1)); + layer()->SetScrollClipLayer(root_id_); + // Set the max scroll offset by noting that the root layer has bounds (1,1), + // thus whatever bounds are set for the layer will be the max scroll + // offset plus 1 in each direction. + host_impl_.active_tree()->root_layer()->SetBounds(gfx::Size(1, 1)); + gfx::Vector2d max_scroll_offset(51, 81); + layer()->SetBounds(gfx::Size(max_scroll_offset.x(), max_scroll_offset.y())); } - LayerImpl* layer() { return host_impl_.active_tree()->root_layer(); } + LayerImpl* layer() { + return host_impl_.active_tree()->root_layer()->children()[0]; + } private: FakeImplProxy proxy_; @@ -405,8 +421,6 @@ class LayerImplScrollTest : public testing::Test { TEST_F(LayerImplScrollTest, ScrollByWithZeroOffset) { // Test that LayerImpl::ScrollBy only affects ScrollDelta and total scroll // offset is bounded by the range [0, max scroll offset]. - gfx::Vector2d max_scroll_offset(50, 80); - layer()->SetMaxScrollOffset(max_scroll_offset); EXPECT_VECTOR_EQ(gfx::Vector2dF(), layer()->TotalScrollOffset()); EXPECT_VECTOR_EQ(gfx::Vector2dF(), layer()->scroll_offset()); @@ -426,9 +440,7 @@ TEST_F(LayerImplScrollTest, ScrollByWithZeroOffset) { } TEST_F(LayerImplScrollTest, ScrollByWithNonZeroOffset) { - gfx::Vector2d max_scroll_offset(50, 80); gfx::Vector2d scroll_offset(10, 5); - layer()->SetMaxScrollOffset(max_scroll_offset); layer()->SetScrollOffset(scroll_offset); EXPECT_VECTOR_EQ(scroll_offset, layer()->TotalScrollOffset()); @@ -472,9 +484,7 @@ class ScrollDelegateIgnore : public LayerScrollOffsetDelegate { }; TEST_F(LayerImplScrollTest, ScrollByWithIgnoringDelegate) { - gfx::Vector2d max_scroll_offset(50, 80); gfx::Vector2d scroll_offset(10, 5); - layer()->SetMaxScrollOffset(max_scroll_offset); layer()->SetScrollOffset(scroll_offset); EXPECT_VECTOR_EQ(scroll_offset, layer()->TotalScrollOffset()); @@ -525,9 +535,7 @@ class ScrollDelegateAccept : public LayerScrollOffsetDelegate { }; TEST_F(LayerImplScrollTest, ScrollByWithAcceptingDelegate) { - gfx::Vector2d max_scroll_offset(50, 80); gfx::Vector2d scroll_offset(10, 5); - layer()->SetMaxScrollOffset(max_scroll_offset); layer()->SetScrollOffset(scroll_offset); EXPECT_VECTOR_EQ(scroll_offset, layer()->TotalScrollOffset()); @@ -559,12 +567,10 @@ TEST_F(LayerImplScrollTest, ScrollByWithAcceptingDelegate) { } TEST_F(LayerImplScrollTest, ApplySentScrollsNoDelegate) { - gfx::Vector2d max_scroll_offset(50, 80); gfx::Vector2d scroll_offset(10, 5); gfx::Vector2dF scroll_delta(20.5f, 8.5f); gfx::Vector2d sent_scroll_delta(12, -3); - layer()->SetMaxScrollOffset(max_scroll_offset); layer()->SetScrollOffset(scroll_offset); layer()->ScrollBy(scroll_delta); layer()->SetSentScrollDelta(sent_scroll_delta); @@ -583,12 +589,10 @@ TEST_F(LayerImplScrollTest, ApplySentScrollsNoDelegate) { } TEST_F(LayerImplScrollTest, ApplySentScrollsWithIgnoringDelegate) { - gfx::Vector2d max_scroll_offset(50, 80); gfx::Vector2d scroll_offset(10, 5); gfx::Vector2d sent_scroll_delta(12, -3); gfx::Vector2dF fixed_offset(32, 12); - layer()->SetMaxScrollOffset(max_scroll_offset); layer()->SetScrollOffset(scroll_offset); ScrollDelegateIgnore delegate; delegate.set_fixed_offset(fixed_offset); @@ -607,12 +611,10 @@ TEST_F(LayerImplScrollTest, ApplySentScrollsWithIgnoringDelegate) { } TEST_F(LayerImplScrollTest, ApplySentScrollsWithAcceptingDelegate) { - gfx::Vector2d max_scroll_offset(50, 80); gfx::Vector2d scroll_offset(10, 5); gfx::Vector2d sent_scroll_delta(12, -3); gfx::Vector2dF scroll_delta(20.5f, 8.5f); - layer()->SetMaxScrollOffset(max_scroll_offset); layer()->SetScrollOffset(scroll_offset); ScrollDelegateAccept delegate; layer()->SetScrollOffsetDelegate(&delegate); @@ -633,12 +635,10 @@ TEST_F(LayerImplScrollTest, ApplySentScrollsWithAcceptingDelegate) { // The user-scrollability breaks for zoomed-in pages. So disable this. // http://crbug.com/322223 TEST_F(LayerImplScrollTest, DISABLED_ScrollUserUnscrollableLayer) { - gfx::Vector2d max_scroll_offset(50, 80); gfx::Vector2d scroll_offset(10, 5); gfx::Vector2dF scroll_delta(20.5f, 8.5f); layer()->set_user_scrollable_vertical(false); - layer()->SetMaxScrollOffset(max_scroll_offset); layer()->SetScrollOffset(scroll_offset); gfx::Vector2dF unscrolled = layer()->ScrollBy(scroll_delta); diff --git a/cc/layers/layer_perftest.cc b/cc/layers/layer_perftest.cc index 32e99fe..865453d 100644 --- a/cc/layers/layer_perftest.cc +++ b/cc/layers/layer_perftest.cc @@ -80,7 +80,7 @@ TEST_F(LayerPerfTest, PushPropertiesTo) { test_layer->SetDoubleSided(double_sided); test_layer->SetHideLayerAndSubtree(hide_layer_and_subtree); test_layer->SetMasksToBounds(masks_to_bounds); - test_layer->SetScrollable(scrollable); + test_layer->SetScrollClipLayer(scrollable ? test_layer : NULL); test_layer->PushPropertiesTo(impl_layer.get()); anchor_point_z += 0.01f; diff --git a/cc/layers/layer_position_constraint_unittest.cc b/cc/layers/layer_position_constraint_unittest.cc index 57e4c1d..3557f7f 100644 --- a/cc/layers/layer_position_constraint_unittest.cc +++ b/cc/layers/layer_position_constraint_unittest.cc @@ -39,13 +39,14 @@ void ExecuteCalculateDrawProperties(LayerImpl* root_layer, bool can_use_lcd_text) { gfx::Transform identity_matrix; std::vector<LayerImpl*> dummy_render_surface_layer_list; + LayerImpl* scroll_layer = root_layer->children()[0]; gfx::Size device_viewport_size = gfx::Size(root_layer->bounds().width() * device_scale_factor, root_layer->bounds().height() * device_scale_factor); - // We are probably not testing what is intended if the root_layer bounds are + // We are probably not testing what is intended if the scroll_layer bounds are // empty. - DCHECK(!root_layer->bounds().IsEmpty()); + DCHECK(!scroll_layer->bounds().IsEmpty()); LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs( root_layer, device_viewport_size, &dummy_render_surface_layer_list); inputs.device_scale_factor = device_scale_factor; @@ -66,6 +67,7 @@ class LayerPositionConstraintTest : public testing::Test { LayerPositionConstraintTest() : host_impl_(&proxy_) { root_ = CreateTreeForTest(); + scroll_ = root_->children()[0]; fixed_to_top_left_.set_is_fixed_position(true); fixed_to_bottom_right_.set_is_fixed_position(true); fixed_to_bottom_right_.set_is_fixed_to_right_edge(true); @@ -74,6 +76,8 @@ class LayerPositionConstraintTest : public testing::Test { scoped_ptr<LayerImpl> CreateTreeForTest() { scoped_ptr<LayerImpl> root = + LayerImpl::Create(host_impl_.active_tree(), 42); + scoped_ptr<LayerImpl> scroll_layer = LayerImpl::Create(host_impl_.active_tree(), 1); scoped_ptr<LayerImpl> child = LayerImpl::Create(host_impl_.active_tree(), 2); @@ -85,8 +89,9 @@ class LayerPositionConstraintTest : public testing::Test { gfx::Transform IdentityMatrix; gfx::PointF anchor; gfx::PointF position; - gfx::Size bounds(100, 100); - SetLayerPropertiesForTesting(root.get(), + gfx::Size bounds(200, 200); + gfx::Size clip_bounds(100, 100); + SetLayerPropertiesForTesting(scroll_layer.get(), IdentityMatrix, IdentityMatrix, anchor, @@ -115,16 +120,15 @@ class LayerPositionConstraintTest : public testing::Test { bounds, false); - root->SetMaxScrollOffset(gfx::Vector2d(100, 100)); - root->SetScrollable(true); - child->SetMaxScrollOffset(gfx::Vector2d(100, 100)); - child->SetScrollable(true); - grand_child->SetMaxScrollOffset(gfx::Vector2d(100, 100)); - grand_child->SetScrollable(true); + root->SetBounds(clip_bounds); + scroll_layer->SetScrollClipLayer(root->id()); + child->SetScrollClipLayer(root->id()); + grand_child->SetScrollClipLayer(root->id()); grand_child->AddChild(great_grand_child.Pass()); child->AddChild(grand_child.Pass()); - root->AddChild(child.Pass()); + scroll_layer->AddChild(child.Pass()); + root->AddChild(scroll_layer.Pass()); return root.Pass(); } @@ -133,6 +137,7 @@ class LayerPositionConstraintTest : public testing::Test { FakeImplProxy proxy_; FakeLayerTreeHostImpl host_impl_; scoped_ptr<LayerImpl> root_; + LayerImpl* scroll_; LayerPositionConstraint fixed_to_top_left_; LayerPositionConstraint fixed_to_bottom_right_; @@ -142,7 +147,7 @@ TEST_F(LayerPositionConstraintTest, ScrollCompensationForFixedPositionLayerWithDirectContainer) { // This test checks for correct scroll compensation when the fixed-position // container is the direct parent of the fixed-position layer. - LayerImpl* child = root_->children()[0]; + LayerImpl* child = scroll_->children()[0]; LayerImpl* grand_child = child->children()[0]; child->SetIsContainerForFixedPositionLayers(true); @@ -210,7 +215,7 @@ TEST_F(LayerPositionConstraintTest, // Transforms are in general non-commutative; using something like a // non-uniform scale helps to verify that translations and non-uniform scales // are applied in the correct order. - LayerImpl* child = root_->children()[0]; + LayerImpl* child = scroll_->children()[0]; LayerImpl* grand_child = child->children()[0]; // This scale will cause child and grand_child to be effectively 200 x 800 @@ -282,7 +287,7 @@ TEST_F(LayerPositionConstraintTest, ScrollCompensationForFixedPositionLayerWithDistantContainer) { // This test checks for correct scroll compensation when the fixed-position // container is NOT the direct parent of the fixed-position layer. - LayerImpl* child = root_->children()[0]; + LayerImpl* child = scroll_->children()[0]; LayerImpl* grand_child = child->children()[0]; LayerImpl* great_grand_child = grand_child->children()[0]; @@ -362,7 +367,7 @@ TEST_F(LayerPositionConstraintTest, // container is NOT the direct parent of the fixed-position layer, and the // hierarchy has various transforms that have to be processed in the correct // order. - LayerImpl* child = root_->children()[0]; + LayerImpl* child = scroll_->children()[0]; LayerImpl* grand_child = child->children()[0]; LayerImpl* great_grand_child = grand_child->children()[0]; @@ -474,7 +479,7 @@ TEST_F(LayerPositionConstraintTest, // container is NOT the direct parent of the fixed-position layer, and the // hierarchy has various transforms that have to be processed in the correct // order. - LayerImpl* child = root_->children()[0]; + LayerImpl* child = scroll_->children()[0]; LayerImpl* grand_child = child->children()[0]; LayerImpl* great_grand_child = grand_child->children()[0]; @@ -585,7 +590,7 @@ TEST_F(LayerPositionConstraintTest, // container contributes to a different render surface than the fixed-position // layer. In this case, the surface draw transforms also have to be accounted // for when checking the scroll delta. - LayerImpl* child = root_->children()[0]; + LayerImpl* child = scroll_->children()[0]; LayerImpl* grand_child = child->children()[0]; LayerImpl* great_grand_child = grand_child->children()[0]; @@ -709,7 +714,7 @@ TEST_F(LayerPositionConstraintTest, // layer, with additional render surfaces in-between. This checks that the // conversion to ancestor surfaces is accumulated properly in the final matrix // transform. - LayerImpl* child = root_->children()[0]; + LayerImpl* child = scroll_->children()[0]; LayerImpl* grand_child = child->children()[0]; LayerImpl* great_grand_child = grand_child->children()[0]; @@ -896,7 +901,7 @@ TEST_F(LayerPositionConstraintTest, // should be treated like a layer that contributes to a render target, and // that render target is completely irrelevant; it should not affect the // scroll compensation. - LayerImpl* child = root_->children()[0]; + LayerImpl* child = scroll_->children()[0]; LayerImpl* grand_child = child->children()[0]; child->SetIsContainerForFixedPositionLayers(true); @@ -974,7 +979,7 @@ TEST_F(LayerPositionConstraintTest, // This test checks the scenario where a fixed-position layer also happens to // be a container itself for a descendant fixed position layer. In particular, // the layer should not accidentally be fixed to itself. - LayerImpl* child = root_->children()[0]; + LayerImpl* child = scroll_->children()[0]; LayerImpl* grand_child = child->children()[0]; child->SetIsContainerForFixedPositionLayers(true); @@ -1034,67 +1039,6 @@ TEST_F(LayerPositionConstraintTest, } TEST_F(LayerPositionConstraintTest, - ScrollCompensationForFixedPositionLayerThatHasNoContainer) { - // This test checks scroll compensation when a fixed-position layer does not - // find any ancestor that is a "containerForFixedPositionLayers". In this - // situation, the layer should be fixed to the root layer. - LayerImpl* child = root_->children()[0]; - LayerImpl* grand_child = child->children()[0]; - - gfx::Transform rotation_by_z; - rotation_by_z.RotateAboutZAxis(90.0); - - root_->SetTransform(rotation_by_z); - grand_child->SetPositionConstraint(fixed_to_top_left_); - - // Case 1: root scroll delta of 0, 0 - root_->SetScrollDelta(gfx::Vector2d(0, 0)); - ExecuteCalculateDrawProperties(root_.get()); - - gfx::Transform identity_matrix; - - EXPECT_TRANSFORMATION_MATRIX_EQ(rotation_by_z, child->draw_transform()); - EXPECT_TRANSFORMATION_MATRIX_EQ(rotation_by_z, - grand_child->draw_transform()); - - // Case 2: root scroll delta of 10, 10 - root_->SetScrollDelta(gfx::Vector2d(10, 20)); - ExecuteCalculateDrawProperties(root_.get()); - - gfx::Transform expected_child_transform; - expected_child_transform.Translate(-10.0, -20.0); - expected_child_transform.PreconcatTransform(rotation_by_z); - - EXPECT_TRANSFORMATION_MATRIX_EQ(expected_child_transform, - child->draw_transform()); - EXPECT_TRANSFORMATION_MATRIX_EQ(rotation_by_z, - grand_child->draw_transform()); - - // Case 3: fixed-container size delta of 20, 20 - root_->SetFixedContainerSizeDelta(gfx::Vector2d(20, 20)); - ExecuteCalculateDrawProperties(root_.get()); - - // Top-left fixed-position layer should not be affected by container size. - EXPECT_TRANSFORMATION_MATRIX_EQ(expected_child_transform, - child->draw_transform()); - EXPECT_TRANSFORMATION_MATRIX_EQ(rotation_by_z, - grand_child->draw_transform()); - - // Case 4: Bottom-right fixed-position layer. - grand_child->SetPositionConstraint(fixed_to_bottom_right_); - ExecuteCalculateDrawProperties(root_.get()); - - gfx::Transform expected_grand_child_transform; - expected_grand_child_transform.Translate(-20.0, 20.0); - expected_grand_child_transform.PreconcatTransform(rotation_by_z); - - EXPECT_TRANSFORMATION_MATRIX_EQ(expected_child_transform, - child->draw_transform()); - EXPECT_TRANSFORMATION_MATRIX_EQ(expected_grand_child_transform, - grand_child->draw_transform()); -} - -TEST_F(LayerPositionConstraintTest, ScrollCompensationForFixedWithinFixedWithSameContainer) { // This test checks scroll compensation for a fixed-position layer that is // inside of another fixed-position layer and both share the same container. @@ -1102,7 +1046,7 @@ TEST_F(LayerPositionConstraintTest, // the scroll compensation, and the child fixed-position layer does not // need to compensate further. - LayerImpl* child = root_->children()[0]; + LayerImpl* child = scroll_->children()[0]; LayerImpl* grand_child = child->children()[0]; LayerImpl* great_grand_child = grand_child->children()[0]; @@ -1161,7 +1105,7 @@ TEST_F(LayerPositionConstraintTest, // position containers. In this situation, the child fixed-position element // would still have to compensate with respect to its container. - LayerImpl* container1 = root_->children()[0]; + LayerImpl* container1 = scroll_->children()[0]; LayerImpl* fixed_to_container1 = container1->children()[0]; LayerImpl* container2 = fixed_to_container1->children()[0]; diff --git a/cc/layers/layer_unittest.cc b/cc/layers/layer_unittest.cc index 55f5616..aa7e205a 100644 --- a/cc/layers/layer_unittest.cc +++ b/cc/layers/layer_unittest.cc @@ -551,7 +551,8 @@ TEST_F(LayerTest, CheckPropertyChangeCausesCorrectBehavior) { EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetPosition(gfx::PointF(4.f, 9.f))); EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetSublayerTransform( gfx::Transform(0.0, 0.0, 0.0, 0.0, 0.0, 0.0))); - EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetScrollable(true)); + // We can use any layer pointer here since we aren't syncing for real. + EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetScrollClipLayer(test_layer.get())); EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetUserScrollable(true, false)); EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetScrollOffset( gfx::Vector2d(10, 10))); diff --git a/cc/layers/painted_scrollbar_layer.cc b/cc/layers/painted_scrollbar_layer.cc index 4466d58..2a68650 100644 --- a/cc/layers/painted_scrollbar_layer.cc +++ b/cc/layers/painted_scrollbar_layer.cc @@ -28,16 +28,17 @@ scoped_ptr<LayerImpl> PaintedScrollbarLayer::CreateLayerImpl( scoped_refptr<PaintedScrollbarLayer> PaintedScrollbarLayer::Create( scoped_ptr<Scrollbar> scrollbar, - int scroll_layer_id) { + Layer* scroll_layer) { return make_scoped_refptr( - new PaintedScrollbarLayer(scrollbar.Pass(), scroll_layer_id)); + new PaintedScrollbarLayer(scrollbar.Pass(), scroll_layer)); } PaintedScrollbarLayer::PaintedScrollbarLayer( scoped_ptr<Scrollbar> scrollbar, - int scroll_layer_id) + Layer* scroll_layer) : scrollbar_(scrollbar.Pass()), - scroll_layer_id_(scroll_layer_id), + scroll_layer_(scroll_layer), + clip_layer_(NULL), thumb_thickness_(scrollbar_->ThumbThickness()), thumb_length_(scrollbar_->ThumbLength()), is_overlay_(scrollbar_->IsOverlay()), @@ -49,14 +50,22 @@ PaintedScrollbarLayer::PaintedScrollbarLayer( PaintedScrollbarLayer::~PaintedScrollbarLayer() {} int PaintedScrollbarLayer::ScrollLayerId() const { - return scroll_layer_id_; + return scroll_layer_->id(); } -void PaintedScrollbarLayer::SetScrollLayerId(int id) { - if (id == scroll_layer_id_) +void PaintedScrollbarLayer::SetScrollLayer(scoped_refptr<Layer> layer) { + if (layer == scroll_layer_) return; - scroll_layer_id_ = id; + scroll_layer_ = layer; + SetNeedsFullTreeSync(); +} + +void PaintedScrollbarLayer::SetClipLayer(scoped_refptr<Layer> layer) { + if (layer == clip_layer_) + return; + + clip_layer_ = layer; SetNeedsFullTreeSync(); } @@ -109,6 +118,8 @@ void PaintedScrollbarLayer::CalculateContentsScale( void PaintedScrollbarLayer::PushPropertiesTo(LayerImpl* layer) { ContentsScalingLayer::PushPropertiesTo(layer); + PushScrollClipPropertiesTo(layer); + PaintedScrollbarLayerImpl* scrollbar_layer = static_cast<PaintedScrollbarLayerImpl*>(layer); @@ -136,6 +147,16 @@ ScrollbarLayerInterface* PaintedScrollbarLayer::ToScrollbarLayer() { return this; } +void PaintedScrollbarLayer::PushScrollClipPropertiesTo(LayerImpl* layer) { + PaintedScrollbarLayerImpl* scrollbar_layer = + static_cast<PaintedScrollbarLayerImpl*>(layer); + + scrollbar_layer->SetScrollLayerById(scroll_layer_ ? scroll_layer_->id() + : Layer::INVALID_ID); + scrollbar_layer->SetClipLayerById(clip_layer_ ? clip_layer_->id() + : Layer::INVALID_ID); +} + void PaintedScrollbarLayer::SetLayerTreeHost(LayerTreeHost* host) { // When the LTH is set to null or has changed, then this layer should remove // all of its associated resources. diff --git a/cc/layers/painted_scrollbar_layer.h b/cc/layers/painted_scrollbar_layer.h index c24c0aa..0b84451 100644 --- a/cc/layers/painted_scrollbar_layer.h +++ b/cc/layers/painted_scrollbar_layer.h @@ -24,14 +24,15 @@ class CC_EXPORT PaintedScrollbarLayer : public ScrollbarLayerInterface, static scoped_refptr<PaintedScrollbarLayer> Create( scoped_ptr<Scrollbar> scrollbar, - int scroll_layer_id); + Layer* scroll_layer); virtual bool OpacityCanAnimateOnImplThread() const OVERRIDE; virtual ScrollbarLayerInterface* ToScrollbarLayer() OVERRIDE; // ScrollbarLayerInterface virtual int ScrollLayerId() const OVERRIDE; - virtual void SetScrollLayerId(int id) OVERRIDE; + virtual void SetScrollLayer(scoped_refptr<Layer> layer) OVERRIDE; + virtual void SetClipLayer(scoped_refptr<Layer> layer) OVERRIDE; virtual ScrollbarOrientation orientation() const OVERRIDE; @@ -40,6 +41,7 @@ class CC_EXPORT PaintedScrollbarLayer : public ScrollbarLayerInterface, const OcclusionTracker* occlusion) OVERRIDE; virtual void SetLayerTreeHost(LayerTreeHost* host) OVERRIDE; virtual void PushPropertiesTo(LayerImpl* layer) OVERRIDE; + virtual void PushScrollClipPropertiesTo(LayerImpl* layer) OVERRIDE; virtual void CalculateContentsScale(float ideal_contents_scale, float device_scale_factor, float page_scale_factor, @@ -49,7 +51,7 @@ class CC_EXPORT PaintedScrollbarLayer : public ScrollbarLayerInterface, gfx::Size* content_bounds) OVERRIDE; protected: - PaintedScrollbarLayer(scoped_ptr<Scrollbar> scrollbar, int scroll_layer_id); + PaintedScrollbarLayer(scoped_ptr<Scrollbar> scrollbar, Layer* scroll_layer); virtual ~PaintedScrollbarLayer(); // For unit tests @@ -79,7 +81,8 @@ class CC_EXPORT PaintedScrollbarLayer : public ScrollbarLayerInterface, ScrollbarPart part); scoped_ptr<Scrollbar> scrollbar_; - int scroll_layer_id_; + scoped_refptr<Layer> scroll_layer_; + scoped_refptr<Layer> clip_layer_; // Snapshot of properties taken in UpdateThumbAndTrackGeometry and used in // PushPropertiesTo. diff --git a/cc/layers/painted_scrollbar_layer_impl.cc b/cc/layers/painted_scrollbar_layer_impl.cc index d67fbe4..2af722d 100644 --- a/cc/layers/painted_scrollbar_layer_impl.cc +++ b/cc/layers/painted_scrollbar_layer_impl.cc @@ -29,7 +29,7 @@ PaintedScrollbarLayerImpl::PaintedScrollbarLayerImpl( LayerTreeImpl* tree_impl, int id, ScrollbarOrientation orientation) - : ScrollbarLayerImplBase(tree_impl, id, orientation, false), + : ScrollbarLayerImplBase(tree_impl, id, orientation, false, false), track_ui_resource_id_(0), thumb_ui_resource_id_(0), thumb_thickness_(0), diff --git a/cc/layers/scrollbar_layer_impl_base.cc b/cc/layers/scrollbar_layer_impl_base.cc index 55f46f5..22583a1 100644 --- a/cc/layers/scrollbar_layer_impl_base.cc +++ b/cc/layers/scrollbar_layer_impl_base.cc @@ -5,7 +5,7 @@ #include "cc/layers/scrollbar_layer_impl_base.h" #include <algorithm> -#include "cc/layers/layer.h" +#include "cc/trees/layer_tree_impl.h" #include "ui/gfx/rect_conversions.h" namespace cc { @@ -14,10 +14,12 @@ ScrollbarLayerImplBase::ScrollbarLayerImplBase( LayerTreeImpl* tree_impl, int id, ScrollbarOrientation orientation, - bool is_left_side_vertical_scrollbar) + bool is_left_side_vertical_scrollbar, + bool is_overlay) : LayerImpl(tree_impl, id), - scroll_layer_id_(Layer::INVALID_ID), - is_overlay_scrollbar_(false), + scroll_layer_(NULL), + clip_layer_(NULL), + is_overlay_scrollbar_(is_overlay), thumb_thickness_scale_factor_(1.f), current_pos_(0.f), maximum_(0), @@ -26,14 +28,50 @@ ScrollbarLayerImplBase::ScrollbarLayerImplBase( vertical_adjust_(0.f), visible_to_total_length_ratio_(1.f) {} +ScrollbarLayerImplBase::~ScrollbarLayerImplBase() { +} + void ScrollbarLayerImplBase::PushPropertiesTo(LayerImpl* layer) { LayerImpl::PushPropertiesTo(layer); + DCHECK(layer->ToScrollbarLayer()); + layer->ToScrollbarLayer()->set_is_overlay_scrollbar(is_overlay_scrollbar_); + PushScrollClipPropertiesTo(layer); +} + +void ScrollbarLayerImplBase::PushScrollClipPropertiesTo(LayerImpl* layer) { + DCHECK(layer->ToScrollbarLayer()); + layer->ToScrollbarLayer()->SetScrollLayerById(ScrollLayerId()); + layer->ToScrollbarLayer()->SetClipLayerById(ClipLayerId()); } ScrollbarLayerImplBase* ScrollbarLayerImplBase::ToScrollbarLayer() { return this; } +void ScrollbarLayerImplBase::SetScrollLayerById(int id) { + LayerImpl* scroll_layer = layer_tree_impl()->LayerById(id); + if (scroll_layer_ == scroll_layer) + return; + + if (scroll_layer_) + scroll_layer_->RemoveScrollbar(this); + scroll_layer_ = scroll_layer; + if (scroll_layer_) + scroll_layer_->AddScrollbar(this); +} + +void ScrollbarLayerImplBase::SetClipLayerById(int id) { + LayerImpl* clip_layer = layer_tree_impl()->LayerById(id); + if (clip_layer_ == clip_layer) + return; + + if (clip_layer_) + clip_layer_->RemoveScrollbar(this); + clip_layer_ = clip_layer; + if (clip_layer_) + clip_layer_->AddScrollbar(this); +} + gfx::Rect ScrollbarLayerImplBase::ScrollbarLayerRectToContentRect( const gfx::RectF& layer_rect) const { // Don't intersect with the bounds as in LayerRectToContentRect() because @@ -177,4 +215,11 @@ gfx::Rect ScrollbarLayerImplBase::ComputeThumbQuadRect() const { return ScrollbarLayerRectToContentRect(thumb_rect); } +void ScrollbarLayerImplBase::ScrollbarParametersDidChange() { + if (!clip_layer_ || !scroll_layer_) + return; + + scroll_layer_->SetScrollbarPosition(this, clip_layer_); +} + } // namespace cc diff --git a/cc/layers/scrollbar_layer_impl_base.h b/cc/layers/scrollbar_layer_impl_base.h index 6bba749..e7a2fc7 100644 --- a/cc/layers/scrollbar_layer_impl_base.h +++ b/cc/layers/scrollbar_layer_impl_base.h @@ -7,6 +7,7 @@ #include "cc/base/cc_export.h" #include "cc/input/scrollbar.h" +#include "cc/layers/layer.h" #include "cc/layers/layer_impl.h" namespace cc { @@ -15,8 +16,16 @@ class LayerTreeImpl; class CC_EXPORT ScrollbarLayerImplBase : public LayerImpl { public: - int ScrollLayerId() const { return scroll_layer_id_; } - void set_scroll_layer_id(int id) { scroll_layer_id_ = id; } + int ScrollLayerId() const { + return scroll_layer_ ? scroll_layer_->id() : Layer::INVALID_ID; + } + void ClearScrollLayer() { scroll_layer_ = NULL; } + void SetScrollLayerById(int id); + int ClipLayerId() const { + return clip_layer_ ? clip_layer_->id() : Layer::INVALID_ID; + } + void ClearClipLayer() { clip_layer_ = NULL; } + void SetClipLayerById(int id); float current_pos() const { return current_pos_; } void SetCurrentPos(float current_pos); @@ -37,6 +46,7 @@ class CC_EXPORT ScrollbarLayerImplBase : public LayerImpl { virtual void PushPropertiesTo(LayerImpl* layer) OVERRIDE; virtual ScrollbarLayerImplBase* ToScrollbarLayer() OVERRIDE; + void PushScrollClipPropertiesTo(LayerImpl* layer); void SetVisibleToTotalLengthRatio(float ratio); virtual gfx::Rect ComputeThumbQuadRect() const; @@ -46,12 +56,15 @@ class CC_EXPORT ScrollbarLayerImplBase : public LayerImpl { } void SetThumbThicknessScaleFactor(float thumb_thickness_scale_factor); + void ScrollbarParametersDidChange(); + protected: ScrollbarLayerImplBase(LayerTreeImpl* tree_impl, int id, ScrollbarOrientation orientation, - bool is_left_side_vertical_scrollbar); - virtual ~ScrollbarLayerImplBase() {} + bool is_left_side_vertical_scrollbar, + bool is_overlay); + virtual ~ScrollbarLayerImplBase(); gfx::Rect ScrollbarLayerRectToContentRect(const gfx::RectF& layer_rect) const; @@ -69,7 +82,8 @@ class CC_EXPORT ScrollbarLayerImplBase : public LayerImpl { virtual bool IsThumbResizable() const = 0; private: - int scroll_layer_id_; + LayerImpl* scroll_layer_; + LayerImpl* clip_layer_; bool is_overlay_scrollbar_; float thumb_thickness_scale_factor_; diff --git a/cc/layers/scrollbar_layer_interface.h b/cc/layers/scrollbar_layer_interface.h index bbb0da6..3a66963 100644 --- a/cc/layers/scrollbar_layer_interface.h +++ b/cc/layers/scrollbar_layer_interface.h @@ -10,10 +10,15 @@ namespace cc { +class Layer; +class LayerImpl; + class CC_EXPORT ScrollbarLayerInterface { public: virtual int ScrollLayerId() const = 0; - virtual void SetScrollLayerId(int id) = 0; + virtual void SetScrollLayer(scoped_refptr<Layer> layer) = 0; + virtual void SetClipLayer(scoped_refptr<Layer> layer) = 0; + virtual void PushScrollClipPropertiesTo(LayerImpl* layer) = 0; virtual ScrollbarOrientation orientation() const = 0; diff --git a/cc/layers/scrollbar_layer_unittest.cc b/cc/layers/scrollbar_layer_unittest.cc index 4fab625..3de091f 100644 --- a/cc/layers/scrollbar_layer_unittest.cc +++ b/cc/layers/scrollbar_layer_unittest.cc @@ -45,9 +45,9 @@ LayerImpl* LayerImplForScrollAreaAndScrollbar( const bool kIsLeftSideVerticalScrollbar = false; child2 = SolidColorScrollbarLayer::Create( scrollbar->Orientation(), thumb_thickness, - kIsLeftSideVerticalScrollbar, child1->id()); + kIsLeftSideVerticalScrollbar, child1.get()); } else { - child2 = PaintedScrollbarLayer::Create(scrollbar.Pass(), child1->id()); + child2 = PaintedScrollbarLayer::Create(scrollbar.Pass(), child1.get()); } layer_tree_root->AddChild(child1); layer_tree_root->InsertChild(child2, reverse_order ? 0 : 1); @@ -66,7 +66,8 @@ TEST(ScrollbarLayerTest, ResolveScrollLayerPointer) { static_cast<PaintedScrollbarLayerImpl*>( layer_impl_tree_root->children()[1]); - EXPECT_EQ(cc_child1->horizontal_scrollbar_layer(), cc_child2); + EXPECT_EQ(cc_child1->scrollbars()->size(), 1UL); + EXPECT_EQ(*(cc_child1->scrollbars()->begin()), cc_child2); } TEST(ScrollbarLayerTest, ResolveScrollLayerPointer_ReverseOrder) { @@ -80,7 +81,8 @@ TEST(ScrollbarLayerTest, ResolveScrollLayerPointer_ReverseOrder) { layer_impl_tree_root->children()[0]); LayerImpl* cc_child2 = layer_impl_tree_root->children()[1]; - EXPECT_EQ(cc_child2->horizontal_scrollbar_layer(), cc_child1); + EXPECT_EQ(cc_child2->scrollbars()->size(), 1UL); + EXPECT_EQ(*(cc_child2->scrollbars()->begin()), cc_child1); } TEST(ScrollbarLayerTest, ShouldScrollNonOverlayOnMainThread) { @@ -121,19 +123,24 @@ TEST(PaintedScrollbarLayerTest, ScrollOffsetSynchronization) { scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar); scoped_refptr<Layer> layer_tree_root = Layer::Create(); + scoped_refptr<Layer> scroll_layer = Layer::Create(); scoped_refptr<Layer> content_layer = Layer::Create(); scoped_refptr<Layer> scrollbar_layer = - PaintedScrollbarLayer::Create(scrollbar.Pass(), layer_tree_root->id()); + PaintedScrollbarLayer::Create(scrollbar.Pass(), layer_tree_root.get()); - layer_tree_root->SetScrollable(true); - layer_tree_root->SetScrollOffset(gfx::Vector2d(10, 20)); - layer_tree_root->SetMaxScrollOffset(gfx::Vector2d(30, 50)); - layer_tree_root->SetBounds(gfx::Size(100, 200)); + // Choose bounds to give max_scroll_offset = (30, 50). + layer_tree_root->SetBounds(gfx::Size(70, 150)); + scroll_layer->SetScrollClipLayer(layer_tree_root.get()); + scroll_layer->SetScrollOffset(gfx::Vector2d(10, 20)); + scroll_layer->SetBounds(gfx::Size(100, 200)); content_layer->SetBounds(gfx::Size(100, 200)); host->SetRootLayer(layer_tree_root); - layer_tree_root->AddChild(content_layer); + layer_tree_root->AddChild(scroll_layer); + scroll_layer->AddChild(content_layer); layer_tree_root->AddChild(scrollbar_layer); + scrollbar_layer->ToScrollbarLayer()->SetScrollLayer(scroll_layer); + scrollbar_layer->ToScrollbarLayer()->SetClipLayer(layer_tree_root); layer_tree_root->SavePaintProperties(); content_layer->SavePaintProperties(); @@ -147,10 +154,11 @@ TEST(PaintedScrollbarLayerTest, ScrollOffsetSynchronization) { EXPECT_EQ(10.f, cc_scrollbar_layer->current_pos()); EXPECT_EQ(30, cc_scrollbar_layer->maximum()); - layer_tree_root->SetScrollOffset(gfx::Vector2d(100, 200)); - layer_tree_root->SetMaxScrollOffset(gfx::Vector2d(300, 500)); - layer_tree_root->SetBounds(gfx::Size(1000, 2000)); + layer_tree_root->SetBounds(gfx::Size(700, 1500)); layer_tree_root->SavePaintProperties(); + scroll_layer->SetBounds(gfx::Size(1000, 2000)); + scroll_layer->SetScrollOffset(gfx::Vector2d(100, 200)); + scroll_layer->SavePaintProperties(); content_layer->SetBounds(gfx::Size(1000, 2000)); content_layer->SavePaintProperties(); @@ -163,65 +171,73 @@ TEST(PaintedScrollbarLayerTest, ScrollOffsetSynchronization) { EXPECT_EQ(100.f, cc_scrollbar_layer->current_pos()); EXPECT_EQ(300, cc_scrollbar_layer->maximum()); - layer_impl_tree_root->ScrollBy(gfx::Vector2d(12, 34)); + LayerImpl* scroll_layer_impl = layer_impl_tree_root->children()[0]; + scroll_layer_impl->ScrollBy(gfx::Vector2d(12, 34)); EXPECT_EQ(112.f, cc_scrollbar_layer->current_pos()); EXPECT_EQ(300, cc_scrollbar_layer->maximum()); } +#define UPDATE_AND_EXTRACT_LAYER_POINTERS() \ + do { \ + scrollbar_layer->UpdateThumbAndTrackGeometry(); \ + root_clip_layer_impl = host->CommitAndCreateLayerImplTree(); \ + root_layer_impl = root_clip_layer_impl->children()[0]; \ + scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>( \ + root_layer_impl->children()[1]); \ + scrollbar_layer_impl->ScrollbarParametersDidChange(); \ + } while (false) + TEST(ScrollbarLayerTest, ThumbRect) { scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(); + scoped_refptr<Layer> root_clip_layer = Layer::Create(); scoped_refptr<Layer> root_layer = Layer::Create(); scoped_refptr<Layer> content_layer = Layer::Create(); scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer = - FakePaintedScrollbarLayer::Create(false, true, root_layer->id()); + FakePaintedScrollbarLayer::Create(false, true, root_layer.get()); - root_layer->SetScrollable(true); - root_layer->SetMaxScrollOffset(gfx::Vector2d(80, 0)); + root_layer->SetScrollClipLayer(root_clip_layer.get()); + // Give the root-clip a size that will result in MaxScrollOffset = (80, 0). + root_clip_layer->SetBounds(gfx::Size(20, 50)); root_layer->SetBounds(gfx::Size(100, 50)); content_layer->SetBounds(gfx::Size(100, 50)); - host->SetRootLayer(root_layer); + host->SetRootLayer(root_clip_layer); + root_clip_layer->AddChild(root_layer); root_layer->AddChild(content_layer); root_layer->AddChild(scrollbar_layer); root_layer->SetScrollOffset(gfx::Vector2d(0, 0)); scrollbar_layer->SetBounds(gfx::Size(70, 10)); + scrollbar_layer->SetScrollLayer(root_layer.get()); + scrollbar_layer->SetClipLayer(root_clip_layer.get()); scrollbar_layer->fake_scrollbar()->set_location(gfx::Point(20, 10)); scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 10, 50, 10)); scrollbar_layer->fake_scrollbar()->set_thumb_thickness(10); scrollbar_layer->fake_scrollbar()->set_thumb_length(4); scrollbar_layer->UpdateThumbAndTrackGeometry(); + LayerImpl* root_clip_layer_impl = NULL; LayerImpl* root_layer_impl = NULL; PaintedScrollbarLayerImpl* scrollbar_layer_impl = NULL; // Thumb is at the edge of the scrollbar (should be inset to // the start of the track within the scrollbar layer's // position). - scrollbar_layer->UpdateThumbAndTrackGeometry(); - root_layer_impl = host->CommitAndCreateLayerImplTree(); - scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>( - root_layer_impl->children()[1]); + UPDATE_AND_EXTRACT_LAYER_POINTERS(); EXPECT_EQ(gfx::Rect(10, 0, 4, 10).ToString(), scrollbar_layer_impl->ComputeThumbQuadRect().ToString()); // Under-scroll (thumb position should clamp and be unchanged). root_layer->SetScrollOffset(gfx::Vector2d(-5, 0)); - scrollbar_layer->UpdateThumbAndTrackGeometry(); - root_layer_impl = host->CommitAndCreateLayerImplTree(); - scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>( - root_layer_impl->children()[1]); + UPDATE_AND_EXTRACT_LAYER_POINTERS(); EXPECT_EQ(gfx::Rect(10, 0, 4, 10).ToString(), scrollbar_layer_impl->ComputeThumbQuadRect().ToString()); // Over-scroll (thumb position should clamp on the far side). root_layer->SetScrollOffset(gfx::Vector2d(85, 0)); - scrollbar_layer->UpdateThumbAndTrackGeometry(); - root_layer_impl = host->CommitAndCreateLayerImplTree(); - scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>( - root_layer_impl->children()[1]); + UPDATE_AND_EXTRACT_LAYER_POINTERS(); EXPECT_EQ(gfx::Rect(56, 0, 4, 10).ToString(), scrollbar_layer_impl->ComputeThumbQuadRect().ToString()); @@ -229,10 +245,7 @@ TEST(ScrollbarLayerTest, ThumbRect) { scrollbar_layer->fake_scrollbar()->set_thumb_thickness(4); scrollbar_layer->fake_scrollbar()->set_thumb_length(6); - scrollbar_layer->UpdateThumbAndTrackGeometry(); - root_layer_impl = host->CommitAndCreateLayerImplTree(); - scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>( - root_layer_impl->children()[1]); + UPDATE_AND_EXTRACT_LAYER_POINTERS(); EXPECT_EQ(gfx::Rect(54, 0, 6, 4).ToString(), scrollbar_layer_impl->ComputeThumbQuadRect().ToString()); @@ -241,10 +254,7 @@ TEST(ScrollbarLayerTest, ThumbRect) { scrollbar_layer->fake_scrollbar()->set_location(gfx::Point(30, 10)); scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 10, 50, 10)); - scrollbar_layer->UpdateThumbAndTrackGeometry(); - root_layer_impl = host->CommitAndCreateLayerImplTree(); - scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>( - root_layer_impl->children()[1]); + UPDATE_AND_EXTRACT_LAYER_POINTERS(); EXPECT_EQ(gfx::Rect(44, 0, 6, 4).ToString(), scrollbar_layer_impl->ComputeThumbQuadRect().ToString()); @@ -253,10 +263,7 @@ TEST(ScrollbarLayerTest, ThumbRect) { // position). scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 12, 50, 6)); - scrollbar_layer->UpdateThumbAndTrackGeometry(); - root_layer_impl = host->CommitAndCreateLayerImplTree(); - scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>( - root_layer_impl->children()[1]); + UPDATE_AND_EXTRACT_LAYER_POINTERS(); EXPECT_EQ(gfx::Rect(44, 0, 6, 4).ToString(), scrollbar_layer_impl->ComputeThumbQuadRect().ToString()); } @@ -332,22 +339,40 @@ TEST(ScrollbarLayerTest, LayerDrivenSolidColorDrawQuads) { FakeLayerTreeHost::Create(layer_tree_settings); scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar(false, true, true)); - LayerImpl* layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar( - host.get(), scrollbar.Pass(), false, true, kThumbThickness); + + { + scoped_refptr<Layer> layer_tree_root = Layer::Create(); + scoped_refptr<Layer> scroll_layer = Layer::Create(); + scroll_layer->SetScrollClipLayer(layer_tree_root); + scoped_refptr<Layer> child1 = Layer::Create(); + scoped_refptr<Layer> child2; + const bool kIsLeftSideVerticalScrollbar = false; + child2 = SolidColorScrollbarLayer::Create( + scrollbar->Orientation(), kThumbThickness, + kIsLeftSideVerticalScrollbar, child1.get()); + child2->ToScrollbarLayer()->SetScrollLayer(scroll_layer); + child2->ToScrollbarLayer()->SetClipLayer(layer_tree_root); + scroll_layer->AddChild(child1); + scroll_layer->InsertChild(child2, 1); + layer_tree_root->AddChild(scroll_layer); + host->SetRootLayer(layer_tree_root); + } + LayerImpl* layer_impl_tree_root = host->CommitAndCreateLayerImplTree(); + LayerImpl* scroll_layer_impl = layer_impl_tree_root->children()[0]; + ScrollbarLayerImplBase* scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>( - layer_impl_tree_root->children()[1]); + scroll_layer_impl->children()[1]); + + // Choose layer bounds to give max_scroll_offset = (8, 8). + layer_impl_tree_root->SetBounds(gfx::Size(2, 2)); + scroll_layer_impl->SetBounds(gfx::Size(10, 10)); + scroll_layer_impl->ScrollBy(gfx::Vector2dF(4.f, 0.f)); scrollbar_layer_impl->SetBounds(gfx::Size(kTrackLength, kThumbThickness)); scrollbar_layer_impl->SetCurrentPos(4.f); scrollbar_layer_impl->SetMaximum(8); - layer_impl_tree_root->SetScrollable(true); - layer_impl_tree_root->SetHorizontalScrollbarLayer(scrollbar_layer_impl); - layer_impl_tree_root->SetMaxScrollOffset(gfx::Vector2d(8, 8)); - layer_impl_tree_root->SetBounds(gfx::Size(2, 2)); - layer_impl_tree_root->ScrollBy(gfx::Vector2dF(4.f, 0.f)); - { MockQuadCuller quad_culler; AppendQuadsData data; @@ -368,13 +393,14 @@ class ScrollbarLayerSolidColorThumbTest : public testing::Test { const int kThumbThickness = 3; const bool kIsLeftSideVerticalScrollbar = false; + const bool kIsOverlayScrollbar = false; horizontal_scrollbar_layer_ = SolidColorScrollbarLayerImpl::Create( host_impl_->active_tree(), 1, HORIZONTAL, kThumbThickness, - kIsLeftSideVerticalScrollbar); + kIsLeftSideVerticalScrollbar, kIsOverlayScrollbar); vertical_scrollbar_layer_ = SolidColorScrollbarLayerImpl::Create( host_impl_->active_tree(), 2, VERTICAL, kThumbThickness, - kIsLeftSideVerticalScrollbar); + kIsLeftSideVerticalScrollbar, kIsOverlayScrollbar); } protected: @@ -456,16 +482,17 @@ class ScrollbarLayerTestMaxTextureSize : public LayerTreeTest { void SetScrollbarBounds(gfx::Size bounds) { bounds_ = bounds; } virtual void BeginTest() OVERRIDE { + scroll_layer_ = Layer::Create(); + layer_tree_host()->root_layer()->AddChild(scroll_layer_); + scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar); - scrollbar_layer_ = PaintedScrollbarLayer::Create(scrollbar.Pass(), 1); + scrollbar_layer_ = + PaintedScrollbarLayer::Create(scrollbar.Pass(), scroll_layer_.get()); + scrollbar_layer_->SetScrollLayer(scroll_layer_); scrollbar_layer_->SetLayerTreeHost(layer_tree_host()); scrollbar_layer_->SetBounds(bounds_); layer_tree_host()->root_layer()->AddChild(scrollbar_layer_); - scroll_layer_ = Layer::Create(); - scrollbar_layer_->SetScrollLayerId(scroll_layer_->id()); - layer_tree_host()->root_layer()->AddChild(scroll_layer_); - PostSetNeedsCommitToMainThread(); } @@ -584,10 +611,10 @@ class ScrollbarLayerTestResourceCreation : public testing::Test { SolidColorScrollbarLayer::Create(scrollbar->Orientation(), kThumbThickness, kIsLeftSideVerticalScrollbar, - layer_tree_root->id()); + layer_tree_root.get()); } else { scrollbar_layer = PaintedScrollbarLayer::Create(scrollbar.Pass(), - layer_tree_root->id()); + layer_tree_root.get()); } layer_tree_root->AddChild(content_layer); layer_tree_root->AddChild(scrollbar_layer); @@ -597,7 +624,6 @@ class ScrollbarLayerTestResourceCreation : public testing::Test { scrollbar_layer->SetIsDrawable(true); scrollbar_layer->SetBounds(gfx::Size(100, 100)); layer_tree_root->SetScrollOffset(gfx::Vector2d(10, 20)); - layer_tree_root->SetMaxScrollOffset(gfx::Vector2d(30, 50)); layer_tree_root->SetBounds(gfx::Size(100, 200)); content_layer->SetBounds(gfx::Size(100, 200)); scrollbar_layer->draw_properties().content_bounds = gfx::Size(100, 200); @@ -664,7 +690,7 @@ class ScaledScrollbarLayerTestResourceCreation : public testing::Test { scoped_refptr<Layer> layer_tree_root = Layer::Create(); scoped_refptr<Layer> content_layer = Layer::Create(); scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer = - FakePaintedScrollbarLayer::Create(false, true, layer_tree_root->id()); + FakePaintedScrollbarLayer::Create(false, true, layer_tree_root.get()); layer_tree_root->AddChild(content_layer); layer_tree_root->AddChild(scrollbar_layer); diff --git a/cc/layers/solid_color_scrollbar_layer.cc b/cc/layers/solid_color_scrollbar_layer.cc index d9ed922..196b7e8 100644 --- a/cc/layers/solid_color_scrollbar_layer.cc +++ b/cc/layers/solid_color_scrollbar_layer.cc @@ -12,29 +12,35 @@ namespace cc { scoped_ptr<LayerImpl> SolidColorScrollbarLayer::CreateLayerImpl( LayerTreeImpl* tree_impl) { + const bool kIsOverlayScrollbar = true; return SolidColorScrollbarLayerImpl::Create( - tree_impl, id(), orientation(), thumb_thickness_, - is_left_side_vertical_scrollbar_).PassAs<LayerImpl>(); + tree_impl, + id(), + orientation(), + thumb_thickness_, + is_left_side_vertical_scrollbar_, + kIsOverlayScrollbar).PassAs<LayerImpl>(); } scoped_refptr<SolidColorScrollbarLayer> SolidColorScrollbarLayer::Create( ScrollbarOrientation orientation, int thumb_thickness, bool is_left_side_vertical_scrollbar, - int scroll_layer_id) { + Layer* scroll_layer) { return make_scoped_refptr(new SolidColorScrollbarLayer( orientation, thumb_thickness, is_left_side_vertical_scrollbar, - scroll_layer_id)); + scroll_layer)); } SolidColorScrollbarLayer::SolidColorScrollbarLayer( ScrollbarOrientation orientation, int thumb_thickness, bool is_left_side_vertical_scrollbar, - int scroll_layer_id) - : scroll_layer_id_(scroll_layer_id), + Layer* scroll_layer) + : scroll_layer_(scroll_layer), + clip_layer_(NULL), orientation_(orientation), thumb_thickness_(thumb_thickness), is_left_side_vertical_scrollbar_(is_left_side_vertical_scrollbar) {} @@ -45,19 +51,42 @@ ScrollbarLayerInterface* SolidColorScrollbarLayer::ToScrollbarLayer() { return this; } +void SolidColorScrollbarLayer::PushPropertiesTo(LayerImpl* layer) { + Layer::PushPropertiesTo(layer); + PushScrollClipPropertiesTo(layer); +} + +void SolidColorScrollbarLayer::PushScrollClipPropertiesTo(LayerImpl* layer) { + SolidColorScrollbarLayerImpl* scrollbar_layer = + static_cast<SolidColorScrollbarLayerImpl*>(layer); + + scrollbar_layer->SetScrollLayerById(scroll_layer_ ? scroll_layer_->id() + : Layer::INVALID_ID); + scrollbar_layer->SetClipLayerById(clip_layer_ ? clip_layer_->id() + : Layer::INVALID_ID); +} + bool SolidColorScrollbarLayer::OpacityCanAnimateOnImplThread() const { return true; } int SolidColorScrollbarLayer::ScrollLayerId() const { - return scroll_layer_id_; + return scroll_layer_->id(); +} + +void SolidColorScrollbarLayer::SetScrollLayer(scoped_refptr<Layer> layer) { + if (layer == scroll_layer_) + return; + + scroll_layer_ = layer; + SetNeedsFullTreeSync(); } -void SolidColorScrollbarLayer::SetScrollLayerId(int id) { - if (id == scroll_layer_id_) +void SolidColorScrollbarLayer::SetClipLayer(scoped_refptr<Layer> layer) { + if (layer == clip_layer_) return; - scroll_layer_id_ = id; + clip_layer_ = layer; SetNeedsFullTreeSync(); } diff --git a/cc/layers/solid_color_scrollbar_layer.h b/cc/layers/solid_color_scrollbar_layer.h index 9c0dc1e..a954af1 100644 --- a/cc/layers/solid_color_scrollbar_layer.h +++ b/cc/layers/solid_color_scrollbar_layer.h @@ -21,15 +21,19 @@ class CC_EXPORT SolidColorScrollbarLayer : public ScrollbarLayerInterface, ScrollbarOrientation orientation, int thumb_thickness, bool is_left_side_vertical_scrollbar, - int scroll_layer_id); + Layer* scroll_layer); // Layer overrides. virtual bool OpacityCanAnimateOnImplThread() const OVERRIDE; virtual ScrollbarLayerInterface* ToScrollbarLayer() OVERRIDE; + virtual void PushPropertiesTo(LayerImpl* layer) OVERRIDE; + virtual void PushScrollClipPropertiesTo(LayerImpl* layer) OVERRIDE; + // ScrollbarLayerInterface virtual int ScrollLayerId() const OVERRIDE; - virtual void SetScrollLayerId(int id) OVERRIDE; + virtual void SetScrollLayer(scoped_refptr<Layer> layer) OVERRIDE; + virtual void SetClipLayer(scoped_refptr<Layer> layer) OVERRIDE; virtual ScrollbarOrientation orientation() const OVERRIDE; @@ -37,11 +41,12 @@ class CC_EXPORT SolidColorScrollbarLayer : public ScrollbarLayerInterface, SolidColorScrollbarLayer(ScrollbarOrientation orientation, int thumb_thickness, bool is_left_side_vertical_scrollbar, - int scroll_layer_id); + Layer* scroll_layer); virtual ~SolidColorScrollbarLayer(); private: - int scroll_layer_id_; + scoped_refptr<Layer> scroll_layer_; + scoped_refptr<Layer> clip_layer_; ScrollbarOrientation orientation_; int thumb_thickness_; bool is_left_side_vertical_scrollbar_; diff --git a/cc/layers/solid_color_scrollbar_layer_impl.cc b/cc/layers/solid_color_scrollbar_layer_impl.cc index 5c63203..34351ce 100644 --- a/cc/layers/solid_color_scrollbar_layer_impl.cc +++ b/cc/layers/solid_color_scrollbar_layer_impl.cc @@ -15,19 +15,24 @@ scoped_ptr<SolidColorScrollbarLayerImpl> SolidColorScrollbarLayerImpl::Create( int id, ScrollbarOrientation orientation, int thumb_thickness, - bool is_left_side_vertical_scrollbar) { + bool is_left_side_vertical_scrollbar, + bool is_overlay) { return make_scoped_ptr(new SolidColorScrollbarLayerImpl( tree_impl, id, orientation, thumb_thickness, - is_left_side_vertical_scrollbar)); + is_left_side_vertical_scrollbar, is_overlay)); } SolidColorScrollbarLayerImpl::~SolidColorScrollbarLayerImpl() {} scoped_ptr<LayerImpl> SolidColorScrollbarLayerImpl::CreateLayerImpl( LayerTreeImpl* tree_impl) { - return SolidColorScrollbarLayerImpl::Create( - tree_impl, id(), orientation(), thumb_thickness_, - is_left_side_vertical_scrollbar()).PassAs<LayerImpl>(); + return SolidColorScrollbarLayerImpl::Create(tree_impl, + id(), + orientation(), + thumb_thickness_, + is_left_side_vertical_scrollbar(), + is_overlay_scrollbar()) + .PassAs<LayerImpl>(); } SolidColorScrollbarLayerImpl::SolidColorScrollbarLayerImpl( @@ -35,9 +40,10 @@ SolidColorScrollbarLayerImpl::SolidColorScrollbarLayerImpl( int id, ScrollbarOrientation orientation, int thumb_thickness, - bool is_left_side_vertical_scrollbar) + bool is_left_side_vertical_scrollbar, + bool is_overlay) : ScrollbarLayerImplBase(tree_impl, id, orientation, - is_left_side_vertical_scrollbar), + is_left_side_vertical_scrollbar, is_overlay), thumb_thickness_(thumb_thickness), color_(tree_impl->settings().solid_color_scrollbar_color) {} diff --git a/cc/layers/solid_color_scrollbar_layer_impl.h b/cc/layers/solid_color_scrollbar_layer_impl.h index b725ed5..205496a 100644 --- a/cc/layers/solid_color_scrollbar_layer_impl.h +++ b/cc/layers/solid_color_scrollbar_layer_impl.h @@ -17,7 +17,8 @@ class CC_EXPORT SolidColorScrollbarLayerImpl : public ScrollbarLayerImplBase { int id, ScrollbarOrientation orientation, int thumb_thickness, - bool is_left_side_vertical_scrollbar); + bool is_left_side_vertical_scrollbar, + bool is_overlay); virtual ~SolidColorScrollbarLayerImpl(); // LayerImpl overrides. @@ -34,7 +35,8 @@ class CC_EXPORT SolidColorScrollbarLayerImpl : public ScrollbarLayerImplBase { int id, ScrollbarOrientation orientation, int thumb_thickness, - bool is_left_side_vertical_scrollbar); + bool is_left_side_vertical_scrollbar, + bool is_overlay); // ScrollbarLayerImplBase implementation. virtual int ThumbThickness() const OVERRIDE; diff --git a/cc/test/fake_painted_scrollbar_layer.cc b/cc/test/fake_painted_scrollbar_layer.cc index 72ef420..b2f3e0d 100644 --- a/cc/test/fake_painted_scrollbar_layer.cc +++ b/cc/test/fake_painted_scrollbar_layer.cc @@ -13,18 +13,18 @@ namespace cc { scoped_refptr<FakePaintedScrollbarLayer> FakePaintedScrollbarLayer::Create( bool paint_during_update, bool has_thumb, - int scrolling_layer_id) { + Layer* scrolling_layer) { FakeScrollbar* fake_scrollbar = new FakeScrollbar( paint_during_update, has_thumb, false); return make_scoped_refptr(new FakePaintedScrollbarLayer( - fake_scrollbar, scrolling_layer_id)); + fake_scrollbar, scrolling_layer)); } FakePaintedScrollbarLayer::FakePaintedScrollbarLayer( FakeScrollbar* fake_scrollbar, - int scrolling_layer_id) + Layer* scrolling_layer) : PaintedScrollbarLayer(scoped_ptr<Scrollbar>(fake_scrollbar).Pass(), - scrolling_layer_id), + scrolling_layer), update_count_(0), push_properties_count_(0), fake_scrollbar_(fake_scrollbar) { diff --git a/cc/test/fake_painted_scrollbar_layer.h b/cc/test/fake_painted_scrollbar_layer.h index 9b1b13d..736a450 100644 --- a/cc/test/fake_painted_scrollbar_layer.h +++ b/cc/test/fake_painted_scrollbar_layer.h @@ -16,7 +16,7 @@ namespace cc { class FakePaintedScrollbarLayer : public PaintedScrollbarLayer { public: static scoped_refptr<FakePaintedScrollbarLayer> - Create(bool paint_during_update, bool has_thumb, int scrolling_layer_id); + Create(bool paint_during_update, bool has_thumb, Layer* scrolling_layer); int update_count() const { return update_count_; } void reset_update_count() { update_count_ = 0; } @@ -44,7 +44,7 @@ class FakePaintedScrollbarLayer : public PaintedScrollbarLayer { private: FakePaintedScrollbarLayer(FakeScrollbar* fake_scrollbar, - int scrolling_layer_id); + Layer* scrolling_layer); virtual ~FakePaintedScrollbarLayer(); int update_count_; diff --git a/cc/test/layer_tree_json_parser.cc b/cc/test/layer_tree_json_parser.cc index e7f3e9b..9c95970 100644 --- a/cc/test/layer_tree_json_parser.cc +++ b/cc/test/layer_tree_json_parser.cc @@ -101,8 +101,26 @@ scoped_refptr<Layer> ParseTreeFromValue(base::Value* val, new_layer->SetContentsOpaque(contents_opaque); bool scrollable; + // TODO(wjmaclean) At some time in the future we may wish to test that a + // reconstructed layer tree contains the correct linkage for the scroll + // clip layer. This is complicated by the fact that the json output doesn't + // (currently) re-construct the tree with the same layer IDs as the original. + // But, since a clip layer is always an ancestor of the scrollable layer, we + // can just count the number of upwards hops to the clip layer and write that + // into the json file (with 0 hops implying no clip layer, i.e. not + // scrollable). Reconstructing the tree can then be accomplished by passing + // the parent pointer to this function and traversing the same number of + // ancestors to determine the pointer to the clip layer. The LayerTreesMatch() + // function should then check that both original and reconstructed layers + // have the same positioning with respect to their clip layers. + // + // For now, we can safely indicate a layer is scrollable by giving it a + // pointer to itself, something not normally allowed in a working tree. + // + // https://code.google.com/p/chromium/issues/detail?id=330622 + // if (dict->GetBoolean("Scrollable", &scrollable)) - new_layer->SetScrollable(scrollable); + new_layer->SetScrollClipLayer(scrollable ? new_layer.get() : NULL); bool wheel_handler; if (dict->GetBoolean("WheelHandler", &wheel_handler)) diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc index 0684a9c..e5f0271 100644 --- a/cc/trees/layer_tree_host.cc +++ b/cc/trees/layer_tree_host.cc @@ -338,12 +338,7 @@ void LayerTreeHost::FinishCommitOnImplThread(LayerTreeHostImpl* host_impl) { sync_tree->set_background_color(background_color_); sync_tree->set_has_transparent_background(has_transparent_background_); - sync_tree->FindRootScrollLayer(); - - // TODO(wjmaclean) For now, not all LTH clients will register viewports, so - // only set them when available.. - if (page_scale_layer_) { - DCHECK(inner_viewport_scroll_layer_); + if (page_scale_layer_ && inner_viewport_scroll_layer_) { sync_tree->SetViewportLayersFromIds( page_scale_layer_->id(), inner_viewport_scroll_layer_->id(), @@ -1045,8 +1040,8 @@ void LayerTreeHost::ApplyScrollAndScale(const ScrollAndScaleSet& info) { if (!root_layer_.get()) return; - gfx::Vector2d root_scroll_delta; - Layer* root_scroll_layer = FindFirstScrollableLayer(root_layer_.get()); + gfx::Vector2d inner_viewport_scroll_delta; + gfx::Vector2d outer_viewport_scroll_delta; for (size_t i = 0; i < info.scrolls.size(); ++i) { Layer* layer = @@ -1054,29 +1049,87 @@ void LayerTreeHost::ApplyScrollAndScale(const ScrollAndScaleSet& info) { info.scrolls[i].layer_id); if (!layer) continue; - if (layer == root_scroll_layer) { - root_scroll_delta += info.scrolls[i].scroll_delta; + if (layer == outer_viewport_scroll_layer_.get()) { + outer_viewport_scroll_delta += info.scrolls[i].scroll_delta; + } else if (layer == inner_viewport_scroll_layer_.get()) { + inner_viewport_scroll_delta += info.scrolls[i].scroll_delta; } else { layer->SetScrollOffsetFromImplSide(layer->scroll_offset() + info.scrolls[i].scroll_delta); } } - if (!root_scroll_delta.IsZero() || info.page_scale_delta != 1.f) { + if (!inner_viewport_scroll_delta.IsZero() || + !outer_viewport_scroll_delta.IsZero() || + info.page_scale_delta != 1.f) { // SetScrollOffsetFromImplSide above could have destroyed the tree, // so re-get this layer before doing anything to it. - root_scroll_layer = FindFirstScrollableLayer(root_layer_.get()); // Preemptively apply the scroll offset and scale delta here before sending // it to the client. If the client comes back and sets it to the same // value, then the layer can early out without needing a full commit. - if (root_scroll_layer) { - root_scroll_layer->SetScrollOffsetFromImplSide( - root_scroll_layer->scroll_offset() + root_scroll_delta); + DCHECK(inner_viewport_scroll_layer_); // We should always have this. + + inner_viewport_scroll_layer_->SetScrollOffsetFromImplSide( + inner_viewport_scroll_layer_->scroll_offset() + + inner_viewport_scroll_delta); + if (outer_viewport_scroll_layer_) { + outer_viewport_scroll_layer_->SetScrollOffsetFromImplSide( + outer_viewport_scroll_layer_->scroll_offset() + + outer_viewport_scroll_delta); } ApplyPageScaleDeltaFromImplSide(info.page_scale_delta); - client_->ApplyScrollAndScale(root_scroll_delta, info.page_scale_delta); + + client_->ApplyScrollAndScale( + inner_viewport_scroll_delta + outer_viewport_scroll_delta, + info.page_scale_delta); + } +} + +gfx::Vector2d LayerTreeHost::DistributeScrollOffsetToViewports( + const gfx::Vector2d offset, + Layer* layer) { + DCHECK(layer); + if (layer != outer_viewport_scroll_layer_.get()) + return offset; + + gfx::Vector2d inner_viewport_offset = + inner_viewport_scroll_layer_->scroll_offset(); + gfx::Vector2d outer_viewport_offset = + outer_viewport_scroll_layer_->scroll_offset(); + + if (offset == inner_viewport_offset + outer_viewport_offset) { + // In this case, nothing should change, so we just return to the outer + // viewport the offset is already has. + return outer_viewport_offset; } + + // In the spirit of document-scrolls-first, we always want any change to + // go to the outer viewport first. + gfx::Vector2d max_outer_viewport_scroll_offset = + outer_viewport_scroll_layer_->MaxScrollOffset(); +#if ENABLE_DCHECK +// TODO(wjmaclean) The DCHECK below is triggering during zoom-out. +// crbug.com/336574 +/* + gfx::Vector2d maxInnerViewportScrollOffset = + inner_viewport_scroll_layer_->MaxScrollOffset(); + + gfx::Vector2d totalMaxScrollOffset = + max_outer_viewport_scroll_offset + maxInnerViewportScrollOffset; + DCHECK(totalMaxScrollOffset.x() >= offset.x() && + totalMaxScrollOffset.y() >= offset.y()); +*/ +#endif + + outer_viewport_offset = offset - inner_viewport_offset; + outer_viewport_offset.SetToMin(max_outer_viewport_scroll_offset); + outer_viewport_offset.SetToMax(gfx::Vector2d()); + + inner_viewport_offset = offset - outer_viewport_offset; + inner_viewport_scroll_layer_->SetScrollOffset(inner_viewport_offset); + + return outer_viewport_offset; } void LayerTreeHost::StartRateLimiter() { diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h index 867bb19..a1f26cc 100644 --- a/cc/trees/layer_tree_host.h +++ b/cc/trees/layer_tree_host.h @@ -195,6 +195,12 @@ class CC_EXPORT LayerTreeHost { scoped_refptr<Layer> page_scale_layer, scoped_refptr<Layer> inner_viewport_scroll_layer, scoped_refptr<Layer> outer_viewport_scroll_layer); + Layer* inner_viewport_scroll_layer() const { + return inner_viewport_scroll_layer_.get(); + } + Layer* outer_viewport_scroll_layer() const { + return outer_viewport_scroll_layer_.get(); + } const LayerTreeSettings& settings() const { return settings_; } @@ -235,6 +241,8 @@ class CC_EXPORT LayerTreeHost { base::TimeDelta duration); void ApplyScrollAndScale(const ScrollAndScaleSet& info); + gfx::Vector2d DistributeScrollOffsetToViewports(const gfx::Vector2d offset, + Layer* layer); void SetImplTransform(const gfx::Transform& transform); diff --git a/cc/trees/layer_tree_host_common_unittest.cc b/cc/trees/layer_tree_host_common_unittest.cc index f7db3e1..93a75e7 100644 --- a/cc/trees/layer_tree_host_common_unittest.cc +++ b/cc/trees/layer_tree_host_common_unittest.cc @@ -422,9 +422,9 @@ TEST_F(LayerTreeHostCommonTest, TransformsAboutScrollOffset) { gfx::Size(500, 500), false); - scoped_ptr<LayerImpl> scroll_layerScopedPtr( + scoped_ptr<LayerImpl> scroll_layer_scoped_ptr( LayerImpl::Create(host_impl.active_tree(), 2)); - LayerImpl* scroll_layer = scroll_layerScopedPtr.get(); + LayerImpl* scroll_layer = scroll_layer_scoped_ptr.get(); SetLayerPropertiesForTesting(scroll_layer, identity_matrix, identity_matrix, @@ -432,12 +432,22 @@ TEST_F(LayerTreeHostCommonTest, TransformsAboutScrollOffset) { gfx::PointF(), gfx::Size(10, 20), false); - scroll_layer->SetScrollable(true); - scroll_layer->SetMaxScrollOffset(kMaxScrollOffset); - scroll_layer->SetScrollOffset(kScrollOffset); + + scoped_ptr<LayerImpl> clip_layer_scoped_ptr( + LayerImpl::Create(host_impl.active_tree(), 4)); + LayerImpl* clip_layer = clip_layer_scoped_ptr.get(); + + scroll_layer->SetScrollClipLayer(clip_layer->id()); + clip_layer->SetBounds( + gfx::Size(scroll_layer->bounds().width() + kMaxScrollOffset.x(), + scroll_layer->bounds().height() + kMaxScrollOffset.y())); + scroll_layer->SetScrollClipLayer(clip_layer->id()); scroll_layer->SetScrollDelta(kScrollDelta); gfx::Transform impl_transform; scroll_layer->AddChild(sublayer_scoped_ptr.Pass()); + LayerImpl* scroll_layer_raw_ptr = scroll_layer_scoped_ptr.get(); + clip_layer->AddChild(scroll_layer_scoped_ptr.Pass()); + scroll_layer_raw_ptr->SetScrollOffset(kScrollOffset); scoped_ptr<LayerImpl> root(LayerImpl::Create(host_impl.active_tree(), 3)); SetLayerPropertiesForTesting(root.get(), @@ -447,7 +457,7 @@ TEST_F(LayerTreeHostCommonTest, TransformsAboutScrollOffset) { gfx::PointF(), gfx::Size(3, 4), false); - root->AddChild(scroll_layerScopedPtr.Pass()); + root->AddChild(clip_layer_scoped_ptr.Pass()); ExecuteCalculateDrawProperties( root.get(), kDeviceScale, kPageScale, scroll_layer->parent()); @@ -1380,7 +1390,7 @@ TEST_F(LayerTreeHostCommonTest, TransformAboveRootLayer) { const gfx::Transform identity_matrix; scoped_refptr<Layer> root = Layer::Create(); scoped_refptr<Layer> child = Layer::Create(); - child->SetScrollable(true); + child->SetScrollClipLayer(root.get()); root->AddChild(child); scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(); @@ -8632,8 +8642,7 @@ TEST_F(LayerTreeHostCommonTest, ClipParentScrolledInterveningLayer) { intervening->SetMasksToBounds(true); clip_parent->SetMasksToBounds(true); - intervening->SetScrollable(true); - intervening->SetMaxScrollOffset(gfx::Vector2d(50, 50)); + intervening->SetScrollClipLayer(clip_parent.get()); intervening->SetScrollOffset(gfx::Vector2d(3, 3)); render_surface1->SetForceRenderSurface(true); @@ -9660,7 +9669,7 @@ TEST_F(LayerTreeHostCommonTest, ScrollCompensationWithRounding) { constraint.set_is_fixed_position(true); fixed->SetPositionConstraint(constraint); - scroller->SetScrollable(true); + scroller->SetScrollClipLayer(container->id()); gfx::Transform identity_transform; gfx::Transform container_transform; diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index 9063caf..4cd7009 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc @@ -432,11 +432,10 @@ void LayerTreeHostImpl::StartPageScaleAnimation(gfx::Vector2d target_offset, bool anchor_point, float page_scale, base::TimeDelta duration) { - if (!RootScrollLayer()) + if (!InnerViewportScrollLayer()) return; - gfx::Vector2dF scroll_total = - RootScrollLayer()->scroll_offset() + RootScrollLayer()->ScrollDelta(); + gfx::Vector2dF scroll_total = active_tree_->TotalScrollOffset(); gfx::SizeF scaled_scrollable_size = active_tree_->ScrollableSize(); gfx::SizeF viewport_size = UnscaledScrollableViewportSize(); @@ -1304,10 +1303,10 @@ CompositorFrameMetadata LayerTreeHostImpl::MakeCompositorFrameMetadata() const { metadata.overdraw_bottom_height = overdraw_bottom_height_; } - if (!RootScrollLayer()) + if (!InnerViewportScrollLayer()) return metadata; - metadata.root_scroll_offset = RootScrollLayer()->TotalScrollOffset(); + metadata.root_scroll_offset = active_tree_->TotalScrollOffset(); return metadata; } @@ -1510,15 +1509,19 @@ void LayerTreeHostImpl::Readback(void* pixels, } bool LayerTreeHostImpl::HaveRootScrollLayer() const { - return !!RootScrollLayer(); + return !!InnerViewportScrollLayer(); } LayerImpl* LayerTreeHostImpl::RootLayer() const { return active_tree_->root_layer(); } -LayerImpl* LayerTreeHostImpl::RootScrollLayer() const { - return active_tree_->RootScrollLayer(); +LayerImpl* LayerTreeHostImpl::InnerViewportScrollLayer() const { + return active_tree_->InnerViewportScrollLayer(); +} + +LayerImpl* LayerTreeHostImpl::OuterViewportScrollLayer() const { + return active_tree_->OuterViewportScrollLayer(); } LayerImpl* LayerTreeHostImpl::CurrentlyScrollingLayer() const { @@ -1527,7 +1530,10 @@ LayerImpl* LayerTreeHostImpl::CurrentlyScrollingLayer() const { bool LayerTreeHostImpl::IsCurrentlyScrolling() const { return CurrentlyScrollingLayer() || - (RootScrollLayer() && RootScrollLayer()->IsExternalFlingActive()); + (InnerViewportScrollLayer() && + InnerViewportScrollLayer()->IsExternalFlingActive()) || + (OuterViewportScrollLayer() && + OuterViewportScrollLayer()->IsExternalFlingActive()); } // Content layers can be either directly scrollable or contained in an outer @@ -1908,8 +1914,6 @@ void LayerTreeHostImpl::SetViewportSize(gfx::Size device_viewport_size) { device_viewport_size_ = device_viewport_size; - UpdateMaxScrollOffset(); - client_->OnCanDrawStateChanged(CanDraw()); SetFullRootLayerDamage(); } @@ -1919,7 +1923,6 @@ void LayerTreeHostImpl::SetOverdrawBottomHeight(float overdraw_bottom_height) { return; overdraw_bottom_height_ = overdraw_bottom_height; - UpdateMaxScrollOffset(); SetFullRootLayerDamage(); } @@ -1935,7 +1938,6 @@ void LayerTreeHostImpl::SetDeviceScaleFactor(float device_scale_factor) { return; device_scale_factor_ = device_scale_factor; - UpdateMaxScrollOffset(); SetFullRootLayerDamage(); } @@ -1961,10 +1963,6 @@ const gfx::Transform& LayerTreeHostImpl::DrawTransform() const { return external_transform_; } -void LayerTreeHostImpl::UpdateMaxScrollOffset() { - active_tree_->UpdateMaxScrollOffset(); -} - void LayerTreeHostImpl::DidChangeTopControlsPosition() { SetNeedsRedraw(); active_tree_->set_needs_update_draw_properties(); @@ -2050,8 +2048,11 @@ InputHandler::ScrollStatus LayerTreeHostImpl::ScrollBegin( return ScrollOnMainThread; } + // If we want to send a DidOverscroll for this scroll it can't be ignored. if (!potentially_scrolling_layer_impl) - potentially_scrolling_layer_impl = RootScrollLayer(); + potentially_scrolling_layer_impl = + OuterViewportScrollLayer() ? OuterViewportScrollLayer() + : InnerViewportScrollLayer(); if (potentially_scrolling_layer_impl) { active_tree_->SetCurrentlyScrollingLayer( @@ -2158,10 +2159,14 @@ bool LayerTreeHostImpl::ScrollBy(gfx::Point viewport_point, gfx::Vector2dF unused_root_delta; bool did_scroll_x = false; bool did_scroll_y = false; - bool consume_by_top_controls = top_controls_manager_ && - (scroll_delta.y() < 0 || - (RootScrollLayer() && CurrentlyScrollingLayer() == RootScrollLayer() && - RootScrollLayer()->max_scroll_offset().y() > 0)); + // TODO(wjmaclean) Should we guard against CurrentlyScrollingLayer() == 0 + // here? + bool consume_by_top_controls = + top_controls_manager_ && + (((CurrentlyScrollingLayer() == InnerViewportScrollLayer() || + CurrentlyScrollingLayer() == OuterViewportScrollLayer()) && + InnerViewportScrollLayer()->MaxScrollOffset().y() > 0) || + scroll_delta.y() < 0); for (LayerImpl* layer_impl = CurrentlyScrollingLayer(); layer_impl; @@ -2169,12 +2174,18 @@ bool LayerTreeHostImpl::ScrollBy(gfx::Point viewport_point, if (!layer_impl->scrollable()) continue; - if (layer_impl == RootScrollLayer()) { + if (layer_impl == InnerViewportScrollLayer()) { // Only allow bubble scrolling when the scroll is in the direction to make // the top controls visible. + gfx::Vector2dF applied_delta; + gfx::Vector2dF excess_delta; if (consume_by_top_controls) { - pending_delta = top_controls_manager_->ScrollBy(pending_delta); - UpdateMaxScrollOffset(); + excess_delta = top_controls_manager_->ScrollBy(pending_delta); + applied_delta = pending_delta - excess_delta; + pending_delta = excess_delta; + // Force updating of vertical adjust values if needed. + if (applied_delta.y() != 0) + layer_impl->ScrollbarParametersDidChange(); } // Track root layer deltas for reporting overscroll. unused_root_delta = pending_delta; @@ -2208,7 +2219,7 @@ bool LayerTreeHostImpl::ScrollBy(gfx::Point viewport_point, break; } - if (layer_impl == RootScrollLayer()) + if (layer_impl == InnerViewportScrollLayer()) unused_root_delta.Subtract(applied_delta); did_lock_scrolling_layer_ = true; @@ -2275,10 +2286,10 @@ bool LayerTreeHostImpl::ScrollVerticallyByPage(gfx::Point viewport_point, if (!layer_impl->scrollable()) continue; - if (!layer_impl->vertical_scrollbar_layer()) + if (!layer_impl->HasScrollbar(VERTICAL)) continue; - float height = layer_impl->vertical_scrollbar_layer()->bounds().height(); + float height = layer_impl->clip_height(); // These magical values match WebKit and are designed to scroll nearly the // entire visible content height but leave a bit of overlap. @@ -2334,8 +2345,8 @@ InputHandler::ScrollStatus LayerTreeHostImpl::FlingScrollBegin() { return ScrollIgnored; if (settings_.ignore_root_layer_flings && - active_tree_->CurrentlyScrollingLayer() == - active_tree_->RootScrollLayer()) { + (active_tree_->CurrentlyScrollingLayer() == InnerViewportScrollLayer() || + active_tree_->CurrentlyScrollingLayer() == OuterViewportScrollLayer())) { ClearCurrentlyScrollingLayer(); return ScrollIgnored; } @@ -2411,11 +2422,14 @@ void LayerTreeHostImpl::MouseMoveAt(gfx::Point viewport_point) { if (!animation_controller) return; - float distance_to_scrollbar = std::min( - DeviceSpaceDistanceToLayer(device_viewport_point, - scroll_layer_impl->horizontal_scrollbar_layer()), - DeviceSpaceDistanceToLayer(device_viewport_point, - scroll_layer_impl->vertical_scrollbar_layer())); + // TODO(wjmaclean) Is it ok to choose distance from more than two scrollbars? + float distance_to_scrollbar = std::numeric_limits<float>::max(); + for (LayerImpl::ScrollbarSet::iterator it = + scroll_layer_impl->scrollbars()->begin(); + it != scroll_layer_impl->scrollbars()->end(); + ++it) + distance_to_scrollbar = std::min(distance_to_scrollbar, + DeviceSpaceDistanceToLayer(device_viewport_point, *it)); bool should_animate = animation_controller->DidMouseMoveNear( CurrentPhysicalTimeTicks(), distance_to_scrollbar / device_scale_factor_); @@ -2450,7 +2464,13 @@ void LayerTreeHostImpl::PinchGestureBegin() { previous_pinch_anchor_ = gfx::Point(); client_->RenewTreePriority(); pinch_gesture_end_should_clear_scrolling_layer_ = !CurrentlyScrollingLayer(); - active_tree_->SetCurrentlyScrollingLayer(RootScrollLayer()); + if (active_tree_->OuterViewportScrollLayer()) { + active_tree_->SetCurrentlyScrollingLayer( + active_tree_->OuterViewportScrollLayer()); + } else { + active_tree_->SetCurrentlyScrollingLayer( + active_tree_->InnerViewportScrollLayer()); + } if (top_controls_manager_) top_controls_manager_->PinchBegin(); } @@ -2459,8 +2479,7 @@ void LayerTreeHostImpl::PinchGestureUpdate(float magnify_delta, gfx::Point anchor) { TRACE_EVENT0("cc", "LayerTreeHostImpl::PinchGestureUpdate"); - if (!RootScrollLayer()) - return; + DCHECK(InnerViewportScrollLayer()); // Keep the center-of-pinch anchor specified by (x, y) in a stable // position over the course of the magnify. @@ -2476,8 +2495,24 @@ void LayerTreeHostImpl::PinchGestureUpdate(float magnify_delta, previous_pinch_anchor_ = anchor; move.Scale(1 / active_tree_->page_scale_factor()); + // If clamping the inner viewport scroll offset causes a change, it should + // be accounted for from the intended move. + move -= InnerViewportScrollLayer()->ClampScrollToMaxScrollOffset(); - RootScrollLayer()->ScrollBy(move); + // We manually manage the bubbling behaviour here as it is different to that + // implemented in LayerTreeHostImpl::ScrollBy(). Specifically: + // 1) we want to explicit limit the bubbling to the outer/inner viewports, + // 2) we don't want the directional limitations on the unused parts that + // ScrollBy() implements, and + // 3) pinching should not engage the top controls manager. + gfx::Vector2dF unused = + OuterViewportScrollLayer() ? OuterViewportScrollLayer()->ScrollBy(move) + : move; + + if (!unused.IsZero()) { + InnerViewportScrollLayer()->ScrollBy(unused); + InnerViewportScrollLayer()->ClampScrollToMaxScrollOffset(); + } client_->SetNeedsCommitOnImplThread(); SetNeedsRedraw(); @@ -2528,13 +2563,24 @@ void LayerTreeHostImpl::SetFullRootLayerDamage() { SetViewportDamage(gfx::Rect(DrawViewportSize())); } +void LayerTreeHostImpl::ScrollViewportBy(gfx::Vector2dF scroll_delta) { + DCHECK(InnerViewportScrollLayer()); + LayerImpl* scroll_layer = + OuterViewportScrollLayer() ? OuterViewportScrollLayer() + : InnerViewportScrollLayer(); + + gfx::Vector2dF unused_delta = scroll_layer->ScrollBy(scroll_delta); + + if (!unused_delta.IsZero() && (scroll_layer == OuterViewportScrollLayer())) + InnerViewportScrollLayer()->ScrollBy(unused_delta); +} + void LayerTreeHostImpl::AnimatePageScale(base::TimeTicks time) { - if (!page_scale_animation_ || !RootScrollLayer()) + if (!page_scale_animation_) return; double monotonic_time = (time - base::TimeTicks()).InSecondsF(); - gfx::Vector2dF scroll_total = RootScrollLayer()->scroll_offset() + - RootScrollLayer()->ScrollDelta(); + gfx::Vector2dF scroll_total = active_tree_->TotalScrollOffset(); if (!page_scale_animation_->IsAnimationStarted()) page_scale_animation_->StartAnimation(monotonic_time); @@ -2545,7 +2591,7 @@ void LayerTreeHostImpl::AnimatePageScale(base::TimeTicks time) { gfx::Vector2dF next_scroll = page_scale_animation_->ScrollOffsetAtTime(monotonic_time); - RootScrollLayer()->ScrollBy(next_scroll - scroll_total); + ScrollViewportBy(next_scroll - scroll_total); SetNeedsRedraw(); if (page_scale_animation_->IsAnimationCompleteAtTime(monotonic_time)) { @@ -2556,18 +2602,17 @@ void LayerTreeHostImpl::AnimatePageScale(base::TimeTicks time) { } void LayerTreeHostImpl::AnimateTopControls(base::TimeTicks time) { - if (!top_controls_manager_ || !RootScrollLayer()) + if (!top_controls_manager_) return; gfx::Vector2dF scroll = top_controls_manager_->Animate(time); - UpdateMaxScrollOffset(); - if (RootScrollLayer()->TotalScrollOffset().y() == 0.f) + if (active_tree_->TotalScrollOffset().y() == 0.f) return; if (scroll.IsZero()) { // This may happen on the first animation step. Force redraw otherwise // the animation would stop because of no new frames. SetNeedsRedraw(); } else { - RootScrollLayer()->ScrollBy(gfx::ScaleVector2d( + ScrollViewportBy(gfx::ScaleVector2d( scroll, 1.f / active_tree_->total_page_scale_factor())); } } diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h index 2b85e32..5b429f6 100644 --- a/cc/trees/layer_tree_host_impl.h +++ b/cc/trees/layer_tree_host_impl.h @@ -277,7 +277,8 @@ class CC_EXPORT LayerTreeHostImpl // Shortcuts to layers on the active tree. LayerImpl* RootLayer() const; - LayerImpl* RootScrollLayer() const; + LayerImpl* InnerViewportScrollLayer() const; + LayerImpl* OuterViewportScrollLayer() const; LayerImpl* CurrentlyScrollingLayer() const; int scroll_layer_id_when_mouse_over_scrollbar() { @@ -464,6 +465,7 @@ class CC_EXPORT LayerTreeHostImpl void ReleaseTreeResources(); void EnforceZeroBudget(bool zero_budget); + void ScrollViewportBy(gfx::Vector2dF scroll_delta); void AnimatePageScale(base::TimeTicks monotonic_time); void AnimateScrollbars(base::TimeTicks monotonic_time); void AnimateTopControls(base::TimeTicks monotonic_time); @@ -474,7 +476,6 @@ class CC_EXPORT LayerTreeHostImpl const gfx::PointF& viewport_point, const gfx::Vector2dF& viewport_delta); - void UpdateMaxScrollOffset(); void TrackDamageForAllSurfaces( LayerImpl* root_draw_layer, const LayerImplList& render_surface_layer_list); diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc index 4797541..8e7bf99 100644 --- a/cc/trees/layer_tree_host_impl_unittest.cc +++ b/cc/trees/layer_tree_host_impl_unittest.cc @@ -205,6 +205,9 @@ class LayerTreeHostImplTest : public testing::Test, LayerImpl* CreateScrollAndContentsLayers(LayerTreeImpl* layer_tree_impl, gfx::Size content_size) { + const int kInnerViewportScrollLayerId = 2; + const int kInnerViewportClipLayerId = 4; + const int kPageScaleLayerId = 5; scoped_ptr<LayerImpl> root = LayerImpl::Create(layer_tree_impl, 1); root->SetBounds(content_size); @@ -213,16 +216,25 @@ class LayerTreeHostImplTest : public testing::Test, root->SetAnchorPoint(gfx::PointF()); scoped_ptr<LayerImpl> scroll = - LayerImpl::Create(layer_tree_impl, 2); + LayerImpl::Create(layer_tree_impl, kInnerViewportScrollLayerId); LayerImpl* scroll_layer = scroll.get(); - scroll->SetScrollable(true); + scroll->SetIsContainerForFixedPositionLayers(true); scroll->SetScrollOffset(gfx::Vector2d()); - scroll->SetMaxScrollOffset(gfx::Vector2d(content_size.width(), - content_size.height())); + + scoped_ptr<LayerImpl> clip = + LayerImpl::Create(layer_tree_impl, kInnerViewportClipLayerId); + clip->SetBounds( + gfx::Size(content_size.width() / 2, content_size.height() / 2)); + + scoped_ptr<LayerImpl> page_scale = + LayerImpl::Create(layer_tree_impl, kPageScaleLayerId); + + scroll->SetScrollClipLayer(clip->id()); scroll->SetBounds(content_size); scroll->SetContentBounds(content_size); scroll->SetPosition(gfx::PointF()); scroll->SetAnchorPoint(gfx::PointF()); + scroll->SetIsContainerForFixedPositionLayers(true); scoped_ptr<LayerImpl> contents = LayerImpl::Create(layer_tree_impl, 3); @@ -233,9 +245,14 @@ class LayerTreeHostImplTest : public testing::Test, contents->SetAnchorPoint(gfx::PointF()); scroll->AddChild(contents.Pass()); - root->AddChild(scroll.Pass()); + page_scale->AddChild(scroll.Pass()); + clip->AddChild(page_scale.Pass()); + root->AddChild(clip.Pass()); layer_tree_impl->SetRootLayer(root.Pass()); + layer_tree_impl->SetViewportLayersFromIds( + kPageScaleLayerId, kInnerViewportScrollLayerId, Layer::INVALID_ID); + return scroll_layer; } @@ -246,15 +263,19 @@ class LayerTreeHostImplTest : public testing::Test, return scroll_layer; } - scoped_ptr<LayerImpl> CreateScrollableLayer(int id, gfx::Size size) { + // TODO(wjmaclean) Add clip-layer pointer to parameters. + scoped_ptr<LayerImpl> CreateScrollableLayer(int id, + gfx::Size size, + LayerImpl* clip_layer) { + DCHECK(clip_layer); + DCHECK(id != clip_layer->id()); scoped_ptr<LayerImpl> layer = LayerImpl::Create(host_impl_->active_tree(), id); - layer->SetScrollable(true); + layer->SetScrollClipLayer(clip_layer->id()); layer->SetDrawsContent(true); layer->SetBounds(size); layer->SetContentBounds(size); - layer->SetMaxScrollOffset(gfx::Vector2d(size.width() * 2, - size.height() * 2)); + clip_layer->SetBounds(gfx::Size(size.width() / 2, size.height() / 2)); return layer.Pass(); } @@ -422,15 +443,20 @@ TEST_F(LayerTreeHostImplTest, ScrollDeltaRepeatedScrolls) { gfx::Vector2d scroll_offset(20, 30); gfx::Vector2d scroll_delta(11, -15); { + scoped_ptr<LayerImpl> root_clip = + LayerImpl::Create(host_impl_->active_tree(), 2); scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1); - root->SetMaxScrollOffset(gfx::Vector2d(100, 100)); - root->SetScrollOffset(scroll_offset); - root->SetScrollable(true); - root->ScrollBy(scroll_delta); - host_impl_->active_tree()->SetRootLayer(root.Pass()); + root_clip->SetBounds(gfx::Size(10, 10)); + LayerImpl* root_layer = root.get(); + root_clip->AddChild(root.Pass()); + root_layer->SetBounds(gfx::Size(110, 110)); + root_layer->SetScrollClipLayer(root_clip->id()); + root_layer->SetScrollOffset(scroll_offset); + root_layer->ScrollBy(scroll_delta); + host_impl_->active_tree()->SetRootLayer(root_clip.Pass()); } - LayerImpl* root = host_impl_->active_tree()->root_layer(); + LayerImpl* root = host_impl_->active_tree()->root_layer()->children()[0]; scoped_ptr<ScrollAndScaleSet> scroll_info; @@ -721,13 +747,14 @@ TEST_F(LayerTreeHostImplTest, ScrollVerticallyByPageReturnsCorrectValue) { 20, VERTICAL)); vertical_scrollbar->SetBounds(gfx::Size(15, 1000)); - host_impl_->RootScrollLayer()->SetVerticalScrollbarLayer( + host_impl_->InnerViewportScrollLayer()->AddScrollbar( vertical_scrollbar.get()); // Trying to scroll with a vertical scrollbar will succeed. EXPECT_TRUE(host_impl_->ScrollVerticallyByPage( gfx::Point(), SCROLL_FORWARD)); - EXPECT_FLOAT_EQ(875.f, host_impl_->RootScrollLayer()->ScrollDelta().y()); + EXPECT_FLOAT_EQ(875.f, + host_impl_->InnerViewportScrollLayer()->ScrollDelta().y()); EXPECT_TRUE(host_impl_->ScrollVerticallyByPage( gfx::Point(), SCROLL_BACKWARD)); } @@ -743,9 +770,7 @@ TEST_F(LayerTreeHostImplTest, DISABLED_ScrollWithUserUnscrollableLayers) { LayerImpl* overflow = scroll_layer->children()[0]; overflow->SetBounds(overflow_size); overflow->SetContentBounds(overflow_size); - overflow->SetScrollable(true); - overflow->SetMaxScrollOffset(gfx::Vector2d(overflow_size.width(), - overflow_size.height())); + overflow->SetScrollClipLayer(scroll_layer->parent()->id()); overflow->SetScrollOffset(gfx::Vector2d()); overflow->SetPosition(gfx::PointF()); overflow->SetAnchorPoint(gfx::PointF()); @@ -808,7 +833,7 @@ TEST_F(LayerTreeHostImplTest, ImplPinchZoom) { host_impl_->SetViewportSize(gfx::Size(50, 50)); DrawFrame(); - EXPECT_EQ(scroll_layer, host_impl_->RootScrollLayer()); + EXPECT_EQ(scroll_layer, host_impl_->InnerViewportScrollLayer()); float min_page_scale = 1.f, max_page_scale = 4.f; @@ -822,6 +847,7 @@ TEST_F(LayerTreeHostImplTest, ImplPinchZoom) { float page_scale_delta = 2.f; host_impl_->ScrollBegin(gfx::Point(50, 50), InputHandler::Gesture); + host_impl_->PinchGestureBegin(); host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(50, 50)); host_impl_->PinchGestureEnd(); host_impl_->ScrollEnd(); @@ -833,7 +859,7 @@ TEST_F(LayerTreeHostImplTest, ImplPinchZoom) { EXPECT_EQ(scroll_info->page_scale_delta, page_scale_delta); EXPECT_EQ(gfx::Vector2d(75, 75).ToString(), - scroll_layer->max_scroll_offset().ToString()); + scroll_layer->MaxScrollOffset().ToString()); } // Scrolling after a pinch gesture should always be in local space. The @@ -872,7 +898,7 @@ TEST_F(LayerTreeHostImplTest, PinchGesture) { host_impl_->SetViewportSize(gfx::Size(50, 50)); DrawFrame(); - LayerImpl* scroll_layer = host_impl_->RootScrollLayer(); + LayerImpl* scroll_layer = host_impl_->InnerViewportScrollLayer(); DCHECK(scroll_layer); float min_page_scale = 1.f; @@ -992,7 +1018,6 @@ TEST_F(LayerTreeHostImplTest, PinchGesture) { 4.f); scroll_layer->SetScrollDelta(gfx::Vector2d()); scroll_layer->SetScrollOffset(gfx::Vector2d(0, 0)); - host_impl_->active_tree()->UpdateMaxScrollOffset(); host_impl_->ScrollBegin(gfx::Point(0, 0), InputHandler::Gesture); host_impl_->PinchGestureBegin(); @@ -1015,7 +1040,7 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimation) { host_impl_->SetViewportSize(gfx::Size(50, 50)); DrawFrame(); - LayerImpl* scroll_layer = host_impl_->RootScrollLayer(); + LayerImpl* scroll_layer = host_impl_->InnerViewportScrollLayer(); DCHECK(scroll_layer); float min_page_scale = 0.5f; @@ -1085,7 +1110,7 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimationNoOp) { host_impl_->SetViewportSize(gfx::Size(50, 50)); DrawFrame(); - LayerImpl* scroll_layer = host_impl_->RootScrollLayer(); + LayerImpl* scroll_layer = host_impl_->InnerViewportScrollLayer(); DCHECK(scroll_layer); float min_page_scale = 0.5f; @@ -1165,12 +1190,12 @@ TEST_F(LayerTreeHostImplTest, ScrollbarLinearFadeScheduling) { scoped_ptr<LayerImpl> scroll = LayerImpl::Create(host_impl_->active_tree(), 2); - scroll->SetScrollable(true); + scroll->SetScrollClipLayer(root->id()); scroll->SetScrollOffset(gfx::Vector2d()); - scroll->SetMaxScrollOffset(gfx::Vector2d(content_size.width(), - content_size.height())); + root->SetBounds(viewport_size); scroll->SetBounds(content_size); scroll->SetContentBounds(content_size); + scroll->SetIsContainerForFixedPositionLayers(true); scoped_ptr<LayerImpl> contents = LayerImpl::Create(host_impl_->active_tree(), 3); @@ -1180,13 +1205,15 @@ TEST_F(LayerTreeHostImplTest, ScrollbarLinearFadeScheduling) { scoped_ptr<PaintedScrollbarLayerImpl> scrollbar = PaintedScrollbarLayerImpl::Create(host_impl_->active_tree(), 4, VERTICAL); - scroll->SetVerticalScrollbarLayer(scrollbar.get()); + scrollbar->SetScrollLayerById(2); + scrollbar->SetClipLayerById(1); scroll->AddChild(contents.Pass()); root->AddChild(scroll.Pass()); root->AddChild(scrollbar.PassAs<LayerImpl>()); host_impl_->active_tree()->SetRootLayer(root.Pass()); + host_impl_->active_tree()->SetViewportLayersFromIds(1, 2, Layer::INVALID_ID); host_impl_->active_tree()->DidBecomeActive(); DrawFrame(); @@ -1237,7 +1264,7 @@ TEST_F(LayerTreeHostImplTest, ScrollbarLinearFadeScheduling) { // Setting the scroll offset outside a scroll should also cause the scrollbar // to appear and to schedule a fade. - host_impl_->RootScrollLayer()->SetScrollOffset(gfx::Vector2d(5, 5)); + host_impl_->InnerViewportScrollLayer()->SetScrollOffset(gfx::Vector2d(5, 5)); host_impl_->StartScrollbarAnimation(); EXPECT_LT(base::TimeDelta::FromMilliseconds(19), requested_scrollbar_animation_delay_); @@ -1271,12 +1298,11 @@ void LayerTreeHostImplTest::SetupMouseMoveAtWithDeviceScale( scoped_ptr<LayerImpl> scroll = LayerImpl::Create(host_impl_->active_tree(), 2); - scroll->SetScrollable(true); + scroll->SetScrollClipLayer(root->id()); scroll->SetScrollOffset(gfx::Vector2d()); - scroll->SetMaxScrollOffset(gfx::Vector2d(content_size.width(), - content_size.height())); scroll->SetBounds(content_size); scroll->SetContentBounds(content_size); + scroll->SetIsContainerForFixedPositionLayers(true); scoped_ptr<LayerImpl> contents = LayerImpl::Create(host_impl_->active_tree(), 3); @@ -1291,17 +1317,19 @@ void LayerTreeHostImplTest::SetupMouseMoveAtWithDeviceScale( scrollbar->SetBounds(gfx::Size(15, viewport_size.height())); scrollbar->SetContentBounds(gfx::Size(15, viewport_size.height())); scrollbar->SetPosition(gfx::Point(285, 0)); - scroll->SetVerticalScrollbarLayer(scrollbar.get()); + scrollbar->SetScrollLayerById(2); scroll->AddChild(contents.Pass()); root->AddChild(scroll.Pass()); root->AddChild(scrollbar.PassAs<LayerImpl>()); host_impl_->active_tree()->SetRootLayer(root.Pass()); + host_impl_->active_tree()->SetViewportLayersFromIds(1, 2, Layer::INVALID_ID); host_impl_->active_tree()->DidBecomeActive(); DrawFrame(); - LayerImpl* root_scroll = host_impl_->active_tree()->RootScrollLayer(); + LayerImpl* root_scroll = + host_impl_->active_tree()->InnerViewportScrollLayer(); ASSERT_TRUE(root_scroll->scrollbar_animation_controller()); ScrollbarAnimationControllerThinning* scrollbar_animation_controller = static_cast<ScrollbarAnimationControllerThinning*>( @@ -1749,7 +1777,7 @@ TEST_F(LayerTreeHostImplTest, PrepareToDrawFailsWhenAnimationUsesCheckerboard) { TEST_F(LayerTreeHostImplTest, ScrollRootIgnored) { scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1); - root->SetScrollable(false); + root->SetScrollClipLayer(Layer::INVALID_ID); host_impl_->active_tree()->SetRootLayer(root.Pass()); DrawFrame(); @@ -1767,18 +1795,23 @@ TEST_F(LayerTreeHostImplTest, ScrollNonScrollableRootWithTopControls) { CreateHostImpl(settings, CreateOutputSurface()); - gfx::Size layer_size(5, 5); + gfx::Size layer_size(10, 10); + gfx::Size clip_size(5, 5); scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1); - root->SetScrollable(true); - root->SetMaxScrollOffset(gfx::Vector2d(layer_size.width(), - layer_size.height())); + 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); - host_impl_->active_tree()->SetRootLayer(root.Pass()); - host_impl_->active_tree()->FindRootScrollLayer(); + 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); DrawFrame(); EXPECT_EQ(InputHandler::ScrollStarted, @@ -1800,29 +1833,32 @@ TEST_F(LayerTreeHostImplTest, ScrollNonCompositedRoot) { // Test the configuration where a non-composited root layer is embedded in a // scrollable outer layer. gfx::Size surface_size(10, 10); + gfx::Size contents_size(20, 20); scoped_ptr<LayerImpl> content_layer = LayerImpl::Create(host_impl_->active_tree(), 1); content_layer->SetDrawsContent(true); content_layer->SetPosition(gfx::PointF()); content_layer->SetAnchorPoint(gfx::PointF()); - content_layer->SetBounds(surface_size); - content_layer->SetContentBounds(gfx::Size(surface_size.width() * 2, - surface_size.height() * 2)); + content_layer->SetBounds(contents_size); + content_layer->SetContentBounds(contents_size); content_layer->SetContentsScale(2.f, 2.f); + scoped_ptr<LayerImpl> scroll_clip_layer = + LayerImpl::Create(host_impl_->active_tree(), 3); + scroll_clip_layer->SetBounds(surface_size); + scoped_ptr<LayerImpl> scroll_layer = LayerImpl::Create(host_impl_->active_tree(), 2); - scroll_layer->SetScrollable(true); - scroll_layer->SetMaxScrollOffset(gfx::Vector2d(surface_size.width(), - surface_size.height())); - scroll_layer->SetBounds(surface_size); - scroll_layer->SetContentBounds(surface_size); + scroll_layer->SetScrollClipLayer(3); + scroll_layer->SetBounds(contents_size); + scroll_layer->SetContentBounds(contents_size); scroll_layer->SetPosition(gfx::PointF()); scroll_layer->SetAnchorPoint(gfx::PointF()); scroll_layer->AddChild(content_layer.Pass()); + scroll_clip_layer->AddChild(scroll_layer.Pass()); - host_impl_->active_tree()->SetRootLayer(scroll_layer.Pass()); + host_impl_->active_tree()->SetRootLayer(scroll_clip_layer.Pass()); host_impl_->SetViewportSize(surface_size); DrawFrame(); @@ -1837,10 +1873,11 @@ TEST_F(LayerTreeHostImplTest, ScrollNonCompositedRoot) { TEST_F(LayerTreeHostImplTest, ScrollChildCallsCommitAndRedraw) { gfx::Size surface_size(10, 10); + gfx::Size contents_size(20, 20); scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1); root->SetBounds(surface_size); - root->SetContentBounds(surface_size); - root->AddChild(CreateScrollableLayer(2, surface_size)); + root->SetContentBounds(contents_size); + root->AddChild(CreateScrollableLayer(2, contents_size, root.get())); host_impl_->active_tree()->SetRootLayer(root.Pass()); host_impl_->SetViewportSize(surface_size); DrawFrame(); @@ -1857,7 +1894,7 @@ TEST_F(LayerTreeHostImplTest, ScrollChildCallsCommitAndRedraw) { TEST_F(LayerTreeHostImplTest, ScrollMissesChild) { gfx::Size surface_size(10, 10); scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1); - root->AddChild(CreateScrollableLayer(2, surface_size)); + root->AddChild(CreateScrollableLayer(2, surface_size, root.get())); host_impl_->active_tree()->SetRootLayer(root.Pass()); host_impl_->SetViewportSize(surface_size); DrawFrame(); @@ -1874,7 +1911,8 @@ TEST_F(LayerTreeHostImplTest, ScrollMissesChild) { TEST_F(LayerTreeHostImplTest, ScrollMissesBackfacingChild) { gfx::Size surface_size(10, 10); scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1); - scoped_ptr<LayerImpl> child = CreateScrollableLayer(2, surface_size); + scoped_ptr<LayerImpl> child = + CreateScrollableLayer(2, surface_size, root.get()); host_impl_->SetViewportSize(surface_size); gfx::Transform matrix; @@ -1897,14 +1935,21 @@ TEST_F(LayerTreeHostImplTest, ScrollMissesBackfacingChild) { TEST_F(LayerTreeHostImplTest, ScrollBlockedByContentLayer) { gfx::Size surface_size(10, 10); - scoped_ptr<LayerImpl> content_layer = CreateScrollableLayer(1, surface_size); + scoped_ptr<LayerImpl> clip_layer = + LayerImpl::Create(host_impl_->active_tree(), 3); + scoped_ptr<LayerImpl> content_layer = + CreateScrollableLayer(1, surface_size, clip_layer.get()); content_layer->SetShouldScrollOnMainThread(true); - content_layer->SetScrollable(false); + content_layer->SetScrollClipLayer(Layer::INVALID_ID); - scoped_ptr<LayerImpl> scroll_layer = CreateScrollableLayer(2, surface_size); + // Note: we can use the same clip layer for both since both calls to + // CreateScrollableLayer() use the same surface size. + scoped_ptr<LayerImpl> scroll_layer = + CreateScrollableLayer(2, surface_size, clip_layer.get()); scroll_layer->AddChild(content_layer.Pass()); + clip_layer->AddChild(scroll_layer.Pass()); - host_impl_->active_tree()->SetRootLayer(scroll_layer.Pass()); + host_impl_->active_tree()->SetRootLayer(clip_layer.Pass()); host_impl_->SetViewportSize(surface_size); DrawFrame(); @@ -1916,21 +1961,30 @@ TEST_F(LayerTreeHostImplTest, ScrollBlockedByContentLayer) { } TEST_F(LayerTreeHostImplTest, ScrollRootAndChangePageScaleOnMainThread) { - gfx::Size surface_size(10, 10); + gfx::Size surface_size(20, 20); float page_scale = 2.f; scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1); - scoped_ptr<LayerImpl> root_scrolling = CreateScrollableLayer(2, surface_size); - root->AddChild(root_scrolling.Pass()); + scoped_ptr<LayerImpl> root_clip = + LayerImpl::Create(host_impl_->active_tree(), 2); + scoped_ptr<LayerImpl> root_scrolling = + CreateScrollableLayer(3, surface_size, root_clip.get()); + root_scrolling->SetIsContainerForFixedPositionLayers(true); + root_clip->AddChild(root_scrolling.Pass()); + root->AddChild(root_clip.Pass()); host_impl_->active_tree()->SetRootLayer(root.Pass()); + // The behaviour in this test assumes the page scale is applied at a layer + // above the clip layer. + host_impl_->active_tree()->SetViewportLayersFromIds(1, 3, Layer::INVALID_ID); host_impl_->active_tree()->DidBecomeActive(); host_impl_->SetViewportSize(surface_size); DrawFrame(); - LayerImpl* root_scroll = host_impl_->active_tree()->RootScrollLayer(); + LayerImpl* root_scroll = + host_impl_->active_tree()->InnerViewportScrollLayer(); gfx::Vector2d scroll_delta(0, 10); gfx::Vector2d expected_scroll_delta = scroll_delta; - gfx::Vector2d expected_max_scroll = root_scroll->max_scroll_offset(); + gfx::Vector2d expected_max_scroll = root_scroll->MaxScrollOffset(); EXPECT_EQ(InputHandler::ScrollStarted, host_impl_->ScrollBegin(gfx::Point(5, 5), InputHandler::Wheel)); @@ -1946,7 +2000,7 @@ TEST_F(LayerTreeHostImplTest, ScrollRootAndChangePageScaleOnMainThread) { ExpectContains(*scroll_info.get(), root_scroll->id(), expected_scroll_delta); // The scroll range should also have been updated. - EXPECT_EQ(expected_max_scroll, root_scroll->max_scroll_offset()); + EXPECT_EQ(expected_max_scroll, root_scroll->MaxScrollOffset()); // The page scale delta remains constant because the impl thread did not // scale. @@ -1954,22 +2008,31 @@ TEST_F(LayerTreeHostImplTest, ScrollRootAndChangePageScaleOnMainThread) { } TEST_F(LayerTreeHostImplTest, ScrollRootAndChangePageScaleOnImplThread) { - gfx::Size surface_size(10, 10); + gfx::Size surface_size(20, 20); float page_scale = 2.f; scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1); - scoped_ptr<LayerImpl> root_scrolling = CreateScrollableLayer(2, surface_size); - root->AddChild(root_scrolling.Pass()); + scoped_ptr<LayerImpl> root_clip = + LayerImpl::Create(host_impl_->active_tree(), 2); + scoped_ptr<LayerImpl> root_scrolling = + CreateScrollableLayer(3, surface_size, root_clip.get()); + root_scrolling->SetIsContainerForFixedPositionLayers(true); + root_clip->AddChild(root_scrolling.Pass()); + root->AddChild(root_clip.Pass()); host_impl_->active_tree()->SetRootLayer(root.Pass()); + // The behaviour in this test assumes the page scale is applied at a layer + // 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_->active_tree()->SetPageScaleFactorAndLimits(1.f, 1.f, page_scale); DrawFrame(); - LayerImpl* root_scroll = host_impl_->active_tree()->RootScrollLayer(); + LayerImpl* root_scroll = + host_impl_->active_tree()->InnerViewportScrollLayer(); gfx::Vector2d scroll_delta(0, 10); gfx::Vector2d expected_scroll_delta = scroll_delta; - gfx::Vector2d expected_max_scroll = root_scroll->max_scroll_offset(); + gfx::Vector2d expected_max_scroll = root_scroll->MaxScrollOffset(); EXPECT_EQ(InputHandler::ScrollStarted, host_impl_->ScrollBegin(gfx::Point(5, 5), InputHandler::Wheel)); @@ -1989,7 +2052,7 @@ TEST_F(LayerTreeHostImplTest, ScrollRootAndChangePageScaleOnImplThread) { ExpectContains(*scroll_info.get(), root_scroll->id(), expected_scroll_delta); // The scroll range should also have been updated. - EXPECT_EQ(expected_max_scroll, root_scroll->max_scroll_offset()); + EXPECT_EQ(expected_max_scroll, root_scroll->MaxScrollOffset()); // The page scale delta should match the new scale on the impl side. EXPECT_EQ(page_scale, host_impl_->active_tree()->total_page_scale_factor()); @@ -2010,9 +2073,12 @@ TEST_F(LayerTreeHostImplTest, PageScaleDeltaAppliedToRootScrollLayerOnly) { LayerImpl* root = host_impl_->active_tree()->root_layer(); LayerImpl* child = scroll->children()[0]; + scoped_ptr<LayerImpl> scrollable_child_clip = + LayerImpl::Create(host_impl_->active_tree(), 6); scoped_ptr<LayerImpl> scrollable_child = - CreateScrollableLayer(4, surface_size); - child->AddChild(scrollable_child.Pass()); + CreateScrollableLayer(7, surface_size, scrollable_child_clip.get()); + scrollable_child_clip->AddChild(scrollable_child.Pass()); + child->AddChild(scrollable_child_clip.Pass()); LayerImpl* grand_child = child->children()[0]; // Set new page scale on impl thread by pinching. @@ -2052,27 +2118,31 @@ TEST_F(LayerTreeHostImplTest, PageScaleDeltaAppliedToRootScrollLayerOnly) { } TEST_F(LayerTreeHostImplTest, ScrollChildAndChangePageScaleOnMainThread) { - gfx::Size surface_size(10, 10); + gfx::Size surface_size(30, 30); scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1); + root->SetBounds(gfx::Size(5, 5)); scoped_ptr<LayerImpl> root_scrolling = LayerImpl::Create(host_impl_->active_tree(), 2); root_scrolling->SetBounds(surface_size); root_scrolling->SetContentBounds(surface_size); - root_scrolling->SetScrollable(true); + root_scrolling->SetScrollClipLayer(root->id()); + root_scrolling->SetIsContainerForFixedPositionLayers(true); + LayerImpl* root_scrolling_ptr = root_scrolling.get(); root->AddChild(root_scrolling.Pass()); int child_scroll_layer_id = 3; - scoped_ptr<LayerImpl> child_scrolling = - CreateScrollableLayer(child_scroll_layer_id, surface_size); + scoped_ptr<LayerImpl> child_scrolling = CreateScrollableLayer( + child_scroll_layer_id, surface_size, root_scrolling_ptr); LayerImpl* child = child_scrolling.get(); - root->AddChild(child_scrolling.Pass()); + root_scrolling_ptr->AddChild(child_scrolling.Pass()); 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); DrawFrame(); gfx::Vector2d scroll_delta(0, 10); gfx::Vector2d expected_scroll_delta(scroll_delta); - gfx::Vector2d expected_max_scroll(child->max_scroll_offset()); + gfx::Vector2d expected_max_scroll(child->MaxScrollOffset()); EXPECT_EQ(InputHandler::ScrollStarted, host_impl_->ScrollBegin(gfx::Point(5, 5), InputHandler::Wheel)); @@ -2091,7 +2161,7 @@ TEST_F(LayerTreeHostImplTest, ScrollChildAndChangePageScaleOnMainThread) { *scroll_info.get(), child_scroll_layer_id, expected_scroll_delta); // The scroll range should not have changed. - EXPECT_EQ(child->max_scroll_offset(), expected_max_scroll); + EXPECT_EQ(child->MaxScrollOffset(), expected_max_scroll); // The page scale delta remains constant because the impl thread did not // scale. @@ -2103,19 +2173,26 @@ TEST_F(LayerTreeHostImplTest, ScrollChildBeyondLimit) { // parent layer is scrolled on the axis on which the child was unable to // scroll. gfx::Size surface_size(10, 10); - scoped_ptr<LayerImpl> root = CreateScrollableLayer(1, surface_size); + gfx::Size content_size(20, 20); + scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1); + root->SetBounds(surface_size); - scoped_ptr<LayerImpl> grand_child = CreateScrollableLayer(3, surface_size); - grand_child->SetScrollOffset(gfx::Vector2d(0, 5)); + scoped_ptr<LayerImpl> grand_child = + CreateScrollableLayer(3, content_size, root.get()); - scoped_ptr<LayerImpl> child = CreateScrollableLayer(2, surface_size); - child->SetScrollOffset(gfx::Vector2d(3, 0)); + scoped_ptr<LayerImpl> child = + CreateScrollableLayer(2, content_size, root.get()); + LayerImpl* grand_child_layer = grand_child.get(); child->AddChild(grand_child.Pass()); + LayerImpl* child_layer = child.get(); root->AddChild(child.Pass()); host_impl_->active_tree()->SetRootLayer(root.Pass()); host_impl_->active_tree()->DidBecomeActive(); host_impl_->SetViewportSize(surface_size); + grand_child_layer->SetScrollOffset(gfx::Vector2d(0, 5)); + child_layer->SetScrollOffset(gfx::Vector2d(3, 0)); + DrawFrame(); { gfx::Vector2d scroll_delta(-8, -7); @@ -2141,22 +2218,31 @@ TEST_F(LayerTreeHostImplTest, ScrollChildBeyondLimit) { TEST_F(LayerTreeHostImplTest, ScrollWithoutBubbling) { // 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(10, 10); + gfx::Size surface_size(20, 20); scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1); - scoped_ptr<LayerImpl> root_scrolling = CreateScrollableLayer(2, surface_size); + scoped_ptr<LayerImpl> root_scrolling = + CreateScrollableLayer(2, surface_size, root.get()); + root_scrolling->SetIsContainerForFixedPositionLayers(true); - scoped_ptr<LayerImpl> grand_child = CreateScrollableLayer(4, surface_size); - grand_child->SetScrollOffset(gfx::Vector2d(0, 2)); + scoped_ptr<LayerImpl> grand_child = + CreateScrollableLayer(4, surface_size, root.get()); - scoped_ptr<LayerImpl> child = CreateScrollableLayer(3, surface_size); - child->SetScrollOffset(gfx::Vector2d(0, 3)); + scoped_ptr<LayerImpl> child = + CreateScrollableLayer(3, surface_size, root.get()); + LayerImpl* grand_child_layer = grand_child.get(); child->AddChild(grand_child.Pass()); + LayerImpl* child_layer = child.get(); root_scrolling->AddChild(child.Pass()); root->AddChild(root_scrolling.Pass()); 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); + + grand_child_layer->SetScrollOffset(gfx::Vector2d(0, 2)); + child_layer->SetScrollOffset(gfx::Vector2d(0, 3)); + DrawFrame(); { gfx::Vector2d scroll_delta(0, -10); @@ -2234,20 +2320,29 @@ TEST_F(LayerTreeHostImplTest, ScrollWithoutBubbling) { ExpectContains(*scroll_info.get(), grand_child->id(), gfx::Vector2d(0, 4)); } } - TEST_F(LayerTreeHostImplTest, ScrollEventBubbling) { // When we try to scroll a non-scrollable child layer, the scroll delta // should be applied to one of its ancestors if possible. gfx::Size surface_size(10, 10); gfx::Size content_size(20, 20); - scoped_ptr<LayerImpl> root = CreateScrollableLayer(1, content_size); - scoped_ptr<LayerImpl> child = CreateScrollableLayer(2, content_size); + scoped_ptr<LayerImpl> root_clip = + LayerImpl::Create(host_impl_->active_tree(), 3); + scoped_ptr<LayerImpl> root = + CreateScrollableLayer(1, content_size, root_clip.get()); + // Make 'root' the clip layer for child: since they have the same sizes the + // child will have zero max_scroll_offset and scrolls will bubble. + scoped_ptr<LayerImpl> child = + CreateScrollableLayer(2, content_size, root.get()); + child->SetIsContainerForFixedPositionLayers(true); + root->SetBounds(content_size); - child->SetScrollable(false); + int root_scroll_id = root->id(); root->AddChild(child.Pass()); + root_clip->AddChild(root.Pass()); host_impl_->SetViewportSize(surface_size); - host_impl_->active_tree()->SetRootLayer(root.Pass()); + host_impl_->active_tree()->SetRootLayer(root_clip.Pass()); + host_impl_->active_tree()->SetViewportLayersFromIds(3, 2, Layer::INVALID_ID); host_impl_->active_tree()->DidBecomeActive(); DrawFrame(); { @@ -2261,18 +2356,22 @@ TEST_F(LayerTreeHostImplTest, ScrollEventBubbling) { scoped_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas(); - // Only the root should have scrolled. + // Only the root scroll should have scrolled. ASSERT_EQ(scroll_info->scrolls.size(), 1u); - ExpectContains(*scroll_info.get(), - host_impl_->active_tree()->root_layer()->id(), - scroll_delta); + ExpectContains(*scroll_info.get(), root_scroll_id, scroll_delta); } } TEST_F(LayerTreeHostImplTest, ScrollBeforeRedraw) { gfx::Size surface_size(10, 10); - host_impl_->active_tree()->SetRootLayer( - CreateScrollableLayer(1, surface_size)); + scoped_ptr<LayerImpl> root_clip = + LayerImpl::Create(host_impl_->active_tree(), 1); + scoped_ptr<LayerImpl> root_scroll = + CreateScrollableLayer(2, surface_size, root_clip.get()); + root_scroll->SetIsContainerForFixedPositionLayers(true); + root_clip->AddChild(root_scroll.Pass()); + host_impl_->active_tree()->SetRootLayer(root_clip.Pass()); + host_impl_->active_tree()->SetViewportLayersFromIds(1, 2, Layer::INVALID_ID); host_impl_->active_tree()->DidBecomeActive(); host_impl_->SetViewportSize(surface_size); @@ -2280,8 +2379,14 @@ TEST_F(LayerTreeHostImplTest, ScrollBeforeRedraw) { // synchronization. DrawFrame(); host_impl_->active_tree()->DetachLayerTree(); - host_impl_->active_tree()->SetRootLayer( - CreateScrollableLayer(2, surface_size)); + scoped_ptr<LayerImpl> root_clip2 = + LayerImpl::Create(host_impl_->active_tree(), 3); + scoped_ptr<LayerImpl> root_scroll2 = + CreateScrollableLayer(4, surface_size, root_clip2.get()); + root_scroll2->SetIsContainerForFixedPositionLayers(true); + root_clip2->AddChild(root_scroll2.Pass()); + host_impl_->active_tree()->SetRootLayer(root_clip2.Pass()); + host_impl_->active_tree()->SetViewportLayersFromIds(3, 4, Layer::INVALID_ID); host_impl_->active_tree()->DidBecomeActive(); // Scrolling should still work even though we did not draw yet. @@ -2334,22 +2439,31 @@ TEST_F(LayerTreeHostImplTest, ScrollAxisAlignedRotatedLayer) { TEST_F(LayerTreeHostImplTest, ScrollNonAxisAlignedRotatedLayer) { LayerImpl* scroll_layer = SetupScrollAndContentsLayers(gfx::Size(100, 100)); - int child_layer_id = 4; + int child_clip_layer_id = 6; + int child_layer_id = 7; float child_layer_angle = -20.f; // Create a child layer that is rotated to a non-axis-aligned angle. + scoped_ptr<LayerImpl> clip_layer = + LayerImpl::Create(host_impl_->active_tree(), child_clip_layer_id); scoped_ptr<LayerImpl> child = CreateScrollableLayer( - child_layer_id, - scroll_layer->content_bounds()); + child_layer_id, scroll_layer->content_bounds(), clip_layer.get()); gfx::Transform rotate_transform; rotate_transform.Translate(-50.0, -50.0); rotate_transform.Rotate(child_layer_angle); rotate_transform.Translate(50.0, 50.0); - child->SetTransform(rotate_transform); + clip_layer->SetTransform(rotate_transform); // Only allow vertical scrolling. - child->SetMaxScrollOffset(gfx::Vector2d(0, child->content_bounds().height())); - scroll_layer->AddChild(child.Pass()); + clip_layer->SetBounds( + gfx::Size(child->bounds().width(), child->bounds().height() / 2)); + // The rotation depends on the layer's anchor point, and the child layer is a + // different size than the clip, so make sure the clip layer's anchor lines + // up over the child. + clip_layer->SetAnchorPoint(gfx::PointF(0.5, 1.0)); + LayerImpl* child_ptr = child.get(); + clip_layer->AddChild(child.Pass()); + scroll_layer->AddChild(clip_layer.Pass()); gfx::Size surface_size(50, 50); host_impl_->SetViewportSize(surface_size); @@ -2379,7 +2493,7 @@ TEST_F(LayerTreeHostImplTest, ScrollNonAxisAlignedRotatedLayer) { } { // Now reset and scroll the same amount horizontally. - scroll_layer->children()[1]->SetScrollDelta( + child_ptr->SetScrollDelta( gfx::Vector2dF()); gfx::Vector2d gesture_scroll_delta(10, 0); EXPECT_EQ(InputHandler::ScrollStarted, @@ -2514,6 +2628,8 @@ TEST_F(LayerTreeHostImplTest, RootLayerScrollOffsetDelegation) { TestScrollOffsetDelegate scroll_delegate; host_impl_->SetViewportSize(gfx::Size(10, 20)); LayerImpl* scroll_layer = SetupScrollAndContentsLayers(gfx::Size(100, 100)); + LayerImpl* clip_layer = scroll_layer->parent()->parent(); + clip_layer->SetBounds(gfx::Size(10, 20)); // Setting the delegate results in the current scroll offset being set. gfx::Vector2dF initial_scroll_delta(10.f, 10.f); @@ -2637,17 +2753,25 @@ TEST_F(LayerTreeHostImplTest, OverscrollChildWithoutBubbling) { // Scroll child layers beyond their maximum scroll range and make sure root // overscroll does not accumulate. gfx::Size surface_size(10, 10); - scoped_ptr<LayerImpl> root = CreateScrollableLayer(1, surface_size); + scoped_ptr<LayerImpl> root_clip = + LayerImpl::Create(host_impl_->active_tree(), 4); + scoped_ptr<LayerImpl> root = + CreateScrollableLayer(1, surface_size, root_clip.get()); - scoped_ptr<LayerImpl> grand_child = CreateScrollableLayer(3, surface_size); - grand_child->SetScrollOffset(gfx::Vector2d(0, 2)); + scoped_ptr<LayerImpl> grand_child = + CreateScrollableLayer(3, surface_size, root_clip.get()); - scoped_ptr<LayerImpl> child = CreateScrollableLayer(2, surface_size); - child->SetScrollOffset(gfx::Vector2d(0, 3)); + scoped_ptr<LayerImpl> child = + CreateScrollableLayer(2, surface_size, root_clip.get()); + LayerImpl* grand_child_layer = grand_child.get(); child->AddChild(grand_child.Pass()); + LayerImpl* child_layer = child.get(); root->AddChild(child.Pass()); - host_impl_->active_tree()->SetRootLayer(root.Pass()); + root_clip->AddChild(root.Pass()); + child_layer->SetScrollOffset(gfx::Vector2d(0, 3)); + grand_child_layer->SetScrollOffset(gfx::Vector2d(0, 2)); + host_impl_->active_tree()->SetRootLayer(root_clip.Pass()); host_impl_->active_tree()->DidBecomeActive(); host_impl_->SetViewportSize(surface_size); DrawFrame(); @@ -2660,19 +2784,16 @@ TEST_F(LayerTreeHostImplTest, OverscrollChildWithoutBubbling) { EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll()); host_impl_->ScrollEnd(); - LayerImpl* child = host_impl_->active_tree()->root_layer()->children()[0]; - LayerImpl* grand_child = child->children()[0]; - // The next time we scroll we should only scroll the parent, but overscroll // should still not reach the root layer. scroll_delta = gfx::Vector2d(0, -30); EXPECT_EQ(InputHandler::ScrollStarted, host_impl_->ScrollBegin(gfx::Point(5, 5), InputHandler::NonBubblingGesture)); - EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child); + EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child_layer); EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll()); host_impl_->ScrollBy(gfx::Point(), scroll_delta); - EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), child); + EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), child_layer); EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll()); host_impl_->ScrollEnd(); @@ -2684,9 +2805,9 @@ TEST_F(LayerTreeHostImplTest, OverscrollChildWithoutBubbling) { EXPECT_EQ(InputHandler::ScrollStarted, host_impl_->ScrollBegin(gfx::Point(5, 5), InputHandler::NonBubblingGesture)); - EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child); + EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child_layer); host_impl_->ScrollBy(gfx::Point(), scroll_delta); - EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child); + EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child_layer); EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll()); EXPECT_EQ(gfx::Vector2dF(), host_impl_->current_fling_velocity()); host_impl_->ScrollEnd(); @@ -2699,14 +2820,21 @@ TEST_F(LayerTreeHostImplTest, OverscrollChildEventBubbling) { // be reflected only when it has bubbled up to the root scrolling layer. gfx::Size surface_size(10, 10); gfx::Size content_size(20, 20); - scoped_ptr<LayerImpl> root = CreateScrollableLayer(1, content_size); - scoped_ptr<LayerImpl> child = CreateScrollableLayer(2, content_size); + scoped_ptr<LayerImpl> root_clip = + LayerImpl::Create(host_impl_->active_tree(), 3); + scoped_ptr<LayerImpl> root = + CreateScrollableLayer(1, content_size, root_clip.get()); + root->SetIsContainerForFixedPositionLayers(true); + scoped_ptr<LayerImpl> child = + CreateScrollableLayer(2, content_size, root_clip.get()); - child->SetScrollable(false); + child->SetScrollClipLayer(Layer::INVALID_ID); root->AddChild(child.Pass()); + root_clip->AddChild(root.Pass()); host_impl_->SetViewportSize(surface_size); - host_impl_->active_tree()->SetRootLayer(root.Pass()); + host_impl_->active_tree()->SetRootLayer(root_clip.Pass()); + host_impl_->active_tree()->SetViewportLayersFromIds(3, 1, Layer::INVALID_ID); host_impl_->active_tree()->DidBecomeActive(); DrawFrame(); { @@ -2728,7 +2856,9 @@ TEST_F(LayerTreeHostImplTest, OverscrollAlways) { LayerTreeSettings settings; CreateHostImpl(settings, CreateOutputSurface()); - SetupScrollAndContentsLayers(gfx::Size(50, 50)); + LayerImpl* scroll_layer = SetupScrollAndContentsLayers(gfx::Size(50, 50)); + LayerImpl* clip_layer = scroll_layer->parent()->parent(); + clip_layer->SetBounds(gfx::Size(50, 50)); host_impl_->SetViewportSize(gfx::Size(50, 50)); host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f, 0.5f, 4.f); DrawFrame(); @@ -4759,8 +4889,7 @@ TEST_F(LayerTreeHostImplTest, FarAwayQuadsDontNeedAA) { root->SetBounds(root_size); gfx::Vector2d scroll_offset(100000, 0); - scrolling_layer->SetScrollable(true); - scrolling_layer->SetMaxScrollOffset(scroll_offset); + scrolling_layer->SetScrollClipLayer(root->id()); scrolling_layer->SetScrollOffset(scroll_offset); host_impl_->ActivatePendingTree(); @@ -5210,13 +5339,21 @@ TEST_F(LayerTreeHostImplTest, TouchFlingShouldNotBubble) { // bubble). gfx::Size surface_size(10, 10); gfx::Size content_size(20, 20); - scoped_ptr<LayerImpl> root = CreateScrollableLayer(1, content_size); - scoped_ptr<LayerImpl> child = CreateScrollableLayer(2, content_size); + scoped_ptr<LayerImpl> root_clip = + LayerImpl::Create(host_impl_->active_tree(), 3); + scoped_ptr<LayerImpl> root = + CreateScrollableLayer(1, content_size, root_clip.get()); + root->SetIsContainerForFixedPositionLayers(true); + scoped_ptr<LayerImpl> child = + CreateScrollableLayer(2, content_size, root_clip.get()); root->AddChild(child.Pass()); + int root_id = root->id(); + root_clip->AddChild(root.Pass()); host_impl_->SetViewportSize(surface_size); - host_impl_->active_tree()->SetRootLayer(root.Pass()); + host_impl_->active_tree()->SetRootLayer(root_clip.Pass()); + host_impl_->active_tree()->SetViewportLayersFromIds(3, 1, Layer::INVALID_ID); host_impl_->active_tree()->DidBecomeActive(); DrawFrame(); { @@ -5238,8 +5375,7 @@ TEST_F(LayerTreeHostImplTest, TouchFlingShouldNotBubble) { // Only the child should have scrolled. ASSERT_EQ(1u, scroll_info->scrolls.size()); - ExpectNone(*scroll_info.get(), - host_impl_->active_tree()->root_layer()->id()); + ExpectNone(*scroll_info.get(), root_id); } } @@ -5248,12 +5384,15 @@ TEST_F(LayerTreeHostImplTest, TouchFlingShouldLockToFirstScrolledLayer) { // the scroll doesn't bubble up to the parent layer. gfx::Size surface_size(10, 10); scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1); - scoped_ptr<LayerImpl> root_scrolling = CreateScrollableLayer(2, surface_size); + scoped_ptr<LayerImpl> root_scrolling = + CreateScrollableLayer(2, surface_size, root.get()); - scoped_ptr<LayerImpl> grand_child = CreateScrollableLayer(4, surface_size); + scoped_ptr<LayerImpl> grand_child = + CreateScrollableLayer(4, surface_size, root.get()); grand_child->SetScrollOffset(gfx::Vector2d(0, 2)); - scoped_ptr<LayerImpl> child = CreateScrollableLayer(3, surface_size); + scoped_ptr<LayerImpl> child = + CreateScrollableLayer(3, surface_size, root.get()); child->SetScrollOffset(gfx::Vector2d(0, 4)); child->AddChild(grand_child.Pass()); @@ -5313,13 +5452,19 @@ TEST_F(LayerTreeHostImplTest, WheelFlingShouldBubble) { // bubble). gfx::Size surface_size(10, 10); gfx::Size content_size(20, 20); - scoped_ptr<LayerImpl> root = CreateScrollableLayer(1, content_size); - scoped_ptr<LayerImpl> child = CreateScrollableLayer(2, content_size); + scoped_ptr<LayerImpl> root_clip = + LayerImpl::Create(host_impl_->active_tree(), 3); + scoped_ptr<LayerImpl> root_scroll = + CreateScrollableLayer(1, content_size, root_clip.get()); + int root_scroll_id = root_scroll->id(); + scoped_ptr<LayerImpl> child = + CreateScrollableLayer(2, content_size, root_clip.get()); - root->AddChild(child.Pass()); + root_scroll->AddChild(child.Pass()); + root_clip->AddChild(root_scroll.Pass()); host_impl_->SetViewportSize(surface_size); - host_impl_->active_tree()->SetRootLayer(root.Pass()); + host_impl_->active_tree()->SetRootLayer(root_clip.Pass()); host_impl_->active_tree()->DidBecomeActive(); DrawFrame(); { @@ -5340,9 +5485,7 @@ TEST_F(LayerTreeHostImplTest, WheelFlingShouldBubble) { // The root should have scrolled. ASSERT_EQ(2u, scroll_info->scrolls.size()); - ExpectContains(*scroll_info.get(), - host_impl_->active_tree()->root_layer()->id(), - gfx::Vector2d(0, 10)); + ExpectContains(*scroll_info.get(), root_scroll_id, gfx::Vector2d(0, 10)); } } diff --git a/cc/trees/layer_tree_host_perftest.cc b/cc/trees/layer_tree_host_perftest.cc index 1bfe1c4..d8da0a0 100644 --- a/cc/trees/layer_tree_host_perftest.cc +++ b/cc/trees/layer_tree_host_perftest.cc @@ -338,6 +338,21 @@ class PageScaleImplSidePaintingPerfTest layer_tree_host()->SetPageScaleFactorAndLimits(1.f, min_scale_, max_scale_); } + virtual void BuildTree() OVERRIDE { + LayerTreeHostPerfTestJsonReader::BuildTree(); + + // TODO(wjmaclean) The JSON tree reader should be able to mark inner/out + // viewport scroll layers as part of its tree setup. The code below is + // matched to the tree specified in the data file heavy_layer_tree. + Layer* root = layer_tree_host()->root_layer(); + Layer* clip_layer = root->children()[0]; + Layer* inner_viewport_scroll_layer = clip_layer->children()[0]; + inner_viewport_scroll_layer->SetScrollClipLayer(root); + inner_viewport_scroll_layer->SetIsContainerForFixedPositionLayers(true); + layer_tree_host()->RegisterViewportLayers( + root, inner_viewport_scroll_layer, 0); + } + virtual void ApplyScrollAndScale(gfx::Vector2d scroll_delta, float scale_delta) OVERRIDE { float page_scale_factor = layer_tree_host()->page_scale_factor(); diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc index 5737b42..5c8d624 100644 --- a/cc/trees/layer_tree_host_unittest.cc +++ b/cc/trees/layer_tree_host_unittest.cc @@ -392,7 +392,7 @@ class LayerTreeHostTestNoExtraCommitFromScrollbarInvalidate bool paint_scrollbar = true; bool has_thumb = false; scrollbar_ = FakePaintedScrollbarLayer::Create( - paint_scrollbar, has_thumb, root_layer_->id()); + paint_scrollbar, has_thumb, root_layer_.get()); scrollbar_->SetPosition(gfx::Point(0, 10)); scrollbar_->SetBounds(gfx::Size(10, 10)); @@ -1137,9 +1137,17 @@ class LayerTreeHostTestStartPageScaleAnimation : public LayerTreeHostTest { scroll_layer_ = FakeContentLayer::Create(&client_); } - scroll_layer_->SetScrollable(true); + Layer* root_layer = layer_tree_host()->root_layer(); + scroll_layer_->SetScrollClipLayer(root_layer); + scroll_layer_->SetIsContainerForFixedPositionLayers(true); + scroll_layer_->SetBounds(gfx::Size(2 * root_layer->bounds().width(), + 2 * root_layer->bounds().height())); scroll_layer_->SetScrollOffset(gfx::Vector2d()); layer_tree_host()->root_layer()->AddChild(scroll_layer_); + // This test requires the page_scale and inner viewport layers to be + // identified. + layer_tree_host()->RegisterViewportLayers( + root_layer, scroll_layer_.get(), NULL); layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 0.5f, 2.f); } @@ -1448,7 +1456,7 @@ class LayerTreeHostTestDirectRendererAtomicCommit : public LayerTreeHostTest { bool paint_scrollbar = true; bool has_thumb = false; scrollbar_ = FakePaintedScrollbarLayer::Create( - paint_scrollbar, has_thumb, layer_->id()); + paint_scrollbar, has_thumb, layer_); scrollbar_->SetPosition(gfx::Point(0, 10)); scrollbar_->SetBounds(gfx::Size(10, 10)); @@ -3661,7 +3669,7 @@ class LayerTreeHostTestPropertyChangesDuringUpdateArePushed bool paint_scrollbar = true; bool has_thumb = false; scrollbar_layer_ = FakePaintedScrollbarLayer::Create( - paint_scrollbar, has_thumb, root_->id()); + paint_scrollbar, has_thumb, root_.get()); root_->AddChild(scrollbar_layer_); diff --git a/cc/trees/layer_tree_host_unittest_animation.cc b/cc/trees/layer_tree_host_unittest_animation.cc index 22c8965..c615c16 100644 --- a/cc/trees/layer_tree_host_unittest_animation.cc +++ b/cc/trees/layer_tree_host_unittest_animation.cc @@ -972,7 +972,7 @@ class LayerTreeHostAnimationTestScrollOffsetChangesArePropagated LayerTreeHostAnimationTest::SetupTree(); scroll_layer_ = FakeContentLayer::Create(&client_); - scroll_layer_->SetScrollable(true); + scroll_layer_->SetScrollClipLayer(layer_tree_host()->root_layer()); scroll_layer_->SetBounds(gfx::Size(1000, 1000)); scroll_layer_->SetScrollOffset(gfx::Vector2d(10, 20)); layer_tree_host()->root_layer()->AddChild(scroll_layer_); diff --git a/cc/trees/layer_tree_host_unittest_context.cc b/cc/trees/layer_tree_host_unittest_context.cc index 57c780b..0fef2e3 100644 --- a/cc/trees/layer_tree_host_unittest_context.cc +++ b/cc/trees/layer_tree_host_unittest_context.cc @@ -1090,7 +1090,7 @@ class LayerTreeHostContextTestDontUseLostResources scoped_refptr<PaintedScrollbarLayer> scrollbar = PaintedScrollbarLayer::Create( - scoped_ptr<Scrollbar>(new FakeScrollbar).Pass(), content->id()); + scoped_ptr<Scrollbar>(new FakeScrollbar).Pass(), content.get()); scrollbar->SetBounds(gfx::Size(10, 10)); scrollbar->SetAnchorPoint(gfx::PointF()); scrollbar->SetIsDrawable(true); @@ -1455,8 +1455,8 @@ class ScrollbarLayerLostContext : public LayerTreeHostContextTest { virtual void BeginTest() OVERRIDE { scoped_refptr<Layer> scroll_layer = Layer::Create(); - scrollbar_layer_ = - FakePaintedScrollbarLayer::Create(false, true, scroll_layer->id()); + scrollbar_layer_ = FakePaintedScrollbarLayer::Create( + false, true, scroll_layer.get()); scrollbar_layer_->SetBounds(gfx::Size(10, 100)); layer_tree_host()->root_layer()->AddChild(scrollbar_layer_); layer_tree_host()->root_layer()->AddChild(scroll_layer); diff --git a/cc/trees/layer_tree_host_unittest_damage.cc b/cc/trees/layer_tree_host_unittest_damage.cc index 7f008b4..846d5df 100644 --- a/cc/trees/layer_tree_host_unittest_damage.cc +++ b/cc/trees/layer_tree_host_unittest_damage.cc @@ -428,17 +428,23 @@ class LayerTreeHostScrollbarDamageTest : public LayerTreeHostDamageTest { root_layer->SetMasksToBounds(true); layer_tree_host()->SetRootLayer(root_layer); + scoped_refptr<Layer> scroll_clip_layer = Layer::Create(); scoped_refptr<Layer> content_layer = FakeContentLayer::Create(&client_); - content_layer->SetScrollable(true); + content_layer->SetScrollClipLayer(scroll_clip_layer.get()); content_layer->SetScrollOffset(gfx::Vector2d(10, 20)); - content_layer->SetMaxScrollOffset(gfx::Vector2d(30, 50)); content_layer->SetBounds(gfx::Size(100, 200)); - root_layer->AddChild(content_layer); + scroll_clip_layer->SetBounds( + gfx::Size(content_layer->bounds().width() - 30, + content_layer->bounds().height() - 50)); + scroll_clip_layer->AddChild(content_layer); + root_layer->AddChild(scroll_clip_layer); scoped_refptr<Layer> scrollbar_layer = - FakePaintedScrollbarLayer::Create(false, true, content_layer->id()); + FakePaintedScrollbarLayer::Create(false, true, content_layer.get()); scrollbar_layer->SetPosition(gfx::Point(300, 300)); scrollbar_layer->SetBounds(gfx::Size(10, 100)); + scrollbar_layer->ToScrollbarLayer()->SetClipLayer(scroll_clip_layer); + scrollbar_layer->ToScrollbarLayer()->SetScrollLayer(content_layer); root_layer->AddChild(scrollbar_layer); gfx::RectF content_rect(content_layer->position(), @@ -496,7 +502,8 @@ class LayerTreeHostDamageTestScrollbarDoesDamage ++did_swaps_; EXPECT_TRUE(result); LayerImpl* root = host_impl->active_tree()->root_layer(); - LayerImpl* scroll_layer = root->children()[0]; + LayerImpl* scroll_clip_layer = root->children()[0]; + LayerImpl* scroll_layer = scroll_clip_layer->children()[0]; switch (did_swaps_) { case 1: // Test that modifying the position of the content layer (not @@ -510,7 +517,8 @@ class LayerTreeHostDamageTestScrollbarDoesDamage host_impl->SetNeedsRedraw(); break; case 3: - scroll_layer->SetMaxScrollOffset(gfx::Vector2d(60, 100)); + scroll_layer->SetBounds(gfx::Size(root->bounds().width() + 60, + root->bounds().height() + 100)); host_impl->SetNeedsRedraw(); break; } @@ -569,7 +577,8 @@ class LayerTreeHostDamageTestScrollbarCommitDoesNoDamage ++did_swaps_; EXPECT_TRUE(result); LayerImpl* root = host_impl->active_tree()->root_layer(); - LayerImpl* scroll_layer = root->children()[0]; + LayerImpl* scroll_clip_layer = root->children()[0]; + LayerImpl* scroll_layer = scroll_clip_layer->children()[0]; switch (did_swaps_) { case 1: // Scroll on the thread. This should damage the scrollbar for the diff --git a/cc/trees/layer_tree_host_unittest_scroll.cc b/cc/trees/layer_tree_host_unittest_scroll.cc index 3871154..c7ea722 100644 --- a/cc/trees/layer_tree_host_unittest_scroll.cc +++ b/cc/trees/layer_tree_host_unittest_scroll.cc @@ -31,42 +31,53 @@ class LayerTreeHostScrollTestScrollSimple : public LayerTreeHostScrollTest { num_scrolls_(0) {} virtual void BeginTest() OVERRIDE { - layer_tree_host()->root_layer()->SetScrollable(true); - layer_tree_host()->root_layer() - ->SetMaxScrollOffset(gfx::Vector2d(100, 100)); - layer_tree_host()->root_layer()->SetScrollOffset(initial_scroll_); + Layer* root_layer = layer_tree_host()->root_layer(); + scoped_refptr<Layer> scroll_layer = Layer::Create(); + root_layer->AddChild(scroll_layer); + // Create an effective max_scroll_offset of (100, 100). + scroll_layer->SetBounds(gfx::Size(root_layer->bounds().width() + 100, + root_layer->bounds().height() + 100)); + scroll_layer->SetIsDrawable(true); + scroll_layer->SetIsContainerForFixedPositionLayers(true); + scroll_layer->SetScrollClipLayer(root_layer); + scroll_layer->SetScrollOffset(initial_scroll_); + layer_tree_host()->RegisterViewportLayers(root_layer, scroll_layer, NULL); PostSetNeedsCommitToMainThread(); } virtual void Layout() OVERRIDE { Layer* root = layer_tree_host()->root_layer(); + Layer* scroll_layer = root->children()[0]; if (!layer_tree_host()->source_frame_number()) { - EXPECT_VECTOR_EQ(initial_scroll_, root->scroll_offset()); + EXPECT_VECTOR_EQ(initial_scroll_, scroll_layer->scroll_offset()); } else { - EXPECT_VECTOR_EQ(initial_scroll_ + scroll_amount_, root->scroll_offset()); + EXPECT_VECTOR_EQ(initial_scroll_ + scroll_amount_, + scroll_layer->scroll_offset()); // Pretend like Javascript updated the scroll position itself. - root->SetScrollOffset(second_scroll_); + scroll_layer->SetScrollOffset(second_scroll_); } } virtual void DrawLayersOnThread(LayerTreeHostImpl* impl) OVERRIDE { LayerImpl* root = impl->active_tree()->root_layer(); - EXPECT_VECTOR_EQ(gfx::Vector2d(), root->ScrollDelta()); + LayerImpl* scroll_layer = root->children()[0]; + EXPECT_VECTOR_EQ(gfx::Vector2d(), scroll_layer->ScrollDelta()); - root->SetScrollable(true); - root->SetMaxScrollOffset(gfx::Vector2d(100, 100)); - root->ScrollBy(scroll_amount_); + scroll_layer->SetScrollClipLayer(root->id()); + scroll_layer->SetBounds( + gfx::Size(root->bounds().width() + 100, root->bounds().height() + 100)); + scroll_layer->ScrollBy(scroll_amount_); switch (impl->active_tree()->source_frame_number()) { case 0: - EXPECT_VECTOR_EQ(initial_scroll_, root->scroll_offset()); - EXPECT_VECTOR_EQ(scroll_amount_, root->ScrollDelta()); + EXPECT_VECTOR_EQ(initial_scroll_, scroll_layer->scroll_offset()); + EXPECT_VECTOR_EQ(scroll_amount_, scroll_layer->ScrollDelta()); PostSetNeedsCommitToMainThread(); break; case 1: - EXPECT_VECTOR_EQ(root->scroll_offset(), second_scroll_); - EXPECT_VECTOR_EQ(root->ScrollDelta(), scroll_amount_); + EXPECT_VECTOR_EQ(scroll_layer->scroll_offset(), second_scroll_); + EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(), scroll_amount_); EndTest(); break; } @@ -95,55 +106,62 @@ class LayerTreeHostScrollTestScrollMultipleRedraw : initial_scroll_(40, 10), scroll_amount_(-3, 17), num_scrolls_(0) {} virtual void BeginTest() OVERRIDE { - layer_tree_host()->root_layer()->SetScrollable(true); - layer_tree_host()->root_layer()->SetScrollOffset(initial_scroll_); - layer_tree_host()->root_layer()->SetBounds(gfx::Size(200, 200)); - layer_tree_host()->root_layer() - ->SetMaxScrollOffset(gfx::Vector2d(100, 100)); + Layer* root_layer = layer_tree_host()->root_layer(); + scroll_layer_ = Layer::Create(); + root_layer->AddChild(scroll_layer_); + // Create an effective max_scroll_offset of (100, 100). + scroll_layer_->SetBounds(gfx::Size(root_layer->bounds().width() + 100, + root_layer->bounds().height() + 100)); + scroll_layer_->SetIsDrawable(true); + scroll_layer_->SetIsContainerForFixedPositionLayers(true); + scroll_layer_->SetScrollClipLayer(root_layer); + scroll_layer_->SetScrollOffset(initial_scroll_); + layer_tree_host()->RegisterViewportLayers(root_layer, scroll_layer_, NULL); PostSetNeedsCommitToMainThread(); } virtual void BeginCommitOnThread(LayerTreeHostImpl* impl) OVERRIDE { - Layer* root = layer_tree_host()->root_layer(); switch (layer_tree_host()->source_frame_number()) { case 0: - EXPECT_VECTOR_EQ(root->scroll_offset(), initial_scroll_); + EXPECT_VECTOR_EQ(scroll_layer_->scroll_offset(), initial_scroll_); break; case 1: - EXPECT_VECTOR_EQ(root->scroll_offset(), + EXPECT_VECTOR_EQ(scroll_layer_->scroll_offset(), initial_scroll_ + scroll_amount_ + scroll_amount_); case 2: - EXPECT_VECTOR_EQ(root->scroll_offset(), + EXPECT_VECTOR_EQ(scroll_layer_->scroll_offset(), initial_scroll_ + scroll_amount_ + scroll_amount_); break; } } virtual void DrawLayersOnThread(LayerTreeHostImpl* impl) OVERRIDE { - LayerImpl* root = impl->active_tree()->root_layer(); + LayerImpl* scroll_layer = + impl->active_tree()->LayerById(scroll_layer_->id()); if (impl->active_tree()->source_frame_number() == 0 && impl->SourceAnimationFrameNumber() == 1) { // First draw after first commit. - EXPECT_VECTOR_EQ(root->ScrollDelta(), gfx::Vector2d()); - root->ScrollBy(scroll_amount_); - EXPECT_VECTOR_EQ(root->ScrollDelta(), scroll_amount_); + EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(), gfx::Vector2d()); + scroll_layer->ScrollBy(scroll_amount_); + EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(), scroll_amount_); - EXPECT_VECTOR_EQ(root->scroll_offset(), initial_scroll_); + EXPECT_VECTOR_EQ(scroll_layer->scroll_offset(), initial_scroll_); PostSetNeedsRedrawToMainThread(); } else if (impl->active_tree()->source_frame_number() == 0 && impl->SourceAnimationFrameNumber() == 2) { // Second draw after first commit. - EXPECT_EQ(root->ScrollDelta(), scroll_amount_); - root->ScrollBy(scroll_amount_); - EXPECT_VECTOR_EQ(root->ScrollDelta(), scroll_amount_ + scroll_amount_); + EXPECT_EQ(scroll_layer->ScrollDelta(), scroll_amount_); + scroll_layer->ScrollBy(scroll_amount_); + EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(), + scroll_amount_ + scroll_amount_); - EXPECT_VECTOR_EQ(root->scroll_offset(), initial_scroll_); + EXPECT_VECTOR_EQ(scroll_layer_->scroll_offset(), initial_scroll_); PostSetNeedsCommitToMainThread(); } else if (impl->active_tree()->source_frame_number() == 1) { // Third or later draw after second commit. EXPECT_GE(impl->SourceAnimationFrameNumber(), 3); - EXPECT_VECTOR_EQ(root->ScrollDelta(), gfx::Vector2d()); - EXPECT_VECTOR_EQ(root->scroll_offset(), + EXPECT_VECTOR_EQ(scroll_layer_->ScrollDelta(), gfx::Vector2d()); + EXPECT_VECTOR_EQ(scroll_layer_->scroll_offset(), initial_scroll_ + scroll_amount_ + scroll_amount_); EndTest(); } @@ -160,6 +178,7 @@ class LayerTreeHostScrollTestScrollMultipleRedraw gfx::Vector2d initial_scroll_; gfx::Vector2d scroll_amount_; int num_scrolls_; + scoped_refptr<Layer> scroll_layer_; }; MULTI_THREAD_TEST_F(LayerTreeHostScrollTestScrollMultipleRedraw); @@ -183,14 +202,17 @@ class LayerTreeHostScrollTestScrollAbortedCommit virtual void SetupTree() OVERRIDE { LayerTreeHostScrollTest::SetupTree(); + Layer* root_layer = layer_tree_host()->root_layer(); scoped_refptr<Layer> root_scroll_layer = Layer::Create(); - root_scroll_layer->SetScrollable(true); + root_scroll_layer->SetScrollClipLayer(root_layer); root_scroll_layer->SetScrollOffset(initial_scroll_); root_scroll_layer->SetBounds(gfx::Size(200, 200)); - root_scroll_layer->SetMaxScrollOffset(gfx::Vector2d(100, 100)); root_scroll_layer->SetIsDrawable(true); - layer_tree_host()->root_layer()->AddChild(root_scroll_layer); + root_scroll_layer->SetIsContainerForFixedPositionLayers(true); + root_layer->AddChild(root_scroll_layer); + layer_tree_host()->RegisterViewportLayers( + root_layer, root_scroll_layer, NULL); layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 0.01f, 100.f); } @@ -344,42 +366,57 @@ class LayerTreeHostScrollTestFractionalScroll : public LayerTreeHostScrollTest { public: LayerTreeHostScrollTestFractionalScroll() : scroll_amount_(1.75, 0) {} + virtual void SetupTree() OVERRIDE { + LayerTreeHostScrollTest::SetupTree(); + Layer* root_layer = layer_tree_host()->root_layer(); + scoped_refptr<Layer> root_scroll_layer = Layer::Create(); + root_scroll_layer->SetScrollClipLayer(root_layer); + root_scroll_layer->SetBounds( + gfx::Size(root_layer->bounds().width() + 100, + root_layer->bounds().height() + 100)); + root_scroll_layer->SetIsDrawable(true); + root_scroll_layer->SetIsContainerForFixedPositionLayers(true); + root_layer->AddChild(root_scroll_layer); + + layer_tree_host()->RegisterViewportLayers( + root_layer, root_scroll_layer, NULL); + layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 0.01f, 100.f); + } + virtual void BeginTest() OVERRIDE { - layer_tree_host()->root_layer()->SetScrollable(true); - layer_tree_host()->root_layer() - ->SetMaxScrollOffset(gfx::Vector2d(100, 100)); PostSetNeedsCommitToMainThread(); } virtual void DrawLayersOnThread(LayerTreeHostImpl* impl) OVERRIDE { LayerImpl* root = impl->active_tree()->root_layer(); + LayerImpl* scroll_layer = root->children()[0]; // Check that a fractional scroll delta is correctly accumulated over // multiple commits. switch (impl->active_tree()->source_frame_number()) { case 0: - EXPECT_VECTOR_EQ(root->scroll_offset(), gfx::Vector2d(0, 0)); - EXPECT_VECTOR_EQ(root->ScrollDelta(), gfx::Vector2d(0, 0)); + EXPECT_VECTOR_EQ(scroll_layer->scroll_offset(), gfx::Vector2d(0, 0)); + EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(), gfx::Vector2d(0, 0)); PostSetNeedsCommitToMainThread(); break; case 1: - EXPECT_VECTOR_EQ(root->scroll_offset(), + EXPECT_VECTOR_EQ(scroll_layer->scroll_offset(), gfx::ToFlooredVector2d(scroll_amount_)); - EXPECT_VECTOR_EQ(root->ScrollDelta(), + EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(), gfx::Vector2dF(fmod(scroll_amount_.x(), 1.0f), 0.0f)); PostSetNeedsCommitToMainThread(); break; case 2: EXPECT_VECTOR_EQ( - root->scroll_offset(), + scroll_layer->scroll_offset(), gfx::ToFlooredVector2d(scroll_amount_ + scroll_amount_)); EXPECT_VECTOR_EQ( - root->ScrollDelta(), + scroll_layer->ScrollDelta(), gfx::Vector2dF(fmod(2.0f * scroll_amount_.x(), 1.0f), 0.0f)); EndTest(); break; } - root->ScrollBy(scroll_amount_); + scroll_layer->ScrollBy(scroll_amount_); } virtual void AfterTest() OVERRIDE {} @@ -411,8 +448,8 @@ class LayerTreeHostScrollTestCaseWithChild : public LayerTreeHostScrollTest { root_scroll_layer_->SetAnchorPoint(gfx::PointF()); root_scroll_layer_->SetIsDrawable(true); - root_scroll_layer_->SetScrollable(true); - root_scroll_layer_->SetMaxScrollOffset(gfx::Vector2d(100, 100)); + root_scroll_layer_->SetScrollClipLayer(root_layer); + root_scroll_layer_->SetIsContainerForFixedPositionLayers(true); root_layer->AddChild(root_scroll_layer_); child_layer_ = ContentLayer::Create(&fake_content_layer_client_); @@ -433,8 +470,8 @@ class LayerTreeHostScrollTestCaseWithChild : public LayerTreeHostScrollTest { child_layer_->SetAnchorPoint(gfx::PointF()); child_layer_->SetIsDrawable(true); - child_layer_->SetScrollable(true); - child_layer_->SetMaxScrollOffset(gfx::Vector2d(100, 100)); + child_layer_->SetScrollClipLayer(root_layer); + child_layer_->SetBounds(root_scroll_layer_->bounds()); root_scroll_layer_->AddChild(child_layer_); if (scroll_child_layer_) { @@ -448,6 +485,8 @@ class LayerTreeHostScrollTestCaseWithChild : public LayerTreeHostScrollTest { expected_scroll_layer_->SetScrollOffset(initial_offset_); layer_tree_host()->SetRootLayer(root_layer); + layer_tree_host()->RegisterViewportLayers( + root_layer, root_scroll_layer_, NULL); LayerTreeHostScrollTest::SetupTree(); } @@ -724,26 +763,41 @@ class ImplSidePaintingScrollTestSimple : public ImplSidePaintingScrollTest { impl_thread_scroll2_(-3, 10), num_scrolls_(0) {} + virtual void SetupTree() OVERRIDE { + LayerTreeHostScrollTest::SetupTree(); + Layer* root_layer = layer_tree_host()->root_layer(); + scoped_refptr<Layer> root_scroll_layer = Layer::Create(); + root_scroll_layer->SetScrollClipLayer(root_layer); + root_scroll_layer->SetScrollOffset(initial_scroll_); + root_scroll_layer->SetBounds( + gfx::Size(root_layer->bounds().width() + 100, + root_layer->bounds().height() + 100)); + root_scroll_layer->SetIsDrawable(true); + root_scroll_layer->SetIsContainerForFixedPositionLayers(true); + root_layer->AddChild(root_scroll_layer); + + layer_tree_host()->RegisterViewportLayers( + root_layer, root_scroll_layer, NULL); + layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 0.01f, 100.f); + } + virtual void BeginTest() OVERRIDE { - layer_tree_host()->root_layer()->SetScrollable(true); - layer_tree_host()->root_layer() - ->SetMaxScrollOffset(gfx::Vector2d(100, 100)); - layer_tree_host()->root_layer()->SetScrollOffset(initial_scroll_); PostSetNeedsCommitToMainThread(); } virtual void Layout() OVERRIDE { Layer* root = layer_tree_host()->root_layer(); + Layer* scroll_layer = root->children()[0]; if (!layer_tree_host()->source_frame_number()) { - EXPECT_VECTOR_EQ(root->scroll_offset(), initial_scroll_); + EXPECT_VECTOR_EQ(scroll_layer->scroll_offset(), initial_scroll_); } else { - EXPECT_VECTOR_EQ(root->scroll_offset(), + EXPECT_VECTOR_EQ(scroll_layer->scroll_offset(), initial_scroll_ + impl_thread_scroll1_); // Pretend like Javascript updated the scroll position itself with a // change of main_thread_scroll. - root->SetScrollOffset(initial_scroll_ + main_thread_scroll_ + - impl_thread_scroll1_); + scroll_layer->SetScrollOffset(initial_scroll_ + main_thread_scroll_ + + impl_thread_scroll1_); } } @@ -758,6 +812,7 @@ class ImplSidePaintingScrollTestSimple : public ImplSidePaintingScrollTest { ImplSidePaintingScrollTest::DrawLayersOnThread(impl); LayerImpl* root = impl->active_tree()->root_layer(); + LayerImpl* scroll_layer = root->children()[0]; LayerImpl* pending_root = impl->active_tree()->FindPendingTreeLayerById(root->id()); @@ -765,12 +820,12 @@ class ImplSidePaintingScrollTestSimple : public ImplSidePaintingScrollTest { case 0: if (!impl->pending_tree()) { impl->BlockNotifyReadyToActivateForTesting(true); - EXPECT_VECTOR_EQ(root->ScrollDelta(), gfx::Vector2d()); - root->ScrollBy(impl_thread_scroll1_); + EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(), gfx::Vector2d()); + scroll_layer->ScrollBy(impl_thread_scroll1_); - EXPECT_VECTOR_EQ(root->scroll_offset(), initial_scroll_); - EXPECT_VECTOR_EQ(root->ScrollDelta(), impl_thread_scroll1_); - EXPECT_VECTOR_EQ(root->sent_scroll_delta(), gfx::Vector2d()); + EXPECT_VECTOR_EQ(scroll_layer->scroll_offset(), initial_scroll_); + EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(), impl_thread_scroll1_); + EXPECT_VECTOR_EQ(scroll_layer->sent_scroll_delta(), gfx::Vector2d()); PostSetNeedsCommitToMainThread(); // CommitCompleteOnThread will trigger this function again @@ -780,26 +835,30 @@ class ImplSidePaintingScrollTestSimple : public ImplSidePaintingScrollTest { ASSERT_TRUE(pending_root); EXPECT_EQ(impl->pending_tree()->source_frame_number(), 1); - root->ScrollBy(impl_thread_scroll2_); - EXPECT_VECTOR_EQ(root->scroll_offset(), initial_scroll_); - EXPECT_VECTOR_EQ(root->ScrollDelta(), + scroll_layer->ScrollBy(impl_thread_scroll2_); + EXPECT_VECTOR_EQ(scroll_layer->scroll_offset(), initial_scroll_); + EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(), impl_thread_scroll1_ + impl_thread_scroll2_); - EXPECT_VECTOR_EQ(root->sent_scroll_delta(), impl_thread_scroll1_); + EXPECT_VECTOR_EQ(scroll_layer->sent_scroll_delta(), + impl_thread_scroll1_); + LayerImpl* pending_scroll_layer = pending_root->children()[0]; EXPECT_VECTOR_EQ( - pending_root->scroll_offset(), + pending_scroll_layer->scroll_offset(), initial_scroll_ + main_thread_scroll_ + impl_thread_scroll1_); - EXPECT_VECTOR_EQ(pending_root->ScrollDelta(), impl_thread_scroll2_); - EXPECT_VECTOR_EQ(pending_root->sent_scroll_delta(), gfx::Vector2d()); + EXPECT_VECTOR_EQ(pending_scroll_layer->ScrollDelta(), + impl_thread_scroll2_); + EXPECT_VECTOR_EQ(pending_scroll_layer->sent_scroll_delta(), + gfx::Vector2d()); } break; case 1: EXPECT_FALSE(impl->pending_tree()); EXPECT_VECTOR_EQ( - root->scroll_offset(), + scroll_layer->scroll_offset(), initial_scroll_ + main_thread_scroll_ + impl_thread_scroll1_); - EXPECT_VECTOR_EQ(root->ScrollDelta(), impl_thread_scroll2_); - EXPECT_VECTOR_EQ(root->sent_scroll_delta(), gfx::Vector2d()); + EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(), impl_thread_scroll2_); + EXPECT_VECTOR_EQ(scroll_layer->sent_scroll_delta(), gfx::Vector2d()); EndTest(); break; } @@ -832,25 +891,40 @@ class ImplSidePaintingScrollTestImplOnlyScroll ImplSidePaintingScrollTestImplOnlyScroll() : initial_scroll_(20, 10), impl_thread_scroll_(-2, 3) {} + virtual void SetupTree() OVERRIDE { + LayerTreeHostScrollTest::SetupTree(); + Layer* root_layer = layer_tree_host()->root_layer(); + scoped_refptr<Layer> root_scroll_layer = Layer::Create(); + root_scroll_layer->SetScrollClipLayer(root_layer); + root_scroll_layer->SetScrollOffset(initial_scroll_); + root_scroll_layer->SetBounds( + gfx::Size(root_layer->bounds().width() + 100, + root_layer->bounds().height() + 100)); + root_scroll_layer->SetIsDrawable(true); + root_scroll_layer->SetIsContainerForFixedPositionLayers(true); + root_layer->AddChild(root_scroll_layer); + + layer_tree_host()->RegisterViewportLayers( + root_layer, root_scroll_layer, NULL); + layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 0.01f, 100.f); + } + virtual void BeginTest() OVERRIDE { - layer_tree_host()->root_layer()->SetScrollable(true); - layer_tree_host()->root_layer()->SetMaxScrollOffset( - gfx::Vector2d(100, 100)); - layer_tree_host()->root_layer()->SetScrollOffset(initial_scroll_); PostSetNeedsCommitToMainThread(); } virtual void WillCommit() OVERRIDE { Layer* root = layer_tree_host()->root_layer(); + Layer* scroll_layer = root->children()[0]; switch (layer_tree_host()->source_frame_number()) { case 0: - EXPECT_TRUE(root->needs_push_properties()); + EXPECT_TRUE(scroll_layer->needs_push_properties()); break; case 1: // Even if this layer doesn't need push properties, it should // still pick up scrolls that happen on the active layer during // commit. - EXPECT_FALSE(root->needs_push_properties()); + EXPECT_FALSE(scroll_layer->needs_push_properties()); break; } } @@ -859,8 +933,10 @@ class ImplSidePaintingScrollTestImplOnlyScroll // Scroll after the 2nd commit has started. if (impl->active_tree()->source_frame_number() == 0) { LayerImpl* active_root = impl->active_tree()->root_layer(); + LayerImpl* active_scroll_layer = active_root->children()[0]; ASSERT_TRUE(active_root); - active_root->ScrollBy(impl_thread_scroll_); + ASSERT_TRUE(active_scroll_layer); + active_scroll_layer->ScrollBy(impl_thread_scroll_); } } @@ -868,33 +944,45 @@ class ImplSidePaintingScrollTestImplOnlyScroll // We force a second draw here of the first commit before activating // the second commit. LayerImpl* active_root = impl->active_tree()->root_layer(); + LayerImpl* active_scroll_layer = + active_root ? active_root->children()[0] : NULL; LayerImpl* pending_root = impl->pending_tree()->root_layer(); + LayerImpl* pending_scroll_layer = pending_root->children()[0]; ASSERT_TRUE(pending_root); + ASSERT_TRUE(pending_scroll_layer); switch (impl->pending_tree()->source_frame_number()) { case 0: - EXPECT_VECTOR_EQ(pending_root->scroll_offset(), initial_scroll_); - EXPECT_VECTOR_EQ(pending_root->ScrollDelta(), gfx::Vector2d()); - EXPECT_VECTOR_EQ(pending_root->sent_scroll_delta(), gfx::Vector2d()); + EXPECT_VECTOR_EQ(pending_scroll_layer->scroll_offset(), + initial_scroll_); + EXPECT_VECTOR_EQ(pending_scroll_layer->ScrollDelta(), gfx::Vector2d()); + EXPECT_VECTOR_EQ(pending_scroll_layer->sent_scroll_delta(), + gfx::Vector2d()); EXPECT_FALSE(active_root); break; case 1: // Even though the scroll happened during the commit, both layers // should have the appropriate scroll delta. - EXPECT_VECTOR_EQ(pending_root->scroll_offset(), initial_scroll_); - EXPECT_VECTOR_EQ(pending_root->ScrollDelta(), impl_thread_scroll_); - EXPECT_VECTOR_EQ(pending_root->sent_scroll_delta(), gfx::Vector2d()); + EXPECT_VECTOR_EQ(pending_scroll_layer->scroll_offset(), + initial_scroll_); + EXPECT_VECTOR_EQ(pending_scroll_layer->ScrollDelta(), + impl_thread_scroll_); + EXPECT_VECTOR_EQ(pending_scroll_layer->sent_scroll_delta(), + gfx::Vector2d()); ASSERT_TRUE(active_root); - EXPECT_VECTOR_EQ(active_root->scroll_offset(), initial_scroll_); - EXPECT_VECTOR_EQ(active_root->ScrollDelta(), impl_thread_scroll_); - EXPECT_VECTOR_EQ(active_root->sent_scroll_delta(), gfx::Vector2d()); + EXPECT_VECTOR_EQ(active_scroll_layer->scroll_offset(), initial_scroll_); + EXPECT_VECTOR_EQ(active_scroll_layer->ScrollDelta(), + impl_thread_scroll_); + EXPECT_VECTOR_EQ(active_scroll_layer->sent_scroll_delta(), + gfx::Vector2d()); break; case 2: // On the next commit, this delta should have been sent and applied. - EXPECT_VECTOR_EQ(pending_root->scroll_offset(), + EXPECT_VECTOR_EQ(pending_scroll_layer->scroll_offset(), initial_scroll_ + impl_thread_scroll_); - EXPECT_VECTOR_EQ(pending_root->ScrollDelta(), gfx::Vector2d()); - EXPECT_VECTOR_EQ(pending_root->sent_scroll_delta(), gfx::Vector2d()); + EXPECT_VECTOR_EQ(pending_scroll_layer->ScrollDelta(), gfx::Vector2d()); + EXPECT_VECTOR_EQ(pending_scroll_layer->sent_scroll_delta(), + gfx::Vector2d()); EndTest(); break; } @@ -904,18 +992,19 @@ class ImplSidePaintingScrollTestImplOnlyScroll ImplSidePaintingScrollTest::DrawLayersOnThread(impl); LayerImpl* root = impl->active_tree()->root_layer(); + LayerImpl* scroll_layer = root->children()[0]; switch (impl->active_tree()->source_frame_number()) { case 0: - EXPECT_VECTOR_EQ(root->scroll_offset(), initial_scroll_); - EXPECT_VECTOR_EQ(root->ScrollDelta(), gfx::Vector2d()); - EXPECT_VECTOR_EQ(root->sent_scroll_delta(), gfx::Vector2d()); + EXPECT_VECTOR_EQ(scroll_layer->scroll_offset(), initial_scroll_); + EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(), gfx::Vector2d()); + EXPECT_VECTOR_EQ(scroll_layer->sent_scroll_delta(), gfx::Vector2d()); PostSetNeedsCommitToMainThread(); break; case 1: - EXPECT_VECTOR_EQ(root->scroll_offset(), initial_scroll_); - EXPECT_VECTOR_EQ(root->ScrollDelta(), impl_thread_scroll_); - EXPECT_VECTOR_EQ(root->sent_scroll_delta(), gfx::Vector2d()); + EXPECT_VECTOR_EQ(scroll_layer->scroll_offset(), initial_scroll_); + EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(), impl_thread_scroll_); + EXPECT_VECTOR_EQ(scroll_layer->sent_scroll_delta(), gfx::Vector2d()); PostSetNeedsCommitToMainThread(); break; } @@ -935,23 +1024,37 @@ class LayerTreeHostScrollTestScrollZeroMaxScrollOffset public: LayerTreeHostScrollTestScrollZeroMaxScrollOffset() {} + virtual void SetupTree() OVERRIDE { + LayerTreeTest::SetupTree(); + scoped_refptr<Layer> scroll_layer = Layer::Create(); + layer_tree_host()->root_layer()->AddChild(scroll_layer); + } + virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); } virtual void DrawLayersOnThread(LayerTreeHostImpl* impl) OVERRIDE { LayerImpl* root = impl->active_tree()->root_layer(); - root->SetScrollable(true); + LayerImpl* scroll_layer = root->children()[0]; + scroll_layer->SetScrollClipLayer(root->id()); - root->SetMaxScrollOffset(gfx::Vector2d(100, 100)); + // Set max_scroll_offset = (100, 100). + scroll_layer->SetBounds( + gfx::Size(root->bounds().width() + 100, root->bounds().height() + 100)); EXPECT_EQ(InputHandler::ScrollStarted, - root->TryScroll(gfx::PointF(0.0f, 1.0f), InputHandler::Gesture)); + scroll_layer->TryScroll(gfx::PointF(0.0f, 1.0f), + InputHandler::Gesture)); - root->SetMaxScrollOffset(gfx::Vector2d(0, 0)); + // Set max_scroll_offset = (0, 0). + scroll_layer->SetBounds(root->bounds()); EXPECT_EQ(InputHandler::ScrollIgnored, - root->TryScroll(gfx::PointF(0.0f, 1.0f), InputHandler::Gesture)); + scroll_layer->TryScroll(gfx::PointF(0.0f, 1.0f), + InputHandler::Gesture)); - root->SetMaxScrollOffset(gfx::Vector2d(-100, -100)); + // Set max_scroll_offset = (-100, -100). + scroll_layer->SetBounds(gfx::Size()); EXPECT_EQ(InputHandler::ScrollIgnored, - root->TryScroll(gfx::PointF(0.0f, 1.0f), InputHandler::Gesture)); + scroll_layer->TryScroll(gfx::PointF(0.0f, 1.0f), + InputHandler::Gesture)); EndTest(); } @@ -1093,8 +1196,9 @@ class LayerTreeHostScrollTestLayerStructureChange scroll_layer->SetPosition(gfx::Point(0, 0)); scroll_layer->SetAnchorPoint(gfx::PointF()); scroll_layer->SetIsDrawable(true); - scroll_layer->SetScrollable(true); - scroll_layer->SetMaxScrollOffset(gfx::Vector2d(100, 100)); + scroll_layer->SetScrollClipLayer(parent); + scroll_layer->SetBounds(gfx::Size(parent->bounds().width() + 100, + parent->bounds().height() + 100)); scroll_layer->set_did_scroll_callback(base::Bind( &FakeLayerScrollClient::DidScroll, base::Unretained(client))); client->owner_ = this; diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc index 34130de..e7b24c7 100644 --- a/cc/trees/layer_tree_impl.cc +++ b/cc/trees/layer_tree_impl.cc @@ -22,11 +22,62 @@ namespace cc { +// This class exists to split the LayerScrollOffsetDelegate between the +// InnerViewportScrollLayer and the OuterViewportScrollLayer in a manner +// that never requires the embedder or LayerImpl to know about. +class LayerScrollOffsetDelegateProxy : public LayerScrollOffsetDelegate { + public: + LayerScrollOffsetDelegateProxy(LayerImpl* layer, + LayerScrollOffsetDelegate* delegate, + LayerTreeImpl* layer_tree) + : layer_(layer), + delegate_(delegate), + layer_tree_impl_(layer_tree) {} + + gfx::Vector2dF last_set_scroll_offset() const { + return last_set_scroll_offset_; + } + + // LayerScrollOffsetDelegate implementation. + + virtual void SetTotalScrollOffset(const gfx::Vector2dF& new_offset) OVERRIDE { + last_set_scroll_offset_ = new_offset; + layer_tree_impl_->UpdateScrollOffsetDelegate(); + } + + virtual gfx::Vector2dF GetTotalScrollOffset() OVERRIDE { + return layer_tree_impl_->GetDelegatedScrollOffset(layer_); + } + + virtual bool IsExternalFlingActive() const OVERRIDE { + return delegate_->IsExternalFlingActive(); + } + + // Functions below this point are never called by LayerImpl on its + // LayerScrollOffsetDelegate, and so are not implemented. + virtual void SetMaxScrollOffset(const gfx::Vector2dF&) OVERRIDE { + NOTIMPLEMENTED(); + } + + virtual void SetTotalPageScaleFactor(float scale) OVERRIDE { + NOTIMPLEMENTED(); + } + + virtual void SetScrollableSize(const gfx::SizeF& scrollable_size) OVERRIDE { + NOTIMPLEMENTED(); + } + + private: + LayerImpl* layer_; + LayerScrollOffsetDelegate* delegate_; + LayerTreeImpl* layer_tree_impl_; + gfx::Vector2dF last_set_scroll_offset_; +}; + LayerTreeImpl::LayerTreeImpl(LayerTreeHostImpl* layer_tree_host_impl) : layer_tree_host_impl_(layer_tree_host_impl), source_frame_number_(-1), hud_layer_(0), - root_scroll_layer_(NULL), currently_scrolling_layer_(NULL), root_layer_scroll_offset_delegate_(NULL), background_color_(0), @@ -53,57 +104,77 @@ LayerTreeImpl::~LayerTreeImpl() { root_layer_.reset(); } -static LayerImpl* FindRootScrollLayerRecursive(LayerImpl* layer) { - if (!layer) - return NULL; +void LayerTreeImpl::SetRootLayer(scoped_ptr<LayerImpl> layer) { + if (inner_viewport_scroll_layer_) + inner_viewport_scroll_layer_->SetScrollOffsetDelegate(NULL); + if (outer_viewport_scroll_layer_) + outer_viewport_scroll_layer_->SetScrollOffsetDelegate(NULL); + inner_viewport_scroll_delegate_proxy_.reset(); + outer_viewport_scroll_delegate_proxy_.reset(); - if (layer->scrollable()) - return layer; + root_layer_ = layer.Pass(); + currently_scrolling_layer_ = NULL; + inner_viewport_scroll_layer_ = NULL; + outer_viewport_scroll_layer_ = NULL; + page_scale_layer_ = NULL; - for (size_t i = 0; i < layer->children().size(); ++i) { - LayerImpl* found = FindRootScrollLayerRecursive(layer->children()[i]); - if (found) - return found; - } + layer_tree_host_impl_->OnCanDrawStateChangedForTree(); +} - return NULL; +LayerImpl* LayerTreeImpl::InnerViewportScrollLayer() const { + return inner_viewport_scroll_layer_; } -void LayerTreeImpl::SetRootLayer(scoped_ptr<LayerImpl> layer) { - if (root_scroll_layer_) - root_scroll_layer_->SetScrollOffsetDelegate(NULL); - root_layer_ = layer.Pass(); - currently_scrolling_layer_ = NULL; - root_scroll_layer_ = NULL; +LayerImpl* LayerTreeImpl::OuterViewportScrollLayer() const { + return outer_viewport_scroll_layer_; +} - layer_tree_host_impl_->OnCanDrawStateChangedForTree(); +gfx::Vector2dF LayerTreeImpl::TotalScrollOffset() const { + gfx::Vector2dF offset; + + if (inner_viewport_scroll_layer_) + offset += inner_viewport_scroll_layer_->TotalScrollOffset(); + + if (outer_viewport_scroll_layer_) + offset += outer_viewport_scroll_layer_->TotalScrollOffset(); + + return offset; } -void LayerTreeImpl::FindRootScrollLayer() { - root_scroll_layer_ = FindRootScrollLayerRecursive(root_layer_.get()); +gfx::Vector2dF LayerTreeImpl::TotalMaxScrollOffset() const { + gfx::Vector2dF offset; - if (root_scroll_layer_) { - UpdateMaxScrollOffset(); - root_scroll_layer_->SetScrollOffsetDelegate( - root_layer_scroll_offset_delegate_); - } + if (inner_viewport_scroll_layer_) + offset += inner_viewport_scroll_layer_->MaxScrollOffset(); - if (scrolling_layer_id_from_previous_tree_) { - currently_scrolling_layer_ = LayerTreeHostCommon::FindLayerInSubtree( - root_layer_.get(), - scrolling_layer_id_from_previous_tree_); - } + if (outer_viewport_scroll_layer_) + offset += outer_viewport_scroll_layer_->MaxScrollOffset(); - scrolling_layer_id_from_previous_tree_ = 0; + return offset; +} +gfx::Vector2dF LayerTreeImpl::TotalScrollDelta() const { + DCHECK(inner_viewport_scroll_layer_); + gfx::Vector2dF delta = inner_viewport_scroll_layer_->ScrollDelta(); + + if (outer_viewport_scroll_layer_) + delta += outer_viewport_scroll_layer_->ScrollDelta(); + + return delta; } scoped_ptr<LayerImpl> LayerTreeImpl::DetachLayerTree() { // Clear all data structures that have direct references to the layer tree. scrolling_layer_id_from_previous_tree_ = currently_scrolling_layer_ ? currently_scrolling_layer_->id() : 0; - if (root_scroll_layer_) - root_scroll_layer_->SetScrollOffsetDelegate(NULL); - root_scroll_layer_ = NULL; + if (inner_viewport_scroll_layer_) + inner_viewport_scroll_layer_->SetScrollOffsetDelegate(NULL); + if (outer_viewport_scroll_layer_) + outer_viewport_scroll_layer_->SetScrollOffsetDelegate(NULL); + inner_viewport_scroll_delegate_proxy_.reset(); + outer_viewport_scroll_delegate_proxy_.reset(); + inner_viewport_scroll_layer_ = NULL; + outer_viewport_scroll_layer_ = NULL; + page_scale_layer_ = NULL; currently_scrolling_layer_ = NULL; render_surface_layer_list_.clear(); @@ -128,12 +199,14 @@ void LayerTreeImpl::PushPropertiesTo(LayerTreeImpl* target_tree) { target_tree->page_scale_delta() / target_tree->sent_page_scale_delta()); target_tree->set_sent_page_scale_delta(1); - if (settings().use_pinch_virtual_viewport) { + if (page_scale_layer_ && inner_viewport_scroll_layer_) { target_tree->SetViewportLayersFromIds( page_scale_layer_->id(), inner_viewport_scroll_layer_->id(), outer_viewport_scroll_layer_ ? outer_viewport_scroll_layer_->id() : Layer::INVALID_ID); + } else { + target_tree->ClearViewportLayers(); } // This should match the property synchronization in // LayerTreeHost::finishCommitOnImplThread(). @@ -159,12 +232,9 @@ void LayerTreeImpl::PushPropertiesTo(LayerTreeImpl* target_tree) { target_tree->set_hud_layer(NULL); } -LayerImpl* LayerTreeImpl::RootScrollLayer() const { - return root_scroll_layer_; -} - LayerImpl* LayerTreeImpl::RootContainerLayer() const { - return root_scroll_layer_ ? root_scroll_layer_->parent() : NULL; + return inner_viewport_scroll_layer_ ? inner_viewport_scroll_layer_->parent() + : NULL; } LayerImpl* LayerTreeImpl::CurrentlyScrollingLayer() const { @@ -190,6 +260,29 @@ void LayerTreeImpl::ClearCurrentlyScrollingLayer() { scrolling_layer_id_from_previous_tree_ = 0; } +float LayerTreeImpl::VerticalAdjust(const LayerImpl* layer) const { + DCHECK(layer); + if (layer->parent() != RootContainerLayer()) + return 0.f; + + return layer_tree_host_impl_->UnscaledScrollableViewportSize().height() - + RootContainerLayer()->bounds().height(); +} + +namespace { + +void ForceScrollbarParameterUpdateAfterScaleChange(LayerImpl* current_layer) { + if (!current_layer) + return; + + while (current_layer) { + current_layer->ScrollbarParametersDidChange(); + current_layer = current_layer->parent(); + } +} + +} // namespace + void LayerTreeImpl::SetPageScaleFactorAndLimits(float page_scale_factor, float min_page_scale_factor, float max_page_scale_factor) { if (!page_scale_factor) @@ -203,6 +296,8 @@ void LayerTreeImpl::SetPageScaleFactorAndLimits(float page_scale_factor, root_layer_scroll_offset_delegate_->SetTotalPageScaleFactor( total_page_scale_factor()); } + + ForceScrollbarParameterUpdateAfterScaleChange(page_scale_layer()); } void LayerTreeImpl::SetPageScaleDelta(float delta) { @@ -227,7 +322,6 @@ void LayerTreeImpl::SetPageScaleDelta(float delta) { } } - UpdateMaxScrollOffset(); set_needs_update_draw_properties(); if (root_layer_scroll_offset_delegate_) { @@ -237,34 +331,26 @@ void LayerTreeImpl::SetPageScaleDelta(float delta) { } gfx::SizeF LayerTreeImpl::ScrollableViewportSize() const { - return gfx::ScaleSize(layer_tree_host_impl_->UnscaledScrollableViewportSize(), - 1.0f / total_page_scale_factor()); + if (outer_viewport_scroll_layer_) + return layer_tree_host_impl_->UnscaledScrollableViewportSize(); + else + return gfx::ScaleSize( + layer_tree_host_impl_->UnscaledScrollableViewportSize(), + 1.0f / total_page_scale_factor()); } gfx::Rect LayerTreeImpl::RootScrollLayerDeviceViewportBounds() const { - if (!root_scroll_layer_ || root_scroll_layer_->children().empty()) + LayerImpl* root_scroll_layer = + OuterViewportScrollLayer() ? OuterViewportScrollLayer() + : InnerViewportScrollLayer(); + if (!root_scroll_layer || root_scroll_layer->children().empty()) return gfx::Rect(); - LayerImpl* layer = root_scroll_layer_->children()[0]; + LayerImpl* layer = root_scroll_layer->children()[0]; return MathUtil::MapClippedRect( layer->screen_space_transform(), gfx::Rect(layer->content_bounds())); } -void LayerTreeImpl::UpdateMaxScrollOffset() { - LayerImpl* root_scroll = RootScrollLayer(); - if (!root_scroll || !root_scroll->children().size()) - return; - - gfx::Vector2dF max_scroll = gfx::Rect(ScrollableSize()).bottom_right() - - gfx::RectF(ScrollableViewportSize()).bottom_right(); - - // The viewport may be larger than the contents in some cases, such as - // having a vertical scrollbar but no horizontal overflow. - max_scroll.SetToMax(gfx::Vector2dF()); - - root_scroll_layer_->SetMaxScrollOffset(gfx::ToFlooredVector2d(max_scroll)); -} - static void ApplySentScrollDeltasFromAbortedCommitTo(LayerImpl* layer) { layer->ApplySentScrollDeltasFromAbortedCommit(); } @@ -311,6 +397,20 @@ void LayerTreeImpl::SetViewportLayersFromIds( LayerById(outer_viewport_scroll_layer_id); DCHECK(outer_viewport_scroll_layer_ || outer_viewport_scroll_layer_id == Layer::INVALID_ID); + + if (!root_layer_scroll_offset_delegate_) + return; + + inner_viewport_scroll_delegate_proxy_ = make_scoped_ptr( + new LayerScrollOffsetDelegateProxy(inner_viewport_scroll_layer_, + root_layer_scroll_offset_delegate_, + this)); + + if (outer_viewport_scroll_layer_) + outer_viewport_scroll_delegate_proxy_ = make_scoped_ptr( + new LayerScrollOffsetDelegateProxy(outer_viewport_scroll_layer_, + root_layer_scroll_offset_delegate_, + this)); } void LayerTreeImpl::ClearViewportLayers() { @@ -319,42 +419,9 @@ void LayerTreeImpl::ClearViewportLayers() { outer_viewport_scroll_layer_ = NULL; } -// TODO(wjmaclean) This needs to go away, and be replaced with a single core -// of login that works for both scrollbar layer types. This is already planned -// as part of the larger pinch-zoom re-factoring viewport. -void LayerTreeImpl::UpdateSolidColorScrollbars() { - LayerImpl* root_scroll = RootScrollLayer(); - DCHECK(root_scroll); - DCHECK(IsActiveTree()); - - gfx::RectF scrollable_viewport( - gfx::PointAtOffsetFromOrigin(root_scroll->TotalScrollOffset()), - ScrollableViewportSize()); - float vertical_adjust = 0.0f; - if (RootContainerLayer()) - vertical_adjust = - layer_tree_host_impl_->UnscaledScrollableViewportSize().height() - - RootContainerLayer()->bounds().height(); - if (ScrollbarLayerImplBase* horiz = - root_scroll->horizontal_scrollbar_layer()) { - horiz->SetVerticalAdjust(vertical_adjust); - horiz->SetVisibleToTotalLengthRatio( - scrollable_viewport.width() / ScrollableSize().width()); - } - if (ScrollbarLayerImplBase* vertical = - root_scroll->vertical_scrollbar_layer()) { - vertical->SetVerticalAdjust(vertical_adjust); - vertical->SetVisibleToTotalLengthRatio( - scrollable_viewport.height() / ScrollableSize().height()); - } -} - void LayerTreeImpl::UpdateDrawProperties() { - if (IsActiveTree() && RootScrollLayer() && RootContainerLayer()) - UpdateRootScrollLayerSizeDelta(); - if (IsActiveTree() && RootContainerLayer()) - UpdateSolidColorScrollbars(); + UpdateRootScrollLayerSizeDelta(); needs_update_draw_properties_ = false; render_surface_layer_list_.clear(); @@ -434,9 +501,11 @@ const LayerImplList& LayerTreeImpl::RenderSurfaceLayerList() const { } gfx::Size LayerTreeImpl::ScrollableSize() const { - if (!root_scroll_layer_ || root_scroll_layer_->children().empty()) + LayerImpl* root_scroll_layer = OuterViewportScrollLayer() ? + OuterViewportScrollLayer() : InnerViewportScrollLayer(); + if (!root_scroll_layer || root_scroll_layer->children().empty()) return gfx::Size(); - return root_scroll_layer_->children()[0]->bounds(); + return root_scroll_layer->children()[0]->bounds(); } LayerImpl* LayerTreeImpl::LayerById(int id) { @@ -470,8 +539,13 @@ void LayerTreeImpl::DidBecomeActive() { if (!root_layer()) return; + if (scrolling_layer_id_from_previous_tree_) { + currently_scrolling_layer_ = LayerTreeHostCommon::FindLayerInSubtree( + root_layer_.get(), + scrolling_layer_id_from_previous_tree_); + } + DidBecomeActiveRecursive(root_layer()); - FindRootScrollLayer(); } bool LayerTreeImpl::ContentsTexturesPurged() const { @@ -662,22 +736,110 @@ void LayerTreeImpl::SetRootLayerScrollOffsetDelegate( if (root_layer_scroll_offset_delegate_ == root_layer_scroll_offset_delegate) return; - root_layer_scroll_offset_delegate_ = root_layer_scroll_offset_delegate; - - if (root_scroll_layer_) { - root_scroll_layer_->SetScrollOffsetDelegate( - root_layer_scroll_offset_delegate_); + if (!root_layer_scroll_offset_delegate) { + // Make sure we remove the proxies from their layers before + // releasing them. + if (InnerViewportScrollLayer()) + InnerViewportScrollLayer()->SetScrollOffsetDelegate(NULL); + if (OuterViewportScrollLayer()) + OuterViewportScrollLayer()->SetScrollOffsetDelegate(NULL); + inner_viewport_scroll_delegate_proxy_.reset(); + outer_viewport_scroll_delegate_proxy_.reset(); } + root_layer_scroll_offset_delegate_ = root_layer_scroll_offset_delegate; + if (root_layer_scroll_offset_delegate_) { + root_layer_scroll_offset_delegate_->SetTotalScrollOffset( + TotalScrollOffset()); + root_layer_scroll_offset_delegate_->SetMaxScrollOffset( + TotalMaxScrollOffset()); root_layer_scroll_offset_delegate_->SetScrollableSize(ScrollableSize()); root_layer_scroll_offset_delegate_->SetTotalPageScaleFactor( total_page_scale_factor()); + + if (inner_viewport_scroll_layer_) { + inner_viewport_scroll_delegate_proxy_ = make_scoped_ptr( + new LayerScrollOffsetDelegateProxy(InnerViewportScrollLayer(), + root_layer_scroll_offset_delegate_, + this)); + inner_viewport_scroll_layer_->SetScrollOffsetDelegate( + inner_viewport_scroll_delegate_proxy_.get()); + } + + if (outer_viewport_scroll_layer_) { + outer_viewport_scroll_delegate_proxy_ = make_scoped_ptr( + new LayerScrollOffsetDelegateProxy(OuterViewportScrollLayer(), + root_layer_scroll_offset_delegate_, + this)); + outer_viewport_scroll_layer_->SetScrollOffsetDelegate( + outer_viewport_scroll_delegate_proxy_.get()); + } } } +void LayerTreeImpl::UpdateScrollOffsetDelegate() { + DCHECK(InnerViewportScrollLayer()); + DCHECK(root_layer_scroll_offset_delegate_); + + gfx::Vector2dF offset = + inner_viewport_scroll_delegate_proxy_->last_set_scroll_offset(); + + if (OuterViewportScrollLayer()) + offset += + outer_viewport_scroll_delegate_proxy_->last_set_scroll_offset(); + + root_layer_scroll_offset_delegate_->SetTotalScrollOffset(offset); + root_layer_scroll_offset_delegate_->SetMaxScrollOffset( + TotalMaxScrollOffset()); +} + +gfx::Vector2dF LayerTreeImpl::GetDelegatedScrollOffset(LayerImpl* layer) { + DCHECK(root_layer_scroll_offset_delegate_); + DCHECK(InnerViewportScrollLayer()); + if (layer == InnerViewportScrollLayer() && !OuterViewportScrollLayer()) + return root_layer_scroll_offset_delegate_->GetTotalScrollOffset(); + + // If we get here, we have both inner/outer viewports, and need to distribute + // the scroll offset between them. + DCHECK(inner_viewport_scroll_delegate_proxy_); + DCHECK(outer_viewport_scroll_delegate_proxy_); + gfx::Vector2dF inner_viewport_offset = + inner_viewport_scroll_delegate_proxy_->last_set_scroll_offset(); + gfx::Vector2dF outer_viewport_offset = + outer_viewport_scroll_delegate_proxy_->last_set_scroll_offset(); + + // It may be nothing has changed. + gfx::Vector2dF delegate_offset = + root_layer_scroll_offset_delegate_->GetTotalScrollOffset(); + if (inner_viewport_offset + outer_viewport_offset == delegate_offset) { + if (layer == InnerViewportScrollLayer()) + return inner_viewport_offset; + else + return outer_viewport_offset; + } + + gfx::Vector2d max_outer_viewport_scroll_offset = + OuterViewportScrollLayer()->MaxScrollOffset(); + + outer_viewport_offset = delegate_offset - inner_viewport_offset; + outer_viewport_offset.SetToMin(max_outer_viewport_scroll_offset); + outer_viewport_offset.SetToMax(gfx::Vector2d()); + + if (layer == OuterViewportScrollLayer()) + return outer_viewport_offset; + + inner_viewport_offset = delegate_offset - outer_viewport_offset; + + return inner_viewport_offset; +} + +// TODO(wjmaclean) Rename this function, as we no longer have a +// "RootScrollLayer". void LayerTreeImpl::UpdateRootScrollLayerSizeDelta() { - LayerImpl* root_scroll = RootScrollLayer(); + // 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); diff --git a/cc/trees/layer_tree_impl.h b/cc/trees/layer_tree_impl.h index 7c4479d..81a8992 100644 --- a/cc/trees/layer_tree_impl.h +++ b/cc/trees/layer_tree_impl.h @@ -34,6 +34,7 @@ class ContextProvider; class DebugRectHistory; class FrameRateCounter; class HeadsUpDisplayLayerImpl; +class LayerScrollOffsetDelegateProxy; class LayerTreeDebugState; class LayerTreeHostImpl; class LayerTreeImpl; @@ -113,18 +114,24 @@ class CC_EXPORT LayerTreeImpl { hud_layer_ = layer_impl; } - LayerImpl* RootScrollLayer() const; + LayerImpl* InnerViewportScrollLayer() const; + // This function may return NULL, it is the caller's responsibility to check. + LayerImpl* OuterViewportScrollLayer() const; + gfx::Vector2dF TotalScrollOffset() const; + gfx::Vector2dF TotalMaxScrollOffset() const; + gfx::Vector2dF TotalScrollDelta() const; + LayerImpl* RootContainerLayer() const; LayerImpl* CurrentlyScrollingLayer() const; void SetCurrentlyScrollingLayer(LayerImpl* layer); void ClearCurrentlyScrollingLayer(); + float VerticalAdjust(const LayerImpl* layer) const; - void FindRootScrollLayer(); - void UpdateMaxScrollOffset(); void SetViewportLayersFromIds(int page_scale_layer_id, int inner_viewport_scroll_layer_id, int outer_viewport_scroll_layer_id); void ClearViewportLayers(); + LayerImpl* page_scale_layer() { return page_scale_layer_; } void ApplySentScrollAndScaleDeltasFromAbortedCommit(); void ApplyScrollDeltasSinceBeginMainFrame(); @@ -207,6 +214,8 @@ class CC_EXPORT LayerTreeImpl { void SetRootLayerScrollOffsetDelegate( LayerScrollOffsetDelegate* root_layer_scroll_offset_delegate); + void UpdateScrollOffsetDelegate(); + gfx::Vector2dF GetDelegatedScrollOffset(LayerImpl* layer); // Call this function when you expect there to be a swap buffer. // See swap_promise.h for how to use SwapPromise. @@ -231,17 +240,18 @@ class CC_EXPORT LayerTreeImpl { protected: explicit LayerTreeImpl(LayerTreeHostImpl* layer_tree_host_impl); - void UpdateSolidColorScrollbars(); - void UpdateRootScrollLayerSizeDelta(); LayerTreeHostImpl* layer_tree_host_impl_; int source_frame_number_; scoped_ptr<LayerImpl> root_layer_; HeadsUpDisplayLayerImpl* hud_layer_; - LayerImpl* root_scroll_layer_; LayerImpl* currently_scrolling_layer_; LayerScrollOffsetDelegate* root_layer_scroll_offset_delegate_; + scoped_ptr<LayerScrollOffsetDelegateProxy> + inner_viewport_scroll_delegate_proxy_; + scoped_ptr<LayerScrollOffsetDelegateProxy> + outer_viewport_scroll_delegate_proxy_; SkColor background_color_; bool has_transparent_background_; diff --git a/cc/trees/tree_synchronizer.cc b/cc/trees/tree_synchronizer.cc index 27f9dab..1c1c7e1 100644 --- a/cc/trees/tree_synchronizer.cc +++ b/cc/trees/tree_synchronizer.cc @@ -25,6 +25,13 @@ void CollectExistingLayerImplRecursive(ScopedPtrLayerImplMap* old_layers, if (!layer_impl) return; + layer_impl->ClearScrollbars(); + if (ScrollbarLayerImplBase* scrollbar_layer = + layer_impl->ToScrollbarLayer()) { + scrollbar_layer->ClearClipLayer(); + scrollbar_layer->ClearScrollLayer(); + } + OwnedLayerImplList& children = layer_impl->children(); for (OwnedLayerImplList::iterator it = children.begin(); it != children.end(); @@ -112,11 +119,6 @@ scoped_ptr<LayerImpl> SynchronizeTreesRecursiveInternal( layer_impl->SetReplicaLayer(SynchronizeTreesRecursiveInternal( new_layers, old_layers, layer->replica_layer(), tree_impl)); - // Remove all dangling pointers. The pointers will be setup later in - // UpdateScrollbarLayerPointersRecursive phase - layer_impl->SetHorizontalScrollbarLayer(NULL); - layer_impl->SetVerticalScrollbarLayer(NULL); - return layer_impl.Pass(); } @@ -160,17 +162,9 @@ void UpdateScrollbarLayerPointersRecursiveInternal( iter != new_layers->end() ? static_cast<ScrollbarLayerImplBase*>(iter->second) : NULL; - iter = new_layers->find(scrollbar_layer->ScrollLayerId()); - LayerImpl* scroll_layer_impl = - iter != new_layers->end() ? iter->second : NULL; - DCHECK(scrollbar_layer_impl); - DCHECK(scroll_layer_impl); - if (scrollbar_layer->orientation() == HORIZONTAL) - scroll_layer_impl->SetHorizontalScrollbarLayer(scrollbar_layer_impl); - else - scroll_layer_impl->SetVerticalScrollbarLayer(scrollbar_layer_impl); + scrollbar_layer->PushScrollClipPropertiesTo(scrollbar_layer_impl); } void UpdateScrollbarLayerPointersRecursive(const RawPtrLayerImplMap* new_layers, @@ -205,6 +199,8 @@ void TreeSynchronizer::PushPropertiesInternal( if (push_layer) layer->PushPropertiesTo(layer_impl); + else if (layer->ToScrollbarLayer()) + layer->ToScrollbarLayer()->PushScrollClipPropertiesTo(layer_impl); size_t num_dependents_need_push_properties = 0; if (recurse_on_children_and_dependents) { diff --git a/content/public/common/common_param_traits_macros.h b/content/public/common/common_param_traits_macros.h index a11194e..7f46790 100644 --- a/content/public/common/common_param_traits_macros.h +++ b/content/public/common/common_param_traits_macros.h @@ -123,6 +123,7 @@ IPC_STRUCT_TRAITS_BEGIN(WebPreferences) IPC_STRUCT_TRAITS_MEMBER(pepper_3d_enabled) IPC_STRUCT_TRAITS_MEMBER(experimental_websocket_enabled) IPC_STRUCT_TRAITS_MEMBER(pinch_virtual_viewport_enabled) + IPC_STRUCT_TRAITS_MEMBER(pinch_overlay_scrollbar_thickness) IPC_STRUCT_TRAITS_MEMBER(use_solid_color_scrollbars) IPC_STRUCT_TRAITS_MEMBER(flash_3d_enabled) IPC_STRUCT_TRAITS_MEMBER(flash_stage3d_enabled) diff --git a/content/renderer/gpu/render_widget_compositor.cc b/content/renderer/gpu/render_widget_compositor.cc index fe8693b..301e11d 100644 --- a/content/renderer/gpu/render_widget_compositor.cc +++ b/content/renderer/gpu/render_widget_compositor.cc @@ -269,6 +269,7 @@ scoped_ptr<RenderWidgetCompositor> RenderWidgetCompositor::Create( if (cmd->HasSwitch(cc::switches::kEnablePinchVirtualViewport) || IsOverlayScrollbarEnabled()) { settings.solid_color_scrollbar_color = SkColorSetARGB(128, 128, 128, 128); + settings.scrollbar_animator = cc::LayerTreeSettings::LinearFade; } #endif diff --git a/content/test/web_layer_tree_view_impl_for_testing.cc b/content/test/web_layer_tree_view_impl_for_testing.cc index d29e68b..3b0c967 100644 --- a/content/test/web_layer_tree_view_impl_for_testing.cc +++ b/content/test/web_layer_tree_view_impl_for_testing.cc @@ -164,4 +164,25 @@ WebLayerTreeViewImplForTesting::OffscreenContextProvider() { OffscreenContextProviderForMainThread(); } +void WebLayerTreeViewImplForTesting::registerViewportLayers( + const blink::WebLayer* pageScaleLayer, + const blink::WebLayer* innerViewportScrollLayer, + const blink::WebLayer* outerViewportScrollLayer) { + layer_tree_host_->RegisterViewportLayers( + static_cast<const WebLayerImpl*>(pageScaleLayer)->layer(), + static_cast<const WebLayerImpl*>(innerViewportScrollLayer) + ->layer(), + // The outer viewport layer will only exist when using pinch virtual + // viewports. + outerViewportScrollLayer ? static_cast<const WebLayerImpl*>( + outerViewportScrollLayer)->layer() + : NULL); +} + +void WebLayerTreeViewImplForTesting::clearViewportLayers() { + layer_tree_host_->RegisterViewportLayers(scoped_refptr<cc::Layer>(), + scoped_refptr<cc::Layer>(), + scoped_refptr<cc::Layer>()); +} + } // namespace webkit diff --git a/content/test/web_layer_tree_view_impl_for_testing.h b/content/test/web_layer_tree_view_impl_for_testing.h index 4f496bb..c5f9cf9 100644 --- a/content/test/web_layer_tree_view_impl_for_testing.h +++ b/content/test/web_layer_tree_view_impl_for_testing.h @@ -57,6 +57,11 @@ class WebLayerTreeViewImplForTesting virtual void setDeferCommits(bool defer_commits); virtual void renderingStats( blink::WebRenderingStats& stats) const; // NOLINT(runtime/references) + virtual void registerViewportLayers( + const blink::WebLayer* pageScaleLayerLayer, + const blink::WebLayer* innerViewportScrollLayer, + const blink::WebLayer* outerViewportScrollLayer) OVERRIDE; + virtual void clearViewportLayers() OVERRIDE; // cc::LayerTreeHostClient implementation. virtual void WillBeginMainFrame(int frame_id) OVERRIDE {} diff --git a/ui/gfx/transform.h b/ui/gfx/transform.h index 5e3b830..b319831 100644 --- a/ui/gfx/transform.h +++ b/ui/gfx/transform.h @@ -89,6 +89,9 @@ class GFX_EXPORT Transform { // to |this|. void Scale(SkMScalar x, SkMScalar y); void Scale3d(SkMScalar x, SkMScalar y, SkMScalar z); + gfx::Vector2dF Scale2d() const { + return gfx::Vector2dF(matrix_.get(0,0), matrix_.get(1,1)); + } // Applies the current transformation on a translation and assigns the result // to |this|. @@ -136,6 +139,11 @@ class GFX_EXPORT Transform { // translation. bool IsIdentityOrIntegerTranslation() const; + // Returns true if the matrix had only scaling components. + bool IsScale2d() const { + return !(matrix_.getType() & ~SkMatrix44::kScale_Mask); + } + // Returns true if the matrix is has only scaling and translation components. bool IsScaleOrTranslation() const { int mask = SkMatrix44::kScale_Mask | SkMatrix44::kTranslate_Mask; diff --git a/webkit/renderer/compositor_bindings/web_layer_impl.cc b/webkit/renderer/compositor_bindings/web_layer_impl.cc index 7c12480..8dd66e2 100644 --- a/webkit/renderer/compositor_bindings/web_layer_impl.cc +++ b/webkit/renderer/compositor_bindings/web_layer_impl.cc @@ -14,6 +14,7 @@ #include "cc/base/switches.h" #include "cc/layers/layer.h" #include "cc/layers/layer_position_constraint.h" +#include "cc/trees/layer_tree_host.h" #include "third_party/WebKit/public/platform/WebFloatPoint.h" #include "third_party/WebKit/public/platform/WebFloatRect.h" #include "third_party/WebKit/public/platform/WebGraphicsLayerDebugInfo.h" @@ -260,16 +261,14 @@ blink::WebPoint WebLayerImpl::scrollPosition() const { return gfx::PointAtOffsetFromOrigin(layer_->scroll_offset()); } -void WebLayerImpl::setMaxScrollPosition(WebSize max_scroll_position) { - layer_->SetMaxScrollOffset(max_scroll_position); -} - WebSize WebLayerImpl::maxScrollPosition() const { - return layer_->max_scroll_offset(); + return layer_->MaxScrollOffset(); } -void WebLayerImpl::setScrollable(bool scrollable) { - layer_->SetScrollable(scrollable); +void WebLayerImpl::setScrollClipLayer(WebLayer* clip_layer) { + cc::Layer* cc_clip_layer = + clip_layer ? static_cast<WebLayerImpl*>(clip_layer)->layer() : 0; + layer_->SetScrollClipLayer(cc_clip_layer); } bool WebLayerImpl::scrollable() const { return layer_->scrollable(); } diff --git a/webkit/renderer/compositor_bindings/web_layer_impl.h b/webkit/renderer/compositor_bindings/web_layer_impl.h index e21c2f8..c4c34ef 100644 --- a/webkit/renderer/compositor_bindings/web_layer_impl.h +++ b/webkit/renderer/compositor_bindings/web_layer_impl.h @@ -107,9 +107,8 @@ class WebLayerImpl : public blink::WebLayer, public cc::LayerClient { virtual void setForceRenderSurface(bool force); virtual void setScrollPosition(blink::WebPoint position); virtual blink::WebPoint scrollPosition() const; - virtual void setMaxScrollPosition(blink::WebSize max_position); virtual blink::WebSize maxScrollPosition() const; - virtual void setScrollable(bool scrollable); + virtual void setScrollClipLayer(blink::WebLayer* clip_layer); virtual bool scrollable() const; virtual void setUserScrollable(bool horizontal, bool vertical); virtual bool userScrollableHorizontal() const; diff --git a/webkit/renderer/compositor_bindings/web_scrollbar_layer_impl.cc b/webkit/renderer/compositor_bindings/web_scrollbar_layer_impl.cc index 265a97d..484c946 100644 --- a/webkit/renderer/compositor_bindings/web_scrollbar_layer_impl.cc +++ b/webkit/renderer/compositor_bindings/web_scrollbar_layer_impl.cc @@ -4,6 +4,7 @@ #include "webkit/renderer/compositor_bindings/web_scrollbar_layer_impl.h" +#include "cc/layers/layer.h" #include "cc/layers/painted_scrollbar_layer.h" #include "cc/layers/scrollbar_layer_interface.h" #include "cc/layers/solid_color_scrollbar_layer.h" @@ -51,8 +52,16 @@ WebScrollbarLayerImpl::~WebScrollbarLayerImpl() {} blink::WebLayer* WebScrollbarLayerImpl::layer() { return layer_.get(); } void WebScrollbarLayerImpl::setScrollLayer(blink::WebLayer* layer) { - int id = layer ? static_cast<WebLayerImpl*>(layer)->layer()->id() : 0; - static_cast<PaintedScrollbarLayer*>(layer_->layer())->SetScrollLayerId(id); + cc::Layer* scroll_layer = + layer ? static_cast<WebLayerImpl*>(layer)->layer() : 0; + layer_->layer()->ToScrollbarLayer()->SetScrollLayer(scroll_layer); +} + +void WebScrollbarLayerImpl::setClipLayer(blink::WebLayer* layer) { + cc::Layer* clip_layer = + layer ? static_cast<WebLayerImpl*>(layer)->layer() : 0; + layer_->layer()->ToScrollbarLayer() + ->SetClipLayer(clip_layer); } } // namespace webkit diff --git a/webkit/renderer/compositor_bindings/web_scrollbar_layer_impl.h b/webkit/renderer/compositor_bindings/web_scrollbar_layer_impl.h index 85d9794..a0e8d0a 100644 --- a/webkit/renderer/compositor_bindings/web_scrollbar_layer_impl.h +++ b/webkit/renderer/compositor_bindings/web_scrollbar_layer_impl.h @@ -34,6 +34,7 @@ class WebScrollbarLayerImpl : public blink::WebScrollbarLayer { // blink::WebScrollbarLayer implementation. virtual blink::WebLayer* layer(); virtual void setScrollLayer(blink::WebLayer* layer); + virtual void setClipLayer(blink::WebLayer* layer); private: scoped_ptr<WebLayerImpl> layer_; |