Index: content/browser/web_contents/aura/overscroll_window_animation.cc |
diff --git a/content/browser/web_contents/aura/overscroll_window_animation.cc b/content/browser/web_contents/aura/overscroll_window_animation.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..ff04dc92aa3e2d7296813f8827759aab9cbbdb2b |
--- /dev/null |
+++ b/content/browser/web_contents/aura/overscroll_window_animation.cc |
@@ -0,0 +1,303 @@ |
+// Copyright (c) 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "content/browser/web_contents/aura/overscroll_window_animation.h" |
+ |
+#include "base/auto_reset.h" |
+#include "content/browser/web_contents/aura/overscroll_window_delegate.h" |
+#include "content/browser/web_contents/aura/shadow_layer_delegate.h" |
+#include "content/browser/web_contents/web_contents_impl.h" |
+#include "content/browser/web_contents/web_contents_view_aura.h" |
+#include "content/public/browser/render_widget_host_view.h" |
+#include "ui/aura/window.h" |
+#include "ui/compositor/layer_animation_observer.h" |
+#include "ui/compositor/scoped_layer_animation_settings.h" |
+ |
+namespace content { |
+ |
+namespace { |
+ |
+// Responsible for fading out and deleting the layer of the overlay window. |
+class OverlayDismissAnimator : public ui::LayerAnimationObserver { |
+ public: |
+ // Takes ownership of the layer. |
+ explicit OverlayDismissAnimator(scoped_ptr<ui::Layer> layer) |
+ : layer_(layer.Pass()) { |
+ CHECK(layer_.get()); |
+ } |
+ |
+ // Starts the fadeout animation on the layer. When the animation finishes, |
+ // the object deletes itself along with the layer. |
+ void Animate() { |
+ DCHECK(layer_.get()); |
+ ui::LayerAnimator* animator = layer_->GetAnimator(); |
+ // This makes SetOpacity() animate with default duration (which could be |
+ // zero, e.g. when running tests). |
+ ui::ScopedLayerAnimationSettings settings(animator); |
+ animator->AddObserver(this); |
+ LOG(ERROR) << "Setting opacity to 0"; |
+ layer_->SetOpacity(0); |
+ } |
+ |
+ // Overridden from ui::LayerAnimationObserver |
+ void OnLayerAnimationEnded(ui::LayerAnimationSequence* sequence) override { |
+ LOG(ERROR) << "Deleting dismiss layer"; |
+ delete this; |
+ } |
+ |
+ void OnLayerAnimationAborted(ui::LayerAnimationSequence* sequence) override { |
+ LOG(ERROR) << "Animation aborted!!!"; |
+ delete this; |
+ } |
+ |
+ void OnLayerAnimationScheduled( |
+ ui::LayerAnimationSequence* sequence) override {} |
+ |
+ private: |
+ ~OverlayDismissAnimator() override {} |
+ |
+ scoped_ptr<ui::Layer> layer_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(OverlayDismissAnimator); |
+}; |
+ |
+} // namespace |
+ |
+OverscrollWindowAnimation::OverscrollWindowAnimation( |
+ WebContentsImpl* web_contents, |
+ OverscrollNavigationOverlay* ono, |
+ aura::Window* web_contents_window) |
+ : web_contents_(web_contents), |
+ ono_(ono), |
+ direction_(OverscrollNavigationOverlay::NONE), |
+ web_contents_window_(web_contents_window), |
+ slide_layer_(nullptr), |
+ fade_out_(false), |
+ animation_cancelled_(false), |
+ gesture_completed_(false) { |
+} |
+ |
+OverscrollWindowAnimation::~OverscrollWindowAnimation() { |
+ LOG(ERROR) << "OWA destructor"; |
+} |
+ |
+void OverscrollWindowAnimation::CancelAnimation() { |
+ LOG(ERROR) << "Cancelling animation"; |
+ animation_cancelled_ = true; |
+ fade_out_ = false; |
+ gesture_completed_ = true; |
+ aura::Window* animate_window = GetWindowToAnimateForOverscroll(); |
+ if (!animate_window) |
+ return; |
+ ui::ScopedLayerAnimationSettings settings( |
+ animate_window->layer()->GetAnimator()); |
+ settings.SetPreemptionStrategy( |
+ ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); |
+ settings.SetTweenType(gfx::Tween::EASE_OUT); |
+ settings.AddObserver(this); |
+ animate_window->SetTransform(gfx::Transform()); |
+ direction_ = OverscrollNavigationOverlay::NONE; |
+} |
+ |
+// We should be able to delete this function. |
+void OverscrollWindowAnimation::AbortAllAnimations() { |
+ aura::Window* target = GetWindowToAnimateForOverscroll(); |
+ if (target) |
+ target->layer()->GetAnimator()->AbortAllAnimations(); |
+} |
+ |
+void OverscrollWindowAnimation::DismissOverlay() { |
+ LOG(ERROR) << "Dismissing overlay"; |
+ if (gesture_completed_) { |
+ FadeOutOverscrollWindow(); |
+ return; |
+ } |
+ fade_out_ = true; |
+} |
+ |
+void OverscrollWindowAnimation::OnImplicitAnimationsCompleted() { |
+ LOG(ERROR) << "On implicit animations completed"; |
+ if (!overscroll_window_) { |
+ LOG(ERROR) << "Overscroll window already destroyed, returning"; |
+ return; |
+ } |
+ gesture_completed_ = true; |
+ aura::Window* contents = web_contents_->GetContentNativeView(); |
+ contents->parent()->StackChildBelow(contents, overscroll_window_.get()); |
mfomitchev
2015/02/13 22:08:48
Similar to the previous comments - this logic shou
|
+ contents->SetTransform(gfx::Transform()); |
+ if (fade_out_) { |
+ LOG(ERROR) << "With fade_out_ == true"; |
+ FadeOutOverscrollWindow(); |
+ return; |
+ } |
+ if (animation_cancelled_) { |
+ LOG(ERROR) << "With animation_cancelled_ == true"; |
+ overscroll_window_.reset(); |
+ overscroll_shadow_.reset(); |
+ } |
+} |
+ |
+gfx::Vector2dF OverscrollWindowAnimation::GetTranslationForOverscroll( |
+ float delta_x) { |
+ const float bounds_width = |
+ static_cast<float>(web_contents_window_->bounds().width()); |
+ if (direction_ == OverscrollNavigationOverlay::FORWARD) |
+ return gfx::Vector2dF(std::max(-bounds_width, delta_x), 0); |
+ else |
+ return gfx::Vector2dF(std::min(bounds_width, delta_x), 0); |
+} |
+ |
+gfx::Rect OverscrollWindowAnimation::GetVisibleBounds() const { |
+ return web_contents_window_->bounds(); |
+} |
+ |
+bool OverscrollWindowAnimation::OnOverscrollUpdate(float delta_x, |
+ float delta_y) { |
+ if (direction_ == OverscrollNavigationOverlay::NONE) |
+ return false; |
+ LOG(ERROR) << "OWA: OnOverscrollUpdate"; |
+ gfx::Vector2dF translate = GetTranslationForOverscroll(delta_x); |
+ if (translate.IsZero()) |
+ return false; |
+ |
+ gfx::Transform transform; |
+ transform.Translate(translate.x(), translate.y()); |
+ aura::Window* animate_window = GetWindowToAnimateForOverscroll(); |
+ if (animate_window) { |
+ animate_window->SetTransform(transform); |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+void OverscrollWindowAnimation::OnOverscrollModeChange( |
+ OverscrollMode old_mode, |
+ OverscrollMode new_mode) { |
+ LOG(ERROR) << "OWA: OnOverscrollModeChange"; |
+ animation_cancelled_ = false; |
+ AbortAllAnimations(); |
+ |
+ direction_ = |
+ ono_->GetNavigationDirection(web_contents_->GetController(), new_mode); |
+ // TODO(nsatragno): in this case, show a feedback animation. |
+ if (direction_ == OverscrollNavigationOverlay::NONE) { |
+ if (overscroll_window_) |
+ CancelAnimation(); |
+ return; |
+ } |
+ if (overscroll_window_) { |
+ LOG(ERROR) << "OWA: SHOULD CREATE LAYER"; |
+ AddNewLayer(); |
+ return; |
+ } |
+ |
+ StartAnimating(); |
+} |
+ |
+void OverscrollWindowAnimation::StartAnimating() { |
+ LOG(ERROR) << "OWA: StartAnimating"; |
+ gesture_completed_ = false; |
+ OverscrollWindowDelegate* overscroll_delegate = new OverscrollWindowDelegate( |
mfomitchev
2015/02/13 22:08:48
I am not sure this setup code belongs in OWA eithe
|
+ this, ono_->GetImageForDirection(direction_)); |
+ overscroll_window_.reset(new aura::Window(overscroll_delegate)); |
+ overscroll_window_->SetType(ui::wm::WINDOW_TYPE_CONTROL); |
+ overscroll_window_->SetTransparent(true); |
+ overscroll_window_->Init(aura::WINDOW_LAYER_TEXTURED); |
+ overscroll_window_->layer()->SetMasksToBounds(false); |
+ overscroll_window_->SetName("OverscrollOverlay"); |
+ |
+ aura::Window* animate_window = GetWindowToAnimateForOverscroll(); |
+ web_contents_window_->AddChild(overscroll_window_.get()); |
+ |
+ if (animate_window == overscroll_window_) { |
+ LOG(ERROR) << "animate_window == overscroll_window_"; |
+ web_contents_window_->StackChildAbove( |
+ overscroll_window_.get(), web_contents_->GetContentNativeView()); |
+ } else { |
+ LOG(ERROR) << "animate_window != overscroll_window_"; |
+ web_contents_window_->StackChildBelow( |
+ overscroll_window_.get(), web_contents_->GetContentNativeView()); |
+ } |
+ |
+ overscroll_window_->SetBounds(GetStarterBounds()); |
+ overscroll_window_->Show(); |
+ |
+ if (!animate_window) |
+ LOG(ERROR) << "ERROR: ANIMATE_WINDOW_ IS NULL"; |
+ |
+ overscroll_shadow_.reset(new ShadowLayerDelegate(animate_window->layer())); |
+} |
+ |
+void OverscrollWindowAnimation::AddNewLayer() { |
+ slide_layer_ = ono_->CreateLayerForDirection(direction_); |
+ ui::Layer* parent = overscroll_window_->layer()->parent(); |
mfomitchev
2015/02/13 22:08:48
Same here
|
+ parent->Add(slide_layer_.get()); |
+ // TODO stack apropriately. |
+ if (direction_ == OverscrollNavigationOverlay::FORWARD) |
+ parent->StackAbove(slide_layer_.get(), overscroll_window_->layer()); |
+ else |
+ parent->StackBelow(slide_layer_.get(), overscroll_window_->layer()); |
+ slide_layer_->SetBounds(GetStarterBounds()); |
+} |
+ |
+void OverscrollWindowAnimation::FadeOutOverscrollWindow() { |
+ fade_out_ = false; |
+ LOG(ERROR) << "FadeOutOverscrollWindow"; |
+ if (!overscroll_window_) |
+ return; |
+ aura::Window* contents = web_contents_->GetContentNativeView(); |
+ contents->layer()->SetLayerBrightness(1.f); |
+ { |
+ ui::ScopedLayerAnimationSettings settings(contents->layer()->GetAnimator()); |
+ settings.SetPreemptionStrategy( |
+ ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); |
+ settings.SetTweenType(gfx::Tween::EASE_OUT); |
+ contents->layer()->SetLayerBrightness(0.f); |
+ } |
+ scoped_ptr<ui::Layer> dismiss_layer = overscroll_window_->AcquireLayer(); |
+ overscroll_window_.reset(); |
+ (new OverlayDismissAnimator(dismiss_layer.Pass()))->Animate(); |
+ // TODO delete shadow when the dismiss animation finishes? |
+ overscroll_shadow_.reset(); |
+} |
+ |
+gfx::Rect OverscrollWindowAnimation::GetStarterBounds() const { |
+ gfx::Rect bounds = gfx::Rect(web_contents_window_->bounds().size()); |
+ if (direction_ == OverscrollNavigationOverlay::FORWARD) { |
+ // The overlay will be sliding in from the right edge towards the left in |
+ // non-RTL, or sliding in from the left edge towards the right in RTL. |
+ // So position the overlay window accordingly. |
+ bounds.Offset(base::i18n::IsRTL() ? -bounds.width() : bounds.width(), 0); |
+ } |
+ return bounds; |
+} |
+ |
+void OverscrollWindowAnimation::OnOverscrollComplete( |
+ OverscrollMode overscroll_mode) { |
+ LOG(ERROR) << "OWA: OnOverscrollComplete"; |
+ aura::Window* target = GetWindowToAnimateForOverscroll(); |
+ ui::ScopedLayerAnimationSettings settings(target->layer()->GetAnimator()); |
+ settings.SetPreemptionStrategy( |
+ ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); |
+ settings.SetTweenType(gfx::Tween::EASE_OUT); |
+ settings.AddObserver(this); |
+ gfx::Transform transform; |
+ int content_width = |
+ web_contents_->GetRenderWidgetHostView()->GetViewBounds().width(); |
+ float translate_x = static_cast<float>( |
+ direction_ == OverscrollNavigationOverlay::FORWARD ? -content_width |
+ : content_width); |
+ transform.Translate(translate_x, 0); |
+ target->SetTransform(transform); |
+ direction_ = OverscrollNavigationOverlay::NONE; |
+} |
+ |
+aura::Window* OverscrollWindowAnimation::GetWindowToAnimateForOverscroll() |
+ const { |
+ return direction_ == OverscrollNavigationOverlay::FORWARD |
+ ? overscroll_window_.get() |
+ : web_contents_->GetContentNativeView(); |
+} |
+ |
+} // namespace content |