| Index: content/browser/android/overscroll_glow.cc
|
| diff --git a/content/browser/android/overscroll_glow.cc b/content/browser/android/overscroll_glow.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..cd76261072547d3837a195ac9a90d285048997c2
|
| --- /dev/null
|
| +++ b/content/browser/android/overscroll_glow.cc
|
| @@ -0,0 +1,192 @@
|
| +// Copyright (c) 2013 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/overscroll_glow.h"
|
| +
|
| +#include "cc/layers/image_layer.h"
|
| +
|
| +namespace content {
|
| +
|
| +namespace {
|
| +
|
| +static scoped_refptr<cc::Layer> NewLayer(const SkBitmap& bitmap) {
|
| + scoped_refptr<cc::ImageLayer> layer = cc::ImageLayer::Create();
|
| + layer->SetContentsOpaque(false);
|
| + layer->SetBitmap(bitmap);
|
| + return layer;
|
| +}
|
| +
|
| +}
|
| +
|
| +OverscrollGlow::OverscrollGlow(const SkBitmap& edge, const SkBitmap& glow)
|
| + : horizontal_overscroll_enabled_(true) {
|
| + for (unsigned i = 0; i < EDGE_COUNT; ++i)
|
| + edge_effects_[i]
|
| + = make_scoped_ptr(new EdgeEffect(NewLayer(edge), NewLayer(glow)));
|
| +}
|
| +
|
| +OverscrollGlow::~OverscrollGlow() { }
|
| +
|
| +void OverscrollGlow::OnOverscrolled(base::TimeTicks current_time,
|
| + gfx::Vector2dF overscroll,
|
| + gfx::Vector2dF velocity) {
|
| + if (!horizontal_overscroll_enabled_) {
|
| + overscroll.set_x(0);
|
| + velocity.set_x(0);
|
| + }
|
| +
|
| + if (overscroll.IsZero()) {
|
| + old_overscroll_ = overscroll;
|
| + if (IsAnimating())
|
| + Release(current_time);
|
| + return;
|
| + }
|
| +
|
| + if (!velocity.IsZero()) {
|
| + Absorb(current_time, velocity, overscroll, old_overscroll_);
|
| + } else {
|
| + if (overscroll.x() * old_overscroll_.x() <= 0 ||
|
| + std::abs(overscroll.x()) < std::abs(old_overscroll_.x())) {
|
| + edge_effects_[EdgeEffect::EDGE_LEFT]->Release(current_time);
|
| + edge_effects_[EdgeEffect::EDGE_RIGHT]->Release(current_time);
|
| + }
|
| + if (overscroll.y() * old_overscroll_.y() <= 0 ||
|
| + std::abs(overscroll.y()) < std::abs(old_overscroll_.y())) {
|
| + edge_effects_[EdgeEffect::EDGE_TOP]->Release(current_time);
|
| + edge_effects_[EdgeEffect::EDGE_BOTTOM]->Release(current_time);
|
| + }
|
| +
|
| + gfx::Vector2dF overscroll_delta = overscroll - old_overscroll_;
|
| + // Ensure monotonic overscroll accumulation
|
| + if (overscroll_delta.x() * old_overscroll_.x() < 0)
|
| + overscroll_delta.set_x(0);
|
| + if (overscroll_delta.y() * old_overscroll_.y() < 0)
|
| + overscroll_delta.set_y(0);
|
| + Pull(current_time, overscroll_delta);
|
| + }
|
| +
|
| + old_overscroll_ = overscroll;
|
| +}
|
| +
|
| +void OverscrollGlow::Release(base::TimeTicks current_time) {
|
| + for (unsigned i = 0; i < EDGE_COUNT; ++i) {
|
| + edge_effects_[i]->Release(current_time);
|
| + }
|
| + old_overscroll_ = gfx::Vector2dF();
|
| +}
|
| +
|
| +void OverscrollGlow::Finish() {
|
| + for (unsigned i = 0; i < EDGE_COUNT; ++i) {
|
| + edge_effects_[i]->Finish();
|
| + }
|
| + old_overscroll_ = gfx::Vector2dF();
|
| +}
|
| +
|
| +bool OverscrollGlow::Animate(base::TimeTicks current_time) {
|
| + if (size_.GetArea() == 0)
|
| + return IsAnimating();
|
| +
|
| + gfx::SizeF sizes[EDGE_COUNT] = {
|
| + size_, gfx::SizeF(size_.height(), size_.width()),
|
| + size_, gfx::SizeF(size_.height(), size_.width())
|
| + };
|
| +
|
| + bool active = false;
|
| + for (unsigned i = 0; i < EDGE_COUNT; ++i) {
|
| + active |= edge_effects_[i]->Update(current_time);
|
| + edge_effects_[i]->Draw(parent_layer_, sizes[i],
|
| + static_cast<EdgeEffect::Edge>(i));
|
| + }
|
| +
|
| + return active;
|
| +}
|
| +
|
| +bool OverscrollGlow::IsAnimating() const {
|
| + for (unsigned i = 0; i < EDGE_COUNT; ++i) {
|
| + if (!edge_effects_[i]->IsFinished())
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +void OverscrollGlow::set_horizontal_overscroll_enabled(bool enabled) {
|
| + horizontal_overscroll_enabled_ = enabled;
|
| +}
|
| +
|
| +void OverscrollGlow::set_size(const gfx::SizeF& size) {
|
| + size_ = size;
|
| +}
|
| +
|
| +void OverscrollGlow::set_parent_layer(scoped_refptr<cc::Layer> parent_layer) {
|
| + if (parent_layer == parent_layer_)
|
| + return;
|
| +
|
| + Finish();
|
| +
|
| + parent_layer_ = parent_layer;
|
| +}
|
| +
|
| +
|
| +void OverscrollGlow::Pull(base::TimeTicks current_time,
|
| + const gfx::Vector2dF& overscroll_delta) {
|
| + using std::max;
|
| + using std::min;
|
| +
|
| + if (overscroll_delta.IsZero())
|
| + return;
|
| +
|
| + gfx::Vector2dF overscroll_pull = gfx::ScaleVector2d(overscroll_delta,
|
| + 1.f / size_.width(),
|
| + 1.f / size_.height());
|
| + float edge_overscroll_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 (unsigned i = 0; i < EDGE_COUNT; ++i) {
|
| + if (!edge_overscroll_pull[i])
|
| + continue;
|
| +
|
| + EdgeEffect& edge_effect = *edge_effects_[i];
|
| + EdgeEffect& opposite_edge_effect = *edge_effects_[(i + 2) % EDGE_COUNT];
|
| + edge_effect.Pull(current_time, std::abs(edge_overscroll_pull[i]));
|
| + if (!opposite_edge_effect.IsFinished())
|
| + opposite_edge_effect.Release(current_time);
|
| + }
|
| +}
|
| +
|
| +void OverscrollGlow::Absorb(base::TimeTicks current_time,
|
| + const gfx::Vector2dF& velocity,
|
| + const gfx::Vector2dF& overscroll,
|
| + const gfx::Vector2dF& old_overscroll) {
|
| + using std::max;
|
| + using std::min;
|
| +
|
| + if (overscroll.IsZero() || velocity.IsZero())
|
| + return;
|
| +
|
| + // Only trigger on initial overscroll at a non-zero velocity
|
| + const float overscroll_velocities[EDGE_COUNT] = {
|
| + old_overscroll.y() >= 0 && overscroll.y() < 0 ? min(velocity.y(), 0.f) : 0,
|
| + old_overscroll.x() >= 0 && overscroll.x() < 0 ? min(velocity.x(), 0.f) : 0,
|
| + old_overscroll.y() <= 0 && overscroll.y() > 0 ? max(velocity.y(), 0.f) : 0,
|
| + old_overscroll.x() <= 0 && overscroll.x() > 0 ? max(velocity.x(), 0.f) : 0
|
| + };
|
| +
|
| + for (unsigned i = 0; i < EDGE_COUNT; ++i) {
|
| + if (!overscroll_velocities[i])
|
| + continue;
|
| +
|
| + EdgeEffect& edge_effect = *edge_effects_[i];
|
| + EdgeEffect& opposite_edge_effect = *edge_effects_[(i + 2) % EDGE_COUNT];
|
| + edge_effect.Absorb(current_time, std::abs(overscroll_velocities[i]));
|
| + if (!opposite_edge_effect.IsFinished()) {
|
| + opposite_edge_effect.Release(current_time);
|
| + }
|
| + }
|
| +}
|
| +
|
| +} // namespace content
|
|
|