diff options
author | jdduke@chromium.org <jdduke@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-08-15 23:38:24 +0000 |
---|---|---|
committer | jdduke@chromium.org <jdduke@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-08-15 23:38:24 +0000 |
commit | 611f300744675e72623d2814e6df70f051e4f185 (patch) | |
tree | 018ab2fad4698371d81381146def0a25f6a7fb05 | |
parent | d781d7cec694108e53c3ce069f5c500e6cb6326c (diff) | |
download | chromium_src-611f300744675e72623d2814e6df70f051e4f185.zip chromium_src-611f300744675e72623d2814e6df70f051e4f185.tar.gz chromium_src-611f300744675e72623d2814e6df70f051e4f185.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
Review URL: https://codereview.chromium.org/367173003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@290052 0039d316-1c4b-4281-b951-d872f2087c98
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 05ca36b1..aeaf7fb 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(¤t_overscroll_params_, - &overscroll_params); + auto_reset_current_overscroll_params( + ¤t_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() {} |