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

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

Powered by Google App Engine
This is Rietveld 408576698