edge_effect.cc revision a02191e04bc25c4935f804f2c080ae28663d096d
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"
890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace content {
1090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace {
1290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)enum State {
1490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  STATE_IDLE = 0,
1590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  STATE_PULL,
1690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  STATE_ABSORB,
1790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  STATE_RECEDE,
1890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  STATE_PULL_DECAY
1990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)};
2090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Time it will take the effect to fully recede in ms
2290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const int kRecedeTime = 1000;
2390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Time it will take before a pulled glow begins receding in ms
2590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const int kPullTime = 167;
2690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Time it will take in ms for a pulled glow to decay before release
2890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const int kPullDecayTime = 1000;
2990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const float kMaxAlpha = 1.f;
3190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const float kHeldEdgeScaleY = .5f;
3290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const float kMaxGlowHeight = 4.f;
3490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const float kPullGlowBegin = 1.f;
3690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const float kPullEdgeBegin = 0.6f;
3790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
388bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// Min/max velocity that will be absorbed
3990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const float kMinVelocity = 100.f;
408bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)const float kMaxVelocity = 10000.f;
4190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
4290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const float kEpsilon = 0.001f;
4390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
44a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochconst float kGlowHeightToWidthRatio = 0.25f;
45a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
4690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// How much dragging should effect the height of the edge image.
4790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Number determined by user testing.
4890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const int kPullDistanceEdgeFactor = 7;
4990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// How much dragging should effect the height of the glow image.
5190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Number determined by user testing.
5290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const int kPullDistanceGlowFactor = 7;
5390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const float kPullDistanceAlphaGlowFactor = 1.1f;
5490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const int kVelocityEdgeFactor = 8;
568bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)const int kVelocityGlowFactor = 12;
5790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)template <typename T>
5990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)T Lerp(T a, T b, T t) {
6090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return a + (b - a) * t;
6190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
6290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
6390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)template <typename T>
6490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)T Clamp(T value, T low, T high) {
6590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)   return value < low ? low : (value > high ? high : value);
6690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
6790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
6890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)template <typename T>
6990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)T Damp(T input, T factor) {
7090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  T result;
7190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (factor == 1) {
7290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    result = 1 - (1 - input) * (1 - input);
7390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  } else {
7490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    result = 1 - std::pow(1 - input, 2 * factor);
7590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
7690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return result;
7790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
7890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
7990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)gfx::Transform ComputeTransform(EdgeEffect::Edge edge,
80a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                                const gfx::SizeF& window_size,
81a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                                int offset,
82a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                                int height) {
83a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // Edge effects that require rotation are translated to the center about which
84a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // the layer should be rotated to align with the corresponding edge.
8590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  switch (edge) {
8690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    case EdgeEffect::EDGE_TOP:
87a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      return gfx::Transform(1, 0, 0, 1, 0, offset);
8890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    case EdgeEffect::EDGE_LEFT:
8990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return gfx::Transform(0, 1, -1, 0,
90a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                            (-window_size.height() + height) / 2.f + offset,
91a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                            (window_size.height() - height) / 2.f);
9290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    case EdgeEffect::EDGE_BOTTOM:
93a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      return gfx::Transform(-1, 0, 0, -1,
94a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                            0, window_size.height() - height + offset);
9590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    case EdgeEffect::EDGE_RIGHT:
9690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return gfx::Transform(0, -1, 1, 0,
97a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch          (-window_size.height() - height) / 2.f + window_size.width() + offset,
98a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch          (window_size.height() - height) / 2.f);
99a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    default:
100a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      NOTREACHED() << "Invalid edge: " << edge;
101a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      return gfx::Transform();
102a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  };
103a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}
104a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
105a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochgfx::Size ComputeBounds(EdgeEffect::Edge edge,
106a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                        const gfx::SizeF& window_size,
107a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                        int height) {
108a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  switch (edge) {
109a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    case EdgeEffect::EDGE_TOP:
110a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    case EdgeEffect::EDGE_BOTTOM:
111a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      return gfx::Size(window_size.width(), height);
112a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    case EdgeEffect::EDGE_LEFT:
113a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    case EdgeEffect::EDGE_RIGHT:
114a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      return gfx::Size(window_size.height(), height);
115a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    default:
116a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      NOTREACHED() << "Invalid edge: " << edge;
117a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      return gfx::Size();
11890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  };
11990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
12090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
12190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void DisableLayer(cc::Layer* layer) {
12290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(layer);
12390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  layer->SetIsDrawable(false);
12490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  layer->SetTransform(gfx::Transform());
12590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  layer->SetOpacity(1.f);
12690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
12790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
12890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void UpdateLayer(cc::Layer* layer,
12990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                 EdgeEffect::Edge edge,
130a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                 const gfx::SizeF& window_size,
131a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                 int offset,
13290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                 int height,
13390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                 float opacity) {
13490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(layer);
13590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  layer->SetIsDrawable(true);
136a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  layer->SetTransform(ComputeTransform(edge, window_size, offset, height));
137a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  layer->SetBounds(ComputeBounds(edge, window_size, height));
13890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  layer->SetOpacity(Clamp(opacity, 0.f, 1.f));
13990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
14090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
14190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} // namespace
14290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
14390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)EdgeEffect::EdgeEffect(scoped_refptr<cc::Layer> edge,
14490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                       scoped_refptr<cc::Layer> glow)
14590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  : edge_(edge)
14690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  , glow_(glow)
14790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  , edge_alpha_(0)
14890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  , edge_scale_y_(0)
14990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  , glow_alpha_(0)
15090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  , glow_scale_y_(0)
15190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  , edge_alpha_start_(0)
15290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  , edge_alpha_finish_(0)
15390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  , edge_scale_y_start_(0)
15490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  , edge_scale_y_finish_(0)
15590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  , glow_alpha_start_(0)
15690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  , glow_alpha_finish_(0)
15790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  , glow_scale_y_start_(0)
15890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  , glow_scale_y_finish_(0)
15990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  , state_(STATE_IDLE)
160a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  , pull_distance_(0) {
16190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Prevent the provided layers from drawing until the effect is activated.
1627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  DisableLayer(edge_.get());
1637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  DisableLayer(glow_.get());
16490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
16590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
16690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)EdgeEffect::~EdgeEffect() { }
16790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
16890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool EdgeEffect::IsFinished() const {
16990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return state_ == STATE_IDLE;
17090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
17190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
17290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void EdgeEffect::Finish() {
1737d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  DisableLayer(edge_.get());
1747d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  DisableLayer(glow_.get());
17590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  pull_distance_ = 0;
17690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  state_ = STATE_IDLE;
17790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
17890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
17990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void EdgeEffect::Pull(base::TimeTicks current_time, float delta_distance) {
18090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (state_ == STATE_PULL_DECAY && current_time - start_time_ < duration_) {
18190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return;
18290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
18390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (state_ != STATE_PULL) {
18490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    glow_scale_y_ = kPullGlowBegin;
18590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
18690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  state_ = STATE_PULL;
18790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
18890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  start_time_ = current_time;
18990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  duration_ = base::TimeDelta::FromMilliseconds(kPullTime);
19090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
19190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  float abs_delta_distance = std::abs(delta_distance);
19290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  pull_distance_ += delta_distance;
19390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  float distance = std::abs(pull_distance_);
19490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
19590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  edge_alpha_ = edge_alpha_start_ = Clamp(distance, kPullEdgeBegin, kMaxAlpha);
19690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  edge_scale_y_ = edge_scale_y_start_
19790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      = Clamp(distance * kPullDistanceEdgeFactor, kHeldEdgeScaleY, 1.f);
19890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
19990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  glow_alpha_ = glow_alpha_start_ =
20090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      std::min(kMaxAlpha,
20190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)               glow_alpha_ + abs_delta_distance * kPullDistanceAlphaGlowFactor);
20290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
20390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  float glow_change = abs_delta_distance;
20490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (delta_distance > 0 && pull_distance_ < 0)
20590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    glow_change = -glow_change;
20690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (pull_distance_ == 0)
20790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    glow_scale_y_ = 0;
20890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
20990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Do not allow glow to get larger than kMaxGlowHeight.
21090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  glow_scale_y_ = glow_scale_y_start_ =
21190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      Clamp(glow_scale_y_ + glow_change * kPullDistanceGlowFactor,
21290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            0.f, kMaxGlowHeight);
21390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
21490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  edge_alpha_finish_ = edge_alpha_;
21590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  edge_scale_y_finish_ = edge_scale_y_;
21690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  glow_alpha_finish_ = glow_alpha_;
21790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  glow_scale_y_finish_ = glow_scale_y_;
21890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
21990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
22090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void EdgeEffect::Release(base::TimeTicks current_time) {
22190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  pull_distance_ = 0;
22290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
22390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (state_ != STATE_PULL && state_ != STATE_PULL_DECAY)
22490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return;
22590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
22690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  state_ = STATE_RECEDE;
22790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  edge_alpha_start_ = edge_alpha_;
22890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  edge_scale_y_start_ = edge_scale_y_;
22990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  glow_alpha_start_ = glow_alpha_;
23090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  glow_scale_y_start_ = glow_scale_y_;
23190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
23290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  edge_alpha_finish_ = 0.f;
23390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  edge_scale_y_finish_ = 0.f;
23490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  glow_alpha_finish_ = 0.f;
23590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  glow_scale_y_finish_ = 0.f;
23690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
23790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  start_time_ = current_time;
23890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  duration_ = base::TimeDelta::FromMilliseconds(kRecedeTime);
23990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
24090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
24190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void EdgeEffect::Absorb(base::TimeTicks current_time, float velocity) {
24290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  state_ = STATE_ABSORB;
243a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  velocity = Clamp(std::abs(velocity), kMinVelocity, kMaxVelocity);
24490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
24590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  start_time_ = current_time;
24690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // This should never be less than 1 millisecond.
2478bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  duration_ = base::TimeDelta::FromMilliseconds(0.15f + (velocity * 0.02f));
24890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
24990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // The edge should always be at least partially visible, regardless
25090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // of velocity.
25190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  edge_alpha_start_ = 0.f;
25290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  edge_scale_y_ = edge_scale_y_start_ = 0.f;
25390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // The glow depends more on the velocity, and therefore starts out
25490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // nearly invisible.
2558bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  glow_alpha_start_ = 0.3f;
25690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  glow_scale_y_start_ = 0.f;
25790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
25890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Factor the velocity by 8. Testing on device shows this works best to
25990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // reflect the strength of the user's scrolling.
260a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  edge_alpha_finish_ = Clamp(velocity * kVelocityEdgeFactor, 0.f, 1.f);
26190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Edge should never get larger than the size of its asset.
262a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  edge_scale_y_finish_ = Clamp(velocity * kVelocityEdgeFactor,
26390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                               kHeldEdgeScaleY, 1.f);
26490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
26590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Growth for the size of the glow should be quadratic to properly
26690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // respond
26790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // to a user's scrolling speed. The faster the scrolling speed, the more
26890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // intense the effect should be for both the size and the saturation.
269d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  glow_scale_y_finish_ = std::min(
270a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      0.025f + (velocity * (velocity / 100) * 0.00015f), 1.75f);
27190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Alpha should change for the glow as well as size.
272d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  glow_alpha_finish_ = Clamp(glow_alpha_start_,
273a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                             velocity * kVelocityGlowFactor * .00001f,
274d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                             kMaxAlpha);
27590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
27690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
27790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool EdgeEffect::Update(base::TimeTicks current_time) {
27890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (IsFinished())
27990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return false;
28090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
28190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  const double dt = (current_time - start_time_).InMilliseconds();
28290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  const double t = std::min(dt / duration_.InMilliseconds(), 1.);
28390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  const float interp = static_cast<float>(Damp(t, 1.));
28490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
28590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  edge_alpha_ = Lerp(edge_alpha_start_, edge_alpha_finish_, interp);
28690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  edge_scale_y_ = Lerp(edge_scale_y_start_, edge_scale_y_finish_, interp);
28790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  glow_alpha_ = Lerp(glow_alpha_start_, glow_alpha_finish_, interp);
28890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  glow_scale_y_ = Lerp(glow_scale_y_start_, glow_scale_y_finish_, interp);
28990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
29090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (t >= 1.f - kEpsilon) {
29190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    switch (state_) {
29290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      case STATE_ABSORB:
29390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        state_ = STATE_RECEDE;
29490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        start_time_ = current_time;
29590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        duration_ = base::TimeDelta::FromMilliseconds(kRecedeTime);
29690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
29790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        edge_alpha_start_ = edge_alpha_;
29890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        edge_scale_y_start_ = edge_scale_y_;
29990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        glow_alpha_start_ = glow_alpha_;
30090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        glow_scale_y_start_ = glow_scale_y_;
30190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
30290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // After absorb, the glow and edge should fade to nothing.
30390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        edge_alpha_finish_ = 0.f;
30490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        edge_scale_y_finish_ = 0.f;
30590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        glow_alpha_finish_ = 0.f;
30690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        glow_scale_y_finish_ = 0.f;
30790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        break;
30890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      case STATE_PULL:
30990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        state_ = STATE_PULL_DECAY;
31090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        start_time_ = current_time;
31190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        duration_ = base::TimeDelta::FromMilliseconds(kPullDecayTime);
31290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
31390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        edge_alpha_start_ = edge_alpha_;
31490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        edge_scale_y_start_ = edge_scale_y_;
31590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        glow_alpha_start_ = glow_alpha_;
31690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        glow_scale_y_start_ = glow_scale_y_;
31790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
31890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        // After pull, the glow and edge should fade to nothing.
31990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        edge_alpha_finish_ = 0.f;
32090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        edge_scale_y_finish_ = 0.f;
32190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        glow_alpha_finish_ = 0.f;
32290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        glow_scale_y_finish_ = 0.f;
32390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        break;
324a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      case STATE_PULL_DECAY: {
325a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        // When receding, we want edge to decrease more slowly
326a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        // than the glow.
327a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        const float factor = glow_scale_y_finish_ != 0 ?
328a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch            1 / (glow_scale_y_finish_ * glow_scale_y_finish_) :
329a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch            std::numeric_limits<float>::max();
330a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        edge_scale_y_ = edge_scale_y_start_ +
331a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch            (edge_scale_y_finish_ - edge_scale_y_start_) * interp * factor;
332a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        state_ = STATE_RECEDE;
333a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      } break;
33490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      case STATE_RECEDE:
33590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        Finish();
33690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        break;
33790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      default:
33890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        break;
33990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
34090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
34190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
34290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (state_ == STATE_RECEDE && glow_scale_y_ <= 0 && edge_scale_y_ <= 0)
34390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    Finish();
34490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
34590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return !IsFinished();
34690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
34790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
348a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochvoid EdgeEffect::ApplyToLayers(gfx::SizeF window_size,
349a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                               Edge edge,
350a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                               float edge_height,
351a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                               float glow_height,
352a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                               float offset) {
35390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (IsFinished())
35490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return;
35590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
356a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // An empty window size, while meaningless, is also relatively harmless, and
35790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // will simply prevent any drawing of the layers.
358a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (window_size.IsEmpty()) {
3597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    DisableLayer(edge_.get());
3607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    DisableLayer(glow_.get());
36190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return;
36290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
36390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
36490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Glow
365a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  const int scaled_glow_height = static_cast<int>(
366a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      std::min(glow_height * glow_scale_y_ * kGlowHeightToWidthRatio * 0.6f,
367a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch               glow_height * kMaxGlowHeight) + 0.5f);
368a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  UpdateLayer(
369a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      glow_.get(), edge, window_size, offset, scaled_glow_height, glow_alpha_);
37090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
37190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Edge
372a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch const int scaled_edge_height = static_cast<int>(edge_height * edge_scale_y_);
373a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  UpdateLayer(
374a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      edge_.get(), edge, window_size, offset, scaled_edge_height, edge_alpha_);
37590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
37690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
37790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} // namespace content
378