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

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 vsync ticks to drive overscroll animation Created 7 years, 8 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 "cc/layers/image_layer.h"
8 #include "skia/ext/image_operations.h"
9 #include "ui/gfx/android/java_bitmap.h"
10
11 namespace content {
12
13 namespace {
aelias_OOO_until_Jul13 2013/04/22 23:46:48 Delete all "static"s inside here
jdduke (slow) 2013/04/23 16:02:13 Done.
14
15 static const float VEC_LENGTH_EPS_SQUARED = 1e-5f;
16
17 static SkBitmap CreateBitmap(const char* resource, gfx::Size size) {
18 SkBitmap bitmap = gfx::CreateSkBitmapFromResource(resource);
19 if (bitmap.isNull())
20 return bitmap;
21 return skia::ImageOperations::Resize(bitmap,
22 skia::ImageOperations::RESIZE_GOOD,
23 size.width(), size.height());
24 }
25
26 static const SkBitmap& GetOverscrollEdgeBitmap() {
27 static SkBitmap edge = CreateBitmap("android:drawable/overscroll_edge",
28 gfx::Size(256, 12));
29 return edge;
30 }
31
32 static const SkBitmap& GetOverscrollGlowBitmap() {
33 static SkBitmap glow = CreateBitmap("android:drawable/overscroll_glow",
34 gfx::Size(128, 128));
35 return glow;
36 }
37
38 static scoped_refptr<cc::Layer> NewLayer(const SkBitmap& bitmap) {
39 scoped_refptr<cc::ImageLayer> layer = cc::ImageLayer::Create();
40 layer->SetContentsOpaque(false);
41 layer->SetBitmap(bitmap);
42 return layer;
43 }
44
45 static bool IsApproxZero(const gfx::Vector2dF& vector) {
46 return vector.LengthSquared() < VEC_LENGTH_EPS_SQUARED;
47 }
48
49 }
50
51 scoped_ptr<OverscrollGlow> OverscrollGlow::Create() {
52 const SkBitmap& edge = GetOverscrollEdgeBitmap();
53 const SkBitmap& glow = GetOverscrollGlowBitmap();
54 if (edge.isNull() || glow.isNull())
55 return scoped_ptr<OverscrollGlow>();
56
57 return make_scoped_ptr(new OverscrollGlow(edge, glow));
58 }
59
60 OverscrollGlow::OverscrollGlow(const SkBitmap& edge, const SkBitmap& glow)
61 : horizontal_overscroll_enabled_(true) {
62 for (unsigned i = 0; i < EDGE_COUNT; ++i) {
63 edge_effects_[i]
64 = make_scoped_ptr(new EdgeEffect(NewLayer(edge), NewLayer(glow)));
65 }
66 }
67
68 OverscrollGlow::~OverscrollGlow() { }
69
70 void OverscrollGlow::OnOverscrolled(base::TimeTicks current_time,
71 gfx::Vector2dF overscroll,
72 gfx::Vector2dF velocity) {
73 if (!horizontal_overscroll_enabled_) {
74 overscroll.set_x(0);
75 velocity.set_x(0);
76 }
77
78 if (IsApproxZero(overscroll)) {
79 Release(current_time);
80 return;
81 }
82
83 if (!IsApproxZero(velocity)) {
84 if (velocity.x() * old_velocity_.x() < 0)
85 Release(AXIS_X, current_time);
86 if (velocity.y() * old_velocity_.y() < 0)
87 Release(AXIS_Y, current_time);
88
89 Absorb(current_time, velocity, overscroll, old_overscroll_);
90 } else {
91 if (overscroll.x() * old_overscroll_.x() < 0 ||
92 std::abs(overscroll.x()) < std::abs(old_overscroll_.x()))
93 Release(AXIS_X, current_time);
94 if (overscroll.y() * old_overscroll_.y() < 0 ||
95 std::abs(overscroll.y()) < std::abs(old_overscroll_.y()))
96 Release(AXIS_Y, current_time);
97
98 // Ensure monotonic overscroll accumulation
99 gfx::Vector2dF overscroll_delta = overscroll - old_overscroll_;
100 if (overscroll_delta.x() * old_overscroll_.x() < 0)
101 overscroll_delta.set_x(0);
102 if (overscroll_delta.y() * old_overscroll_.y() < 0)
103 overscroll_delta.set_y(0);
104
105 Pull(current_time, overscroll_delta);
106 }
107
108 old_velocity_ = velocity;
109 old_overscroll_ = overscroll;
110 }
111
112 void OverscrollGlow::Release(base::TimeTicks current_time) {
113 for (unsigned i = 0; i < EDGE_COUNT; ++i) {
114 edge_effects_[i]->Release(current_time);
115 }
116 old_overscroll_ = gfx::Vector2dF();
117 old_velocity_ = gfx::Vector2dF();
118 }
119
120 void OverscrollGlow::Finish() {
121 for (unsigned i = 0; i < EDGE_COUNT; ++i) {
122 edge_effects_[i]->Finish();
123 }
124 old_overscroll_ = gfx::Vector2dF();
125 old_velocity_ = gfx::Vector2dF();
126 }
127
128 bool OverscrollGlow::Animate(base::TimeTicks current_time) {
129 if (!IsAnimating())
130 return false;
131
132 const gfx::SizeF sizes[EDGE_COUNT] = {
133 size_, gfx::SizeF(size_.height(), size_.width()),
134 size_, gfx::SizeF(size_.height(), size_.width())
135 };
136
137 bool active = false;
138 for (unsigned i = 0; i < EDGE_COUNT; ++i) {
139 if (edge_effects_[i]->Update(current_time))
140 edge_effects_[i]->Draw(parent_layer_, sizes[i],
141 static_cast<EdgeEffect::Edge>(i));
142 }
143
144 return active;
145 }
146
147 bool OverscrollGlow::IsAnimating() const {
148 for (unsigned i = 0; i < EDGE_COUNT; ++i) {
149 if (!edge_effects_[i]->IsFinished())
150 return true;
151 }
152 return false;
153 }
154
155 void OverscrollGlow::set_horizontal_overscroll_enabled(bool enabled) {
156 horizontal_overscroll_enabled_ = enabled;
157 }
158
159 void OverscrollGlow::set_size(const gfx::SizeF& size) {
160 size_ = size;
161 }
162
163 void OverscrollGlow::set_parent_layer(scoped_refptr<cc::Layer> parent_layer) {
164 if (parent_layer == parent_layer_)
165 return;
166
167 Finish();
168
169 parent_layer_ = parent_layer;
170 }
171
172
173 void OverscrollGlow::Pull(base::TimeTicks current_time,
174 const gfx::Vector2dF& overscroll_delta) {
175 using std::max;
aelias_OOO_until_Jul13 2013/04/22 23:46:48 Please delete these using declarations or move the
jdduke (slow) 2013/04/23 16:02:13 Done.
176 using std::min;
177
178 if (IsApproxZero(overscroll_delta))
179 return;
180
181 gfx::Vector2dF overscroll_pull = gfx::ScaleVector2d(overscroll_delta,
182 1.f / size_.width(),
183 1.f / size_.height());
184 float edge_overscroll_pull[EDGE_COUNT] = {
185 min(overscroll_pull.y(), 0.f), // Top
186 min(overscroll_pull.x(), 0.f), // Left
187 max(overscroll_pull.y(), 0.f), // Bottom
188 max(overscroll_pull.x(), 0.f) // Right
189 };
190
191 for (unsigned i = 0; i < EDGE_COUNT; ++i) {
aelias_OOO_until_Jul13 2013/04/22 23:46:48 Should be "size_t i"
jdduke (slow) 2013/04/23 16:02:13 Done.
192 if (!edge_overscroll_pull[i])
193 continue;
194
195 EdgeEffect& edge_effect = *edge_effects_[i];
196 EdgeEffect& opposite_edge_effect = *GetOppositeEdge(i);
197 edge_effect.Pull(current_time, std::abs(edge_overscroll_pull[i]));
198 if (!opposite_edge_effect.IsFinished())
199 opposite_edge_effect.Release(current_time);
200 }
201 }
202
203 void OverscrollGlow::Absorb(base::TimeTicks current_time,
204 const gfx::Vector2dF& velocity,
205 const gfx::Vector2dF& overscroll,
206 const gfx::Vector2dF& old_overscroll) {
207 using std::max;
aelias_OOO_until_Jul13 2013/04/22 23:46:48 Delete these
jdduke (slow) 2013/04/23 16:02:13 Done.
208 using std::min;
209
210 if (IsApproxZero(overscroll) || IsApproxZero(velocity))
211 return;
212
213 // Only trigger on initial overscroll at a non-zero velocity
214 const float overscroll_velocities[EDGE_COUNT] = {
215 old_overscroll.y() >= 0 && overscroll.y() < 0 ? min(velocity.y(), 0.f) : 0,
216 old_overscroll.x() >= 0 && overscroll.x() < 0 ? min(velocity.x(), 0.f) : 0,
217 old_overscroll.y() <= 0 && overscroll.y() > 0 ? max(velocity.y(), 0.f) : 0,
218 old_overscroll.x() <= 0 && overscroll.x() > 0 ? max(velocity.x(), 0.f) : 0
219 };
220
221 for (unsigned i = 0; i < EDGE_COUNT; ++i) {
aelias_OOO_until_Jul13 2013/04/22 23:46:48 Should be "size_t i"
jdduke (slow) 2013/04/23 16:02:13 Done.
222 if (!overscroll_velocities[i])
223 continue;
224
225 EdgeEffect& edge_effect = *edge_effects_[i];
aelias_OOO_until_Jul13 2013/04/22 23:46:48 Please use pointers here, non-const references are
jdduke (slow) 2013/04/23 16:02:13 Done.
226 EdgeEffect& opposite_edge_effect = *GetOppositeEdge(i);
227 edge_effect.Absorb(current_time, std::abs(overscroll_velocities[i]));
228 if (!opposite_edge_effect.IsFinished())
229 opposite_edge_effect.Release(current_time);
230 }
231 }
232
233 void OverscrollGlow::Release(Axis axis, base::TimeTicks current_time) {
234 switch (axis) {
235 case AXIS_Y:
236 edge_effects_[EdgeEffect::EDGE_LEFT]->Release(current_time);
237 edge_effects_[EdgeEffect::EDGE_RIGHT]->Release(current_time);
238 old_overscroll_.set_y(0);
239 old_velocity_.set_y(0);
240 break;
241 case AXIS_X:
242 default:
aelias_OOO_until_Jul13 2013/04/22 23:46:48 This "default" is weird. Please delete it entirel
jdduke (slow) 2013/04/23 16:02:13 Done.
243 edge_effects_[EdgeEffect::EDGE_LEFT]->Release(current_time);
244 edge_effects_[EdgeEffect::EDGE_RIGHT]->Release(current_time);
245 old_overscroll_.set_x(0);
246 old_velocity_.set_x(0);
247 break;
248 };
249 }
250
251 EdgeEffect* OverscrollGlow::GetOppositeEdge(int edge_index) {
252 return edge_effects_[(edge_index + 2) % EDGE_COUNT].get();
253 }
254
255 } // namespace content
256
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698