Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / ash / wm / overview / scoped_transform_overview_window.cc
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.
4
5 #include "ash/wm/overview/scoped_transform_overview_window.h"
6
7 #include "ash/screen_util.h"
8 #include "ash/shell_window_ids.h"
9 #include "ash/wm/overview/scoped_window_copy.h"
10 #include "ash/wm/overview/window_selector_item.h"
11 #include "ash/wm/window_state.h"
12 #include "ash/wm/window_util.h"
13 #include "ui/aura/client/aura_constants.h"
14 #include "ui/aura/client/screen_position_client.h"
15 #include "ui/aura/window.h"
16 #include "ui/compositor/scoped_layer_animation_settings.h"
17 #include "ui/gfx/animation/tween.h"
18 #include "ui/views/widget/widget.h"
19 #include "ui/wm/core/window_animations.h"
20 #include "ui/wm/core/window_util.h"
21
22 namespace ash {
23
24 namespace {
25
26 // The animation settings used for window selector animations.
27 class WindowSelectorAnimationSettings
28     : public ui::ScopedLayerAnimationSettings {
29  public:
30   WindowSelectorAnimationSettings(aura::Window* window) :
31       ui::ScopedLayerAnimationSettings(window->layer()->GetAnimator()) {
32     SetPreemptionStrategy(
33         ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
34     SetTransitionDuration(base::TimeDelta::FromMilliseconds(
35         ScopedTransformOverviewWindow::kTransitionMilliseconds));
36     SetTweenType(gfx::Tween::FAST_OUT_SLOW_IN);
37   }
38
39   virtual ~WindowSelectorAnimationSettings() {
40   }
41 };
42
43 void SetTransformOnWindow(aura::Window* window,
44                           const gfx::Transform& transform,
45                           bool animate) {
46   if (animate) {
47     WindowSelectorAnimationSettings animation_settings(window);
48     window->SetTransform(transform);
49   } else {
50     window->SetTransform(transform);
51   }
52 }
53
54 gfx::Transform TranslateTransformOrigin(const gfx::Vector2d& new_origin,
55                                         const gfx::Transform& transform) {
56   gfx::Transform result;
57   result.Translate(-new_origin.x(), -new_origin.y());
58   result.PreconcatTransform(transform);
59   result.Translate(new_origin.x(), new_origin.y());
60   return result;
61 }
62
63 void SetTransformOnWindowAndAllTransientChildren(
64     aura::Window* window,
65     const gfx::Transform& transform,
66     bool animate) {
67   SetTransformOnWindow(window, transform, animate);
68
69   aura::Window::Windows transient_children =
70       ::wm::GetTransientChildren(window);
71   for (aura::Window::Windows::iterator iter = transient_children.begin();
72        iter != transient_children.end(); ++iter) {
73     aura::Window* transient_child = *iter;
74     gfx::Rect window_bounds = window->bounds();
75     gfx::Rect child_bounds = transient_child->bounds();
76     gfx::Transform transient_window_transform(
77         TranslateTransformOrigin(child_bounds.origin() - window_bounds.origin(),
78                                  transform));
79     SetTransformOnWindow(transient_child, transient_window_transform, animate);
80   }
81 }
82
83 aura::Window* GetModalTransientParent(aura::Window* window) {
84   if (window->GetProperty(aura::client::kModalKey) == ui::MODAL_TYPE_WINDOW)
85     return ::wm::GetTransientParent(window);
86   return NULL;
87 }
88
89 }  // namespace
90
91 const int ScopedTransformOverviewWindow::kTransitionMilliseconds = 200;
92
93 ScopedTransformOverviewWindow::ScopedTransformOverviewWindow(
94         aura::Window* window)
95     : window_(window),
96       minimized_(window->GetProperty(aura::client::kShowStateKey) ==
97                  ui::SHOW_STATE_MINIMIZED),
98       ignored_by_shelf_(ash::wm::GetWindowState(window)->ignored_by_shelf()),
99       overview_started_(false),
100       original_transform_(window->layer()->GetTargetTransform()),
101       opacity_(window->layer()->GetTargetOpacity()) {
102 }
103
104 ScopedTransformOverviewWindow::~ScopedTransformOverviewWindow() {
105   if (window_) {
106     WindowSelectorAnimationSettings animation_settings(window_);
107     gfx::Transform transform;
108     SetTransformOnWindowAndTransientChildren(original_transform_, true);
109     if (minimized_ && window_->GetProperty(aura::client::kShowStateKey) !=
110         ui::SHOW_STATE_MINIMIZED) {
111       // Setting opacity 0 and visible false ensures that the property change
112       // to SHOW_STATE_MINIMIZED will not animate the window from its original
113       // bounds to the minimized position.
114       // Hiding the window needs to be done before the target opacity is 0,
115       // otherwise the layer's visibility will not be updated
116       // (See VisibilityController::UpdateLayerVisibility).
117       window_->Hide();
118       window_->layer()->SetOpacity(0);
119       window_->SetProperty(aura::client::kShowStateKey,
120                            ui::SHOW_STATE_MINIMIZED);
121     }
122     ash::wm::GetWindowState(window_)->set_ignored_by_shelf(ignored_by_shelf_);
123     window_->layer()->SetOpacity(opacity_);
124   }
125 }
126
127 bool ScopedTransformOverviewWindow::Contains(const aura::Window* target) const {
128   for (ScopedVector<ScopedWindowCopy>::const_iterator iter =
129       window_copies_.begin(); iter != window_copies_.end(); ++iter) {
130     if ((*iter)->GetWindow()->Contains(target))
131       return true;
132   }
133   aura::Window* window = window_;
134   while (window) {
135     if (window->Contains(target))
136       return true;
137     window = GetModalTransientParent(window);
138   }
139   return false;
140 }
141
142 gfx::Rect ScopedTransformOverviewWindow::GetBoundsInScreen() const {
143   gfx::Rect bounds;
144   aura::Window* window = window_;
145   while (window) {
146     bounds.Union(ScreenUtil::ConvertRectToScreen(window->parent(),
147                                                 window->GetTargetBounds()));
148     window = GetModalTransientParent(window);
149   }
150   return bounds;
151 }
152
153 void ScopedTransformOverviewWindow::RestoreWindow() {
154   if (minimized_ && window_->GetProperty(aura::client::kShowStateKey) ==
155       ui::SHOW_STATE_MINIMIZED) {
156     window_->Show();
157   }
158 }
159
160 void ScopedTransformOverviewWindow::RestoreWindowOnExit() {
161   minimized_ = false;
162   original_transform_ = gfx::Transform();
163   opacity_ = 1;
164 }
165
166 void ScopedTransformOverviewWindow::OnWindowDestroyed() {
167   window_ = NULL;
168 }
169
170 gfx::Rect ScopedTransformOverviewWindow::ShrinkRectToFitPreservingAspectRatio(
171     const gfx::Rect& rect,
172     const gfx::Rect& bounds) {
173   DCHECK(!rect.IsEmpty());
174   DCHECK(!bounds.IsEmpty());
175   float scale = std::min(1.0f,
176       std::min(static_cast<float>(bounds.width()) / rect.width(),
177                static_cast<float>(bounds.height()) / rect.height()));
178   return gfx::Rect(bounds.x() + 0.5 * (bounds.width() - scale * rect.width()),
179                    bounds.y() + 0.5 * (bounds.height() - scale * rect.height()),
180                    rect.width() * scale,
181                    rect.height() * scale);
182 }
183
184 gfx::Transform ScopedTransformOverviewWindow::GetTransformForRect(
185     const gfx::Rect& src_rect,
186     const gfx::Rect& dst_rect) {
187   DCHECK(!src_rect.IsEmpty());
188   DCHECK(!dst_rect.IsEmpty());
189   gfx::Transform transform;
190   transform.Translate(dst_rect.x() - src_rect.x(),
191                       dst_rect.y() - src_rect.y());
192   transform.Scale(static_cast<float>(dst_rect.width()) / src_rect.width(),
193                   static_cast<float>(dst_rect.height()) / src_rect.height());
194   return transform;
195 }
196
197 void ScopedTransformOverviewWindow::SetTransform(
198     aura::Window* root_window,
199     const gfx::Transform& transform,
200     bool animate) {
201   DCHECK(overview_started_);
202
203   if (root_window != window_->GetRootWindow()) {
204     if (!window_copies_.empty()) {
205       bool bounds_or_hierarchy_changed = false;
206       aura::Window* window = window_;
207       for (ScopedVector<ScopedWindowCopy>::reverse_iterator iter =
208                window_copies_.rbegin();
209            !bounds_or_hierarchy_changed && iter != window_copies_.rend();
210            ++iter, window = GetModalTransientParent(window)) {
211         if (!window) {
212           bounds_or_hierarchy_changed = true;
213         } else if ((*iter)->GetWindow()->GetBoundsInScreen() !=
214                 window->GetBoundsInScreen()) {
215           bounds_or_hierarchy_changed = true;
216         }
217       }
218       // Clearing the window copies array will force it to be recreated.
219       // TODO(flackr): If only the position changed and not the size,
220       // update the existing window copy's position and continue to use it.
221       if (bounds_or_hierarchy_changed)
222         window_copies_.clear();
223     }
224     if (window_copies_.empty()) {
225       // TODO(flackr): Create copies of the transient children windows as well.
226       // Currently they will only be visible on the window's initial display.
227       CopyWindowAndTransientParents(root_window, window_);
228     }
229   }
230   SetTransformOnWindowAndTransientChildren(transform, animate);
231 }
232
233 void ScopedTransformOverviewWindow::CopyWindowAndTransientParents(
234     aura::Window* target_root,
235     aura::Window* window) {
236   aura::Window* modal_parent = GetModalTransientParent(window);
237   if (modal_parent)
238     CopyWindowAndTransientParents(target_root, modal_parent);
239   window_copies_.push_back(new ScopedWindowCopy(target_root, window));
240 }
241
242 void ScopedTransformOverviewWindow::SetTransformOnWindowAndTransientChildren(
243     const gfx::Transform& transform,
244     bool animate) {
245   gfx::Point origin(GetBoundsInScreen().origin());
246   aura::Window* window = window_;
247   while (::wm::GetTransientParent(window))
248     window = ::wm::GetTransientParent(window);
249   for (ScopedVector<ScopedWindowCopy>::const_iterator iter =
250       window_copies_.begin(); iter != window_copies_.end(); ++iter) {
251     SetTransformOnWindow(
252         (*iter)->GetWindow(),
253         TranslateTransformOrigin(ScreenUtil::ConvertRectToScreen(
254             (*iter)->GetWindow()->parent(),
255             (*iter)->GetWindow()->GetTargetBounds()).origin() - origin,
256             transform),
257         animate);
258   }
259   SetTransformOnWindowAndAllTransientChildren(
260       window,
261       TranslateTransformOrigin(ScreenUtil::ConvertRectToScreen(
262           window->parent(), window->GetTargetBounds()).origin() - origin,
263           transform),
264       animate);
265 }
266
267 void ScopedTransformOverviewWindow::PrepareForOverview() {
268   DCHECK(!overview_started_);
269   overview_started_ = true;
270   ash::wm::GetWindowState(window_)->set_ignored_by_shelf(true);
271   RestoreWindow();
272 }
273
274 }  // namespace ash