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

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: Code review 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/debug/trace_event.h"
8 #include "base/lazy_instance.h"
9 #include "cc/layers/layer.h" 7 #include "cc/layers/layer.h"
10 #include "content/browser/android/edge_effect.h" 8 #include "content/browser/android/edge_effect_base.h"
11 9
12 using std::max; 10 using std::max;
13 using std::min; 11 using std::min;
14 12
15 namespace content { 13 namespace content {
16 14
17 namespace { 15 namespace {
18 16
19 const float kEpsilon = 1e-3f; 17 const float kEpsilon = 1e-3f;
20 const float kEdgeHeightAtMdpi = 12.f;
21 const float kGlowHeightAtMdpi = 128.f;
22 18
23 bool IsApproxZero(float value) { 19 bool IsApproxZero(float value) {
24 return std::abs(value) < kEpsilon; 20 return std::abs(value) < kEpsilon;
25 } 21 }
26 22
27 gfx::Vector2dF ZeroSmallComponents(gfx::Vector2dF vector) { 23 gfx::Vector2dF ZeroSmallComponents(gfx::Vector2dF vector) {
28 if (IsApproxZero(vector.x())) 24 if (IsApproxZero(vector.x()))
29 vector.set_x(0); 25 vector.set_x(0);
30 if (IsApproxZero(vector.y())) 26 if (IsApproxZero(vector.y()))
31 vector.set_y(0); 27 vector.set_y(0);
32 return vector; 28 return vector;
33 } 29 }
34 30
31 gfx::Transform ComputeTransform(OverscrollGlow::Edge edge,
32 const gfx::SizeF& window_size,
33 float offset) {
34 // Transforms assume the edge layers are anchored to their *top center point*.
35 switch (edge) {
36 case OverscrollGlow::EDGE_TOP:
37 return gfx::Transform(1, 0, 0, 1, 0, offset);
38 case OverscrollGlow::EDGE_LEFT:
39 return gfx::Transform(0,
40 1,
41 -1,
42 0,
43 -window_size.height() / 2.f + offset,
44 window_size.height() / 2.f);
45 case OverscrollGlow::EDGE_BOTTOM:
46 return gfx::Transform(-1, 0, 0, -1, 0, window_size.height() + offset);
47 case OverscrollGlow::EDGE_RIGHT:
48 return gfx::Transform(
49 0,
50 -1,
51 1,
52 0,
53 -window_size.height() / 2.f + window_size.width() + offset,
54 window_size.height() / 2.f);
55 default:
56 NOTREACHED() << "Invalid edge: " << edge;
57 return gfx::Transform();
58 };
59 }
60
61 gfx::SizeF ComputeSize(OverscrollGlow::Edge edge,
62 const gfx::SizeF& window_size) {
63 switch (edge) {
64 case OverscrollGlow::EDGE_TOP:
65 case OverscrollGlow::EDGE_BOTTOM:
66 return window_size;
67 case OverscrollGlow::EDGE_LEFT:
68 case OverscrollGlow::EDGE_RIGHT:
69 return gfx::SizeF(window_size.height(), window_size.width());
70 default:
71 NOTREACHED() << "Invalid edge: " << edge;
72 return gfx::SizeF();
73 };
74 }
75
35 } // namespace 76 } // namespace
36 77
37 scoped_ptr<OverscrollGlow> OverscrollGlow::Create( 78 OverscrollGlow::OverscrollGlow(const EdgeEffectProvider& edge_effect_provider)
38 ui::SystemUIResourceManager* resource_manager) { 79 : edge_effect_provider_(edge_effect_provider),
39 return make_scoped_ptr(new OverscrollGlow(resource_manager)); 80 enabled_(true),
40 } 81 initialized_(false) {
41 82 DCHECK(!edge_effect_provider_.is_null());
42 OverscrollGlow::OverscrollGlow(ui::SystemUIResourceManager* resource_manager)
43 : enabled_(true), initialized_(false), resource_manager_(resource_manager) {
44 DCHECK(resource_manager_);
45 EdgeEffect::PreloadResources(resource_manager_);
46 } 83 }
47 84
48 OverscrollGlow::~OverscrollGlow() { 85 OverscrollGlow::~OverscrollGlow() {
49 Detach(); 86 Detach();
50 } 87 }
51 88
52 void OverscrollGlow::Enable() { 89 void OverscrollGlow::Enable() {
53 enabled_ = true; 90 enabled_ = true;
54 } 91 }
55 92
56 void OverscrollGlow::Disable() { 93 void OverscrollGlow::Disable() {
57 if (!enabled_) 94 if (!enabled_)
58 return; 95 return;
59 enabled_ = false; 96 enabled_ = false;
60 if (!enabled_ && initialized_) { 97 if (!enabled_ && initialized_) {
61 Detach(); 98 Detach();
62 for (size_t i = 0; i < EdgeEffect::EDGE_COUNT; ++i) 99 for (size_t i = 0; i < EDGE_COUNT; ++i)
63 edge_effects_[i]->Finish(); 100 edge_effects_[i]->Finish();
64 } 101 }
65 } 102 }
66 103
67 bool OverscrollGlow::OnOverscrolled(cc::Layer* overscrolling_layer, 104 bool OverscrollGlow::OnOverscrolled(cc::Layer* overscrolling_layer,
68 base::TimeTicks current_time, 105 base::TimeTicks current_time,
69 gfx::Vector2dF accumulated_overscroll, 106 gfx::Vector2dF accumulated_overscroll,
70 gfx::Vector2dF overscroll_delta, 107 gfx::Vector2dF overscroll_delta,
71 gfx::Vector2dF velocity) { 108 gfx::Vector2dF velocity,
109 gfx::Vector2dF displacement) {
72 DCHECK(overscrolling_layer); 110 DCHECK(overscrolling_layer);
73 111
74 if (!enabled_) 112 if (!enabled_)
75 return false; 113 return false;
76 114
77 // The size of the glow determines the relative effect of the inputs; an 115 // The size of the glow determines the relative effect of the inputs; an
78 // empty-sized effect is effectively disabled. 116 // empty-sized effect is effectively disabled.
79 if (display_params_.size.IsEmpty()) 117 if (display_params_.size.IsEmpty())
80 return false; 118 return false;
81 119
82 // Ignore sufficiently small values that won't meaningfuly affect animation. 120 // Ignore sufficiently small values that won't meaningfuly affect animation.
83 overscroll_delta = ZeroSmallComponents(overscroll_delta); 121 overscroll_delta = ZeroSmallComponents(overscroll_delta);
84 if (overscroll_delta.IsZero()) { 122 if (overscroll_delta.IsZero()) {
85 if (initialized_) { 123 if (initialized_) {
86 Release(current_time); 124 Release(current_time);
87 UpdateLayerAttachment(overscrolling_layer); 125 UpdateLayerAttachment(overscrolling_layer);
88 } 126 }
89 return NeedsAnimate(); 127 return NeedsAnimate();
90 } 128 }
91 129
92 if (!InitializeIfNecessary()) 130 if (!InitializeIfNecessary())
93 return false; 131 return false;
94 132
95 gfx::Vector2dF old_overscroll = accumulated_overscroll - overscroll_delta; 133 gfx::Vector2dF old_overscroll = accumulated_overscroll - overscroll_delta;
96 bool x_overscroll_started = 134 bool x_overscroll_started =
97 !IsApproxZero(overscroll_delta.x()) && IsApproxZero(old_overscroll.x()); 135 !IsApproxZero(overscroll_delta.x()) && IsApproxZero(old_overscroll.x());
98 bool y_overscroll_started = 136 bool y_overscroll_started =
99 !IsApproxZero(overscroll_delta.y()) && IsApproxZero(old_overscroll.y()); 137 !IsApproxZero(overscroll_delta.y()) && IsApproxZero(old_overscroll.y());
100 138
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); 139 velocity = ZeroSmallComponents(velocity);
107 if (!velocity.IsZero()) 140 if (!velocity.IsZero())
108 Absorb(current_time, velocity, x_overscroll_started, y_overscroll_started); 141 Absorb(current_time, velocity, x_overscroll_started, y_overscroll_started);
109 else 142 else
110 Pull(current_time, overscroll_delta); 143 Pull(current_time, overscroll_delta, displacement);
111 144
112 UpdateLayerAttachment(overscrolling_layer); 145 UpdateLayerAttachment(overscrolling_layer);
113 return NeedsAnimate(); 146 return NeedsAnimate();
114 } 147 }
115 148
116 bool OverscrollGlow::Animate(base::TimeTicks current_time) { 149 bool OverscrollGlow::Animate(base::TimeTicks current_time) {
117 if (!NeedsAnimate()) { 150 if (!NeedsAnimate()) {
118 Detach(); 151 Detach();
119 return false; 152 return false;
120 } 153 }
121 154
122 for (size_t i = 0; i < EdgeEffect::EDGE_COUNT; ++i) { 155 for (size_t i = 0; i < EDGE_COUNT; ++i) {
123 if (edge_effects_[i]->Update(current_time)) { 156 if (edge_effects_[i]->Update(current_time)) {
157 Edge edge = static_cast<Edge>(i);
124 edge_effects_[i]->ApplyToLayers( 158 edge_effects_[i]->ApplyToLayers(
125 display_params_.size, 159 ComputeSize(edge, display_params_.size),
126 static_cast<EdgeEffect::Edge>(i), 160 ComputeTransform(
127 kEdgeHeightAtMdpi * display_params_.device_scale_factor, 161 edge, display_params_.size, display_params_.edge_offsets[i]));
128 kGlowHeightAtMdpi * display_params_.device_scale_factor,
129 display_params_.edge_offsets[i]);
130 } 162 }
131 } 163 }
132 164
133 if (!NeedsAnimate()) { 165 if (!NeedsAnimate()) {
134 Detach(); 166 Detach();
135 return false; 167 return false;
136 } 168 }
137 169
138 return true; 170 return true;
139 } 171 }
140 172
141 void OverscrollGlow::UpdateDisplayParameters(const DisplayParameters& params) { 173 void OverscrollGlow::UpdateDisplayParameters(const DisplayParameters& params) {
142 display_params_ = params; 174 display_params_ = params;
143 } 175 }
144 176
145 bool OverscrollGlow::NeedsAnimate() const { 177 bool OverscrollGlow::NeedsAnimate() const {
146 if (!enabled_ || !initialized_) 178 if (!enabled_ || !initialized_)
147 return false; 179 return false;
148 for (size_t i = 0; i < EdgeEffect::EDGE_COUNT; ++i) { 180 for (size_t i = 0; i < EDGE_COUNT; ++i) {
149 if (!edge_effects_[i]->IsFinished()) 181 if (!edge_effects_[i]->IsFinished())
150 return true; 182 return true;
151 } 183 }
152 return false; 184 return false;
153 } 185 }
154 186
155 void OverscrollGlow::UpdateLayerAttachment(cc::Layer* parent) { 187 void OverscrollGlow::UpdateLayerAttachment(cc::Layer* parent) {
156 DCHECK(parent); 188 DCHECK(parent);
157 if (!root_layer_) 189 if (!root_layer_)
158 return; 190 return;
159 191
160 if (!NeedsAnimate()) { 192 if (!NeedsAnimate()) {
161 Detach(); 193 Detach();
162 return; 194 return;
163 } 195 }
164 196
165 if (root_layer_->parent() != parent) 197 if (root_layer_->parent() != parent)
166 parent->AddChild(root_layer_); 198 parent->AddChild(root_layer_);
167 199
168 for (size_t i = 0; i < EdgeEffect::EDGE_COUNT; ++i) 200 for (size_t i = 0; i < EDGE_COUNT; ++i)
169 edge_effects_[i]->SetParent(root_layer_); 201 edge_effects_[i]->SetParent(root_layer_);
170 } 202 }
171 203
172 void OverscrollGlow::Detach() { 204 void OverscrollGlow::Detach() {
173 if (root_layer_) 205 if (root_layer_)
174 root_layer_->RemoveFromParent(); 206 root_layer_->RemoveFromParent();
175 } 207 }
176 208
177 bool OverscrollGlow::InitializeIfNecessary() { 209 bool OverscrollGlow::InitializeIfNecessary() {
178 DCHECK(enabled_); 210 DCHECK(enabled_);
179 if (initialized_) 211 if (initialized_)
180 return true; 212 return true;
181 213
182 DCHECK(!root_layer_); 214 DCHECK(!root_layer_);
183 root_layer_ = cc::Layer::Create(); 215 root_layer_ = cc::Layer::Create();
184 for (size_t i = 0; i < EdgeEffect::EDGE_COUNT; ++i) 216 for (size_t i = 0; i < EDGE_COUNT; ++i) {
185 edge_effects_[i] = make_scoped_ptr(new EdgeEffect(resource_manager_)); 217 edge_effects_[i] = edge_effect_provider_.Run();
218 DCHECK(edge_effects_[i]);
219 }
186 220
187 initialized_ = true; 221 initialized_ = true;
188 return true; 222 return true;
189 } 223 }
190 224
191 void OverscrollGlow::Pull(base::TimeTicks current_time, 225 void OverscrollGlow::Pull(base::TimeTicks current_time,
192 gfx::Vector2dF overscroll_delta) { 226 const gfx::Vector2dF& overscroll_delta,
227 const gfx::Vector2dF& overscroll_location) {
193 DCHECK(enabled_ && initialized_); 228 DCHECK(enabled_ && initialized_);
194 overscroll_delta = ZeroSmallComponents(overscroll_delta); 229 DCHECK(!overscroll_delta.IsZero());
195 if (overscroll_delta.IsZero()) 230 const float inv_width = 1.f / display_params_.size.width();
196 return; 231 const float inv_height = 1.f / display_params_.size.height();
197 232
198 gfx::Vector2dF overscroll_pull = 233 gfx::Vector2dF overscroll_pull =
199 gfx::ScaleVector2d(overscroll_delta, 234 gfx::ScaleVector2d(overscroll_delta, inv_width, inv_height);
200 1.f / display_params_.size.width(), 235 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 236 min(overscroll_pull.y(), 0.f), // Top
204 min(overscroll_pull.x(), 0.f), // Left 237 min(overscroll_pull.x(), 0.f), // Left
205 max(overscroll_pull.y(), 0.f), // Bottom 238 max(overscroll_pull.y(), 0.f), // Bottom
206 max(overscroll_pull.x(), 0.f) // Right 239 max(overscroll_pull.x(), 0.f) // Right
207 }; 240 };
208 241
209 for (size_t i = 0; i < EdgeEffect::EDGE_COUNT; ++i) { 242 gfx::Vector2dF displacement =
210 if (!edge_overscroll_pull[i]) 243 gfx::ScaleVector2d(overscroll_location, inv_width, inv_height);
244 displacement.set_x(max(0.f, min(1.f, displacement.x())));
245 displacement.set_y(max(0.f, min(1.f, displacement.y())));
246 const float edge_displacement[EDGE_COUNT] = {
247 1.f - displacement.x(), // Top
248 displacement.y(), // Left
249 displacement.x(), // Bottom
250 1.f - displacement.y() // Right
251 };
252
253 for (size_t i = 0; i < EDGE_COUNT; ++i) {
254 if (!edge_pull[i])
211 continue; 255 continue;
212 256
213 edge_effects_[i]->Pull(current_time, std::abs(edge_overscroll_pull[i])); 257 edge_effects_[i]->Pull(
258 current_time, std::abs(edge_pull[i]), edge_displacement[i]);
214 GetOppositeEdge(i)->Release(current_time); 259 GetOppositeEdge(i)->Release(current_time);
215 } 260 }
216 } 261 }
217 262
218 void OverscrollGlow::Absorb(base::TimeTicks current_time, 263 void OverscrollGlow::Absorb(base::TimeTicks current_time,
219 gfx::Vector2dF velocity, 264 const gfx::Vector2dF& velocity,
220 bool x_overscroll_started, 265 bool x_overscroll_started,
221 bool y_overscroll_started) { 266 bool y_overscroll_started) {
222 DCHECK(enabled_ && initialized_); 267 DCHECK(enabled_ && initialized_);
223 if (velocity.IsZero()) 268 DCHECK(!velocity.IsZero());
224 return;
225 269
226 // Only trigger on initial overscroll at a non-zero velocity 270 // Only trigger on initial overscroll at a non-zero velocity
227 const float overscroll_velocities[EdgeEffect::EDGE_COUNT] = { 271 const float overscroll_velocities[EDGE_COUNT] = {
228 y_overscroll_started ? min(velocity.y(), 0.f) : 0, // Top 272 y_overscroll_started ? min(velocity.y(), 0.f) : 0, // Top
229 x_overscroll_started ? min(velocity.x(), 0.f) : 0, // Left 273 x_overscroll_started ? min(velocity.x(), 0.f) : 0, // Left
230 y_overscroll_started ? max(velocity.y(), 0.f) : 0, // Bottom 274 y_overscroll_started ? max(velocity.y(), 0.f) : 0, // Bottom
231 x_overscroll_started ? max(velocity.x(), 0.f) : 0 // Right 275 x_overscroll_started ? max(velocity.x(), 0.f) : 0 // Right
232 }; 276 };
233 277
234 for (size_t i = 0; i < EdgeEffect::EDGE_COUNT; ++i) { 278 for (size_t i = 0; i < EDGE_COUNT; ++i) {
235 if (!overscroll_velocities[i]) 279 if (!overscroll_velocities[i])
236 continue; 280 continue;
237 281
238 edge_effects_[i]->Absorb(current_time, std::abs(overscroll_velocities[i])); 282 edge_effects_[i]->Absorb(current_time, std::abs(overscroll_velocities[i]));
239 GetOppositeEdge(i)->Release(current_time); 283 GetOppositeEdge(i)->Release(current_time);
240 } 284 }
241 } 285 }
242 286
243 void OverscrollGlow::Release(base::TimeTicks current_time) { 287 void OverscrollGlow::Release(base::TimeTicks current_time) {
244 DCHECK(initialized_); 288 DCHECK(initialized_);
245 for (size_t i = 0; i < EdgeEffect::EDGE_COUNT; ++i) 289 for (size_t i = 0; i < EDGE_COUNT; ++i)
246 edge_effects_[i]->Release(current_time); 290 edge_effects_[i]->Release(current_time);
247 } 291 }
248 292
249 void OverscrollGlow::ReleaseAxis(Axis axis, base::TimeTicks current_time) { 293 EdgeEffectBase* OverscrollGlow::GetOppositeEdge(int edge_index) {
250 DCHECK(initialized_); 294 DCHECK(initialized_);
251 switch (axis) { 295 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 } 296 }
262 297
263 EdgeEffect* OverscrollGlow::GetOppositeEdge(int edge_index) { 298 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; 299 edge_offsets[0] = edge_offsets[1] = edge_offsets[2] = edge_offsets[3] = 0.f;
271 } 300 }
272 301
273 } // namespace content 302 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/android/overscroll_glow.h ('k') | content/browser/android/system_ui_resource_manager_impl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698