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