Commit 8bfcbd34 authored by MinChen's avatar MinChen Committed by Commit Bot

Allowing the snapped window can be moved outside of work area.

Changes:
1. Allowing the snapped window that next to the origin of the work area
   can be moved outside of the bounds of work area.
2. Delete RestackWindows in SplitViewController, since left and right
   snapped window will not overlap now.

Bug: 775236
Change-Id: Ib1d12443f8b9965544014590b8eff37ed8b3f665
Reviewed-on: https://chromium-review.googlesource.com/741489
Commit-Queue: min c <minch@chromium.org>
Reviewed-by: default avatarMitsuru Oshima <oshima@chromium.org>
Reviewed-by: default avatarXiaoqian Dai <xdai@chromium.org>
Cr-Commit-Position: refs/heads/master@{#513052}
parent 09399732
......@@ -65,6 +65,11 @@ bool IsLeftWindowOnTopOrLeftOfScreen(
blink::kWebScreenOrientationLockPortraitSecondary;
}
// Transpose the given |rect|.
void TransposeRect(gfx::Rect* rect) {
rect->SetRect(rect->y(), rect->x(), rect->height(), rect->width());
}
} // namespace
SplitViewController::SplitViewController() {
......@@ -235,6 +240,14 @@ gfx::Rect SplitViewController::GetSnappedWindowBoundsInScreen(
IsCurrentScreenOrientationLandscape(), &left_or_top_rect,
&right_or_bottom_rect);
// Only need to adjust the bounds for |left_or_top_rect| since the origin of
// the left or top snapped window's bounds is always the origin of the work
// area's bounds. It can not be moved to outside of the work area when the
// window's minimum size is larger than current acquired window bounds, which
// will lead to the divider pass over the window. This is no need for
// |right_or_bottom_rect| since its origin of the bounds is flexible.
AdjustLeftOrTopSnappedWindowBoundsDuringResizing(&left_or_top_rect);
if (IsLeftWindowOnTopOrLeftOfScreen(screen_orientation_))
return (snap_position == LEFT) ? left_or_top_rect : right_or_bottom_rect;
else
......@@ -274,13 +287,9 @@ void SplitViewController::Resize(const gfx::Point& location_in_screen) {
GetBoundedPosition(location_in_screen, work_area_bounds);
// Update |divider_position_|.
const int previous_divider_position = divider_position_;
UpdateDividerPosition(modified_location_in_screen);
NotifyDividerPositionChanged();
// Restack windows order if necessary.
RestackWindows(previous_divider_position, divider_position_);
// Update the black scrim layer's bounds and opacity.
UpdateBlackScrim(modified_location_in_screen);
......@@ -580,29 +589,6 @@ void SplitViewController::UpdateBlackScrim(
black_scrim_layer_->SetOpacity(opacity);
}
void SplitViewController::RestackWindows(const int previous_divider_position,
const int current_divider_position) {
if (!left_window_ || !right_window_)
return;
DCHECK(IsSplitViewModeActive());
DCHECK_EQ(left_window_->parent(), right_window_->parent());
const int mid_position = GetDefaultDividerPosition(GetDefaultSnappedWindow());
if (std::signbit(previous_divider_position - mid_position) ==
std::signbit(current_divider_position - mid_position)) {
// No need to restack windows if the divider position doesn't pass over the
// middle position.
return;
}
if ((current_divider_position < mid_position) ==
IsLeftWindowOnTopOrLeftOfScreen(screen_orientation_)) {
left_window_->parent()->StackChildAbove(right_window_, left_window_);
} else {
left_window_->parent()->StackChildAbove(left_window_, right_window_);
}
}
void SplitViewController::UpdateSnappedWindowsAndDividerBounds() {
DCHECK(IsSplitViewModeActive());
......@@ -776,4 +762,32 @@ void SplitViewController::OnSnappedWindowMinimizedOrDestroyed(
}
}
void SplitViewController::AdjustLeftOrTopSnappedWindowBoundsDuringResizing(
gfx::Rect* left_or_top_rect) {
if (!is_resizing_)
return;
aura::Window* left_or_top_window =
IsLeftWindowOnTopOrLeftOfScreen(screen_orientation_) ? left_window_
: right_window_;
bool is_landscape = IsCurrentScreenOrientationLandscape();
int minimum_width = 0;
if (left_or_top_window && left_or_top_window->delegate()) {
gfx::Size minimum_size = left_or_top_window->delegate()->GetMinimumSize();
minimum_width = is_landscape ? minimum_size.width() : minimum_size.height();
}
if (!is_landscape)
TransposeRect(left_or_top_rect);
if (left_or_top_rect->width() < minimum_width) {
left_or_top_rect->set_x(left_or_top_rect->x() -
(minimum_width - left_or_top_rect->width()));
left_or_top_rect->set_width(minimum_width);
}
if (!is_landscape)
TransposeRect(left_or_top_rect);
}
} // namespace ash
......@@ -164,14 +164,6 @@ class ASH_EXPORT SplitViewController : public aura::WindowObserver,
// of the screen.
void UpdateBlackScrim(const gfx::Point& location_in_screen);
// Restacks the two snapped windows while dragging the divider. If the divider
// was in the left side of the screen, stack |right_window_| above
// |left_window_|, otherwise, stack |left_window_| above |right_window_|. It's
// necessary since we want the top window increasingly cover the entire
// screen as the divider gets closer to the edge of the screen.
void RestackWindows(const int previous_divider_position,
const int current_divider_position);
// Updates the bounds for the snapped windows and divider according to the
// current snap direction.
void UpdateSnappedWindowsAndDividerBounds();
......@@ -215,6 +207,14 @@ class ASH_EXPORT SplitViewController : public aura::WindowObserver,
// overview mode is active at that moment.
void OnSnappedWindowMinimizedOrDestroyed(aura::Window* window);
// Adjust the bounds of the left or top snapped window during resizing when
// its minimum size is larger than current window bounds to make sure it can
// be moved outside of the work area in this case. Note, no need to adjust
// when it is not during resizing since the window will not be snapped to a
// position that smaller than its minimum size.
void AdjustLeftOrTopSnappedWindowBoundsDuringResizing(
gfx::Rect* left_or_top_rect);
// The current left/right snapped window.
aura::Window* left_window_ = nullptr;
aura::Window* right_window_ = nullptr;
......
......@@ -837,4 +837,126 @@ TEST_F(SplitViewControllerTest, SnapWindowWithMinimumSizeTest) {
EXPECT_FALSE(split_view_controller()->CanSnap(window1.get()));
}
// Tests that the left or top snapped window can be moved outside of work area
// when its minimum size is larger than its current bounds.
TEST_F(SplitViewControllerTest, SnapWindowBoundsWithMinimumSizeTest) {
int64_t display_id = display::Screen::GetScreen()->GetPrimaryDisplay().id();
display::DisplayManager* display_manager = Shell::Get()->display_manager();
display::test::ScopedSetInternalDisplayId set_internal(display_manager,
display_id);
ScreenOrientationControllerTestApi test_api(
Shell::Get()->screen_orientation_controller());
const gfx::Rect bounds(0, 0, 300, 200);
std::unique_ptr<aura::Window> window1(CreateWindow(bounds));
aura::test::TestWindowDelegate* delegate1 =
static_cast<aura::test::TestWindowDelegate*>(window1->delegate());
// Set the screen orientation to LANDSCAPE_PRIMARY
test_api.SetDisplayRotation(display::Display::ROTATE_0,
display::Display::ROTATION_SOURCE_ACTIVE);
EXPECT_EQ(test_api.GetCurrentOrientation(),
blink::kWebScreenOrientationLockLandscapePrimary);
gfx::Rect display_bounds =
split_view_controller()->GetDisplayWorkAreaBoundsInScreen(window1.get());
EXPECT_TRUE(split_view_controller()->CanSnap(window1.get()));
split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT);
delegate1->set_minimum_size(
gfx::Size(display_bounds.width() * 0.4f, display_bounds.height()));
gfx::Rect divider_bounds =
split_view_divider()->GetDividerBoundsInScreen(false);
split_view_controller()->StartResize(divider_bounds.CenterPoint());
gfx::Point resize_point(display_bounds.width() * 0.33f, 0);
split_view_controller()->Resize(resize_point);
gfx::Rect snapped_window_bounds =
split_view_controller()->GetSnappedWindowBoundsInScreen(
window1.get(), SplitViewController::LEFT);
EXPECT_LT(snapped_window_bounds.x(), display_bounds.x());
EXPECT_EQ(snapped_window_bounds.width(),
window1->delegate()->GetMinimumSize().width());
EndSplitView();
// Rotate the screen by 90 degree.
test_api.SetDisplayRotation(display::Display::ROTATE_90,
display::Display::ROTATION_SOURCE_ACTIVE);
EXPECT_EQ(test_api.GetCurrentOrientation(),
blink::kWebScreenOrientationLockPortraitPrimary);
display_bounds =
split_view_controller()->GetDisplayWorkAreaBoundsInScreen(window1.get());
delegate1->set_minimum_size(
gfx::Size(display_bounds.width(), display_bounds.height() * 0.4f));
EXPECT_TRUE(split_view_controller()->CanSnap(window1.get()));
split_view_controller()->SnapWindow(window1.get(),
SplitViewController::RIGHT);
divider_bounds = split_view_divider()->GetDividerBoundsInScreen(false);
split_view_controller()->StartResize(divider_bounds.CenterPoint());
resize_point.SetPoint(0, display_bounds.height() * 0.33f);
split_view_controller()->Resize(resize_point);
snapped_window_bounds =
split_view_controller()->GetSnappedWindowBoundsInScreen(
window1.get(), SplitViewController::RIGHT);
EXPECT_LT(snapped_window_bounds.y(), display_bounds.y());
EXPECT_EQ(snapped_window_bounds.height(),
window1->delegate()->GetMinimumSize().height());
EndSplitView();
// Rotate the screen by 180 degree.
test_api.SetDisplayRotation(display::Display::ROTATE_180,
display::Display::ROTATION_SOURCE_ACTIVE);
EXPECT_EQ(test_api.GetCurrentOrientation(),
blink::kWebScreenOrientationLockLandscapeSecondary);
display_bounds =
split_view_controller()->GetDisplayWorkAreaBoundsInScreen(window1.get());
delegate1->set_minimum_size(
gfx::Size(display_bounds.width() * 0.4f, display_bounds.height()));
EXPECT_TRUE(split_view_controller()->CanSnap(window1.get()));
split_view_controller()->SnapWindow(window1.get(),
SplitViewController::RIGHT);
divider_bounds = split_view_divider()->GetDividerBoundsInScreen(false);
split_view_controller()->StartResize(divider_bounds.CenterPoint());
resize_point.SetPoint(display_bounds.width() * 0.33f, 0);
split_view_controller()->Resize(resize_point);
snapped_window_bounds =
split_view_controller()->GetSnappedWindowBoundsInScreen(
window1.get(), SplitViewController::RIGHT);
EXPECT_LT(snapped_window_bounds.x(), display_bounds.x());
EXPECT_EQ(snapped_window_bounds.width(),
window1->delegate()->GetMinimumSize().width());
EndSplitView();
// Rotate the screen by 270 degree.
test_api.SetDisplayRotation(display::Display::ROTATE_270,
display::Display::ROTATION_SOURCE_ACTIVE);
EXPECT_EQ(test_api.GetCurrentOrientation(),
blink::kWebScreenOrientationLockPortraitSecondary);
display_bounds =
split_view_controller()->GetDisplayWorkAreaBoundsInScreen(window1.get());
delegate1->set_minimum_size(
gfx::Size(display_bounds.width(), display_bounds.height() * 0.4f));
EXPECT_TRUE(split_view_controller()->CanSnap(window1.get()));
split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT);
divider_bounds = split_view_divider()->GetDividerBoundsInScreen(false);
split_view_controller()->StartResize(divider_bounds.CenterPoint());
resize_point.SetPoint(0, display_bounds.height() * 0.33f);
split_view_controller()->Resize(resize_point);
snapped_window_bounds =
split_view_controller()->GetSnappedWindowBoundsInScreen(
window1.get(), SplitViewController::LEFT);
EXPECT_LT(snapped_window_bounds.y(), display_bounds.y());
EXPECT_EQ(snapped_window_bounds.height(),
window1->delegate()->GetMinimumSize().height());
EndSplitView();
}
} // namespace ash
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