Commit 407b5a14 authored by sadrul@chromium.org's avatar sadrul@chromium.org

aura: Use the WindowSlider for gesture-nav while the page is reloading.

Allow navigating through history at the end of a gesture-nav, while
the page is still reloading from the previous gesture nav.

BUG=196607
R=sky@chromium.org

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@207959 0039d316-1c4b-4281-b951-d872f2087c98
parent 39cdd0c4
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include "content/browser/web_contents/aura/window_slider.h" #include "content/browser/web_contents/aura/window_slider.h"
#include <algorithm>
#include "base/bind.h" #include "base/bind.h"
#include "base/callback.h" #include "base/callback.h"
#include "content/browser/web_contents/aura/shadow_layer_delegate.h" #include "content/browser/web_contents/aura/shadow_layer_delegate.h"
...@@ -67,13 +69,13 @@ WindowSlider::WindowSlider(Delegate* delegate, ...@@ -67,13 +69,13 @@ WindowSlider::WindowSlider(Delegate* delegate,
} }
WindowSlider::~WindowSlider() { WindowSlider::~WindowSlider() {
delegate_->OnWindowSliderDestroyed();
if (event_window_) { if (event_window_) {
event_window_->RemovePreTargetHandler(this); event_window_->RemovePreTargetHandler(this);
event_window_->RemoveObserver(this); event_window_->RemoveObserver(this);
} }
if (owner_) if (owner_)
owner_->RemoveObserver(this); owner_->RemoveObserver(this);
delegate_->OnWindowSliderDestroyed();
} }
void WindowSlider::ChangeOwner(aura::Window* new_owner) { void WindowSlider::ChangeOwner(aura::Window* new_owner) {
...@@ -86,6 +88,11 @@ void WindowSlider::ChangeOwner(aura::Window* new_owner) { ...@@ -86,6 +88,11 @@ void WindowSlider::ChangeOwner(aura::Window* new_owner) {
} }
} }
bool WindowSlider::IsSlideInProgress() const {
return fabs(delta_x_) >= min_start_threshold_ || slider_.get() ||
weak_factory_.HasWeakPtrs();
}
void WindowSlider::SetupSliderLayer() { void WindowSlider::SetupSliderLayer() {
ui::Layer* parent = owner_->layer()->parent(); ui::Layer* parent = owner_->layer()->parent();
parent->Add(slider_.get()); parent->Add(slider_.get());
...@@ -100,10 +107,8 @@ void WindowSlider::SetupSliderLayer() { ...@@ -100,10 +107,8 @@ void WindowSlider::SetupSliderLayer() {
void WindowSlider::UpdateForScroll(float x_offset, float y_offset) { void WindowSlider::UpdateForScroll(float x_offset, float y_offset) {
float old_delta = delta_x_; float old_delta = delta_x_;
delta_x_ += x_offset; delta_x_ += x_offset;
if (fabs(delta_x_) < min_start_threshold_) { if (fabs(delta_x_) < min_start_threshold_ && !slider_.get())
ResetScroll();
return; return;
}
if ((old_delta < 0 && delta_x_ > 0) || if ((old_delta < 0 && delta_x_ > 0) ||
(old_delta > 0 && delta_x_ < 0)) { (old_delta > 0 && delta_x_ < 0)) {
...@@ -117,17 +122,23 @@ void WindowSlider::UpdateForScroll(float x_offset, float y_offset) { ...@@ -117,17 +122,23 @@ void WindowSlider::UpdateForScroll(float x_offset, float y_offset) {
if (delta_x_ <= -min_start_threshold_) { if (delta_x_ <= -min_start_threshold_) {
if (!slider_.get()) { if (!slider_.get()) {
slider_.reset(delegate_->CreateFrontLayer()); slider_.reset(delegate_->CreateFrontLayer());
if (!slider_.get())
return;
SetupSliderLayer(); SetupSliderLayer();
} }
translate = event_window_->bounds().width() - translate = owner_->bounds().width() +
fabs(delta_x_ - min_start_threshold_); std::max(delta_x_ + min_start_threshold_,
static_cast<float>(-owner_->bounds().width()));
translate_layer = slider_.get(); translate_layer = slider_.get();
} else if (delta_x_ >= min_start_threshold_) { } else if (delta_x_ >= min_start_threshold_) {
if (!slider_.get()) { if (!slider_.get()) {
slider_.reset(delegate_->CreateBackLayer()); slider_.reset(delegate_->CreateBackLayer());
if (!slider_.get())
return;
SetupSliderLayer(); SetupSliderLayer();
} }
translate = delta_x_ - min_start_threshold_; translate = std::min(delta_x_ - min_start_threshold_,
static_cast<float>(owner_->bounds().width()));
translate_layer = owner_->layer(); translate_layer = owner_->layer();
} else { } else {
NOTREACHED(); NOTREACHED();
...@@ -142,7 +153,7 @@ void WindowSlider::UpdateForScroll(float x_offset, float y_offset) { ...@@ -142,7 +153,7 @@ void WindowSlider::UpdateForScroll(float x_offset, float y_offset) {
} }
void WindowSlider::UpdateForFling(float x_velocity, float y_velocity) { void WindowSlider::UpdateForFling(float x_velocity, float y_velocity) {
if (fabs(delta_x_) < min_start_threshold_) if (!slider_.get())
return; return;
int width = owner_->bounds().width(); int width = owner_->bounds().width();
...@@ -214,6 +225,14 @@ void WindowSlider::CancelScroll() { ...@@ -214,6 +225,14 @@ void WindowSlider::CancelScroll() {
} }
void WindowSlider::CompleteWindowSlideAfterAnimation() { void WindowSlider::CompleteWindowSlideAfterAnimation() {
// The delegate may delete the |owner_| from the |OnWindowSlideComplete()|
// callback, which would trigger the
// |WindowSlider::OnWindowRemovingFromRootWindow()| callback, which would try
// to delete itself again. So avoid that by resetting |owner_| before calling
// the |OnWindowSlideComplete()| callback on the delegate.
owner_->RemoveObserver(this);
owner_ = NULL;
delegate_->OnWindowSlideComplete(); delegate_->OnWindowSlideComplete();
delete this; delete this;
} }
...@@ -281,8 +300,7 @@ void WindowSlider::OnWindowRemovingFromRootWindow(aura::Window* window) { ...@@ -281,8 +300,7 @@ void WindowSlider::OnWindowRemovingFromRootWindow(aura::Window* window) {
} else if (window == owner_) { } else if (window == owner_) {
window->RemoveObserver(this); window->RemoveObserver(this);
owner_ = NULL; owner_ = NULL;
if (!slider_.get()) delete this;
delete this;
} else { } else {
NOTREACHED(); NOTREACHED();
} }
......
...@@ -65,6 +65,8 @@ class CONTENT_EXPORT WindowSlider : public ui::EventHandler, ...@@ -65,6 +65,8 @@ class CONTENT_EXPORT WindowSlider : public ui::EventHandler,
// Changes the owner of the slider. // Changes the owner of the slider.
void ChangeOwner(aura::Window* new_owner); void ChangeOwner(aura::Window* new_owner);
bool IsSlideInProgress() const;
private: private:
// Sets up the slider layer correctly (sets the correct bounds of the layer, // 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). // parents it to the right layer, and sets up the correct stacking order).
......
...@@ -60,7 +60,8 @@ class NoEventWindowDelegate : public aura::test::TestWindowDelegate { ...@@ -60,7 +60,8 @@ class NoEventWindowDelegate : public aura::test::TestWindowDelegate {
class WindowSliderDelegateTest : public WindowSlider::Delegate { class WindowSliderDelegateTest : public WindowSlider::Delegate {
public: public:
WindowSliderDelegateTest() WindowSliderDelegateTest()
: created_back_layer_(false), : can_create_layer_(true),
created_back_layer_(false),
created_front_layer_(false), created_front_layer_(false),
slide_completed_(false), slide_completed_(false),
slide_aborted_(false), slide_aborted_(false),
...@@ -69,6 +70,7 @@ class WindowSliderDelegateTest : public WindowSlider::Delegate { ...@@ -69,6 +70,7 @@ class WindowSliderDelegateTest : public WindowSlider::Delegate {
virtual ~WindowSliderDelegateTest() {} virtual ~WindowSliderDelegateTest() {}
void Reset() { void Reset() {
can_create_layer_ = true;
created_back_layer_ = false; created_back_layer_ = false;
created_front_layer_ = false; created_front_layer_ = false;
slide_completed_ = false; slide_completed_ = false;
...@@ -76,14 +78,19 @@ class WindowSliderDelegateTest : public WindowSlider::Delegate { ...@@ -76,14 +78,19 @@ class WindowSliderDelegateTest : public WindowSlider::Delegate {
slider_destroyed_ = false; slider_destroyed_ = false;
} }
void SetCanCreateLayer(bool can_create_layer) {
can_create_layer_ = can_create_layer;
}
bool created_back_layer() const { return created_back_layer_; } bool created_back_layer() const { return created_back_layer_; }
bool created_front_layer() const { return created_front_layer_; } bool created_front_layer() const { return created_front_layer_; }
bool slide_completed() const { return slide_completed_; } bool slide_completed() const { return slide_completed_; }
bool slide_aborted() const { return slide_aborted_; } bool slide_aborted() const { return slide_aborted_; }
bool slider_destroyed() const { return slider_destroyed_; } bool slider_destroyed() const { return slider_destroyed_; }
private: protected:
ui::Layer* CreateLayerForTest() { ui::Layer* CreateLayerForTest() {
CHECK(can_create_layer_);
ui::Layer* layer = new ui::Layer(ui::LAYER_SOLID_COLOR); ui::Layer* layer = new ui::Layer(ui::LAYER_SOLID_COLOR);
layer->SetColor(SK_ColorRED); layer->SetColor(SK_ColorRED);
return layer; return layer;
...@@ -91,11 +98,15 @@ class WindowSliderDelegateTest : public WindowSlider::Delegate { ...@@ -91,11 +98,15 @@ class WindowSliderDelegateTest : public WindowSlider::Delegate {
// Overridden from WindowSlider::Delegate: // Overridden from WindowSlider::Delegate:
virtual ui::Layer* CreateBackLayer() OVERRIDE { virtual ui::Layer* CreateBackLayer() OVERRIDE {
if (!can_create_layer_)
return NULL;
created_back_layer_ = true; created_back_layer_ = true;
return CreateLayerForTest(); return CreateLayerForTest();
} }
virtual ui::Layer* CreateFrontLayer() OVERRIDE { virtual ui::Layer* CreateFrontLayer() OVERRIDE {
if (!can_create_layer_)
return NULL;
created_front_layer_ = true; created_front_layer_ = true;
return CreateLayerForTest(); return CreateLayerForTest();
} }
...@@ -112,6 +123,8 @@ class WindowSliderDelegateTest : public WindowSlider::Delegate { ...@@ -112,6 +123,8 @@ class WindowSliderDelegateTest : public WindowSlider::Delegate {
slider_destroyed_ = true; slider_destroyed_ = true;
} }
private:
bool can_create_layer_;
bool created_back_layer_; bool created_back_layer_;
bool created_front_layer_; bool created_front_layer_;
bool slide_completed_; bool slide_completed_;
...@@ -121,6 +134,44 @@ class WindowSliderDelegateTest : public WindowSlider::Delegate { ...@@ -121,6 +134,44 @@ class WindowSliderDelegateTest : public WindowSlider::Delegate {
DISALLOW_COPY_AND_ASSIGN(WindowSliderDelegateTest); DISALLOW_COPY_AND_ASSIGN(WindowSliderDelegateTest);
}; };
// This delegate destroys the owner window when the slider is destroyed.
class WindowSliderDeleteOwnerOnDestroy : public WindowSliderDelegateTest {
public:
explicit WindowSliderDeleteOwnerOnDestroy(aura::Window* owner)
: owner_(owner) {
}
virtual ~WindowSliderDeleteOwnerOnDestroy() {}
private:
// Overridden from WindowSlider::Delegate:
virtual void OnWindowSliderDestroyed() OVERRIDE {
WindowSliderDelegateTest::OnWindowSliderDestroyed();
delete owner_;
}
aura::Window* owner_;
DISALLOW_COPY_AND_ASSIGN(WindowSliderDeleteOwnerOnDestroy);
};
// This delegate destroyes the owner window when a slide is completed.
class WindowSliderDeleteOwnerOnComplete : public WindowSliderDelegateTest {
public:
explicit WindowSliderDeleteOwnerOnComplete(aura::Window* owner)
: owner_(owner) {
}
virtual ~WindowSliderDeleteOwnerOnComplete() {}
private:
// Overridden from WindowSlider::Delegate:
virtual void OnWindowSlideComplete() OVERRIDE {
WindowSliderDelegateTest::OnWindowSlideComplete();
delete owner_;
}
aura::Window* owner_;
DISALLOW_COPY_AND_ASSIGN(WindowSliderDeleteOwnerOnComplete);
};
typedef aura::test::AuraTestBase WindowSliderTest; typedef aura::test::AuraTestBase WindowSliderTest;
TEST_F(WindowSliderTest, WindowSlideUsingGesture) { TEST_F(WindowSliderTest, WindowSlideUsingGesture) {
...@@ -268,4 +319,93 @@ TEST_F(WindowSliderTest, OwnerWindowChangesDuringWindowSlide) { ...@@ -268,4 +319,93 @@ TEST_F(WindowSliderTest, OwnerWindowChangesDuringWindowSlide) {
EXPECT_TRUE(slider_delegate.slider_destroyed()); EXPECT_TRUE(slider_delegate.slider_destroyed());
} }
TEST_F(WindowSliderTest, NoSlideWhenLayerCantBeCreated) {
scoped_ptr<aura::Window> window(CreateNormalWindow(0, root_window(), NULL));
window->SetBounds(gfx::Rect(0, 0, 400, 400));
WindowSliderDelegateTest slider_delegate;
slider_delegate.SetCanCreateLayer(false);
aura::test::EventGenerator generator(root_window());
// Generate a horizontal overscroll.
new WindowSlider(&slider_delegate, root_window(), window.get());
generator.GestureScrollSequence(gfx::Point(10, 10),
gfx::Point(160, 10),
base::TimeDelta::FromMilliseconds(10),
10);
EXPECT_FALSE(slider_delegate.created_back_layer());
EXPECT_FALSE(slider_delegate.slide_completed());
EXPECT_FALSE(slider_delegate.created_front_layer());
EXPECT_FALSE(slider_delegate.slide_aborted());
EXPECT_FALSE(slider_delegate.slider_destroyed());
window->SetTransform(gfx::Transform());
slider_delegate.SetCanCreateLayer(true);
generator.GestureScrollSequence(gfx::Point(10, 10),
gfx::Point(160, 10),
base::TimeDelta::FromMilliseconds(10),
10);
EXPECT_TRUE(slider_delegate.created_back_layer());
EXPECT_TRUE(slider_delegate.slide_completed());
EXPECT_FALSE(slider_delegate.created_front_layer());
EXPECT_FALSE(slider_delegate.slide_aborted());
EXPECT_TRUE(slider_delegate.slider_destroyed());
}
// Tests that the owner window can be destroyed from |OnWindowSliderDestroyed()|
// delegate callback without causing a crash.
TEST_F(WindowSliderTest, OwnerIsDestroyedOnSliderDestroy) {
size_t child_windows = root_window()->children().size();
aura::Window* window = CreateNormalWindow(0, root_window(), NULL);
window->SetBounds(gfx::Rect(0, 0, 400, 400));
EXPECT_EQ(child_windows + 1, root_window()->children().size());
WindowSliderDeleteOwnerOnDestroy slider_delegate(window);
aura::test::EventGenerator generator(root_window());
// Generate a horizontal overscroll.
new WindowSlider(&slider_delegate, root_window(), window);
generator.GestureScrollSequence(gfx::Point(10, 10),
gfx::Point(160, 10),
base::TimeDelta::FromMilliseconds(10),
10);
EXPECT_TRUE(slider_delegate.created_back_layer());
EXPECT_TRUE(slider_delegate.slide_completed());
EXPECT_FALSE(slider_delegate.created_front_layer());
EXPECT_FALSE(slider_delegate.slide_aborted());
EXPECT_TRUE(slider_delegate.slider_destroyed());
// Destroying the slider would have destroyed |window| too. So |window| should
// not need to be destroyed here.
EXPECT_EQ(child_windows, root_window()->children().size());
}
// Tests that the owner window can be destroyed from |OnWindowSlideComplete()|
// delegate callback without causing a crash.
TEST_F(WindowSliderTest, OwnerIsDestroyedOnSlideComplete) {
size_t child_windows = root_window()->children().size();
aura::Window* window = CreateNormalWindow(0, root_window(), NULL);
window->SetBounds(gfx::Rect(0, 0, 400, 400));
EXPECT_EQ(child_windows + 1, root_window()->children().size());
WindowSliderDeleteOwnerOnComplete slider_delegate(window);
aura::test::EventGenerator generator(root_window());
// Generate a horizontal overscroll.
new WindowSlider(&slider_delegate, root_window(), window);
generator.GestureScrollSequence(gfx::Point(10, 10),
gfx::Point(160, 10),
base::TimeDelta::FromMilliseconds(10),
10);
EXPECT_TRUE(slider_delegate.created_back_layer());
EXPECT_TRUE(slider_delegate.slide_completed());
EXPECT_FALSE(slider_delegate.created_front_layer());
EXPECT_FALSE(slider_delegate.slide_aborted());
EXPECT_TRUE(slider_delegate.slider_destroyed());
// Destroying the slider would have destroyed |window| too. So |window| should
// not need to be destroyed here.
EXPECT_EQ(child_windows, root_window()->children().size());
}
} // namespace content } // namespace content
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