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 AnimateTranslation(GetBackLayer(), 0, false);
43 AnimateTranslation(GetFrontLayer(), 0, true);
46 float OverscrollWindowAnimation::GetTranslationForOverscroll(float delta_x
) {
47 DCHECK(direction_
!= SLIDE_NONE
);
48 const float bounds_width
= GetVisibleBounds().width();
49 if (direction_
== SLIDE_FRONT
)
50 return std::max(-bounds_width
, delta_x
);
52 return std::min(bounds_width
, delta_x
);
55 gfx::Rect
OverscrollWindowAnimation::GetVisibleBounds() const {
56 return delegate_
->GetMainWindow()->bounds();
59 bool OverscrollWindowAnimation::OnOverscrollUpdate(float delta_x
,
61 if (direction_
== SLIDE_NONE
)
63 gfx::Transform front_transform
;
64 gfx::Transform back_transform
;
65 float translate_x
= GetTranslationForOverscroll(delta_x
);
66 front_transform
.Translate(translate_x
, 0);
67 back_transform
.Translate(translate_x
/ 2, 0);
68 GetFrontLayer()->SetTransform(front_transform
);
69 GetBackLayer()->SetTransform(back_transform
);
73 void OverscrollWindowAnimation::OnImplicitAnimationsCompleted() {
74 if (overscroll_cancelled_
) {
75 slide_window_
.reset();
76 delegate_
->OnOverscrollCancelled();
77 overscroll_cancelled_
= false;
79 delegate_
->OnOverscrollCompleted(slide_window_
.Pass());
81 direction_
= SLIDE_NONE
;
84 void OverscrollWindowAnimation::OnOverscrollModeChange(
85 OverscrollMode old_mode
,
86 OverscrollMode new_mode
) {
87 Direction new_direction
= GetDirectionForMode(new_mode
);
88 if (new_direction
== SLIDE_NONE
) {
89 // The user cancelled the in progress animation.
95 slide_window_
->layer()->GetAnimator()->StopAnimating();
96 delegate_
->GetMainWindow()->layer()->GetAnimator()->StopAnimating();
98 gfx::Rect slide_window_bounds
= gfx::Rect(GetVisibleBounds().size());
99 if (new_direction
== SLIDE_FRONT
) {
100 slide_window_bounds
.Offset(base::i18n::IsRTL()
101 ? -slide_window_bounds
.width()
102 : slide_window_bounds
.width(),
105 slide_window_bounds
.Offset(base::i18n::IsRTL()
106 ? slide_window_bounds
.width() / 2
107 : -slide_window_bounds
.width() / 2,
110 slide_window_
= new_direction
== SLIDE_FRONT
111 ? delegate_
->CreateFrontWindow(slide_window_bounds
)
112 : delegate_
->CreateBackWindow(slide_window_bounds
);
113 if (!slide_window_
) {
114 // Cannot navigate, do not start an overscroll gesture.
115 direction_
= SLIDE_NONE
;
118 overscroll_cancelled_
= false;
119 direction_
= new_direction
;
120 shadow_
.reset(new ShadowLayerDelegate(GetFrontLayer()));
123 void OverscrollWindowAnimation::OnOverscrollComplete(
124 OverscrollMode overscroll_mode
) {
127 delegate_
->OnOverscrollCompleting();
128 int content_width
= GetVisibleBounds().width();
130 if ((base::i18n::IsRTL() && direction_
== SLIDE_FRONT
) ||
131 (!base::i18n::IsRTL() && direction_
== SLIDE_BACK
)) {
132 translate_x
= content_width
;
134 translate_x
= -content_width
;
136 AnimateTranslation(GetBackLayer(), translate_x
/ 2, false);
137 AnimateTranslation(GetFrontLayer(), translate_x
, true);
140 void OverscrollWindowAnimation::AnimateTranslation(ui::Layer
* layer
,
142 bool listen_for_completion
) {
143 gfx::Transform transform
;
144 transform
.Translate(translate_x
, 0);
145 ui::ScopedLayerAnimationSettings
settings(layer
->GetAnimator());
146 settings
.SetPreemptionStrategy(
147 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET
);
148 settings
.SetTweenType(gfx::Tween::EASE_OUT
);
149 if (listen_for_completion
)
150 settings
.AddObserver(this);
151 layer
->SetTransform(transform
);
154 ui::Layer
* OverscrollWindowAnimation::GetFrontLayer() const {
155 DCHECK(direction_
!= SLIDE_NONE
);
156 if (direction_
== SLIDE_FRONT
) {
157 DCHECK(slide_window_
);
158 return slide_window_
->layer();
160 return delegate_
->GetMainWindow()->layer();
163 ui::Layer
* OverscrollWindowAnimation::GetBackLayer() const {
164 DCHECK(direction_
!= SLIDE_NONE
);
165 if (direction_
== SLIDE_BACK
) {
166 DCHECK(slide_window_
);
167 return slide_window_
->layer();
169 return delegate_
->GetMainWindow()->layer();
172 } // namespace content