| Index: cc/layers/layer_impl.cc
|
| diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc
|
| index 42338e0b8197fb17f8b9b242d9243a16c534f7e0..e21cc13e29422256bdb597a456ea2cae5b08dbf1 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(const 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,150 @@ 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 +1286,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 +1320,53 @@ 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() {
|
|
|