summaryrefslogtreecommitdiffstats
path: root/content/browser/android
diff options
context:
space:
mode:
Diffstat (limited to 'content/browser/android')
-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
9 files changed, 660 insertions, 248 deletions
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];