• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 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/window_animations.h"
6 
7 #include <math.h>
8 
9 #include <algorithm>
10 #include <vector>
11 
12 #include "ash/launcher/launcher.h"
13 #include "ash/screen_ash.h"
14 #include "ash/shelf/shelf_layout_manager.h"
15 #include "ash/shelf/shelf_widget.h"
16 #include "ash/shell.h"
17 #include "ash/wm/window_util.h"
18 #include "ash/wm/workspace_controller.h"
19 #include "base/command_line.h"
20 #include "base/compiler_specific.h"
21 #include "base/logging.h"
22 #include "base/message_loop/message_loop.h"
23 #include "base/stl_util.h"
24 #include "base/time/time.h"
25 #include "ui/aura/client/aura_constants.h"
26 #include "ui/aura/window.h"
27 #include "ui/aura/window_observer.h"
28 #include "ui/aura/window_property.h"
29 #include "ui/compositor/compositor_observer.h"
30 #include "ui/compositor/layer.h"
31 #include "ui/compositor/layer_animation_observer.h"
32 #include "ui/compositor/layer_animation_sequence.h"
33 #include "ui/compositor/layer_animator.h"
34 #include "ui/compositor/scoped_layer_animation_settings.h"
35 #include "ui/gfx/interpolated_transform.h"
36 #include "ui/gfx/screen.h"
37 #include "ui/gfx/vector3d_f.h"
38 #include "ui/views/corewm/window_util.h"
39 #include "ui/views/view.h"
40 #include "ui/views/widget/widget.h"
41 
42 namespace ash {
43 namespace {
44 const int kLayerAnimationsForMinimizeDurationMS = 200;
45 
46 // Durations for the cross-fade animation, in milliseconds.
47 const float kCrossFadeDurationMinMs = 200.f;
48 const float kCrossFadeDurationMaxMs = 400.f;
49 
50 // Durations for the brightness/grayscale fade animation, in milliseconds.
51 const int kBrightnessGrayscaleFadeDurationMs = 1000;
52 
53 // Brightness/grayscale values for hide/show window animations.
54 const float kWindowAnimation_HideBrightnessGrayscale = 1.f;
55 const float kWindowAnimation_ShowBrightnessGrayscale = 0.f;
56 
57 const float kWindowAnimation_HideOpacity = 0.f;
58 const float kWindowAnimation_ShowOpacity = 1.f;
59 // TODO(sky): if we end up sticking with 0, nuke the code doing the rotation.
60 const float kWindowAnimation_MinimizeRotate = 0.f;
61 
62 // Scales for AshWindow above/below current workspace.
63 const float kLayerScaleAboveSize = 1.1f;
64 const float kLayerScaleBelowSize = .9f;
65 
Round64(float f)66 int64 Round64(float f) {
67   return static_cast<int64>(f + 0.5f);
68 }
69 
70 }  // namespace
71 
72 const int kCrossFadeDurationMS = 200;
73 
AddLayerAnimationsForMinimize(aura::Window * window,bool show)74 void AddLayerAnimationsForMinimize(aura::Window* window, bool show) {
75   // Recalculate the transform at restore time since the launcher item may have
76   // moved while the window was minimized.
77   gfx::Rect bounds = window->bounds();
78   gfx::Rect target_bounds = GetMinimizeAnimationTargetBoundsInScreen(window);
79   target_bounds =
80       ScreenAsh::ConvertRectFromScreen(window->parent(), target_bounds);
81 
82   float scale_x = static_cast<float>(target_bounds.width()) / bounds.width();
83   float scale_y = static_cast<float>(target_bounds.height()) / bounds.height();
84 
85   scoped_ptr<ui::InterpolatedTransform> scale(
86       new ui::InterpolatedScale(gfx::Point3F(1, 1, 1),
87                                 gfx::Point3F(scale_x, scale_y, 1)));
88 
89   scoped_ptr<ui::InterpolatedTransform> translation(
90       new ui::InterpolatedTranslation(
91           gfx::Point(),
92           gfx::Point(target_bounds.x() - bounds.x(),
93                      target_bounds.y() - bounds.y())));
94 
95   scoped_ptr<ui::InterpolatedTransform> rotation(
96       new ui::InterpolatedRotation(0, kWindowAnimation_MinimizeRotate));
97 
98   scoped_ptr<ui::InterpolatedTransform> rotation_about_pivot(
99       new ui::InterpolatedTransformAboutPivot(
100           gfx::Point(bounds.width() * 0.5, bounds.height() * 0.5),
101           rotation.release()));
102 
103   scale->SetChild(translation.release());
104   rotation_about_pivot->SetChild(scale.release());
105 
106   rotation_about_pivot->SetReversed(show);
107 
108   base::TimeDelta duration = window->layer()->GetAnimator()->
109       GetTransitionDuration();
110 
111   scoped_ptr<ui::LayerAnimationElement> transition(
112       ui::LayerAnimationElement::CreateInterpolatedTransformElement(
113           rotation_about_pivot.release(), duration));
114 
115   transition->set_tween_type(
116       show ? gfx::Tween::EASE_IN : gfx::Tween::EASE_IN_OUT);
117 
118   window->layer()->GetAnimator()->ScheduleAnimation(
119       new ui::LayerAnimationSequence(transition.release()));
120 
121   // When hiding a window, turn off blending until the animation is 3 / 4 done
122   // to save bandwidth and reduce jank.
123   if (!show) {
124     window->layer()->GetAnimator()->SchedulePauseForProperties(
125         (duration * 3) / 4, ui::LayerAnimationElement::OPACITY, -1);
126   }
127 
128   // Fade in and out quickly when the window is small to reduce jank.
129   float opacity = show ? 1.0f : 0.0f;
130   window->layer()->GetAnimator()->ScheduleAnimation(
131       new ui::LayerAnimationSequence(
132           ui::LayerAnimationElement::CreateOpacityElement(
133               opacity, duration / 4)));
134 }
135 
AnimateShowWindow_Minimize(aura::Window * window)136 void AnimateShowWindow_Minimize(aura::Window* window) {
137   window->layer()->set_delegate(window);
138   window->layer()->SetOpacity(kWindowAnimation_HideOpacity);
139   ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
140   base::TimeDelta duration = base::TimeDelta::FromMilliseconds(
141       kLayerAnimationsForMinimizeDurationMS);
142   settings.SetTransitionDuration(duration);
143   AddLayerAnimationsForMinimize(window, true);
144 
145   // Now that the window has been restored, we need to clear its animation style
146   // to default so that normal animation applies.
147   views::corewm::SetWindowVisibilityAnimationType(
148       window, views::corewm::WINDOW_VISIBILITY_ANIMATION_TYPE_DEFAULT);
149 }
150 
AnimateHideWindow_Minimize(aura::Window * window)151 void AnimateHideWindow_Minimize(aura::Window* window) {
152   window->layer()->set_delegate(NULL);
153 
154   // Property sets within this scope will be implicitly animated.
155   ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
156   base::TimeDelta duration = base::TimeDelta::FromMilliseconds(
157       kLayerAnimationsForMinimizeDurationMS);
158   settings.SetTransitionDuration(duration);
159   settings.AddObserver(
160       views::corewm::CreateHidingWindowAnimationObserver(window));
161   window->layer()->SetVisible(false);
162 
163   AddLayerAnimationsForMinimize(window, false);
164 }
165 
AnimateShowHideWindowCommon_BrightnessGrayscale(aura::Window * window,bool show)166 void AnimateShowHideWindowCommon_BrightnessGrayscale(aura::Window* window,
167                                                      bool show) {
168   window->layer()->set_delegate(window);
169 
170   float start_value, end_value;
171   if (show) {
172     start_value = kWindowAnimation_HideBrightnessGrayscale;
173     end_value = kWindowAnimation_ShowBrightnessGrayscale;
174   } else {
175     start_value = kWindowAnimation_ShowBrightnessGrayscale;
176     end_value = kWindowAnimation_HideBrightnessGrayscale;
177   }
178 
179   window->layer()->SetLayerBrightness(start_value);
180   window->layer()->SetLayerGrayscale(start_value);
181   if (show) {
182     window->layer()->SetOpacity(kWindowAnimation_ShowOpacity);
183     window->layer()->SetVisible(true);
184   }
185 
186   base::TimeDelta duration =
187       base::TimeDelta::FromMilliseconds(kBrightnessGrayscaleFadeDurationMs);
188 
189   ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
190   settings.SetTransitionDuration(duration);
191   if (!show) {
192     settings.AddObserver(
193         views::corewm::CreateHidingWindowAnimationObserver(window));
194   }
195 
196   window->layer()->GetAnimator()->
197       ScheduleTogether(
198           CreateBrightnessGrayscaleAnimationSequence(end_value, duration));
199   if (!show) {
200     window->layer()->SetOpacity(kWindowAnimation_HideOpacity);
201     window->layer()->SetVisible(false);
202   }
203 }
204 
AnimateShowWindow_BrightnessGrayscale(aura::Window * window)205 void AnimateShowWindow_BrightnessGrayscale(aura::Window* window) {
206   AnimateShowHideWindowCommon_BrightnessGrayscale(window, true);
207 }
208 
AnimateHideWindow_BrightnessGrayscale(aura::Window * window)209 void AnimateHideWindow_BrightnessGrayscale(aura::Window* window) {
210   AnimateShowHideWindowCommon_BrightnessGrayscale(window, false);
211 }
212 
AnimateShowWindow(aura::Window * window)213 bool AnimateShowWindow(aura::Window* window) {
214   if (!views::corewm::HasWindowVisibilityAnimationTransition(
215           window, views::corewm::ANIMATE_SHOW)) {
216     return false;
217   }
218 
219   switch (views::corewm::GetWindowVisibilityAnimationType(window)) {
220     case WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE:
221       AnimateShowWindow_Minimize(window);
222       return true;
223     case WINDOW_VISIBILITY_ANIMATION_TYPE_BRIGHTNESS_GRAYSCALE:
224       AnimateShowWindow_BrightnessGrayscale(window);
225       return true;
226     default:
227       NOTREACHED();
228       return false;
229   }
230 }
231 
AnimateHideWindow(aura::Window * window)232 bool AnimateHideWindow(aura::Window* window) {
233   if (!views::corewm::HasWindowVisibilityAnimationTransition(
234           window, views::corewm::ANIMATE_HIDE)) {
235     return false;
236   }
237 
238   switch (views::corewm::GetWindowVisibilityAnimationType(window)) {
239     case WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE:
240       AnimateHideWindow_Minimize(window);
241       return true;
242     case WINDOW_VISIBILITY_ANIMATION_TYPE_BRIGHTNESS_GRAYSCALE:
243       AnimateHideWindow_BrightnessGrayscale(window);
244       return true;
245     default:
246       NOTREACHED();
247       return false;
248   }
249 }
250 
251 // Observer for a window cross-fade animation. If either the window closes or
252 // the layer's animation completes or compositing is aborted due to GPU crash,
253 // it deletes the layer and removes itself as an observer.
254 class CrossFadeObserver : public ui::CompositorObserver,
255                           public aura::WindowObserver,
256                           public ui::ImplicitAnimationObserver {
257  public:
258   // Observes |window| for destruction, but does not take ownership.
259   // Takes ownership of |layer| and its child layers.
CrossFadeObserver(aura::Window * window,ui::Layer * layer)260   CrossFadeObserver(aura::Window* window, ui::Layer* layer)
261       : window_(window),
262         layer_(layer) {
263     window_->AddObserver(this);
264     layer_->GetCompositor()->AddObserver(this);
265   }
~CrossFadeObserver()266   virtual ~CrossFadeObserver() {
267     window_->RemoveObserver(this);
268     window_ = NULL;
269     layer_->GetCompositor()->RemoveObserver(this);
270     views::corewm::DeepDeleteLayers(layer_);
271     layer_ = NULL;
272   }
273 
274   // ui::CompositorObserver overrides:
OnCompositingDidCommit(ui::Compositor * compositor)275   virtual void OnCompositingDidCommit(ui::Compositor* compositor) OVERRIDE {
276   }
OnCompositingStarted(ui::Compositor * compositor,base::TimeTicks start_time)277   virtual void OnCompositingStarted(ui::Compositor* compositor,
278                                     base::TimeTicks start_time) OVERRIDE {
279   }
OnCompositingEnded(ui::Compositor * compositor)280   virtual void OnCompositingEnded(ui::Compositor* compositor) OVERRIDE {
281   }
OnCompositingAborted(ui::Compositor * compositor)282   virtual void OnCompositingAborted(ui::Compositor* compositor) OVERRIDE {
283     // Triggers OnImplicitAnimationsCompleted() to be called and deletes us.
284     layer_->GetAnimator()->StopAnimating();
285   }
OnCompositingLockStateChanged(ui::Compositor * compositor)286   virtual void OnCompositingLockStateChanged(
287       ui::Compositor* compositor) OVERRIDE {
288   }
OnUpdateVSyncParameters(ui::Compositor * compositor,base::TimeTicks timebase,base::TimeDelta interval)289   virtual void OnUpdateVSyncParameters(ui::Compositor* compositor,
290                                        base::TimeTicks timebase,
291                                        base::TimeDelta interval) OVERRIDE {
292   }
293 
294   // aura::WindowObserver overrides:
OnWindowDestroying(aura::Window * window)295   virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {
296     // Triggers OnImplicitAnimationsCompleted() to be called and deletes us.
297     layer_->GetAnimator()->StopAnimating();
298   }
OnWindowRemovingFromRootWindow(aura::Window * window)299   virtual void OnWindowRemovingFromRootWindow(aura::Window* window) OVERRIDE {
300     layer_->GetAnimator()->StopAnimating();
301   }
302 
303   // ui::ImplicitAnimationObserver overrides:
OnImplicitAnimationsCompleted()304   virtual void OnImplicitAnimationsCompleted() OVERRIDE {
305     delete this;
306   }
307 
308  private:
309   aura::Window* window_;  // not owned
310   ui::Layer* layer_;  // owned
311 
312   DISALLOW_COPY_AND_ASSIGN(CrossFadeObserver);
313 };
314 
315 // Implementation of cross fading. Window is the window being cross faded. It
316 // should be at the target bounds. |old_layer| the previous layer from |window|.
317 // This takes ownership of |old_layer| and deletes when the animation is done.
318 // |pause_duration| is the duration to pause at the current bounds before
319 // animating. Returns the duration of the fade.
CrossFadeImpl(aura::Window * window,ui::Layer * old_layer,gfx::Tween::Type tween_type)320 base::TimeDelta CrossFadeImpl(aura::Window* window,
321                               ui::Layer* old_layer,
322                               gfx::Tween::Type tween_type) {
323   const gfx::Rect old_bounds(old_layer->bounds());
324   const gfx::Rect new_bounds(window->bounds());
325   const bool old_on_top = (old_bounds.width() > new_bounds.width());
326 
327   // Shorten the animation if there's not much visual movement.
328   const base::TimeDelta duration = GetCrossFadeDuration(window,
329                                                         old_bounds, new_bounds);
330 
331   // Scale up the old layer while translating to new position.
332   {
333     old_layer->GetAnimator()->StopAnimating();
334     ui::ScopedLayerAnimationSettings settings(old_layer->GetAnimator());
335 
336     // Animation observer owns the old layer and deletes itself.
337     settings.AddObserver(new CrossFadeObserver(window, old_layer));
338     settings.SetTransitionDuration(duration);
339     settings.SetTweenType(tween_type);
340     gfx::Transform out_transform;
341     float scale_x = static_cast<float>(new_bounds.width()) /
342         static_cast<float>(old_bounds.width());
343     float scale_y = static_cast<float>(new_bounds.height()) /
344         static_cast<float>(old_bounds.height());
345     out_transform.Translate(new_bounds.x() - old_bounds.x(),
346                             new_bounds.y() - old_bounds.y());
347     out_transform.Scale(scale_x, scale_y);
348     old_layer->SetTransform(out_transform);
349     if (old_on_top) {
350       // The old layer is on top, and should fade out.  The new layer below will
351       // stay opaque to block the desktop.
352       old_layer->SetOpacity(kWindowAnimation_HideOpacity);
353     }
354     // In tests |old_layer| is deleted here, as animations have zero duration.
355     old_layer = NULL;
356   }
357 
358   // Set the new layer's current transform, such that the user sees a scaled
359   // version of the window with the original bounds at the original position.
360   gfx::Transform in_transform;
361   const float scale_x = static_cast<float>(old_bounds.width()) /
362       static_cast<float>(new_bounds.width());
363   const float scale_y = static_cast<float>(old_bounds.height()) /
364       static_cast<float>(new_bounds.height());
365   in_transform.Translate(old_bounds.x() - new_bounds.x(),
366                                old_bounds.y() - new_bounds.y());
367   in_transform.Scale(scale_x, scale_y);
368   window->layer()->SetTransform(in_transform);
369   if (!old_on_top) {
370     // The new layer is on top and should fade in.  The old layer below will
371     // stay opaque and block the desktop.
372     window->layer()->SetOpacity(kWindowAnimation_HideOpacity);
373   }
374   {
375     // Animate the new layer to the identity transform, so the window goes to
376     // its newly set bounds.
377     ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
378     settings.SetTransitionDuration(duration);
379     settings.SetTweenType(tween_type);
380     window->layer()->SetTransform(gfx::Transform());
381     if (!old_on_top) {
382       // New layer is on top, fade it in.
383       window->layer()->SetOpacity(kWindowAnimation_ShowOpacity);
384     }
385   }
386   return duration;
387 }
388 
CrossFadeToBounds(aura::Window * window,const gfx::Rect & new_bounds)389 void CrossFadeToBounds(aura::Window* window, const gfx::Rect& new_bounds) {
390   // Some test results in invoking CrossFadeToBounds when window is not visible.
391   // No animation is necessary in that case, thus just change the bounds and
392   // quit.
393   if (!window->TargetVisibility()) {
394     window->SetBounds(new_bounds);
395     return;
396   }
397 
398   const gfx::Rect old_bounds = window->bounds();
399 
400   // Create fresh layers for the window and all its children to paint into.
401   // Takes ownership of the old layer and all its children, which will be
402   // cleaned up after the animation completes.
403   // Specify |set_bounds| to true here to keep the old bounds in the child
404   // windows of |window|.
405   ui::Layer* old_layer = views::corewm::RecreateWindowLayers(window, true);
406   ui::Layer* new_layer = window->layer();
407 
408   // Resize the window to the new size, which will force a layout and paint.
409   window->SetBounds(new_bounds);
410 
411   // Ensure the higher-resolution layer is on top.
412   bool old_on_top = (old_bounds.width() > new_bounds.width());
413   if (old_on_top)
414     old_layer->parent()->StackBelow(new_layer, old_layer);
415   else
416     old_layer->parent()->StackAbove(new_layer, old_layer);
417 
418   CrossFadeImpl(window, old_layer, gfx::Tween::EASE_OUT);
419 }
420 
GetCrossFadeDuration(aura::Window * window,const gfx::Rect & old_bounds,const gfx::Rect & new_bounds)421 base::TimeDelta GetCrossFadeDuration(aura::Window* window,
422                                      const gfx::Rect& old_bounds,
423                                      const gfx::Rect& new_bounds) {
424   if (views::corewm::WindowAnimationsDisabled(window))
425     return base::TimeDelta();
426 
427   int old_area = old_bounds.width() * old_bounds.height();
428   int new_area = new_bounds.width() * new_bounds.height();
429   int max_area = std::max(old_area, new_area);
430   // Avoid divide by zero.
431   if (max_area == 0)
432     return base::TimeDelta::FromMilliseconds(kCrossFadeDurationMS);
433 
434   int delta_area = std::abs(old_area - new_area);
435   // If the area didn't change, the animation is instantaneous.
436   if (delta_area == 0)
437     return base::TimeDelta::FromMilliseconds(kCrossFadeDurationMS);
438 
439   float factor =
440       static_cast<float>(delta_area) / static_cast<float>(max_area);
441   const float kRange = kCrossFadeDurationMaxMs - kCrossFadeDurationMinMs;
442   return base::TimeDelta::FromMilliseconds(
443       Round64(kCrossFadeDurationMinMs + (factor * kRange)));
444 }
445 
AnimateOnChildWindowVisibilityChanged(aura::Window * window,bool visible)446 bool AnimateOnChildWindowVisibilityChanged(aura::Window* window, bool visible) {
447   if (views::corewm::WindowAnimationsDisabled(window))
448     return false;
449 
450   // Attempt to run CoreWm supplied animation types.
451   if (views::corewm::AnimateOnChildWindowVisibilityChanged(window, visible))
452     return true;
453 
454   // Otherwise try to run an Ash-specific animation.
455   if (visible)
456     return AnimateShowWindow(window);
457   // Don't start hiding the window again if it's already being hidden.
458   return window->layer()->GetTargetOpacity() != 0.0f &&
459       AnimateHideWindow(window);
460 }
461 
462 std::vector<ui::LayerAnimationSequence*>
CreateBrightnessGrayscaleAnimationSequence(float target_value,base::TimeDelta duration)463 CreateBrightnessGrayscaleAnimationSequence(float target_value,
464                                            base::TimeDelta duration) {
465   gfx::Tween::Type animation_type = gfx::Tween::EASE_OUT;
466   scoped_ptr<ui::LayerAnimationSequence> brightness_sequence(
467       new ui::LayerAnimationSequence());
468   scoped_ptr<ui::LayerAnimationSequence> grayscale_sequence(
469       new ui::LayerAnimationSequence());
470 
471   scoped_ptr<ui::LayerAnimationElement> brightness_element(
472       ui::LayerAnimationElement::CreateBrightnessElement(
473           target_value, duration));
474   brightness_element->set_tween_type(animation_type);
475   brightness_sequence->AddElement(brightness_element.release());
476 
477   scoped_ptr<ui::LayerAnimationElement> grayscale_element(
478       ui::LayerAnimationElement::CreateGrayscaleElement(
479           target_value, duration));
480   grayscale_element->set_tween_type(animation_type);
481   grayscale_sequence->AddElement(grayscale_element.release());
482 
483   std::vector<ui::LayerAnimationSequence*> animations;
484   animations.push_back(brightness_sequence.release());
485   animations.push_back(grayscale_sequence.release());
486 
487   return animations;
488 }
489 
490 // Returns scale related to the specified AshWindowScaleType.
SetTransformForScaleAnimation(ui::Layer * layer,LayerScaleAnimationDirection type)491 void SetTransformForScaleAnimation(ui::Layer* layer,
492                                    LayerScaleAnimationDirection type) {
493   const float scale =
494       type == LAYER_SCALE_ANIMATION_ABOVE ? kLayerScaleAboveSize :
495           kLayerScaleBelowSize;
496   gfx::Transform transform;
497   transform.Translate(-layer->bounds().width() * (scale - 1.0f) / 2,
498                       -layer->bounds().height() * (scale - 1.0f) / 2);
499   transform.Scale(scale, scale);
500   layer->SetTransform(transform);
501 }
502 
GetMinimizeAnimationTargetBoundsInScreen(aura::Window * window)503 gfx::Rect GetMinimizeAnimationTargetBoundsInScreen(aura::Window* window) {
504   Launcher* launcher = Launcher::ForWindow(window);
505   // Shelf is created lazily and can be NULL.
506   if (!launcher)
507     return gfx::Rect();
508   gfx::Rect item_rect = launcher->GetScreenBoundsOfItemIconForWindow(window);
509 
510   // The launcher item is visible and has an icon.
511   if (!item_rect.IsEmpty())
512     return item_rect;
513 
514   // If both the icon width and height are 0, then there is no icon in the
515   // launcher for |window| or the icon is hidden in the overflow menu. If the
516   // launcher is auto hidden, one of the height or width will be 0 but the
517   // position in the launcher and the major dimension are still reported
518   // correctly and the window can be animated to the launcher item's light
519   // bar.
520   if (item_rect.width() != 0 || item_rect.height() != 0) {
521     internal::ShelfLayoutManager* layout_manager =
522         internal::ShelfLayoutManager::ForLauncher(window);
523     if (layout_manager->visibility_state() == SHELF_AUTO_HIDE) {
524       gfx::Rect shelf_bounds =
525           launcher->shelf_widget()->GetWindowBoundsInScreen();
526       switch (layout_manager->GetAlignment()) {
527         case SHELF_ALIGNMENT_BOTTOM:
528           item_rect.set_y(shelf_bounds.y());
529           break;
530         case SHELF_ALIGNMENT_LEFT:
531           item_rect.set_x(shelf_bounds.right());
532           break;
533         case SHELF_ALIGNMENT_RIGHT:
534           item_rect.set_x(shelf_bounds.x());
535           break;
536         case SHELF_ALIGNMENT_TOP:
537           item_rect.set_y(shelf_bounds.bottom());
538           break;
539       }
540       return item_rect;
541     }
542   }
543 
544   // Assume the launcher is overflowed, zoom off to the bottom right of the
545   // work area.
546   gfx::Rect work_area =
547       Shell::GetScreen()->GetDisplayNearestWindow(window).work_area();
548   return gfx::Rect(work_area.right(), work_area.bottom(), 0, 0);
549 }
550 
551 }  // namespace ash
552