Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / content / browser / web_contents / aura / overscroll_window_animation.cc
blobc89faa08b082c9a5db39f5a526bc66b838f9f2f0
1 // Copyright 2015 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.
5 #include "content/browser/web_contents/aura/overscroll_window_animation.h"
7 #include <algorithm>
9 #include "base/i18n/rtl.h"
10 #include "content/browser/web_contents/aura/shadow_layer_delegate.h"
11 #include "content/browser/web_contents/web_contents_impl.h"
12 #include "ui/aura/window.h"
13 #include "ui/compositor/layer_animation_observer.h"
14 #include "ui/compositor/scoped_layer_animation_settings.h"
16 namespace content {
18 namespace {
20 OverscrollWindowAnimation::Direction GetDirectionForMode(OverscrollMode mode) {
21 if (mode == (base::i18n::IsRTL() ? OVERSCROLL_EAST : OVERSCROLL_WEST))
22 return OverscrollWindowAnimation::SLIDE_FRONT;
23 if (mode == (base::i18n::IsRTL() ? OVERSCROLL_WEST : OVERSCROLL_EAST))
24 return OverscrollWindowAnimation::SLIDE_BACK;
25 return OverscrollWindowAnimation::SLIDE_NONE;
28 } // namespace
30 OverscrollWindowAnimation::OverscrollWindowAnimation(Delegate* delegate)
31 : delegate_(delegate),
32 direction_(SLIDE_NONE),
33 overscroll_cancelled_(false) {
34 DCHECK(delegate_);
37 OverscrollWindowAnimation::~OverscrollWindowAnimation() {
40 void OverscrollWindowAnimation::CancelSlide() {
41 overscroll_cancelled_ = true;
42 // Listen to the animation of the main window.
43 bool main_window_is_front = direction_ == SLIDE_BACK;
44 AnimateTranslation(GetBackLayer(), 0, !main_window_is_front);
45 AnimateTranslation(GetFrontLayer(), 0, main_window_is_front);
48 float OverscrollWindowAnimation::GetTranslationForOverscroll(float delta_x) {
49 DCHECK(direction_ != SLIDE_NONE);
50 const float bounds_width = GetVisibleBounds().width();
51 if (direction_ == SLIDE_FRONT)
52 return std::max(-bounds_width, delta_x);
53 else
54 return std::min(bounds_width, delta_x);
57 gfx::Rect OverscrollWindowAnimation::GetVisibleBounds() const {
58 return delegate_->GetMainWindow()->bounds();
61 bool OverscrollWindowAnimation::OnOverscrollUpdate(float delta_x,
62 float delta_y) {
63 if (direction_ == SLIDE_NONE)
64 return false;
65 gfx::Transform front_transform;
66 gfx::Transform back_transform;
67 float translate_x = GetTranslationForOverscroll(delta_x);
68 front_transform.Translate(translate_x, 0);
69 back_transform.Translate(translate_x / 2, 0);
70 GetFrontLayer()->SetTransform(front_transform);
71 GetBackLayer()->SetTransform(back_transform);
72 return true;
75 void OverscrollWindowAnimation::OnImplicitAnimationsCompleted() {
76 if (overscroll_cancelled_) {
77 slide_window_.reset();
78 delegate_->OnOverscrollCancelled();
79 overscroll_cancelled_ = false;
80 } else {
81 delegate_->OnOverscrollCompleted(slide_window_.Pass());
83 direction_ = SLIDE_NONE;
86 void OverscrollWindowAnimation::OnOverscrollModeChange(
87 OverscrollMode old_mode,
88 OverscrollMode new_mode) {
89 DCHECK_NE(old_mode, new_mode);
90 Direction new_direction = GetDirectionForMode(new_mode);
91 if (new_direction == SLIDE_NONE) {
92 // The user cancelled the in progress animation.
93 if (is_active())
94 CancelSlide();
95 return;
97 if (is_active()) {
98 slide_window_->layer()->GetAnimator()->StopAnimating();
99 delegate_->GetMainWindow()->layer()->GetAnimator()->StopAnimating();
101 gfx::Rect slide_window_bounds = gfx::Rect(GetVisibleBounds().size());
102 if (new_direction == SLIDE_FRONT) {
103 slide_window_bounds.Offset(base::i18n::IsRTL()
104 ? -slide_window_bounds.width()
105 : slide_window_bounds.width(),
107 } else {
108 slide_window_bounds.Offset(base::i18n::IsRTL()
109 ? slide_window_bounds.width() / 2
110 : -slide_window_bounds.width() / 2,
113 slide_window_ = new_direction == SLIDE_FRONT
114 ? delegate_->CreateFrontWindow(slide_window_bounds)
115 : delegate_->CreateBackWindow(slide_window_bounds);
116 if (!slide_window_) {
117 // Cannot navigate, do not start an overscroll gesture.
118 direction_ = SLIDE_NONE;
119 return;
121 overscroll_cancelled_ = false;
122 direction_ = new_direction;
123 shadow_.reset(new ShadowLayerDelegate(GetFrontLayer()));
126 void OverscrollWindowAnimation::OnOverscrollComplete(
127 OverscrollMode overscroll_mode) {
128 if (!is_active())
129 return;
130 delegate_->OnOverscrollCompleting();
131 int content_width = GetVisibleBounds().width();
132 float translate_x;
133 if ((base::i18n::IsRTL() && direction_ == SLIDE_FRONT) ||
134 (!base::i18n::IsRTL() && direction_ == SLIDE_BACK)) {
135 translate_x = content_width;
136 } else {
137 translate_x = -content_width;
139 // Listen to the animation of the main window.
140 bool main_window_is_front = direction_ == SLIDE_BACK;
141 AnimateTranslation(GetBackLayer(), translate_x / 2, !main_window_is_front);
142 AnimateTranslation(GetFrontLayer(), translate_x, main_window_is_front);
145 void OverscrollWindowAnimation::AnimateTranslation(ui::Layer* layer,
146 float translate_x,
147 bool listen_for_completion) {
148 gfx::Transform transform;
149 transform.Translate(translate_x, 0);
150 ui::ScopedLayerAnimationSettings settings(layer->GetAnimator());
151 settings.SetPreemptionStrategy(
152 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
153 settings.SetTweenType(gfx::Tween::EASE_OUT);
154 if (listen_for_completion)
155 settings.AddObserver(this);
156 layer->SetTransform(transform);
159 ui::Layer* OverscrollWindowAnimation::GetFrontLayer() const {
160 DCHECK(direction_ != SLIDE_NONE);
161 if (direction_ == SLIDE_FRONT) {
162 DCHECK(slide_window_);
163 return slide_window_->layer();
165 return delegate_->GetMainWindow()->layer();
168 ui::Layer* OverscrollWindowAnimation::GetBackLayer() const {
169 DCHECK(direction_ != SLIDE_NONE);
170 if (direction_ == SLIDE_BACK) {
171 DCHECK(slide_window_);
172 return slide_window_->layer();
174 return delegate_->GetMainWindow()->layer();
177 } // namespace content