Remove PlatformFile from profile_browsertest
[chromium-blink-merge.git] / content / browser / web_contents / aura / window_slider.cc
blob61146e37c3731d6a42f5c3b08d7078ebc1f0f017
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.
5 #include "content/browser/web_contents/aura/window_slider.h"
7 #include <algorithm>
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"
18 namespace content {
20 namespace {
22 // An animation observer that runs a callback at the end of the animation, and
23 // destroys itself.
24 class CallbackAnimationObserver : public ui::ImplicitAnimationObserver {
25 public:
26 CallbackAnimationObserver(const base::Closure& closure)
27 : closure_(closure) {
30 virtual ~CallbackAnimationObserver() {}
32 private:
33 // Overridden from ui::ImplicitAnimationObserver:
34 virtual void OnImplicitAnimationsCompleted() OVERRIDE {
35 if (!closure_.is_null())
36 closure_.Run();
37 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
40 const base::Closure closure_;
42 DISALLOW_COPY_AND_ASSIGN(CallbackAnimationObserver);
45 } // namespace
47 WindowSlider::WindowSlider(Delegate* delegate,
48 aura::Window* event_window,
49 aura::Window* owner)
50 : delegate_(delegate),
51 event_window_(event_window),
52 owner_(owner),
53 active_animator_(NULL),
54 delta_x_(0.f),
55 weak_factory_(this),
56 active_start_threshold_(0.f),
57 start_threshold_touchscreen_(content::GetOverscrollConfig(
58 content::OVERSCROLL_CONFIG_HORIZ_THRESHOLD_START_TOUCHSCREEN)),
59 start_threshold_touchpad_(content::GetOverscrollConfig(
60 content::OVERSCROLL_CONFIG_HORIZ_THRESHOLD_START_TOUCHPAD)),
61 complete_threshold_(content::GetOverscrollConfig(
62 content::OVERSCROLL_CONFIG_HORIZ_THRESHOLD_COMPLETE)) {
63 event_window_->AddPreTargetHandler(this);
65 event_window_->AddObserver(this);
66 owner_->AddObserver(this);
69 WindowSlider::~WindowSlider() {
70 if (event_window_) {
71 event_window_->RemovePreTargetHandler(this);
72 event_window_->RemoveObserver(this);
74 if (owner_)
75 owner_->RemoveObserver(this);
76 delegate_->OnWindowSliderDestroyed();
79 void WindowSlider::ChangeOwner(aura::Window* new_owner) {
80 if (owner_)
81 owner_->RemoveObserver(this);
82 owner_ = new_owner;
83 if (owner_) {
84 owner_->AddObserver(this);
85 UpdateForScroll(0.f, 0.f);
89 bool WindowSlider::IsSlideInProgress() const {
90 // if active_start_threshold_ is 0, it means that sliding hasn't been started
91 return active_start_threshold_ != 0 && (slider_.get() || active_animator_);
94 void WindowSlider::SetupSliderLayer() {
95 ui::Layer* parent = owner_->layer()->parent();
96 parent->Add(slider_.get());
97 if (delta_x_ < 0)
98 parent->StackAbove(slider_.get(), owner_->layer());
99 else
100 parent->StackBelow(slider_.get(), owner_->layer());
101 slider_->SetBounds(owner_->layer()->bounds());
102 slider_->SetVisible(true);
105 void WindowSlider::UpdateForScroll(float x_offset, float y_offset) {
106 if (active_animator_) {
107 // If there is an active animation, complete it before processing the scroll
108 // so that the callbacks that are invoked on the Delegate are consistent.
109 // Completing the animation may destroy WindowSlider through the animation
110 // callback, so we can't continue processing the scroll event here.
111 delta_x_ += x_offset;
112 CompleteActiveAnimations();
113 return;
116 float old_delta = delta_x_;
117 delta_x_ += x_offset;
118 if (fabs(delta_x_) < active_start_threshold_ && !slider_.get())
119 return;
121 if ((old_delta < 0 && delta_x_ > 0) ||
122 (old_delta > 0 && delta_x_ < 0)) {
123 slider_.reset();
124 shadow_.reset();
127 float translate = 0.f;
128 ui::Layer* translate_layer = NULL;
130 if (!slider_.get()) {
131 slider_.reset(delta_x_ < 0 ? delegate_->CreateFrontLayer() :
132 delegate_->CreateBackLayer());
133 if (!slider_.get())
134 return;
135 SetupSliderLayer();
138 if (delta_x_ <= -active_start_threshold_) {
139 translate = owner_->bounds().width() +
140 std::max(delta_x_ + active_start_threshold_,
141 static_cast<float>(-owner_->bounds().width()));
142 translate_layer = slider_.get();
143 } else if (delta_x_ >= active_start_threshold_) {
144 translate = std::min(delta_x_ - active_start_threshold_,
145 static_cast<float>(owner_->bounds().width()));
146 translate_layer = owner_->layer();
147 } else {
148 return;
151 if (!shadow_.get())
152 shadow_.reset(new ShadowLayerDelegate(translate_layer));
154 gfx::Transform transform;
155 transform.Translate(translate, 0);
156 translate_layer->SetTransform(transform);
159 void WindowSlider::CompleteOrResetSlide() {
160 if (!slider_.get())
161 return;
163 int width = owner_->bounds().width();
164 float ratio = (fabs(delta_x_) - active_start_threshold_) / width;
165 if (ratio < complete_threshold_) {
166 ResetSlide();
167 return;
170 ui::Layer* sliding = delta_x_ < 0 ? slider_.get() : owner_->layer();
171 active_animator_ = sliding->GetAnimator();
173 ui::ScopedLayerAnimationSettings settings(active_animator_);
174 settings.SetPreemptionStrategy(
175 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
176 settings.SetTweenType(gfx::Tween::EASE_OUT);
177 settings.AddObserver(new CallbackAnimationObserver(
178 base::Bind(&WindowSlider::SlideAnimationCompleted,
179 weak_factory_.GetWeakPtr(),
180 base::Passed(&slider_),
181 base::Passed(&shadow_))));
183 gfx::Transform transform;
184 transform.Translate(delta_x_ < 0 ? 0 : width, 0);
185 delta_x_ = 0;
186 delegate_->OnWindowSlideCompleting();
187 sliding->SetTransform(transform);
190 void WindowSlider::CompleteActiveAnimations() {
191 if (active_animator_)
192 active_animator_->StopAnimating();
195 void WindowSlider::ResetSlide() {
196 if (!slider_.get())
197 return;
199 // Reset the state of the sliding layer.
200 if (slider_.get()) {
201 ui::Layer* translate_layer;
202 gfx::Transform transform;
203 if (delta_x_ < 0) {
204 translate_layer = slider_.get();
205 transform.Translate(translate_layer->bounds().width(), 0);
206 } else {
207 translate_layer = owner_->layer();
210 active_animator_ = translate_layer->GetAnimator();
211 ui::ScopedLayerAnimationSettings settings(active_animator_);
212 settings.SetPreemptionStrategy(
213 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
214 settings.SetTweenType(gfx::Tween::EASE_OUT);
215 settings.AddObserver(new CallbackAnimationObserver(
216 base::Bind(&WindowSlider::ResetSlideAnimationCompleted,
217 weak_factory_.GetWeakPtr(),
218 base::Passed(&slider_),
219 base::Passed(&shadow_))));
220 translate_layer->SetTransform(transform);
223 delta_x_ = 0.f;
226 void WindowSlider::SlideAnimationCompleted(
227 scoped_ptr<ui::Layer> layer, scoped_ptr<ShadowLayerDelegate> shadow) {
228 active_animator_ = NULL;
229 shadow.reset();
230 layer.reset();
231 delegate_->OnWindowSlideCompleted();
234 void WindowSlider::ResetSlideAnimationCompleted(
235 scoped_ptr<ui::Layer> layer, scoped_ptr<ShadowLayerDelegate> shadow) {
236 active_animator_ = NULL;
237 shadow.reset();
238 layer.reset();
239 delegate_->OnWindowSlideAborted();
242 void WindowSlider::OnKeyEvent(ui::KeyEvent* event) {
243 ResetSlide();
246 void WindowSlider::OnMouseEvent(ui::MouseEvent* event) {
247 if (!(event->flags() & ui::EF_IS_SYNTHESIZED))
248 ResetSlide();
251 void WindowSlider::OnScrollEvent(ui::ScrollEvent* event) {
252 active_start_threshold_ = start_threshold_touchpad_;
253 if (event->type() == ui::ET_SCROLL)
254 UpdateForScroll(event->x_offset_ordinal(), event->y_offset_ordinal());
255 else if (event->type() == ui::ET_SCROLL_FLING_START)
256 CompleteOrResetSlide();
257 else
258 ResetSlide();
259 event->SetHandled();
262 void WindowSlider::OnGestureEvent(ui::GestureEvent* event) {
263 active_start_threshold_ = start_threshold_touchscreen_;
264 const ui::GestureEventDetails& details = event->details();
265 switch (event->type()) {
266 case ui::ET_GESTURE_SCROLL_BEGIN:
267 CompleteActiveAnimations();
268 break;
270 case ui::ET_GESTURE_SCROLL_UPDATE:
271 UpdateForScroll(details.scroll_x(), details.scroll_y());
272 break;
274 case ui::ET_GESTURE_SCROLL_END:
275 CompleteOrResetSlide();
276 break;
278 case ui::ET_SCROLL_FLING_START:
279 CompleteOrResetSlide();
280 break;
282 case ui::ET_GESTURE_PINCH_BEGIN:
283 case ui::ET_GESTURE_PINCH_UPDATE:
284 case ui::ET_GESTURE_PINCH_END:
285 ResetSlide();
286 break;
288 default:
289 break;
292 event->SetHandled();
295 void WindowSlider::OnWindowRemovingFromRootWindow(aura::Window* window,
296 aura::Window* new_root) {
297 if (window == event_window_) {
298 window->RemoveObserver(this);
299 window->RemovePreTargetHandler(this);
300 event_window_ = NULL;
301 } else if (window == owner_) {
302 window->RemoveObserver(this);
303 owner_ = NULL;
304 delete this;
305 } else {
306 NOTREACHED();
310 } // namespace content