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/base/events/event.h" 15 #include "ui/compositor/layer_animation_observer.h" 16 #include "ui/compositor/scoped_layer_animation_settings.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 horiz_start_threshold_(content::GetOverscrollConfig( 62 content::OVERSCROLL_CONFIG_HORIZ_THRESHOLD_START)), 63 complete_threshold_(content::GetOverscrollConfig( 64 content::OVERSCROLL_CONFIG_HORIZ_THRESHOLD_COMPLETE)) { 65 event_window_->AddPreTargetHandler(this); 66 67 event_window_->AddObserver(this); 68 owner_->AddObserver(this); 69 } 70 71 WindowSlider::~WindowSlider() { 72 if (event_window_) { 73 event_window_->RemovePreTargetHandler(this); 74 event_window_->RemoveObserver(this); 75 } 76 if (owner_) 77 owner_->RemoveObserver(this); 78 delegate_->OnWindowSliderDestroyed(); 79 } 80 81 void WindowSlider::ChangeOwner(aura::Window* new_owner) { 82 if (owner_) 83 owner_->RemoveObserver(this); 84 owner_ = new_owner; 85 if (owner_) { 86 owner_->AddObserver(this); 87 UpdateForScroll(0.f, 0.f); 88 } 89 } 90 91 bool WindowSlider::IsSlideInProgress() const { 92 return fabs(delta_x_) >= horiz_start_threshold_ || slider_.get() || 93 weak_factory_.HasWeakPtrs(); 94 } 95 96 void WindowSlider::SetupSliderLayer() { 97 ui::Layer* parent = owner_->layer()->parent(); 98 parent->Add(slider_.get()); 99 if (delta_x_ < 0) 100 parent->StackAbove(slider_.get(), owner_->layer()); 101 else 102 parent->StackBelow(slider_.get(), owner_->layer()); 103 slider_->SetBounds(owner_->layer()->bounds()); 104 slider_->SetVisible(true); 105 } 106 107 void WindowSlider::UpdateForScroll(float x_offset, float y_offset) { 108 float old_delta = delta_x_; 109 delta_x_ += x_offset; 110 if (fabs(delta_x_) < horiz_start_threshold_ && !slider_.get()) 111 return; 112 113 if ((old_delta < 0 && delta_x_ > 0) || 114 (old_delta > 0 && delta_x_ < 0)) { 115 slider_.reset(); 116 shadow_.reset(); 117 } 118 119 float translate = 0.f; 120 ui::Layer* translate_layer = NULL; 121 122 if (!slider_.get()) { 123 slider_.reset(delta_x_ < 0 ? delegate_->CreateFrontLayer() : 124 delegate_->CreateBackLayer()); 125 if (!slider_.get()) 126 return; 127 SetupSliderLayer(); 128 } 129 130 if (delta_x_ <= -horiz_start_threshold_) { 131 translate = owner_->bounds().width() + 132 std::max(delta_x_ + horiz_start_threshold_, 133 static_cast<float>(-owner_->bounds().width())); 134 translate_layer = slider_.get(); 135 } else if (delta_x_ >= horiz_start_threshold_) { 136 translate = std::min(delta_x_ - horiz_start_threshold_, 137 static_cast<float>(owner_->bounds().width())); 138 translate_layer = owner_->layer(); 139 } else { 140 return; 141 } 142 143 if (!shadow_.get()) 144 shadow_.reset(new ShadowLayerDelegate(translate_layer)); 145 146 gfx::Transform transform; 147 transform.Translate(translate, 0); 148 translate_layer->SetTransform(transform); 149 } 150 151 void WindowSlider::UpdateForFling(float x_velocity, float y_velocity) { 152 if (!slider_.get()) 153 return; 154 155 int width = owner_->bounds().width(); 156 float ratio = (fabs(delta_x_) - horiz_start_threshold_) / width; 157 if (ratio < complete_threshold_) { 158 ResetScroll(); 159 return; 160 } 161 162 ui::Layer* sliding = delta_x_ < 0 ? slider_.get() : owner_->layer(); 163 ui::ScopedLayerAnimationSettings settings(sliding->GetAnimator()); 164 settings.SetPreemptionStrategy( 165 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); 166 settings.SetTweenType(ui::Tween::EASE_OUT); 167 settings.AddObserver(new CallbackAnimationObserver( 168 base::Bind(&WindowSlider::CompleteWindowSlideAfterAnimation, 169 weak_factory_.GetWeakPtr()))); 170 171 gfx::Transform transform; 172 transform.Translate(delta_x_ < 0 ? 0 : width, 0); 173 sliding->SetTransform(transform); 174 } 175 176 void WindowSlider::ResetScroll() { 177 if (!slider_.get()) 178 return; 179 180 // Do not trigger any callbacks if this animation replaces any in-progress 181 // animation. 182 weak_factory_.InvalidateWeakPtrs(); 183 184 // Reset the state of the sliding layer. 185 if (slider_.get()) { 186 ui::Layer* layer = slider_.release(); 187 ui::ScopedLayerAnimationSettings settings(layer->GetAnimator()); 188 settings.SetPreemptionStrategy( 189 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); 190 settings.SetTweenType(ui::Tween::EASE_OUT); 191 192 // Delete the layer and the shadow at the end of the animation. 193 settings.AddObserver(new CallbackAnimationObserver( 194 base::Bind(&DeleteLayerAndShadow, 195 base::Unretained(layer), 196 base::Unretained(shadow_.release())))); 197 198 gfx::Transform transform; 199 transform.Translate(delta_x_ < 0 ? layer->bounds().width() : 0, 0); 200 layer->SetTransform(transform); 201 } 202 203 // Reset the state of the main layer. 204 { 205 ui::ScopedLayerAnimationSettings settings(owner_->layer()->GetAnimator()); 206 settings.SetPreemptionStrategy( 207 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); 208 settings.SetTweenType(ui::Tween::EASE_OUT); 209 settings.AddObserver(new CallbackAnimationObserver( 210 base::Bind(&WindowSlider::AbortWindowSlideAfterAnimation, 211 weak_factory_.GetWeakPtr()))); 212 owner_->layer()->SetTransform(gfx::Transform()); 213 owner_->layer()->SetLayerBrightness(0.f); 214 } 215 216 delta_x_ = 0.f; 217 } 218 219 void WindowSlider::CancelScroll() { 220 ResetScroll(); 221 } 222 223 void WindowSlider::CompleteWindowSlideAfterAnimation() { 224 weak_factory_.InvalidateWeakPtrs(); 225 shadow_.reset(); 226 slider_.reset(); 227 delta_x_ = 0.f; 228 229 delegate_->OnWindowSlideComplete(); 230 } 231 232 void WindowSlider::AbortWindowSlideAfterAnimation() { 233 weak_factory_.InvalidateWeakPtrs(); 234 235 delegate_->OnWindowSlideAborted(); 236 } 237 238 void WindowSlider::OnKeyEvent(ui::KeyEvent* event) { 239 CancelScroll(); 240 } 241 242 void WindowSlider::OnMouseEvent(ui::MouseEvent* event) { 243 if (!(event->flags() & ui::EF_IS_SYNTHESIZED)) 244 CancelScroll(); 245 } 246 247 void WindowSlider::OnScrollEvent(ui::ScrollEvent* event) { 248 if (event->type() == ui::ET_SCROLL) 249 UpdateForScroll(event->x_offset_ordinal(), event->y_offset_ordinal()); 250 else if (event->type() == ui::ET_SCROLL_FLING_START) 251 UpdateForFling(event->x_offset_ordinal(), event->y_offset_ordinal()); 252 else 253 CancelScroll(); 254 event->SetHandled(); 255 } 256 257 void WindowSlider::OnGestureEvent(ui::GestureEvent* event) { 258 const ui::GestureEventDetails& details = event->details(); 259 switch (event->type()) { 260 case ui::ET_GESTURE_SCROLL_BEGIN: 261 ResetScroll(); 262 break; 263 264 case ui::ET_GESTURE_SCROLL_UPDATE: 265 UpdateForScroll(details.scroll_x(), details.scroll_y()); 266 break; 267 268 case ui::ET_GESTURE_SCROLL_END: 269 UpdateForFling(0.f, 0.f); 270 break; 271 272 case ui::ET_SCROLL_FLING_START: 273 UpdateForFling(details.velocity_x(), details.velocity_y()); 274 break; 275 276 case ui::ET_GESTURE_PINCH_BEGIN: 277 case ui::ET_GESTURE_PINCH_UPDATE: 278 case ui::ET_GESTURE_PINCH_END: 279 CancelScroll(); 280 break; 281 282 default: 283 break; 284 } 285 286 event->SetHandled(); 287 } 288 289 void WindowSlider::OnWindowRemovingFromRootWindow(aura::Window* window) { 290 if (window == event_window_) { 291 window->RemoveObserver(this); 292 window->RemovePreTargetHandler(this); 293 event_window_ = NULL; 294 } else if (window == owner_) { 295 window->RemoveObserver(this); 296 owner_ = NULL; 297 delete this; 298 } else { 299 NOTREACHED(); 300 } 301 } 302 303 } // namespace content 304