Skip to content

Commit

Permalink
[ash-md] Improves smoothness with many windows in overview
Browse files Browse the repository at this point in the history
Experimentally, most of the animation cost was coming from having window
shapes (used to mask the window header) and from using rounded rectangle
masks.
This CL disables both those performance hogs when there are more than
certain number of windows in the overview mode (controlled via flags).
Default is set to hardcoded 10.
It also makes sure that window controls (minimize / resize / close) are
hidden when in overview mode for custom and panel frames.

New flags are introduced:

--ash-max-previews-to-use-mask=<number>
Maximum number of preview windows in overview mode that can use masks to
hide window headers and use rounded corners. Use -1 to set to unlimited.

--ash-max-previews-to-use-shape=<number>
Maximum number of preview windows in overview mode that can use shapes to
hide window headers. Use -1 to set to unlimited.

BUG=626851
BUG=624608

Review-Url: https://codereview.chromium.org/2146323004
Cr-Commit-Position: refs/heads/master@{#406286}
  • Loading branch information
varkha authored and Commit bot committed Jul 19, 2016
1 parent bb8a604 commit d8748a3
Show file tree
Hide file tree
Showing 13 changed files with 250 additions and 48 deletions.
10 changes: 10 additions & 0 deletions ash/common/ash_switches.cc
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,16 @@ const char kAshMaterialDesignDisabled[] = "disabled";
const char kAshMaterialDesignEnabled[] = "enabled";
const char kAshMaterialDesignExperimental[] = "experimental";

// Specifies a maximum number of preview windows in overview mode that still
// allows using mask layers to hide the original window header and use rounded
// corners.
const char kAshMaxWindowsToUseMaskInOverview[] = "ash-max-previews-to-use-mask";

// Specifies a maximum number of preview windows in overview mode that still
// allows using alpha shapes to hide the original window header.
const char kAshMaxWindowsToUseShapeInOverview[] =
"ash-max-previews-to-use-shape";

// Specifies the layout mode and offsets for the secondary display for
// testing. The format is "<t|r|b|l>,<offset>" where t=TOP, r=RIGHT,
// b=BOTTOM and L=LEFT. For example, 'r,-100' means the secondary display
Expand Down
2 changes: 2 additions & 0 deletions ash/common/ash_switches.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ ASH_EXPORT extern const char kAshMaterialDesign[];
ASH_EXPORT extern const char kAshMaterialDesignDisabled[];
ASH_EXPORT extern const char kAshMaterialDesignEnabled[];
ASH_EXPORT extern const char kAshMaterialDesignExperimental[];
ASH_EXPORT extern const char kAshMaxWindowsToUseMaskInOverview[];
ASH_EXPORT extern const char kAshMaxWindowsToUseShapeInOverview[];
ASH_EXPORT extern const char kAshSecondaryDisplayLayout[];
ASH_EXPORT extern const char kAshTouchHud[];
ASH_EXPORT extern const char kAshUseFirstDisplayAsInternal[];
Expand Down
40 changes: 26 additions & 14 deletions ash/common/wm/overview/scoped_transform_overview_window.cc
Original file line number Diff line number Diff line change
Expand Up @@ -180,10 +180,11 @@ TransientDescendantIteratorRange GetTransientTreeIterator(WmWindow* window) {
class ScopedTransformOverviewWindow::OverviewContentMask
: public ui::LayerDelegate {
public:
explicit OverviewContentMask(float radius);
explicit OverviewContentMask();
~OverviewContentMask() override;

void set_radius(float radius) { radius_ = radius; }
void set_inset(int inset) { inset_ = inset; }
ui::Layer* layer() { return &layer_; }

// Overridden from LayerDelegate.
Expand All @@ -195,13 +196,13 @@ class ScopedTransformOverviewWindow::OverviewContentMask
private:
ui::Layer layer_;
float radius_;
int inset_;

DISALLOW_COPY_AND_ASSIGN(OverviewContentMask);
};

ScopedTransformOverviewWindow::OverviewContentMask::OverviewContentMask(
float radius)
: layer_(ui::LAYER_TEXTURED), radius_(radius) {
ScopedTransformOverviewWindow::OverviewContentMask::OverviewContentMask()
: layer_(ui::LAYER_TEXTURED), radius_(0), inset_(0) {
layer_.set_delegate(this);
}

Expand All @@ -213,6 +214,7 @@ void ScopedTransformOverviewWindow::OverviewContentMask::OnPaintLayer(
const ui::PaintContext& context) {
ui::PaintRecorder recorder(context, layer()->size());
gfx::Rect bounds(layer()->bounds().size());
bounds.Inset(0, inset_, 0, 0);

// Tile a window into an area, rounding the bottom corners.
const SkRect rect = gfx::RectToSkRect(bounds);
Expand Down Expand Up @@ -268,7 +270,8 @@ void ScopedTransformOverviewWindow::RestoreWindow() {
ScopedAnimationSettings animation_settings_list;
BeginScopedAnimation(OverviewAnimationType::OVERVIEW_ANIMATION_RESTORE_WINDOW,
&animation_settings_list);
SetTransform(window()->GetRootWindow(), original_transform_, 0);
SetTransform(window()->GetRootWindow(), original_transform_,
false /* use_mask */, false /* use_shape */, 0);

std::unique_ptr<ScopedOverviewAnimationSettings> animation_settings =
CreateScopedOverviewAnimationSettings(
Expand Down Expand Up @@ -417,30 +420,39 @@ gfx::Transform ScopedTransformOverviewWindow::GetTransformForRect(
void ScopedTransformOverviewWindow::SetTransform(
WmWindow* root_window,
const gfx::Transform& transform,
bool use_mask,
bool use_shape,
float radius) {
DCHECK(overview_started_);

if (ash::MaterialDesignController::IsOverviewMaterial() &&
&transform != &original_transform_) {
if (!mask_) {
mask_.reset(new OverviewContentMask(radius));
if (use_mask && !mask_) {
mask_.reset(new OverviewContentMask());
mask_->layer()->SetFillsBoundsOpaquely(false);
window()->GetLayer()->SetMaskLayer(mask_->layer());
}
gfx::Rect bounds(GetTargetBoundsInScreen().size());
mask_->layer()->SetBounds(bounds);
mask_->set_radius(radius);
window()->GetLayer()->SchedulePaint(bounds);

if (!determined_original_window_shape_) {
determined_original_window_shape_ = true;
SkRegion* window_shape = window()->GetLayer()->alpha_shape();
if (!original_window_shape_ && window_shape)
original_window_shape_.reset(new SkRegion(*window_shape));
}
gfx::Rect bounds(GetTargetBoundsInScreen().size());
const int inset =
window()->GetIntProperty(WmWindowProperty::TOP_VIEW_INSET);
if (inset > 0) {
(use_mask || use_shape)
? window()->GetIntProperty(WmWindowProperty::TOP_VIEW_INSET)
: 0;
if (mask_) {
// Mask layer is used both to hide the window header and to use rounded
// corners. Its layout needs to be update when setting a transform.
mask_->layer()->SetBounds(bounds);
mask_->set_inset(inset);
mask_->set_radius(radius);
window()->GetLayer()->SchedulePaint(bounds);
} else if (inset > 0) {
// Alpha shape is only used to to hide the window header and only when
// not using a mask layer.
bounds.Inset(0, inset, 0, 0);
SkRegion* region = new SkRegion;
region->setRect(RectToSkIRect(bounds));
Expand Down
7 changes: 6 additions & 1 deletion ash/common/wm/overview/scoped_transform_overview_window.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,14 @@ class ASH_EXPORT ScopedTransformOverviewWindow {

// Applies the |transform| to the overview window and all of its transient
// children. With Material Design creates a mask layer with the bottom edge
// using rounded corners of |radius|.
// using rounded corners of |radius|. When |use_mask| is set, hides the
// original window header and uses rounded rectangle mask which may be
// resource-intensive. When |use_shape| is set and |use_mask| is not, uses
// SetAlphaShape to mask the header.
void SetTransform(WmWindow* root_window,
const gfx::Transform& transform,
bool use_mask,
bool use_shape,
float radius);

// Set's the opacity of the managed windows.
Expand Down
35 changes: 34 additions & 1 deletion ash/common/wm/overview/window_grid.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "base/command_line.h"
#include "base/i18n/string_search.h"
#include "base/memory/scoped_vector.h"
#include "base/strings/string_number_conversions.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/pathops/SkPathOps.h"
#include "ui/compositor/layer_animation_observer.h"
Expand Down Expand Up @@ -73,6 +74,10 @@ const float kCardAspectRatio = 4.0f / 3.0f;
// landscape orientation).
const int kMinCardsMajor = 3;

// Hiding window headers can be resource intensive. Only hide the headers when
// the number of windows in this grid is less or equal than this number.
const int kMaxWindowsCountToHideHeader = 10;

const int kOverviewSelectorTransitionMilliseconds = 250;

// The color and opacity of the screen shield in overview.
Expand Down Expand Up @@ -452,6 +457,34 @@ void WindowGrid::PrepareForOverview() {
void WindowGrid::PositionWindowsMD(bool animate) {
if (window_list_.empty())
return;

const int kUnlimited = -1;
const size_t windows_count = window_list_.size();
const base::CommandLine* command_line =
base::CommandLine::ForCurrentProcess();
int windows_to_use_masks = kMaxWindowsCountToHideHeader;
if (command_line->HasSwitch(switches::kAshMaxWindowsToUseMaskInOverview) &&
(!base::StringToInt(command_line->GetSwitchValueASCII(
switches::kAshMaxWindowsToUseMaskInOverview),
&windows_to_use_masks) ||
windows_to_use_masks <= kUnlimited)) {
windows_to_use_masks = kMaxWindowsCountToHideHeader;
}
int windows_to_use_shapes = kUnlimited;
if (command_line->HasSwitch(switches::kAshMaxWindowsToUseShapeInOverview) &&
(!base::StringToInt(command_line->GetSwitchValueASCII(
switches::kAshMaxWindowsToUseShapeInOverview),
&windows_to_use_shapes) ||
windows_to_use_shapes <= kUnlimited)) {
windows_to_use_shapes = kUnlimited;
}
WindowSelectorItem::set_use_mask(windows_to_use_masks <= kUnlimited ||
static_cast<int>(windows_count) <=
windows_to_use_masks);
WindowSelectorItem::set_use_shape(windows_to_use_shapes <= kUnlimited ||
static_cast<int>(windows_count) <=
windows_to_use_shapes);

gfx::Rect total_bounds =
root_window_->ConvertRectToScreen(wm::GetDisplayWorkAreaBoundsInParent(
root_window_->GetChildByShellWindowId(
Expand Down Expand Up @@ -560,7 +593,7 @@ void WindowGrid::PositionWindowsMD(bool animate) {
}
// Position the windows centering the left-aligned rows vertically.
gfx::Vector2d offset(0, (total_bounds.bottom() - max_bottom) / 2);
for (size_t i = 0; i < window_list_.size(); ++i) {
for (size_t i = 0; i < windows_count; ++i) {
window_list_[i]->SetBounds(
rects[i] + offset,
animate
Expand Down
26 changes: 17 additions & 9 deletions ash/common/wm/overview/window_selector_item.cc
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ static const float kPreCloseScale = 0.02f;

// Calculates the |window| bounds after being transformed to the selector's
// space. The returned Rect is in virtual screen coordinates.
gfx::Rect GetTransformedBounds(WmWindow* window) {
gfx::Rect GetTransformedBounds(WmWindow* window, bool hide_header) {
gfx::RectF bounds(
window->GetRootWindow()->ConvertRectToScreen(window->GetTargetBounds()));
gfx::Transform new_transform = TransformAboutPivot(
Expand All @@ -116,7 +116,7 @@ gfx::Rect GetTransformedBounds(WmWindow* window) {
// With Material Design 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 (ash::MaterialDesignController::IsOverviewMaterial()) {
if (ash::MaterialDesignController::IsOverviewMaterial() && hide_header) {
gfx::RectF header_bounds(bounds);
header_bounds.set_height(
window->GetIntProperty(WmWindowProperty::TOP_VIEW_INSET));
Expand Down Expand Up @@ -215,6 +215,9 @@ class RoundedContainerView : public views::View {

} // namespace

bool WindowSelectorItem::use_mask_ = false;
bool WindowSelectorItem::use_shape_ = false;

WindowSelectorItem::OverviewLabelButton::OverviewLabelButton(
views::ButtonListener* listener,
const base::string16& text)
Expand Down Expand Up @@ -457,9 +460,12 @@ void WindowSelectorItem::OnWindowTitleChanged(WmWindow* window) {

float WindowSelectorItem::GetItemScale(const gfx::Size& size) {
gfx::Size inset_size(size.width(), size.height() - 2 * kWindowMarginMD);
const int header_inset =
hide_header()
? GetWindow()->GetIntProperty(WmWindowProperty::TOP_VIEW_INSET)
: 0;
return ScopedTransformOverviewWindow::GetItemScale(
GetWindow()->GetTargetBounds().size(), inset_size,
GetWindow()->GetIntProperty(WmWindowProperty::TOP_VIEW_INSET),
GetWindow()->GetTargetBounds().size(), inset_size, header_inset,
close_button_->GetPreferredSize().height());
}

Expand All @@ -476,8 +482,10 @@ void WindowSelectorItem::SetItemBounds(const gfx::Rect& target_bounds,
int top_view_inset = 0;
int title_height = 0;
if (ash::MaterialDesignController::IsOverviewMaterial()) {
top_view_inset =
GetWindow()->GetIntProperty(WmWindowProperty::TOP_VIEW_INSET);
if (hide_header()) {
top_view_inset =
GetWindow()->GetIntProperty(WmWindowProperty::TOP_VIEW_INSET);
}
title_height = close_button_->GetPreferredSize().height();
}
gfx::Rect selector_item_bounds =
Expand All @@ -491,7 +499,7 @@ void WindowSelectorItem::SetItemBounds(const gfx::Rect& target_bounds,
// before the transform. Dividing by scale factor obtains the corner radius
// which when scaled will yield |kLabelBackgroundRadius|.
transform_window_.SetTransform(
root_window_, transform,
root_window_, transform, use_mask_, use_shape_,
(kLabelBackgroundRadius / GetItemScale(target_bounds.size())));
transform_window_.set_overview_transform(transform);
}
Expand Down Expand Up @@ -589,8 +597,8 @@ void WindowSelectorItem::CreateWindowLabel(const base::string16& title) {

void WindowSelectorItem::UpdateHeaderLayout(
OverviewAnimationType animation_type) {
gfx::Rect transformed_window_bounds =
root_window_->ConvertRectFromScreen(GetTransformedBounds(GetWindow()));
gfx::Rect transformed_window_bounds = root_window_->ConvertRectFromScreen(
GetTransformedBounds(GetWindow(), hide_header()));

if (ash::MaterialDesignController::IsOverviewMaterial()) {
gfx::Rect label_rect(close_button_->GetPreferredSize());
Expand Down
14 changes: 14 additions & 0 deletions ash/common/wm/overview/window_selector_item.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ class ASH_EXPORT WindowSelectorItem : public views::ButtonListener,
bool dimmed() const { return dimmed_; }

const gfx::Rect& target_bounds() const { return target_bounds_; }
static void set_use_mask(bool use_mask) { use_mask_ = use_mask; }
static void set_use_shape(bool use_shape) { use_shape_ = use_shape; }

// views::ButtonListener:
void ButtonPressed(views::Button* sender, const ui::Event& event) override;
Expand Down Expand Up @@ -154,6 +156,8 @@ class ASH_EXPORT WindowSelectorItem : public views::ButtonListener,
// Updates the close buttons accessibility name.
void UpdateCloseButtonAccessibilityName();

static bool hide_header() { return use_mask_ || use_shape_; }

// True if the item is being shown in the overview, false if it's being
// filtered.
bool dimmed_;
Expand Down Expand Up @@ -203,6 +207,16 @@ class ASH_EXPORT WindowSelectorItem : public views::ButtonListener,
// Guaranteed to be non-null for the lifetime of |this|.
WindowSelector* window_selector_;

// If true, mask the original window header while in overview and make corners
// rounded using a mask layer. This has performance implications so it can be
// disabled when there are many windows.
static bool use_mask_;

// If true, hide the original window header while in overview using alpha
// shape. This has performance implications so it can be disabled when there
// are many windows.
static bool use_shape_;

DISALLOW_COPY_AND_ASSIGN(WindowSelectorItem);
};

Expand Down
13 changes: 13 additions & 0 deletions ash/frame/custom_frame_view_ash.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include "ash/aura/wm_window_aura.h"
#include "ash/common/ash_switches.h"
#include "ash/common/material_design/material_design_controller.h"
#include "ash/common/session/session_state_delegate.h"
#include "ash/common/shell_observer.h"
#include "ash/common/wm/window_state.h"
Expand Down Expand Up @@ -165,6 +166,8 @@ class CustomFrameViewAsh::HeaderView
void ChildPreferredSizeChanged(views::View* child) override;

// ShellObserver:
void OnOverviewModeStarting() override;
void OnOverviewModeEnded() override;
void OnMaximizeModeStarted() override;
void OnMaximizeModeEnded() override;

Expand Down Expand Up @@ -310,6 +313,16 @@ void CustomFrameViewAsh::HeaderView::ChildPreferredSizeChanged(
///////////////////////////////////////////////////////////////////////////////
// CustomFrameViewAsh::HeaderView, ShellObserver overrides:

void CustomFrameViewAsh::HeaderView::OnOverviewModeStarting() {
if (ash::MaterialDesignController::IsOverviewMaterial())
caption_button_container_->SetVisible(false);
}

void CustomFrameViewAsh::HeaderView::OnOverviewModeEnded() {
if (ash::MaterialDesignController::IsOverviewMaterial())
caption_button_container_->SetVisible(true);
}

void CustomFrameViewAsh::HeaderView::OnMaximizeModeStarted() {
caption_button_container_->UpdateSizeButtonVisibility();
parent()->Layout();
Expand Down
Loading

0 comments on commit d8748a3

Please sign in to comment.