Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4374)

Unified Diff: chrome/browser/ui/views/frame/scroll_end_effect_controller_ash.cc

Issue 22265009: Implement initial version of scroll end effect Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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);
+}
+

Powered by Google App Engine
This is Rietveld 408576698