| 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..218ef5225895ef874838fd442365b0785d545b09 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,239 @@
|
|
|
| #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/safe_integer_conversions.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;
|
| +}
|
| +
|
| +// To achieve the desired effect to indicate vertical overscroll is occuring the
|
| +// layer tree needs to be manipulated. Specifically two clipping layers are
|
| +// inserted and the parenting of the web contents and non-client layers is
|
| +// modified. These modifications are removed when the effect is deactivated.
|
| +//
|
| +// The |frame_clipping_layer_| is used to make sure that the bits of the layers
|
| +// below do not peak out since the |browser_frame_layer| is going to be scaled
|
| +// down in size, but some of the sub-layers are going to be counter scaled. This
|
| +// clipping cannot be done in the |browser_frame_layer| since the shadows on the
|
| +// window are outside the clipping bounds, but also children of that layer.
|
| +//
|
| +// The |web_clipping_layer_| is used to trim the web contents so that is does
|
| +// not occlude the non-client elements. This is done to give the visual effect
|
| +// of the contents slide under the top elements without having to break these
|
| +// elements out into their own layer.
|
| +//
|
| +// Layout of layer tree when effect is not active:
|
| +// +----------------------------------+
|
| +// | browser_frame_layer |
|
| +// +-+--------------+---------------+-+
|
| +// | | |
|
| +// | v v
|
| +// v +-------------------+ +---------------------+
|
| +// ... | non_client_layer_ | | web_contents_layer_ |
|
| +// +-------------------+ +---------------------+
|
| +//
|
| +//
|
| +// Layout of the layer tree when effect is active:
|
| +// +---------------------+
|
| +// | browser_frame_layer |
|
| +// +-+---------------+---+
|
| +// | |
|
| +// | v
|
| +// v +-----------------------+
|
| +// ... | frame_clipping_layer_ |
|
| +// +-----+--------------+--+
|
| +// | |
|
| +// v v
|
| +// +-------------------+ +---------------------+
|
| +// | non_client_layer_ | | web_clipping_layer_ |
|
| +// +-------------------+ +---------+-----------+
|
| +// |
|
| +// v
|
| +// +---------------------+
|
| +// | web_contents_layer_ |
|
| +// +---------------------+
|
| +
|
| +ScrollEndEffectController* ScrollEndEffectController::Create(
|
| + BrowserView* view) {
|
| + return new ScrollEndEffectControllerAsh(view);
|
| }
|
|
|
| -ScrollEndEffectControllerAsh::ScrollEndEffectControllerAsh() {
|
| +ScrollEndEffectControllerAsh::ScrollEndEffectControllerAsh(BrowserView* view)
|
| + : browser_view_(view),
|
| + is_effect_active_(false),
|
| + 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;
|
| + }
|
| +
|
| + ui::Layer* browser_frame_layer = browser_view_->frame()->GetLayer();
|
| + if (!browser_frame_layer)
|
| + return;
|
| +
|
| + if (delta_y == 0 && is_effect_active_) {
|
| + 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(gfx::ToRoundedInt((bounds.height() *
|
| + kScrollEndEffectFactor)),
|
| + capped_delta_y);
|
| + } else if (capped_delta_y < 0) {
|
| + capped_delta_y = -std::min(gfx::ToRoundedInt((bounds.height() *
|
| + kScrollEndEffectFactor)),
|
| + -capped_delta_y);
|
| + }
|
| + ApplyDelta(browser_frame_layer, bounds, capped_delta_y);
|
| }
|
| +
|
| +void ScrollEndEffectControllerAsh::ActivateEffect() {
|
| + ui::Layer* browser_frame_layer = browser_view_->frame()->GetLayer();
|
| + if (!browser_frame_layer)
|
| + return;
|
| +
|
| + is_effect_active_ = true;
|
| +
|
| + // Get layers for all of the parts to be manipulated
|
| + 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_);
|
| + CHECK(non_client_layer_);
|
| +
|
| + // 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());
|
| + 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_);
|
| +}
|
| +
|
| +void ScrollEndEffectControllerAsh::DeactivateEffect() {
|
| + ui::Layer* browser_frame_layer = browser_view_->frame()->GetLayer();
|
| + if (!browser_frame_layer)
|
| + return;
|
| +
|
| + 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);
|
| +}
|
| +
|
|
|