Commit 5384f002 authored by nsatragno's avatar nsatragno Committed by Commit bot

Refactor GestureNavigation to eliminate code redundancy

Right now, Gesture Navigation has two very distinct phases: the initial
one, where the web contents window receives events and is moved, and the
follow up navigation, where the page still hasn't loaded and the user
scrolls on the overlay. The meat of this patch is to unify as much of
the logic as possible without sacrificing features. A new class is
introduced, OverscrollWindowAnimation, and the responsibility of the
existing OverscrollNavigationOverlay is steered into performing the
actual navigation.

TEST=Overscroll*
BUG=467692,464532,420121

Review URL: https://codereview.chromium.org/895543005

Cr-Commit-Position: refs/heads/master@{#324275}
parent 44a5cf89
......@@ -396,10 +396,12 @@ source_set("browser") {
"web_contents/aura/gesture_nav_simple.h",
"web_contents/aura/overscroll_navigation_overlay.cc",
"web_contents/aura/overscroll_navigation_overlay.h",
"web_contents/aura/overscroll_window_animation.cc",
"web_contents/aura/overscroll_window_animation.h",
"web_contents/aura/overscroll_window_delegate.cc",
"web_contents/aura/overscroll_window_delegate.h",
"web_contents/aura/shadow_layer_delegate.cc",
"web_contents/aura/shadow_layer_delegate.h",
"web_contents/aura/window_slider.cc",
"web_contents/aura/window_slider.h",
"web_contents/touch_editable_impl_aura.cc",
"web_contents/touch_editable_impl_aura.h",
"web_contents/web_contents_view_aura.cc",
......
......@@ -8,13 +8,14 @@
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "content/browser/renderer_host/overscroll_controller.h"
#include "content/common/content_export.h"
#include "ui/gfx/geometry/rect.h"
namespace content {
// The delegate receives overscroll gesture updates from the controller and
// should perform appropriate actions.
class OverscrollControllerDelegate {
class CONTENT_EXPORT OverscrollControllerDelegate {
public:
OverscrollControllerDelegate() {}
virtual ~OverscrollControllerDelegate() {}
......
......@@ -7,34 +7,56 @@
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "content/browser/web_contents/aura/window_slider.h"
#include "content/browser/web_contents/aura/overscroll_window_animation.h"
#include "content/browser/web_contents/web_contents_view_aura.h"
#include "content/common/content_export.h"
#include "content/public/browser/web_contents_observer.h"
#include "ui/gfx/image/image.h"
struct ViewHostMsg_UpdateRect_Params;
namespace aura_extra {
class ImageWindowDelegate;
}
namespace content {
class ImageLayerDelegate;
class OverscrollWindowDelegate;
class OverscrollNavigationOverlayTest;
class ScopedLayerClippingSetting;
// When a history navigation is triggered at the end of an overscroll
// navigation, it is necessary to show the history-screenshot until the page is
// done navigating and painting. This class accomplishes this by showing the
// screenshot window on top of the page until the page has completed loading and
// painting.
// done navigating and painting. This class accomplishes this by calling the
// navigation and creating, showing and destroying the screenshot window on top
// of the page until the page has completed loading and painting. When the
// overscroll completes, this screenshot window is returned by
// OnOverscrollComplete and |window_| is set to own it.
// There are two overscroll cases, for the first one the main window is the web
// contents window. At this stage, |window_| is null. The second case is
// triggered if the user overscrolls after |window_| is set, before the page
// finishes loading. When this happens, |window_| is the main window.
class CONTENT_EXPORT OverscrollNavigationOverlay
: public WebContentsObserver,
public WindowSlider::Delegate {
public OverscrollWindowAnimation::Delegate {
public:
explicit OverscrollNavigationOverlay(WebContentsImpl* web_contents);
enum NavigationDirection { FORWARD, BACK, NONE };
OverscrollNavigationOverlay(WebContentsImpl* web_contents,
aura::Window* web_contents_window);
~OverscrollNavigationOverlay() override;
bool has_window() const { return !!window_.get(); }
// Returns a pointer to the relay delegate we own.
OverscrollControllerDelegate* relay_delegate() { return owa_.get(); }
private:
class ScopedLayerClippingSetting;
friend class OverscrollNavigationOverlayTest;
FRIEND_TEST_ALL_PREFIXES(OverscrollNavigationOverlayTest, WithScreenshot);
FRIEND_TEST_ALL_PREFIXES(OverscrollNavigationOverlayTest, WithoutScreenshot);
FRIEND_TEST_ALL_PREFIXES(OverscrollNavigationOverlayTest, CannotNavigate);
FRIEND_TEST_ALL_PREFIXES(OverscrollNavigationOverlayTest, CancelNavigation);
FRIEND_TEST_ALL_PREFIXES(OverscrollNavigationOverlayTest,
CancelAfterSuccessfulNavigation);
FRIEND_TEST_ALL_PREFIXES(OverscrollNavigationOverlayTest, OverlayWindowSwap);
// Resets state and starts observing |web_contents_| for page load/paint
// updates. This function makes sure that the screenshot window is stacked
......@@ -44,63 +66,40 @@ class CONTENT_EXPORT OverscrollNavigationOverlay
// otherwise the overlay may be dismissed prematurely.
void StartObserving();
// Sets the screenshot window and the delegate. This takes ownership of
// |window|.
// Note that aura_extra::ImageWindowDelegate manages its own lifetime, so this
// function does not take ownership of |delegate|.
void SetOverlayWindow(scoped_ptr<aura::Window> window,
aura_extra::ImageWindowDelegate* delegate);
private:
friend class OverscrollNavigationOverlayTest;
FRIEND_TEST_ALL_PREFIXES(OverscrollNavigationOverlayTest,
FirstVisuallyNonEmptyPaint_NoImage);
FRIEND_TEST_ALL_PREFIXES(OverscrollNavigationOverlayTest,
FirstVisuallyNonEmptyPaint_WithImage);
FRIEND_TEST_ALL_PREFIXES(OverscrollNavigationOverlayTest,
LoadUpdateWithoutNonEmptyPaint);
FRIEND_TEST_ALL_PREFIXES(OverscrollNavigationOverlayTest,
MultiNavigation_LoadingUpdate);
FRIEND_TEST_ALL_PREFIXES(OverscrollNavigationOverlayTest,
MultiNavigation_PaintUpdate);
enum SlideDirection {
SLIDE_UNKNOWN,
SLIDE_BACK,
SLIDE_FRONT
};
// Stop observing the page and start the final overlay fade-out animation if
// a window-slide isn't in progress and either the page has been painted or
// the page-load has completed.
// there's no active overscroll window animation.
void StopObservingIfDone();
// Creates a layer to be used for window-slide. |offset| is the offset of the
// NavigationEntry for the screenshot image to display.
ui::Layer* CreateSlideLayer(int offset);
// Creates a window that shows a history-screenshot and is stacked relative to
// the current overscroll |direction_| with the given |bounds|.
scoped_ptr<aura::Window> CreateOverlayWindow(const gfx::Rect& bounds);
// Returns an image with the history-screenshot for the previous or next page,
// according to the given |direction|.
const gfx::Image GetImageForDirection(NavigationDirection direction) const;
// Overridden from WindowSlider::Delegate:
ui::Layer* CreateBackLayer() override;
ui::Layer* CreateFrontLayer() override;
void OnWindowSlideCompleting() override;
void OnWindowSlideCompleted(scoped_ptr<ui::Layer> layer) override;
void OnWindowSlideAborted() override;
void OnWindowSliderDestroyed() override;
// Overridden from OverscrollWindowAnimation::Delegate:
scoped_ptr<aura::Window> CreateFrontWindow(const gfx::Rect& bounds) override;
scoped_ptr<aura::Window> CreateBackWindow(const gfx::Rect& bounds) override;
aura::Window* GetMainWindow() const override;
void OnOverscrollCompleting() override;
void OnOverscrollCompleted(scoped_ptr<aura::Window> window) override;
void OnOverscrollCancelled() override;
// Overridden from WebContentsObserver:
void DidFirstVisuallyNonEmptyPaint() override;
void DidStopLoading() override;
// The WebContents which is being navigated.
// The current overscroll direction.
NavigationDirection direction_;
// The web contents that are being navigated.
WebContentsImpl* web_contents_;
// The screenshot overlay window.
// The overlay window that shows a screenshot during an overscroll gesture and
// handles overscroll events during the second overscroll case.
scoped_ptr<aura::Window> window_;
// This is the WindowDelegate of |window_|. The delegate manages its own
// lifetime (destroys itself when |window_| is destroyed).
aura_extra::ImageWindowDelegate* image_delegate_;
bool loading_complete_;
bool received_paint_update_;
......@@ -109,19 +108,15 @@ class CONTENT_EXPORT OverscrollNavigationOverlay
// when the relevant page loads and paints.
GURL pending_entry_url_;
// The |WindowSlider| that allows sliding history layers while the page is
// being reloaded.
scoped_ptr<WindowSlider> window_slider_;
// Layer to be used for the final overlay fadeout animation when the overlay
// is being dismissed.
scoped_ptr<ui::Layer> overlay_dismiss_layer_;
// Manages the overscroll animations.
scoped_ptr<OverscrollWindowAnimation> owa_;
// The direction of the in-progress slide (if any).
SlideDirection slide_direction_;
// The window that hosts the web contents.
aura::Window* web_contents_window_;
// The LayerDelegate used for the back/front layers during a slide.
scoped_ptr<ImageLayerDelegate> layer_delegate_;
// Scoped clipping settings for the contents layer and its parent.
scoped_ptr<ScopedLayerClippingSetting> contents_layer_settings_;
scoped_ptr<ScopedLayerClippingSetting> contents_layer_parent_settings_;
DISALLOW_COPY_AND_ASSIGN(OverscrollNavigationOverlay);
};
......
// Copyright 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 <algorithm>
#include "base/i18n/rtl.h"
#include "content/browser/web_contents/aura/shadow_layer_delegate.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "ui/aura/window.h"
#include "ui/compositor/layer_animation_observer.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
namespace content {
namespace {
OverscrollWindowAnimation::Direction GetDirectionForMode(OverscrollMode mode) {
if (mode == (base::i18n::IsRTL() ? OVERSCROLL_EAST : OVERSCROLL_WEST))
return OverscrollWindowAnimation::SLIDE_FRONT;
if (mode == (base::i18n::IsRTL() ? OVERSCROLL_WEST : OVERSCROLL_EAST))
return OverscrollWindowAnimation::SLIDE_BACK;
return OverscrollWindowAnimation::SLIDE_NONE;
}
} // namespace
OverscrollWindowAnimation::OverscrollWindowAnimation(Delegate* delegate)
: delegate_(delegate),
direction_(SLIDE_NONE),
overscroll_cancelled_(false) {
DCHECK(delegate_);
}
OverscrollWindowAnimation::~OverscrollWindowAnimation() {
}
void OverscrollWindowAnimation::CancelSlide() {
ui::Layer* layer = GetFrontLayer();
ui::ScopedLayerAnimationSettings settings(layer->GetAnimator());
settings.SetPreemptionStrategy(
ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
settings.SetTweenType(gfx::Tween::EASE_OUT);
settings.AddObserver(this);
layer->SetTransform(gfx::Transform());
overscroll_cancelled_ = true;
}
float OverscrollWindowAnimation::GetTranslationForOverscroll(float delta_x) {
DCHECK(direction_ != SLIDE_NONE);
const float bounds_width = GetVisibleBounds().width();
if (direction_ == SLIDE_FRONT)
return std::max(-bounds_width, delta_x);
else
return std::min(bounds_width, delta_x);
}
gfx::Rect OverscrollWindowAnimation::GetVisibleBounds() const {
return delegate_->GetMainWindow()->bounds();
}
bool OverscrollWindowAnimation::OnOverscrollUpdate(float delta_x,
float delta_y) {
if (direction_ == SLIDE_NONE)
return false;
gfx::Transform transform;
transform.Translate(GetTranslationForOverscroll(delta_x), 0);
GetFrontLayer()->SetTransform(transform);
return true;
}
void OverscrollWindowAnimation::OnImplicitAnimationsCompleted() {
if (overscroll_cancelled_) {
slide_window_.reset();
delegate_->OnOverscrollCancelled();
overscroll_cancelled_ = false;
} else {
delegate_->OnOverscrollCompleted(slide_window_.Pass());
}
direction_ = SLIDE_NONE;
}
void OverscrollWindowAnimation::OnOverscrollModeChange(
OverscrollMode old_mode,
OverscrollMode new_mode) {
Direction new_direction = GetDirectionForMode(new_mode);
if (new_direction == SLIDE_NONE) {
// The user cancelled the in progress animation.
if (is_active())
CancelSlide();
return;
}
if (is_active())
GetFrontLayer()->GetAnimator()->StopAnimating();
gfx::Rect slide_window_bounds = gfx::Rect(GetVisibleBounds().size());
if (new_direction == SLIDE_FRONT) {
slide_window_bounds.Offset(base::i18n::IsRTL()
? -slide_window_bounds.width()
: slide_window_bounds.width(),
0);
}
slide_window_ = new_direction == SLIDE_FRONT
? delegate_->CreateFrontWindow(slide_window_bounds)
: delegate_->CreateBackWindow(slide_window_bounds);
if (!slide_window_) {
// Cannot navigate, do not start an overscroll gesture.
direction_ = SLIDE_NONE;
return;
}
overscroll_cancelled_ = false;
direction_ = new_direction;
shadow_.reset(new ShadowLayerDelegate(GetFrontLayer()));
}
void OverscrollWindowAnimation::OnOverscrollComplete(
OverscrollMode overscroll_mode) {
if (!is_active())
return;
delegate_->OnOverscrollCompleting();
int content_width = GetVisibleBounds().width();
float translate_x;
if ((base::i18n::IsRTL() && direction_ == SLIDE_FRONT) ||
(!base::i18n::IsRTL() && direction_ == SLIDE_BACK)) {
translate_x = content_width;
} else {
translate_x = -content_width;
}
ui::Layer* layer = GetFrontLayer();
gfx::Transform transform;
transform.Translate(translate_x, 0);
ui::ScopedLayerAnimationSettings settings(layer->GetAnimator());
settings.SetPreemptionStrategy(
ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
settings.SetTweenType(gfx::Tween::EASE_OUT);
settings.AddObserver(this);
layer->SetTransform(transform);
}
ui::Layer* OverscrollWindowAnimation::GetFrontLayer() const {
DCHECK(direction_ != SLIDE_NONE);
if (direction_ == SLIDE_FRONT) {
DCHECK(slide_window_);
return slide_window_->layer();
}
return delegate_->GetMainWindow()->layer();
}
} // namespace content
// Copyright 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.
#ifndef CONTENT_BROWSER_WEB_CONTENTS_AURA_OVERSCROLL_WINDOW_ANIMATION_H_
#define CONTENT_BROWSER_WEB_CONTENTS_AURA_OVERSCROLL_WINDOW_ANIMATION_H_
#include "base/gtest_prod_util.h"
#include "content/browser/renderer_host/overscroll_controller_delegate.h"
#include "content/common/content_export.h"
#include "ui/compositor/layer_animation_observer.h"
namespace aura {
class Window;
}
namespace ui {
class Layer;
class LayerAnimator;
}
namespace content {
class ShadowLayerDelegate;
class WebContentsImpl;
// Manages the animation of a window sliding on top or behind another one. The
// main window, which is the one displayed before the animation starts, is not
// owned by OverscrollWindowAnimation, while the slide window, created at the
// start of the animation, is owned by us for its duration.
class CONTENT_EXPORT OverscrollWindowAnimation
: public OverscrollControllerDelegate,
ui::ImplicitAnimationObserver {
public:
// The direction of this animation. SLIDE_FRONT indicates that the main window
// stays still while the slide window moves on top of it, entering in from the
// right. SLIDE_BACK means that the main window is animated to the right,
// revealing the slide window in the back, which stays still. SLIDE_NONE
// means we are not animating yet. Left and right are reversed for RTL
// languages, but stack order remains unchanged.
enum Direction { SLIDE_FRONT, SLIDE_BACK, SLIDE_NONE };
// Delegate class that interfaces with the window animation.
class CONTENT_EXPORT Delegate {
public:
virtual ~Delegate() {}
// Create a slide window with the given |bounds| relative to its parent.
virtual scoped_ptr<aura::Window> CreateFrontWindow(
const gfx::Rect& bounds) = 0;
virtual scoped_ptr<aura::Window> CreateBackWindow(
const gfx::Rect& bounds) = 0;
// Returns the main window that participates in the animation. The delegate
// does not own this window.
virtual aura::Window* GetMainWindow() const = 0;
// Called when we know the animation is going to complete successfully, but
// before it actually completes.
virtual void OnOverscrollCompleting() = 0;
// Called when the animation has been completed. The slide window is
// transferred to the delegate.
virtual void OnOverscrollCompleted(scoped_ptr<aura::Window> window) = 0;
// Called when the overscroll gesture has been cancelled, after the cancel
// animation finishes.
virtual void OnOverscrollCancelled() = 0;
};
explicit OverscrollWindowAnimation(Delegate* delegate);
~OverscrollWindowAnimation() override;
// Returns true if we are currently animating.
bool is_active() const { return !!slide_window_; }
// OverscrollControllerDelegate:
gfx::Rect GetVisibleBounds() const override;
bool OnOverscrollUpdate(float delta_x, float delta_y) override;
void OnOverscrollComplete(OverscrollMode overscroll_mode) override;
void OnOverscrollModeChange(OverscrollMode old_mode,
OverscrollMode new_mode) override;
private:
// Cancels the slide, animating the front window to its original position.
void CancelSlide();
// Returns a translation on the x axis for the given overscroll.
float GetTranslationForOverscroll(float delta_x);
// Returns the layer that is animated for the animation. The caller does not
// own it.
ui::Layer* GetFrontLayer() const;
// ui::ImplicitAnimationObserver:
void OnImplicitAnimationsCompleted() override;
// We own the window created for the animation.
scoped_ptr<aura::Window> slide_window_;
// Shadow shown under the animated layer.
scoped_ptr<ShadowLayerDelegate> shadow_;
// Delegate that provides the animation target and is notified of the
// animation state.
Delegate* delegate_;
// The current animation direction.
Direction direction_;
// Indicates if the current animation has been cancelled. True while the
// cancel animation is in progress.
bool overscroll_cancelled_;
DISALLOW_COPY_AND_ASSIGN(OverscrollWindowAnimation);
};
} // namespace content
#endif // CONTENT_BROWSER_WEB_CONTENTS_AURA_OVERSCROLL_WINDOW_ANIMATION_H_
// Copyright 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 "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/test/aura_test_base.h"
#include "ui/aura/window.h"
#include "ui/compositor/scoped_animation_duration_scale_mode.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/compositor/test/layer_animator_test_controller.h"
#include "ui/gfx/frame_time.h"
namespace content {
class OverscrollWindowAnimationTest
: public OverscrollWindowAnimation::Delegate,
public aura::test::AuraTestBase {
public:
OverscrollWindowAnimationTest()
: create_window_(true),
overscroll_started_(false),
overscroll_completing_(false),
overscroll_completed_(false),
overscroll_aborted_(false),
main_window_(nullptr) {}
~OverscrollWindowAnimationTest() override {}
OverscrollWindowAnimation* owa() { return owa_.get(); }
// Set to true to return a window in the Create*Window functions, false to
// return null.
void set_create_window(bool create_window) { create_window_ = create_window; }
// The following functions indicate if the events have been called on this
// delegate.
bool overscroll_started() { return overscroll_started_; }
bool overscroll_completing() { return overscroll_completing_; }
bool overscroll_completed() { return overscroll_completed_; }
bool overscroll_aborted() { return overscroll_aborted_; }
void ResetFlags() {
overscroll_started_ = false;
overscroll_completing_ = false;
overscroll_completed_ = false;
overscroll_aborted_ = false;
}
protected:
// aura::test::AuraTestBase:
void SetUp() override {
aura::test::AuraTestBase::SetUp();
main_window_.reset(CreateNormalWindow(0, root_window(), nullptr));
ResetFlags();
create_window_ = true;
last_window_id_ = 0;
owa_.reset(new OverscrollWindowAnimation(this));
}
void TearDown() override {
owa_.reset();
main_window_.reset();
aura::test::AuraTestBase::TearDown();
}
// OverscrollWindowAnimation::Delegate:
scoped_ptr<aura::Window> CreateFrontWindow(const gfx::Rect& bounds) override {
return CreateSlideWindow(bounds);
}
scoped_ptr<aura::Window> CreateBackWindow(const gfx::Rect& bounds) override {
return CreateSlideWindow(bounds);
}
aura::Window* GetMainWindow() const override { return main_window_.get(); }
void OnOverscrollCompleting() override { overscroll_completing_ = true; }
void OnOverscrollCompleted(scoped_ptr<aura::Window> window) override {
overscroll_completed_ = true;
}
void OnOverscrollCancelled() override { overscroll_aborted_ = true; }
private:
// The overscroll window animation under test.
scoped_ptr<OverscrollWindowAnimation> owa_;
scoped_ptr<aura::Window> CreateSlideWindow(const gfx::Rect& bounds) {
overscroll_started_ = true;
if (create_window_) {
scoped_ptr<aura::Window> window(
CreateNormalWindow(++last_window_id_, root_window(), nullptr));
window->SetBounds(bounds);
return window.Pass();
}
return nullptr;
}
// Controls if we return a window for the window creation callbacks or not.
bool create_window_;
// State flags.
bool overscroll_started_;
bool overscroll_completing_;
bool overscroll_completed_;
bool overscroll_aborted_;
int last_window_id_;
// The dummy target window we provide.
scoped_ptr<aura::Window> main_window_;
DISALLOW_COPY_AND_ASSIGN(OverscrollWindowAnimationTest);
};
// Tests a simple overscroll gesture.
TEST_F(OverscrollWindowAnimationTest, BasicOverscroll) {
EXPECT_FALSE(owa()->is_active());
EXPECT_FALSE(overscroll_started());
EXPECT_FALSE(overscroll_completing());
EXPECT_FALSE(overscroll_completed());
EXPECT_FALSE(overscroll_aborted());
// Start an OVERSCROLL_EAST gesture.
owa()->OnOverscrollModeChange(OVERSCROLL_NONE, OVERSCROLL_EAST);
EXPECT_TRUE(owa()->is_active());
EXPECT_TRUE(overscroll_started());
EXPECT_FALSE(overscroll_completing());
EXPECT_FALSE(overscroll_completed());
EXPECT_FALSE(overscroll_aborted());
// Complete the overscroll.
owa()->OnOverscrollComplete(OVERSCROLL_EAST);
EXPECT_FALSE(owa()->is_active());
EXPECT_TRUE(overscroll_started());
EXPECT_TRUE(overscroll_completing());
EXPECT_TRUE(overscroll_completed());
EXPECT_FALSE(overscroll_aborted());
}
// Tests aborting an overscroll gesture.
TEST_F(OverscrollWindowAnimationTest, BasicAbort) {
// Start an OVERSCROLL_EAST gesture.
owa()->OnOverscrollModeChange(OVERSCROLL_NONE, OVERSCROLL_EAST);
// Abort the overscroll.
owa()->OnOverscrollModeChange(OVERSCROLL_EAST, OVERSCROLL_NONE);
EXPECT_FALSE(owa()->is_active());
EXPECT_TRUE(overscroll_started());
EXPECT_FALSE(overscroll_completing());
EXPECT_FALSE(overscroll_completed());
EXPECT_TRUE(overscroll_aborted());
}
// Tests starting an overscroll gesture when the slide window cannot be created.
TEST_F(OverscrollWindowAnimationTest, BasicCannotNavigate) {
set_create_window(false);
// Start an OVERSCROLL_EAST gesture.
owa()->OnOverscrollModeChange(OVERSCROLL_NONE, OVERSCROLL_EAST);
EXPECT_FALSE(owa()->is_active());
EXPECT_TRUE(overscroll_started());
EXPECT_FALSE(overscroll_completing());
EXPECT_FALSE(overscroll_completed());
EXPECT_FALSE(overscroll_aborted());
}
// Tests starting an overscroll gesture while another one was in progress
// completes the first one.
TEST_F(OverscrollWindowAnimationTest, NewOverscrollCompletesPreviousGesture) {
// This test requires a normal animation duration so that
// OnImplicitAnimationsCancelled is not called as soon as the first overscroll
// finishes.
ui::ScopedAnimationDurationScaleMode normal_duration(
ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
ui::LayerAnimator* animator = GetMainWindow()->layer()->GetAnimator();
ui::ScopedLayerAnimationSettings settings(animator);
animator->set_disable_timer_for_test(true);
ui::LayerAnimatorTestController test_controller(animator);
// Start an OVERSCROLL_EAST gesture.
owa()->OnOverscrollModeChange(OVERSCROLL_NONE, OVERSCROLL_EAST);
// Finishes the OVERSCROLL_EAST gesture. At this point the window should be
// being animated to its final position.
owa()->OnOverscrollComplete(OVERSCROLL_EAST);
EXPECT_TRUE(owa()->is_active());
EXPECT_TRUE(overscroll_started());
EXPECT_TRUE(overscroll_completing());
EXPECT_FALSE(overscroll_completed());
EXPECT_FALSE(overscroll_aborted());
// Start another OVERSCROLL_EAST gesture.
owa()->OnOverscrollModeChange(OVERSCROLL_NONE, OVERSCROLL_EAST);
EXPECT_TRUE(owa()->is_active());
EXPECT_TRUE(overscroll_started());
EXPECT_TRUE(overscroll_completing());
EXPECT_TRUE(overscroll_completed());
EXPECT_FALSE(overscroll_aborted());
// Complete the overscroll gesture.
ResetFlags();
owa()->OnOverscrollComplete(OVERSCROLL_EAST);
base::TimeDelta duration = settings.GetTransitionDuration();
test_controller.StartThreadedAnimationsIfNeeded();
base::TimeTicks start_time = gfx::FrameTime::Now();
// Halfway through the animation, OverscrollCompleting should have been fired.
animator->Step(start_time + duration / 2);
EXPECT_TRUE(owa()->is_active());
EXPECT_FALSE(overscroll_started());
EXPECT_TRUE(overscroll_completing());
EXPECT_FALSE(overscroll_completed());
EXPECT_FALSE(overscroll_aborted());
// The animation has finished, OverscrollCompleted should have been fired.
animator->Step(start_time + duration);
EXPECT_FALSE(owa()->is_active());
EXPECT_FALSE(overscroll_started());
EXPECT_TRUE(overscroll_completing());
EXPECT_TRUE(overscroll_completed());
EXPECT_FALSE(overscroll_aborted());
}
} // namespace content
// Copyright 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_delegate.h"
#include "base/i18n/rtl.h"
#include "content/browser/frame_host/navigation_controller_impl.h"
#include "content/browser/frame_host/navigation_entry_impl.h"
#include "content/browser/renderer_host/overscroll_controller_delegate.h"
#include "content/public/browser/overscroll_configuration.h"
#include "ui/aura/window.h"
#include "ui/gfx/image/image_png_rep.h"
namespace content {
OverscrollWindowDelegate::OverscrollWindowDelegate(
OverscrollControllerDelegate* delegate,
const gfx::Image& image)
: delegate_(delegate),
overscroll_mode_(OVERSCROLL_NONE),
delta_x_(0.f),
complete_threshold_ratio_(content::GetOverscrollConfig(
content::OVERSCROLL_CONFIG_HORIZ_THRESHOLD_COMPLETE)),
start_threshold_touchscreen_(content::GetOverscrollConfig(
content::OVERSCROLL_CONFIG_HORIZ_THRESHOLD_START_TOUCHSCREEN)),
start_threshold_touchpad_(content::GetOverscrollConfig(
content::OVERSCROLL_CONFIG_HORIZ_THRESHOLD_START_TOUCHPAD)),
active_start_threshold_(0.f) {
SetImage(image);
}
OverscrollWindowDelegate::~OverscrollWindowDelegate() {
}
void OverscrollWindowDelegate::StartOverscroll() {
OverscrollMode old_mode = overscroll_mode_;
if (delta_x_ > 0)
overscroll_mode_ = OVERSCROLL_EAST;
else
overscroll_mode_ = OVERSCROLL_WEST;
delegate_->OnOverscrollModeChange(old_mode, overscroll_mode_);
}
void OverscrollWindowDelegate::ResetOverscroll() {
delegate_->OnOverscrollModeChange(overscroll_mode_, OVERSCROLL_NONE);
overscroll_mode_ = OVERSCROLL_NONE;
delta_x_ = 0;
}
void OverscrollWindowDelegate::CompleteOrResetOverscroll() {
if (overscroll_mode_ == OVERSCROLL_NONE)
return;
int width = delegate_->GetVisibleBounds().width();
float ratio = (fabs(delta_x_)) / width;
if (ratio < complete_threshold_ratio_) {
ResetOverscroll();
return;
}
delegate_->OnOverscrollComplete(overscroll_mode_);
overscroll_mode_ = OVERSCROLL_NONE;
delta_x_ = 0;
}
void OverscrollWindowDelegate::UpdateOverscroll(float delta_x) {
float old_delta_x = delta_x_;
delta_x_ += delta_x;
if (overscroll_mode_ == OVERSCROLL_NONE) {
if (fabs(delta_x_) > active_start_threshold_)
StartOverscroll();
return;
}
if ((old_delta_x < 0 && delta_x_ > 0) || (old_delta_x > 0 && delta_x_ < 0)) {
ResetOverscroll();
return;
}
delegate_->OnOverscrollUpdate(delta_x_, 0.f);
}
void OverscrollWindowDelegate::OnKeyEvent(ui::KeyEvent* event) {
ResetOverscroll();
}
void OverscrollWindowDelegate::OnMouseEvent(ui::MouseEvent* event) {
if (!(event->flags() & ui::EF_IS_SYNTHESIZED) &&
event->type() != ui::ET_MOUSE_CAPTURE_CHANGED) {
ResetOverscroll();
}
}
void OverscrollWindowDelegate::OnScrollEvent(ui::ScrollEvent* event) {
active_start_threshold_ = start_threshold_touchpad_;
if (event->type() == ui::ET_SCROLL)
UpdateOverscroll(event->x_offset_ordinal());
else if (event->type() == ui::ET_SCROLL_FLING_START)
CompleteOrResetOverscroll();
else
ResetOverscroll();
event->SetHandled();
}
void OverscrollWindowDelegate::OnGestureEvent(ui::GestureEvent* event) {
active_start_threshold_ = start_threshold_touchscreen_;
switch (event->type()) {
case ui::ET_GESTURE_SCROLL_UPDATE:
UpdateOverscroll(event->details().scroll_x());
break;
case ui::ET_GESTURE_SCROLL_END:
CompleteOrResetOverscroll();
break;
case ui::ET_SCROLL_FLING_START:
CompleteOrResetOverscroll();
break;
case ui::ET_GESTURE_PINCH_BEGIN:
case ui::ET_GESTURE_PINCH_UPDATE:
case ui::ET_GESTURE_PINCH_END:
ResetOverscroll();
break;
default:
break;
}
event->SetHandled();
}
} // namespace content
// Copyright 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.
#ifndef CONTENT_BROWSER_WEB_CONTENTS_AURA_OVERSCROLL_WINDOW_DELEGATE_H_
#define CONTENT_BROWSER_WEB_CONTENTS_AURA_OVERSCROLL_WINDOW_DELEGATE_H_
#include "content/browser/renderer_host/overscroll_controller.h"
#include "content/browser/web_contents/aura/overscroll_navigation_overlay.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "ui/aura_extra/image_window_delegate.h"
namespace content {
// The window delegate for the overscroll window. This processes UI trackpad and
// touch events and converts them to overscroll event. The delegate destroys
// itself when the window is destroyed.
class CONTENT_EXPORT OverscrollWindowDelegate
: public aura_extra::ImageWindowDelegate {
public:
OverscrollWindowDelegate(OverscrollControllerDelegate* delegate,
const gfx::Image& image);
private:
FRIEND_TEST_ALL_PREFIXES(OverscrollWindowDelegateTest, BasicOverscrollModes);
~OverscrollWindowDelegate() override;
// Starts the overscroll gesture.
void StartOverscroll();
// Resets the overscroll state.
void ResetOverscroll();
// Completes or resets the overscroll from the current state.
void CompleteOrResetOverscroll();
// Updates the current horizontal overscroll.
void UpdateOverscroll(float delta_x);
// Overridden from ui::EventHandler.
void OnKeyEvent(ui::KeyEvent* event) override;
void OnMouseEvent(ui::MouseEvent* event) override;
void OnScrollEvent(ui::ScrollEvent* event) override;
void OnGestureEvent(ui::GestureEvent* event) override;
// Delegate to which we forward overscroll events.
OverscrollControllerDelegate* delegate_;
// The current overscroll mode.
OverscrollMode overscroll_mode_;
// The latest delta_x scroll update.
float delta_x_;
// The ratio of overscroll at which we consider the overscroll completed.
const float complete_threshold_ratio_;
// The threshold for starting the overscroll gesture, for touchscreen or
// touchpads.
const float start_threshold_touchscreen_;
const float start_threshold_touchpad_;
// The threshold for starting the overscroll gesture for the current touch
// input.
float active_start_threshold_;
DISALLOW_COPY_AND_ASSIGN(OverscrollWindowDelegate);
};
} // namespace content
#endif // CONTENT_BROWSER_WEB_CONTENTS_AURA_OVERSCROLL_WINDOW_DELEGATE_H_
// Copyright 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_delegate.h"
#include "content/browser/renderer_host/overscroll_controller_delegate.h"
#include "content/public/browser/overscroll_configuration.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/test/aura_test_base.h"
#include "ui/aura/window.h"
#include "ui/events/gesture_detection/gesture_configuration.h"
#include "ui/events/test/event_generator.h"
namespace content {
namespace {
const int kTestWindowWidth = 600;
}
class OverscrollWindowDelegateTest : public aura::test::AuraTestBase,
public OverscrollControllerDelegate {
public:
OverscrollWindowDelegateTest()
: window_(nullptr),
overscroll_complete_(false),
overscroll_started_(false),
current_mode_(OVERSCROLL_NONE),
touch_start_threshold_(content::GetOverscrollConfig(
content::OVERSCROLL_CONFIG_HORIZ_THRESHOLD_START_TOUCHSCREEN)),
touch_complete_threshold_(content::GetOverscrollConfig(
content::OVERSCROLL_CONFIG_HORIZ_THRESHOLD_COMPLETE)) {
}
~OverscrollWindowDelegateTest() override {}
void Reset() {
overscroll_complete_ = false;
overscroll_started_ = false;
current_mode_ = OVERSCROLL_NONE;
window_.reset(CreateNormalWindow(
0, root_window(), new OverscrollWindowDelegate(this, gfx::Image())));
window_->SetBounds(gfx::Rect(0, 0, kTestWindowWidth, kTestWindowWidth));
}
// Accessors.
aura::Window* window() { return window_.get(); }
bool overscroll_complete() { return overscroll_complete_; }
bool overscroll_started() { return overscroll_started_; }
OverscrollMode current_mode() { return current_mode_; }
const float touch_start_threshold() {
return touch_start_threshold_;
}
const float touch_complete_threshold() {
return kTestWindowWidth * touch_complete_threshold_;
}
protected:
// aura::test::AuraTestBase:
void SetUp() override {
aura::test::AuraTestBase::SetUp();
Reset();
ui::GestureConfiguration::GetInstance()
->set_max_touch_move_in_pixels_for_click(0);
}
void TearDown() override {
window_.reset();
aura::test::AuraTestBase::TearDown();
}
private:
// OverscrollControllerDelegate:
gfx::Rect GetVisibleBounds() const override {
return gfx::Rect(kTestWindowWidth, kTestWindowWidth);
}
bool OnOverscrollUpdate(float delta_x, float delta_y) override {
return true;
}
void OnOverscrollComplete(OverscrollMode overscroll_mode) override {
overscroll_complete_ = true;
}
void OnOverscrollModeChange(OverscrollMode old_mode,
OverscrollMode new_mode) override {
current_mode_ = new_mode;
if (current_mode_ != OVERSCROLL_NONE)
overscroll_started_ = true;
}
// Window in which the overscroll window delegate is installed.
scoped_ptr<aura::Window> window_;
// State flags.
bool overscroll_complete_;
bool overscroll_started_;
OverscrollMode current_mode_;
// Config defined constants.
const float touch_start_threshold_;
const float touch_complete_threshold_;
DISALLOW_COPY_AND_ASSIGN(OverscrollWindowDelegateTest);
};
// Tests that the basic overscroll gesture works and sends updates to the
// delegate.
TEST_F(OverscrollWindowDelegateTest, BasicOverscroll) {
ui::test::EventGenerator generator(root_window());
// Start an OVERSCROLL_EAST gesture.
generator.GestureScrollSequence(
gfx::Point(0, 0), gfx::Point(touch_complete_threshold() + 1, 10),
base::TimeDelta::FromMilliseconds(10), 10);
EXPECT_TRUE(overscroll_started());
EXPECT_EQ(current_mode(), OVERSCROLL_EAST);
EXPECT_TRUE(overscroll_complete());
Reset();
// Start an OVERSCROLL_WEST gesture.
generator.GestureScrollSequence(gfx::Point(touch_complete_threshold() + 1, 0),
gfx::Point(0, 0),
base::TimeDelta::FromMilliseconds(10), 10);
EXPECT_TRUE(overscroll_started());
EXPECT_EQ(current_mode(), OVERSCROLL_WEST);
EXPECT_TRUE(overscroll_complete());
}
// Verifies that the OverscrollWindowDelegate direction is set correctly during
// an overscroll.
TEST_F(OverscrollWindowDelegateTest, BasicOverscrollModes) {
ui::test::EventGenerator generator(root_window());
OverscrollWindowDelegate* delegate =
static_cast<OverscrollWindowDelegate*>(window()->delegate());
// Start pressing a touch, but do not start the gesture yet.
generator.MoveTouch(gfx::Point(0, 0));
generator.PressTouch();
EXPECT_EQ(delegate->overscroll_mode_, OVERSCROLL_NONE);
// Slide the touch to the right.
generator.MoveTouch(gfx::Point(touch_complete_threshold() + 1, 0));
EXPECT_EQ(delegate->overscroll_mode_, OVERSCROLL_EAST);
// Complete the gesture.
generator.ReleaseTouch();
EXPECT_EQ(delegate->overscroll_mode_, OVERSCROLL_NONE);
EXPECT_TRUE(overscroll_complete());
// Start another overscroll.
generator.MoveTouch(gfx::Point(touch_complete_threshold() + 1, 0));
generator.PressTouch();
EXPECT_EQ(delegate->overscroll_mode_, OVERSCROLL_NONE);
// Slide the touch to the left.
generator.MoveTouch(gfx::Point(0, 0));
EXPECT_EQ(delegate->overscroll_mode_, OVERSCROLL_WEST);
// Complete the gesture.
generator.ReleaseTouch();
EXPECT_EQ(delegate->overscroll_mode_, OVERSCROLL_NONE);
EXPECT_TRUE(overscroll_complete());
}
// Tests that the overscroll does not start until the gesture gets past a
// particular threshold.
TEST_F(OverscrollWindowDelegateTest, OverscrollThreshold) {
ui::test::EventGenerator generator(root_window());
// Start an OVERSCROLL_EAST gesture.
generator.GestureScrollSequence(gfx::Point(0, 0),
gfx::Point(touch_start_threshold(), 0),
base::TimeDelta::FromMilliseconds(10), 10);
EXPECT_FALSE(overscroll_started());
EXPECT_EQ(current_mode(), OVERSCROLL_NONE);
EXPECT_FALSE(overscroll_complete());
Reset();
// Start an OVERSCROLL_WEST gesture.
generator.GestureScrollSequence(gfx::Point(touch_start_threshold(), 0),
gfx::Point(0, 0),
base::TimeDelta::FromMilliseconds(10), 10);
EXPECT_FALSE(overscroll_started());
EXPECT_EQ(current_mode(), OVERSCROLL_NONE);
EXPECT_FALSE(overscroll_complete());
}
// Tests that the overscroll is aborted if the gesture does not get past the
// completion threshold.
TEST_F(OverscrollWindowDelegateTest, AbortOverscrollThreshold) {
ui::test::EventGenerator generator(root_window());
// Start an OVERSCROLL_EAST gesture.
generator.GestureScrollSequence(gfx::Point(0, 0),
gfx::Point(touch_start_threshold() + 1, 0),
base::TimeDelta::FromMilliseconds(10), 10);
EXPECT_TRUE(overscroll_started());
EXPECT_EQ(current_mode(), OVERSCROLL_NONE);
EXPECT_FALSE(overscroll_complete());
Reset();
// Start an OVERSCROLL_WEST gesture.
generator.GestureScrollSequence(gfx::Point(touch_start_threshold() + 1, 0),
gfx::Point(0, 0),
base::TimeDelta::FromMilliseconds(10), 10);
EXPECT_TRUE(overscroll_started());
EXPECT_EQ(current_mode(), OVERSCROLL_NONE);
EXPECT_FALSE(overscroll_complete());
}
// Tests that the overscroll is aborted if the delegate receives some other
// event.
TEST_F(OverscrollWindowDelegateTest, EventAbortsOverscroll) {
ui::test::EventGenerator generator(root_window());
// Start an OVERSCROLL_EAST gesture, without releasing touch.
generator.set_current_location(gfx::Point(0, 0));
generator.PressTouch();
int touch_x = touch_start_threshold() + 1;
generator.MoveTouch(gfx::Point(touch_x, 0));
EXPECT_TRUE(overscroll_started());
EXPECT_EQ(current_mode(), OVERSCROLL_EAST);
EXPECT_FALSE(overscroll_complete());
// Dispatch a mouse event, the overscroll should be cancelled.
generator.PressLeftButton();
EXPECT_EQ(current_mode(), OVERSCROLL_NONE);
EXPECT_FALSE(overscroll_complete());
// We should be able to restart the overscroll without lifting the finger.
generator.MoveTouch(gfx::Point(touch_x + touch_start_threshold() + 1, 0));
EXPECT_EQ(current_mode(), OVERSCROLL_EAST);
EXPECT_FALSE(overscroll_complete());
}
} // namespace content
// Copyright (c) 2013 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/window_slider.h"
#include <algorithm>
#include "base/bind.h"
#include "base/callback.h"
#include "content/browser/web_contents/aura/shadow_layer_delegate.h"
#include "content/public/browser/overscroll_configuration.h"
#include "ui/aura/window.h"
#include "ui/compositor/layer_animation_observer.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/events/event.h"
namespace content {
namespace {
// An animation observer that runs a callback at the end of the animation, and
// destroys itself.
class CallbackAnimationObserver : public ui::ImplicitAnimationObserver {
public:
CallbackAnimationObserver(const base::Closure& closure)
: closure_(closure) {
}
~CallbackAnimationObserver() override {}
private:
// Overridden from ui::ImplicitAnimationObserver:
void OnImplicitAnimationsCompleted() override {
if (!closure_.is_null())
closure_.Run();
base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
}
const base::Closure closure_;
DISALLOW_COPY_AND_ASSIGN(CallbackAnimationObserver);
};
} // namespace
WindowSlider::WindowSlider(Delegate* delegate,
aura::Window* event_window,
aura::Window* owner)
: delegate_(delegate),
event_window_(event_window),
owner_(owner),
active_animator_(NULL),
delta_x_(0.f),
active_start_threshold_(0.f),
start_threshold_touchscreen_(content::GetOverscrollConfig(
content::OVERSCROLL_CONFIG_HORIZ_THRESHOLD_START_TOUCHSCREEN)),
start_threshold_touchpad_(content::GetOverscrollConfig(
content::OVERSCROLL_CONFIG_HORIZ_THRESHOLD_START_TOUCHPAD)),
complete_threshold_(content::GetOverscrollConfig(
content::OVERSCROLL_CONFIG_HORIZ_THRESHOLD_COMPLETE)),
weak_factory_(this) {
event_window_->AddPreTargetHandler(this);
event_window_->AddObserver(this);
owner_->AddObserver(this);
}
WindowSlider::~WindowSlider() {
if (event_window_) {
event_window_->RemovePreTargetHandler(this);
event_window_->RemoveObserver(this);
}
if (owner_)
owner_->RemoveObserver(this);
delegate_->OnWindowSliderDestroyed();
}
void WindowSlider::ChangeOwner(aura::Window* new_owner) {
if (owner_)
owner_->RemoveObserver(this);
owner_ = new_owner;
if (owner_) {
owner_->AddObserver(this);
UpdateForScroll(0.f, 0.f);
}
}
bool WindowSlider::IsSlideInProgress() const {
// if active_start_threshold_ is 0, it means that sliding hasn't been started
return active_start_threshold_ != 0 && (slider_.get() || active_animator_);
}
void WindowSlider::SetupSliderLayer() {
ui::Layer* parent = owner_->layer()->parent();
parent->Add(slider_.get());
if (delta_x_ < 0)
parent->StackAbove(slider_.get(), owner_->layer());
else
parent->StackBelow(slider_.get(), owner_->layer());
slider_->SetBounds(owner_->layer()->bounds());
slider_->SetVisible(true);
}
void WindowSlider::UpdateForScroll(float x_offset, float y_offset) {
if (active_animator_) {
// If there is an active animation, complete it before processing the scroll
// so that the callbacks that are invoked on the Delegate are consistent.
// Completing the animation may destroy WindowSlider through the animation
// callback, so we can't continue processing the scroll event here.
delta_x_ += x_offset;
CompleteActiveAnimations();
return;
}
float old_delta = delta_x_;
delta_x_ += x_offset;
if (fabs(delta_x_) < active_start_threshold_ && !slider_.get())
return;
if ((old_delta < 0 && delta_x_ > 0) ||
(old_delta > 0 && delta_x_ < 0)) {
slider_.reset();
shadow_.reset();
}
float translate = 0.f;
ui::Layer* translate_layer = NULL;
if (!slider_.get()) {
slider_.reset(delta_x_ < 0 ? delegate_->CreateFrontLayer() :
delegate_->CreateBackLayer());
if (!slider_.get())
return;
SetupSliderLayer();
}
if (delta_x_ <= -active_start_threshold_) {
translate = owner_->bounds().width() +
std::max(delta_x_ + active_start_threshold_,
static_cast<float>(-owner_->bounds().width()));
translate_layer = slider_.get();
} else if (delta_x_ >= active_start_threshold_) {
translate = std::min(delta_x_ - active_start_threshold_,
static_cast<float>(owner_->bounds().width()));
translate_layer = owner_->layer();
} else {
return;
}
if (!shadow_.get())
shadow_.reset(new ShadowLayerDelegate(translate_layer));
gfx::Transform transform;
transform.Translate(translate, 0);
translate_layer->SetTransform(transform);
}
void WindowSlider::CompleteOrResetSlide() {
if (!slider_.get())
return;
int width = owner_->bounds().width();
float ratio = (fabs(delta_x_) - active_start_threshold_) / width;
if (ratio < complete_threshold_) {
ResetSlide();
return;
}
ui::Layer* sliding = delta_x_ < 0 ? slider_.get() : owner_->layer();
active_animator_ = sliding->GetAnimator();
ui::ScopedLayerAnimationSettings settings(active_animator_);
settings.SetPreemptionStrategy(
ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
settings.SetTweenType(gfx::Tween::EASE_OUT);
settings.AddObserver(new CallbackAnimationObserver(
base::Bind(&WindowSlider::SlideAnimationCompleted,
weak_factory_.GetWeakPtr(),
base::Passed(&slider_),
base::Passed(&shadow_))));
gfx::Transform transform;
transform.Translate(delta_x_ < 0 ? 0 : width, 0);
delta_x_ = 0;
delegate_->OnWindowSlideCompleting();
sliding->SetTransform(transform);
}
void WindowSlider::CompleteActiveAnimations() {
if (active_animator_)
active_animator_->StopAnimating();
}
void WindowSlider::ResetSlide() {
if (!slider_.get())
return;
// Reset the state of the sliding layer.
if (slider_.get()) {
ui::Layer* translate_layer;
gfx::Transform transform;
if (delta_x_ < 0) {
translate_layer = slider_.get();
transform.Translate(translate_layer->bounds().width(), 0);
} else {
translate_layer = owner_->layer();
}
active_animator_ = translate_layer->GetAnimator();
ui::ScopedLayerAnimationSettings settings(active_animator_);
settings.SetPreemptionStrategy(
ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
settings.SetTweenType(gfx::Tween::EASE_OUT);
settings.AddObserver(new CallbackAnimationObserver(
base::Bind(&WindowSlider::ResetSlideAnimationCompleted,
weak_factory_.GetWeakPtr(),
base::Passed(&slider_),
base::Passed(&shadow_))));
translate_layer->SetTransform(transform);
}
delta_x_ = 0.f;
}
void WindowSlider::SlideAnimationCompleted(
scoped_ptr<ui::Layer> layer, scoped_ptr<ShadowLayerDelegate> shadow) {
active_animator_ = NULL;
shadow.reset();
delegate_->OnWindowSlideCompleted(layer.Pass());
}
void WindowSlider::ResetSlideAnimationCompleted(
scoped_ptr<ui::Layer> layer, scoped_ptr<ShadowLayerDelegate> shadow) {
active_animator_ = NULL;
shadow.reset();
layer.reset();
delegate_->OnWindowSlideAborted();
}
void WindowSlider::OnKeyEvent(ui::KeyEvent* event) {
ResetSlide();
}
void WindowSlider::OnMouseEvent(ui::MouseEvent* event) {
if (!(event->flags() & ui::EF_IS_SYNTHESIZED))
ResetSlide();
}
void WindowSlider::OnScrollEvent(ui::ScrollEvent* event) {
active_start_threshold_ = start_threshold_touchpad_;
if (event->type() == ui::ET_SCROLL)
UpdateForScroll(event->x_offset_ordinal(), event->y_offset_ordinal());
else if (event->type() == ui::ET_SCROLL_FLING_START)
CompleteOrResetSlide();
else
ResetSlide();
event->SetHandled();
}
void WindowSlider::OnGestureEvent(ui::GestureEvent* event) {
active_start_threshold_ = start_threshold_touchscreen_;
const ui::GestureEventDetails& details = event->details();
switch (event->type()) {
case ui::ET_GESTURE_SCROLL_BEGIN:
CompleteActiveAnimations();
break;
case ui::ET_GESTURE_SCROLL_UPDATE:
UpdateForScroll(details.scroll_x(), details.scroll_y());
break;
case ui::ET_GESTURE_SCROLL_END:
CompleteOrResetSlide();
break;
case ui::ET_SCROLL_FLING_START:
CompleteOrResetSlide();
break;
case ui::ET_GESTURE_PINCH_BEGIN:
case ui::ET_GESTURE_PINCH_UPDATE:
case ui::ET_GESTURE_PINCH_END:
ResetSlide();
break;
default:
break;
}
event->SetHandled();
}
void WindowSlider::OnWindowRemovingFromRootWindow(aura::Window* window,
aura::Window* new_root) {
if (window == event_window_) {
window->RemoveObserver(this);
window->RemovePreTargetHandler(this);
event_window_ = NULL;
} else if (window == owner_) {
window->RemoveObserver(this);
owner_ = NULL;
delete this;
} else {
NOTREACHED();
}
}
} // namespace content
// Copyright (c) 2013 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.
#ifndef CONTENT_BROWSER_WEB_CONTENTS_AURA_WINDOW_SLIDER_H_
#define CONTENT_BROWSER_WEB_CONTENTS_AURA_WINDOW_SLIDER_H_
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "content/common/content_export.h"
#include "ui/aura/window_observer.h"
#include "ui/compositor/layer_animator.h"
#include "ui/events/event_handler.h"
namespace ui {
class Layer;
}
namespace content {
class ShadowLayerDelegate;
// A class for sliding the layer in a Window on top of other layers.
class CONTENT_EXPORT WindowSlider : public ui::EventHandler,
public aura::WindowObserver {
public:
class CONTENT_EXPORT Delegate {
public:
virtual ~Delegate() {}
// Creates a layer to show behind the window-layer. Called when the
// window-layer starts sliding out to reveal the layer underneath.
// The WindowSlider takes ownership of the created layer.
virtual ui::Layer* CreateBackLayer() = 0;
// Creates a layer to show on top of the window-layer. Called when the new
// layer needs to start sliding in on top of the window-layer.
// The WindowSlider takes ownership of the created layer.
virtual ui::Layer* CreateFrontLayer() = 0;
// Called when the slide is aborted. Note that when the slide is aborted,
// the WindowSlider resets any transform it applied on the window-layer.
virtual void OnWindowSlideAborted() = 0;
// Called when the slide is about to be complete. The delegate can take
// action with the assumption that slide will complete soon (within the
// duration of the final transition animation effect).
// This callback is always preceeded by CreateBackLayer() or by
// CreateFrontLayer() callback, and is guaranteed to be followed by the
// OnWindowSlideCompleted() callback.
virtual void OnWindowSlideCompleting() = 0;
// Called when the window slide completes. Note that at the end the
// window-layer may have been transformed. The callback here should reset
// the transform if necessary. |layer| is the slider's layer (previously
// created via CreateBackLayer() or CreateFrontLayer()).
virtual void OnWindowSlideCompleted(scoped_ptr<ui::Layer> layer) = 0;
// Called when the slider is destroyed.
virtual void OnWindowSliderDestroyed() = 0;
};
// The WindowSlider slides the layers in the |owner| window. It starts
// intercepting scroll events on |event_window|, and uses those events to
// control the layer-slide. The lifetime of the slider is managed by the
// lifetime of |owner|, i.e. if |owner| is destroyed, then the slider also
// destroys itself.
WindowSlider(Delegate* delegate,
aura::Window* event_window,
aura::Window* owner);
~WindowSlider() override;
// Changes the owner of the slider.
void ChangeOwner(aura::Window* new_owner);
bool IsSlideInProgress() const;
private:
// Sets up the slider layer correctly (sets the correct bounds of the layer,
// parents it to the right layer, and sets up the correct stacking order).
void SetupSliderLayer();
void UpdateForScroll(float x_offset, float y_offset);
// Completes or resets the slide depending on whether the sliding layer
// passed the "complete slide threshold".
void CompleteOrResetSlide();
// Stops all slider-owned animations, progressing them to their end-points.
// Note that depending on the sate of the Delegate and the WindowSlider, this
// may destroy the WindowSlider through animation callbacks.
void CompleteActiveAnimations();
// Resets in-progress slide if any, and starts the animation of the slidden
// window to its original position.
void ResetSlide();
// The following callbacks are triggered after an animation.
void SlideAnimationCompleted(scoped_ptr<ui::Layer> layer,
scoped_ptr<ShadowLayerDelegate> shadow);
void ResetSlideAnimationCompleted(scoped_ptr<ui::Layer> layer,
scoped_ptr<ShadowLayerDelegate> shadow);
// Overridden from ui::EventHandler:
void OnKeyEvent(ui::KeyEvent* event) override;
void OnMouseEvent(ui::MouseEvent* event) override;
void OnScrollEvent(ui::ScrollEvent* event) override;
void OnGestureEvent(ui::GestureEvent* event) override;
// Overridden from aura::WindowObserver:
void OnWindowRemovingFromRootWindow(aura::Window* window,
aura::Window* new_root) override;
Delegate* delegate_;
// The slider intercepts scroll events from this window. The slider does not
// own |event_window_|. If |event_window_| is destroyed, then the slider stops
// listening for events, but it doesn't destroy itself.
aura::Window* event_window_;
// The window the slider operates on. The lifetime of the slider is bound to
// this window (i.e. if |owner_| does, the slider destroys itself). The slider
// can also delete itself when a slide gesture is completed. This does not
// destroy |owner_|.
aura::Window* owner_;
// Set to the Animator of the currently active animation. If no animation is
// active, this is set to NULL.
ui::LayerAnimator* active_animator_;
// The accumulated amount of horizontal scroll.
float delta_x_;
// This keeps track of the layer created by the delegate.
scoped_ptr<ui::Layer> slider_;
// This manages the shadow for the layers.
scoped_ptr<ShadowLayerDelegate> shadow_;
float active_start_threshold_;
const float start_threshold_touchscreen_;
const float start_threshold_touchpad_;
const float complete_threshold_;
base::WeakPtrFactory<WindowSlider> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(WindowSlider);
};
} // namespace content
#endif // CONTENT_BROWSER_WEB_CONTENTS_AURA_WINDOW_SLIDER_H_
......@@ -15,7 +15,6 @@
#include "content/common/content_export.h"
#include "ui/aura/window_delegate.h"
#include "ui/aura/window_observer.h"
#include "ui/compositor/layer_animation_observer.h"
#include "ui/wm/public/drag_drop_delegate.h"
namespace aura {
......@@ -41,7 +40,6 @@ class WebContentsViewAura
: public WebContentsView,
public RenderViewHostDelegateView,
public OverscrollControllerDelegate,
public ui::ImplicitAnimationObserver,
public aura::WindowDelegate,
public aura::client::DragDropDelegate,
public aura::WindowObserver {
......@@ -63,41 +61,15 @@ class WebContentsViewAura
void InstallOverscrollControllerDelegate(RenderWidgetHostViewAura* view);
// Creates and sets up the overlay window that will be displayed during the
// overscroll gesture.
void PrepareOverscrollWindow();
// Sets up the content window in preparation for starting an overscroll
// gesture.
void PrepareContentWindowForOverscroll();
// Resets any in-progress animation for the overscroll gesture. Note that this
// doesn't immediately reset the internal states; that happens after an
// animation.
void ResetOverscrollTransform();
// Completes the navigation in response to a completed overscroll gesture.
// The navigation happens after an animation (either the overlay window
// animates in, or the content window animates out).
void CompleteOverscrollNavigation(OverscrollMode mode);
// Returns the window that should be animated for the overscroll gesture.
// (note that during the overscroll gesture, either the overlay window or the
// content window can be animated).
aura::Window* GetWindowToAnimateForOverscroll();
// Returns the amount the animating window should be translated in response to
// the overscroll gesture.
gfx::Vector2dF GetTranslationForOverscroll(float delta_x, float delta_y);
// A window showing the screenshot is overlayed during a navigation triggered
// by overscroll. This function sets this up.
void PrepareOverscrollNavigationOverlay();
// Changes the brightness of the layer depending on the amount of horizontal
// overscroll (|delta_x|, in pixels).
void UpdateOverscrollWindowBrightness(float delta_x);
void AttachTouchEditableToRenderView();
void OverscrollUpdateForWebContentsDelegate(float delta_y);
......@@ -151,9 +123,6 @@ class WebContentsViewAura
void OnOverscrollModeChange(OverscrollMode old_mode,
OverscrollMode new_mode) override;
// Overridden from ui::ImplicitAnimationObserver:
void OnImplicitAnimationsCompleted() override;
// Overridden from aura::WindowDelegate:
gfx::Size GetMinimumSize() const override;
gfx::Size GetMaximumSize() const override;
......@@ -193,10 +162,6 @@ class WebContentsViewAura
scoped_ptr<aura::Window> window_;
// The window that shows the screenshot of the history page during an
// overscroll navigation gesture.
scoped_ptr<aura::Window> overscroll_window_;
scoped_ptr<WindowObserver> window_observer_;
// The WebContentsImpl whose contents we display.
......@@ -216,8 +181,6 @@ class WebContentsViewAura
// pointers.
void* current_rvh_for_drag_;
bool overscroll_change_brightness_;
// The overscroll gesture currently in progress.
OverscrollMode current_overscroll_gesture_;
......@@ -229,8 +192,6 @@ class WebContentsViewAura
// navigation triggered by the overscroll gesture.
scoped_ptr<OverscrollNavigationOverlay> navigation_overlay_;
scoped_ptr<ShadowLayerDelegate> overscroll_shadow_;
scoped_ptr<TouchEditableImplAura> touch_editable_;
scoped_ptr<GestureNavSimple> gesture_nav_simple_;
......
......@@ -1451,10 +1451,12 @@
'browser/web_contents/aura/gesture_nav_simple.h',
'browser/web_contents/aura/overscroll_navigation_overlay.cc',
'browser/web_contents/aura/overscroll_navigation_overlay.h',
'browser/web_contents/aura/overscroll_window_animation.cc',
'browser/web_contents/aura/overscroll_window_animation.h',
'browser/web_contents/aura/overscroll_window_delegate.cc',
'browser/web_contents/aura/overscroll_window_delegate.h',
'browser/web_contents/aura/shadow_layer_delegate.cc',
'browser/web_contents/aura/shadow_layer_delegate.h',
'browser/web_contents/aura/window_slider.cc',
'browser/web_contents/aura/window_slider.h',
'browser/web_contents/touch_editable_impl_aura.cc',
'browser/web_contents/touch_editable_impl_aura.h',
'browser/web_contents/web_contents_android.cc',
......
......@@ -563,7 +563,8 @@
'browser/system_message_window_win_unittest.cc',
'browser/transition_request_manager_unittest.cc',
'browser/web_contents/aura/overscroll_navigation_overlay_unittest.cc',
'browser/web_contents/aura/window_slider_unittest.cc',
'browser/web_contents/aura/overscroll_window_animation_unittest.cc',
'browser/web_contents/aura/overscroll_window_delegate_unittest.cc',
'browser/web_contents/web_contents_delegate_unittest.cc',
'browser/web_contents/web_contents_impl_unittest.cc',
'browser/web_contents/web_contents_user_data_unittest.cc',
......
......@@ -600,7 +600,8 @@ if (!is_mac) { # TODO(GYP) enable on Mac once it links.
"../browser/renderer_host/render_widget_host_view_aura_unittest.cc",
"../browser/renderer_host/web_input_event_aura_unittest.cc",
"../browser/web_contents/aura/overscroll_navigation_overlay_unittest.cc",
"../browser/web_contents/aura/window_slider_unittest.cc",
"../browser/web_contents/aura/overscroll_window_animation_unittest.cc",
"../browser/web_contents/aura/overscroll_window_delegate_unittest.cc",
]
}
if (use_aura || toolkit_views) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment