Commit 96202134 authored by Min Chen's avatar Min Chen Committed by Commit Bot

Defer resetting identity transform of the drag window from top until

it has been snapped.

We did defer resetting the transform to identity of the drag window from
overview items until it has been snapped. In order to avoid the weird
transform if trying to snap an arc window.

Previous cl:
https://chromium-review.googlesource.com/c/chromium/src/+/910076

We should do the same thing if we try to snap a window through drag from
the top.
Changes in this cl,
- Do not restore the drag window's transform to identity when end window
   drag if the window should be snapped or drop into overview.

- Restore identity transform after window has been snapped. Calculate a
  starting transform for the to-be-snapped window based on its transformed
  bounds before to be snapped.

- Move the logic of GetTransformedBounds and GetTopInset to overview_util.

Bug: 872538
Change-Id: Icc2f034e0752fba4ba8ec673022e1f9306ca35b2
Reviewed-on: https://chromium-review.googlesource.com/1178385
Commit-Queue: Min Chen <minch@chromium.org>
Reviewed-by: default avatarXiaoqian Dai <xdai@chromium.org>
Reviewed-by: default avatarMitsuru Oshima <oshima@chromium.org>
Cr-Commit-Position: refs/heads/master@{#586030}
parent 9c6ba22a
...@@ -12,13 +12,16 @@ ...@@ -12,13 +12,16 @@
#include "ash/wm/overview/window_selector_controller.h" #include "ash/wm/overview/window_selector_controller.h"
#include "ash/wm/splitview/split_view_controller.h" #include "ash/wm/splitview/split_view_controller.h"
#include "ash/wm/window_state.h" #include "ash/wm/window_state.h"
#include "ash/wm/window_transient_descendant_iterator.h"
#include "third_party/skia/include/pathops/SkPathOps.h" #include "third_party/skia/include/pathops/SkPathOps.h"
#include "ui/aura/window.h" #include "ui/aura/window.h"
#include "ui/gfx/canvas.h" #include "ui/gfx/canvas.h"
#include "ui/gfx/scoped_canvas.h" #include "ui/gfx/scoped_canvas.h"
#include "ui/gfx/transform_util.h"
#include "ui/views/background.h" #include "ui/views/background.h"
#include "ui/views/view.h" #include "ui/views/view.h"
#include "ui/views/widget/widget.h" #include "ui/views/widget/widget.h"
#include "ui/wm/core/coordinate_conversion.h"
#include "ui/wm/core/window_animations.h" #include "ui/wm/core/window_animations.h"
namespace ash { namespace ash {
...@@ -217,4 +220,37 @@ std::unique_ptr<views::Widget> CreateBackgroundWidget(aura::Window* root_window, ...@@ -217,4 +220,37 @@ std::unique_ptr<views::Widget> CreateBackgroundWidget(aura::Window* root_window,
return widget; return widget;
} }
gfx::Rect GetTransformedBounds(aura::Window* transformed_window,
int top_inset) {
gfx::Rect bounds;
for (auto* window : wm::GetTransientTreeIterator(transformed_window)) {
// Ignore other window types when computing bounding box of window
// selector target item.
if (window != transformed_window &&
(window->type() != aura::client::WINDOW_TYPE_NORMAL &&
window->type() != aura::client::WINDOW_TYPE_PANEL)) {
continue;
}
gfx::RectF window_bounds(window->GetTargetBounds());
gfx::Transform new_transform =
TransformAboutPivot(gfx::Point(window_bounds.x(), window_bounds.y()),
window->layer()->GetTargetTransform());
new_transform.TransformRect(&window_bounds);
// The preview title is shown above the preview window. Hide the window
// header for apps or browser windows with no tabs (web apps) to avoid
// showing both the window header and the preview title.
if (top_inset > 0) {
gfx::RectF header_bounds(window_bounds);
header_bounds.set_height(top_inset);
new_transform.TransformRect(&header_bounds);
window_bounds.Inset(0, gfx::ToCeiledInt(header_bounds.height()), 0, 0);
}
gfx::Rect enclosing_bounds = ToEnclosingRect(window_bounds);
::wm::ConvertRectToScreen(window->parent(), &enclosing_bounds);
bounds.Union(enclosing_bounds);
}
return bounds;
}
} // namespace ash } // namespace ash
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "ash/wm/overview/overview_animation_type.h" #include "ash/wm/overview/overview_animation_type.h"
#include "third_party/skia/include/core/SkColor.h" #include "third_party/skia/include/core/SkColor.h"
#include "ui/compositor/layer_type.h" #include "ui/compositor/layer_type.h"
#include "ui/gfx/geometry/rect.h"
namespace aura { namespace aura {
class Window; class Window;
...@@ -60,6 +61,14 @@ std::unique_ptr<views::Widget> CreateBackgroundWidget(aura::Window* root_window, ...@@ -60,6 +61,14 @@ std::unique_ptr<views::Widget> CreateBackgroundWidget(aura::Window* root_window,
float initial_opacity, float initial_opacity,
aura::Window* parent, aura::Window* parent,
bool stack_on_top); bool stack_on_top);
// Calculates the bounds of the |transformed_window|. Those bounds are a union
// of all regular (normal and panel) windows in the |transformed_window|'s
// transient hierarchy. The returned Rect is in virtual screen coordinates. The
// returned bounds are adjusted to allow the original |transformed_window|'s
// header to be hidden if |top_inset| is not zero.
gfx::Rect GetTransformedBounds(aura::Window* transformed_window, int top_inset);
} // namespace ash } // namespace ash
#endif // ASH_WM_OVERVIEW_OVERVIEW_UTILS_H_ #endif // ASH_WM_OVERVIEW_OVERVIEW_UTILS_H_
...@@ -289,37 +289,7 @@ gfx::Rect ScopedTransformOverviewWindow::GetTargetBoundsInScreen() const { ...@@ -289,37 +289,7 @@ gfx::Rect ScopedTransformOverviewWindow::GetTargetBoundsInScreen() const {
} }
gfx::Rect ScopedTransformOverviewWindow::GetTransformedBounds() const { gfx::Rect ScopedTransformOverviewWindow::GetTransformedBounds() const {
const int top_inset = GetTopInset(); return ::ash::GetTransformedBounds(GetOverviewWindow(), GetTopInset());
gfx::Rect bounds;
aura::Window* overview_window = GetOverviewWindow();
for (auto* window : wm::GetTransientTreeIterator(overview_window)) {
// Ignore other window types when computing bounding box of window
// selector target item.
if (window != overview_window &&
(window->type() != aura::client::WINDOW_TYPE_NORMAL &&
window->type() != aura::client::WINDOW_TYPE_PANEL)) {
continue;
}
gfx::RectF window_bounds(window->GetTargetBounds());
gfx::Transform new_transform =
TransformAboutPivot(gfx::Point(window_bounds.x(), window_bounds.y()),
window->layer()->GetTargetTransform());
new_transform.TransformRect(&window_bounds);
// The preview title is shown above the preview window. Hide the window
// header for apps or browser windows with no tabs (web apps) to avoid
// showing both the window header and the preview title.
if (top_inset > 0) {
gfx::RectF header_bounds(window_bounds);
header_bounds.set_height(top_inset);
new_transform.TransformRect(&header_bounds);
window_bounds.Inset(0, gfx::ToCeiledInt(header_bounds.height()), 0, 0);
}
gfx::Rect enclosing_bounds = ToEnclosingRect(window_bounds);
::wm::ConvertRectToScreen(window->parent(), &enclosing_bounds);
bounds.Union(enclosing_bounds);
}
return bounds;
} }
int ScopedTransformOverviewWindow::GetTopInset() const { int ScopedTransformOverviewWindow::GetTopInset() const {
......
...@@ -102,11 +102,8 @@ class ASH_EXPORT ScopedTransformOverviewWindow ...@@ -102,11 +102,8 @@ class ASH_EXPORT ScopedTransformOverviewWindow
// Returns the original target bounds of all transformed windows. // Returns the original target bounds of all transformed windows.
gfx::Rect GetTargetBoundsInScreen() const; gfx::Rect GetTargetBoundsInScreen() const;
// Calculates the bounds of a |window_| after being transformed to the // Returns transformed bounds of the overview window. See
// selector's space. Those bounds are a union of all regular (normal and // OverviewUtil::GetTransformedBounds for more details.
// panel) windows in the |window_|'s transient hierarchy. The returned Rect is
// in virtual screen coordinates. The returned bounds are adjusted to allow
// the original |window_|'s header to be hidden.
gfx::Rect GetTransformedBounds() const; gfx::Rect GetTransformedBounds() const;
// Returns the kTopViewInset property of |window_| unless there are transient // Returns the kTopViewInset property of |window_| unless there are transient
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "ash/system/toast/toast_data.h" #include "ash/system/toast/toast_data.h"
#include "ash/system/toast/toast_manager.h" #include "ash/system/toast/toast_manager.h"
#include "ash/wm/mru_window_tracker.h" #include "ash/wm/mru_window_tracker.h"
#include "ash/wm/overview/overview_utils.h"
#include "ash/wm/overview/window_grid.h" #include "ash/wm/overview/window_grid.h"
#include "ash/wm/overview/window_selector_controller.h" #include "ash/wm/overview/window_selector_controller.h"
#include "ash/wm/overview/window_selector_item.h" #include "ash/wm/overview/window_selector_item.h"
...@@ -266,8 +267,7 @@ void SplitViewController::SnapWindow(aura::Window* window, ...@@ -266,8 +267,7 @@ void SplitViewController::SnapWindow(aura::Window* window,
DCHECK(window && CanSnap(window)); DCHECK(window && CanSnap(window));
DCHECK_NE(snap_position, NONE); DCHECK_NE(snap_position, NONE);
// Before trying to snap |window|, try to remove it from the overview window UpdateSnappingWindowTransformedBounds(window);
// grid if applicable.
RemoveWindowFromOverviewIfApplicable(window); RemoveWindowFromOverviewIfApplicable(window);
if (state_ == NO_SNAP) { if (state_ == NO_SNAP) {
...@@ -570,7 +570,7 @@ void SplitViewController::EndSplitView(EndReason end_reason) { ...@@ -570,7 +570,7 @@ void SplitViewController::EndSplitView(EndReason end_reason) {
black_scrim_layer_.reset(); black_scrim_layer_.reset();
default_snap_position_ = NONE; default_snap_position_ = NONE;
divider_position_ = -1; divider_position_ = -1;
overview_window_item_bounds_map_.clear(); snapping_window_transformed_bounds_map_.clear();
UpdateSplitViewStateAndNotifyObservers(); UpdateSplitViewStateAndNotifyObservers();
base::RecordAction(base::UserMetricsAction("SplitView_EndSplitView")); base::RecordAction(base::UserMetricsAction("SplitView_EndSplitView"));
...@@ -621,9 +621,9 @@ void SplitViewController::AddObserver(mojom::SplitViewObserverPtr observer) { ...@@ -621,9 +621,9 @@ void SplitViewController::AddObserver(mojom::SplitViewObserverPtr observer) {
void SplitViewController::OnWindowDestroyed(aura::Window* window) { void SplitViewController::OnWindowDestroyed(aura::Window* window) {
DCHECK(IsSplitViewModeActive()); DCHECK(IsSplitViewModeActive());
DCHECK(window == left_window_ || window == right_window_); DCHECK(window == left_window_ || window == right_window_);
auto iter = overview_window_item_bounds_map_.find(window); auto iter = snapping_window_transformed_bounds_map_.find(window);
if (iter != overview_window_item_bounds_map_.end()) if (iter != snapping_window_transformed_bounds_map_.end())
overview_window_item_bounds_map_.erase(iter); snapping_window_transformed_bounds_map_.erase(iter);
OnSnappedWindowDetached(window); OnSnappedWindowDetached(window);
} }
...@@ -1102,8 +1102,6 @@ int SplitViewController::GetDividerEndPosition() { ...@@ -1102,8 +1102,6 @@ int SplitViewController::GetDividerEndPosition() {
} }
void SplitViewController::OnWindowSnapped(aura::Window* window) { void SplitViewController::OnWindowSnapped(aura::Window* window) {
// Restore the window's transform if it's not identity. It means the window
// comes from the overview.
RestoreTransformIfApplicable(window); RestoreTransformIfApplicable(window);
UpdateSplitViewStateAndNotifyObservers(); UpdateSplitViewStateAndNotifyObservers();
ActivateAndStackSnappedWindow(window); ActivateAndStackSnappedWindow(window);
...@@ -1271,19 +1269,19 @@ gfx::Point SplitViewController::GetEndDragLocationInScreen( ...@@ -1271,19 +1269,19 @@ gfx::Point SplitViewController::GetEndDragLocationInScreen(
void SplitViewController::RestoreTransformIfApplicable(aura::Window* window) { void SplitViewController::RestoreTransformIfApplicable(aura::Window* window) {
DCHECK(window == left_window_ || window == right_window_); DCHECK(window == left_window_ || window == right_window_);
// If the snapped window comes from the overview window grid, calculate a good // If the transform of the window has been changed, calculate a good starting
// starting transform based on the overview window item's bounds. // transform based on its transformed bounds before to be snapped.
auto iter = overview_window_item_bounds_map_.find(window); auto iter = snapping_window_transformed_bounds_map_.find(window);
if (iter == overview_window_item_bounds_map_.end()) if (iter == snapping_window_transformed_bounds_map_.end())
return; return;
const gfx::Rect item_bounds = iter->second; const gfx::Rect item_bounds = iter->second;
overview_window_item_bounds_map_.erase(iter); snapping_window_transformed_bounds_map_.erase(iter);
// Restore the window's transform first if it's not identity. // Restore the window's transform first if it's not identity.
if (!window->layer()->GetTargetTransform().IsIdentity()) { if (!window->layer()->GetTargetTransform().IsIdentity()) {
// Calculate the starting transform based on the window's expected snapped // Calculate the starting transform based on the window's expected snapped
// bounds and its window item bounds in overview. // bounds and its transformed bounds before to be snapped.
const gfx::Rect snapped_bounds = GetSnappedWindowBoundsInScreen( const gfx::Rect snapped_bounds = GetSnappedWindowBoundsInScreen(
window, (window == left_window_) ? LEFT : RIGHT); window, (window == left_window_) ? LEFT : RIGHT);
const gfx::Transform starting_transform = const gfx::Transform starting_transform =
...@@ -1392,10 +1390,6 @@ void SplitViewController::RemoveWindowFromOverviewIfApplicable( ...@@ -1392,10 +1390,6 @@ void SplitViewController::RemoveWindowFromOverviewIfApplicable(
if (!item) if (!item)
return; return;
// Before removing |window| from overview grid, remember its current bounds
// in the overview grid.
overview_window_item_bounds_map_[window] = item->target_bounds();
// Remove it from the grid. The transform will be reset later after the // Remove it from the grid. The transform will be reset later after the
// window is snapped. Note the remaining windows in overview don't need to be // window is snapped. Note the remaining windows in overview don't need to be
// repositioned in this case as they have been positioned to the right place // repositioned in this case as they have been positioned to the right place
...@@ -1404,6 +1398,14 @@ void SplitViewController::RemoveWindowFromOverviewIfApplicable( ...@@ -1404,6 +1398,14 @@ void SplitViewController::RemoveWindowFromOverviewIfApplicable(
window_selector->RemoveWindowSelectorItem(item, /*reposition=*/false); window_selector->RemoveWindowSelectorItem(item, /*reposition=*/false);
} }
void SplitViewController::UpdateSnappingWindowTransformedBounds(
aura::Window* window) {
if (!window->layer()->GetTargetTransform().IsIdentity()) {
snapping_window_transformed_bounds_map_[window] =
GetTransformedBounds(window, /*top_inset=*/0);
}
}
void SplitViewController::InsertWindowToOverview(aura::Window* window) { void SplitViewController::InsertWindowToOverview(aura::Window* window) {
if (!window || !Shell::Get()->window_selector_controller()->IsSelecting()) if (!window || !Shell::Get()->window_selector_controller()->IsSelecting())
return; return;
......
...@@ -325,6 +325,10 @@ class ASH_EXPORT SplitViewController : public mojom::SplitViewController, ...@@ -325,6 +325,10 @@ class ASH_EXPORT SplitViewController : public mojom::SplitViewController,
// called before trying to snap the window. // called before trying to snap the window.
void RemoveWindowFromOverviewIfApplicable(aura::Window* window); void RemoveWindowFromOverviewIfApplicable(aura::Window* window);
// Updates the |snapping_window_transformed_bounds_map_| on |window|. It
// should be called before trying to snap the window.
void UpdateSnappingWindowTransformedBounds(aura::Window* window);
// Inserts |window| into overview window grid if overview mode is active. Do // Inserts |window| into overview window grid if overview mode is active. Do
// nothing if overview mode is inactive at the moment. // nothing if overview mode is inactive at the moment.
void InsertWindowToOverview(aura::Window* window); void InsertWindowToOverview(aura::Window* window);
...@@ -405,9 +409,9 @@ class ASH_EXPORT SplitViewController : public mojom::SplitViewController, ...@@ -405,9 +409,9 @@ class ASH_EXPORT SplitViewController : public mojom::SplitViewController,
// The time when splitview starts. Used for metric collection purpose. // The time when splitview starts. Used for metric collection purpose.
base::Time splitview_start_time_; base::Time splitview_start_time_;
// The map from a to-be-snapped window to its overview item's bounds if the // The map from a to-be-snapped window to its transformed bounds.
// window comes from the overview. base::flat_map<aura::Window*, gfx::Rect>
base::flat_map<aura::Window*, gfx::Rect> overview_window_item_bounds_map_; snapping_window_transformed_bounds_map_;
base::ObserverList<Observer>::Unchecked observers_; base::ObserverList<Observer>::Unchecked observers_;
mojo::InterfacePtrSet<mojom::SplitViewObserver> mojo_observers_; mojo::InterfacePtrSet<mojom::SplitViewObserver> mojo_observers_;
......
...@@ -196,11 +196,15 @@ void TabletModeWindowDragDelegate::EndWindowDrag( ...@@ -196,11 +196,15 @@ void TabletModeWindowDragDelegate::EndWindowDrag(
split_view_drag_indicators_->SetIndicatorState(IndicatorState::kNone, split_view_drag_indicators_->SetIndicatorState(IndicatorState::kNone,
location_in_screen); location_in_screen);
// If |dragged_window_|'s transform has changed during dragging, and it has const bool snapped_or_into_overview =
// not been added into overview grid, restore its transform to identity. snap_position != SplitViewController::NONE ||
(GetWindowSelector() &&
GetWindowSelector()->IsWindowInOverview(dragged_window_));
// If |dragged_window_|'s transform has changed during dragging, and it was
// not snapped into splitscreen or dropped into overview. Then restore its
// transform to identity.
if (!dragged_window_->layer()->GetTargetTransform().IsIdentity() && if (!dragged_window_->layer()->GetTargetTransform().IsIdentity() &&
(!GetWindowSelector() || !snapped_or_into_overview) {
!GetWindowSelector()->IsWindowInOverview(dragged_window_))) {
SetTransform(dragged_window_, gfx::Transform()); SetTransform(dragged_window_, gfx::Transform());
} }
......
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