190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// found in the LICENSE file.
490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "content/browser/android/edge_effect.h"
690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "cc/layers/layer.h"
86e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "cc/layers/ui_resource_layer.h"
96e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "ui/base/android/system_ui_resource_manager.h"
1090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace content {
1290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace {
1490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Time it will take the effect to fully recede in ms
1603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)const int kRecedeTimeMs = 1000;
1790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Time it will take before a pulled glow begins receding in ms
1903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)const int kPullTimeMs = 167;
2090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Time it will take in ms for a pulled glow to decay before release
2203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)const int kPullDecayTimeMs = 1000;
2390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const float kMaxAlpha = 1.f;
2590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const float kHeldEdgeScaleY = .5f;
2690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const float kMaxGlowHeight = 4.f;
2890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const float kPullGlowBegin = 1.f;
3090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const float kPullEdgeBegin = 0.6f;
3190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
328bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// Min/max velocity that will be absorbed
3390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const float kMinVelocity = 100.f;
348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)const float kMaxVelocity = 10000.f;
3590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const float kEpsilon = 0.001f;
3790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)const float kGlowHeightWidthRatio = 0.25f;
39a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
4090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// How much dragging should effect the height of the edge image.
4190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Number determined by user testing.
4290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const int kPullDistanceEdgeFactor = 7;
4390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
4490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// How much dragging should effect the height of the glow image.
4590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Number determined by user testing.
4690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const int kPullDistanceGlowFactor = 7;
4790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const float kPullDistanceAlphaGlowFactor = 1.1f;
4890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
4990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const int kVelocityEdgeFactor = 8;
508bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)const int kVelocityGlowFactor = 12;
5190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)const float kEdgeHeightAtMdpi = 12.f;
5303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)const float kGlowHeightAtMdpi = 128.f;
5403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
5590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)template <typename T>
5690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)T Lerp(T a, T b, T t) {
5790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return a + (b - a) * t;
5890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
5990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
6090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)template <typename T>
6190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)T Clamp(T value, T low, T high) {
6203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return value < low ? low : (value > high ? high : value);
6390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
6490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
6590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)template <typename T>
6690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)T Damp(T input, T factor) {
6790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  T result;
6890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (factor == 1) {
6990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    result = 1 - (1 - input) * (1 - input);
7090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  } else {
7190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    result = 1 - std::pow(1 - input, 2 * factor);
7290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
7390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return result;
7490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
7590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}  // namespace
7790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)class EdgeEffect::EffectLayer {
796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) public:
806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  EffectLayer(ui::SystemUIResourceManager::ResourceType resource_type,
816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)              ui::SystemUIResourceManager* resource_manager)
826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      : ui_resource_layer_(cc::UIResourceLayer::Create()),
836e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        resource_type_(resource_type),
846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        resource_manager_(resource_manager) {}
856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
866e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  ~EffectLayer() { ui_resource_layer_->RemoveFromParent(); }
876e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  void SetParent(cc::Layer* parent) {
896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (ui_resource_layer_->parent() != parent)
906e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      parent->AddChild(ui_resource_layer_);
916e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    ui_resource_layer_->SetUIResourceId(
926e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        resource_manager_->GetUIResourceId(resource_type_));
936e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
946e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
956e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  void Disable() { ui_resource_layer_->SetIsDrawable(false); }
966e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
9703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  void Update(const gfx::Size& size,
9803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)              const gfx::Transform& transform,
996e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)              float opacity) {
1006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    ui_resource_layer_->SetUIResourceId(
1016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        resource_manager_->GetUIResourceId(resource_type_));
1026e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    ui_resource_layer_->SetIsDrawable(true);
1036e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    ui_resource_layer_->SetTransformOrigin(
10403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        gfx::Point3F(size.width() * 0.5f, 0, 0));
10503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    ui_resource_layer_->SetTransform(transform);
10603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    ui_resource_layer_->SetBounds(size);
1076e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    ui_resource_layer_->SetOpacity(Clamp(opacity, 0.f, 1.f));
1086e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
10990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  scoped_refptr<cc::UIResourceLayer> ui_resource_layer_;
1116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  ui::SystemUIResourceManager::ResourceType resource_type_;
1126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  ui::SystemUIResourceManager* resource_manager_;
1136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(EffectLayer);
1156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)};
1166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
11703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)EdgeEffect::EdgeEffect(ui::SystemUIResourceManager* resource_manager,
11803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                       float device_scale_factor)
1196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    : edge_(new EffectLayer(ui::SystemUIResourceManager::OVERSCROLL_EDGE,
1206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                            resource_manager)),
1216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      glow_(new EffectLayer(ui::SystemUIResourceManager::OVERSCROLL_GLOW,
1226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                            resource_manager)),
12303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      base_edge_height_(kEdgeHeightAtMdpi * device_scale_factor),
12403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      base_glow_height_(kGlowHeightAtMdpi * device_scale_factor),
1256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      edge_alpha_(0),
1266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      edge_scale_y_(0),
1276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      glow_alpha_(0),
1286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      glow_scale_y_(0),
1296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      edge_alpha_start_(0),
1306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      edge_alpha_finish_(0),
1316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      edge_scale_y_start_(0),
1326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      edge_scale_y_finish_(0),
1336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      glow_alpha_start_(0),
1346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      glow_alpha_finish_(0),
1356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      glow_scale_y_start_(0),
1366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      glow_scale_y_finish_(0),
1376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      state_(STATE_IDLE),
1386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      pull_distance_(0) {
13990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
14090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
14103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)EdgeEffect::~EdgeEffect() {
14203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
14390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
14490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool EdgeEffect::IsFinished() const {
14590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return state_ == STATE_IDLE;
14690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
14790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
14890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void EdgeEffect::Finish() {
1496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  edge_->Disable();
1506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  glow_->Disable();
15190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  pull_distance_ = 0;
15290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  state_ = STATE_IDLE;
15390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
15490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
15503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void EdgeEffect::Pull(base::TimeTicks current_time,
15603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                      float delta_distance,
15703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                      float displacement) {
15890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (state_ == STATE_PULL_DECAY && current_time - start_time_ < duration_) {
15990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return;
16090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
16190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (state_ != STATE_PULL) {
16290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    glow_scale_y_ = kPullGlowBegin;
16390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
16490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  state_ = STATE_PULL;
16590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
16690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  start_time_ = current_time;
16703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  duration_ = base::TimeDelta::FromMilliseconds(kPullTimeMs);
16890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
16990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  float abs_delta_distance = std::abs(delta_distance);
17090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  pull_distance_ += delta_distance;
17190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  float distance = std::abs(pull_distance_);
17290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
17390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  edge_alpha_ = edge_alpha_start_ = Clamp(distance, kPullEdgeBegin, kMaxAlpha);
17403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  edge_scale_y_ = edge_scale_y_start_ =
17503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      Clamp(distance * kPullDistanceEdgeFactor, kHeldEdgeScaleY, 1.f);
17690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
17790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  glow_alpha_ = glow_alpha_start_ =
17890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      std::min(kMaxAlpha,
17990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)               glow_alpha_ + abs_delta_distance * kPullDistanceAlphaGlowFactor);
18090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
18190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  float glow_change = abs_delta_distance;
18290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (delta_distance > 0 && pull_distance_ < 0)
18390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    glow_change = -glow_change;
18490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (pull_distance_ == 0)
18590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    glow_scale_y_ = 0;
18690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
18790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Do not allow glow to get larger than kMaxGlowHeight.
18890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  glow_scale_y_ = glow_scale_y_start_ =
18990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      Clamp(glow_scale_y_ + glow_change * kPullDistanceGlowFactor,
19003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)            0.f,
19103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)            kMaxGlowHeight);
19290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
19390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  edge_alpha_finish_ = edge_alpha_;
19490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  edge_scale_y_finish_ = edge_scale_y_;
19590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  glow_alpha_finish_ = glow_alpha_;
19690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  glow_scale_y_finish_ = glow_scale_y_;
19790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
19890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
19990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void EdgeEffect::Release(base::TimeTicks current_time) {
20090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  pull_distance_ = 0;
20190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
20290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (state_ != STATE_PULL && state_ != STATE_PULL_DECAY)
20390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return;
20490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
20590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  state_ = STATE_RECEDE;
20690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  edge_alpha_start_ = edge_alpha_;
20790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  edge_scale_y_start_ = edge_scale_y_;
20890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  glow_alpha_start_ = glow_alpha_;
20990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  glow_scale_y_start_ = glow_scale_y_;
21090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
21190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  edge_alpha_finish_ = 0.f;
21290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  edge_scale_y_finish_ = 0.f;
21390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  glow_alpha_finish_ = 0.f;
21490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  glow_scale_y_finish_ = 0.f;
21590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
21690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  start_time_ = current_time;
21703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  duration_ = base::TimeDelta::FromMilliseconds(kRecedeTimeMs);
21890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
21990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
22090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void EdgeEffect::Absorb(base::TimeTicks current_time, float velocity) {
22190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  state_ = STATE_ABSORB;
222a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  velocity = Clamp(std::abs(velocity), kMinVelocity, kMaxVelocity);
22390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
22490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  start_time_ = current_time;
22590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // This should never be less than 1 millisecond.
2268bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  duration_ = base::TimeDelta::FromMilliseconds(0.15f + (velocity * 0.02f));
22790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
22890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // The edge should always be at least partially visible, regardless
22990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // of velocity.
23090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  edge_alpha_start_ = 0.f;
23190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  edge_scale_y_ = edge_scale_y_start_ = 0.f;
23290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // The glow depends more on the velocity, and therefore starts out
23390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // nearly invisible.
2348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  glow_alpha_start_ = 0.3f;
23590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  glow_scale_y_start_ = 0.f;
23690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
23790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Factor the velocity by 8. Testing on device shows this works best to
23890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // reflect the strength of the user's scrolling.
239a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  edge_alpha_finish_ = Clamp(velocity * kVelocityEdgeFactor, 0.f, 1.f);
24090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Edge should never get larger than the size of its asset.
24103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  edge_scale_y_finish_ =
24203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      Clamp(velocity * kVelocityEdgeFactor, kHeldEdgeScaleY, 1.f);
24390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
24490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Growth for the size of the glow should be quadratic to properly
24590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // respond
24690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // to a user's scrolling speed. The faster the scrolling speed, the more
24790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // intense the effect should be for both the size and the saturation.
24803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  glow_scale_y_finish_ =
24903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      std::min(0.025f + (velocity * (velocity / 100) * 0.00015f), 1.75f);
25090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Alpha should change for the glow as well as size.
25103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  glow_alpha_finish_ = Clamp(
25203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      glow_alpha_start_, velocity * kVelocityGlowFactor * .00001f, kMaxAlpha);
25390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
25490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
25590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool EdgeEffect::Update(base::TimeTicks current_time) {
25690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (IsFinished())
25790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return false;
25890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
25990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  const double dt = (current_time - start_time_).InMilliseconds();
26090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  const double t = std::min(dt / duration_.InMilliseconds(), 1.);
26190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  const float interp = static_cast<float>(Damp(t, 1.));
26290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
26390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  edge_alpha_ = Lerp(edge_alpha_start_, edge_alpha_finish_, interp);
26490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  edge_scale_y_ = Lerp(edge_scale_y_start_, edge_scale_y_finish_, interp);
26590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  glow_alpha_ = Lerp(glow_alpha_start_, glow_alpha_finish_, interp);
26690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  glow_scale_y_ = Lerp(glow_scale_y_start_, glow_scale_y_finish_, interp);
26790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
26890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (t >= 1.f - kEpsilon) {
26990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    switch (state_) {
27090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      case STATE_ABSORB:
27190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        state_ = STATE_RECEDE;
27290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        start_time_ = current_time;
27303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        duration_ = base::TimeDelta::FromMilliseconds(kRecedeTimeMs);
27490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
27590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        edge_alpha_start_ = edge_alpha_;
27690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        edge_scale_y_start_ = edge_scale_y_;
27790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        glow_alpha_start_ = glow_alpha_;
27890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        glow_scale_y_start_ = glow_scale_y_;
27990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
28090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // After absorb, the glow and edge should fade to nothing.
28190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        edge_alpha_finish_ = 0.f;
28290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        edge_scale_y_finish_ = 0.f;
28390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        glow_alpha_finish_ = 0.f;
28490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        glow_scale_y_finish_ = 0.f;
28590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        break;
28690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      case STATE_PULL:
28790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        state_ = STATE_PULL_DECAY;
28890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        start_time_ = current_time;
28903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        duration_ = base::TimeDelta::FromMilliseconds(kPullDecayTimeMs);
29090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
29190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        edge_alpha_start_ = edge_alpha_;
29290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        edge_scale_y_start_ = edge_scale_y_;
29390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        glow_alpha_start_ = glow_alpha_;
29490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        glow_scale_y_start_ = glow_scale_y_;
29590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
29690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // After pull, the glow and edge should fade to nothing.
29790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        edge_alpha_finish_ = 0.f;
29890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        edge_scale_y_finish_ = 0.f;
29990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        glow_alpha_finish_ = 0.f;
30090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        glow_scale_y_finish_ = 0.f;
30190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        break;
302a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      case STATE_PULL_DECAY: {
303a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        // When receding, we want edge to decrease more slowly
304a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        // than the glow.
30503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        const float factor =
30603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)            glow_scale_y_finish_
30703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                ? 1 / (glow_scale_y_finish_ * glow_scale_y_finish_)
30803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                : std::numeric_limits<float>::max();
30903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        edge_scale_y_ =
31003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)            edge_scale_y_start_ +
311a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch            (edge_scale_y_finish_ - edge_scale_y_start_) * interp * factor;
312a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        state_ = STATE_RECEDE;
313a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      } break;
31490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      case STATE_RECEDE:
31590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        Finish();
31690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        break;
31790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      default:
31890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        break;
31990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
32090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
32190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
32290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (state_ == STATE_RECEDE && glow_scale_y_ <= 0 && edge_scale_y_ <= 0)
32390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    Finish();
32490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
32590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return !IsFinished();
32690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
32790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
32803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void EdgeEffect::ApplyToLayers(const gfx::SizeF& size,
32903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                               const gfx::Transform& transform) {
33090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (IsFinished())
33190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return;
33290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
333a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // An empty window size, while meaningless, is also relatively harmless, and
33490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // will simply prevent any drawing of the layers.
33503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (size.IsEmpty()) {
3366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    edge_->Disable();
3376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    glow_->Disable();
33890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return;
33990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
34090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
34190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Glow
342a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  const int scaled_glow_height = static_cast<int>(
34303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      std::min(base_glow_height_ * glow_scale_y_ * kGlowHeightWidthRatio * 0.6f,
34403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)               base_glow_height_ * kMaxGlowHeight) +
34503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      0.5f);
34603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  const gfx::Size glow_size(size.width(), scaled_glow_height);
34703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  glow_->Update(glow_size, transform, glow_alpha_);
34890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
34990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Edge
35003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  const int scaled_edge_height =
35103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      static_cast<int>(base_edge_height_ * edge_scale_y_);
35203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  const gfx::Size edge_size(size.width(), scaled_edge_height);
35303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  edge_->Update(edge_size, transform, edge_alpha_);
3546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
3556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
3566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void EdgeEffect::SetParent(cc::Layer* parent) {
3576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  edge_->SetParent(parent);
3586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  glow_->SetParent(parent);
3596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
3606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
3616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// static
3626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void EdgeEffect::PreloadResources(
3636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    ui::SystemUIResourceManager* resource_manager) {
3646e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  DCHECK(resource_manager);
3656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  resource_manager->PreloadResource(
3666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      ui::SystemUIResourceManager::OVERSCROLL_EDGE);
3676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  resource_manager->PreloadResource(
3686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      ui::SystemUIResourceManager::OVERSCROLL_GLOW);
36990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
37090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
37103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}  // namespace content
372