Chromium Code Reviews| Index: chrome/browser/ui/views/frame/scroll_end_effect_controller_ash.cc |
| diff --git a/chrome/browser/ui/views/frame/scroll_end_effect_controller_ash.cc b/chrome/browser/ui/views/frame/scroll_end_effect_controller_ash.cc |
| index aa0642821e61bc5cfe4d5932bf978aca44f60377..a0ea0d2db4bd3777ca8d283ade8490b9d3cf5e56 100644 |
| --- a/chrome/browser/ui/views/frame/scroll_end_effect_controller_ash.cc |
| +++ b/chrome/browser/ui/views/frame/scroll_end_effect_controller_ash.cc |
| @@ -4,16 +4,183 @@ |
| #include "chrome/browser/ui/views/frame/scroll_end_effect_controller_ash.h" |
| -ScrollEndEffectController* ScrollEndEffectController::Create() { |
| - return new ScrollEndEffectControllerAsh(); |
| +#include "chrome/browser/ui/views/frame/browser_frame.h" |
| +#include "chrome/browser/ui/views/frame/browser_view.h" |
| +#include "content/public/browser/web_contents.h" |
| +#include "content/public/browser/web_contents_view.h" |
| +#include "ui/aura/window.h" |
| +#include "ui/compositor/layer_type.h" |
| +#include "ui/gfx/rect.h" |
| +#include "ui/gfx/transform.h" |
| + |
| +namespace { |
| +// This factor is used to control how much translation is applied relative to |
| +// the size of the window. Specifically translation is limited to a max of |
| +// window_size * factor. |
| +const float kScrollEndEffectFactor = 0.10; |
| +} |
| + |
| +ScrollEndEffectController* ScrollEndEffectController::Create( |
| + BrowserView* view) { |
| + return new ScrollEndEffectControllerAsh(view); |
| } |
| -ScrollEndEffectControllerAsh::ScrollEndEffectControllerAsh() { |
| +ScrollEndEffectControllerAsh::ScrollEndEffectControllerAsh(BrowserView* view) |
| + : browser_view_(view), |
| + is_effect_active_(false), |
| + browser_frame_layer_(NULL), |
| + web_contents_layer_(NULL), |
| + non_client_layer_(NULL), |
| + web_contents_parent_(NULL), |
| + non_client_view_(NULL) { |
| } |
| ScrollEndEffectControllerAsh::~ScrollEndEffectControllerAsh() { |
| } |
| void ScrollEndEffectControllerAsh::OverscrollUpdate(int delta_y) { |
| - // TODO(rharrison): Implement initial version of scroll end effect |
| + if (browser_view_ == NULL || browser_view_->frame() == NULL) { |
| + return; |
| + } |
| + |
| + if (delta_y == 0 && is_effect_active_) { |
| + if (browser_frame_layer_) { |
| + ApplyDelta(browser_frame_layer_, browser_frame_layer_->bounds(), 0); |
| + DeactivateEffect(); |
| + } |
| + return; |
| + } |
| + |
| + if (!is_effect_active_) |
| + ActivateEffect(); |
| + |
| + int capped_delta_y = delta_y; |
| + gfx::Rect bounds = browser_frame_layer_->bounds(); |
| + // Limiting the delta size being a proportion of the frame bounds size. |
| + if (capped_delta_y > 0) { |
| + capped_delta_y = std::min(static_cast<int>(roundf(bounds.height() * |
| + kScrollEndEffectFactor)), |
| + capped_delta_y); |
| + } else if (capped_delta_y < 0) { |
| + capped_delta_y = -std::min(static_cast<int>(roundf(bounds.height() * |
| + kScrollEndEffectFactor)), |
| + -capped_delta_y); |
| + } |
| + ApplyDelta(browser_frame_layer_, bounds, capped_delta_y); |
| +} |
| + |
| +void ScrollEndEffectControllerAsh::ActivateEffect() { |
| + is_effect_active_ = true; |
| + |
| + // Get layers for all of the parts to be manipulated |
| + browser_frame_layer_ = browser_view_->frame()->GetLayer(); |
| + web_contents_layer_ = browser_view_-> GetActiveWebContents()->GetView()-> |
| + GetNativeView()->layer(); |
| + non_client_view_ = browser_view_->frame()->GetContentsView(); |
| + non_client_view_->SetPaintToLayer(true); |
| + non_client_layer_ = non_client_view_->layer(); |
| + non_client_layer_->SetFillsBoundsOpaquely(false); |
| + // non_client_layer_->SetOpacity(0.5); |
| + |
| + CHECK(web_contents_layer_ != NULL); |
|
sadrul
2013/08/20 16:14:59
CHECK(web_contents_layer_), or CHECK_NE
rharrison
2013/08/20 19:57:41
Done.
|
| + CHECK(non_client_layer_ != NULL); |
| + |
| + // Setup clipping layers |
| + frame_clipping_layer_.reset(new ui::Layer(ui::LAYER_NOT_DRAWN)); |
| + frame_clipping_layer_->set_name("OverscrollFrameClippingLayer"); |
| + frame_clipping_layer_->SetMasksToBounds(true); |
| + gfx::Rect frame_clipping_bounds = browser_frame_layer_->bounds(); |
| + frame_clipping_bounds.set_origin(gfx::Point(0,0)); |
|
sadrul
2013/08/20 16:14:59
gfx::Point()
rharrison
2013/08/20 19:57:41
Done.
|
| + frame_clipping_layer_->SetBounds(frame_clipping_bounds); |
| + |
| + web_clipping_layer_.reset(new ui::Layer(ui::LAYER_NOT_DRAWN)); |
| + web_clipping_layer_->set_name("OverscrollWebClippingLayer"); |
| + web_clipping_layer_->SetMasksToBounds(true); |
| + gfx::Rect web_clipping_bounds = browser_frame_layer_->bounds(); |
| + non_content_height_ = browser_frame_layer_->bounds().height() - |
| + web_contents_layer_->bounds().height(); |
| + web_clipping_bounds.set_height(browser_frame_layer_->bounds().height() - |
| + non_content_height_); |
| + web_clipping_bounds.set_origin(gfx::Point(0, non_content_height_)); |
| + web_clipping_layer_->SetBounds(web_clipping_bounds); |
| + |
| + // Move the web contents since bounds are relative to the parent layer |
| + gfx::Rect web_contents_bounds = web_clipping_bounds; |
| + web_contents_parent_ = web_contents_layer_->parent(); |
| + web_contents_bounds.set_origin(gfx::Point(0, 0)); |
| + web_contents_bounds_ = web_contents_layer_->bounds(); |
| + web_contents_layer_->SetBounds(web_contents_bounds); |
| + |
| + // Adjust the toplogy of the layer tree to add clipping layers |
| + browser_frame_layer_->Add(frame_clipping_layer_.get()); |
| + frame_clipping_layer_->Add(non_client_layer_); |
| + frame_clipping_layer_->Add(web_clipping_layer_.get()); |
| + web_clipping_layer_->Add(web_contents_layer_); |
|
sadrul
2013/08/20 16:14:59
I think this looks reasonable. Two notes:
* Is it
rharrison
2013/08/20 19:57:41
Done.
|
| } |
| + |
| +void ScrollEndEffectControllerAsh::DeactivateEffect() { |
| + is_effect_active_ = false; |
| + |
| + web_contents_layer_->SetBounds(web_contents_bounds_); |
| + web_contents_parent_->Add(web_contents_layer_); |
| + web_contents_parent_ = NULL; |
| + web_contents_layer_ = NULL; |
| + |
| + frame_clipping_layer_->Remove(non_client_layer_); |
| + non_client_view_->SetPaintToLayer(false); |
| + non_client_layer_ = NULL; |
| + non_client_view_ = NULL; |
| + |
| + frame_clipping_layer_->Remove(web_clipping_layer_.get()); |
| + web_clipping_layer_.reset(); |
| + browser_frame_layer_->Remove(frame_clipping_layer_.get()); |
| + frame_clipping_layer_.reset(); |
| + browser_frame_layer_ = NULL; |
| +} |
| + |
| +void ScrollEndEffectControllerAsh::ApplyDelta(ui::Layer* frame, |
| + gfx::Rect bounds, |
| + int delta_y) { |
| + float scale_factor = std::abs(delta_y); |
| + scale_factor /= bounds.height(); |
| + scale_factor = 1 - scale_factor; |
| + |
| + gfx::Transform frame_transform; |
| + if (delta_y > 0) { |
| + frame_transform.Translate(0, delta_y); |
| + frame_transform.Scale(1, scale_factor); |
| + } else { |
| + frame_transform.Scale(1, scale_factor); |
| + } |
| + gfx::Transform counter_transform; |
| + CHECK(frame_transform.GetInverse(&counter_transform)); |
| + frame->SetTransform(frame_transform); |
| + |
| + // Ensure that we apply the counter translation about origin of the web |
| + // contents |
| + gfx::Transform web_to_frame_transform; |
| + web_to_frame_transform.Translate(0, -non_content_height_); |
| + gfx::Transform frame_to_web_transform; |
| + frame_to_web_transform.Translate(0, non_content_height_); |
| + gfx::Transform web_clipping_transform = counter_transform; |
| + web_clipping_transform.ConcatTransform(web_to_frame_transform); |
| + web_clipping_transform.PreconcatTransform(frame_to_web_transform); |
| + |
| + if (delta_y >= 0) { |
| + web_clipping_transform.Translate(0, delta_y); |
| + } |
| + web_clipping_layer_->SetTransform(web_clipping_transform); |
| + |
| + if (delta_y <= 0) { |
| + gfx::Transform web_contents_transform; |
| + web_contents_transform.Translate(0, delta_y); |
| + web_contents_layer_->SetTransform(web_contents_transform); |
| + } |
| + |
| + gfx::Transform non_client_transform = counter_transform; |
| + if (delta_y >= 0) { |
| + non_client_transform.Translate(0, delta_y); |
| + } |
| + non_client_layer_->SetTransform(non_client_transform); |
| +} |
| + |