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

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

Issue 367173003: [Android] Implementation of overscroll effect for Android L (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Write event location through DidOverscrollParams Created 6 years, 4 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
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/android/overscroll_glow.h" 5 #include "content/browser/android/overscroll_glow.h"
6 6
7 #include "base/android/build_info.h"
7 #include "base/debug/trace_event.h" 8 #include "base/debug/trace_event.h"
8 #include "base/lazy_instance.h" 9 #include "base/lazy_instance.h"
9 #include "cc/layers/layer.h" 10 #include "cc/layers/layer.h"
10 #include "content/browser/android/edge_effect.h" 11 #include "content/browser/android/edge_effect.h"
12 #include "content/browser/android/edge_effect_l.h"
13 #include "ui/gfx/screen.h"
11 14
12 using std::max; 15 using std::max;
13 using std::min; 16 using std::min;
14 17
15 namespace content { 18 namespace content {
16 19
17 namespace { 20 namespace {
18 21
19 const float kEpsilon = 1e-3f; 22 const float kEpsilon = 1e-3f;
20 const float kEdgeHeightAtMdpi = 12.f; 23
21 const float kGlowHeightAtMdpi = 128.f; 24 // The maximum Android build version prior to L release.
25 const int kKitKatSDKVersion = 19;
aelias_OOO_until_Jul13 2014/08/14 22:54:19 Suggest rename to kKitKatMR2SDKVersion to avoid am
jdduke (slow) 2014/08/15 19:15:06 Done.
22 26
23 bool IsApproxZero(float value) { 27 bool IsApproxZero(float value) {
24 return std::abs(value) < kEpsilon; 28 return std::abs(value) < kEpsilon;
25 } 29 }
26 30
27 gfx::Vector2dF ZeroSmallComponents(gfx::Vector2dF vector) { 31 gfx::Vector2dF ZeroSmallComponents(gfx::Vector2dF vector) {
28 if (IsApproxZero(vector.x())) 32 if (IsApproxZero(vector.x()))
29 vector.set_x(0); 33 vector.set_x(0);
30 if (IsApproxZero(vector.y())) 34 if (IsApproxZero(vector.y()))
31 vector.set_y(0); 35 vector.set_y(0);
32 return vector; 36 return vector;
33 } 37 }
34 38
39 gfx::Transform ComputeTransform(OverscrollGlow::Edge edge,
40 const gfx::SizeF& window_size,
41 float offset) {
42 // Transforms assume the edge layers are anchored to their *top center point*.
43 switch (edge) {
44 case OverscrollGlow::EDGE_TOP:
45 return gfx::Transform(1, 0, 0, 1, 0, offset);
46 case OverscrollGlow::EDGE_LEFT:
47 return gfx::Transform(0,
48 1,
49 -1,
50 0,
51 -window_size.height() / 2.f + offset,
52 window_size.height() / 2.f);
53 case OverscrollGlow::EDGE_BOTTOM:
54 return gfx::Transform(-1, 0, 0, -1, 0, window_size.height() + offset);
55 case OverscrollGlow::EDGE_RIGHT:
56 return gfx::Transform(
57 0,
58 -1,
59 1,
60 0,
61 -window_size.height() / 2.f + window_size.width() + offset,
62 window_size.height() / 2.f);
63 default:
64 NOTREACHED() << "Invalid edge: " << edge;
65 return gfx::Transform();
66 };
67 }
68
69 gfx::SizeF ComputeSize(OverscrollGlow::Edge edge,
70 const gfx::SizeF& window_size) {
71 switch (edge) {
72 case OverscrollGlow::EDGE_TOP:
73 case OverscrollGlow::EDGE_BOTTOM:
74 return window_size;
75 case OverscrollGlow::EDGE_LEFT:
76 case OverscrollGlow::EDGE_RIGHT:
77 return gfx::SizeF(window_size.height(), window_size.width());
78 default:
79 NOTREACHED() << "Invalid edge: " << edge;
80 return gfx::SizeF();
81 };
82 }
83
84 bool UseEdgeEffectL() {
aelias_OOO_until_Jul13 2014/08/14 22:54:19 I don't like this kind of global factory policy.
jdduke (slow) 2014/08/15 19:15:06 Hmm, the EdgeEffects are currently setup to be laz
85 static bool use_edge_effect_l =
86 base::android::BuildInfo::GetInstance()->sdk_int() > kKitKatSDKVersion;
87 return use_edge_effect_l;
88 }
89
90 void PreloadResourcesNonBlocking(
91 ui::SystemUIResourceManager* resource_manager) {
92 if (UseEdgeEffectL())
93 EdgeEffectL::PreloadResources(resource_manager);
94 else
95 EdgeEffect::PreloadResources(resource_manager);
96 }
97
98 scoped_ptr<EdgeEffectBase> CreateEdgeEffect(
99 ui::SystemUIResourceManager* resource_manager,
100 float device_scale_factor) {
101 scoped_ptr<EdgeEffectBase> result;
102 if (UseEdgeEffectL())
103 result.reset(new EdgeEffectL(resource_manager));
104 else
105 result.reset(new EdgeEffect(resource_manager, device_scale_factor));
106 return result.Pass();
107 }
108
35 } // namespace 109 } // namespace
36 110
37 scoped_ptr<OverscrollGlow> OverscrollGlow::Create( 111 scoped_ptr<OverscrollGlow> OverscrollGlow::Create(
38 ui::SystemUIResourceManager* resource_manager) { 112 ui::SystemUIResourceManager* resource_manager) {
39 return make_scoped_ptr(new OverscrollGlow(resource_manager)); 113 return make_scoped_ptr(new OverscrollGlow(resource_manager));
40 } 114 }
41 115
42 OverscrollGlow::OverscrollGlow(ui::SystemUIResourceManager* resource_manager) 116 OverscrollGlow::OverscrollGlow(ui::SystemUIResourceManager* resource_manager)
43 : enabled_(true), initialized_(false), resource_manager_(resource_manager) { 117 : enabled_(true), initialized_(false), resource_manager_(resource_manager) {
44 DCHECK(resource_manager_); 118 DCHECK(resource_manager_);
45 EdgeEffect::PreloadResources(resource_manager_); 119 PreloadResourcesNonBlocking(resource_manager_);
46 } 120 }
47 121
48 OverscrollGlow::~OverscrollGlow() { 122 OverscrollGlow::~OverscrollGlow() {
49 Detach(); 123 Detach();
50 } 124 }
51 125
52 void OverscrollGlow::Enable() { 126 void OverscrollGlow::Enable() {
53 enabled_ = true; 127 enabled_ = true;
54 } 128 }
55 129
56 void OverscrollGlow::Disable() { 130 void OverscrollGlow::Disable() {
57 if (!enabled_) 131 if (!enabled_)
58 return; 132 return;
59 enabled_ = false; 133 enabled_ = false;
60 if (!enabled_ && initialized_) { 134 if (!enabled_ && initialized_) {
61 Detach(); 135 Detach();
62 for (size_t i = 0; i < EdgeEffect::EDGE_COUNT; ++i) 136 for (size_t i = 0; i < EDGE_COUNT; ++i)
63 edge_effects_[i]->Finish(); 137 edge_effects_[i]->Finish();
64 } 138 }
65 } 139 }
66 140
67 bool OverscrollGlow::OnOverscrolled(cc::Layer* overscrolling_layer, 141 bool OverscrollGlow::OnOverscrolled(cc::Layer* overscrolling_layer,
68 base::TimeTicks current_time, 142 base::TimeTicks current_time,
69 gfx::Vector2dF accumulated_overscroll, 143 gfx::Vector2dF accumulated_overscroll,
70 gfx::Vector2dF overscroll_delta, 144 gfx::Vector2dF overscroll_delta,
71 gfx::Vector2dF velocity) { 145 gfx::Vector2dF velocity,
146 gfx::Vector2dF displacement) {
72 DCHECK(overscrolling_layer); 147 DCHECK(overscrolling_layer);
73 148
74 if (!enabled_) 149 if (!enabled_)
75 return false; 150 return false;
76 151
77 // The size of the glow determines the relative effect of the inputs; an 152 // The size of the glow determines the relative effect of the inputs; an
78 // empty-sized effect is effectively disabled. 153 // empty-sized effect is effectively disabled.
79 if (display_params_.size.IsEmpty()) 154 if (display_params_.size.IsEmpty())
80 return false; 155 return false;
81 156
82 // Ignore sufficiently small values that won't meaningfuly affect animation. 157 // Ignore sufficiently small values that won't meaningfuly affect animation.
83 overscroll_delta = ZeroSmallComponents(overscroll_delta); 158 overscroll_delta = ZeroSmallComponents(overscroll_delta);
84 if (overscroll_delta.IsZero()) { 159 if (overscroll_delta.IsZero()) {
85 if (initialized_) { 160 if (initialized_) {
86 Release(current_time); 161 Release(current_time);
87 UpdateLayerAttachment(overscrolling_layer); 162 UpdateLayerAttachment(overscrolling_layer);
88 } 163 }
89 return NeedsAnimate(); 164 return NeedsAnimate();
90 } 165 }
91 166
92 if (!InitializeIfNecessary()) 167 if (!InitializeIfNecessary())
93 return false; 168 return false;
94 169
95 gfx::Vector2dF old_overscroll = accumulated_overscroll - overscroll_delta; 170 gfx::Vector2dF old_overscroll = accumulated_overscroll - overscroll_delta;
96 bool x_overscroll_started = 171 bool x_overscroll_started =
97 !IsApproxZero(overscroll_delta.x()) && IsApproxZero(old_overscroll.x()); 172 !IsApproxZero(overscroll_delta.x()) && IsApproxZero(old_overscroll.x());
98 bool y_overscroll_started = 173 bool y_overscroll_started =
99 !IsApproxZero(overscroll_delta.y()) && IsApproxZero(old_overscroll.y()); 174 !IsApproxZero(overscroll_delta.y()) && IsApproxZero(old_overscroll.y());
100 175
101 if (x_overscroll_started)
102 ReleaseAxis(AXIS_X, current_time);
103 if (y_overscroll_started)
104 ReleaseAxis(AXIS_Y, current_time);
105
106 velocity = ZeroSmallComponents(velocity); 176 velocity = ZeroSmallComponents(velocity);
107 if (!velocity.IsZero()) 177 if (!velocity.IsZero())
108 Absorb(current_time, velocity, x_overscroll_started, y_overscroll_started); 178 Absorb(current_time, velocity, x_overscroll_started, y_overscroll_started);
109 else 179 else
110 Pull(current_time, overscroll_delta); 180 Pull(current_time, overscroll_delta, displacement);
111 181
112 UpdateLayerAttachment(overscrolling_layer); 182 UpdateLayerAttachment(overscrolling_layer);
113 return NeedsAnimate(); 183 return NeedsAnimate();
114 } 184 }
115 185
116 bool OverscrollGlow::Animate(base::TimeTicks current_time) { 186 bool OverscrollGlow::Animate(base::TimeTicks current_time) {
117 if (!NeedsAnimate()) { 187 if (!NeedsAnimate()) {
118 Detach(); 188 Detach();
119 return false; 189 return false;
120 } 190 }
121 191
122 for (size_t i = 0; i < EdgeEffect::EDGE_COUNT; ++i) { 192 for (size_t i = 0; i < EDGE_COUNT; ++i) {
123 if (edge_effects_[i]->Update(current_time)) { 193 if (edge_effects_[i]->Update(current_time)) {
194 Edge edge = static_cast<Edge>(i);
124 edge_effects_[i]->ApplyToLayers( 195 edge_effects_[i]->ApplyToLayers(
125 display_params_.size, 196 ComputeSize(edge, display_params_.size),
126 static_cast<EdgeEffect::Edge>(i), 197 ComputeTransform(
127 kEdgeHeightAtMdpi * display_params_.device_scale_factor, 198 edge, display_params_.size, display_params_.edge_offsets[i]));
128 kGlowHeightAtMdpi * display_params_.device_scale_factor,
129 display_params_.edge_offsets[i]);
130 } 199 }
131 } 200 }
132 201
133 if (!NeedsAnimate()) { 202 if (!NeedsAnimate()) {
134 Detach(); 203 Detach();
135 return false; 204 return false;
136 } 205 }
137 206
138 return true; 207 return true;
139 } 208 }
140 209
141 void OverscrollGlow::UpdateDisplayParameters(const DisplayParameters& params) { 210 void OverscrollGlow::UpdateDisplayParameters(const DisplayParameters& params) {
142 display_params_ = params; 211 display_params_ = params;
143 } 212 }
144 213
145 bool OverscrollGlow::NeedsAnimate() const { 214 bool OverscrollGlow::NeedsAnimate() const {
146 if (!enabled_ || !initialized_) 215 if (!enabled_ || !initialized_)
147 return false; 216 return false;
148 for (size_t i = 0; i < EdgeEffect::EDGE_COUNT; ++i) { 217 for (size_t i = 0; i < EDGE_COUNT; ++i) {
149 if (!edge_effects_[i]->IsFinished()) 218 if (!edge_effects_[i]->IsFinished())
150 return true; 219 return true;
151 } 220 }
152 return false; 221 return false;
153 } 222 }
154 223
155 void OverscrollGlow::UpdateLayerAttachment(cc::Layer* parent) { 224 void OverscrollGlow::UpdateLayerAttachment(cc::Layer* parent) {
156 DCHECK(parent); 225 DCHECK(parent);
157 if (!root_layer_) 226 if (!root_layer_)
158 return; 227 return;
159 228
160 if (!NeedsAnimate()) { 229 if (!NeedsAnimate()) {
161 Detach(); 230 Detach();
162 return; 231 return;
163 } 232 }
164 233
165 if (root_layer_->parent() != parent) 234 if (root_layer_->parent() != parent)
166 parent->AddChild(root_layer_); 235 parent->AddChild(root_layer_);
167 236
168 for (size_t i = 0; i < EdgeEffect::EDGE_COUNT; ++i) 237 for (size_t i = 0; i < EDGE_COUNT; ++i)
169 edge_effects_[i]->SetParent(root_layer_); 238 edge_effects_[i]->SetParent(root_layer_);
170 } 239 }
171 240
172 void OverscrollGlow::Detach() { 241 void OverscrollGlow::Detach() {
173 if (root_layer_) 242 if (root_layer_)
174 root_layer_->RemoveFromParent(); 243 root_layer_->RemoveFromParent();
175 } 244 }
176 245
177 bool OverscrollGlow::InitializeIfNecessary() { 246 bool OverscrollGlow::InitializeIfNecessary() {
178 DCHECK(enabled_); 247 DCHECK(enabled_);
179 if (initialized_) 248 if (initialized_)
180 return true; 249 return true;
181 250
182 DCHECK(!root_layer_); 251 DCHECK(!root_layer_);
183 root_layer_ = cc::Layer::Create(); 252 root_layer_ = cc::Layer::Create();
184 for (size_t i = 0; i < EdgeEffect::EDGE_COUNT; ++i) 253 const float device_scale_factor =
185 edge_effects_[i] = make_scoped_ptr(new EdgeEffect(resource_manager_)); 254 gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().device_scale_factor();
aelias_OOO_until_Jul13 2014/08/14 22:54:19 Can this also be passed in the OverscrollGlow cons
jdduke (slow) 2014/08/15 19:15:06 Hmm, if I pass in a factory method I think we can
255 for (size_t i = 0; i < EDGE_COUNT; ++i)
256 edge_effects_[i] = CreateEdgeEffect(resource_manager_, device_scale_factor);
186 257
187 initialized_ = true; 258 initialized_ = true;
188 return true; 259 return true;
189 } 260 }
190 261
191 void OverscrollGlow::Pull(base::TimeTicks current_time, 262 void OverscrollGlow::Pull(base::TimeTicks current_time,
192 gfx::Vector2dF overscroll_delta) { 263 const gfx::Vector2dF& overscroll_delta,
264 const gfx::Vector2dF& overscroll_location) {
193 DCHECK(enabled_ && initialized_); 265 DCHECK(enabled_ && initialized_);
194 overscroll_delta = ZeroSmallComponents(overscroll_delta); 266 DCHECK(!overscroll_delta.IsZero());
195 if (overscroll_delta.IsZero()) 267 const float inv_width = 1.f / display_params_.size.width();
196 return; 268 const float inv_height = 1.f / display_params_.size.height();
197 269
198 gfx::Vector2dF overscroll_pull = 270 gfx::Vector2dF overscroll_pull =
199 gfx::ScaleVector2d(overscroll_delta, 271 gfx::ScaleVector2d(overscroll_delta, inv_width, inv_height);
200 1.f / display_params_.size.width(), 272 const float edge_pull[EDGE_COUNT] = {
201 1.f / display_params_.size.height());
202 float edge_overscroll_pull[EdgeEffect::EDGE_COUNT] = {
203 min(overscroll_pull.y(), 0.f), // Top 273 min(overscroll_pull.y(), 0.f), // Top
204 min(overscroll_pull.x(), 0.f), // Left 274 min(overscroll_pull.x(), 0.f), // Left
205 max(overscroll_pull.y(), 0.f), // Bottom 275 max(overscroll_pull.y(), 0.f), // Bottom
206 max(overscroll_pull.x(), 0.f) // Right 276 max(overscroll_pull.x(), 0.f) // Right
207 }; 277 };
208 278
209 for (size_t i = 0; i < EdgeEffect::EDGE_COUNT; ++i) { 279 gfx::Vector2dF displacement =
210 if (!edge_overscroll_pull[i]) 280 gfx::ScaleVector2d(overscroll_location, inv_width, inv_height);
281 displacement.set_x(max(0.f, min(1.f, displacement.x())));
282 displacement.set_y(max(0.f, min(1.f, displacement.y())));
283 const float edge_displacement[EDGE_COUNT] = {
284 1.f - displacement.x(), // Top
285 displacement.y(), // Left
286 displacement.x(), // Bottom
287 1.f - displacement.y() // Right
288 };
289
290 for (size_t i = 0; i < EDGE_COUNT; ++i) {
291 if (!edge_pull[i])
211 continue; 292 continue;
212 293
213 edge_effects_[i]->Pull(current_time, std::abs(edge_overscroll_pull[i])); 294 edge_effects_[i]->Pull(
295 current_time, std::abs(edge_pull[i]), edge_displacement[i]);
214 GetOppositeEdge(i)->Release(current_time); 296 GetOppositeEdge(i)->Release(current_time);
215 } 297 }
216 } 298 }
217 299
218 void OverscrollGlow::Absorb(base::TimeTicks current_time, 300 void OverscrollGlow::Absorb(base::TimeTicks current_time,
219 gfx::Vector2dF velocity, 301 const gfx::Vector2dF& velocity,
220 bool x_overscroll_started, 302 bool x_overscroll_started,
221 bool y_overscroll_started) { 303 bool y_overscroll_started) {
222 DCHECK(enabled_ && initialized_); 304 DCHECK(enabled_ && initialized_);
223 if (velocity.IsZero()) 305 DCHECK(!velocity.IsZero());
224 return;
225 306
226 // Only trigger on initial overscroll at a non-zero velocity 307 // Only trigger on initial overscroll at a non-zero velocity
227 const float overscroll_velocities[EdgeEffect::EDGE_COUNT] = { 308 const float overscroll_velocities[EDGE_COUNT] = {
228 y_overscroll_started ? min(velocity.y(), 0.f) : 0, // Top 309 y_overscroll_started ? min(velocity.y(), 0.f) : 0, // Top
229 x_overscroll_started ? min(velocity.x(), 0.f) : 0, // Left 310 x_overscroll_started ? min(velocity.x(), 0.f) : 0, // Left
230 y_overscroll_started ? max(velocity.y(), 0.f) : 0, // Bottom 311 y_overscroll_started ? max(velocity.y(), 0.f) : 0, // Bottom
231 x_overscroll_started ? max(velocity.x(), 0.f) : 0 // Right 312 x_overscroll_started ? max(velocity.x(), 0.f) : 0 // Right
232 }; 313 };
233 314
234 for (size_t i = 0; i < EdgeEffect::EDGE_COUNT; ++i) { 315 for (size_t i = 0; i < EDGE_COUNT; ++i) {
235 if (!overscroll_velocities[i]) 316 if (!overscroll_velocities[i])
236 continue; 317 continue;
237 318
238 edge_effects_[i]->Absorb(current_time, std::abs(overscroll_velocities[i])); 319 edge_effects_[i]->Absorb(current_time, std::abs(overscroll_velocities[i]));
239 GetOppositeEdge(i)->Release(current_time); 320 GetOppositeEdge(i)->Release(current_time);
240 } 321 }
241 } 322 }
242 323
243 void OverscrollGlow::Release(base::TimeTicks current_time) { 324 void OverscrollGlow::Release(base::TimeTicks current_time) {
244 DCHECK(initialized_); 325 DCHECK(initialized_);
245 for (size_t i = 0; i < EdgeEffect::EDGE_COUNT; ++i) 326 for (size_t i = 0; i < EDGE_COUNT; ++i)
246 edge_effects_[i]->Release(current_time); 327 edge_effects_[i]->Release(current_time);
247 } 328 }
248 329
249 void OverscrollGlow::ReleaseAxis(Axis axis, base::TimeTicks current_time) { 330 EdgeEffectBase* OverscrollGlow::GetOppositeEdge(int edge_index) {
250 DCHECK(initialized_); 331 DCHECK(initialized_);
251 switch (axis) { 332 return edge_effects_[(edge_index + 2) % EDGE_COUNT].get();
252 case AXIS_X:
253 edge_effects_[EdgeEffect::EDGE_LEFT]->Release(current_time);
254 edge_effects_[EdgeEffect::EDGE_RIGHT]->Release(current_time);
255 break;
256 case AXIS_Y:
257 edge_effects_[EdgeEffect::EDGE_TOP]->Release(current_time);
258 edge_effects_[EdgeEffect::EDGE_BOTTOM]->Release(current_time);
259 break;
260 };
261 } 333 }
262 334
263 EdgeEffect* OverscrollGlow::GetOppositeEdge(int edge_index) { 335 OverscrollGlow::DisplayParameters::DisplayParameters() {
264 DCHECK(initialized_);
265 return edge_effects_[(edge_index + 2) % EdgeEffect::EDGE_COUNT].get();
266 }
267
268 OverscrollGlow::DisplayParameters::DisplayParameters()
269 : device_scale_factor(1) {
270 edge_offsets[0] = edge_offsets[1] = edge_offsets[2] = edge_offsets[3] = 0.f; 336 edge_offsets[0] = edge_offsets[1] = edge_offsets[2] = edge_offsets[3] = 0.f;
271 } 337 }
272 338
273 } // namespace content 339 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698