Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(65)

Side by Side Diff: content/browser/android/overscroll_glow.cc

Issue 14268004: Add overscroll edge effect animations for Android. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Use LazyInstance for overscroll resources Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/browser/android/overscroll_glow.h"
6
7 #include "base/lazy_instance.h"
8 #include "cc/layers/image_layer.h"
9 #include "content/browser/android/edge_effect.h"
10 #include "skia/ext/image_operations.h"
11 #include "ui/gfx/android/java_bitmap.h"
12
13 using std::max;
14 using std::min;
15
16 namespace content {
17
18 namespace {
19
20 const float kEpsilon = 1e-3f;
21
22 SkBitmap CreateBitmap(const char* resource, gfx::Size size) {
23 SkBitmap bitmap = gfx::CreateSkBitmapFromResource(resource);
24 if (bitmap.isNull())
25 return bitmap;
26 return skia::ImageOperations::Resize(bitmap,
27 skia::ImageOperations::RESIZE_GOOD,
28 size.width(), size.height());
29 }
30
31 class OverscrollResources {
32 public:
33 OverscrollResources()
34 : edge_bitmap_(CreateBitmap("android:drawable/overscroll_edge",
35 gfx::Size(256, 12))),
36 glow_bitmap_(CreateBitmap("android:drawable/overscroll_glow",
37 gfx::Size(128, 128))) {
38 }
39
40 const SkBitmap& edge_bitmap() { return edge_bitmap_; }
41 const SkBitmap& glow_bitmap() { return glow_bitmap_; }
42
43 private:
44 SkBitmap edge_bitmap_;
45 SkBitmap glow_bitmap_;
46
47 DISALLOW_COPY_AND_ASSIGN(OverscrollResources);
48 };
49
50 base::LazyInstance<OverscrollResources> g_overscroll_resources =
51 LAZY_INSTANCE_INITIALIZER;
52
53 scoped_refptr<cc::Layer> CreateImageLayer(const SkBitmap& bitmap) {
54 scoped_refptr<cc::ImageLayer> layer = cc::ImageLayer::Create();
55 layer->SetBitmap(bitmap);
56 return layer;
57 }
58
59 bool IsApproxZero(float value) {
60 return std::abs(value) < kEpsilon;
61 }
62
63 bool IsApproxZero(gfx::Vector2dF vector) {
64 return IsApproxZero(vector.x()) && IsApproxZero(vector.y());
65 }
66
67 gfx::Vector2dF ZeroSmallComponents(gfx::Vector2dF vector) {
68 if (IsApproxZero(vector.x()))
69 vector.set_x(0);
70 if (IsApproxZero(vector.y()))
71 vector.set_y(0);
72 return vector;
73 }
74
75 } // namespace
76
77 scoped_ptr<OverscrollGlow> OverscrollGlow::Create() {
78 const SkBitmap& edge = g_overscroll_resources.Get().edge_bitmap();
79 const SkBitmap& glow = g_overscroll_resources.Get().glow_bitmap();
80 if (edge.isNull() || glow.isNull())
81 return scoped_ptr<OverscrollGlow>();
82
83 return make_scoped_ptr(new OverscrollGlow(edge, glow));
84 }
85
86 OverscrollGlow::OverscrollGlow(const SkBitmap& edge, const SkBitmap& glow)
87 : horizontal_overscroll_enabled_(true),
88 vertical_overscroll_enabled_(true),
89 root_layer_(cc::Layer::Create()) {
90 for (size_t i = 0; i < EdgeEffect::EDGE_COUNT; ++i) {
91 scoped_refptr<cc::Layer> edge_layer = CreateImageLayer(edge);
92 scoped_refptr<cc::Layer> glow_layer = CreateImageLayer(glow);
93 root_layer_->AddChild(edge_layer);
94 root_layer_->AddChild(glow_layer);
95 edge_effects_[i] = make_scoped_ptr(new EdgeEffect(edge_layer, glow_layer));
96 }
97 }
98
99 OverscrollGlow::~OverscrollGlow() {
100 root_layer_->RemoveFromParent();
101 }
102
103 void OverscrollGlow::OnOverscrolled(base::TimeTicks current_time,
104 gfx::Vector2dF overscroll,
105 gfx::Vector2dF velocity) {
106 // The size of the glow determines the relative effect of the inputs; an
107 // empty-sized effect is effectively disabled.
108 if (size_.IsEmpty())
109 return;
110
111 if (!horizontal_overscroll_enabled_) {
112 overscroll.set_x(0);
113 velocity.set_x(0);
114 }
115 if (!vertical_overscroll_enabled_) {
116 overscroll.set_y(0);
117 velocity.set_y(0);
118 }
119
120 // Ignore sufficiently small values that won't meaningfuly affect animation.
121 overscroll = ZeroSmallComponents(overscroll);
122 velocity = ZeroSmallComponents(velocity);
123
124 if (overscroll.IsZero()) {
125 Release(current_time);
126 return;
127 }
128
129 if (!velocity.IsZero()) {
130 // Release effects if scrolling has changed directions.
131 if (velocity.x() * old_velocity_.x() < 0)
132 Release(AXIS_X, current_time);
133 if (velocity.y() * old_velocity_.y() < 0)
134 Release(AXIS_Y, current_time);
135
136 Absorb(current_time, velocity, overscroll, old_overscroll_);
137 } else {
138 // Release effects when overscroll accumulation violates monotonicity.
139 if (overscroll.x() * old_overscroll_.x() < 0 ||
140 std::abs(overscroll.x()) < std::abs(old_overscroll_.x()))
141 Release(AXIS_X, current_time);
142 if (overscroll.y() * old_overscroll_.y() < 0 ||
143 std::abs(overscroll.y()) < std::abs(old_overscroll_.y()))
144 Release(AXIS_Y, current_time);
145
146 Pull(current_time, overscroll - old_overscroll_);
147 }
148
149 old_velocity_ = velocity;
150 old_overscroll_ = overscroll;
151 }
152
153 bool OverscrollGlow::Animate(base::TimeTicks current_time) {
154 if (!IsActive())
155 return false;
156
157 const gfx::SizeF sizes[EdgeEffect::EDGE_COUNT] = {
158 size_, gfx::SizeF(size_.height(), size_.width()),
159 size_, gfx::SizeF(size_.height(), size_.width())
160 };
161
162 for (size_t i = 0; i < EdgeEffect::EDGE_COUNT; ++i) {
163 if (edge_effects_[i]->Update(current_time)) {
164 edge_effects_[i]->ApplyToLayers(sizes[i],
165 static_cast<EdgeEffect::Edge>(i));
166 }
167 }
168
169 return IsActive();
170 }
171
172 bool OverscrollGlow::IsActive() const {
173 for (size_t i = 0; i < EdgeEffect::EDGE_COUNT; ++i) {
174 if (!edge_effects_[i]->IsFinished())
175 return true;
176 }
177 return false;
178 }
179
180 void OverscrollGlow::Finish() {
181 for (size_t i = 0; i < EdgeEffect::EDGE_COUNT; ++i)
182 edge_effects_[i]->Finish();
183 }
184
185 void OverscrollGlow::Pull(base::TimeTicks current_time,
186 gfx::Vector2dF overscroll_delta) {
187 overscroll_delta = ZeroSmallComponents(overscroll_delta);
188 if (overscroll_delta.IsZero())
189 return;
190
191 gfx::Vector2dF overscroll_pull = gfx::ScaleVector2d(overscroll_delta,
192 1.f / size_.width(),
193 1.f / size_.height());
194 float edge_overscroll_pull[EdgeEffect::EDGE_COUNT] = {
195 min(overscroll_pull.y(), 0.f), // Top
196 min(overscroll_pull.x(), 0.f), // Left
197 max(overscroll_pull.y(), 0.f), // Bottom
198 max(overscroll_pull.x(), 0.f) // Right
199 };
200
201 for (size_t i = 0; i < EdgeEffect::EDGE_COUNT; ++i) {
202 if (!edge_overscroll_pull[i])
203 continue;
204
205 edge_effects_[i]->Pull(current_time, std::abs(edge_overscroll_pull[i]));
206 GetOppositeEdge(i)->Release(current_time);
207 }
208 }
209
210 void OverscrollGlow::Absorb(base::TimeTicks current_time,
211 gfx::Vector2dF velocity,
212 gfx::Vector2dF overscroll,
213 gfx::Vector2dF old_overscroll) {
214 if (overscroll.IsZero() || velocity.IsZero())
215 return;
216
217 // Only trigger on initial overscroll at a non-zero velocity
218 const float overscroll_velocities[EdgeEffect::EDGE_COUNT] = {
219 old_overscroll.y() >= 0 && overscroll.y() < 0 ? min(velocity.y(), 0.f) : 0,
220 old_overscroll.x() >= 0 && overscroll.x() < 0 ? min(velocity.x(), 0.f) : 0,
221 old_overscroll.y() <= 0 && overscroll.y() > 0 ? max(velocity.y(), 0.f) : 0,
222 old_overscroll.x() <= 0 && overscroll.x() > 0 ? max(velocity.x(), 0.f) : 0
223 };
224
225 for (size_t i = 0; i < EdgeEffect::EDGE_COUNT; ++i) {
226 if (!overscroll_velocities[i])
227 continue;
228
229 edge_effects_[i]->Absorb(current_time, std::abs(overscroll_velocities[i]));
230 GetOppositeEdge(i)->Release(current_time);
231 }
232 }
233
234 void OverscrollGlow::Release(base::TimeTicks current_time) {
235 for (size_t i = 0; i < EdgeEffect::EDGE_COUNT; ++i) {
236 edge_effects_[i]->Release(current_time);
237 }
238 old_overscroll_ = old_velocity_ = gfx::Vector2dF();
239 }
240
241 void OverscrollGlow::Release(Axis axis, base::TimeTicks current_time) {
242 switch (axis) {
243 case AXIS_X:
244 edge_effects_[EdgeEffect::EDGE_LEFT]->Release(current_time);
245 edge_effects_[EdgeEffect::EDGE_RIGHT]->Release(current_time);
246 old_overscroll_.set_x(0);
247 old_velocity_.set_x(0);
248 break;
249 case AXIS_Y:
250 edge_effects_[EdgeEffect::EDGE_TOP]->Release(current_time);
251 edge_effects_[EdgeEffect::EDGE_BOTTOM]->Release(current_time);
252 old_overscroll_.set_y(0);
253 old_velocity_.set_y(0);
254 break;
255 };
256 }
257
258 EdgeEffect* OverscrollGlow::GetOppositeEdge(int edge_index) {
259 return edge_effects_[(edge_index + 2) % EdgeEffect::EDGE_COUNT].get();
260 }
261
262 } // namespace content
263
OLDNEW
« no previous file with comments | « content/browser/android/overscroll_glow.h ('k') | content/browser/renderer_host/render_widget_host_view_android.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698