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"
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"
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
;
30 OverscrollWindowAnimation::OverscrollWindowAnimation(Delegate
* delegate
)
31 : delegate_(delegate
),
32 direction_(SLIDE_NONE
),
33 overscroll_cancelled_(false) {
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
);
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
,
63 if (direction_
== SLIDE_NONE
)
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
);
75 void OverscrollWindowAnimation::OnImplicitAnimationsCompleted() {
76 if (overscroll_cancelled_
) {
77 slide_window_
.reset();
78 delegate_
->OnOverscrollCancelled();
79 overscroll_cancelled_
= false;
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.
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(),
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
;
121 overscroll_cancelled_
= false;
122 direction_
= new_direction
;
123 shadow_
.reset(new ShadowLayerDelegate(GetFrontLayer()));
126 void OverscrollWindowAnimation::OnOverscrollComplete(
127 OverscrollMode overscroll_mode
) {
130 delegate_
->OnOverscrollCompleting();
131 int content_width
= GetVisibleBounds().width();
133 if ((base::i18n::IsRTL() && direction_
== SLIDE_FRONT
) ||
134 (!base::i18n::IsRTL() && direction_
== SLIDE_BACK
)) {
135 translate_x
= content_width
;
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
,
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