| Index: cc/layers/layer_impl.cc
|
| diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc
|
| index 74b69b5572a953f0eb08818e153630400a69cf8e..acc8b31ab9a00433974414f76515d39d8bed897a 100644
|
| --- a/cc/layers/layer_impl.cc
|
| +++ b/cc/layers/layer_impl.cc
|
| @@ -41,7 +41,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),
|
| + clip_layer_(NULL),
|
| should_scroll_on_main_thread_(false),
|
| have_wheel_event_handlers_(false),
|
| user_scrollable_horizontal_(true),
|
| @@ -64,9 +64,7 @@ LayerImpl::LayerImpl(LayerTreeImpl* tree_impl, int id)
|
| blend_mode_(SkXfermode::kSrcOver_Mode),
|
| draw_depth_(0.f),
|
| compositing_reasons_(kCompositingReasonUnknown),
|
| - 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);
|
| @@ -360,7 +358,7 @@ void LayerImpl::SetSentScrollDelta(gfx::Vector2d sent_scroll_delta) {
|
| gfx::Vector2dF LayerImpl::ScrollBy(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);
|
| @@ -368,9 +366,14 @@ gfx::Vector2dF LayerImpl::ScrollBy(gfx::Vector2dF scroll) {
|
| gfx::Vector2dF unscrolled =
|
| ScrollDelta() + scroll - new_delta;
|
| SetScrollDelta(new_delta);
|
| +
|
| return unscrolled;
|
| }
|
|
|
| +void LayerImpl::SetScrollClipLayer(int clip_layer_id) {
|
| + clip_layer_ = layer_tree_impl()->LayerById(clip_layer_id);
|
| +}
|
| +
|
| void LayerImpl::ApplySentScrollDeltasFromAbortedCommit() {
|
| // Pending tree never has sent scroll deltas
|
| DCHECK(layer_tree_impl()->IsActiveTree());
|
| @@ -460,7 +463,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.");
|
| @@ -533,15 +537,14 @@ void LayerImpl::PushPropertiesTo(LayerImpl* layer) {
|
| layer->SetSublayerTransform(sublayer_transform_);
|
| layer->SetTransform(transform_);
|
|
|
| - layer->SetScrollable(scrollable_);
|
| + layer->SetScrollClipLayer(clip_layer_ ? 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());
|
| @@ -614,8 +617,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_);
|
| @@ -723,6 +726,7 @@ void LayerImpl::SetBounds(gfx::Size bounds) {
|
|
|
| bounds_ = bounds;
|
|
|
| + ScrollbarParametersDidChange();
|
| if (masks_to_bounds())
|
| NoteLayerPropertyChangedForSubtree();
|
| else
|
| @@ -990,44 +994,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.
|
| @@ -1038,10 +1004,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 {
|
| @@ -1057,6 +1021,8 @@ void LayerImpl::SetScrollOffsetAndDelta(gfx::Vector2d scroll_offset,
|
| gfx::Vector2dF scroll_delta) {
|
| bool changed = false;
|
|
|
| + last_scroll_offset_ = scroll_offset;
|
| +
|
| if (scroll_offset_ != scroll_offset) {
|
| changed = true;
|
| scroll_offset_ = scroll_offset;
|
| @@ -1091,7 +1057,7 @@ void LayerImpl::SetScrollOffsetAndDelta(gfx::Vector2d scroll_offset,
|
|
|
| if (changed) {
|
| NoteLayerPropertyChangedForSubtree();
|
| - UpdateScrollbarPositions();
|
| + ScrollbarParametersDidChange();
|
| }
|
| }
|
|
|
| @@ -1127,16 +1093,125 @@ void LayerImpl::DidBeginTracing() {}
|
|
|
| void LayerImpl::DidLoseOutputSurface() {}
|
|
|
| -void LayerImpl::SetMaxScrollOffset(gfx::Vector2d max_scroll_offset) {
|
| - if (max_scroll_offset_ == max_scroll_offset)
|
| - return;
|
| - max_scroll_offset_ = max_scroll_offset;
|
| +gfx::Vector2d LayerImpl::MaxScrollOffset() const {
|
| + if (!clip_layer_)
|
| + return gfx::Vector2d();
|
| +
|
| + gfx::Size scaled_scroll_bounds(bounds());
|
| + LayerImpl const* current_layer = this->parent();
|
| + LayerImpl const* page_scale_layer = layer_tree_impl()->page_scale_layer();
|
| + DCHECK(this != page_scale_layer);
|
| + DCHECK(clip_layer_);
|
| + float scale_factor = 1.f;
|
| + while (current_layer && current_layer != clip_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.IsScale());
|
| + gfx::Vector2dF layer_scale = layer_transform.Scale();
|
| + // TODO(wjmaclean) Allow for non-isotropic scales.
|
| + DCHECK(layer_scale.x() == layer_scale.y());
|
| + current_layer_scale = layer_scale.x();
|
| + }
|
|
|
| - if (scroll_offset_delegate_)
|
| - scroll_offset_delegate_->SetMaxScrollOffset(max_scroll_offset_);
|
| + scale_factor *= current_layer_scale;
|
| + current_layer = current_layer->parent();
|
| + }
|
| + DCHECK(current_layer == clip_layer_);
|
| +
|
| + scaled_scroll_bounds.SetSize(
|
| + scale_factor * scaled_scroll_bounds.width(),
|
| + scale_factor * scaled_scroll_bounds.height());
|
| +
|
| + gfx::Vector2dF max_offset(
|
| + scaled_scroll_bounds.width() - clip_layer_->bounds().width(),
|
| + scaled_scroll_bounds.height() - clip_layer_->bounds().height());
|
| + // We need the final scroll offset to be in CSS coords.
|
| + max_offset.Scale(1 / scale_factor);
|
| + return gfx::Vector2d(max_offset.x(), max_offset.y());
|
| +}
|
| +
|
| +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);
|
| + gfx::RectF clip_rect(gfx::PointF(), scrollbar_clip_layer->bounds());
|
| + if (scrollbar_clip_layer == layer_tree_impl()->InnerViewportScrollLayer())
|
| + clip_rect =
|
| + gfx::RectF(gfx::PointF(), layer_tree_impl()->ScrollableViewportSize());
|
| + gfx::RectF scroll_rect(gfx::PointF(), bounds());
|
| +
|
| + gfx::Vector2dF current_offset = scroll_offset() + ScrollDelta();
|
| +
|
| + // TODO(wjmaclean) This computation is nearly identical to the one in
|
| + // MaxScrollOffset. Find some way to combine these.
|
| + LayerImpl const* current_layer = this->parent();
|
| + float scale_factor = 1.f;
|
| + while (current_layer && current_layer != scrollbar_clip_layer) {
|
| + const gfx::Transform& layer_transform = current_layer->transform();
|
| + if (current_layer == page_scale_layer) {
|
| + DCHECK(layer_transform.IsIdentity());
|
| + scale_factor = layer_tree_impl()->total_page_scale_factor();
|
| + current_offset.Scale(scale_factor);
|
| + scroll_rect.Scale(scale_factor);
|
| + } else {
|
| + DCHECK(layer_transform.IsScale());
|
| + gfx::Vector2dF layer_scale = layer_transform.Scale();
|
| + 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;
|
| + }
|
| + current_layer = current_layer->parent();
|
| + }
|
| + DCHECK(current_layer == scrollbar_clip_layer);
|
| +
|
| + 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();
|
| + // 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() {
|
| @@ -1145,8 +1220,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;
|
| @@ -1179,18 +1253,50 @@ void LayerImpl::DidBecomeActive() {
|
| break;
|
| }
|
| }
|
| -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);
|
| + if (!scrollbars_)
|
| + scrollbars_.reset(new ScrollbarSet());
|
| +
|
| + scrollbars_->insert(layer);
|
| +}
|
| +
|
| +void LayerImpl::RemoveScrollbar(ScrollbarLayerImplBase* layer) {
|
| + DCHECK(scrollbars_);
|
| + DCHECK(layer);
|
| +
|
| + 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();
|
| }
|
|
|
| static scoped_ptr<base::Value>
|
|
|