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

Side by Side Diff: content/browser/web_contents/aura/gesture_nav_simple.cc

Issue 2656463002: Implement MD simple gesture nav (Closed)
Patch Set: Rebased Created 3 years, 10 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 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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/web_contents/aura/gesture_nav_simple.h" 5 #include "content/browser/web_contents/aura/gesture_nav_simple.h"
6 6
7 #include <utility> 7 #include <utility>
8 8
9 #include "base/macros.h" 9 #include "base/macros.h"
10 #include "cc/layers/layer.h"
11 #include "cc/paint/paint_flags.h" 10 #include "cc/paint/paint_flags.h"
12 #include "content/browser/frame_host/navigation_controller_impl.h" 11 #include "content/browser/frame_host/navigation_controller_impl.h"
13 #include "content/browser/renderer_host/overscroll_controller.h" 12 #include "content/browser/renderer_host/overscroll_controller.h"
14 #include "content/browser/web_contents/web_contents_impl.h" 13 #include "content/browser/web_contents/web_contents_impl.h"
15 #include "content/browser/web_contents/web_contents_view.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "content/public/browser/overscroll_configuration.h" 14 #include "content/public/browser/overscroll_configuration.h"
18 #include "content/public/common/content_client.h" 15 #include "third_party/skia/include/core/SkDrawLooper.h"
19 #include "ui/aura/window.h" 16 #include "ui/aura/window.h"
20 #include "ui/compositor/layer.h" 17 #include "ui/compositor/layer.h"
21 #include "ui/compositor/layer_animation_observer.h"
22 #include "ui/compositor/layer_delegate.h" 18 #include "ui/compositor/layer_delegate.h"
23 #include "ui/compositor/paint_recorder.h" 19 #include "ui/compositor/paint_recorder.h"
24 #include "ui/compositor/scoped_layer_animation_settings.h" 20 #include "ui/gfx/animation/animation_delegate.h"
21 #include "ui/gfx/animation/linear_animation.h"
25 #include "ui/gfx/animation/tween.h" 22 #include "ui/gfx/animation/tween.h"
26 #include "ui/gfx/canvas.h" 23 #include "ui/gfx/canvas.h"
27 #include "ui/gfx/image/image.h" 24 #include "ui/gfx/color_palette.h"
28 #include "ui/resources/grit/ui_resources.h" 25 #include "ui/gfx/paint_vector_icon.h"
26 #include "ui/gfx/shadow_value.h"
27 #include "ui/gfx/skia_paint_util.h"
28 #include "ui/resources/vector_icons/vector_icons.h"
29 29
30 namespace content { 30 namespace content {
31 31
32 namespace { 32 namespace {
33 33
34 const int kArrowHeight = 280; 34 // Parameters defining the arrow icon inside the affordance.
35 const int kArrowWidth = 140; 35 const int kArrowSize = 16;
36 const float kMinOpacity = 0.25f; 36 const SkColor kArrowColor = gfx::kGoogleBlue500;
37
38 // Parameters defining the background circle of the affordance.
39 const int kBackgroundRadius = 18;
40 const SkColor kBackgroundColor = SK_ColorWHITE;
41 const int kBgShadowOffsetY = 2;
42 const int kBgShadowBlurRadius = 8;
43 const SkColor kBgShadowColor = SkColorSetA(SK_ColorBLACK, 0x4D);
44
45 // Parameters defining the affordance ripple. The ripple fades in and grows as
46 // the user drags the affordance until it reaches |kMaxRippleRadius|. If the
47 // overscroll is successful, the ripple will burst by fading out and growing to
48 // |kMaxRippleBurstRadius|.
49 const int kMaxRippleRadius = 54;
50 const SkColor kRippleColor = SkColorSetA(gfx::kGoogleBlue500, 0x33);
51 const int kMaxRippleBurstRadius = 72;
52 const gfx::Tween::Type kBurstAnimationTweenType = gfx::Tween::EASE_IN;
53 const int kRippleBurstAnimationDuration = 160;
54
55 // Offset of the affordance when it is at the maximum distance with content
56 // border. Since the affordance is initially out of content bounds, this is the
57 // offset of the farther side of the affordance (which equals 128 + 18).
58 const int kMaxAffordanceOffset = 146;
59
60 // Parameters defining animation when the affordance is aborted.
61 const gfx::Tween::Type kAbortAnimationTweenType = gfx::Tween::EASE_IN;
62 const int kAbortAnimationDuration = 300;
37 63
38 bool ShouldNavigateForward(const NavigationController& controller, 64 bool ShouldNavigateForward(const NavigationController& controller,
39 OverscrollMode mode) { 65 OverscrollMode mode) {
40 return mode == (base::i18n::IsRTL() ? OVERSCROLL_EAST : OVERSCROLL_WEST) && 66 return mode == (base::i18n::IsRTL() ? OVERSCROLL_EAST : OVERSCROLL_WEST) &&
41 controller.CanGoForward(); 67 controller.CanGoForward();
42 } 68 }
43 69
44 bool ShouldNavigateBack(const NavigationController& controller, 70 bool ShouldNavigateBack(const NavigationController& controller,
45 OverscrollMode mode) { 71 OverscrollMode mode) {
46 return mode == (base::i18n::IsRTL() ? OVERSCROLL_WEST : OVERSCROLL_EAST) && 72 return mode == (base::i18n::IsRTL() ? OVERSCROLL_WEST : OVERSCROLL_EAST) &&
47 controller.CanGoBack(); 73 controller.CanGoBack();
48 } 74 }
49 75
50 // An animation observers that deletes itself and a pointer after the end of the 76 } // namespace
51 // animation. 77
52 template <class T> 78 // This class is responsible for creating, painting, and positioning the layer
53 class DeleteAfterAnimation : public ui::ImplicitAnimationObserver { 79 // for the gesture nav affordance.
80 class GestureNavSimple::Affordance : public ui::LayerDelegate,
81 public gfx::AnimationDelegate {
54 public: 82 public:
55 explicit DeleteAfterAnimation(std::unique_ptr<T> object) 83 Affordance(OverscrollMode mode, const gfx::Rect& content_bounds);
56 : object_(std::move(object)) {} 84 ~Affordance() override;
85
86 // Sets progress of affordance drag as a value between 0 and 1.
87 void SetDragProgress(float progress);
88
89 // Aborts the affordance and animates it back. This will delete |this|
90 // instance after the animation.
91 void Abort();
92
93 // Completes the affordance by doing a ripple burst animation. This will
94 // delete |this| instance after the animation.
95 void Complete();
96
97 // Returns the root layer of the affordance.
98 ui::Layer* root_layer() const { return root_layer_.get(); }
57 99
58 private: 100 private:
59 friend class base::DeleteHelper<DeleteAfterAnimation<T> >; 101 enum class State { DRAGGING, ABORTING, COMPLETING };
60 102
61 ~DeleteAfterAnimation() override {} 103 void UpdateTransform();
62 104 void SchedulePaint();
63 // ui::ImplicitAnimationObserver: 105 void SetAbortProgress(float progress);
64 void OnImplicitAnimationsCompleted() override { 106 void SetCompleteProgress(float progress);
65 // Deleting an observer when a ScopedLayerAnimationSettings is iterating 107
66 // over them can cause a crash (which can happen during tests). So instead, 108 // ui::LayerDelegate:
67 // schedule this observer to be deleted soon. 109 void OnPaintLayer(const ui::PaintContext& context) override;
68 BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, this); 110 void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override;
111 void OnDeviceScaleFactorChanged(float device_scale_factor) override;
112
113 // gfx::AnimationDelegate:
114 void AnimationEnded(const gfx::Animation* animation) override;
115 void AnimationProgressed(const gfx::Animation* animation) override;
116 void AnimationCanceled(const gfx::Animation* animation) override;
117
118 const OverscrollMode mode_;
119
120 // Root layer of the affordance. This is used to clip the affordance to the
121 // content bounds.
122 std::unique_ptr<ui::Layer> root_layer_;
123
124 // Layer that actually paints the affordance.
125 std::unique_ptr<ui::Layer> painted_layer_;
126
127 // Arrow image to be used for the affordance.
128 const gfx::Image image_;
129
130 // Values that determine current state of the affordance.
131 State state_ = State::DRAGGING;
132 float drag_progress_ = 0.f;
133 float abort_progress_ = 0.f;
134 float complete_progress_ = 0.f;
135
136 std::unique_ptr<gfx::LinearAnimation> animation_;
137
138 DISALLOW_COPY_AND_ASSIGN(Affordance);
139 };
140
141 GestureNavSimple::Affordance::Affordance(OverscrollMode mode,
142 const gfx::Rect& content_bounds)
143 : mode_(mode),
144 root_layer_(base::MakeUnique<ui::Layer>(ui::LAYER_NOT_DRAWN)),
145 painted_layer_(base::MakeUnique<ui::Layer>(ui::LAYER_TEXTURED)),
146 image_(gfx::CreateVectorIcon(mode == OVERSCROLL_EAST
147 ? ui::kNavigateBackIcon
148 : ui::kNavigateForwardIcon,
149 kArrowSize,
150 kArrowColor)) {
151 DCHECK(mode == OVERSCROLL_EAST || mode == OVERSCROLL_WEST);
152 DCHECK(!image_.IsEmpty());
153
154 root_layer_->SetBounds(content_bounds);
155 root_layer_->SetMasksToBounds(true);
156
157 painted_layer_->SetFillsBoundsOpaquely(false);
158 int x =
159 mode_ == OVERSCROLL_EAST
160 ? -kMaxRippleBurstRadius - kBackgroundRadius
161 : content_bounds.width() - kMaxRippleBurstRadius + kBackgroundRadius;
162 int y = std::max(0, content_bounds.height() / 2 - kMaxRippleBurstRadius);
163 painted_layer_->SetBounds(
164 gfx::Rect(x, y, 2 * kMaxRippleBurstRadius, 2 * kMaxRippleBurstRadius));
165 painted_layer_->set_delegate(this);
166
167 root_layer_->Add(painted_layer_.get());
168 }
169
170 GestureNavSimple::Affordance::~Affordance() {}
171
172 void GestureNavSimple::Affordance::SetDragProgress(float progress) {
173 DCHECK_EQ(State::DRAGGING, state_);
174 DCHECK_LE(0.f, progress);
175 DCHECK_GE(1.f, progress);
176
177 if (drag_progress_ == progress)
178 return;
179 drag_progress_ = progress;
180
181 UpdateTransform();
182 SchedulePaint();
183 }
184
185 void GestureNavSimple::Affordance::Abort() {
186 DCHECK_EQ(State::DRAGGING, state_);
187
188 state_ = State::ABORTING;
189
190 animation_.reset(
191 new gfx::LinearAnimation(drag_progress_ * kAbortAnimationDuration,
192 gfx::LinearAnimation::kDefaultFrameRate, this));
193 animation_->Start();
194 }
195
196 void GestureNavSimple::Affordance::Complete() {
197 DCHECK_EQ(State::DRAGGING, state_);
198 DCHECK_EQ(1.f, drag_progress_);
199
200 state_ = State::COMPLETING;
201
202 animation_.reset(
203 new gfx::LinearAnimation(kRippleBurstAnimationDuration,
204 gfx::LinearAnimation::kDefaultFrameRate, this));
205 animation_->Start();
206 }
207
208 void GestureNavSimple::Affordance::UpdateTransform() {
209 float offset = (1 - abort_progress_) * drag_progress_ * kMaxAffordanceOffset;
210 gfx::Transform transform;
211 transform.Translate(mode_ == OVERSCROLL_EAST ? offset : -offset, 0);
212 painted_layer_->SetTransform(transform);
213 }
214
215 void GestureNavSimple::Affordance::SchedulePaint() {
216 painted_layer_->SchedulePaint(gfx::Rect(painted_layer_->size()));
217 }
218
219 void GestureNavSimple::Affordance::SetAbortProgress(float progress) {
220 DCHECK_EQ(State::ABORTING, state_);
221 DCHECK_LE(0.f, progress);
222 DCHECK_GE(1.f, progress);
223
224 if (abort_progress_ == progress)
225 return;
226 abort_progress_ = progress;
227
228 UpdateTransform();
229 SchedulePaint();
230 }
231
232 void GestureNavSimple::Affordance::SetCompleteProgress(float progress) {
233 DCHECK_EQ(State::COMPLETING, state_);
234 DCHECK_LE(0.f, progress);
235 DCHECK_GE(1.f, progress);
236
237 if (complete_progress_ == progress)
238 return;
239 complete_progress_ = progress;
240
241 painted_layer_->SetOpacity(1 - complete_progress_);
242 SchedulePaint();
243 }
244
245 void GestureNavSimple::Affordance::OnPaintLayer(
246 const ui::PaintContext& context) {
247 DCHECK(drag_progress_ == 1.f || state_ != State::COMPLETING);
248 DCHECK(abort_progress_ == 0.f || state_ == State::ABORTING);
249 DCHECK(complete_progress_ == 0.f || state_ == State::COMPLETING);
250
251 ui::PaintRecorder recorder(context, painted_layer_->size());
252 gfx::Canvas* canvas = recorder.canvas();
253
254 gfx::PointF center_point(kMaxRippleBurstRadius, kMaxRippleBurstRadius);
255 float progress = (1 - abort_progress_) * drag_progress_;
256
257 // Draw the ripple.
258 cc::PaintFlags ripple_paint;
259 ripple_paint.setAntiAlias(true);
260 ripple_paint.setStyle(cc::PaintFlags::kFill_Style);
261 ripple_paint.setColor(kRippleColor);
262 float ripple_radius;
263 if (state_ == State::COMPLETING) {
264 ripple_radius =
265 kMaxRippleRadius +
266 complete_progress_ * (kMaxRippleBurstRadius - kMaxRippleRadius);
267 } else {
268 ripple_radius =
269 kBackgroundRadius + progress * (kMaxRippleRadius - kBackgroundRadius);
69 } 270 }
70 271 canvas->DrawCircle(center_point, ripple_radius, ripple_paint);
71 std::unique_ptr<T> object_; 272
72 DISALLOW_COPY_AND_ASSIGN(DeleteAfterAnimation); 273 // Draw the arrow background circle with the shadow.
73 }; 274 cc::PaintFlags bg_paint;
74 275 bg_paint.setAntiAlias(true);
75 } // namespace 276 bg_paint.setStyle(cc::PaintFlags::kFill_Style);
76 277 bg_paint.setColor(kBackgroundColor);
77 // A layer delegate that paints the shield with the arrow in it. 278 gfx::ShadowValues shadow;
78 class ArrowLayerDelegate : public ui::LayerDelegate { 279 shadow.emplace_back(gfx::Vector2d(0, kBgShadowOffsetY), kBgShadowBlurRadius,
79 public: 280 kBgShadowColor);
80 explicit ArrowLayerDelegate(int resource_id) 281 bg_paint.setLooper(gfx::CreateShadowDrawLooperCorrectBlur(shadow));
81 : image_(GetContentClient()->GetNativeImageNamed(resource_id)), 282 canvas->DrawCircle(center_point, kBackgroundRadius, bg_paint);
82 left_arrow_(resource_id == IDR_BACK_ARROW) { 283
83 CHECK(!image_.IsEmpty()); 284 // Draw the arrow.
285 float arrow_x = center_point.x() - kArrowSize / 2.f;
286 float arrow_y = center_point.y() - kArrowSize / 2.f;
287 // Calculate the offset for the arrow relative to its circular background.
288 float arrow_x_offset =
289 (1 - progress) * (-kBackgroundRadius + kArrowSize / 2.f);
290 arrow_x += mode_ == OVERSCROLL_EAST ? arrow_x_offset : -arrow_x_offset;
291 uint8_t arrow_alpha =
292 static_cast<uint8_t>(std::min(0xFF, static_cast<int>(progress * 0xFF)));
293 canvas->DrawImageInt(*image_.ToImageSkia(), static_cast<int>(arrow_x),
294 static_cast<int>(arrow_y), arrow_alpha);
295 }
296
297 void GestureNavSimple::Affordance::OnDelegatedFrameDamage(
298 const gfx::Rect& damage_rect_in_dip) {}
299
300 void GestureNavSimple::Affordance::OnDeviceScaleFactorChanged(
301 float device_scale_factor) {}
302
303 void GestureNavSimple::Affordance::AnimationEnded(
304 const gfx::Animation* animation) {
305 delete this;
306 }
307
308 void GestureNavSimple::Affordance::AnimationProgressed(
309 const gfx::Animation* animation) {
310 switch (state_) {
311 case State::DRAGGING:
312 NOTREACHED();
313 break;
314 case State::ABORTING:
315 SetAbortProgress(gfx::Tween::CalculateValue(
316 kAbortAnimationTweenType, animation->GetCurrentValue()));
317 break;
318 case State::COMPLETING:
319 SetCompleteProgress(gfx::Tween::CalculateValue(
320 kBurstAnimationTweenType, animation->GetCurrentValue()));
321 break;
84 } 322 }
85 323 }
86 ~ArrowLayerDelegate() override {} 324
87 325 void GestureNavSimple::Affordance::AnimationCanceled(
88 bool left() const { return left_arrow_; } 326 const gfx::Animation* animation) {
89 327 NOTREACHED();
90 private: 328 }
91 // ui::LayerDelegate: 329
92 void OnPaintLayer(const ui::PaintContext& context) override {
93 cc::PaintFlags paint;
94 paint.setColor(SkColorSetARGB(0xa0, 0, 0, 0));
95 paint.setStyle(cc::PaintFlags::kFill_Style);
96 paint.setAntiAlias(true);
97
98 // Set the recording size to be the size of the |arrow_| layer, and draw a
99 // half circle (the other half will be clipped), then an arrow image inside
100 // it.
101 ui::PaintRecorder recorder(context, gfx::Size(kArrowWidth, kArrowHeight));
102 recorder.canvas()->DrawCircle(
103 gfx::Point(left_arrow_ ? 0 : kArrowWidth, kArrowHeight / 2),
104 kArrowWidth, paint);
105 recorder.canvas()->DrawImageInt(
106 *image_.ToImageSkia(), left_arrow_ ? 0 : kArrowWidth - image_.Width(),
107 (kArrowHeight - image_.Height()) / 2);
108 }
109
110 void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override {}
111
112 void OnDeviceScaleFactorChanged(float device_scale_factor) override {}
113
114 const gfx::Image& image_;
115 const bool left_arrow_;
116
117 DISALLOW_COPY_AND_ASSIGN(ArrowLayerDelegate);
118 };
119 330
120 GestureNavSimple::GestureNavSimple(WebContentsImpl* web_contents) 331 GestureNavSimple::GestureNavSimple(WebContentsImpl* web_contents)
121 : web_contents_(web_contents), 332 : web_contents_(web_contents),
122 completion_threshold_(0.f) {} 333 completion_threshold_(0.f) {}
123 334
124 GestureNavSimple::~GestureNavSimple() {} 335 GestureNavSimple::~GestureNavSimple() {}
125 336
126 void GestureNavSimple::ApplyEffectsAndDestroy(const gfx::Transform& transform,
127 float opacity) {
128 ui::Layer* layer = arrow_.get();
129 ui::ScopedLayerAnimationSettings settings(arrow_->GetAnimator());
130 settings.AddObserver(
131 new DeleteAfterAnimation<ArrowLayerDelegate>(std::move(arrow_delegate_)));
132 settings.AddObserver(new DeleteAfterAnimation<ui::Layer>(std::move(arrow_)));
133 settings.AddObserver(
134 new DeleteAfterAnimation<ui::Layer>(std::move(clip_layer_)));
135 layer->SetTransform(transform);
136 layer->SetOpacity(opacity);
137 }
138
139 void GestureNavSimple::AbortGestureAnimation() { 337 void GestureNavSimple::AbortGestureAnimation() {
140 if (!arrow_) 338 if (!affordance_)
141 return; 339 return;
142 gfx::Transform transform; 340 // Release the unique pointer. The affordance will delete itself upon
143 transform.Translate(arrow_delegate_->left() ? -kArrowWidth : kArrowWidth, 0); 341 // completion of animation.
144 ApplyEffectsAndDestroy(transform, kMinOpacity); 342 Affordance* affordance = affordance_.release();
343 affordance->Abort();
145 } 344 }
146 345
147 void GestureNavSimple::CompleteGestureAnimation() { 346 void GestureNavSimple::CompleteGestureAnimation() {
148 if (!arrow_) 347 if (!affordance_)
149 return; 348 return;
150 // Make sure the fade-out starts from the complete state. 349 // Release the unique pointer. The affordance will delete itself upon
151 ApplyEffectsForDelta(completion_threshold_); 350 // completion of animation.
152 ApplyEffectsAndDestroy(arrow_->transform(), 0.f); 351 Affordance* affordance = affordance_.release();
153 } 352 affordance->Complete();
154
155 bool GestureNavSimple::ApplyEffectsForDelta(float delta_x) {
156 if (!arrow_)
157 return false;
158 CHECK_GT(completion_threshold_, 0.f);
159 CHECK_GE(delta_x, 0.f);
160 double complete = std::min(1.f, delta_x / completion_threshold_);
161 float translate_x = gfx::Tween::FloatValueBetween(complete, -kArrowWidth, 0);
162 gfx::Transform transform;
163 transform.Translate(arrow_delegate_->left() ? translate_x : -translate_x,
164 0.f);
165 arrow_->SetTransform(transform);
166 arrow_->SetOpacity(gfx::Tween::FloatValueBetween(complete, kMinOpacity, 1.f));
167 return true;
168 } 353 }
169 354
170 gfx::Rect GestureNavSimple::GetVisibleBounds() const { 355 gfx::Rect GestureNavSimple::GetVisibleBounds() const {
171 return web_contents_->GetNativeView()->bounds(); 356 return web_contents_->GetNativeView()->bounds();
172 } 357 }
173 358
174 bool GestureNavSimple::OnOverscrollUpdate(float delta_x, float delta_y) { 359 bool GestureNavSimple::OnOverscrollUpdate(float delta_x, float delta_y) {
175 return ApplyEffectsForDelta(std::abs(delta_x) + 50.f); 360 if (!affordance_)
361 return false;
362 affordance_->SetDragProgress(
363 std::min(1.f, std::abs(delta_x) / completion_threshold_));
364 return true;
176 } 365 }
177 366
178 void GestureNavSimple::OnOverscrollComplete(OverscrollMode overscroll_mode) { 367 void GestureNavSimple::OnOverscrollComplete(OverscrollMode overscroll_mode) {
179 CompleteGestureAnimation(); 368 CompleteGestureAnimation();
180 369
181 NavigationControllerImpl& controller = web_contents_->GetController(); 370 NavigationControllerImpl& controller = web_contents_->GetController();
182 if (ShouldNavigateForward(controller, overscroll_mode)) 371 if (ShouldNavigateForward(controller, overscroll_mode))
183 controller.GoForward(); 372 controller.GoForward();
184 else if (ShouldNavigateBack(controller, overscroll_mode)) 373 else if (ShouldNavigateBack(controller, overscroll_mode))
185 controller.GoBack(); 374 controller.GoBack();
186 } 375 }
187 376
188 void GestureNavSimple::OnOverscrollModeChange(OverscrollMode old_mode, 377 void GestureNavSimple::OnOverscrollModeChange(OverscrollMode old_mode,
189 OverscrollMode new_mode) { 378 OverscrollMode new_mode) {
190 NavigationControllerImpl& controller = web_contents_->GetController(); 379 NavigationControllerImpl& controller = web_contents_->GetController();
191 if (!ShouldNavigateForward(controller, new_mode) && 380 if (!ShouldNavigateForward(controller, new_mode) &&
192 !ShouldNavigateBack(controller, new_mode)) { 381 !ShouldNavigateBack(controller, new_mode)) {
193 AbortGestureAnimation(); 382 AbortGestureAnimation();
194 return; 383 return;
195 } 384 }
196 385
197 arrow_.reset(new ui::Layer(ui::LAYER_TEXTURED));
198 // Note that RTL doesn't affect the arrow that should be displayed.
199 int resource_id = 0;
200 if (new_mode == OVERSCROLL_WEST)
201 resource_id = IDR_FORWARD_ARROW;
202 else if (new_mode == OVERSCROLL_EAST)
203 resource_id = IDR_BACK_ARROW;
204 else
205 NOTREACHED();
206
207 arrow_delegate_.reset(new ArrowLayerDelegate(resource_id));
208 arrow_->set_delegate(arrow_delegate_.get());
209 arrow_->SetFillsBoundsOpaquely(false);
210
211 aura::Window* window = web_contents_->GetNativeView(); 386 aura::Window* window = web_contents_->GetNativeView();
212 const gfx::Rect& window_bounds = window->bounds(); 387 const gfx::Rect& window_bounds = window->bounds();
213 completion_threshold_ = window_bounds.width() * 388 completion_threshold_ =
214 GetOverscrollConfig(OVERSCROLL_CONFIG_HORIZ_THRESHOLD_COMPLETE); 389 window_bounds.width() *
390 GetOverscrollConfig(OVERSCROLL_CONFIG_HORIZ_THRESHOLD_COMPLETE) -
391 GetOverscrollConfig(OVERSCROLL_CONFIG_HORIZ_THRESHOLD_START_TOUCHSCREEN);
215 392
216 // Align on the left or right edge. 393 affordance_.reset(new Affordance(new_mode, window_bounds));
217 int x = (resource_id == IDR_BACK_ARROW) ? 0 :
218 (window_bounds.width() - kArrowWidth);
219 // Align in the center vertically.
220 int y = std::max(0, (window_bounds.height() - kArrowHeight) / 2);
221 arrow_->SetBounds(gfx::Rect(x, y, kArrowWidth, kArrowHeight));
222 ApplyEffectsForDelta(0.f);
223 394
224 // Adding the arrow as a child of the content window is not sufficient, 395 // Adding the affordance as a child of the content window is not sufficient,
225 // because it is possible for a new layer to be parented on top of the arrow 396 // because it is possible for a new layer to be parented on top of the
226 // layer (e.g. when the navigated-to page is displayed while the completion 397 // affordance layer (e.g. when the navigated-to page is displayed while the
227 // animation is in progress). So instead, a clip layer (that doesn't paint) is 398 // completion animation is in progress). So instead, it is installed on top of
228 // installed on top of the content window as its sibling, and the arrow layer 399 // the content window as its sibling. Note that the affordance itself makes
229 // is added to that clip layer. 400 // sure that its contents are clipped to the bounds given to it.
230 clip_layer_.reset(new ui::Layer(ui::LAYER_NOT_DRAWN));
231 clip_layer_->SetBounds(window->layer()->bounds());
232 clip_layer_->SetMasksToBounds(true);
233 clip_layer_->Add(arrow_.get());
234
235 ui::Layer* parent = window->layer()->parent(); 401 ui::Layer* parent = window->layer()->parent();
236 parent->Add(clip_layer_.get()); 402 parent->Add(affordance_->root_layer());
237 parent->StackAtTop(clip_layer_.get()); 403 parent->StackAtTop(affordance_->root_layer());
238 } 404 }
239 405
240 } // namespace content 406 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698