Commit fa9facbf authored by Sammie Quon's avatar Sammie Quon Committed by Commit Bot

overview: Make scrolling more performant.

- Do not update scroll if the delta is too small, this matches what
  drags on overview items do.
- Pause occlusion tracker on scroll.
- When scrolling, do not call SetBounds unless the item is leaving or
  entering the view of the grid.

Tested locally with OverviewScrollTest.Basic. Not the greatest gains
when only 12 windows, but scales much better with larger number of
windows.

Presentation time:
Before 12 windows: 55ms
Before 42 windows: 180ms
After 12 windows: 53ms
After 42 windows: 88ms

Also renamed a overview_grid_pre_event_handler ->
overview_grid_event_handler as it handles regular events now.

Test: manual
Bug: 978112, 993615
Change-Id: I28bcbb8ce3291f975df9f1033961fbe176052fc0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1784349
Commit-Queue: Sammie Quon <sammiequon@chromium.org>
Reviewed-by: default avatarXiaoqian Dai <xdai@chromium.org>
Cr-Commit-Position: refs/heads/master@{#693921}
parent fb518331
......@@ -1161,8 +1161,8 @@ component("ash") {
"wm/overview/overview_delegate.h",
"wm/overview/overview_grid.cc",
"wm/overview/overview_grid.h",
"wm/overview/overview_grid_pre_event_handler.cc",
"wm/overview/overview_grid_pre_event_handler.h",
"wm/overview/overview_grid_event_handler.cc",
"wm/overview/overview_grid_event_handler.h",
"wm/overview/overview_highlight_controller.cc",
"wm/overview/overview_highlight_controller.h",
"wm/overview/overview_item.cc",
......
......@@ -30,7 +30,7 @@
#include "ash/wm/overview/overview_constants.h"
#include "ash/wm/overview/overview_controller.h"
#include "ash/wm/overview/overview_delegate.h"
#include "ash/wm/overview/overview_grid_pre_event_handler.h"
#include "ash/wm/overview/overview_grid_event_handler.h"
#include "ash/wm/overview/overview_highlight_controller.h"
#include "ash/wm/overview/overview_item.h"
#include "ash/wm/overview/overview_session.h"
......@@ -76,6 +76,13 @@ constexpr int kTabletLayoutRow = 2;
constexpr int kMinimumItemsForNewLayout = 6;
// The minimum distance that is needed to process a scroll event.
constexpr float kMinimumScrollDistanceDp = 5.f;
// Wait a while before unpausing the occlusion tracker after a scroll has
// completed as the user may start another scroll.
constexpr int kOcclusionUnpauseDurationForScrollMs = 500;
// Histogram names for overview enter/exit smoothness in clamshell,
// tablet mode and splitview.
constexpr char kOverviewEnterClamshellHistogram[] =
......@@ -402,7 +409,7 @@ OverviewGrid::~OverviewGrid() = default;
void OverviewGrid::Shutdown() {
ScreenRotationAnimator::GetForRootWindow(root_window_)->RemoveObserver(this);
Shell::Get()->wallpaper_controller()->RemoveObserver(this);
grid_pre_event_handler_.reset();
grid_event_handler_.reset();
bool has_non_cover_animating = false;
int animate_count = 0;
......@@ -445,7 +452,7 @@ void OverviewGrid::PrepareForOverview() {
ScreenRotationAnimator::GetForRootWindow(root_window_)->AddObserver(this);
}
grid_pre_event_handler_ = std::make_unique<OverviewGridPreEventHandler>(this);
grid_event_handler_ = std::make_unique<OverviewGridEventHandler>(this);
Shell::Get()->wallpaper_controller()->AddObserver(this);
}
......@@ -922,11 +929,11 @@ void OverviewGrid::OnScreenRotationAnimationFinished(
}
void OverviewGrid::OnWallpaperChanging() {
grid_pre_event_handler_.reset();
grid_event_handler_.reset();
}
void OverviewGrid::OnWallpaperChanged() {
grid_pre_event_handler_ = std::make_unique<OverviewGridPreEventHandler>(this);
grid_event_handler_ = std::make_unique<OverviewGridEventHandler>(this);
}
void OverviewGrid::OnStartingAnimationComplete(bool canceled) {
......@@ -1344,17 +1351,25 @@ bool OverviewGrid::MaybeDropItemOnDeskMiniView(
}
void OverviewGrid::StartScroll() {
Shell::Get()->overview_controller()->PauseOcclusionTracker();
// Users are not allowed to scroll past the leftmost or rightmost bounds of
// the items on screen in the grid. |scroll_offset_min_| is the amount needed
// to fit the rightmost window into |total_bounds|. The max is zero which is
// default because windows are aligned to the left from the beginning.
gfx::Rect total_bounds = GetGridEffectiveBounds();
total_bounds.Inset(GetGridInsets(total_bounds));
float rightmost_window_right = 0;
for (const auto& window : window_list_) {
if (rightmost_window_right < window->target_bounds().right())
rightmost_window_right = window->target_bounds().right();
items_scrolling_bounds_.resize(window_list_.size());
for (size_t i = 0; i < items_scrolling_bounds_.size(); ++i) {
const gfx::RectF bounds = window_list_[i]->target_bounds();
if (rightmost_window_right < bounds.right())
rightmost_window_right = bounds.right();
items_scrolling_bounds_[i] = bounds;
}
// |rightmost_window_right| may have been modified by an earlier scroll.
// |scroll_offset_| is added to adjust for that.
rightmost_window_right -= scroll_offset_;
......@@ -1366,13 +1381,33 @@ void OverviewGrid::StartScroll() {
}
bool OverviewGrid::UpdateScrollOffset(float delta) {
const float previous_scroll_offset = scroll_offset_;
scroll_offset_ += delta;
scroll_offset_ = base::ClampToRange(scroll_offset_, scroll_offset_min_, 0.f);
if (scroll_offset_ == previous_scroll_offset)
float new_scroll_offset = scroll_offset_;
new_scroll_offset += delta;
new_scroll_offset =
base::ClampToRange(new_scroll_offset, scroll_offset_min_, 0.f);
if (new_scroll_offset == scroll_offset_)
return false;
PositionWindows(/*animate=*/false);
// Do not process scrolls that haven't moved much, unless we are at the
// edges.
if (std::abs(scroll_offset_ - new_scroll_offset) < kMinimumScrollDistanceDp &&
scroll_offset_ > scroll_offset_min_ && scroll_offset_ < 0) {
return false;
}
// Update the bounds of the items which are currently visible on screen.
DCHECK_EQ(items_scrolling_bounds_.size(), window_list_.size());
for (size_t i = 0; i < items_scrolling_bounds_.size(); ++i) {
const gfx::RectF previous_bounds = items_scrolling_bounds_[i];
items_scrolling_bounds_[i].Offset(new_scroll_offset - scroll_offset_, 0.f);
const gfx::RectF new_bounds = items_scrolling_bounds_[i];
if (gfx::RectF(GetGridEffectiveBounds()).Intersects(new_bounds) ||
gfx::RectF(GetGridEffectiveBounds()).Intersects(previous_bounds)) {
window_list_[i]->SetBounds(new_bounds, OVERVIEW_ANIMATION_NONE);
}
}
scroll_offset_ = new_scroll_offset;
DCHECK(presentation_time_recorder_);
presentation_time_recorder_->RequestNext();
......@@ -1380,7 +1415,12 @@ bool OverviewGrid::UpdateScrollOffset(float delta) {
}
void OverviewGrid::EndScroll() {
Shell::Get()->overview_controller()->UnpauseOcclusionTracker(
kOcclusionUnpauseDurationForScrollMs);
items_scrolling_bounds_.clear();
presentation_time_recorder_.reset();
PositionWindows(/*animate=*/false);
}
void OverviewGrid::MaybeInitDesksWidget() {
......
......@@ -32,7 +32,7 @@ namespace ash {
class DesksBarView;
class FpsCounter;
class OverviewGridPreEventHandler;
class OverviewGridEventHandler;
class OverviewItem;
class PresentationTimeRecorder;
......@@ -316,8 +316,8 @@ class ASH_EXPORT OverviewGrid : public aura::WindowObserver,
views::Widget* drop_target_widget() { return drop_target_widget_.get(); }
OverviewGridPreEventHandler* grid_pre_event_handler() {
return grid_pre_event_handler_.get();
OverviewGridEventHandler* grid_event_handler() {
return grid_event_handler_.get();
}
private:
......@@ -439,8 +439,8 @@ class ASH_EXPORT OverviewGrid : public aura::WindowObserver,
// Measures the animation smoothness of overview animation.
std::unique_ptr<FpsCounter> fps_counter_;
// True to skip |PositionWindows()|. Used to avoid O(n^2) layout
// when reposition windows in tablet overview mode.
// True to skip |PositionWindows()|. Used to avoid O(n^2) layout when
// reposition windows in tablet overview mode.
bool suspend_reposition_ = false;
// Used by |GetWindowRectsForTabletModeLayout| to shift the x position of the
......@@ -451,8 +451,12 @@ class ASH_EXPORT OverviewGrid : public aura::WindowObserver,
// are visible in tablet overview mode.
float scroll_offset_min_ = 0;
// Cached values of the item bounds so that they do not have to be calculated
// on each scroll update.
std::vector<gfx::RectF> items_scrolling_bounds_;
// Handles events that are not handled by the OverviewItems.
std::unique_ptr<OverviewGridPreEventHandler> grid_pre_event_handler_;
std::unique_ptr<OverviewGridEventHandler> grid_event_handler_;
// Records the presentation time of scrolling the grid in overview mode.
std::unique_ptr<PresentationTimeRecorder> presentation_time_recorder_;
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/wm/overview/overview_grid_pre_event_handler.h"
#include "ash/wm/overview/overview_grid_event_handler.h"
#include "ash/root_window_controller.h"
#include "ash/shell.h"
......@@ -30,14 +30,14 @@ WallpaperView* GetWallpaperViewForRoot(const aura::Window* root_window) {
} // namespace
OverviewGridPreEventHandler::OverviewGridPreEventHandler(OverviewGrid* grid)
OverviewGridEventHandler::OverviewGridEventHandler(OverviewGrid* grid)
: grid_(grid) {
auto* wallpaper_view = GetWallpaperViewForRoot(grid_->root_window());
if (wallpaper_view)
wallpaper_view->AddPreTargetHandler(this);
}
OverviewGridPreEventHandler::~OverviewGridPreEventHandler() {
OverviewGridEventHandler::~OverviewGridEventHandler() {
EndFling();
grid_->EndScroll();
......@@ -46,12 +46,12 @@ OverviewGridPreEventHandler::~OverviewGridPreEventHandler() {
wallpaper_view->RemovePreTargetHandler(this);
}
void OverviewGridPreEventHandler::OnMouseEvent(ui::MouseEvent* event) {
void OverviewGridEventHandler::OnMouseEvent(ui::MouseEvent* event) {
if (event->type() == ui::ET_MOUSE_RELEASED)
HandleClickOrTap(event);
}
void OverviewGridPreEventHandler::OnGestureEvent(ui::GestureEvent* event) {
void OverviewGridEventHandler::OnGestureEvent(ui::GestureEvent* event) {
switch (event->type()) {
case ui::ET_GESTURE_TAP: {
HandleClickOrTap(event);
......@@ -91,7 +91,7 @@ void OverviewGridPreEventHandler::OnGestureEvent(ui::GestureEvent* event) {
}
}
void OverviewGridPreEventHandler::OnAnimationStep(base::TimeTicks timestamp) {
void OverviewGridEventHandler::OnAnimationStep(base::TimeTicks timestamp) {
// Updates |grid_| based on |offset| when |observed_compositor_| begins a new
// frame.
DCHECK(observed_compositor_);
......@@ -113,13 +113,13 @@ void OverviewGridPreEventHandler::OnAnimationStep(base::TimeTicks timestamp) {
EndFling();
}
void OverviewGridPreEventHandler::OnCompositingShuttingDown(
void OverviewGridEventHandler::OnCompositingShuttingDown(
ui::Compositor* compositor) {
DCHECK_EQ(compositor, observed_compositor_);
EndFling();
}
void OverviewGridPreEventHandler::HandleClickOrTap(ui::Event* event) {
void OverviewGridEventHandler::HandleClickOrTap(ui::Event* event) {
CHECK_EQ(ui::EP_PRETARGET, event->phase());
// Events that happen while app list is sliding out during overview should
// be ignored to prevent overview from disappearing out from under the user.
......@@ -128,7 +128,7 @@ void OverviewGridPreEventHandler::HandleClickOrTap(ui::Event* event) {
event->StopPropagation();
}
void OverviewGridPreEventHandler::HandleFlingScroll(ui::GestureEvent* event) {
void OverviewGridEventHandler::HandleFlingScroll(ui::GestureEvent* event) {
fling_velocity_ = gfx::Vector2dF(event->details().velocity_x(),
event->details().velocity_y());
fling_curve_ =
......@@ -138,7 +138,7 @@ void OverviewGridPreEventHandler::HandleFlingScroll(ui::GestureEvent* event) {
observed_compositor_->AddAnimationObserver(this);
}
void OverviewGridPreEventHandler::EndFling() {
void OverviewGridEventHandler::EndFling() {
if (!observed_compositor_)
return;
observed_compositor_->RemoveAnimationObserver(this);
......
......@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ASH_WM_OVERVIEW_OVERVIEW_GRID_PRE_EVENT_HANDLER_H_
#define ASH_WM_OVERVIEW_OVERVIEW_GRID_PRE_EVENT_HANDLER_H_
#ifndef ASH_WM_OVERVIEW_OVERVIEW_GRID_EVENT_HANDLER_H_
#define ASH_WM_OVERVIEW_OVERVIEW_GRID_EVENT_HANDLER_H_
#include "base/macros.h"
#include "base/optional.h"
......@@ -28,11 +28,11 @@ class OverviewGrid;
// - Disabling overview mode on mouse release.
// - Scrolling through tablet overview mode on scrolling.
// - Scrolling through tablet overview mode on flinging.
class OverviewGridPreEventHandler : public ui::EventHandler,
class OverviewGridEventHandler : public ui::EventHandler,
public ui::CompositorAnimationObserver {
public:
explicit OverviewGridPreEventHandler(OverviewGrid* grid);
~OverviewGridPreEventHandler() override;
explicit OverviewGridEventHandler(OverviewGrid* grid);
~OverviewGridEventHandler() override;
// ui::EventHandler:
void OnMouseEvent(ui::MouseEvent* event) override;
......@@ -67,9 +67,9 @@ class OverviewGridPreEventHandler : public ui::EventHandler,
// The compositor we are observing when a fling is underway.
ui::Compositor* observed_compositor_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(OverviewGridPreEventHandler);
DISALLOW_COPY_AND_ASSIGN(OverviewGridEventHandler);
};
} // namespace ash
#endif // ASH_WM_OVERVIEW_OVERVIEW_GRID_PRE_EVENT_HANDLER_H_
#endif // ASH_WM_OVERVIEW_OVERVIEW_GRID_EVENT_HANDLER_H_
......@@ -21,7 +21,7 @@
#include "ash/wm/overview/overview_constants.h"
#include "ash/wm/overview/overview_controller.h"
#include "ash/wm/overview/overview_grid.h"
#include "ash/wm/overview/overview_grid_pre_event_handler.h"
#include "ash/wm/overview/overview_grid_event_handler.h"
#include "ash/wm/overview/overview_highlight_controller.h"
#include "ash/wm/overview/overview_utils.h"
#include "ash/wm/overview/overview_window_drag_controller.h"
......@@ -818,21 +818,21 @@ void OverviewItem::HandleGestureEventForTabletModeLayout(
if (IsDragItem())
HandleDragEvent(location);
else
overview_grid()->grid_pre_event_handler()->OnGestureEvent(event);
overview_grid()->grid_event_handler()->OnGestureEvent(event);
break;
case ui::ET_SCROLL_FLING_START:
if (IsDragItem()) {
HandleFlingStartEvent(location, event->details().velocity_x(),
event->details().velocity_y());
} else {
overview_grid()->grid_pre_event_handler()->OnGestureEvent(event);
overview_grid()->grid_event_handler()->OnGestureEvent(event);
}
break;
case ui::ET_GESTURE_SCROLL_END:
if (IsDragItem())
HandleReleaseEvent(location);
else
overview_grid()->grid_pre_event_handler()->OnGestureEvent(event);
overview_grid()->grid_event_handler()->OnGestureEvent(event);
break;
case ui::ET_GESTURE_LONG_PRESS:
HandlePressEvent(location, /*from_touch_gesture=*/true);
......@@ -844,7 +844,7 @@ void OverviewItem::HandleGestureEventForTabletModeLayout(
HandleGestureEndEvent();
break;
default:
overview_grid()->grid_pre_event_handler()->OnGestureEvent(event);
overview_grid()->grid_event_handler()->OnGestureEvent(event);
break;
}
}
......
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