Mac: Fix performance issues with remote CoreAnimation
[chromium-blink-merge.git] / ash / wm / overview / scoped_transform_overview_window.cc
blob9a3e09dad40634cde9f8982cffc8cd28d1900e6d
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ash/wm/overview/scoped_transform_overview_window.h"
7 #include "ash/screen_util.h"
8 #include "ash/shell_window_ids.h"
9 #include "ash/wm/overview/scoped_overview_animation_settings.h"
10 #include "ash/wm/overview/scoped_window_copy.h"
11 #include "ash/wm/overview/window_selector_item.h"
12 #include "ash/wm/window_state.h"
13 #include "ash/wm/window_util.h"
14 #include "ui/aura/client/aura_constants.h"
15 #include "ui/aura/client/screen_position_client.h"
16 #include "ui/aura/window.h"
17 #include "ui/compositor/scoped_layer_animation_settings.h"
18 #include "ui/gfx/animation/tween.h"
19 #include "ui/views/widget/widget.h"
20 #include "ui/wm/core/window_animations.h"
21 #include "ui/wm/core/window_util.h"
23 namespace ash {
25 namespace {
27 void SetTransformOnWindow(aura::Window* window,
28 const gfx::Transform& transform,
29 bool animate) {
30 ScopedOverviewAnimationSettings animation_settings(animate ?
31 OverviewAnimationType::OVERVIEW_ANIMATION_LAY_OUT_SELECTOR_ITEMS :
32 OverviewAnimationType::OVERVIEW_ANIMATION_NONE,
33 window);
34 window->SetTransform(transform);
37 gfx::Transform TranslateTransformOrigin(const gfx::Vector2d& new_origin,
38 const gfx::Transform& transform) {
39 gfx::Transform result;
40 result.Translate(-new_origin.x(), -new_origin.y());
41 result.PreconcatTransform(transform);
42 result.Translate(new_origin.x(), new_origin.y());
43 return result;
46 void SetTransformOnWindowAndAllTransientChildren(
47 aura::Window* window,
48 const gfx::Transform& transform,
49 bool animate) {
50 SetTransformOnWindow(window, transform, animate);
52 aura::Window::Windows transient_children =
53 ::wm::GetTransientChildren(window);
54 for (aura::Window::Windows::iterator iter = transient_children.begin();
55 iter != transient_children.end(); ++iter) {
56 aura::Window* transient_child = *iter;
57 gfx::Rect window_bounds = window->bounds();
58 gfx::Rect child_bounds = transient_child->bounds();
59 gfx::Transform transient_window_transform(
60 TranslateTransformOrigin(child_bounds.origin() - window_bounds.origin(),
61 transform));
62 SetTransformOnWindow(transient_child, transient_window_transform, animate);
66 aura::Window* GetModalTransientParent(aura::Window* window) {
67 if (window->GetProperty(aura::client::kModalKey) == ui::MODAL_TYPE_WINDOW)
68 return ::wm::GetTransientParent(window);
69 return NULL;
72 } // namespace
74 const int ScopedTransformOverviewWindow::kTransitionMilliseconds = 200;
76 ScopedTransformOverviewWindow::ScopedTransformOverviewWindow(
77 aura::Window* window)
78 : window_(window),
79 minimized_(window->GetProperty(aura::client::kShowStateKey) ==
80 ui::SHOW_STATE_MINIMIZED),
81 ignored_by_shelf_(wm::GetWindowState(window)->ignored_by_shelf()),
82 overview_started_(false),
83 original_transform_(window->layer()->GetTargetTransform()),
84 opacity_(window->layer()->GetTargetOpacity()) {
87 ScopedTransformOverviewWindow::~ScopedTransformOverviewWindow() {
88 if (window_) {
89 ScopedOverviewAnimationSettings animation_settings(
90 OverviewAnimationType::OVERVIEW_ANIMATION_LAY_OUT_SELECTOR_ITEMS,
91 window_);
92 gfx::Transform transform;
93 SetTransformOnWindowAndTransientChildren(original_transform_, true);
94 if (minimized_ && window_->GetProperty(aura::client::kShowStateKey) !=
95 ui::SHOW_STATE_MINIMIZED) {
96 // Setting opacity 0 and visible false ensures that the property change
97 // to SHOW_STATE_MINIMIZED will not animate the window from its original
98 // bounds to the minimized position.
99 // Hiding the window needs to be done before the target opacity is 0,
100 // otherwise the layer's visibility will not be updated
101 // (See VisibilityController::UpdateLayerVisibility).
102 window_->Hide();
103 window_->layer()->SetOpacity(0);
104 window_->SetProperty(aura::client::kShowStateKey,
105 ui::SHOW_STATE_MINIMIZED);
107 wm::GetWindowState(window_)->set_ignored_by_shelf(ignored_by_shelf_);
108 window_->layer()->SetOpacity(opacity_);
112 bool ScopedTransformOverviewWindow::Contains(const aura::Window* target) const {
113 for (ScopedVector<ScopedWindowCopy>::const_iterator iter =
114 window_copies_.begin(); iter != window_copies_.end(); ++iter) {
115 if ((*iter)->GetWindow()->Contains(target))
116 return true;
118 aura::Window* window = window_;
119 while (window) {
120 if (window->Contains(target))
121 return true;
122 window = GetModalTransientParent(window);
124 return false;
127 gfx::Rect ScopedTransformOverviewWindow::GetBoundsInScreen() const {
128 gfx::Rect bounds;
129 aura::Window* window = window_;
130 while (window) {
131 bounds.Union(ScreenUtil::ConvertRectToScreen(window->parent(),
132 window->GetTargetBounds()));
133 window = GetModalTransientParent(window);
135 return bounds;
138 void ScopedTransformOverviewWindow::RestoreWindow() {
139 if (minimized_ && window_->GetProperty(aura::client::kShowStateKey) ==
140 ui::SHOW_STATE_MINIMIZED) {
141 window_->Show();
145 void ScopedTransformOverviewWindow::RestoreWindowOnExit() {
146 minimized_ = false;
147 original_transform_ = gfx::Transform();
148 opacity_ = 1;
151 void ScopedTransformOverviewWindow::OnWindowDestroyed() {
152 window_ = NULL;
155 gfx::Rect ScopedTransformOverviewWindow::ShrinkRectToFitPreservingAspectRatio(
156 const gfx::Rect& rect,
157 const gfx::Rect& bounds) {
158 DCHECK(!rect.IsEmpty());
159 DCHECK(!bounds.IsEmpty());
160 float scale = std::min(1.0f,
161 std::min(static_cast<float>(bounds.width()) / rect.width(),
162 static_cast<float>(bounds.height()) / rect.height()));
163 return gfx::Rect(bounds.x() + 0.5 * (bounds.width() - scale * rect.width()),
164 bounds.y() + 0.5 * (bounds.height() - scale * rect.height()),
165 rect.width() * scale,
166 rect.height() * scale);
169 gfx::Transform ScopedTransformOverviewWindow::GetTransformForRect(
170 const gfx::Rect& src_rect,
171 const gfx::Rect& dst_rect) {
172 DCHECK(!src_rect.IsEmpty());
173 DCHECK(!dst_rect.IsEmpty());
174 gfx::Transform transform;
175 transform.Translate(dst_rect.x() - src_rect.x(),
176 dst_rect.y() - src_rect.y());
177 transform.Scale(static_cast<float>(dst_rect.width()) / src_rect.width(),
178 static_cast<float>(dst_rect.height()) / src_rect.height());
179 return transform;
182 void ScopedTransformOverviewWindow::SetTransform(
183 aura::Window* root_window,
184 const gfx::Transform& transform,
185 bool animate) {
186 DCHECK(overview_started_);
188 if (root_window != window_->GetRootWindow()) {
189 if (!window_copies_.empty()) {
190 bool bounds_or_hierarchy_changed = false;
191 aura::Window* window = window_;
192 for (ScopedVector<ScopedWindowCopy>::reverse_iterator iter =
193 window_copies_.rbegin();
194 !bounds_or_hierarchy_changed && iter != window_copies_.rend();
195 ++iter, window = GetModalTransientParent(window)) {
196 if (!window) {
197 bounds_or_hierarchy_changed = true;
198 } else if ((*iter)->GetWindow()->GetBoundsInScreen() !=
199 window->GetBoundsInScreen()) {
200 bounds_or_hierarchy_changed = true;
203 // Clearing the window copies array will force it to be recreated.
204 // TODO(flackr): If only the position changed and not the size,
205 // update the existing window copy's position and continue to use it.
206 if (bounds_or_hierarchy_changed)
207 window_copies_.clear();
209 if (window_copies_.empty()) {
210 // TODO(flackr): Create copies of the transient children windows as well.
211 // Currently they will only be visible on the window's initial display.
212 CopyWindowAndTransientParents(root_window, window_);
215 SetTransformOnWindowAndTransientChildren(transform, animate);
218 void ScopedTransformOverviewWindow::CopyWindowAndTransientParents(
219 aura::Window* target_root,
220 aura::Window* window) {
221 aura::Window* modal_parent = GetModalTransientParent(window);
222 if (modal_parent)
223 CopyWindowAndTransientParents(target_root, modal_parent);
224 window_copies_.push_back(new ScopedWindowCopy(target_root, window));
227 void ScopedTransformOverviewWindow::SetTransformOnWindowAndTransientChildren(
228 const gfx::Transform& transform,
229 bool animate) {
230 gfx::Point origin(GetBoundsInScreen().origin());
231 aura::Window* window = window_;
232 while (::wm::GetTransientParent(window))
233 window = ::wm::GetTransientParent(window);
234 for (ScopedVector<ScopedWindowCopy>::const_iterator iter =
235 window_copies_.begin(); iter != window_copies_.end(); ++iter) {
236 SetTransformOnWindow(
237 (*iter)->GetWindow(),
238 TranslateTransformOrigin(ScreenUtil::ConvertRectToScreen(
239 (*iter)->GetWindow()->parent(),
240 (*iter)->GetWindow()->GetTargetBounds()).origin() - origin,
241 transform),
242 animate);
244 SetTransformOnWindowAndAllTransientChildren(
245 window,
246 TranslateTransformOrigin(ScreenUtil::ConvertRectToScreen(
247 window->parent(), window->GetTargetBounds()).origin() - origin,
248 transform),
249 animate);
252 void ScopedTransformOverviewWindow::PrepareForOverview() {
253 DCHECK(!overview_started_);
254 overview_started_ = true;
255 wm::GetWindowState(window_)->set_ignored_by_shelf(true);
256 RestoreWindow();
259 } // namespace ash