Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / athena / wm / window_overview_mode.cc
1 // Copyright 2014 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 "athena/wm/window_overview_mode.h"
6
7 #include <complex>
8 #include <vector>
9
10 #include "athena/wm/overview_toolbar.h"
11 #include "athena/wm/public/window_list_provider.h"
12 #include "athena/wm/public/window_list_provider_observer.h"
13 #include "athena/wm/split_view_controller.h"
14 #include "base/bind.h"
15 #include "base/memory/scoped_vector.h"
16 #include "ui/aura/scoped_window_targeter.h"
17 #include "ui/aura/window.h"
18 #include "ui/aura/window_delegate.h"
19 #include "ui/aura/window_property.h"
20 #include "ui/aura/window_targeter.h"
21 #include "ui/aura/window_tree_host.h"
22 #include "ui/compositor/closure_animation_observer.h"
23 #include "ui/compositor/compositor.h"
24 #include "ui/compositor/compositor_animation_observer.h"
25 #include "ui/compositor/scoped_layer_animation_settings.h"
26 #include "ui/events/event_handler.h"
27 #include "ui/events/gestures/fling_curve.h"
28 #include "ui/gfx/frame_time.h"
29 #include "ui/gfx/transform.h"
30 #include "ui/wm/core/shadow_types.h"
31 #include "ui/wm/core/window_animations.h"
32 #include "ui/wm/core/window_util.h"
33 #include "ui/wm/public/activation_client.h"
34
35 namespace {
36
37 struct WindowOverviewState {
38   // The current overview state of the window. 0.f means the window is at the
39   // topmost position. 1.f means the window is at the bottom-most position.
40   float progress;
41
42   // The top-most and bottom-most vertical position of the window in overview
43   // mode.
44   float max_y;
45   float min_y;
46
47   // |split| is set if this window is one of the two split windows in split-view
48   // mode.
49   bool split;
50 };
51
52 }  // namespace
53
54 DECLARE_WINDOW_PROPERTY_TYPE(WindowOverviewState*);
55 DEFINE_OWNED_WINDOW_PROPERTY_KEY(WindowOverviewState,
56                                  kWindowOverviewState,
57                                  nullptr);
58
59 namespace athena {
60
61 namespace {
62
63 const float kOverviewDefaultScale = 0.75f;
64
65 gfx::Transform GetTransformForSplitWindow(aura::Window* window, float scale) {
66   const float kScrollWindowPositionInOverview = 0.65f;
67   int x_translate = window->bounds().width() * (1 - scale) / 2;
68   gfx::Transform transform;
69   transform.Translate(
70       x_translate, window->bounds().height() * kScrollWindowPositionInOverview);
71   transform.Scale(scale, scale);
72   return transform;
73 }
74
75 // Gets the transform for the window in its current state.
76 gfx::Transform GetTransformForState(aura::Window* window,
77                                     WindowOverviewState* state) {
78   if (state->split)
79     return GetTransformForSplitWindow(window, kOverviewDefaultScale);
80
81   const float kProgressToStartShrinking = 0.07;
82   const float kOverviewScale = 0.75f;
83   float scale = kOverviewScale;
84   if (state->progress < kProgressToStartShrinking) {
85     const float kShrunkMinimumScale = 0.7f;
86     scale = gfx::Tween::FloatValueBetween(
87         state->progress / kProgressToStartShrinking,
88         kShrunkMinimumScale,
89         kOverviewScale);
90   }
91   int container_width = window->parent()->bounds().width();
92   int window_width = window->bounds().width();
93   int window_x = window->bounds().x();
94   float x_translate = (container_width - (window_width * scale)) / 2 - window_x;
95   float y_translate = gfx::Tween::FloatValueBetween(
96       state->progress, state->min_y, state->max_y);
97   gfx::Transform transform;
98   transform.Translate(x_translate, y_translate);
99   transform.Scale(scale, scale);
100   return transform;
101 }
102
103 // A utility class used to set the transform/opacity to the window and
104 // its transient children.
105 class TransientGroupSetter {
106  public:
107   explicit TransientGroupSetter(aura::Window* window) : window_(window) {
108   }
109   ~TransientGroupSetter() {}
110
111   // Aborts all animations including its transient children.
112   void AbortAllAnimations() {
113     window_->layer()->GetAnimator()->AbortAllAnimations();
114     for (aura::Window* transient_child : wm::GetTransientChildren(window_))
115       transient_child->layer()->GetAnimator()->AbortAllAnimations();
116   }
117
118   // Applys transform to the window and its transient children.
119   // Transient children gets a tranfrorm with the offset relateive
120   // it its transient parent.
121   void SetTransform(const gfx::Transform& transform) {
122     window_->SetTransform(transform);
123     for (aura::Window* transient_child : wm::GetTransientChildren(window_)) {
124       gfx::Rect window_bounds = window_->bounds();
125       gfx::Rect child_bounds = transient_child->bounds();
126       gfx::Transform transient_window_transform(TranslateTransformOrigin(
127           child_bounds.origin() - window_bounds.origin(), transform));
128       transient_child->SetTransform(transient_window_transform);
129     }
130   }
131
132   // Sets the opacity to the window and its transient children.
133   void SetOpacity(float opacity) {
134     window_->layer()->SetOpacity(opacity);
135     for (aura::Window* transient_child : wm::GetTransientChildren(window_)) {
136       transient_child->layer()->SetOpacity(opacity);
137     }
138   }
139
140   // Apply the transform with the overview scroll |progress|.
141   void SetWindowProgress(float progress) {
142     WindowOverviewState* state = window_->GetProperty(kWindowOverviewState);
143     state->progress = progress;
144
145     SetTransform(GetTransformForState(window_, state));
146   }
147
148  private:
149   static gfx::Transform TranslateTransformOrigin(
150       const gfx::Vector2d& new_origin,
151       const gfx::Transform& transform) {
152     gfx::Transform result;
153     result.Translate(-new_origin.x(), -new_origin.y());
154     result.PreconcatTransform(transform);
155     result.Translate(new_origin.x(), new_origin.y());
156     return result;
157   }
158
159   aura::Window* window_;
160
161   DISALLOW_COPY_AND_ASSIGN(TransientGroupSetter);
162 };
163
164 // TransientGroupSetter with animation.
165 class AnimateTransientGroupSetter : public TransientGroupSetter {
166  public:
167   explicit AnimateTransientGroupSetter(aura::Window* window)
168       : TransientGroupSetter(window) {
169     animation_settings_.push_back(CreateScopedLayerAnimationSettings(window));
170     for (aura::Window* transient_child : wm::GetTransientChildren(window)) {
171       animation_settings_.push_back(
172           CreateScopedLayerAnimationSettings(transient_child));
173     }
174   }
175   ~AnimateTransientGroupSetter() {}
176
177   ui::ScopedLayerAnimationSettings* GetMainWindowAnimationSettings() {
178     CHECK(animation_settings_.size());
179     return animation_settings_[0];
180   }
181
182  private:
183   static ui::ScopedLayerAnimationSettings* CreateScopedLayerAnimationSettings(
184       aura::Window* window) {
185     const int kTransitionMs = 250;
186
187     ui::ScopedLayerAnimationSettings* settings =
188         new ui::ScopedLayerAnimationSettings(window->layer()->GetAnimator());
189     settings->SetPreemptionStrategy(
190         ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
191     settings->SetTransitionDuration(
192         base::TimeDelta::FromMilliseconds(kTransitionMs));
193     return settings;
194   }
195
196   ScopedVector<ui::ScopedLayerAnimationSettings> animation_settings_;
197   DISALLOW_COPY_AND_ASSIGN(AnimateTransientGroupSetter);
198 };
199
200 void HideWindowIfNotVisible(aura::Window* window,
201                             SplitViewController* split_view_controller) {
202   bool should_hide = true;
203   if (split_view_controller->IsSplitViewModeActive()) {
204     should_hide = window != split_view_controller->left_window() &&
205                   window != split_view_controller->right_window();
206   } else {
207     aura::Window* active = aura::client::GetActivationClient(
208                                window->GetRootWindow())->GetActiveWindow();
209     should_hide = active != window && wm::GetTransientParent(active) != window;
210   }
211   if (should_hide)
212     window->Hide();
213 }
214
215 // Resets the overview-related state for |window|.
216 void RestoreWindowState(aura::Window* window,
217                         SplitViewController* split_view_controller) {
218   window->ClearProperty(kWindowOverviewState);
219
220   AnimateTransientGroupSetter setter(window);
221
222   setter.GetMainWindowAnimationSettings()->AddObserver(
223       new ui::ClosureAnimationObserver(
224           base::Bind(&HideWindowIfNotVisible, window, split_view_controller)));
225
226   setter.SetTransform(gfx::Transform());
227   // Reset the window opacity in case the user is dragging a window.
228   setter.SetOpacity(1.0f);
229
230   wm::SetShadowType(window, wm::SHADOW_TYPE_NONE);
231 }
232
233 gfx::RectF GetTransformedBounds(aura::Window* window) {
234   gfx::Transform transform;
235   gfx::RectF bounds = window->bounds();
236   transform.Translate(bounds.x(), bounds.y());
237   transform.PreconcatTransform(window->layer()->transform());
238   transform.Translate(-bounds.x(), -bounds.y());
239   transform.TransformRect(&bounds);
240   return bounds;
241 }
242
243 void TransformSplitWindowScale(aura::Window* window, float scale) {
244   gfx::Transform transform = window->layer()->GetTargetTransform();
245   if (transform.Scale2d() == gfx::Vector2dF(scale, scale))
246     return;
247   AnimateTransientGroupSetter setter(window);
248   setter.SetTransform(GetTransformForSplitWindow(window, scale));
249 }
250
251 void AnimateWindowTo(aura::Window* animate_window,
252                      aura::Window* target_window) {
253   AnimateTransientGroupSetter setter(animate_window);
254
255   WindowOverviewState* target_state =
256       target_window->GetProperty(kWindowOverviewState);
257   setter.SetWindowProgress(target_state->progress);
258 }
259
260 // Always returns the same target.
261 class StaticWindowTargeter : public aura::WindowTargeter {
262  public:
263   explicit StaticWindowTargeter(aura::Window* target) : target_(target) {}
264   ~StaticWindowTargeter() override {}
265
266  private:
267   // aura::WindowTargeter:
268   ui::EventTarget* FindTargetForEvent(ui::EventTarget* root,
269                                       ui::Event* event) override {
270     return target_;
271   }
272
273   ui::EventTarget* FindTargetForLocatedEvent(ui::EventTarget* root,
274                                              ui::LocatedEvent* event) override {
275     return target_;
276   }
277
278   aura::Window* target_;
279   DISALLOW_COPY_AND_ASSIGN(StaticWindowTargeter);
280 };
281
282 class WindowOverviewModeImpl : public WindowOverviewMode,
283                                public ui::EventHandler,
284                                public ui::CompositorAnimationObserver,
285                                public WindowListProviderObserver {
286  public:
287   WindowOverviewModeImpl(aura::Window* container,
288                          WindowListProvider* window_list_provider,
289                          SplitViewController* split_view_controller,
290                          WindowOverviewModeDelegate* delegate)
291       : container_(container),
292         window_list_provider_(window_list_provider),
293         split_view_controller_(split_view_controller),
294         delegate_(delegate),
295         scoped_targeter_(new aura::ScopedWindowTargeter(
296             container,
297             scoped_ptr<ui::EventTargeter>(
298                 new StaticWindowTargeter(container)))),
299         dragged_window_(nullptr) {
300     CHECK(delegate_);
301     container_->set_target_handler(this);
302
303     // Prepare the desired transforms for all the windows, and set the initial
304     // state on the windows.
305     ComputeTerminalStatesForAllWindows();
306     SetInitialWindowStates();
307
308     window_list_provider_->AddObserver(this);
309   }
310
311   ~WindowOverviewModeImpl() override {
312     window_list_provider_->RemoveObserver(this);
313     container_->set_target_handler(container_->delegate());
314     RemoveAnimationObserver();
315     const aura::Window::Windows& windows =
316         window_list_provider_->GetWindowList();
317     if (windows.empty())
318       return;
319     for (aura::Window* window : windows)
320       RestoreWindowState(window, split_view_controller_);
321   }
322
323  private:
324   // Computes the transforms for all windows in both the topmost and bottom-most
325   // positions. The transforms are set in the |kWindowOverviewState| property of
326   // the windows.
327   void ComputeTerminalStatesForAllWindows() {
328     size_t index = 0;
329
330     const aura::Window::Windows& windows =
331         window_list_provider_->GetWindowList();
332     for (aura::Window::Windows::const_reverse_iterator iter = windows.rbegin();
333          iter != windows.rend();
334          ++iter, ++index) {
335       aura::Window* window = (*iter);
336       wm::SetShadowType(window, wm::SHADOW_TYPE_RECTANGULAR_ALWAYS_ACTIVE);
337
338       WindowOverviewState* state = new WindowOverviewState;
339       window->SetProperty(kWindowOverviewState, state);
340       if (split_view_controller_->IsSplitViewModeActive() &&
341           (window == split_view_controller_->left_window() ||
342            window == split_view_controller_->right_window())) {
343         // Do not let the left/right windows be scrolled.
344         gfx::Transform transform =
345             GetTransformForSplitWindow(window, kOverviewDefaultScale);
346         state->max_y = state->min_y = transform.To2dTranslation().y();
347         state->split = true;
348         --index;
349         continue;
350       }
351       state->split = false;
352       UpdateTerminalStateForWindowAtIndex(window, index, windows.size());
353     }
354   }
355
356   // Computes the terminal states (i.e. the transforms for the top-most and
357   // bottom-most position in the stack) for |window|. |window_count| is the
358   // number of windows in the stack, and |index| is the position of the window
359   // in the stack (0 being the front-most window).
360   void UpdateTerminalStateForWindowAtIndex(aura::Window* window,
361                                            size_t index,
362                                            size_t window_count) {
363     const int kGapBetweenWindowsBottom = 10;
364     const int kGapBetweenWindowsTop = 5;
365
366     int top = (window_count - index - 1) * kGapBetweenWindowsTop;
367     int bottom = GetScrollableHeight() - (index * kGapBetweenWindowsBottom);
368
369     WindowOverviewState* state = window->GetProperty(kWindowOverviewState);
370     CHECK(state);
371     if (state->split)
372       return;
373     state->min_y = top;
374     state->max_y = bottom - window->bounds().y();
375     state->progress = 0.f;
376   }
377
378   // Sets the initial position for the windows for the overview mode.
379   void SetInitialWindowStates() {
380     // The initial overview state of the topmost three windows.
381     const float kInitialProgress[] = { 0.5f, 0.05f, 0.01f };
382     size_t index = 0;
383     const aura::Window::Windows& windows =
384         window_list_provider_->GetWindowList();
385     for (aura::Window::Windows::const_reverse_iterator iter = windows.rbegin();
386          iter != windows.rend();
387          ++iter) {
388       float progress = 0.f;
389       aura::Window* window = *iter;
390       if (split_view_controller_->IsSplitViewModeActive() &&
391           (window == split_view_controller_->left_window() ||
392            window == split_view_controller_->right_window())) {
393         progress = 1;
394       } else {
395         if (index < arraysize(kInitialProgress))
396           progress = kInitialProgress[index];
397         ++index;
398       }
399
400       TransientGroupSetter setter(window);
401
402       // Unset any in-progress animation.
403       setter.AbortAllAnimations();
404
405       // Showing transient parent will show the transient children if any.
406       window->Show();
407
408       setter.SetTransform(gfx::Transform());
409       // Setup the animation.
410       {
411         AnimateTransientGroupSetter setter(window);
412         setter.SetWindowProgress(progress);
413       }
414     }
415   }
416
417   aura::Window* SelectWindowAt(ui::LocatedEvent* event) {
418     CHECK_EQ(container_, event->target());
419     // Find the old targeter to find the target of the event.
420     ui::EventTarget* window = container_;
421     ui::EventTargeter* targeter = scoped_targeter_->old_targeter();
422     while (!targeter && window->GetParentTarget()) {
423       window = window->GetParentTarget();
424       targeter = window->GetEventTargeter();
425     }
426     if (!targeter)
427       return nullptr;
428     aura::Window* target = static_cast<aura::Window*>(
429         targeter->FindTargetForLocatedEvent(container_, event));
430     while (target && target->parent() != container_)
431       target = target->parent();
432     aura::Window* transient_parent =
433         target ? wm::GetTransientParent(target) : nullptr;
434     return transient_parent ? transient_parent : target;
435   }
436
437   // Scroll the window list by |delta_y| amount. |delta_y| is negative when
438   // scrolling up; and positive when scrolling down.
439   void DoScroll(float delta_y) {
440     const float kEpsilon = 1e-3f;
441     float delta_y_p = std::abs(delta_y) / GetScrollableHeight();
442     const aura::Window::Windows& windows =
443         window_list_provider_->GetWindowList();
444     if (delta_y < 0) {
445       // Scroll up. Start with the top-most (i.e. behind-most in terms of
446       // z-index) window, and try to scroll them up.
447       for (aura::Window::Windows::const_iterator iter = windows.begin();
448            delta_y_p > kEpsilon && iter != windows.end();
449            ++iter) {
450         aura::Window* window = (*iter);
451         WindowOverviewState* state = window->GetProperty(kWindowOverviewState);
452         if (state->progress > kEpsilon) {
453           // It is possible to scroll |window| up. Scroll it up, and update
454           // |delta_y_p| for the next window.
455           float apply = delta_y_p * state->progress;
456           TransientGroupSetter setter(window);
457           setter.SetWindowProgress(std::max(0.f, state->progress - apply * 3));
458           delta_y_p -= apply;
459         }
460       }
461     } else {
462       // Scroll down. Start with the bottom-most (i.e. front-most in terms of
463       // z-index) window, and try to scroll them down.
464       aura::Window::Windows::const_reverse_iterator iter;
465       for (iter = windows.rbegin();
466            delta_y_p > kEpsilon && iter != windows.rend();
467            ++iter) {
468         aura::Window* window = (*iter);
469         WindowOverviewState* state = window->GetProperty(kWindowOverviewState);
470         if (1.f - state->progress > kEpsilon) {
471           // It is possible to scroll |window| down. Scroll it down, and update
472           // |delta_y_p| for the next window.
473           TransientGroupSetter setter(window);
474           setter.SetWindowProgress(std::min(1.f, state->progress + delta_y_p));
475           delta_y_p /= 2.f;
476         }
477       }
478     }
479   }
480
481   int GetScrollableHeight() const {
482     const float kScrollableFraction = 0.85f;
483     const float kScrollableFractionInSplit = 0.5f;
484     const float fraction = split_view_controller_->IsSplitViewModeActive()
485                                ? kScrollableFractionInSplit
486                                : kScrollableFraction;
487     return container_->bounds().height() * fraction;
488   }
489
490   void CreateFlingerFor(const ui::GestureEvent& event) {
491     gfx::Vector2dF velocity(event.details().velocity_x(),
492                             event.details().velocity_y());
493     fling_.reset(new ui::FlingCurve(velocity, gfx::FrameTime::Now()));
494   }
495
496   void AddAnimationObserver() {
497     ui::Compositor* compositor = container_->GetHost()->compositor();
498     if (!compositor->HasAnimationObserver(this))
499       compositor->AddAnimationObserver(this);
500   }
501
502   void RemoveAnimationObserver() {
503     ui::Compositor* compositor = container_->GetHost()->compositor();
504     if (compositor->HasAnimationObserver(this))
505       compositor->RemoveAnimationObserver(this);
506   }
507
508   aura::Window* GetSplitWindowDropTarget(const ui::GestureEvent& event) const {
509     if (!split_view_controller_->IsSplitViewModeActive())
510       return nullptr;
511     CHECK(dragged_window_);
512     CHECK_NE(split_view_controller_->left_window(), dragged_window_);
513     CHECK_NE(split_view_controller_->right_window(), dragged_window_);
514     aura::Window* window = split_view_controller_->left_window();
515     if (GetTransformedBounds(window).Contains(event.location()))
516       return window;
517     window = split_view_controller_->right_window();
518     if (GetTransformedBounds(window).Contains(event.location()))
519       return window;
520     return nullptr;
521   }
522
523   void DragWindow(const ui::GestureEvent& event) {
524     CHECK(dragged_window_);
525     CHECK_EQ(ui::ET_GESTURE_SCROLL_UPDATE, event.type());
526     CHECK(overview_toolbar_);
527     gfx::Vector2dF dragged_distance =
528         dragged_start_location_ - event.location();
529     WindowOverviewState* dragged_state =
530         dragged_window_->GetProperty(kWindowOverviewState);
531     CHECK(dragged_state);
532     gfx::Transform transform =
533         GetTransformForState(dragged_window_, dragged_state);
534     transform.Translate(-dragged_distance.x(), 0);
535     TransientGroupSetter setter(dragged_window_);
536     setter.SetTransform(transform);
537
538     // Update the toolbar.
539     const int kMinDistanceForActionButtons = 20;
540     if (fabs(dragged_distance.x()) > kMinDistanceForActionButtons)
541       overview_toolbar_->ShowActionButtons();
542     else
543       overview_toolbar_->HideActionButtons();
544
545     // See if the touch-point is above one of the action-buttons.
546     OverviewToolbar::ActionType new_action =
547         overview_toolbar_->GetHighlightAction(event);
548
549     // If the touch-point is not above any of the action buttons, then highlight
550     // the close-button by default, if the user has dragged enough to close the
551     // window.
552     if (new_action == OverviewToolbar::ACTION_TYPE_NONE) {
553       if (fabs(dragged_distance.x()) > kMinDistanceForDismissal)
554         new_action = OverviewToolbar::ACTION_TYPE_CLOSE;
555       else
556         new_action = OverviewToolbar::ACTION_TYPE_NONE;
557     }
558     OverviewToolbar::ActionType previous_action =
559         overview_toolbar_->current_action();
560     overview_toolbar_->SetHighlightAction(new_action);
561
562     aura::Window* split_drop = GetSplitWindowDropTarget(event);
563
564     // If the user has selected to get into split-view mode, then show the
565     // window with full opacity. Otherwise, fade it out as it closes. Animate
566     // the opacity if transitioning to/from the split-view button.
567     bool animate_opacity =
568         (new_action != previous_action) &&
569         ((new_action == OverviewToolbar::ACTION_TYPE_SPLIT) ||
570          (previous_action == OverviewToolbar::ACTION_TYPE_SPLIT));
571     float ratio = std::min(
572         1.f, std::abs(dragged_distance.x()) / kMinDistanceForDismissal);
573     float opacity =
574         (new_action == OverviewToolbar::ACTION_TYPE_SPLIT || split_drop)
575             ? 1
576             : gfx::Tween::FloatValueBetween(ratio, kMaxOpacity, kMinOpacity);
577     if (animate_opacity) {
578       AnimateTransientGroupSetter setter(dragged_window_);
579       setter.SetOpacity(opacity);
580     } else {
581       TransientGroupSetter setter(dragged_window_);
582       setter.SetOpacity(opacity);
583     }
584
585     if (split_view_controller_->IsSplitViewModeActive()) {
586       float scale = kOverviewDefaultScale;
587       if (split_drop == split_view_controller_->left_window())
588         scale = kMaxScaleForSplitTarget;
589       TransformSplitWindowScale(split_view_controller_->left_window(), scale);
590
591       scale = kOverviewDefaultScale;
592       if (split_drop == split_view_controller_->right_window())
593         scale = kMaxScaleForSplitTarget;
594       TransformSplitWindowScale(split_view_controller_->right_window(), scale);
595     }
596   }
597
598   bool ShouldCloseDragWindow(const ui::GestureEvent& event) const {
599     gfx::Vector2dF dragged_distance =
600         dragged_start_location_ - event.location();
601     if (event.type() == ui::ET_GESTURE_SCROLL_END)
602       return std::abs(dragged_distance.x()) >= kMinDistanceForDismissal;
603     CHECK_EQ(ui::ET_SCROLL_FLING_START, event.type());
604     const bool dragging_towards_right = dragged_distance.x() < 0;
605     const bool swipe_towards_right = event.details().velocity_x() > 0;
606     if (dragging_towards_right != swipe_towards_right)
607       return false;
608     const float kMinVelocityForDismissal = 500.f;
609     return std::abs(event.details().velocity_x()) > kMinVelocityForDismissal;
610   }
611
612   void CloseDragWindow(const ui::GestureEvent& gesture) {
613     // Animate |dragged_window_| offscreen first, then destroy it.
614     {
615       AnimateTransientGroupSetter setter(dragged_window_);
616
617       WindowOverviewState* dragged_state =
618           dragged_window_->GetProperty(kWindowOverviewState);
619       CHECK(dragged_state);
620       gfx::Transform transform = dragged_window_->layer()->transform();
621       gfx::RectF transformed_bounds = dragged_window_->bounds();
622       transform.TransformRect(&transformed_bounds);
623       float transform_x = 0.f;
624       if (gesture.location().x() > dragged_start_location_.x())
625         transform_x = container_->bounds().right() - transformed_bounds.x();
626       else
627         transform_x = -(transformed_bounds.x() + transformed_bounds.width());
628       transform.Translate(transform_x / kOverviewDefaultScale, 0);
629
630       setter.SetOpacity(kMinOpacity);
631     }
632     delete dragged_window_;
633     dragged_window_ = nullptr;
634   }
635
636   void RestoreDragWindow() {
637     CHECK(dragged_window_);
638     WindowOverviewState* dragged_state =
639         dragged_window_->GetProperty(kWindowOverviewState);
640     CHECK(dragged_state);
641
642     AnimateTransientGroupSetter setter(dragged_window_);
643     setter.SetTransform(GetTransformForState(dragged_window_, dragged_state));
644     setter.SetOpacity(1.0f);
645     dragged_window_ = nullptr;
646   }
647
648   void EndDragWindow(const ui::GestureEvent& gesture) {
649     CHECK(dragged_window_);
650     CHECK(overview_toolbar_);
651     OverviewToolbar::ActionType action = overview_toolbar_->current_action();
652     overview_toolbar_.reset();
653     if (action == OverviewToolbar::ACTION_TYPE_SPLIT) {
654       delegate_->OnSelectSplitViewWindow(
655           nullptr, dragged_window_, dragged_window_);
656       return;
657     }
658
659     // If the window is dropped on one of the left/right windows in split-mode,
660     // then switch that window.
661     aura::Window* split_drop = GetSplitWindowDropTarget(gesture);
662     if (split_drop) {
663       aura::Window* left = split_view_controller_->left_window();
664       aura::Window* right = split_view_controller_->right_window();
665       if (left == split_drop)
666         left = dragged_window_;
667       else
668         right = dragged_window_;
669       delegate_->OnSelectSplitViewWindow(left, right, dragged_window_);
670       return;
671     }
672
673     if (ShouldCloseDragWindow(gesture))
674       CloseDragWindow(gesture);
675     else
676       RestoreDragWindow();
677   }
678
679   void SelectWindow(aura::Window* window) {
680     if (!split_view_controller_->IsSplitViewModeActive()) {
681       delegate_->OnSelectWindow(window);
682     } else {
683       // If the selected window is one of the left/right windows, then keep the
684       // current state.
685       if (window == split_view_controller_->left_window() ||
686           window == split_view_controller_->right_window()) {
687         delegate_->OnSelectSplitViewWindow(
688             split_view_controller_->left_window(),
689             split_view_controller_->right_window(),
690             window);
691       } else {
692         delegate_->OnSelectWindow(window);
693       }
694     }
695   }
696
697   // ui::EventHandler:
698   void OnMouseEvent(ui::MouseEvent* mouse) override {
699     if (mouse->type() == ui::ET_MOUSE_PRESSED) {
700       aura::Window* select = SelectWindowAt(mouse);
701       if (select) {
702         mouse->SetHandled();
703         SelectWindow(select);
704       }
705     } else if (mouse->type() == ui::ET_MOUSEWHEEL) {
706       DoScroll(static_cast<ui::MouseWheelEvent*>(mouse)->y_offset());
707     }
708   }
709
710   void OnScrollEvent(ui::ScrollEvent* scroll) override {
711     if (scroll->type() == ui::ET_SCROLL)
712       DoScroll(scroll->y_offset());
713   }
714
715   void OnGestureEvent(ui::GestureEvent* gesture) override {
716     if (gesture->type() == ui::ET_GESTURE_TAP) {
717       aura::Window* select = SelectWindowAt(gesture);
718       if (select) {
719         gesture->SetHandled();
720         SelectWindow(select);
721       }
722     } else if (gesture->type() == ui::ET_GESTURE_SCROLL_BEGIN) {
723       if (std::abs(gesture->details().scroll_x_hint()) >
724           std::abs(gesture->details().scroll_y_hint()) * 2) {
725         dragged_start_location_ = gesture->location();
726         dragged_window_ = SelectWindowAt(gesture);
727         if (split_view_controller_->IsSplitViewModeActive() &&
728             (dragged_window_ == split_view_controller_->left_window() ||
729              dragged_window_ == split_view_controller_->right_window())) {
730           // TODO(sad): Allow closing the left/right window. Closing one of
731           // these windows will terminate the split-view mode. Until then, do
732           // not allow closing these (since otherwise it gets into an undefined
733           // state).
734           dragged_window_ = nullptr;
735         }
736
737         if (dragged_window_) {
738           // Show the toolbar (for closing a window, or going into split-view
739           // mode). If already in split-view mode, then do not show the 'Split'
740           // option.
741           overview_toolbar_.reset(new OverviewToolbar(container_));
742           if (!split_view_controller_->CanActivateSplitViewMode()) {
743             overview_toolbar_->DisableAction(
744                 OverviewToolbar::ACTION_TYPE_SPLIT);
745           }
746         }
747       }
748     } else if (gesture->type() == ui::ET_GESTURE_SCROLL_UPDATE) {
749       if (dragged_window_)
750         DragWindow(*gesture);
751       else
752         DoScroll(gesture->details().scroll_y());
753       gesture->SetHandled();
754     } else if (gesture->type() == ui::ET_GESTURE_SCROLL_END) {
755       if (dragged_window_)
756         EndDragWindow(*gesture);
757       gesture->SetHandled();
758     } else if (gesture->type() == ui::ET_SCROLL_FLING_START) {
759       if (dragged_window_) {
760         EndDragWindow(*gesture);
761       } else {
762         CreateFlingerFor(*gesture);
763         AddAnimationObserver();
764       }
765       gesture->SetHandled();
766     } else if (gesture->type() == ui::ET_GESTURE_TAP_DOWN) {
767       if (fling_) {
768         fling_.reset();
769         RemoveAnimationObserver();
770         gesture->SetHandled();
771       }
772       dragged_window_ = nullptr;
773     }
774   }
775
776   // ui::CompositorAnimationObserver:
777   void OnAnimationStep(base::TimeTicks timestamp) override {
778     CHECK(fling_);
779     gfx::Vector2dF delta;
780     bool fling_active = fling_->ComputeScrollDeltaAtTime(timestamp, &delta);
781
782     if (!delta.IsZero())
783       DoScroll(delta.y());
784
785     if (!fling_active) {
786       fling_.reset();
787       RemoveAnimationObserver();
788     }
789   }
790
791   // WindowListProviderObserver:
792   void OnWindowStackingChangedInList() override {
793     // Recompute the states of all windows. There isn't enough information at
794     // this point to do anything more clever.
795     ComputeTerminalStatesForAllWindows();
796     SetInitialWindowStates();
797   }
798
799   void OnWindowAddedToList(aura::Window* removed_window) override {}
800
801   void OnWindowRemovedFromList(aura::Window* removed_window,
802                                int index) override {
803     const aura::Window::Windows& windows =
804         window_list_provider_->GetWindowList();
805     if (windows.empty())
806       return;
807     CHECK_LE(index, static_cast<int>(windows.size()));
808     if (index == 0) {
809       // The back-most window has been removed. Move all the remaining windows
810       // one step backwards.
811       for (int i = windows.size() - 1; i > 0; --i) {
812         UpdateTerminalStateForWindowAtIndex(
813             windows[i], windows.size() - 1 - i, windows.size());
814         AnimateWindowTo(windows[i], windows[i - 1]);
815       }
816       UpdateTerminalStateForWindowAtIndex(windows.front(),
817                                           windows.size() - 1,
818                                           windows.size());
819       AnimateWindowTo(windows.front(), removed_window);
820     } else {
821       // Move all windows behind the removed window one step forwards.
822       for (int i = 0; i < index - 1; ++i) {
823         UpdateTerminalStateForWindowAtIndex(windows[i], windows.size() - 1 - i,
824                                             windows.size());
825         AnimateWindowTo(windows[i], windows[i + 1]);
826       }
827       UpdateTerminalStateForWindowAtIndex(windows[index - 1],
828                                           windows.size() - index,
829                                           windows.size());
830       AnimateWindowTo(windows[index - 1], removed_window);
831     }
832   }
833
834   const int kMinDistanceForDismissal = 300;
835   const float kMaxOpacity = 1.0f;
836   const float kMinOpacity = 0.2f;
837   const float kMaxScaleForSplitTarget = 0.9f;
838
839   aura::Window* container_;
840   // Provider of the stack of windows to show in the overview mode. Not owned.
841   WindowListProvider* window_list_provider_;
842   SplitViewController* split_view_controller_;
843
844   WindowOverviewModeDelegate* delegate_;
845   scoped_ptr<aura::ScopedWindowTargeter> scoped_targeter_;
846   scoped_ptr<ui::FlingCurve> fling_;
847
848   aura::Window* dragged_window_;
849   gfx::Point dragged_start_location_;
850   scoped_ptr<OverviewToolbar> overview_toolbar_;
851
852   DISALLOW_COPY_AND_ASSIGN(WindowOverviewModeImpl);
853 };
854
855 }  // namespace
856
857 // static
858 scoped_ptr<WindowOverviewMode> WindowOverviewMode::Create(
859     aura::Window* container,
860     WindowListProvider* window_list_provider,
861     SplitViewController* split_view_controller,
862     WindowOverviewModeDelegate* delegate) {
863   return scoped_ptr<WindowOverviewMode>(
864       new WindowOverviewModeImpl(container, window_list_provider,
865                                  split_view_controller, delegate));
866 }
867
868 }  // namespace athena