- add sources.
[platform/framework/web/crosswalk.git] / src / content / browser / web_contents / aura / window_slider.cc
1 // Copyright (c) 2013 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.
4
5 #include "content/browser/web_contents/aura/window_slider.h"
6
7 #include <algorithm>
8
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "content/browser/web_contents/aura/shadow_layer_delegate.h"
12 #include "content/public/browser/overscroll_configuration.h"
13 #include "ui/aura/window.h"
14 #include "ui/compositor/layer_animation_observer.h"
15 #include "ui/compositor/scoped_layer_animation_settings.h"
16 #include "ui/events/event.h"
17
18 namespace content {
19
20 namespace {
21
22 void DeleteLayerAndShadow(ui::Layer* layer,
23                           ShadowLayerDelegate* shadow) {
24   delete shadow;
25   delete layer;
26 }
27
28 // An animation observer that runs a callback at the end of the animation, and
29 // destroys itself.
30 class CallbackAnimationObserver : public ui::ImplicitAnimationObserver {
31  public:
32   CallbackAnimationObserver(const base::Closure& closure)
33       : closure_(closure) {
34   }
35
36   virtual ~CallbackAnimationObserver() {}
37
38  private:
39   // Overridden from ui::ImplicitAnimationObserver:
40   virtual void OnImplicitAnimationsCompleted() OVERRIDE {
41     if (!closure_.is_null())
42       closure_.Run();
43     base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
44   }
45
46   const base::Closure closure_;
47
48   DISALLOW_COPY_AND_ASSIGN(CallbackAnimationObserver);
49 };
50
51 }  // namespace
52
53 WindowSlider::WindowSlider(Delegate* delegate,
54                            aura::Window* event_window,
55                            aura::Window* owner)
56     : delegate_(delegate),
57       event_window_(event_window),
58       owner_(owner),
59       delta_x_(0.f),
60       weak_factory_(this),
61       active_start_threshold_(0.f),
62       start_threshold_touchscreen_(content::GetOverscrollConfig(
63           content::OVERSCROLL_CONFIG_HORIZ_THRESHOLD_START_TOUCHSCREEN)),
64       start_threshold_touchpad_(content::GetOverscrollConfig(
65           content::OVERSCROLL_CONFIG_HORIZ_THRESHOLD_START_TOUCHPAD)),
66       complete_threshold_(content::GetOverscrollConfig(
67           content::OVERSCROLL_CONFIG_HORIZ_THRESHOLD_COMPLETE)) {
68   event_window_->AddPreTargetHandler(this);
69
70   event_window_->AddObserver(this);
71   owner_->AddObserver(this);
72 }
73
74 WindowSlider::~WindowSlider() {
75   if (event_window_) {
76     event_window_->RemovePreTargetHandler(this);
77     event_window_->RemoveObserver(this);
78   }
79   if (owner_)
80     owner_->RemoveObserver(this);
81   delegate_->OnWindowSliderDestroyed();
82 }
83
84 void WindowSlider::ChangeOwner(aura::Window* new_owner) {
85   if (owner_)
86     owner_->RemoveObserver(this);
87   owner_ = new_owner;
88   if (owner_) {
89     owner_->AddObserver(this);
90     UpdateForScroll(0.f, 0.f);
91   }
92 }
93
94 bool WindowSlider::IsSlideInProgress() const {
95   return fabs(delta_x_) >= active_start_threshold_ || slider_.get() ||
96       weak_factory_.HasWeakPtrs();
97 }
98
99 void WindowSlider::SetupSliderLayer() {
100   ui::Layer* parent = owner_->layer()->parent();
101   parent->Add(slider_.get());
102   if (delta_x_ < 0)
103     parent->StackAbove(slider_.get(), owner_->layer());
104   else
105     parent->StackBelow(slider_.get(), owner_->layer());
106   slider_->SetBounds(owner_->layer()->bounds());
107   slider_->SetVisible(true);
108 }
109
110 void WindowSlider::UpdateForScroll(float x_offset, float y_offset) {
111   float old_delta = delta_x_;
112   delta_x_ += x_offset;
113   if (fabs(delta_x_) < active_start_threshold_ && !slider_.get())
114     return;
115
116   if ((old_delta < 0 && delta_x_ > 0) ||
117       (old_delta > 0 && delta_x_ < 0)) {
118     slider_.reset();
119     shadow_.reset();
120   }
121
122   float translate = 0.f;
123   ui::Layer* translate_layer = NULL;
124
125   if (!slider_.get()) {
126     slider_.reset(delta_x_ < 0 ? delegate_->CreateFrontLayer() :
127                                  delegate_->CreateBackLayer());
128     if (!slider_.get())
129       return;
130     SetupSliderLayer();
131   }
132
133   if (delta_x_ <= -active_start_threshold_) {
134     translate = owner_->bounds().width() +
135         std::max(delta_x_ + active_start_threshold_,
136                  static_cast<float>(-owner_->bounds().width()));
137     translate_layer = slider_.get();
138   } else if (delta_x_ >= active_start_threshold_) {
139     translate = std::min(delta_x_ - active_start_threshold_,
140                          static_cast<float>(owner_->bounds().width()));
141     translate_layer = owner_->layer();
142   } else {
143     return;
144   }
145
146   if (!shadow_.get())
147     shadow_.reset(new ShadowLayerDelegate(translate_layer));
148
149   gfx::Transform transform;
150   transform.Translate(translate, 0);
151   translate_layer->SetTransform(transform);
152 }
153
154 void WindowSlider::UpdateForFling(float x_velocity, float y_velocity) {
155   if (!slider_.get())
156     return;
157
158   int width = owner_->bounds().width();
159   float ratio = (fabs(delta_x_) - active_start_threshold_) / width;
160   if (ratio < complete_threshold_) {
161     ResetScroll();
162     return;
163   }
164
165   ui::Layer* sliding = delta_x_ < 0 ? slider_.get() : owner_->layer();
166   ui::ScopedLayerAnimationSettings settings(sliding->GetAnimator());
167   settings.SetPreemptionStrategy(
168       ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
169   settings.SetTweenType(gfx::Tween::EASE_OUT);
170   settings.AddObserver(new CallbackAnimationObserver(
171       base::Bind(&WindowSlider::CompleteWindowSlideAfterAnimation,
172                  weak_factory_.GetWeakPtr())));
173
174   gfx::Transform transform;
175   transform.Translate(delta_x_ < 0 ? 0 : width, 0);
176   sliding->SetTransform(transform);
177 }
178
179 void WindowSlider::ResetScroll() {
180   if (!slider_.get())
181     return;
182
183   // Do not trigger any callbacks if this animation replaces any in-progress
184   // animation.
185   weak_factory_.InvalidateWeakPtrs();
186
187   // Reset the state of the sliding layer.
188   if (slider_.get()) {
189     ui::Layer* layer = slider_.release();
190     ui::ScopedLayerAnimationSettings settings(layer->GetAnimator());
191     settings.SetPreemptionStrategy(
192         ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
193     settings.SetTweenType(gfx::Tween::EASE_OUT);
194
195     // Delete the layer and the shadow at the end of the animation.
196     settings.AddObserver(new CallbackAnimationObserver(
197         base::Bind(&DeleteLayerAndShadow,
198                    base::Unretained(layer),
199                    base::Unretained(shadow_.release()))));
200
201     gfx::Transform transform;
202     transform.Translate(delta_x_ < 0 ? layer->bounds().width() : 0, 0);
203     layer->SetTransform(transform);
204   }
205
206   // Reset the state of the main layer.
207   {
208     ui::ScopedLayerAnimationSettings settings(owner_->layer()->GetAnimator());
209     settings.SetPreemptionStrategy(
210         ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
211     settings.SetTweenType(gfx::Tween::EASE_OUT);
212     settings.AddObserver(new CallbackAnimationObserver(
213         base::Bind(&WindowSlider::AbortWindowSlideAfterAnimation,
214                    weak_factory_.GetWeakPtr())));
215     owner_->layer()->SetTransform(gfx::Transform());
216     owner_->layer()->SetLayerBrightness(0.f);
217   }
218
219   delta_x_ = 0.f;
220 }
221
222 void WindowSlider::CancelScroll() {
223   ResetScroll();
224 }
225
226 void WindowSlider::CompleteWindowSlideAfterAnimation() {
227   weak_factory_.InvalidateWeakPtrs();
228   shadow_.reset();
229   slider_.reset();
230   delta_x_ = 0.f;
231
232   delegate_->OnWindowSlideComplete();
233 }
234
235 void WindowSlider::AbortWindowSlideAfterAnimation() {
236   weak_factory_.InvalidateWeakPtrs();
237
238   delegate_->OnWindowSlideAborted();
239 }
240
241 void WindowSlider::OnKeyEvent(ui::KeyEvent* event) {
242   CancelScroll();
243 }
244
245 void WindowSlider::OnMouseEvent(ui::MouseEvent* event) {
246   if (!(event->flags() & ui::EF_IS_SYNTHESIZED))
247     CancelScroll();
248 }
249
250 void WindowSlider::OnScrollEvent(ui::ScrollEvent* event) {
251   active_start_threshold_ = start_threshold_touchpad_;
252   if (event->type() == ui::ET_SCROLL)
253     UpdateForScroll(event->x_offset_ordinal(), event->y_offset_ordinal());
254   else if (event->type() == ui::ET_SCROLL_FLING_START)
255     UpdateForFling(event->x_offset_ordinal(), event->y_offset_ordinal());
256   else
257     CancelScroll();
258   event->SetHandled();
259 }
260
261 void WindowSlider::OnGestureEvent(ui::GestureEvent* event) {
262   active_start_threshold_ = start_threshold_touchscreen_;
263   const ui::GestureEventDetails& details = event->details();
264   switch (event->type()) {
265     case ui::ET_GESTURE_SCROLL_BEGIN:
266       ResetScroll();
267       break;
268
269     case ui::ET_GESTURE_SCROLL_UPDATE:
270       UpdateForScroll(details.scroll_x(), details.scroll_y());
271       break;
272
273     case ui::ET_GESTURE_SCROLL_END:
274       UpdateForFling(0.f, 0.f);
275       break;
276
277     case ui::ET_SCROLL_FLING_START:
278       UpdateForFling(details.velocity_x(), details.velocity_y());
279       break;
280
281     case ui::ET_GESTURE_PINCH_BEGIN:
282     case ui::ET_GESTURE_PINCH_UPDATE:
283     case ui::ET_GESTURE_PINCH_END:
284       CancelScroll();
285       break;
286
287     default:
288       break;
289   }
290
291   event->SetHandled();
292 }
293
294 void WindowSlider::OnWindowRemovingFromRootWindow(aura::Window* window) {
295   if (window == event_window_) {
296     window->RemoveObserver(this);
297     window->RemovePreTargetHandler(this);
298     event_window_ = NULL;
299   } else if (window == owner_) {
300     window->RemoveObserver(this);
301     owner_ = NULL;
302     delete this;
303   } else {
304     NOTREACHED();
305   }
306 }
307
308 }  // namespace content