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

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

Issue 367173003: [Android] Implementation of overscroll effect for Android L (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix build Created 6 years, 5 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.nes
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/edge_effect.h" 5 #include "content/browser/android/edge_effect.h"
6 6
7 #include "cc/layers/layer.h" 7 #include "base/debug/trace_event.h"
8 #include "base/lazy_instance.h"
9 #include "cc/layers/image_layer.h"
10 #include "skia/ext/image_operations.h"
11 #include "ui/gfx/android/java_bitmap.h"
8 12
9 namespace content { 13 namespace content {
10 14
11 namespace { 15 namespace {
12 16
13 enum State {
14 STATE_IDLE = 0,
15 STATE_PULL,
16 STATE_ABSORB,
17 STATE_RECEDE,
18 STATE_PULL_DECAY
19 };
20
21 // Time it will take the effect to fully recede in ms 17 // Time it will take the effect to fully recede in ms
22 const int kRecedeTime = 1000; 18 const int kRecedeTime = 1000;
23 19
24 // Time it will take before a pulled glow begins receding in ms 20 // Time it will take before a pulled glow begins receding in ms
25 const int kPullTime = 167; 21 const int kPullTime = 167;
26 22
27 // Time it will take in ms for a pulled glow to decay before release 23 // Time it will take in ms for a pulled glow to decay before release
28 const int kPullDecayTime = 1000; 24 const int kPullDecayTime = 1000;
29 25
30 const float kMaxAlpha = 1.f; 26 const float kMaxAlpha = 1.f;
31 const float kHeldEdgeScaleY = .5f; 27 const float kHeldEdgeScaleY = .5f;
32 28
33 const float kMaxGlowHeight = 4.f; 29 const float kMaxGlowHeight = 4.f;
34 30
35 const float kPullGlowBegin = 1.f; 31 const float kPullGlowBegin = 1.f;
36 const float kPullEdgeBegin = 0.6f; 32 const float kPullEdgeBegin = 0.6f;
37 33
38 // Min/max velocity that will be absorbed 34 // Min/max velocity that will be absorbed
39 const float kMinVelocity = 100.f; 35 const float kMinVelocity = 100.f;
40 const float kMaxVelocity = 10000.f; 36 const float kMaxVelocity = 10000.f;
41 37
42 const float kEpsilon = 0.001f; 38 const float kEpsilon = 0.001f;
43 39
44 const float kGlowHeightToWidthRatio = 0.25f; 40 const float kGlowHeightWidthRatio = 0.25f;
45 41
46 // How much dragging should effect the height of the edge image. 42 // How much dragging should effect the height of the edge image.
47 // Number determined by user testing. 43 // Number determined by user testing.
48 const int kPullDistanceEdgeFactor = 7; 44 const int kPullDistanceEdgeFactor = 7;
49 45
50 // How much dragging should effect the height of the glow image. 46 // How much dragging should effect the height of the glow image.
51 // Number determined by user testing. 47 // Number determined by user testing.
52 const int kPullDistanceGlowFactor = 7; 48 const int kPullDistanceGlowFactor = 7;
53 const float kPullDistanceAlphaGlowFactor = 1.1f; 49 const float kPullDistanceAlphaGlowFactor = 1.1f;
54 50
55 const int kVelocityEdgeFactor = 8; 51 const int kVelocityEdgeFactor = 8;
56 const int kVelocityGlowFactor = 12; 52 const int kVelocityGlowFactor = 12;
57 53
54 const int kScaledEdgeHeight = 12;
55 const int kScaledGlowHeight = 64;
56 const float kEdgeHeightAtMdpi = 12.f;
57 const float kGlowHeightAtMdpi = 128.f;
58
58 template <typename T> 59 template <typename T>
59 T Lerp(T a, T b, T t) { 60 T Lerp(T a, T b, T t) {
60 return a + (b - a) * t; 61 return a + (b - a) * t;
61 } 62 }
62 63
63 template <typename T> 64 template <typename T>
64 T Clamp(T value, T low, T high) { 65 T Clamp(T value, T low, T high) {
65 return value < low ? low : (value > high ? high : value); 66 return value < low ? low : (value > high ? high : value);
66 } 67 }
67 68
68 template <typename T> 69 template <typename T>
69 T Damp(T input, T factor) { 70 T Damp(T input, T factor) {
70 T result; 71 T result;
71 if (factor == 1) { 72 if (factor == 1) {
72 result = 1 - (1 - input) * (1 - input); 73 result = 1 - (1 - input) * (1 - input);
73 } else { 74 } else {
74 result = 1 - std::pow(1 - input, 2 * factor); 75 result = 1 - std::pow(1 - input, 2 * factor);
75 } 76 }
76 return result; 77 return result;
77 } 78 }
78 79
79 gfx::Transform ComputeTransform(EdgeEffect::Edge edge,
80 const gfx::SizeF& window_size,
81 int offset,
82 int height) {
83 // Edge effects that require rotation are translated to the center about which
84 // the layer should be rotated to align with the corresponding edge.
85 switch (edge) {
86 case EdgeEffect::EDGE_TOP:
87 return gfx::Transform(1, 0, 0, 1, 0, offset);
88 case EdgeEffect::EDGE_LEFT:
89 return gfx::Transform(0, 1, -1, 0,
90 (-window_size.height() + height) / 2.f + offset,
91 (window_size.height() - height) / 2.f);
92 case EdgeEffect::EDGE_BOTTOM:
93 return gfx::Transform(-1, 0, 0, -1,
94 0, window_size.height() - height + offset);
95 case EdgeEffect::EDGE_RIGHT:
96 return gfx::Transform(0, -1, 1, 0,
97 (-window_size.height() - height) / 2.f + window_size.width() + offset,
98 (window_size.height() - height) / 2.f);
99 default:
100 NOTREACHED() << "Invalid edge: " << edge;
101 return gfx::Transform();
102 };
103 }
104
105 gfx::Size ComputeBounds(EdgeEffect::Edge edge,
106 const gfx::SizeF& window_size,
107 int height) {
108 switch (edge) {
109 case EdgeEffect::EDGE_TOP:
110 case EdgeEffect::EDGE_BOTTOM:
111 return gfx::Size(window_size.width(), height);
112 case EdgeEffect::EDGE_LEFT:
113 case EdgeEffect::EDGE_RIGHT:
114 return gfx::Size(window_size.height(), height);
115 default:
116 NOTREACHED() << "Invalid edge: " << edge;
117 return gfx::Size();
118 };
119 }
120
121 void DisableLayer(cc::Layer* layer) { 80 void DisableLayer(cc::Layer* layer) {
122 DCHECK(layer); 81 DCHECK(layer);
123 layer->SetIsDrawable(false); 82 layer->SetIsDrawable(false);
124 layer->SetTransform(gfx::Transform()); 83 layer->SetTransform(gfx::Transform());
125 layer->SetOpacity(1.f); 84 layer->SetOpacity(1.f);
126 } 85 }
127 86
128 void UpdateLayer(cc::Layer* layer, 87 void UpdateLayer(cc::Layer* layer,
129 EdgeEffect::Edge edge, 88 const gfx::Size& size,
130 const gfx::SizeF& window_size, 89 const gfx::Transform& transform,
131 int offset,
132 int height,
133 float opacity) { 90 float opacity) {
134 DCHECK(layer); 91 DCHECK(layer);
135 layer->SetIsDrawable(true); 92 layer->SetIsDrawable(true);
136 gfx::Size bounds = ComputeBounds(edge, window_size, height); 93 layer->SetTransformOrigin(gfx::Point3F(size.width() * 0.5f, 0, 0));
137 layer->SetTransformOrigin( 94 layer->SetTransform(transform);
138 gfx::Point3F(bounds.width() * 0.5f, bounds.height() * 0.5f, 0)); 95 layer->SetBounds(size);
139 layer->SetTransform(ComputeTransform(edge, window_size, offset, height));
140 layer->SetBounds(bounds);
141 layer->SetOpacity(Clamp(opacity, 0.f, 1.f)); 96 layer->SetOpacity(Clamp(opacity, 0.f, 1.f));
142 } 97 }
143 98
99 scoped_refptr<cc::Layer> CreateImageLayer(const SkBitmap& bitmap) {
100 scoped_refptr<cc::ImageLayer> layer = cc::ImageLayer::Create();
101 layer->SetBitmap(bitmap);
102 return layer;
103 }
104
105 SkBitmap CreateSkBitmapFromAndroidResource(const char* name, gfx::Size size) {
106 base::android::ScopedJavaLocalRef<jobject> jobj =
107 gfx::CreateJavaBitmapFromAndroidResource(name, size);
108 if (jobj.is_null())
109 return SkBitmap();
110
111 SkBitmap bitmap = CreateSkBitmapFromJavaBitmap(gfx::JavaBitmap(jobj.obj()));
112 if (bitmap.isNull())
113 return bitmap;
114
115 return skia::ImageOperations::Resize(
116 bitmap, skia::ImageOperations::RESIZE_BOX, size.width(), size.height());
117 }
118
119 class EdgeEffectResources {
120 public:
121 EdgeEffectResources() {
122 TRACE_EVENT0("browser", "EdgeEffectResources::Create");
123 edge_bitmap_ =
124 CreateSkBitmapFromAndroidResource("android:drawable/overscroll_edge",
125 gfx::Size(128, kScaledEdgeHeight));
126 glow_bitmap_ =
127 CreateSkBitmapFromAndroidResource("android:drawable/overscroll_glow",
128 gfx::Size(128, kScaledGlowHeight));
129 }
130
131 const SkBitmap& edge_bitmap() const { return edge_bitmap_; }
132 const SkBitmap& glow_bitmap() const { return glow_bitmap_; }
133
134 private:
135 SkBitmap edge_bitmap_;
136 SkBitmap glow_bitmap_;
137
138 DISALLOW_COPY_AND_ASSIGN(EdgeEffectResources);
139 };
140
141 // Leaky to allow access from a worker thread.
142 base::LazyInstance<EdgeEffectResources>::Leaky g_edge_effect_resources =
143 LAZY_INSTANCE_INITIALIZER;
144
144 } // namespace 145 } // namespace
145 146
146 EdgeEffect::EdgeEffect(scoped_refptr<cc::Layer> edge, 147 // static
147 scoped_refptr<cc::Layer> glow) 148 scoped_ptr<EdgeEffect> EdgeEffect::Create(cc::Layer* root_layer,
149 float device_scale_factor) {
150 DCHECK(root_layer);
151
152 const SkBitmap& edge = g_edge_effect_resources.Get().edge_bitmap();
153 const SkBitmap& glow = g_edge_effect_resources.Get().glow_bitmap();
154 if (edge.isNull() || glow.isNull())
155 return scoped_ptr<EdgeEffect>();
156
157 scoped_refptr<cc::Layer> edge_layer = CreateImageLayer(edge);
158 scoped_refptr<cc::Layer> glow_layer = CreateImageLayer(glow);
159 root_layer->AddChild(edge_layer);
160 root_layer->AddChild(glow_layer);
161 return make_scoped_ptr(
162 new EdgeEffect(edge_layer, glow_layer, device_scale_factor));
163 }
164
165 EdgeEffect::EdgeEffect(const scoped_refptr<cc::Layer>& edge,
166 const scoped_refptr<cc::Layer>& glow,
167 float device_scale_factor)
148 : edge_(edge) 168 : edge_(edge)
149 , glow_(glow) 169 , glow_(glow)
170 , base_edge_height_(kEdgeHeightAtMdpi * device_scale_factor)
171 , base_glow_height_(kGlowHeightAtMdpi * device_scale_factor)
150 , edge_alpha_(0) 172 , edge_alpha_(0)
151 , edge_scale_y_(0) 173 , edge_scale_y_(0)
152 , glow_alpha_(0) 174 , glow_alpha_(0)
153 , glow_scale_y_(0) 175 , glow_scale_y_(0)
154 , edge_alpha_start_(0) 176 , edge_alpha_start_(0)
155 , edge_alpha_finish_(0) 177 , edge_alpha_finish_(0)
156 , edge_scale_y_start_(0) 178 , edge_scale_y_start_(0)
157 , edge_scale_y_finish_(0) 179 , edge_scale_y_finish_(0)
158 , glow_alpha_start_(0) 180 , glow_alpha_start_(0)
159 , glow_alpha_finish_(0) 181 , glow_alpha_finish_(0)
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
234 256
235 edge_alpha_finish_ = 0.f; 257 edge_alpha_finish_ = 0.f;
236 edge_scale_y_finish_ = 0.f; 258 edge_scale_y_finish_ = 0.f;
237 glow_alpha_finish_ = 0.f; 259 glow_alpha_finish_ = 0.f;
238 glow_scale_y_finish_ = 0.f; 260 glow_scale_y_finish_ = 0.f;
239 261
240 start_time_ = current_time; 262 start_time_ = current_time;
241 duration_ = base::TimeDelta::FromMilliseconds(kRecedeTime); 263 duration_ = base::TimeDelta::FromMilliseconds(kRecedeTime);
242 } 264 }
243 265
266 void EdgeEffect::Pull(base::TimeTicks current_time,
267 float delta_distance,
268 float displacement) {
269 Pull(current_time, delta_distance);
270 }
271
244 void EdgeEffect::Absorb(base::TimeTicks current_time, float velocity) { 272 void EdgeEffect::Absorb(base::TimeTicks current_time, float velocity) {
245 state_ = STATE_ABSORB; 273 state_ = STATE_ABSORB;
246 velocity = Clamp(std::abs(velocity), kMinVelocity, kMaxVelocity); 274 velocity = Clamp(std::abs(velocity), kMinVelocity, kMaxVelocity);
247 275
248 start_time_ = current_time; 276 start_time_ = current_time;
249 // This should never be less than 1 millisecond. 277 // This should never be less than 1 millisecond.
250 duration_ = base::TimeDelta::FromMilliseconds(0.15f + (velocity * 0.02f)); 278 duration_ = base::TimeDelta::FromMilliseconds(0.15f + (velocity * 0.02f));
251 279
252 // The edge should always be at least partially visible, regardless 280 // The edge should always be at least partially visible, regardless
253 // of velocity. 281 // of velocity.
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
341 break; 369 break;
342 } 370 }
343 } 371 }
344 372
345 if (state_ == STATE_RECEDE && glow_scale_y_ <= 0 && edge_scale_y_ <= 0) 373 if (state_ == STATE_RECEDE && glow_scale_y_ <= 0 && edge_scale_y_ <= 0)
346 Finish(); 374 Finish();
347 375
348 return !IsFinished(); 376 return !IsFinished();
349 } 377 }
350 378
351 void EdgeEffect::ApplyToLayers(gfx::SizeF window_size, 379 void EdgeEffect::ApplyToLayers(const gfx::SizeF& size,
352 Edge edge, 380 const gfx::Transform& transform) {
353 float edge_height,
354 float glow_height,
355 float offset) {
356 if (IsFinished()) 381 if (IsFinished())
357 return; 382 return;
358 383
359 // An empty window size, while meaningless, is also relatively harmless, and 384 // An empty window size, while meaningless, is also relatively harmless, and
360 // will simply prevent any drawing of the layers. 385 // will simply prevent any drawing of the layers.
361 if (window_size.IsEmpty()) { 386 if (size.IsEmpty()) {
362 DisableLayer(edge_.get()); 387 DisableLayer(edge_.get());
363 DisableLayer(glow_.get()); 388 DisableLayer(glow_.get());
364 return; 389 return;
365 } 390 }
366 391
367 // Glow 392 // Glow
368 const int scaled_glow_height = static_cast<int>( 393 const int scaled_glow_height = static_cast<int>(
369 std::min(glow_height * glow_scale_y_ * kGlowHeightToWidthRatio * 0.6f, 394 std::min(base_glow_height_ * glow_scale_y_ * kGlowHeightWidthRatio * 0.6f,
370 glow_height * kMaxGlowHeight) + 0.5f); 395 base_glow_height_ * kMaxGlowHeight) + 0.5f);
371 UpdateLayer( 396 const gfx::Size glow_size(size.width(), scaled_glow_height);
372 glow_.get(), edge, window_size, offset, scaled_glow_height, glow_alpha_); 397 UpdateLayer(glow_.get(), glow_size, transform, glow_alpha_);
373 398
374 // Edge 399 // Edge
375 const int scaled_edge_height = static_cast<int>(edge_height * edge_scale_y_); 400 const int scaled_edge_height =
376 UpdateLayer( 401 static_cast<int>(base_edge_height_ * edge_scale_y_);
377 edge_.get(), edge, window_size, offset, scaled_edge_height, edge_alpha_); 402 const gfx::Size edge_size(size.width(), scaled_edge_height);
403 UpdateLayer(edge_.get(), edge_size, transform, edge_alpha_);
404 }
405
406 // static
407 void EdgeEffect::EnsureResources() {
408 g_edge_effect_resources.Get();
378 } 409 }
379 410
380 } // namespace content 411 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698