summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJared Duke <jdduke@chromium.org>2014-08-25 13:17:01 -0700
committerJared Duke <jdduke@chromium.org>2014-08-25 20:20:25 +0000
commit243300e3fd1a7b49476d4af02cbfd5ad657eb837 (patch)
treed8bd5c0999d7ae7080bac9e5dccbd51816b77ff1
parentdc074b149392946f86fb6f2a5b6b3952ee087446 (diff)
downloadchromium_src-243300e3fd1a7b49476d4af02cbfd5ad657eb837.zip
chromium_src-243300e3fd1a7b49476d4af02cbfd5ad657eb837.tar.gz
chromium_src-243300e3fd1a7b49476d4af02cbfd5ad657eb837.tar.bz2
[Android] Implementation of overscroll effect for Android L
Add an overscroll effect implementation that mimics that of Android L. The primary differences are the use of a single rasterized arc layer and the inclusion of motion orthogonal to overscroll in computing the effect offset. BUG=389744 TBR=tsepez@chromium.org,aelias@chromium.org,yfriedman@chromium.org Review URL: https://codereview.chromium.org/367173003 Cr-Commit-Position: refs/heads/master@{#290052} git-svn-id: svn://svn.chromium.org/chrome/trunk/src@290052 0039d316-1c4b-4281-b951-d872f2087c98 (cherry picked from commit cffc32811f74487652b5c34f28ec9a1a752919c3) Review URL: https://codereview.chromium.org/476313006 Cr-Commit-Position: refs/branch-heads/2125@{#89} Cr-Branched-From: b68026d94bda36dd106a3d91a098719f952a9477-refs/heads/master@{#290040}
-rw-r--r--cc/input/input_handler.h3
-rw-r--r--cc/trees/layer_tree_host_impl.cc6
-rw-r--r--cc/trees/layer_tree_host_unittest_scroll.cc7
-rw-r--r--content/browser/android/edge_effect.cc152
-rw-r--r--content/browser/android/edge_effect.h66
-rw-r--r--content/browser/android/edge_effect_base.h49
-rw-r--r--content/browser/android/edge_effect_l.cc268
-rw-r--r--content/browser/android/edge_effect_l.h81
-rw-r--r--content/browser/android/overscroll_glow.cc161
-rw-r--r--content/browser/android/overscroll_glow.h46
-rw-r--r--content/browser/android/system_ui_resource_manager_impl.cc84
-rw-r--r--content/browser/android/system_ui_resource_manager_impl.h1
-rw-r--r--content/browser/renderer_host/render_widget_host_view_android.cc81
-rw-r--r--content/browser/renderer_host/render_widget_host_view_android.h3
-rw-r--r--content/common/input/did_overscroll_params.cc15
-rw-r--r--content/common/input/did_overscroll_params.h7
-rw-r--r--content/common/input_messages.h1
-rw-r--r--content/content_browser.gypi2
-rw-r--r--content/content_common.gypi1
-rw-r--r--content/renderer/input/input_event_filter.cc8
-rw-r--r--content/renderer/input/input_handler_proxy.cc2
-rw-r--r--content/renderer/input/input_handler_proxy.h7
-rw-r--r--content/renderer/input/input_handler_proxy_unittest.cc75
-rw-r--r--ui/base/android/system_ui_resource_manager.h3
24 files changed, 814 insertions, 315 deletions
diff --git a/cc/input/input_handler.h b/cc/input/input_handler.h
index 9cf764e..880c208 100644
--- a/cc/input/input_handler.h
+++ b/cc/input/input_handler.h
@@ -35,7 +35,8 @@ class CC_EXPORT InputHandlerClient {
// Called when scroll deltas reaching the root scrolling layer go unused.
// The accumulated overscroll is scoped by the most recent call to
// InputHandler::ScrollBegin.
- virtual void DidOverscroll(const gfx::Vector2dF& accumulated_overscroll,
+ virtual void DidOverscroll(const gfx::PointF& causal_event_viewport_point,
+ const gfx::Vector2dF& accumulated_overscroll,
const gfx::Vector2dF& latest_overscroll_delta) = 0;
protected:
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 2845d18..705598b 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -2672,8 +2672,8 @@ bool LayerTreeHostImpl::ScrollBy(const gfx::Point& viewport_point,
accumulated_root_overscroll_ += unused_root_delta;
bool did_overscroll = !unused_root_delta.IsZero();
if (did_overscroll && input_handler_client_) {
- input_handler_client_->DidOverscroll(accumulated_root_overscroll_,
- unused_root_delta);
+ input_handler_client_->DidOverscroll(
+ viewport_point, accumulated_root_overscroll_, unused_root_delta);
}
return did_scroll_content || did_scroll_top_controls;
@@ -3297,7 +3297,7 @@ void LayerTreeHostImpl::CreateUIResource(UIResourceId uid,
case UIResourceBitmap::ETC1:
format = ETC1;
break;
- };
+ }
id = resource_provider_->CreateResource(
bitmap.GetSize(),
wrap_mode,
diff --git a/cc/trees/layer_tree_host_unittest_scroll.cc b/cc/trees/layer_tree_host_unittest_scroll.cc
index e1eb884..60ca59b 100644
--- a/cc/trees/layer_tree_host_unittest_scroll.cc
+++ b/cc/trees/layer_tree_host_unittest_scroll.cc
@@ -1073,9 +1073,10 @@ class ThreadCheckingInputHandlerClient : public InputHandlerClient {
*received_stop_flinging_ = true;
}
- virtual void DidOverscroll(const gfx::Vector2dF& accumulated_overscroll,
- const gfx::Vector2dF& latest_overscroll_delta)
- OVERRIDE {
+ virtual void DidOverscroll(
+ const gfx::PointF& causal_event_viewport_point,
+ const gfx::Vector2dF& accumulated_overscroll,
+ const gfx::Vector2dF& latest_overscroll_delta) OVERRIDE {
if (!task_runner_->BelongsToCurrentThread())
ADD_FAILURE() << "DidOverscroll called on wrong thread";
}
diff --git a/content/browser/android/edge_effect.cc b/content/browser/android/edge_effect.cc
index 2979872..00c1aa5 100644
--- a/content/browser/android/edge_effect.cc
+++ b/content/browser/android/edge_effect.cc
@@ -12,22 +12,14 @@ namespace content {
namespace {
-enum State {
- STATE_IDLE = 0,
- STATE_PULL,
- STATE_ABSORB,
- STATE_RECEDE,
- STATE_PULL_DECAY
-};
-
// Time it will take the effect to fully recede in ms
-const int kRecedeTime = 1000;
+const int kRecedeTimeMs = 1000;
// Time it will take before a pulled glow begins receding in ms
-const int kPullTime = 167;
+const int kPullTimeMs = 167;
// Time it will take in ms for a pulled glow to decay before release
-const int kPullDecayTime = 1000;
+const int kPullDecayTimeMs = 1000;
const float kMaxAlpha = 1.f;
const float kHeldEdgeScaleY = .5f;
@@ -43,7 +35,7 @@ const float kMaxVelocity = 10000.f;
const float kEpsilon = 0.001f;
-const float kGlowHeightToWidthRatio = 0.25f;
+const float kGlowHeightWidthRatio = 0.25f;
// How much dragging should effect the height of the edge image.
// Number determined by user testing.
@@ -57,6 +49,9 @@ const float kPullDistanceAlphaGlowFactor = 1.1f;
const int kVelocityEdgeFactor = 8;
const int kVelocityGlowFactor = 12;
+const float kEdgeHeightAtMdpi = 12.f;
+const float kGlowHeightAtMdpi = 128.f;
+
template <typename T>
T Lerp(T a, T b, T t) {
return a + (b - a) * t;
@@ -64,7 +59,7 @@ T Lerp(T a, T b, T t) {
template <typename T>
T Clamp(T value, T low, T high) {
- return value < low ? low : (value > high ? high : value);
+ return value < low ? low : (value > high ? high : value);
}
template <typename T>
@@ -78,48 +73,6 @@ T Damp(T input, T factor) {
return result;
}
-gfx::Transform ComputeTransform(EdgeEffect::Edge edge,
- const gfx::SizeF& window_size,
- int offset,
- int height) {
- // Edge effects that require rotation are translated to the center about which
- // the layer should be rotated to align with the corresponding edge.
- switch (edge) {
- case EdgeEffect::EDGE_TOP:
- return gfx::Transform(1, 0, 0, 1, 0, offset);
- case EdgeEffect::EDGE_LEFT:
- return gfx::Transform(0, 1, -1, 0,
- (-window_size.height() + height) / 2.f + offset,
- (window_size.height() - height) / 2.f);
- case EdgeEffect::EDGE_BOTTOM:
- return gfx::Transform(-1, 0, 0, -1,
- 0, window_size.height() - height + offset);
- case EdgeEffect::EDGE_RIGHT:
- return gfx::Transform(0, -1, 1, 0,
- (-window_size.height() - height) / 2.f + window_size.width() + offset,
- (window_size.height() - height) / 2.f);
- default:
- NOTREACHED() << "Invalid edge: " << edge;
- return gfx::Transform();
- };
-}
-
-gfx::Size ComputeBounds(EdgeEffect::Edge edge,
- const gfx::SizeF& window_size,
- int height) {
- switch (edge) {
- case EdgeEffect::EDGE_TOP:
- case EdgeEffect::EDGE_BOTTOM:
- return gfx::Size(window_size.width(), height);
- case EdgeEffect::EDGE_LEFT:
- case EdgeEffect::EDGE_RIGHT:
- return gfx::Size(window_size.height(), height);
- default:
- NOTREACHED() << "Invalid edge: " << edge;
- return gfx::Size();
- };
-}
-
} // namespace
class EdgeEffect::EffectLayer {
@@ -141,20 +94,16 @@ class EdgeEffect::EffectLayer {
void Disable() { ui_resource_layer_->SetIsDrawable(false); }
- void Update(EdgeEffect::Edge edge,
- const gfx::SizeF& window_size,
- int offset,
- int height,
+ void Update(const gfx::Size& size,
+ const gfx::Transform& transform,
float opacity) {
ui_resource_layer_->SetUIResourceId(
resource_manager_->GetUIResourceId(resource_type_));
ui_resource_layer_->SetIsDrawable(true);
- gfx::Size bounds = ComputeBounds(edge, window_size, height);
ui_resource_layer_->SetTransformOrigin(
- gfx::Point3F(bounds.width() * 0.5f, bounds.height() * 0.5f, 0));
- ui_resource_layer_->SetTransform(
- ComputeTransform(edge, window_size, offset, height));
- ui_resource_layer_->SetBounds(bounds);
+ gfx::Point3F(size.width() * 0.5f, 0, 0));
+ ui_resource_layer_->SetTransform(transform);
+ ui_resource_layer_->SetBounds(size);
ui_resource_layer_->SetOpacity(Clamp(opacity, 0.f, 1.f));
}
@@ -165,11 +114,14 @@ class EdgeEffect::EffectLayer {
DISALLOW_COPY_AND_ASSIGN(EffectLayer);
};
-EdgeEffect::EdgeEffect(ui::SystemUIResourceManager* resource_manager)
+EdgeEffect::EdgeEffect(ui::SystemUIResourceManager* resource_manager,
+ float device_scale_factor)
: edge_(new EffectLayer(ui::SystemUIResourceManager::OVERSCROLL_EDGE,
resource_manager)),
glow_(new EffectLayer(ui::SystemUIResourceManager::OVERSCROLL_GLOW,
resource_manager)),
+ base_edge_height_(kEdgeHeightAtMdpi * device_scale_factor),
+ base_glow_height_(kGlowHeightAtMdpi * device_scale_factor),
edge_alpha_(0),
edge_scale_y_(0),
glow_alpha_(0),
@@ -186,7 +138,8 @@ EdgeEffect::EdgeEffect(ui::SystemUIResourceManager* resource_manager)
pull_distance_(0) {
}
-EdgeEffect::~EdgeEffect() { }
+EdgeEffect::~EdgeEffect() {
+}
bool EdgeEffect::IsFinished() const {
return state_ == STATE_IDLE;
@@ -199,7 +152,9 @@ void EdgeEffect::Finish() {
state_ = STATE_IDLE;
}
-void EdgeEffect::Pull(base::TimeTicks current_time, float delta_distance) {
+void EdgeEffect::Pull(base::TimeTicks current_time,
+ float delta_distance,
+ float displacement) {
if (state_ == STATE_PULL_DECAY && current_time - start_time_ < duration_) {
return;
}
@@ -209,15 +164,15 @@ void EdgeEffect::Pull(base::TimeTicks current_time, float delta_distance) {
state_ = STATE_PULL;
start_time_ = current_time;
- duration_ = base::TimeDelta::FromMilliseconds(kPullTime);
+ duration_ = base::TimeDelta::FromMilliseconds(kPullTimeMs);
float abs_delta_distance = std::abs(delta_distance);
pull_distance_ += delta_distance;
float distance = std::abs(pull_distance_);
edge_alpha_ = edge_alpha_start_ = Clamp(distance, kPullEdgeBegin, kMaxAlpha);
- edge_scale_y_ = edge_scale_y_start_
- = Clamp(distance * kPullDistanceEdgeFactor, kHeldEdgeScaleY, 1.f);
+ edge_scale_y_ = edge_scale_y_start_ =
+ Clamp(distance * kPullDistanceEdgeFactor, kHeldEdgeScaleY, 1.f);
glow_alpha_ = glow_alpha_start_ =
std::min(kMaxAlpha,
@@ -232,7 +187,8 @@ void EdgeEffect::Pull(base::TimeTicks current_time, float delta_distance) {
// Do not allow glow to get larger than kMaxGlowHeight.
glow_scale_y_ = glow_scale_y_start_ =
Clamp(glow_scale_y_ + glow_change * kPullDistanceGlowFactor,
- 0.f, kMaxGlowHeight);
+ 0.f,
+ kMaxGlowHeight);
edge_alpha_finish_ = edge_alpha_;
edge_scale_y_finish_ = edge_scale_y_;
@@ -258,7 +214,7 @@ void EdgeEffect::Release(base::TimeTicks current_time) {
glow_scale_y_finish_ = 0.f;
start_time_ = current_time;
- duration_ = base::TimeDelta::FromMilliseconds(kRecedeTime);
+ duration_ = base::TimeDelta::FromMilliseconds(kRecedeTimeMs);
}
void EdgeEffect::Absorb(base::TimeTicks current_time, float velocity) {
@@ -282,19 +238,18 @@ void EdgeEffect::Absorb(base::TimeTicks current_time, float velocity) {
// reflect the strength of the user's scrolling.
edge_alpha_finish_ = Clamp(velocity * kVelocityEdgeFactor, 0.f, 1.f);
// Edge should never get larger than the size of its asset.
- edge_scale_y_finish_ = Clamp(velocity * kVelocityEdgeFactor,
- kHeldEdgeScaleY, 1.f);
+ edge_scale_y_finish_ =
+ Clamp(velocity * kVelocityEdgeFactor, kHeldEdgeScaleY, 1.f);
// Growth for the size of the glow should be quadratic to properly
// respond
// to a user's scrolling speed. The faster the scrolling speed, the more
// intense the effect should be for both the size and the saturation.
- glow_scale_y_finish_ = std::min(
- 0.025f + (velocity * (velocity / 100) * 0.00015f), 1.75f);
+ glow_scale_y_finish_ =
+ std::min(0.025f + (velocity * (velocity / 100) * 0.00015f), 1.75f);
// Alpha should change for the glow as well as size.
- glow_alpha_finish_ = Clamp(glow_alpha_start_,
- velocity * kVelocityGlowFactor * .00001f,
- kMaxAlpha);
+ glow_alpha_finish_ = Clamp(
+ glow_alpha_start_, velocity * kVelocityGlowFactor * .00001f, kMaxAlpha);
}
bool EdgeEffect::Update(base::TimeTicks current_time) {
@@ -315,7 +270,7 @@ bool EdgeEffect::Update(base::TimeTicks current_time) {
case STATE_ABSORB:
state_ = STATE_RECEDE;
start_time_ = current_time;
- duration_ = base::TimeDelta::FromMilliseconds(kRecedeTime);
+ duration_ = base::TimeDelta::FromMilliseconds(kRecedeTimeMs);
edge_alpha_start_ = edge_alpha_;
edge_scale_y_start_ = edge_scale_y_;
@@ -331,7 +286,7 @@ bool EdgeEffect::Update(base::TimeTicks current_time) {
case STATE_PULL:
state_ = STATE_PULL_DECAY;
start_time_ = current_time;
- duration_ = base::TimeDelta::FromMilliseconds(kPullDecayTime);
+ duration_ = base::TimeDelta::FromMilliseconds(kPullDecayTimeMs);
edge_alpha_start_ = edge_alpha_;
edge_scale_y_start_ = edge_scale_y_;
@@ -347,10 +302,12 @@ bool EdgeEffect::Update(base::TimeTicks current_time) {
case STATE_PULL_DECAY: {
// When receding, we want edge to decrease more slowly
// than the glow.
- const float factor = glow_scale_y_finish_ != 0 ?
- 1 / (glow_scale_y_finish_ * glow_scale_y_finish_) :
- std::numeric_limits<float>::max();
- edge_scale_y_ = edge_scale_y_start_ +
+ const float factor =
+ glow_scale_y_finish_
+ ? 1 / (glow_scale_y_finish_ * glow_scale_y_finish_)
+ : std::numeric_limits<float>::max();
+ edge_scale_y_ =
+ edge_scale_y_start_ +
(edge_scale_y_finish_ - edge_scale_y_start_) * interp * factor;
state_ = STATE_RECEDE;
} break;
@@ -368,17 +325,14 @@ bool EdgeEffect::Update(base::TimeTicks current_time) {
return !IsFinished();
}
-void EdgeEffect::ApplyToLayers(gfx::SizeF window_size,
- Edge edge,
- float edge_height,
- float glow_height,
- float offset) {
+void EdgeEffect::ApplyToLayers(const gfx::SizeF& size,
+ const gfx::Transform& transform) {
if (IsFinished())
return;
// An empty window size, while meaningless, is also relatively harmless, and
// will simply prevent any drawing of the layers.
- if (window_size.IsEmpty()) {
+ if (size.IsEmpty()) {
edge_->Disable();
glow_->Disable();
return;
@@ -386,13 +340,17 @@ void EdgeEffect::ApplyToLayers(gfx::SizeF window_size,
// Glow
const int scaled_glow_height = static_cast<int>(
- std::min(glow_height * glow_scale_y_ * kGlowHeightToWidthRatio * 0.6f,
- glow_height * kMaxGlowHeight) + 0.5f);
- glow_->Update(edge, window_size, offset, scaled_glow_height, glow_alpha_);
+ std::min(base_glow_height_ * glow_scale_y_ * kGlowHeightWidthRatio * 0.6f,
+ base_glow_height_ * kMaxGlowHeight) +
+ 0.5f);
+ const gfx::Size glow_size(size.width(), scaled_glow_height);
+ glow_->Update(glow_size, transform, glow_alpha_);
// Edge
- const int scaled_edge_height = static_cast<int>(edge_height * edge_scale_y_);
- edge_->Update(edge, window_size, offset, scaled_edge_height, edge_alpha_);
+ const int scaled_edge_height =
+ static_cast<int>(base_edge_height_ * edge_scale_y_);
+ const gfx::Size edge_size(size.width(), scaled_edge_height);
+ edge_->Update(edge_size, transform, edge_alpha_);
}
void EdgeEffect::SetParent(cc::Layer* parent) {
@@ -410,4 +368,4 @@ void EdgeEffect::PreloadResources(
ui::SystemUIResourceManager::OVERSCROLL_GLOW);
}
-} // namespace content
+} // namespace content
diff --git a/content/browser/android/edge_effect.h b/content/browser/android/edge_effect.h
index a8f944c..ced6a32 100644
--- a/content/browser/android/edge_effect.h
+++ b/content/browser/android/edge_effect.h
@@ -5,10 +5,8 @@
#ifndef CONTENT_BROWSER_ANDROID_EDGE_EFFECT_H_
#define CONTENT_BROWSER_ANDROID_EDGE_EFFECT_H_
-#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
-#include "base/time/time.h"
-#include "ui/gfx/size_f.h"
+#include "content/browser/android/edge_effect_base.h"
namespace cc {
class Layer;
@@ -20,57 +18,41 @@ class SystemUIResourceManager;
namespace content {
-/* |EdgeEffect| mirrors its Android counterpart, EdgeEffect.java.
- * The primary difference is ownership; the Android version manages render
- * resources directly, while this version simply applies the effect to
- * existing resources. Conscious tradeoffs were made to align this as closely
- * as possible with the original Android java version.
- * All coordinates and dimensions are in device pixels.
- */
-class EdgeEffect {
+// |EdgeEffect| mirrors its Android counterpart, EdgeEffect.java.
+// Conscious tradeoffs were made to align this as closely as possible with the
+// the original Android java version.
+// All coordinates and dimensions are in device pixels.
+class EdgeEffect : public EdgeEffectBase {
public:
- enum Edge {
- EDGE_TOP = 0,
- EDGE_LEFT,
- EDGE_BOTTOM,
- EDGE_RIGHT,
- EDGE_COUNT
- };
+ explicit EdgeEffect(ui::SystemUIResourceManager* resource_manager,
+ float device_scale_factor);
+ virtual ~EdgeEffect();
- explicit EdgeEffect(ui::SystemUIResourceManager* resource_manager);
- ~EdgeEffect();
+ virtual void Pull(base::TimeTicks current_time,
+ float delta_distance,
+ float displacement) OVERRIDE;
+ virtual void Absorb(base::TimeTicks current_time, float velocity) OVERRIDE;
+ virtual bool Update(base::TimeTicks current_time) OVERRIDE;
+ virtual void Release(base::TimeTicks current_time) OVERRIDE;
- void Pull(base::TimeTicks current_time, float delta_distance);
- void Absorb(base::TimeTicks current_time, float velocity);
- bool Update(base::TimeTicks current_time);
- void Release(base::TimeTicks current_time);
+ virtual void Finish() OVERRIDE;
+ virtual bool IsFinished() const OVERRIDE;
- void Finish();
- bool IsFinished() const;
-
- void ApplyToLayers(gfx::SizeF window_size,
- Edge edge,
- float edge_height,
- float glow_height,
- float offset);
-
- void SetParent(cc::Layer* parent);
+ virtual void ApplyToLayers(const gfx::SizeF& size,
+ const gfx::Transform& transform) OVERRIDE;
+ virtual void SetParent(cc::Layer* parent) OVERRIDE;
+ // Thread-safe trigger to load resources.
static void PreloadResources(ui::SystemUIResourceManager* resource_manager);
private:
- enum State {
- STATE_IDLE = 0,
- STATE_PULL,
- STATE_ABSORB,
- STATE_RECEDE,
- STATE_PULL_DECAY
- };
-
class EffectLayer;
scoped_ptr<EffectLayer> edge_;
scoped_ptr<EffectLayer> glow_;
+ float base_edge_height_;
+ float base_glow_height_;
+
float edge_alpha_;
float edge_scale_y_;
float glow_alpha_;
diff --git a/content/browser/android/edge_effect_base.h b/content/browser/android/edge_effect_base.h
new file mode 100644
index 0000000..f7df20d
--- /dev/null
+++ b/content/browser/android/edge_effect_base.h
@@ -0,0 +1,49 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_ANDROID_EDGE_EFFECT_BASE_H_
+#define CONTENT_BROWSER_ANDROID_EDGE_EFFECT_BASE_H_
+
+#include "base/basictypes.h"
+#include "base/time/time.h"
+#include "ui/gfx/geometry/size_f.h"
+#include "ui/gfx/transform.h"
+
+namespace cc {
+class Layer;
+}
+
+namespace content {
+
+// A base class for overscroll-related Android effects.
+class EdgeEffectBase {
+ public:
+ enum State {
+ STATE_IDLE = 0,
+ STATE_PULL,
+ STATE_ABSORB,
+ STATE_RECEDE,
+ STATE_PULL_DECAY
+ };
+
+ virtual ~EdgeEffectBase() {}
+
+ virtual void Pull(base::TimeTicks current_time,
+ float delta_distance,
+ float displacement) = 0;
+ virtual void Absorb(base::TimeTicks current_time, float velocity) = 0;
+ virtual bool Update(base::TimeTicks current_time) = 0;
+ virtual void Release(base::TimeTicks current_time) = 0;
+
+ virtual void Finish() = 0;
+ virtual bool IsFinished() const = 0;
+
+ virtual void ApplyToLayers(const gfx::SizeF& size,
+ const gfx::Transform& transform) = 0;
+ virtual void SetParent(cc::Layer* parent) = 0;
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_ANDROID_EDGE_EFFECT_BASE_H_
diff --git a/content/browser/android/edge_effect_l.cc b/content/browser/android/edge_effect_l.cc
new file mode 100644
index 0000000..4bf2646
--- /dev/null
+++ b/content/browser/android/edge_effect_l.cc
@@ -0,0 +1,268 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/android/edge_effect_l.h"
+
+#include "cc/layers/ui_resource_layer.h"
+#include "ui/base/android/system_ui_resource_manager.h"
+
+namespace content {
+
+namespace {
+
+// Time it will take the effect to fully recede in ms
+const int kRecedeTimeMs = 1000;
+
+// Time it will take before a pulled glow begins receding in ms
+const int kPullTimeMs = 167;
+
+const float kMaxAlpha = 1.f;
+
+const float kPullGlowBegin = 0.f;
+
+// Min/max velocity that will be absorbed
+const float kMinVelocity = 100.f;
+const float kMaxVelocity = 10000.f;
+
+const float kEpsilon = 0.001f;
+
+const float kSin = 0.5f; // sin(PI / 6)
+const float kCos = 0.866f; // cos(PI / 6);
+
+// How much dragging should effect the height of the glow image.
+// Number determined by user testing.
+const float kPullDistanceAlphaGlowFactor = 1.1f;
+
+const int kVelocityGlowFactor = 12;
+
+const ui::SystemUIResourceManager::ResourceType kResourceType =
+ ui::SystemUIResourceManager::OVERSCROLL_GLOW_L;
+
+template <typename T>
+T Lerp(T a, T b, T t) {
+ return a + (b - a) * t;
+}
+
+template <typename T>
+T Clamp(T value, T low, T high) {
+ return value < low ? low : (value > high ? high : value);
+}
+
+template <typename T>
+T Damp(T input, T factor) {
+ T result;
+ if (factor == 1) {
+ result = 1 - (1 - input) * (1 - input);
+ } else {
+ result = 1 - std::pow(1 - input, 2 * factor);
+ }
+ return result;
+}
+
+} // namespace
+
+EdgeEffectL::EdgeEffectL(ui::SystemUIResourceManager* resource_manager)
+ : resource_manager_(resource_manager),
+ glow_(cc::UIResourceLayer::Create()),
+ glow_alpha_(0),
+ glow_scale_y_(0),
+ glow_alpha_start_(0),
+ glow_alpha_finish_(0),
+ glow_scale_y_start_(0),
+ glow_scale_y_finish_(0),
+ displacement_(0.5f),
+ target_displacement_(0.5f),
+ state_(STATE_IDLE),
+ pull_distance_(0) {
+ // Prevent the provided layers from drawing until the effect is activated.
+ glow_->SetIsDrawable(false);
+}
+
+EdgeEffectL::~EdgeEffectL() {
+ glow_->RemoveFromParent();
+}
+
+bool EdgeEffectL::IsFinished() const {
+ return state_ == STATE_IDLE;
+}
+
+void EdgeEffectL::Finish() {
+ glow_->SetIsDrawable(false);
+ pull_distance_ = 0;
+ state_ = STATE_IDLE;
+}
+
+void EdgeEffectL::Pull(base::TimeTicks current_time,
+ float delta_distance,
+ float displacement) {
+ target_displacement_ = displacement;
+ if (state_ == STATE_PULL_DECAY && current_time - start_time_ < duration_) {
+ return;
+ }
+ if (state_ != STATE_PULL) {
+ glow_scale_y_ = std::max(kPullGlowBegin, glow_scale_y_);
+ }
+ state_ = STATE_PULL;
+
+ start_time_ = current_time;
+ duration_ = base::TimeDelta::FromMilliseconds(kPullTimeMs);
+
+ float abs_delta_distance = std::abs(delta_distance);
+ pull_distance_ += delta_distance;
+
+ glow_alpha_ = glow_alpha_start_ = std::min(
+ kMaxAlpha,
+ glow_alpha_ + (abs_delta_distance * kPullDistanceAlphaGlowFactor));
+
+ if (pull_distance_ == 0) {
+ glow_scale_y_ = glow_scale_y_start_ = 0;
+ } else {
+ float scale = 1.f -
+ 1.f / std::sqrt(std::abs(pull_distance_) * bounds_.height()) -
+ 0.3f;
+ glow_scale_y_ = glow_scale_y_start_ = std::max(0.f, scale) / 0.7f;
+ }
+
+ glow_alpha_finish_ = glow_alpha_;
+ glow_scale_y_finish_ = glow_scale_y_;
+}
+
+void EdgeEffectL::Release(base::TimeTicks current_time) {
+ pull_distance_ = 0;
+
+ if (state_ != STATE_PULL && state_ != STATE_PULL_DECAY)
+ return;
+
+ state_ = STATE_RECEDE;
+ glow_alpha_start_ = glow_alpha_;
+ glow_scale_y_start_ = glow_scale_y_;
+
+ glow_alpha_finish_ = 0.f;
+ glow_scale_y_finish_ = 0.f;
+
+ start_time_ = current_time;
+ duration_ = base::TimeDelta::FromMilliseconds(kRecedeTimeMs);
+}
+
+void EdgeEffectL::Absorb(base::TimeTicks current_time, float velocity) {
+ state_ = STATE_ABSORB;
+
+ velocity = Clamp(std::abs(velocity), kMinVelocity, kMaxVelocity);
+
+ start_time_ = current_time;
+ // This should never be less than 1 millisecond.
+ duration_ = base::TimeDelta::FromMilliseconds(0.15f + (velocity * 0.02f));
+
+ // The glow depends more on the velocity, and therefore starts out
+ // nearly invisible.
+ glow_alpha_start_ = 0.3f;
+ glow_scale_y_start_ = std::max(glow_scale_y_, 0.f);
+
+ // Growth for the size of the glow should be quadratic to properly respond
+ // to a user's scrolling speed. The faster the scrolling speed, the more
+ // intense the effect should be for both the size and the saturation.
+ glow_scale_y_finish_ =
+ std::min(0.025f + (velocity * (velocity / 100) * 0.00015f) / 2.f, 1.f);
+ // Alpha should change for the glow as well as size.
+ glow_alpha_finish_ = Clamp(
+ glow_alpha_start_, velocity * kVelocityGlowFactor * .00001f, kMaxAlpha);
+ target_displacement_ = 0.5;
+}
+
+bool EdgeEffectL::Update(base::TimeTicks current_time) {
+ if (IsFinished())
+ return false;
+
+ const double dt = (current_time - start_time_).InMilliseconds();
+ const double t = std::min(dt / duration_.InMilliseconds(), 1.);
+ const float interp = static_cast<float>(Damp(t, 1.));
+
+ glow_alpha_ = Lerp(glow_alpha_start_, glow_alpha_finish_, interp);
+ glow_scale_y_ = Lerp(glow_scale_y_start_, glow_scale_y_finish_, interp);
+ displacement_ = (displacement_ + target_displacement_) / 2.f;
+
+ if (t >= 1.f - kEpsilon) {
+ switch (state_) {
+ case STATE_ABSORB:
+ state_ = STATE_RECEDE;
+ start_time_ = current_time;
+ duration_ = base::TimeDelta::FromMilliseconds(kRecedeTimeMs);
+
+ glow_alpha_start_ = glow_alpha_;
+ glow_scale_y_start_ = glow_scale_y_;
+
+ glow_alpha_finish_ = 0.f;
+ glow_scale_y_finish_ = 0.f;
+ break;
+ case STATE_PULL:
+ // Hold in this state until explicitly released.
+ break;
+ case STATE_PULL_DECAY:
+ state_ = STATE_RECEDE;
+ break;
+ case STATE_RECEDE:
+ Finish();
+ break;
+ default:
+ break;
+ }
+ }
+
+ bool one_last_frame = false;
+ if (state_ == STATE_RECEDE && glow_scale_y_ <= 0) {
+ Finish();
+ one_last_frame = true;
+ }
+
+ return !IsFinished() || one_last_frame;
+}
+
+void EdgeEffectL::ApplyToLayers(const gfx::SizeF& size,
+ const gfx::Transform& transform) {
+ if (IsFinished())
+ return;
+
+ // An empty window size, while meaningless, is also relatively harmless, and
+ // will simply prevent any drawing of the layers.
+ if (size.IsEmpty()) {
+ glow_->SetIsDrawable(false);
+ return;
+ }
+
+ const float r = size.width() * 0.75f / kSin;
+ const float y = kCos * r;
+ const float h = r - y;
+ bounds_ = gfx::Size(size.width(), (int)std::min(size.height(), h));
+ gfx::Size image_bounds(r, std::min(1.f, glow_scale_y_) * bounds_.height());
+
+ glow_->SetIsDrawable(true);
+ glow_->SetUIResourceId(resource_manager_->GetUIResourceId(kResourceType));
+ glow_->SetTransformOrigin(gfx::Point3F(bounds_.width() * 0.5f, 0, 0));
+ glow_->SetBounds(image_bounds);
+ glow_->SetContentsOpaque(false);
+ glow_->SetOpacity(Clamp(glow_alpha_, 0.f, 1.f));
+
+ const float displacement = Clamp(displacement_, 0.f, 1.f) - 0.5f;
+ const float displacement_offset_x = bounds_.width() * displacement * 0.5f;
+ const float image_offset_x = (bounds_.width() - image_bounds.width()) * 0.5f;
+ gfx::Transform offset_transform;
+ offset_transform.Translate(image_offset_x - displacement_offset_x, 0);
+ offset_transform.ConcatTransform(transform);
+ glow_->SetTransform(offset_transform);
+}
+
+void EdgeEffectL::SetParent(cc::Layer* parent) {
+ if (glow_->parent() != parent)
+ parent->AddChild(glow_);
+ glow_->SetUIResourceId(resource_manager_->GetUIResourceId(kResourceType));
+}
+
+// static
+void EdgeEffectL::PreloadResources(
+ ui::SystemUIResourceManager* resource_manager) {
+ DCHECK(resource_manager);
+ resource_manager->PreloadResource(kResourceType);
+}
+
+} // namespace content
diff --git a/content/browser/android/edge_effect_l.h b/content/browser/android/edge_effect_l.h
new file mode 100644
index 0000000..0294180
--- /dev/null
+++ b/content/browser/android/edge_effect_l.h
@@ -0,0 +1,81 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_ANDROID_EDGE_EFFECT_L_H_
+#define CONTENT_BROWSER_ANDROID_EDGE_EFFECT_L_H_
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/browser/android/edge_effect_base.h"
+#include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace cc {
+class Layer;
+class UIResourceLayer;
+}
+
+namespace ui {
+class SystemUIResourceManager;
+}
+
+namespace content {
+
+// |EdgeEffectL| mirrors its Android L counterpart, EdgeEffect.java.
+// Conscious tradeoffs were made to align this as closely as possible with the
+// the original Android java version.
+// All coordinates and dimensions are in device pixels.
+class EdgeEffectL : public EdgeEffectBase {
+ public:
+ explicit EdgeEffectL(ui::SystemUIResourceManager* resource_manager);
+ virtual ~EdgeEffectL();
+
+ virtual void Pull(base::TimeTicks current_time,
+ float delta_distance,
+ float displacement) OVERRIDE;
+ virtual void Absorb(base::TimeTicks current_time, float velocity) OVERRIDE;
+ virtual bool Update(base::TimeTicks current_time) OVERRIDE;
+ virtual void Release(base::TimeTicks current_time) OVERRIDE;
+
+ virtual void Finish() OVERRIDE;
+ virtual bool IsFinished() const OVERRIDE;
+
+ virtual void ApplyToLayers(const gfx::SizeF& size,
+ const gfx::Transform& transform) OVERRIDE;
+ virtual void SetParent(cc::Layer* parent) OVERRIDE;
+
+ // Thread-safe trigger to load resources.
+ static void PreloadResources(ui::SystemUIResourceManager* resource_manager);
+
+ private:
+ ui::SystemUIResourceManager* const resource_manager_;
+
+ scoped_refptr<cc::UIResourceLayer> glow_;
+
+ float glow_alpha_;
+ float glow_scale_y_;
+
+ float glow_alpha_start_;
+ float glow_alpha_finish_;
+ float glow_scale_y_start_;
+ float glow_scale_y_finish_;
+
+ gfx::RectF arc_rect_;
+ gfx::Size bounds_;
+ float displacement_;
+ float target_displacement_;
+
+ base::TimeTicks start_time_;
+ base::TimeDelta duration_;
+
+ State state_;
+
+ float pull_distance_;
+
+ DISALLOW_COPY_AND_ASSIGN(EdgeEffectL);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_ANDROID_EDGE_EFFECT_L_H_
diff --git a/content/browser/android/overscroll_glow.cc b/content/browser/android/overscroll_glow.cc
index 3f316d8..b3a969f 100644
--- a/content/browser/android/overscroll_glow.cc
+++ b/content/browser/android/overscroll_glow.cc
@@ -4,10 +4,8 @@
#include "content/browser/android/overscroll_glow.h"
-#include "base/debug/trace_event.h"
-#include "base/lazy_instance.h"
#include "cc/layers/layer.h"
-#include "content/browser/android/edge_effect.h"
+#include "content/browser/android/edge_effect_base.h"
using std::max;
using std::min;
@@ -17,8 +15,6 @@ namespace content {
namespace {
const float kEpsilon = 1e-3f;
-const float kEdgeHeightAtMdpi = 12.f;
-const float kGlowHeightAtMdpi = 128.f;
bool IsApproxZero(float value) {
return std::abs(value) < kEpsilon;
@@ -32,17 +28,58 @@ gfx::Vector2dF ZeroSmallComponents(gfx::Vector2dF vector) {
return vector;
}
-} // namespace
+gfx::Transform ComputeTransform(OverscrollGlow::Edge edge,
+ const gfx::SizeF& window_size,
+ float offset) {
+ // Transforms assume the edge layers are anchored to their *top center point*.
+ switch (edge) {
+ case OverscrollGlow::EDGE_TOP:
+ return gfx::Transform(1, 0, 0, 1, 0, offset);
+ case OverscrollGlow::EDGE_LEFT:
+ return gfx::Transform(0,
+ 1,
+ -1,
+ 0,
+ -window_size.height() / 2.f + offset,
+ window_size.height() / 2.f);
+ case OverscrollGlow::EDGE_BOTTOM:
+ return gfx::Transform(-1, 0, 0, -1, 0, window_size.height() + offset);
+ case OverscrollGlow::EDGE_RIGHT:
+ return gfx::Transform(
+ 0,
+ -1,
+ 1,
+ 0,
+ -window_size.height() / 2.f + window_size.width() + offset,
+ window_size.height() / 2.f);
+ default:
+ NOTREACHED() << "Invalid edge: " << edge;
+ return gfx::Transform();
+ };
+}
-scoped_ptr<OverscrollGlow> OverscrollGlow::Create(
- ui::SystemUIResourceManager* resource_manager) {
- return make_scoped_ptr(new OverscrollGlow(resource_manager));
+gfx::SizeF ComputeSize(OverscrollGlow::Edge edge,
+ const gfx::SizeF& window_size) {
+ switch (edge) {
+ case OverscrollGlow::EDGE_TOP:
+ case OverscrollGlow::EDGE_BOTTOM:
+ return window_size;
+ case OverscrollGlow::EDGE_LEFT:
+ case OverscrollGlow::EDGE_RIGHT:
+ return gfx::SizeF(window_size.height(), window_size.width());
+ default:
+ NOTREACHED() << "Invalid edge: " << edge;
+ return gfx::SizeF();
+ };
}
-OverscrollGlow::OverscrollGlow(ui::SystemUIResourceManager* resource_manager)
- : enabled_(true), initialized_(false), resource_manager_(resource_manager) {
- DCHECK(resource_manager_);
- EdgeEffect::PreloadResources(resource_manager_);
+} // namespace
+
+OverscrollGlow::OverscrollGlow(const EdgeEffectProvider& edge_effect_provider)
+ : edge_effect_provider_(edge_effect_provider),
+ enabled_(true),
+ initialized_(false) {
+ DCHECK(!edge_effect_provider_.is_null());
}
OverscrollGlow::~OverscrollGlow() {
@@ -59,7 +96,7 @@ void OverscrollGlow::Disable() {
enabled_ = false;
if (!enabled_ && initialized_) {
Detach();
- for (size_t i = 0; i < EdgeEffect::EDGE_COUNT; ++i)
+ for (size_t i = 0; i < EDGE_COUNT; ++i)
edge_effects_[i]->Finish();
}
}
@@ -68,7 +105,8 @@ bool OverscrollGlow::OnOverscrolled(cc::Layer* overscrolling_layer,
base::TimeTicks current_time,
gfx::Vector2dF accumulated_overscroll,
gfx::Vector2dF overscroll_delta,
- gfx::Vector2dF velocity) {
+ gfx::Vector2dF velocity,
+ gfx::Vector2dF displacement) {
DCHECK(overscrolling_layer);
if (!enabled_)
@@ -98,16 +136,11 @@ bool OverscrollGlow::OnOverscrolled(cc::Layer* overscrolling_layer,
bool y_overscroll_started =
!IsApproxZero(overscroll_delta.y()) && IsApproxZero(old_overscroll.y());
- if (x_overscroll_started)
- ReleaseAxis(AXIS_X, current_time);
- if (y_overscroll_started)
- ReleaseAxis(AXIS_Y, current_time);
-
velocity = ZeroSmallComponents(velocity);
if (!velocity.IsZero())
Absorb(current_time, velocity, x_overscroll_started, y_overscroll_started);
else
- Pull(current_time, overscroll_delta);
+ Pull(current_time, overscroll_delta, displacement);
UpdateLayerAttachment(overscrolling_layer);
return NeedsAnimate();
@@ -119,14 +152,13 @@ bool OverscrollGlow::Animate(base::TimeTicks current_time) {
return false;
}
- for (size_t i = 0; i < EdgeEffect::EDGE_COUNT; ++i) {
+ for (size_t i = 0; i < EDGE_COUNT; ++i) {
if (edge_effects_[i]->Update(current_time)) {
+ Edge edge = static_cast<Edge>(i);
edge_effects_[i]->ApplyToLayers(
- display_params_.size,
- static_cast<EdgeEffect::Edge>(i),
- kEdgeHeightAtMdpi * display_params_.device_scale_factor,
- kGlowHeightAtMdpi * display_params_.device_scale_factor,
- display_params_.edge_offsets[i]);
+ ComputeSize(edge, display_params_.size),
+ ComputeTransform(
+ edge, display_params_.size, display_params_.edge_offsets[i]));
}
}
@@ -145,7 +177,7 @@ void OverscrollGlow::UpdateDisplayParameters(const DisplayParameters& params) {
bool OverscrollGlow::NeedsAnimate() const {
if (!enabled_ || !initialized_)
return false;
- for (size_t i = 0; i < EdgeEffect::EDGE_COUNT; ++i) {
+ for (size_t i = 0; i < EDGE_COUNT; ++i) {
if (!edge_effects_[i]->IsFinished())
return true;
}
@@ -165,7 +197,7 @@ void OverscrollGlow::UpdateLayerAttachment(cc::Layer* parent) {
if (root_layer_->parent() != parent)
parent->AddChild(root_layer_);
- for (size_t i = 0; i < EdgeEffect::EDGE_COUNT; ++i)
+ for (size_t i = 0; i < EDGE_COUNT; ++i)
edge_effects_[i]->SetParent(root_layer_);
}
@@ -181,57 +213,69 @@ bool OverscrollGlow::InitializeIfNecessary() {
DCHECK(!root_layer_);
root_layer_ = cc::Layer::Create();
- for (size_t i = 0; i < EdgeEffect::EDGE_COUNT; ++i)
- edge_effects_[i] = make_scoped_ptr(new EdgeEffect(resource_manager_));
+ for (size_t i = 0; i < EDGE_COUNT; ++i) {
+ edge_effects_[i] = edge_effect_provider_.Run();
+ DCHECK(edge_effects_[i]);
+ }
initialized_ = true;
return true;
}
void OverscrollGlow::Pull(base::TimeTicks current_time,
- gfx::Vector2dF overscroll_delta) {
+ const gfx::Vector2dF& overscroll_delta,
+ const gfx::Vector2dF& overscroll_location) {
DCHECK(enabled_ && initialized_);
- overscroll_delta = ZeroSmallComponents(overscroll_delta);
- if (overscroll_delta.IsZero())
- return;
+ DCHECK(!overscroll_delta.IsZero());
+ const float inv_width = 1.f / display_params_.size.width();
+ const float inv_height = 1.f / display_params_.size.height();
gfx::Vector2dF overscroll_pull =
- gfx::ScaleVector2d(overscroll_delta,
- 1.f / display_params_.size.width(),
- 1.f / display_params_.size.height());
- float edge_overscroll_pull[EdgeEffect::EDGE_COUNT] = {
+ gfx::ScaleVector2d(overscroll_delta, inv_width, inv_height);
+ const float edge_pull[EDGE_COUNT] = {
min(overscroll_pull.y(), 0.f), // Top
min(overscroll_pull.x(), 0.f), // Left
max(overscroll_pull.y(), 0.f), // Bottom
max(overscroll_pull.x(), 0.f) // Right
};
- for (size_t i = 0; i < EdgeEffect::EDGE_COUNT; ++i) {
- if (!edge_overscroll_pull[i])
+ gfx::Vector2dF displacement =
+ gfx::ScaleVector2d(overscroll_location, inv_width, inv_height);
+ displacement.set_x(max(0.f, min(1.f, displacement.x())));
+ displacement.set_y(max(0.f, min(1.f, displacement.y())));
+ const float edge_displacement[EDGE_COUNT] = {
+ 1.f - displacement.x(), // Top
+ displacement.y(), // Left
+ displacement.x(), // Bottom
+ 1.f - displacement.y() // Right
+ };
+
+ for (size_t i = 0; i < EDGE_COUNT; ++i) {
+ if (!edge_pull[i])
continue;
- edge_effects_[i]->Pull(current_time, std::abs(edge_overscroll_pull[i]));
+ edge_effects_[i]->Pull(
+ current_time, std::abs(edge_pull[i]), edge_displacement[i]);
GetOppositeEdge(i)->Release(current_time);
}
}
void OverscrollGlow::Absorb(base::TimeTicks current_time,
- gfx::Vector2dF velocity,
+ const gfx::Vector2dF& velocity,
bool x_overscroll_started,
bool y_overscroll_started) {
DCHECK(enabled_ && initialized_);
- if (velocity.IsZero())
- return;
+ DCHECK(!velocity.IsZero());
// Only trigger on initial overscroll at a non-zero velocity
- const float overscroll_velocities[EdgeEffect::EDGE_COUNT] = {
+ const float overscroll_velocities[EDGE_COUNT] = {
y_overscroll_started ? min(velocity.y(), 0.f) : 0, // Top
x_overscroll_started ? min(velocity.x(), 0.f) : 0, // Left
y_overscroll_started ? max(velocity.y(), 0.f) : 0, // Bottom
x_overscroll_started ? max(velocity.x(), 0.f) : 0 // Right
};
- for (size_t i = 0; i < EdgeEffect::EDGE_COUNT; ++i) {
+ for (size_t i = 0; i < EDGE_COUNT; ++i) {
if (!overscroll_velocities[i])
continue;
@@ -242,31 +286,16 @@ void OverscrollGlow::Absorb(base::TimeTicks current_time,
void OverscrollGlow::Release(base::TimeTicks current_time) {
DCHECK(initialized_);
- for (size_t i = 0; i < EdgeEffect::EDGE_COUNT; ++i)
+ for (size_t i = 0; i < EDGE_COUNT; ++i)
edge_effects_[i]->Release(current_time);
}
-void OverscrollGlow::ReleaseAxis(Axis axis, base::TimeTicks current_time) {
- DCHECK(initialized_);
- switch (axis) {
- case AXIS_X:
- edge_effects_[EdgeEffect::EDGE_LEFT]->Release(current_time);
- edge_effects_[EdgeEffect::EDGE_RIGHT]->Release(current_time);
- break;
- case AXIS_Y:
- edge_effects_[EdgeEffect::EDGE_TOP]->Release(current_time);
- edge_effects_[EdgeEffect::EDGE_BOTTOM]->Release(current_time);
- break;
- };
-}
-
-EdgeEffect* OverscrollGlow::GetOppositeEdge(int edge_index) {
+EdgeEffectBase* OverscrollGlow::GetOppositeEdge(int edge_index) {
DCHECK(initialized_);
- return edge_effects_[(edge_index + 2) % EdgeEffect::EDGE_COUNT].get();
+ return edge_effects_[(edge_index + 2) % EDGE_COUNT].get();
}
-OverscrollGlow::DisplayParameters::DisplayParameters()
- : device_scale_factor(1) {
+OverscrollGlow::DisplayParameters::DisplayParameters() {
edge_offsets[0] = edge_offsets[1] = edge_offsets[2] = edge_offsets[3] = 0.f;
}
diff --git a/content/browser/android/overscroll_glow.h b/content/browser/android/overscroll_glow.h
index 7500940..878d39a 100644
--- a/content/browser/android/overscroll_glow.h
+++ b/content/browser/android/overscroll_glow.h
@@ -5,32 +5,36 @@
#ifndef CONTENT_BROWSER_ANDROID_OVERSCROLL_GLOW_H_
#define CONTENT_BROWSER_ANDROID_OVERSCROLL_GLOW_H_
+#include "base/callback.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/time/time.h"
-#include "content/browser/android/edge_effect.h"
#include "ui/gfx/size_f.h"
#include "ui/gfx/vector2d_f.h"
-class SkBitmap;
-
-namespace ui {
-class SystemUIResourceManager;
+namespace cc {
+class Layer;
}
namespace content {
+class EdgeEffectBase;
+
/* |OverscrollGlow| mirrors its Android counterpart, OverscrollGlow.java.
* Conscious tradeoffs were made to align this as closely as possible with the
* original Android Java version.
*/
class OverscrollGlow {
public:
- // Create a new effect. |resource_manager| provides the resource for the
- // effect. |resource_manager| must outlive the effect. The effect is
- // activated by default.
- static scoped_ptr<OverscrollGlow> Create(
- ui::SystemUIResourceManager* resource_manager);
+ enum Edge { EDGE_TOP = 0, EDGE_LEFT, EDGE_BOTTOM, EDGE_RIGHT, EDGE_COUNT };
+
+ // Allows lazy creation of the edge effects.
+ typedef base::Callback<scoped_ptr<EdgeEffectBase>(void)> EdgeEffectProvider;
+
+ // |edge_effect_provider| must be valid for the duration of the effect's
+ // lifetime. The effect is enabled by default, but will remain dormant until
+ // the first overscroll event.
+ explicit OverscrollGlow(const EdgeEffectProvider& edge_effect_provider);
~OverscrollGlow();
@@ -50,7 +54,8 @@ class OverscrollGlow {
base::TimeTicks current_time,
gfx::Vector2dF accumulated_overscroll,
gfx::Vector2dF overscroll_delta,
- gfx::Vector2dF velocity);
+ gfx::Vector2dF velocity,
+ gfx::Vector2dF overscroll_location);
// Returns true if the effect still needs animation ticks.
// Note: The effect will detach itself when no further animation is required.
@@ -61,40 +66,37 @@ class OverscrollGlow {
struct DisplayParameters {
DisplayParameters();
gfx::SizeF size;
- float edge_offsets[EdgeEffect::EDGE_COUNT];
- float device_scale_factor;
+ float edge_offsets[EDGE_COUNT];
};
void UpdateDisplayParameters(const DisplayParameters& params);
-
private:
enum Axis { AXIS_X, AXIS_Y };
- explicit OverscrollGlow(ui::SystemUIResourceManager* resource_manager);
-
// Returns whether the effect is initialized.
bool InitializeIfNecessary();
bool NeedsAnimate() const;
void UpdateLayerAttachment(cc::Layer* parent);
void Detach();
- void Pull(base::TimeTicks current_time, gfx::Vector2dF overscroll_delta);
+ void Pull(base::TimeTicks current_time,
+ const gfx::Vector2dF& overscroll_delta,
+ const gfx::Vector2dF& overscroll_location);
void Absorb(base::TimeTicks current_time,
- gfx::Vector2dF velocity,
+ const gfx::Vector2dF& velocity,
bool x_overscroll_started,
bool y_overscroll_started);
void Release(base::TimeTicks current_time);
- void ReleaseAxis(Axis axis, base::TimeTicks current_time);
- EdgeEffect* GetOppositeEdge(int edge_index);
+ EdgeEffectBase* GetOppositeEdge(int edge_index);
- scoped_ptr<EdgeEffect> edge_effects_[EdgeEffect::EDGE_COUNT];
+ EdgeEffectProvider edge_effect_provider_;
+ scoped_ptr<EdgeEffectBase> edge_effects_[EDGE_COUNT];
DisplayParameters display_params_;
bool enabled_;
bool initialized_;
scoped_refptr<cc::Layer> root_layer_;
- ui::SystemUIResourceManager* resource_manager_;
DISALLOW_COPY_AND_ASSIGN(OverscrollGlow);
};
diff --git a/content/browser/android/system_ui_resource_manager_impl.cc b/content/browser/android/system_ui_resource_manager_impl.cc
index 1093968..80c1c43 100644
--- a/content/browser/android/system_ui_resource_manager_impl.cc
+++ b/content/browser/android/system_ui_resource_manager_impl.cc
@@ -6,6 +6,7 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
+#include "base/debug/trace_event.h"
#include "base/location.h"
#include "base/observer_list.h"
#include "base/threading/worker_pool.h"
@@ -13,9 +14,68 @@
#include "content/public/browser/android/ui_resource_client_android.h"
#include "content/public/browser/android/ui_resource_provider.h"
#include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkPaint.h"
+#include "third_party/skia/include/effects/SkPorterDuff.h"
#include "ui/gfx/android/java_bitmap.h"
+#include "ui/gfx/screen.h"
namespace content {
+namespace {
+
+SkBitmap CreateOverscrollGlowLBitmap(const gfx::Size& screen_size) {
+ const float kSin = 0.5f; // sin(PI / 6)
+ const float kCos = 0.866f; // cos(PI / 6);
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setAlpha(0x33);
+ paint.setStyle(SkPaint::kFill_Style);
+
+ const float arc_width =
+ std::min(screen_size.width(), screen_size.height()) * 0.5f / kSin;
+ const float y = kCos * arc_width;
+ const float height = arc_width - y;
+ gfx::Size bounds(arc_width, height);
+ SkRect arc_rect = SkRect::MakeXYWH(
+ -arc_width / 2.f, -arc_width - y, arc_width * 2.f, arc_width * 2.f);
+ SkBitmap glow_bitmap;
+ if (!glow_bitmap.allocPixels(
+ SkImageInfo::MakeA8(bounds.width(), bounds.height()))) {
+ LOG(FATAL) << " Failed to allocate bitmap of size " << bounds.width() << "x"
+ << bounds.height();
+ }
+
+ SkCanvas canvas(glow_bitmap);
+ canvas.clipRect(SkRect::MakeXYWH(0, 0, bounds.width(), bounds.height()));
+ canvas.drawArc(arc_rect, 45, 90, true, paint);
+ return glow_bitmap;
+}
+
+void LoadBitmap(ui::SystemUIResourceManager::ResourceType type,
+ SkBitmap* bitmap_holder,
+ const gfx::Size& screen_size) {
+ TRACE_EVENT1(
+ "browser", "SystemUIResourceManagerImpl::LoadBitmap", "type", type);
+ SkBitmap bitmap;
+ switch (type) {
+ case ui::SystemUIResourceManager::OVERSCROLL_EDGE:
+ bitmap = gfx::CreateSkBitmapFromAndroidResource(
+ "android:drawable/overscroll_edge", gfx::Size(128, 12));
+ break;
+ case ui::SystemUIResourceManager::OVERSCROLL_GLOW:
+ bitmap = gfx::CreateSkBitmapFromAndroidResource(
+ "android:drawable/overscroll_glow", gfx::Size(128, 64));
+ break;
+ case ui::SystemUIResourceManager::OVERSCROLL_GLOW_L:
+ bitmap = CreateOverscrollGlowLBitmap(screen_size);
+ break;
+ }
+ bitmap.setImmutable();
+ *bitmap_holder = bitmap;
+}
+
+} // namespace
class SystemUIResourceManagerImpl::Entry
: public content::UIResourceClientAndroid {
@@ -31,8 +91,7 @@ class SystemUIResourceManagerImpl::Entry
}
void SetBitmap(const SkBitmap& bitmap) {
- // TODO(jdduke): Verify validity of |bitmap| after resolving resource
- // loading issues on Android L, crbug.com/389744.
+ DCHECK(!bitmap.empty());
DCHECK(bitmap_.empty());
DCHECK(!id_);
bitmap_ = bitmap;
@@ -100,8 +159,10 @@ void SystemUIResourceManagerImpl::BuildResource(ResourceType type) {
// Instead of blocking the main thread, we post a task to load the bitmap.
SkBitmap* bitmap = new SkBitmap();
+ gfx::Size screen_size =
+ gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().GetSizeInPixel();
base::Closure load_bitmap =
- base::Bind(&SystemUIResourceManagerImpl::LoadBitmap, type, bitmap);
+ base::Bind(&LoadBitmap, type, bitmap, screen_size);
base::Closure finished_load =
base::Bind(&SystemUIResourceManagerImpl::OnFinishedLoadBitmap,
weak_factory_.GetWeakPtr(),
@@ -111,23 +172,6 @@ void SystemUIResourceManagerImpl::BuildResource(ResourceType type) {
FROM_HERE, load_bitmap, finished_load, true);
}
-void SystemUIResourceManagerImpl::LoadBitmap(ResourceType type,
- SkBitmap* bitmap_holder) {
- SkBitmap bitmap;
- switch (type) {
- case ui::SystemUIResourceManager::OVERSCROLL_EDGE:
- bitmap = gfx::CreateSkBitmapFromAndroidResource(
- "android:drawable/overscroll_edge", gfx::Size(128, 12));
- break;
- case ui::SystemUIResourceManager::OVERSCROLL_GLOW:
- bitmap = gfx::CreateSkBitmapFromAndroidResource(
- "android:drawable/overscroll_glow", gfx::Size(128, 64));
- break;
- }
- bitmap.setImmutable();
- *bitmap_holder = bitmap;
-}
-
void SystemUIResourceManagerImpl::OnFinishedLoadBitmap(
ResourceType type,
SkBitmap* bitmap_holder) {
diff --git a/content/browser/android/system_ui_resource_manager_impl.h b/content/browser/android/system_ui_resource_manager_impl.h
index c5792a1..277f9f0 100644
--- a/content/browser/android/system_ui_resource_manager_impl.h
+++ b/content/browser/android/system_ui_resource_manager_impl.h
@@ -39,7 +39,6 @@ class CONTENT_EXPORT SystemUIResourceManagerImpl
virtual void BuildResource(ResourceType type);
Entry* GetEntry(ResourceType type);
- static void LoadBitmap(ResourceType, SkBitmap* bitmap_holder);
void OnFinishedLoadBitmap(ResourceType, SkBitmap* bitmap_holder);
scoped_ptr<Entry> resource_map_[RESOURCE_TYPE_LAST + 1];
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc
index 00c4259..613fca9 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.cc
+++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -6,6 +6,7 @@
#include <android/bitmap.h>
+#include "base/android/build_info.h"
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/callback_helpers.h"
@@ -29,6 +30,8 @@
#include "content/browser/accessibility/browser_accessibility_manager_android.h"
#include "content/browser/android/composited_touch_handle_drawable.h"
#include "content/browser/android/content_view_core_impl.h"
+#include "content/browser/android/edge_effect.h"
+#include "content/browser/android/edge_effect_l.h"
#include "content/browser/android/in_process/synchronous_compositor_impl.h"
#include "content/browser/android/overscroll_glow.h"
#include "content/browser/devtools/render_view_devtools_agent_host.h"
@@ -83,6 +86,9 @@ const int kUndefinedOutputSurfaceId = -1;
// V1 saw errors of ~0.065 between computed window and content widths.
const float kMobileViewportWidthEpsilon = 0.15f;
+// Used for conditional creation of EdgeEffect types for overscroll.
+const int kKitKatMR2SDKVersion = 19;
+
static const char kAsyncReadBackString[] = "Compositing.CopyFromSurfaceTime";
// Sends an acknowledgement to the renderer of a processed IME event.
@@ -133,23 +139,61 @@ OverscrollGlow::DisplayParameters CreateOverscrollDisplayParameters(
OverscrollGlow::DisplayParameters params;
params.size = gfx::ScaleSize(
frame_metadata.scrollable_viewport_size, scale_factor);
- params.edge_offsets[EdgeEffect::EDGE_TOP] =
+ params.edge_offsets[OverscrollGlow::EDGE_TOP] =
-frame_metadata.root_scroll_offset.y() * scale_factor;
- params.edge_offsets[EdgeEffect::EDGE_LEFT] =
+ params.edge_offsets[OverscrollGlow::EDGE_LEFT] =
-frame_metadata.root_scroll_offset.x() * scale_factor;
- params.edge_offsets[EdgeEffect::EDGE_BOTTOM] =
+ params.edge_offsets[OverscrollGlow::EDGE_BOTTOM] =
(frame_metadata.root_layer_size.height() -
frame_metadata.root_scroll_offset.y() -
- frame_metadata.scrollable_viewport_size.height()) * scale_factor;
- params.edge_offsets[EdgeEffect::EDGE_RIGHT] =
+ frame_metadata.scrollable_viewport_size.height()) *
+ scale_factor;
+ params.edge_offsets[OverscrollGlow::EDGE_RIGHT] =
(frame_metadata.root_layer_size.width() -
frame_metadata.root_scroll_offset.x() -
- frame_metadata.scrollable_viewport_size.width()) * scale_factor;
- params.device_scale_factor = frame_metadata.device_scale_factor;
+ frame_metadata.scrollable_viewport_size.width()) *
+ scale_factor;
return params;
}
+bool UseEdgeEffectL() {
+ static bool use_edge_effect_l =
+ base::android::BuildInfo::GetInstance()->sdk_int() > kKitKatMR2SDKVersion;
+ return use_edge_effect_l;
+}
+
+scoped_ptr<EdgeEffectBase> CreateEdgeEffect(
+ ui::SystemUIResourceManager* resource_manager,
+ float device_scale_factor) {
+ DCHECK(resource_manager);
+ if (UseEdgeEffectL())
+ return scoped_ptr<EdgeEffectBase>(new EdgeEffectL(resource_manager));
+
+ return scoped_ptr<EdgeEffectBase>(
+ new EdgeEffect(resource_manager, device_scale_factor));
+}
+
+scoped_ptr<OverscrollGlow> CreateOverscrollEffect(
+ ContentViewCore* content_view_core) {
+ DCHECK(content_view_core);
+ ui::WindowAndroidCompositor* compositor =
+ content_view_core->GetWindowAndroid()->GetCompositor();
+ DCHECK(compositor);
+ ui::SystemUIResourceManager* system_resource_manager =
+ &compositor->GetSystemUIResourceManager();
+
+ if (UseEdgeEffectL())
+ EdgeEffectL::PreloadResources(system_resource_manager);
+ else
+ EdgeEffect::PreloadResources(system_resource_manager);
+
+ return make_scoped_ptr(
+ new OverscrollGlow(base::Bind(&CreateEdgeEffect,
+ system_resource_manager,
+ content_view_core->GetDpiScale())));
+}
+
ui::GestureProvider::Config CreateGestureProviderConfig() {
ui::GestureProvider::Config config = ui::DefaultGestureProviderConfig();
config.disable_click_delay =
@@ -1237,6 +1281,13 @@ void RenderWidgetHostViewAndroid::ProcessAckedTouchEvent(
void RenderWidgetHostViewAndroid::GestureEventAck(
const blink::WebGestureEvent& event,
InputEventAckState ack_result) {
+ // The overscroll effect requires an explicit release signal that may not be
+ // sent from the renderer compositor.
+ if (event.type == blink::WebInputEvent::GestureScrollEnd ||
+ event.type == blink::WebInputEvent::GestureFlingStart) {
+ DidOverscroll(DidOverscrollParams());
+ }
+
switch (event.type) {
case blink::WebInputEvent::GestureScrollBegin:
touch_scrolling_ = true;
@@ -1424,7 +1475,10 @@ void RenderWidgetHostViewAndroid::DidOverscroll(
gfx::ScaleVector2d(params.latest_overscroll_delta,
device_scale_factor),
gfx::ScaleVector2d(params.current_fling_velocity,
- device_scale_factor))) {
+ device_scale_factor),
+ gfx::ScaleVector2d(
+ params.causal_event_viewport_point.OffsetFromOrigin(),
+ device_scale_factor))) {
SetNeedsAnimate();
}
}
@@ -1484,15 +1538,10 @@ void RenderWidgetHostViewAndroid::SetContentViewCore(
if (!selection_controller_)
selection_controller_.reset(new TouchSelectionController(this));
- if (!content_view_core_) {
+ if (!content_view_core_)
overscroll_effect_.reset();
- } else if (overscroll_effect_enabled_ && !overscroll_effect_) {
- DCHECK(content_view_core_->GetWindowAndroid()->GetCompositor());
- overscroll_effect_ =
- OverscrollGlow::Create(&content_view_core_->GetWindowAndroid()
- ->GetCompositor()
- ->GetSystemUIResourceManager());
- }
+ else if (overscroll_effect_enabled_ && !overscroll_effect_)
+ overscroll_effect_ = CreateOverscrollEffect(content_view_core_);
}
void RenderWidgetHostViewAndroid::RunAckCallbacks() {
diff --git a/content/browser/renderer_host/render_widget_host_view_android.h b/content/browser/renderer_host/render_widget_host_view_android.h
index 91f9d48..7601adc 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.h
+++ b/content/browser/renderer_host/render_widget_host_view_android.h
@@ -343,9 +343,6 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
// The most recent content size that was pushed to the texture layer.
gfx::Size content_size_in_layer_;
- // The device scale of the last received frame.
- float device_scale_factor_;
-
// The output surface id of the last received frame.
uint32_t last_output_surface_id_;
diff --git a/content/common/input/did_overscroll_params.cc b/content/common/input/did_overscroll_params.cc
new file mode 100644
index 0000000..2b69d86
--- /dev/null
+++ b/content/common/input/did_overscroll_params.cc
@@ -0,0 +1,15 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/common/input/did_overscroll_params.h"
+
+namespace content {
+
+DidOverscrollParams::DidOverscrollParams() {
+}
+
+DidOverscrollParams::~DidOverscrollParams() {
+}
+
+} // namespace content
diff --git a/content/common/input/did_overscroll_params.h b/content/common/input/did_overscroll_params.h
index 4f6a7f1..7db3ac4 100644
--- a/content/common/input/did_overscroll_params.h
+++ b/content/common/input/did_overscroll_params.h
@@ -5,14 +5,19 @@
#ifndef CONTENT_COMMON_INPUT_DID_OVERSCROLL_PARAMS_H_
#define CONTENT_COMMON_INPUT_DID_OVERSCROLL_PARAMS_H_
+#include "content/common/content_export.h"
+#include "ui/gfx/geometry/point_f.h"
#include "ui/gfx/geometry/vector2d_f.h"
namespace content {
-struct DidOverscrollParams {
+struct CONTENT_EXPORT DidOverscrollParams {
+ DidOverscrollParams();
+ ~DidOverscrollParams();
gfx::Vector2dF accumulated_overscroll;
gfx::Vector2dF latest_overscroll_delta;
gfx::Vector2dF current_fling_velocity;
+ gfx::PointF causal_event_viewport_point;
};
} // namespace content
diff --git a/content/common/input_messages.h b/content/common/input_messages.h
index d00d45d..1827212 100644
--- a/content/common/input_messages.h
+++ b/content/common/input_messages.h
@@ -59,6 +59,7 @@ IPC_STRUCT_TRAITS_BEGIN(content::DidOverscrollParams)
IPC_STRUCT_TRAITS_MEMBER(accumulated_overscroll)
IPC_STRUCT_TRAITS_MEMBER(latest_overscroll_delta)
IPC_STRUCT_TRAITS_MEMBER(current_fling_velocity)
+ IPC_STRUCT_TRAITS_MEMBER(causal_event_viewport_point)
IPC_STRUCT_TRAITS_END()
IPC_STRUCT_TRAITS_BEGIN(content::EditCommand)
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index 97454ed..84ff880 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -295,6 +295,8 @@
'browser/android/devtools_auth.cc',
'browser/android/edge_effect.cc',
'browser/android/edge_effect.h',
+ 'browser/android/edge_effect_l.cc',
+ 'browser/android/edge_effect_l.h',
'browser/android/gesture_event_type_list.h',
'browser/android/in_process/synchronous_compositor_factory_impl.cc',
'browser/android/in_process/synchronous_compositor_factory_impl.h',
diff --git a/content/content_common.gypi b/content/content_common.gypi
index 6c8c35b..048ab0d 100644
--- a/content/content_common.gypi
+++ b/content/content_common.gypi
@@ -335,6 +335,7 @@
'common/indexed_db/indexed_db_messages.h',
'common/indexed_db/indexed_db_param_traits.cc',
'common/indexed_db/indexed_db_param_traits.h',
+ 'common/input/did_overscroll_params.cc',
'common/input/did_overscroll_params.h',
'common/input/gesture_event_stream_validator.cc',
'common/input/gesture_event_stream_validator.h',
diff --git a/content/renderer/input/input_event_filter.cc b/content/renderer/input/input_event_filter.cc
index fa31658..5017cb4 100644
--- a/content/renderer/input/input_event_filter.cc
+++ b/content/renderer/input/input_event_filter.cc
@@ -164,12 +164,14 @@ void InputEventFilter::ForwardToHandler(const IPC::Message& message) {
bool is_keyboard_shortcut = params.c;
DCHECK(event);
+ const bool send_ack = !WebInputEventTraits::IgnoresAckDisposition(*event);
+
// Intercept |DidOverscroll| notifications, bundling any triggered overscroll
// response with the input event ack.
scoped_ptr<DidOverscrollParams> overscroll_params;
base::AutoReset<scoped_ptr<DidOverscrollParams>*>
- auto_reset_current_overscroll_params(&current_overscroll_params_,
- &overscroll_params);
+ auto_reset_current_overscroll_params(
+ &current_overscroll_params_, send_ack ? &overscroll_params : NULL);
InputEventAckState ack_state = handler_.Run(routing_id, event, &latency_info);
@@ -188,7 +190,7 @@ void InputEventFilter::ForwardToHandler(const IPC::Message& message) {
return;
}
- if (WebInputEventTraits::IgnoresAckDisposition(*event))
+ if (!send_ack)
return;
InputHostMsg_HandleInputEvent_ACK_Params ack;
diff --git a/content/renderer/input/input_handler_proxy.cc b/content/renderer/input/input_handler_proxy.cc
index ba938b8..6970d22 100644
--- a/content/renderer/input/input_handler_proxy.cc
+++ b/content/renderer/input/input_handler_proxy.cc
@@ -643,6 +643,7 @@ void InputHandlerProxy::MainThreadHasStoppedFlinging() {
}
void InputHandlerProxy::DidOverscroll(
+ const gfx::PointF& causal_event_viewport_point,
const gfx::Vector2dF& accumulated_overscroll,
const gfx::Vector2dF& latest_overscroll_delta) {
DCHECK(client_);
@@ -659,6 +660,7 @@ void InputHandlerProxy::DidOverscroll(
params.latest_overscroll_delta = latest_overscroll_delta;
params.current_fling_velocity =
ToClientScrollIncrement(current_fling_velocity_);
+ params.causal_event_viewport_point = causal_event_viewport_point;
if (fling_curve_) {
static const int kFlingOverscrollThreshold = 1;
diff --git a/content/renderer/input/input_handler_proxy.h b/content/renderer/input/input_handler_proxy.h
index 8acc09c..c5f7897 100644
--- a/content/renderer/input/input_handler_proxy.h
+++ b/content/renderer/input/input_handler_proxy.h
@@ -45,9 +45,10 @@ class CONTENT_EXPORT InputHandlerProxy
virtual void WillShutdown() OVERRIDE;
virtual void Animate(base::TimeTicks time) OVERRIDE;
virtual void MainThreadHasStoppedFlinging() OVERRIDE;
- virtual void DidOverscroll(const gfx::Vector2dF& accumulated_overscroll,
- const gfx::Vector2dF& latest_overscroll_delta)
- OVERRIDE;
+ virtual void DidOverscroll(
+ const gfx::PointF& causal_event_viewport_point,
+ const gfx::Vector2dF& accumulated_overscroll,
+ const gfx::Vector2dF& latest_overscroll_delta) OVERRIDE;
// blink::WebGestureCurveTarget implementation.
virtual bool scrollBy(const blink::WebFloatSize& offset,
diff --git a/content/renderer/input/input_handler_proxy_unittest.cc b/content/renderer/input/input_handler_proxy_unittest.cc
index d9ca67c..a2da06c 100644
--- a/content/renderer/input/input_handler_proxy_unittest.cc
+++ b/content/renderer/input/input_handler_proxy_unittest.cc
@@ -1208,17 +1208,20 @@ TEST_F(InputHandlerProxyTest, GestureFlingStopsAtContentEdge) {
// Simulate hitting the bottom content edge.
gfx::Vector2dF accumulated_overscroll(0, 100);
gfx::Vector2dF latest_overscroll_delta(0, 10);
- EXPECT_CALL(mock_client_,
- DidOverscroll(testing::AllOf(
- testing::Field(&DidOverscrollParams::accumulated_overscroll,
- testing::Eq(accumulated_overscroll)),
- testing::Field(&DidOverscrollParams::latest_overscroll_delta,
- testing::Eq(latest_overscroll_delta)),
- testing::Field(
- &DidOverscrollParams::current_fling_velocity,
- testing::Property(&gfx::Vector2dF::y, testing::Lt(0))))));
- input_handler_->DidOverscroll(accumulated_overscroll,
- latest_overscroll_delta);
+ gfx::PointF scroll_point(10, 0);
+ EXPECT_CALL(
+ mock_client_,
+ DidOverscroll(testing::AllOf(
+ testing::Field(&DidOverscrollParams::accumulated_overscroll,
+ testing::Eq(accumulated_overscroll)),
+ testing::Field(&DidOverscrollParams::latest_overscroll_delta,
+ testing::Eq(latest_overscroll_delta)),
+ testing::Field(&DidOverscrollParams::current_fling_velocity,
+ testing::Property(&gfx::Vector2dF::y, testing::Lt(0))),
+ testing::Field(&DidOverscrollParams::causal_event_viewport_point,
+ testing::Eq(scroll_point)))));
+ input_handler_->DidOverscroll(
+ scroll_point, accumulated_overscroll, latest_overscroll_delta);
// The next call to animate will no longer scroll vertically.
EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
@@ -1354,17 +1357,20 @@ TEST_F(InputHandlerProxyTest, GestureFlingCancelledAfterBothAxesStopScrolling) {
// Simulate hitting the bottom content edge.
gfx::Vector2dF accumulated_overscroll(0, 100);
gfx::Vector2dF latest_overscroll_delta(0, 100);
- EXPECT_CALL(mock_client_,
- DidOverscroll(testing::AllOf(
- testing::Field(&DidOverscrollParams::accumulated_overscroll,
- testing::Eq(accumulated_overscroll)),
- testing::Field(&DidOverscrollParams::latest_overscroll_delta,
- testing::Eq(latest_overscroll_delta)),
- testing::Field(
- &DidOverscrollParams::current_fling_velocity,
- testing::Property(&gfx::Vector2dF::y, testing::Lt(0))))));
- input_handler_->DidOverscroll(accumulated_overscroll,
- latest_overscroll_delta);
+ gfx::PointF scroll_point(10, -50);
+ EXPECT_CALL(
+ mock_client_,
+ DidOverscroll(testing::AllOf(
+ testing::Field(&DidOverscrollParams::accumulated_overscroll,
+ testing::Eq(accumulated_overscroll)),
+ testing::Field(&DidOverscrollParams::latest_overscroll_delta,
+ testing::Eq(latest_overscroll_delta)),
+ testing::Field(&DidOverscrollParams::current_fling_velocity,
+ testing::Property(&gfx::Vector2dF::y, testing::Lt(0))),
+ testing::Field(&DidOverscrollParams::causal_event_viewport_point,
+ testing::Eq(scroll_point)))));
+ input_handler_->DidOverscroll(
+ scroll_point, accumulated_overscroll, latest_overscroll_delta);
// The next call to animate will no longer scroll vertically.
EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
@@ -1379,17 +1385,20 @@ TEST_F(InputHandlerProxyTest, GestureFlingCancelledAfterBothAxesStopScrolling) {
// Simulate hitting the right content edge.
accumulated_overscroll = gfx::Vector2dF(100, 100);
latest_overscroll_delta = gfx::Vector2dF(100, 0);
- EXPECT_CALL(mock_client_,
- DidOverscroll(testing::AllOf(
- testing::Field(&DidOverscrollParams::accumulated_overscroll,
- testing::Eq(accumulated_overscroll)),
- testing::Field(&DidOverscrollParams::latest_overscroll_delta,
- testing::Eq(latest_overscroll_delta)),
- testing::Field(
- &DidOverscrollParams::current_fling_velocity,
- testing::Property(&gfx::Vector2dF::x, testing::Lt(0))))));
- input_handler_->DidOverscroll(accumulated_overscroll,
- latest_overscroll_delta);
+ scroll_point = gfx::PointF(50, 0);
+ EXPECT_CALL(
+ mock_client_,
+ DidOverscroll(testing::AllOf(
+ testing::Field(&DidOverscrollParams::accumulated_overscroll,
+ testing::Eq(accumulated_overscroll)),
+ testing::Field(&DidOverscrollParams::latest_overscroll_delta,
+ testing::Eq(latest_overscroll_delta)),
+ testing::Field(&DidOverscrollParams::current_fling_velocity,
+ testing::Property(&gfx::Vector2dF::x, testing::Lt(0))),
+ testing::Field(&DidOverscrollParams::causal_event_viewport_point,
+ testing::Eq(scroll_point)))));
+ input_handler_->DidOverscroll(
+ scroll_point, accumulated_overscroll, latest_overscroll_delta);
// The next call to animate will no longer scroll horizontally or vertically,
// and the fling should be cancelled.
EXPECT_CALL(mock_input_handler_, SetNeedsAnimate()).Times(0);
diff --git a/ui/base/android/system_ui_resource_manager.h b/ui/base/android/system_ui_resource_manager.h
index 03a112d..e1b2edfa 100644
--- a/ui/base/android/system_ui_resource_manager.h
+++ b/ui/base/android/system_ui_resource_manager.h
@@ -16,8 +16,9 @@ class UI_BASE_EXPORT SystemUIResourceManager {
enum ResourceType {
OVERSCROLL_EDGE = 0,
OVERSCROLL_GLOW,
+ OVERSCROLL_GLOW_L,
RESOURCE_TYPE_FIRST = OVERSCROLL_EDGE,
- RESOURCE_TYPE_LAST = OVERSCROLL_GLOW
+ RESOURCE_TYPE_LAST = OVERSCROLL_GLOW_L
};
virtual ~SystemUIResourceManager() {}