- add sources.
[platform/framework/web/crosswalk.git] / src / ash / wm / workspace / workspace_window_resizer_unittest.cc
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/workspace/workspace_window_resizer.h"
6
7 #include "ash/ash_constants.h"
8 #include "ash/ash_switches.h"
9 #include "ash/display/display_manager.h"
10 #include "ash/root_window_controller.h"
11 #include "ash/screen_ash.h"
12 #include "ash/shelf/shelf_layout_manager.h"
13 #include "ash/shell.h"
14 #include "ash/shell_window_ids.h"
15 #include "ash/test/ash_test_base.h"
16 #include "ash/wm/window_state.h"
17 #include "ash/wm/window_util.h"
18 #include "ash/wm/workspace/phantom_window_controller.h"
19 #include "ash/wm/workspace/snap_sizer.h"
20 #include "ash/wm/workspace_controller.h"
21 #include "base/command_line.h"
22 #include "base/strings/string_number_conversions.h"
23 #include "base/strings/stringprintf.h"
24 #include "ui/aura/client/aura_constants.h"
25 #include "ui/aura/root_window.h"
26 #include "ui/aura/test/event_generator.h"
27 #include "ui/aura/test/test_window_delegate.h"
28 #include "ui/base/hit_test.h"
29 #include "ui/gfx/insets.h"
30 #include "ui/gfx/screen.h"
31 #include "ui/views/widget/widget.h"
32
33 namespace gfx {
34
35 // Class to provide access to SlideAnimation internals for testing.
36 // TODO: this should be next to SlideAnimation, not here.
37 class SlideAnimation::TestApi {
38  public:
39   explicit TestApi(SlideAnimation* animation) : animation_(animation) {}
40
41   void SetStartTime(base::TimeTicks ticks) {
42     animation_->SetStartTime(ticks);
43   }
44
45   void Step(base::TimeTicks ticks) {
46     animation_->Step(ticks);
47   }
48
49   void RunTillComplete() {
50     SetStartTime(base::TimeTicks());
51     Step(base::TimeTicks() +
52          base::TimeDelta::FromMilliseconds(animation_->GetSlideDuration()));
53     EXPECT_EQ(1.0, animation_->GetCurrentValue());
54   }
55
56  private:
57   SlideAnimation* animation_;
58
59   DISALLOW_COPY_AND_ASSIGN(TestApi);
60 };
61
62 }
63
64 namespace ash {
65 namespace internal {
66 namespace {
67
68 const int kRootHeight = 600;
69
70 // A simple window delegate that returns the specified min size.
71 class TestWindowDelegate : public aura::test::TestWindowDelegate {
72  public:
73   TestWindowDelegate() {
74   }
75   virtual ~TestWindowDelegate() {}
76
77   void set_min_size(const gfx::Size& size) {
78     min_size_ = size;
79   }
80
81   void set_max_size(const gfx::Size& size) {
82     max_size_ = size;
83   }
84
85  private:
86   // Overridden from aura::Test::TestWindowDelegate:
87   virtual gfx::Size GetMinimumSize() const OVERRIDE {
88     return min_size_;
89   }
90
91   virtual gfx::Size GetMaximumSize() const OVERRIDE {
92     return max_size_;
93   }
94
95   gfx::Size min_size_;
96   gfx::Size max_size_;
97
98   DISALLOW_COPY_AND_ASSIGN(TestWindowDelegate);
99 };
100
101 class WorkspaceWindowResizerTest : public test::AshTestBase {
102  public:
103   WorkspaceWindowResizerTest() {}
104   virtual ~WorkspaceWindowResizerTest() {}
105
106   virtual void SetUp() OVERRIDE {
107     AshTestBase::SetUp();
108     UpdateDisplay(base::StringPrintf("800x%d", kRootHeight));
109
110     aura::Window* root = Shell::GetPrimaryRootWindow();
111     gfx::Rect root_bounds(root->bounds());
112 #if defined(OS_WIN)
113     // RootWindow and Display can't resize on Windows Ash.
114     // http://crbug.com/165962
115     EXPECT_EQ(kRootHeight, root_bounds.height());
116 #endif
117     EXPECT_EQ(800, root_bounds.width());
118     Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets());
119     window_.reset(new aura::Window(&delegate_));
120     window_->SetType(aura::client::WINDOW_TYPE_NORMAL);
121     window_->Init(ui::LAYER_NOT_DRAWN);
122     ParentWindowInPrimaryRootWindow(window_.get());
123     window_->set_id(1);
124
125     window2_.reset(new aura::Window(&delegate2_));
126     window2_->SetType(aura::client::WINDOW_TYPE_NORMAL);
127     window2_->Init(ui::LAYER_NOT_DRAWN);
128     ParentWindowInPrimaryRootWindow(window2_.get());
129     window2_->set_id(2);
130
131     window3_.reset(new aura::Window(&delegate3_));
132     window3_->SetType(aura::client::WINDOW_TYPE_NORMAL);
133     window3_->Init(ui::LAYER_NOT_DRAWN);
134     ParentWindowInPrimaryRootWindow(window3_.get());
135     window3_->set_id(3);
136
137     window4_.reset(new aura::Window(&delegate4_));
138     window4_->SetType(aura::client::WINDOW_TYPE_NORMAL);
139     window4_->Init(ui::LAYER_NOT_DRAWN);
140     ParentWindowInPrimaryRootWindow(window4_.get());
141     window4_->set_id(4);
142   }
143
144   virtual void TearDown() OVERRIDE {
145     window_.reset();
146     window2_.reset();
147     window3_.reset();
148     window4_.reset();
149     touch_resize_window_.reset();
150     AshTestBase::TearDown();
151   }
152
153   // Returns a string identifying the z-order of each of the known child windows
154   // of |parent|.  The returned string constains the id of the known windows and
155   // is ordered from topmost to bottomost windows.
156   std::string WindowOrderAsString(aura::Window* parent) const {
157     std::string result;
158     const aura::Window::Windows& windows = parent->children();
159     for (aura::Window::Windows::const_reverse_iterator i = windows.rbegin();
160          i != windows.rend(); ++i) {
161       if (*i == window_ || *i == window2_ || *i == window3_) {
162         if (!result.empty())
163           result += " ";
164         result += base::IntToString((*i)->id());
165       }
166     }
167     return result;
168   }
169
170  protected:
171   gfx::Point CalculateDragPoint(const WorkspaceWindowResizer& resizer,
172                                 int delta_x,
173                                 int delta_y) const {
174     gfx::Point location = resizer.GetInitialLocation();
175     location.set_x(location.x() + delta_x);
176     location.set_y(location.y() + delta_y);
177     return location;
178   }
179
180   std::vector<aura::Window*> empty_windows() const {
181     return std::vector<aura::Window*>();
182   }
183
184   internal::ShelfLayoutManager* shelf_layout_manager() {
185     return Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager();
186   }
187
188   void InitTouchResizeWindow(const gfx::Rect& bounds, int window_component) {
189     touch_resize_delegate_.set_window_component(window_component);
190     touch_resize_window_.reset(
191         CreateTestWindowInShellWithDelegate(&touch_resize_delegate_, 0,
192                                             bounds));
193     gfx::Insets mouse_outer_insets(-ash::kResizeOutsideBoundsSize,
194                                    -ash::kResizeOutsideBoundsSize,
195                                    -ash::kResizeOutsideBoundsSize,
196                                    -ash::kResizeOutsideBoundsSize);
197     gfx::Insets touch_outer_insets = mouse_outer_insets.Scale(
198         ash::kResizeOutsideBoundsScaleForTouch);
199     touch_resize_window_->SetHitTestBoundsOverrideOuter(mouse_outer_insets,
200                                                         touch_outer_insets);
201   }
202
203   // Simulate running the animation.
204   void RunAnimationTillComplete(gfx::SlideAnimation* animation) {
205     gfx::SlideAnimation::TestApi test_api(animation);
206     test_api.RunTillComplete();
207   }
208
209   TestWindowDelegate delegate_;
210   TestWindowDelegate delegate2_;
211   TestWindowDelegate delegate3_;
212   TestWindowDelegate delegate4_;
213   scoped_ptr<aura::Window> window_;
214   scoped_ptr<aura::Window> window2_;
215   scoped_ptr<aura::Window> window3_;
216   scoped_ptr<aura::Window> window4_;
217
218   TestWindowDelegate touch_resize_delegate_;
219   scoped_ptr<aura::Window> touch_resize_window_;
220
221  private:
222   DISALLOW_COPY_AND_ASSIGN(WorkspaceWindowResizerTest);
223 };
224
225 class WorkspaceWindowResizerTestSticky : public WorkspaceWindowResizerTest {
226  public:
227   WorkspaceWindowResizerTestSticky() {}
228   virtual ~WorkspaceWindowResizerTestSticky() {}
229
230   virtual void SetUp() OVERRIDE {
231     CommandLine::ForCurrentProcess()->AppendSwitch(
232         ash::switches::kAshEnableStickyEdges);
233     WorkspaceWindowResizerTest::SetUp();
234   }
235
236  private:
237   DISALLOW_COPY_AND_ASSIGN(WorkspaceWindowResizerTestSticky);
238 };
239
240 }  // namespace
241
242 // Assertions around attached window resize dragging from the right with 2
243 // windows.
244 TEST_F(WorkspaceWindowResizerTest, AttachedResize_RIGHT_2) {
245   window_->SetBounds(gfx::Rect(0, 300, 400, 300));
246   window2_->SetBounds(gfx::Rect(400, 200, 100, 200));
247
248   std::vector<aura::Window*> windows;
249   windows.push_back(window2_.get());
250   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
251       window_.get(), gfx::Point(), HTRIGHT,
252       aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows));
253   ASSERT_TRUE(resizer.get());
254   // Move it 100 to the right, which should expand w1 and push w2.
255   resizer->Drag(CalculateDragPoint(*resizer, 100, 10), 0);
256   EXPECT_EQ("0,300 500x300", window_->bounds().ToString());
257   EXPECT_EQ("500,200 100x200", window2_->bounds().ToString());
258
259   // Push off the screen, w2 should be resized to its min.
260   delegate2_.set_min_size(gfx::Size(20, 20));
261   resizer->Drag(CalculateDragPoint(*resizer, 800, 20), 0);
262   EXPECT_EQ("0,300 780x300", window_->bounds().ToString());
263   EXPECT_EQ("780,200 20x200", window2_->bounds().ToString());
264
265   // Move back to 100 and verify w2 gets its original size.
266   resizer->Drag(CalculateDragPoint(*resizer, 100, 10), 0);
267   EXPECT_EQ("0,300 500x300", window_->bounds().ToString());
268   EXPECT_EQ("500,200 100x200", window2_->bounds().ToString());
269
270   // Revert and make sure everything moves back.
271   resizer->Drag(CalculateDragPoint(*resizer, 800, 20), 0);
272   resizer->RevertDrag();
273   EXPECT_EQ("0,300 400x300", window_->bounds().ToString());
274   EXPECT_EQ("400,200 100x200", window2_->bounds().ToString());
275 }
276
277 // Assertions around collapsing and expanding.
278 TEST_F(WorkspaceWindowResizerTest, AttachedResize_RIGHT_Compress) {
279   window_->SetBounds(gfx::Rect(   0, 300, 400, 300));
280   window2_->SetBounds(gfx::Rect(400, 200, 100, 200));
281
282   std::vector<aura::Window*> windows;
283   windows.push_back(window2_.get());
284   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
285       window_.get(), gfx::Point(), HTRIGHT,
286       aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows));
287   ASSERT_TRUE(resizer.get());
288   // Move it 100 to the left, which should expand w2 and collapse w1.
289   resizer->Drag(CalculateDragPoint(*resizer, -100, 10), 0);
290   EXPECT_EQ("0,300 300x300", window_->bounds().ToString());
291   EXPECT_EQ("300,200 200x200", window2_->bounds().ToString());
292
293   // Collapse all the way to w1's min.
294   delegate_.set_min_size(gfx::Size(20, 20));
295   resizer->Drag(CalculateDragPoint(*resizer, -800, 20), 0);
296   EXPECT_EQ("0,300 20x300", window_->bounds().ToString());
297   EXPECT_EQ("20,200 480x200", window2_->bounds().ToString());
298
299   // Move 100 to the left.
300   resizer->Drag(CalculateDragPoint(*resizer, 100, 10), 0);
301   EXPECT_EQ("0,300 500x300", window_->bounds().ToString());
302   EXPECT_EQ("500,200 100x200", window2_->bounds().ToString());
303
304   // Back to -100.
305   resizer->Drag(CalculateDragPoint(*resizer, -100, 20), 0);
306   EXPECT_EQ("0,300 300x300", window_->bounds().ToString());
307   EXPECT_EQ("300,200 200x200", window2_->bounds().ToString());
308 }
309
310 // Assertions around attached window resize dragging from the right with 3
311 // windows.
312 TEST_F(WorkspaceWindowResizerTest, AttachedResize_RIGHT_3) {
313   window_->SetBounds(gfx::Rect( 100, 300, 200, 300));
314   window2_->SetBounds(gfx::Rect(300, 300, 150, 200));
315   window3_->SetBounds(gfx::Rect(450, 300, 100, 200));
316   delegate2_.set_min_size(gfx::Size(52, 50));
317   delegate3_.set_min_size(gfx::Size(38, 50));
318
319   std::vector<aura::Window*> windows;
320   windows.push_back(window2_.get());
321   windows.push_back(window3_.get());
322   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
323       window_.get(), gfx::Point(), HTRIGHT,
324       aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows));
325   ASSERT_TRUE(resizer.get());
326   // Move it 100 to the right, which should expand w1 and push w2 and w3.
327   resizer->Drag(CalculateDragPoint(*resizer, 100, -10), 0);
328   EXPECT_EQ("100,300 300x300", window_->bounds().ToString());
329   EXPECT_EQ("400,300 150x200", window2_->bounds().ToString());
330   EXPECT_EQ("550,300 100x200", window3_->bounds().ToString());
331
332   // Move it 300, things should compress.
333   resizer->Drag(CalculateDragPoint(*resizer, 300, -10), 0);
334   EXPECT_EQ("100,300 500x300", window_->bounds().ToString());
335   EXPECT_EQ("600,300 120x200", window2_->bounds().ToString());
336   EXPECT_EQ("720,300 80x200", window3_->bounds().ToString());
337
338   // Move it so much the last two end up at their min.
339   resizer->Drag(CalculateDragPoint(*resizer, 800, 50), 0);
340   EXPECT_EQ("100,300 610x300", window_->bounds().ToString());
341   EXPECT_EQ("710,300 52x200", window2_->bounds().ToString());
342   EXPECT_EQ("762,300 38x200", window3_->bounds().ToString());
343
344   // Revert and make sure everything moves back.
345   resizer->RevertDrag();
346   EXPECT_EQ("100,300 200x300", window_->bounds().ToString());
347   EXPECT_EQ("300,300 150x200", window2_->bounds().ToString());
348   EXPECT_EQ("450,300 100x200", window3_->bounds().ToString());
349 }
350
351 // Assertions around attached window resizing (collapsing and expanding) with
352 // 3 windows.
353 TEST_F(WorkspaceWindowResizerTest, AttachedResize_RIGHT_3_Compress) {
354   window_->SetBounds(gfx::Rect( 100, 300, 200, 300));
355   window2_->SetBounds(gfx::Rect(300, 300, 200, 200));
356   window3_->SetBounds(gfx::Rect(450, 300, 100, 200));
357   delegate2_.set_min_size(gfx::Size(52, 50));
358   delegate3_.set_min_size(gfx::Size(38, 50));
359
360   std::vector<aura::Window*> windows;
361   windows.push_back(window2_.get());
362   windows.push_back(window3_.get());
363   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
364       window_.get(), gfx::Point(), HTRIGHT,
365       aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows));
366   ASSERT_TRUE(resizer.get());
367   // Move it -100 to the right, which should collapse w1 and expand w2 and w3.
368   resizer->Drag(CalculateDragPoint(*resizer, -100, -10), 0);
369   EXPECT_EQ("100,300 100x300", window_->bounds().ToString());
370   EXPECT_EQ("200,300 266x200", window2_->bounds().ToString());
371   EXPECT_EQ("466,300 134x200", window3_->bounds().ToString());
372
373   // Move it 100 to the right.
374   resizer->Drag(CalculateDragPoint(*resizer, 100, -10), 0);
375   EXPECT_EQ("100,300 300x300", window_->bounds().ToString());
376   EXPECT_EQ("400,300 200x200", window2_->bounds().ToString());
377   EXPECT_EQ("600,300 100x200", window3_->bounds().ToString());
378
379   // 100 to the left again.
380   resizer->Drag(CalculateDragPoint(*resizer, -100, -10), 0);
381   EXPECT_EQ("100,300 100x300", window_->bounds().ToString());
382   EXPECT_EQ("200,300 266x200", window2_->bounds().ToString());
383   EXPECT_EQ("466,300 134x200", window3_->bounds().ToString());
384 }
385
386 // Assertions around collapsing and expanding from the bottom.
387 TEST_F(WorkspaceWindowResizerTest, AttachedResize_BOTTOM_Compress) {
388   window_->SetBounds(gfx::Rect(   0, 100, 400, 300));
389   window2_->SetBounds(gfx::Rect(400, 400, 100, 200));
390
391   std::vector<aura::Window*> windows;
392   windows.push_back(window2_.get());
393   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
394       window_.get(), gfx::Point(), HTBOTTOM,
395       aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows));
396   ASSERT_TRUE(resizer.get());
397   // Move it up 100, which should expand w2 and collapse w1.
398   resizer->Drag(CalculateDragPoint(*resizer, 10, -100), 0);
399   EXPECT_EQ("0,100 400x200", window_->bounds().ToString());
400   EXPECT_EQ("400,300 100x300", window2_->bounds().ToString());
401
402   // Collapse all the way to w1's min.
403   delegate_.set_min_size(gfx::Size(20, 20));
404   resizer->Drag(CalculateDragPoint(*resizer, 20, -800), 0);
405   EXPECT_EQ("0,100 400x20", window_->bounds().ToString());
406   EXPECT_EQ("400,120 100x480", window2_->bounds().ToString());
407
408   // Move 100 down.
409   resizer->Drag(CalculateDragPoint(*resizer, 10, 100), 0);
410   EXPECT_EQ("0,100 400x400", window_->bounds().ToString());
411   EXPECT_EQ("400,500 100x100", window2_->bounds().ToString());
412
413   // Back to -100.
414   resizer->Drag(CalculateDragPoint(*resizer, 20, -100), 0);
415   EXPECT_EQ("0,100 400x200", window_->bounds().ToString());
416   EXPECT_EQ("400,300 100x300", window2_->bounds().ToString());
417 }
418
419 // Assertions around attached window resize dragging from the bottom with 2
420 // windows.
421 TEST_F(WorkspaceWindowResizerTest, AttachedResize_BOTTOM_2) {
422   window_->SetBounds(gfx::Rect( 0,  50, 400, 200));
423   window2_->SetBounds(gfx::Rect(0, 250, 200, 100));
424
425   std::vector<aura::Window*> windows;
426   windows.push_back(window2_.get());
427   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
428       window_.get(), gfx::Point(), HTBOTTOM,
429       aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows));
430   ASSERT_TRUE(resizer.get());
431   // Move it 100 to the bottom, which should expand w1 and push w2.
432   resizer->Drag(CalculateDragPoint(*resizer, 10, 100), 0);
433   EXPECT_EQ("0,50 400x300", window_->bounds().ToString());
434   EXPECT_EQ("0,350 200x100", window2_->bounds().ToString());
435
436   // Push off the screen, w2 should be resized to its min.
437   delegate2_.set_min_size(gfx::Size(20, 20));
438   resizer->Drag(CalculateDragPoint(*resizer, 50, 820), 0);
439   EXPECT_EQ("0,50 400x530", window_->bounds().ToString());
440   EXPECT_EQ("0,580 200x20", window2_->bounds().ToString());
441
442   // Move back to 100 and verify w2 gets its original size.
443   resizer->Drag(CalculateDragPoint(*resizer, 10, 100), 0);
444   EXPECT_EQ("0,50 400x300", window_->bounds().ToString());
445   EXPECT_EQ("0,350 200x100", window2_->bounds().ToString());
446
447   // Revert and make sure everything moves back.
448   resizer->Drag(CalculateDragPoint(*resizer, 800, 20), 0);
449   resizer->RevertDrag();
450   EXPECT_EQ("0,50 400x200", window_->bounds().ToString());
451   EXPECT_EQ("0,250 200x100", window2_->bounds().ToString());
452 }
453
454 #if defined(OS_WIN)
455 // RootWindow and Display can't resize on Windows Ash. http://crbug.com/165962
456 #define MAYBE_AttachedResize_BOTTOM_3 DISABLED_AttachedResize_BOTTOM_3
457 #else
458 #define MAYBE_AttachedResize_BOTTOM_3 AttachedResize_BOTTOM_3
459 #endif
460
461 // Assertions around attached window resize dragging from the bottom with 3
462 // windows.
463 TEST_F(WorkspaceWindowResizerTest, MAYBE_AttachedResize_BOTTOM_3) {
464   UpdateDisplay("600x800");
465   aura::Window* root = Shell::GetPrimaryRootWindow();
466   Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets());
467
468   window_->SetBounds(gfx::Rect( 300, 100, 300, 200));
469   window2_->SetBounds(gfx::Rect(300, 300, 200, 150));
470   window3_->SetBounds(gfx::Rect(300, 450, 200, 100));
471   delegate2_.set_min_size(gfx::Size(50, 52));
472   delegate3_.set_min_size(gfx::Size(50, 38));
473
474   std::vector<aura::Window*> windows;
475   windows.push_back(window2_.get());
476   windows.push_back(window3_.get());
477   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
478       window_.get(), gfx::Point(), HTBOTTOM,
479       aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows));
480   ASSERT_TRUE(resizer.get());
481   // Move it 100 down, which should expand w1 and push w2 and w3.
482   resizer->Drag(CalculateDragPoint(*resizer, -10, 100), 0);
483   EXPECT_EQ("300,100 300x300", window_->bounds().ToString());
484   EXPECT_EQ("300,400 200x150", window2_->bounds().ToString());
485   EXPECT_EQ("300,550 200x100", window3_->bounds().ToString());
486
487   // Move it 296 things should compress.
488   resizer->Drag(CalculateDragPoint(*resizer, -10, 296), 0);
489   EXPECT_EQ("300,100 300x496", window_->bounds().ToString());
490   EXPECT_EQ("300,596 200x123", window2_->bounds().ToString());
491   EXPECT_EQ("300,719 200x81", window3_->bounds().ToString());
492
493   // Move it so much everything ends up at its min.
494   resizer->Drag(CalculateDragPoint(*resizer, 50, 798), 0);
495   EXPECT_EQ("300,100 300x610", window_->bounds().ToString());
496   EXPECT_EQ("300,710 200x52", window2_->bounds().ToString());
497   EXPECT_EQ("300,762 200x38", window3_->bounds().ToString());
498
499   // Revert and make sure everything moves back.
500   resizer->RevertDrag();
501   EXPECT_EQ("300,100 300x200", window_->bounds().ToString());
502   EXPECT_EQ("300,300 200x150", window2_->bounds().ToString());
503   EXPECT_EQ("300,450 200x100", window3_->bounds().ToString());
504 }
505
506 // Assertions around attached window resizing (collapsing and expanding) with
507 // 3 windows.
508 TEST_F(WorkspaceWindowResizerTest, AttachedResize_BOTTOM_3_Compress) {
509   window_->SetBounds(gfx::Rect(  0,   0, 200, 200));
510   window2_->SetBounds(gfx::Rect(10, 200, 200, 200));
511   window3_->SetBounds(gfx::Rect(20, 400, 100, 100));
512   delegate2_.set_min_size(gfx::Size(52, 50));
513   delegate3_.set_min_size(gfx::Size(38, 50));
514
515   std::vector<aura::Window*> windows;
516   windows.push_back(window2_.get());
517   windows.push_back(window3_.get());
518   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
519       window_.get(), gfx::Point(), HTBOTTOM,
520       aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows));
521   ASSERT_TRUE(resizer.get());
522   // Move it 100 up, which should collapse w1 and expand w2 and w3.
523   resizer->Drag(CalculateDragPoint(*resizer, -10, -100), 0);
524   EXPECT_EQ("0,0 200x100", window_->bounds().ToString());
525   EXPECT_EQ("10,100 200x266", window2_->bounds().ToString());
526   EXPECT_EQ("20,366 100x134", window3_->bounds().ToString());
527
528   // Move it 100 down.
529   resizer->Drag(CalculateDragPoint(*resizer, 10, 100), 0);
530   EXPECT_EQ("0,0 200x300", window_->bounds().ToString());
531   EXPECT_EQ("10,300 200x200", window2_->bounds().ToString());
532   EXPECT_EQ("20,500 100x100", window3_->bounds().ToString());
533
534   // 100 up again.
535   resizer->Drag(CalculateDragPoint(*resizer, -10, -100), 0);
536   EXPECT_EQ("0,0 200x100", window_->bounds().ToString());
537   EXPECT_EQ("10,100 200x266", window2_->bounds().ToString());
538   EXPECT_EQ("20,366 100x134", window3_->bounds().ToString());
539 }
540
541
542 // Assertions around dragging to the left/right edge of the screen.
543 TEST_F(WorkspaceWindowResizerTest, Edge) {
544   int bottom =
545       ScreenAsh::GetDisplayWorkAreaBoundsInParent(window_.get()).bottom();
546   window_->SetBounds(gfx::Rect(20, 30, 50, 60));
547   wm::WindowState* window_state = wm::GetWindowState(window_.get());
548
549   {
550     scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
551         window_.get(), gfx::Point(), HTCAPTION,
552         aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
553     ASSERT_TRUE(resizer.get());
554     resizer->Drag(CalculateDragPoint(*resizer, 0, 10), 0);
555     resizer->CompleteDrag(0);
556     EXPECT_EQ("0,0 720x" + base::IntToString(bottom),
557               window_->bounds().ToString());
558     ASSERT_TRUE(window_state->HasRestoreBounds());
559     EXPECT_EQ("20,30 50x60",
560               window_state->GetRestoreBoundsInScreen().ToString());
561   }
562   // Try the same with the right side.
563   {
564     scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
565         window_.get(), gfx::Point(), HTCAPTION,
566         aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
567     ASSERT_TRUE(resizer.get());
568     resizer->Drag(CalculateDragPoint(*resizer, 800, 10), 0);
569     resizer->CompleteDrag(0);
570     EXPECT_EQ("80,0 720x" + base::IntToString(bottom),
571               window_->bounds().ToString());
572     ASSERT_TRUE(window_state->HasRestoreBounds());
573     EXPECT_EQ("20,30 50x60",
574               window_state->GetRestoreBoundsInScreen().ToString());
575   }
576
577   // Test if the restore bounds is correct in multiple displays.
578   window_state->ClearRestoreBounds();
579
580   if (!SupportsMultipleDisplays())
581     return;
582
583   UpdateDisplay("800x600,200x600");
584   Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
585   EXPECT_EQ(root_windows[0], window_->GetRootWindow());
586   window_->SetBoundsInScreen(gfx::Rect(800, 10, 50, 60),
587                              ScreenAsh::GetSecondaryDisplay());
588   EXPECT_EQ(root_windows[1], window_->GetRootWindow());
589   {
590     bottom =
591         ScreenAsh::GetDisplayWorkAreaBoundsInParent(window_.get()).bottom();
592     EXPECT_EQ("800,10 50x60", window_->GetBoundsInScreen().ToString());
593
594     scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
595         window_.get(), gfx::Point(), HTCAPTION,
596         aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
597     ASSERT_TRUE(resizer.get());
598
599     resizer->Drag(CalculateDragPoint(*resizer, 199, 00), 0);
600     resizer->CompleteDrag(0);
601     // With the resolution of 200x600 we will hit in this case the 50% screen
602     // size setting.
603     EXPECT_EQ("100,0 100x" + base::IntToString(bottom),
604               window_->bounds().ToString());
605     EXPECT_EQ("800,10 50x60",
606               window_state->GetRestoreBoundsInScreen().ToString());
607   }
608 }
609
610 // Check that non resizable windows will not get resized.
611 TEST_F(WorkspaceWindowResizerTest, NonResizableWindows) {
612   window_->SetBounds(gfx::Rect(20, 30, 50, 60));
613   window_->SetProperty(aura::client::kCanResizeKey, false);
614
615   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
616       window_.get(), gfx::Point(), HTCAPTION,
617       aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
618   ASSERT_TRUE(resizer.get());
619   resizer->Drag(CalculateDragPoint(*resizer, -20, 0), 0);
620   resizer->CompleteDrag(0);
621   EXPECT_EQ("0,30 50x60", window_->bounds().ToString());
622 }
623
624 TEST_F(WorkspaceWindowResizerTest, CancelSnapPhantom) {
625   if (!SupportsMultipleDisplays())
626     return;
627
628   UpdateDisplay("800x600,800x600");
629   Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
630   ASSERT_EQ(2U, root_windows.size());
631
632   window_->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60),
633                              Shell::GetScreen()->GetPrimaryDisplay());
634   EXPECT_EQ(root_windows[0], window_->GetRootWindow());
635   EXPECT_FLOAT_EQ(1.0f, window_->layer()->opacity());
636   {
637     scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
638         window_.get(), gfx::Point(), HTCAPTION,
639         aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
640     ASSERT_TRUE(resizer.get());
641     EXPECT_FALSE(resizer->snap_phantom_window_controller_.get());
642
643     // The pointer is on the edge but not shared. The snap phantom window
644     // controller should be non-NULL.
645     resizer->Drag(CalculateDragPoint(*resizer, 799, 0), 0);
646     EXPECT_TRUE(resizer->snap_phantom_window_controller_.get());
647
648     // Move the cursor across the edge. Now the snap phantom window controller
649     // should be canceled.
650     resizer->Drag(CalculateDragPoint(*resizer, 800, 0), 0);
651     EXPECT_FALSE(resizer->snap_phantom_window_controller_.get());
652   }
653 }
654
655 // Verifies windows are correctly restacked when reordering multiple windows.
656 TEST_F(WorkspaceWindowResizerTest, RestackAttached) {
657   window_->SetBounds(gfx::Rect(   0, 0, 200, 300));
658   window2_->SetBounds(gfx::Rect(200, 0, 100, 200));
659   window3_->SetBounds(gfx::Rect(300, 0, 100, 100));
660
661   {
662     std::vector<aura::Window*> windows;
663     windows.push_back(window2_.get());
664     scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
665         window_.get(), gfx::Point(), HTRIGHT,
666         aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows));
667     ASSERT_TRUE(resizer.get());
668     // Move it 100 to the right, which should expand w1 and push w2 and w3.
669     resizer->Drag(CalculateDragPoint(*resizer, 100, -10), 0);
670
671     // 2 should be topmost since it's initially the highest in the stack.
672     EXPECT_EQ("2 1 3", WindowOrderAsString(window_->parent()));
673   }
674
675   {
676     std::vector<aura::Window*> windows;
677     windows.push_back(window3_.get());
678     scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
679         window2_.get(), gfx::Point(), HTRIGHT,
680         aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows));
681     ASSERT_TRUE(resizer.get());
682     // Move it 100 to the right, which should expand w1 and push w2 and w3.
683     resizer->Drag(CalculateDragPoint(*resizer, 100, -10), 0);
684
685     // 2 should be topmost since it's initially the highest in the stack.
686     EXPECT_EQ("2 3 1", WindowOrderAsString(window_->parent()));
687   }
688 }
689
690 // Makes sure we don't allow dragging below the work area.
691 TEST_F(WorkspaceWindowResizerTest, DontDragOffBottom) {
692   Shell::GetInstance()->SetDisplayWorkAreaInsets(
693       Shell::GetPrimaryRootWindow(), gfx::Insets(0, 0, 10, 0));
694
695   ASSERT_EQ(1, Shell::GetScreen()->GetNumDisplays());
696
697   window_->SetBounds(gfx::Rect(100, 200, 300, 400));
698   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
699       window_.get(), gfx::Point(), HTCAPTION,
700       aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
701   ASSERT_TRUE(resizer.get());
702   resizer->Drag(CalculateDragPoint(*resizer, 0, 600), 0);
703   int expected_y =
704       kRootHeight - WorkspaceWindowResizer::kMinOnscreenHeight - 10;
705   EXPECT_EQ("100," + base::IntToString(expected_y) + " 300x400",
706             window_->bounds().ToString());
707 }
708
709 // Makes sure we don't allow dragging on the work area with multidisplay.
710 TEST_F(WorkspaceWindowResizerTest, DontDragOffBottomWithMultiDisplay) {
711   if (!SupportsMultipleDisplays())
712     return;
713
714   UpdateDisplay("800x600,800x600");
715   ASSERT_EQ(2, Shell::GetScreen()->GetNumDisplays());
716
717   Shell::GetInstance()->SetDisplayWorkAreaInsets(
718       Shell::GetPrimaryRootWindow(), gfx::Insets(0, 0, 10, 0));
719
720   // Positions the secondary display at the bottom the primary display.
721   Shell::GetInstance()->display_manager()->SetLayoutForCurrentDisplays(
722       ash::DisplayLayout(ash::DisplayLayout::BOTTOM, 0));
723
724   {
725     window_->SetBounds(gfx::Rect(100, 200, 300, 20));
726     DCHECK_LT(window_->bounds().height(),
727               WorkspaceWindowResizer::kMinOnscreenHeight);
728     scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
729         window_.get(), gfx::Point(), HTCAPTION,
730         aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
731     ASSERT_TRUE(resizer.get());
732     resizer->Drag(CalculateDragPoint(*resizer, 0, 400), 0);
733     int expected_y = kRootHeight - window_->bounds().height() - 10;
734     // When the mouse cursor is in the primary display, the window cannot move
735     // on non-work area but can get all the way towards the bottom,
736     // restricted only by the window height.
737     EXPECT_EQ("100," + base::IntToString(expected_y) + " 300x20",
738               window_->bounds().ToString());
739   }
740
741   {
742     window_->SetBounds(gfx::Rect(100, 200, 300, 400));
743     scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
744         window_.get(), gfx::Point(), HTCAPTION,
745         aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
746     ASSERT_TRUE(resizer.get());
747     resizer->Drag(CalculateDragPoint(*resizer, 0, 400), 0);
748     int expected_y =
749         kRootHeight - WorkspaceWindowResizer::kMinOnscreenHeight - 10;
750     // When the mouse cursor is in the primary display, the window cannot move
751     // on non-work area with kMinOnscreenHeight margin.
752     EXPECT_EQ("100," + base::IntToString(expected_y) + " 300x400",
753               window_->bounds().ToString());
754   }
755
756   {
757     window_->SetBounds(gfx::Rect(100, 200, 300, 400));
758     scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
759         window_.get(), gfx::Point(), HTCAPTION,
760         aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
761     ASSERT_TRUE(resizer.get());
762     resizer->Drag(CalculateDragPoint(*resizer, 0, 600), 0);
763     // The window can move to the secondary display beyond non-work area of
764     // the primary display.
765     EXPECT_EQ("100,800 300x400", window_->bounds().ToString());
766   }
767 }
768
769 // Makes sure we don't allow dragging off the top of the work area.
770 TEST_F(WorkspaceWindowResizerTest, DontDragOffTop) {
771   Shell::GetInstance()->SetDisplayWorkAreaInsets(
772       Shell::GetPrimaryRootWindow(), gfx::Insets(10, 0, 0, 0));
773
774   window_->SetBounds(gfx::Rect(100, 200, 300, 400));
775   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
776       window_.get(), gfx::Point(), HTCAPTION,
777       aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
778   ASSERT_TRUE(resizer.get());
779   resizer->Drag(CalculateDragPoint(*resizer, 0, -600), 0);
780   EXPECT_EQ("100,10 300x400", window_->bounds().ToString());
781 }
782
783 TEST_F(WorkspaceWindowResizerTest, ResizeBottomOutsideWorkArea) {
784   Shell::GetInstance()->SetDisplayWorkAreaInsets(
785       Shell::GetPrimaryRootWindow(), gfx::Insets(0, 0, 50, 0));
786
787   window_->SetBounds(gfx::Rect(100, 200, 300, 380));
788   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
789       window_.get(), gfx::Point(), HTTOP,
790       aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
791   ASSERT_TRUE(resizer.get());
792   resizer->Drag(CalculateDragPoint(*resizer, 8, 0), 0);
793   EXPECT_EQ("100,200 300x380", window_->bounds().ToString());
794 }
795
796 TEST_F(WorkspaceWindowResizerTest, ResizeWindowOutsideLeftWorkArea) {
797   Shell::GetInstance()->SetDisplayWorkAreaInsets(
798       Shell::GetPrimaryRootWindow(), gfx::Insets(0, 0, 50, 0));
799   int left = ScreenAsh::GetDisplayWorkAreaBoundsInParent(window_.get()).x();
800   int pixels_to_left_border = 50;
801   int window_width = 300;
802   int window_x = left - window_width + pixels_to_left_border;
803   window_->SetBounds(gfx::Rect(window_x, 100, window_width, 380));
804   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
805       window_.get(), gfx::Point(pixels_to_left_border, 0), HTRIGHT,
806       aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
807   ASSERT_TRUE(resizer.get());
808   resizer->Drag(CalculateDragPoint(*resizer, -window_width, 0), 0);
809   EXPECT_EQ(base::IntToString(window_x) + ",100 " +
810             base::IntToString(kMinimumOnScreenArea - window_x) +
811             "x380", window_->bounds().ToString());
812 }
813
814 TEST_F(WorkspaceWindowResizerTest, ResizeWindowOutsideRightWorkArea) {
815   Shell::GetInstance()->SetDisplayWorkAreaInsets(
816       Shell::GetPrimaryRootWindow(), gfx::Insets(0, 0, 50, 0));
817   int right = ScreenAsh::GetDisplayWorkAreaBoundsInParent(
818       window_.get()).right();
819   int pixels_to_right_border = 50;
820   int window_width = 300;
821   int window_x = right - pixels_to_right_border;
822   window_->SetBounds(gfx::Rect(window_x, 100, window_width, 380));
823   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
824       window_.get(), gfx::Point(window_x, 0), HTLEFT,
825       aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
826   ASSERT_TRUE(resizer.get());
827   resizer->Drag(CalculateDragPoint(*resizer, window_width, 0), 0);
828   EXPECT_EQ(base::IntToString(right - kMinimumOnScreenArea) +
829             ",100 " +
830             base::IntToString(window_width - pixels_to_right_border +
831                               kMinimumOnScreenArea) +
832             "x380", window_->bounds().ToString());
833 }
834
835 TEST_F(WorkspaceWindowResizerTest, ResizeWindowOutsideBottomWorkArea) {
836   Shell::GetInstance()->SetDisplayWorkAreaInsets(
837       Shell::GetPrimaryRootWindow(), gfx::Insets(0, 0, 50, 0));
838   int bottom = ScreenAsh::GetDisplayWorkAreaBoundsInParent(
839       window_.get()).bottom();
840   int delta_to_bottom = 50;
841   int height = 380;
842   window_->SetBounds(gfx::Rect(100, bottom - delta_to_bottom, 300, height));
843   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
844       window_.get(), gfx::Point(0, bottom - delta_to_bottom), HTTOP,
845       aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
846   ASSERT_TRUE(resizer.get());
847   resizer->Drag(CalculateDragPoint(*resizer, 0, bottom), 0);
848   EXPECT_EQ("100," +
849             base::IntToString(bottom - kMinimumOnScreenArea) +
850             " 300x" +
851             base::IntToString(height - (delta_to_bottom -
852                                         kMinimumOnScreenArea)),
853             window_->bounds().ToString());
854 }
855
856 // Verifies that 'outside' check of the resizer take into account the extended
857 // desktop in case of repositions.
858 TEST_F(WorkspaceWindowResizerTest, DragWindowOutsideRightToSecondaryDisplay) {
859   // Only primary display.  Changes the window position to fit within the
860   // display.
861   Shell::GetInstance()->SetDisplayWorkAreaInsets(
862       Shell::GetPrimaryRootWindow(), gfx::Insets(0, 0, 50, 0));
863   int right = ScreenAsh::GetDisplayWorkAreaBoundsInParent(
864       window_.get()).right();
865   int pixels_to_right_border = 50;
866   int window_width = 300;
867   int window_x = right - pixels_to_right_border;
868   window_->SetBounds(gfx::Rect(window_x, 100, window_width, 380));
869   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
870       window_.get(), gfx::Point(window_x, 0), HTCAPTION,
871       aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
872   ASSERT_TRUE(resizer.get());
873   resizer->Drag(CalculateDragPoint(*resizer, window_width, 0), 0);
874   EXPECT_EQ(base::IntToString(right - kMinimumOnScreenArea) +
875             ",100 " +
876             base::IntToString(window_width) +
877             "x380", window_->bounds().ToString());
878
879   if (!SupportsMultipleDisplays())
880     return;
881
882   // With secondary display.  Operation itself is same but doesn't change
883   // the position because the window is still within the secondary display.
884   UpdateDisplay("1000x600,600x400");
885   Shell::GetInstance()->SetDisplayWorkAreaInsets(
886       Shell::GetPrimaryRootWindow(), gfx::Insets(0, 0, 50, 0));
887   window_->SetBounds(gfx::Rect(window_x, 100, window_width, 380));
888   resizer->Drag(CalculateDragPoint(*resizer, window_width, 0), 0);
889   EXPECT_EQ(base::IntToString(window_x + window_width) +
890             ",100 " +
891             base::IntToString(window_width) +
892             "x380", window_->bounds().ToString());
893 }
894
895 // Verifies snapping to edges works.
896 TEST_F(WorkspaceWindowResizerTest, SnapToEdge) {
897   Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager()->
898       SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
899   window_->SetBounds(gfx::Rect(96, 112, 320, 160));
900   // Click 50px to the right so that the mouse pointer does not leave the
901   // workspace ensuring sticky behavior.
902   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
903       window_.get(),
904       window_->bounds().origin() + gfx::Vector2d(50, 0),
905       HTCAPTION,
906       aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
907   ASSERT_TRUE(resizer.get());
908   // Move to an x-coordinate of 15, which should not snap.
909   resizer->Drag(CalculateDragPoint(*resizer, 15 - 96, 0), 0);
910   // An x-coordinate of 7 should snap.
911   resizer->Drag(CalculateDragPoint(*resizer, 7 - 96, 0), 0);
912   EXPECT_EQ("0,112 320x160", window_->bounds().ToString());
913   // Move to -15, should still snap to 0.
914   resizer->Drag(CalculateDragPoint(*resizer, -15 - 96, 0), 0);
915   EXPECT_EQ("0,112 320x160", window_->bounds().ToString());
916   // At -32 should move past snap points.
917   resizer->Drag(CalculateDragPoint(*resizer, -32 - 96, 0), 0);
918   EXPECT_EQ("-32,112 320x160", window_->bounds().ToString());
919   resizer->Drag(CalculateDragPoint(*resizer, -33 - 96, 0), 0);
920   EXPECT_EQ("-33,112 320x160", window_->bounds().ToString());
921
922   // Right side should similarly snap.
923   resizer->Drag(CalculateDragPoint(*resizer, 800 - 320 - 96 - 15, 0), 0);
924   EXPECT_EQ("465,112 320x160", window_->bounds().ToString());
925   resizer->Drag(CalculateDragPoint(*resizer, 800 - 320 - 96 - 7, 0), 0);
926   EXPECT_EQ("480,112 320x160", window_->bounds().ToString());
927   resizer->Drag(CalculateDragPoint(*resizer, 800 - 320 - 96 + 15, 0), 0);
928   EXPECT_EQ("480,112 320x160", window_->bounds().ToString());
929   resizer->Drag(CalculateDragPoint(*resizer, 800 - 320 - 96 + 32, 0), 0);
930   EXPECT_EQ("512,112 320x160", window_->bounds().ToString());
931   resizer->Drag(CalculateDragPoint(*resizer, 800 - 320 - 96 + 33, 0), 0);
932   EXPECT_EQ("513,112 320x160", window_->bounds().ToString());
933
934   // And the bottom should snap too.
935   resizer->Drag(CalculateDragPoint(*resizer, 0, 600 - 160 - 112 - 3 - 7), 0);
936   EXPECT_EQ("96,437 320x160", window_->bounds().ToString());
937   resizer->Drag(CalculateDragPoint(*resizer, 0, 600 - 160 - 112 - 3 + 15), 0);
938   EXPECT_EQ("96,437 320x160", window_->bounds().ToString());
939   resizer->Drag(CalculateDragPoint(*resizer, 0, 600 - 160 - 112 - 2 + 32), 0);
940   EXPECT_EQ("96,470 320x160", window_->bounds().ToString());
941   resizer->Drag(CalculateDragPoint(*resizer, 0, 600 - 160 - 112 - 2 + 33), 0);
942   EXPECT_EQ("96,471 320x160", window_->bounds().ToString());
943
944   // And the top should snap too.
945   resizer->Drag(CalculateDragPoint(*resizer, 0, -112 + 20), 0);
946   EXPECT_EQ("96,20 320x160", window_->bounds().ToString());
947   resizer->Drag(CalculateDragPoint(*resizer, 0, -112 + 7), 0);
948   EXPECT_EQ("96,0 320x160", window_->bounds().ToString());
949
950   // And bottom/left should snap too.
951   resizer->Drag(
952       CalculateDragPoint(*resizer, 7 - 96, 600 - 160 - 112 - 3 - 7), 0);
953   EXPECT_EQ("0,437 320x160", window_->bounds().ToString());
954   resizer->Drag(
955       CalculateDragPoint(*resizer, -15 - 96, 600 - 160 - 112 - 3 + 15), 0);
956   EXPECT_EQ("0,437 320x160", window_->bounds().ToString());
957   // should move past snap points.
958   resizer->Drag(
959       CalculateDragPoint(*resizer, -32 - 96, 600 - 160 - 112 - 2 + 32), 0);
960   EXPECT_EQ("-32,470 320x160", window_->bounds().ToString());
961   resizer->Drag(
962       CalculateDragPoint(*resizer, -33 - 96, 600 - 160 - 112 - 2 + 33), 0);
963   EXPECT_EQ("-33,471 320x160", window_->bounds().ToString());
964
965   // No need to test dragging < 0 as we force that to 0.
966 }
967
968 // Verifies a resize snap when dragging TOPLEFT.
969 TEST_F(WorkspaceWindowResizerTest, SnapToWorkArea_TOPLEFT) {
970   window_->SetBounds(gfx::Rect(100, 200, 20, 30));
971   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
972       window_.get(), gfx::Point(), HTTOPLEFT,
973       aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
974   ASSERT_TRUE(resizer.get());
975   resizer->Drag(CalculateDragPoint(*resizer, -98, -199), 0);
976   EXPECT_EQ("0,0 120x230", window_->bounds().ToString());
977 }
978
979 // Verifies a resize snap when dragging TOPRIGHT.
980 TEST_F(WorkspaceWindowResizerTest, SnapToWorkArea_TOPRIGHT) {
981   window_->SetBounds(gfx::Rect(100, 200, 20, 30));
982   gfx::Rect work_area(ScreenAsh::GetDisplayWorkAreaBoundsInParent(
983                           window_.get()));
984   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
985       window_.get(), gfx::Point(), HTTOPRIGHT,
986       aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
987   ASSERT_TRUE(resizer.get());
988   resizer->Drag(
989       CalculateDragPoint(*resizer, work_area.right() - 120 - 1, -199), 0);
990   EXPECT_EQ(100, window_->bounds().x());
991   EXPECT_EQ(work_area.y(), window_->bounds().y());
992   EXPECT_EQ(work_area.right() - 100, window_->bounds().width());
993   EXPECT_EQ(230, window_->bounds().height());
994 }
995
996 // Verifies a resize snap when dragging BOTTOMRIGHT.
997 TEST_F(WorkspaceWindowResizerTest, SnapToWorkArea_BOTTOMRIGHT) {
998   window_->SetBounds(gfx::Rect(100, 200, 20, 30));
999   gfx::Rect work_area(ScreenAsh::GetDisplayWorkAreaBoundsInParent(
1000                           window_.get()));
1001   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
1002       window_.get(), gfx::Point(), HTBOTTOMRIGHT,
1003       aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
1004   ASSERT_TRUE(resizer.get());
1005   resizer->Drag(
1006       CalculateDragPoint(*resizer, work_area.right() - 120 - 1,
1007                          work_area.bottom() - 220 - 2), 0);
1008   EXPECT_EQ(100, window_->bounds().x());
1009   EXPECT_EQ(200, window_->bounds().y());
1010   EXPECT_EQ(work_area.right() - 100, window_->bounds().width());
1011   EXPECT_EQ(work_area.bottom() - 200, window_->bounds().height());
1012 }
1013
1014 // Verifies a resize snap when dragging BOTTOMLEFT.
1015 TEST_F(WorkspaceWindowResizerTest, SnapToWorkArea_BOTTOMLEFT) {
1016   window_->SetBounds(gfx::Rect(100, 200, 20, 30));
1017   gfx::Rect work_area(ScreenAsh::GetDisplayWorkAreaBoundsInParent(
1018                           window_.get()));
1019   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
1020       window_.get(), gfx::Point(), HTBOTTOMLEFT,
1021       aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
1022   ASSERT_TRUE(resizer.get());
1023   resizer->Drag(
1024       CalculateDragPoint(*resizer, -98, work_area.bottom() - 220 - 2), 0);
1025   EXPECT_EQ(0, window_->bounds().x());
1026   EXPECT_EQ(200, window_->bounds().y());
1027   EXPECT_EQ(120, window_->bounds().width());
1028   EXPECT_EQ(work_area.bottom() - 200, window_->bounds().height());
1029 }
1030
1031 // Verifies sticking to edges works.
1032 TEST_F(WorkspaceWindowResizerTestSticky, StickToEdge) {
1033   Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager()->
1034       SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
1035   window_->SetBounds(gfx::Rect(96, 112, 320, 160));
1036   // Click 50px to the right so that the mouse pointer does not leave the
1037   // workspace ensuring sticky behavior.
1038   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
1039       window_.get(),
1040       window_->bounds().origin() + gfx::Vector2d(50, 0),
1041       HTCAPTION,
1042       aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
1043   ASSERT_TRUE(resizer.get());
1044   // Move to an x-coordinate of 15, which should not stick.
1045   resizer->Drag(CalculateDragPoint(*resizer, 15 - 96, 0), 0);
1046   // Move to -15, should still stick to 0.
1047   resizer->Drag(CalculateDragPoint(*resizer, -15 - 96, 0), 0);
1048   EXPECT_EQ("0,112 320x160", window_->bounds().ToString());
1049   // At -100 should move past edge.
1050   resizer->Drag(CalculateDragPoint(*resizer, -100 - 96, 0), 0);
1051   EXPECT_EQ("-100,112 320x160", window_->bounds().ToString());
1052   resizer->Drag(CalculateDragPoint(*resizer, -101 - 96, 0), 0);
1053   EXPECT_EQ("-101,112 320x160", window_->bounds().ToString());
1054
1055   // Right side should similarly stick.
1056   resizer->Drag(CalculateDragPoint(*resizer, 800 - 320 - 96 - 15, 0), 0);
1057   EXPECT_EQ("465,112 320x160", window_->bounds().ToString());
1058   resizer->Drag(CalculateDragPoint(*resizer, 800 - 320 - 96 + 15, 0), 0);
1059   EXPECT_EQ("480,112 320x160", window_->bounds().ToString());
1060   resizer->Drag(CalculateDragPoint(*resizer, 800 - 320 - 96 + 100, 0), 0);
1061   EXPECT_EQ("580,112 320x160", window_->bounds().ToString());
1062   resizer->Drag(CalculateDragPoint(*resizer, 800 - 320 - 96 + 101, 0), 0);
1063   EXPECT_EQ("581,112 320x160", window_->bounds().ToString());
1064
1065   // And the bottom should stick too.
1066   resizer->Drag(CalculateDragPoint(*resizer, 0, 600 - 160 - 112 - 3 + 15), 0);
1067   EXPECT_EQ("96,437 320x160", window_->bounds().ToString());
1068   resizer->Drag(CalculateDragPoint(*resizer, 0, 600 - 160 - 112 - 2 + 100), 0);
1069   EXPECT_EQ("96,538 320x160", window_->bounds().ToString());
1070   resizer->Drag(CalculateDragPoint(*resizer, 0, 600 - 160 - 112 - 2 + 101), 0);
1071   EXPECT_EQ("96,539 320x160", window_->bounds().ToString());
1072
1073   // No need to test dragging < 0 as we force that to 0.
1074 }
1075
1076 // Verifies not sticking to edges when a mouse pointer is outside of work area.
1077 TEST_F(WorkspaceWindowResizerTestSticky, NoStickToEdgeWhenOutside) {
1078   Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager()->
1079       SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
1080   window_->SetBounds(gfx::Rect(96, 112, 320, 160));
1081   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
1082       window_.get(), gfx::Point(), HTCAPTION,
1083       aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
1084   ASSERT_TRUE(resizer.get());
1085   // Move to an x-coordinate of 15, which should not stick.
1086   resizer->Drag(CalculateDragPoint(*resizer, 15 - 96, 0), 0);
1087   // Move to -15, should still stick to 0.
1088   resizer->Drag(CalculateDragPoint(*resizer, -15 - 96, 0), 0);
1089   EXPECT_EQ("-15,112 320x160", window_->bounds().ToString());
1090 }
1091
1092 // Verifies a resize sticks when dragging TOPLEFT.
1093 TEST_F(WorkspaceWindowResizerTestSticky, StickToWorkArea_TOPLEFT) {
1094   window_->SetBounds(gfx::Rect(100, 200, 20, 30));
1095   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
1096       window_.get(), gfx::Point(), HTTOPLEFT,
1097       aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
1098   ASSERT_TRUE(resizer.get());
1099   resizer->Drag(CalculateDragPoint(*resizer, -15 - 100, -15 -200), 0);
1100   EXPECT_EQ("0,0 120x230", window_->bounds().ToString());
1101 }
1102
1103 // Verifies a resize sticks when dragging TOPRIGHT.
1104 TEST_F(WorkspaceWindowResizerTestSticky, StickToWorkArea_TOPRIGHT) {
1105   window_->SetBounds(gfx::Rect(100, 200, 20, 30));
1106   gfx::Rect work_area(ScreenAsh::GetDisplayWorkAreaBoundsInParent(
1107                           window_.get()));
1108   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
1109       window_.get(), gfx::Point(), HTTOPRIGHT,
1110       aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
1111   ASSERT_TRUE(resizer.get());
1112   resizer->Drag(CalculateDragPoint(*resizer, work_area.right() - 100 + 20,
1113                                    -200 - 15), 0);
1114   EXPECT_EQ(100, window_->bounds().x());
1115   EXPECT_EQ(work_area.y(), window_->bounds().y());
1116   EXPECT_EQ(work_area.right() - 100, window_->bounds().width());
1117   EXPECT_EQ(230, window_->bounds().height());
1118 }
1119
1120 // Verifies a resize snap when dragging BOTTOMRIGHT.
1121 TEST_F(WorkspaceWindowResizerTestSticky, StickToWorkArea_BOTTOMRIGHT) {
1122   window_->SetBounds(gfx::Rect(100, 200, 20, 30));
1123   gfx::Rect work_area(ScreenAsh::GetDisplayWorkAreaBoundsInParent(
1124                           window_.get()));
1125   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
1126       window_.get(), gfx::Point(), HTBOTTOMRIGHT,
1127       aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
1128   ASSERT_TRUE(resizer.get());
1129   resizer->Drag(CalculateDragPoint(*resizer, work_area.right() - 100 - 20 + 15,
1130                                    work_area.bottom() - 200 - 30 + 15), 0);
1131   EXPECT_EQ(100, window_->bounds().x());
1132   EXPECT_EQ(200, window_->bounds().y());
1133   EXPECT_EQ(work_area.right() - 100, window_->bounds().width());
1134   EXPECT_EQ(work_area.bottom() - 200, window_->bounds().height());
1135 }
1136
1137 // Verifies a resize snap when dragging BOTTOMLEFT.
1138 TEST_F(WorkspaceWindowResizerTestSticky, StickToWorkArea_BOTTOMLEFT) {
1139   window_->SetBounds(gfx::Rect(100, 200, 20, 30));
1140   gfx::Rect work_area(ScreenAsh::GetDisplayWorkAreaBoundsInParent(
1141                           window_.get()));
1142   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
1143       window_.get(), gfx::Point(), HTBOTTOMLEFT,
1144       aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
1145   ASSERT_TRUE(resizer.get());
1146   resizer->Drag(CalculateDragPoint(*resizer, -15 - 100,
1147                                    work_area.bottom() - 200 - 30 + 15), 0);
1148   EXPECT_EQ(0, window_->bounds().x());
1149   EXPECT_EQ(200, window_->bounds().y());
1150   EXPECT_EQ(120, window_->bounds().width());
1151   EXPECT_EQ(work_area.bottom() - 200, window_->bounds().height());
1152 }
1153
1154 TEST_F(WorkspaceWindowResizerTest, CtrlDragResizeToExactPosition) {
1155   window_->SetBounds(gfx::Rect(96, 112, 320, 160));
1156   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
1157       window_.get(), gfx::Point(), HTBOTTOMRIGHT,
1158       aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
1159   ASSERT_TRUE(resizer.get());
1160   // Resize the right bottom to add 10 in width, 12 in height.
1161   resizer->Drag(CalculateDragPoint(*resizer, 10, 12), ui::EF_CONTROL_DOWN);
1162   // Both bottom and right sides to resize to exact size requested.
1163   EXPECT_EQ("96,112 330x172", window_->bounds().ToString());
1164 }
1165
1166 TEST_F(WorkspaceWindowResizerTest, CtrlCompleteDragMoveToExactPosition) {
1167   window_->SetBounds(gfx::Rect(96, 112, 320, 160));
1168   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
1169       window_.get(), gfx::Point(), HTCAPTION,
1170       aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
1171   ASSERT_TRUE(resizer.get());
1172   // Ctrl + drag the window to new poistion by adding (10, 12) to its origin,
1173   // the window should move to the exact position.
1174   resizer->Drag(CalculateDragPoint(*resizer, 10, 12), 0);
1175   resizer->CompleteDrag(ui::EF_CONTROL_DOWN);
1176   EXPECT_EQ("106,124 320x160", window_->bounds().ToString());
1177 }
1178
1179 // Verifies that a dragged window will restore to its pre-maximized size.
1180 TEST_F(WorkspaceWindowResizerTest, RestoreToPreMaximizeCoordinates) {
1181   window_->SetBounds(gfx::Rect(0, 0, 1000, 1000));
1182   wm::WindowState* window_state = wm::GetWindowState(window_.get());
1183   window_state->SetRestoreBoundsInScreen(gfx::Rect(96, 112, 320, 160));
1184   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
1185       window_.get(), gfx::Point(), HTCAPTION,
1186       aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
1187   ASSERT_TRUE(resizer.get());
1188   // Drag the window to new position by adding (10, 10) to original point,
1189   // the window should get restored.
1190   resizer->Drag(CalculateDragPoint(*resizer, 10, 10), 0);
1191   resizer->CompleteDrag(0);
1192   EXPECT_EQ("10,10 320x160", window_->bounds().ToString());
1193   // The restore rectangle should get cleared as well.
1194   EXPECT_FALSE(window_state->HasRestoreBounds());
1195 }
1196
1197 // Verifies that a dragged window will restore to its pre-maximized size.
1198 TEST_F(WorkspaceWindowResizerTest, RevertResizeOperation) {
1199   const gfx::Rect initial_bounds(0, 0, 200, 400);
1200   window_->SetBounds(initial_bounds);
1201
1202   wm::WindowState* window_state = wm::GetWindowState(window_.get());
1203   window_state->SetRestoreBoundsInScreen(gfx::Rect(96, 112, 320, 160));
1204   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
1205       window_.get(), gfx::Point(), HTCAPTION,
1206       aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
1207   ASSERT_TRUE(resizer.get());
1208   // Drag the window to new poistion by adding (180, 16) to original point,
1209   // the window should get restored.
1210   resizer->Drag(CalculateDragPoint(*resizer, 180, 16), 0);
1211   resizer->RevertDrag();
1212   EXPECT_EQ(initial_bounds.ToString(), window_->bounds().ToString());
1213   EXPECT_EQ("96,112 320x160",
1214             window_state->GetRestoreBoundsInScreen().ToString());
1215 }
1216
1217 // Check that only usable sizes get returned by the resizer.
1218 TEST_F(WorkspaceWindowResizerTest, MagneticallyAttach) {
1219   window_->SetBounds(gfx::Rect(10, 10, 20, 30));
1220   window2_->SetBounds(gfx::Rect(150, 160, 25, 20));
1221   window2_->Show();
1222
1223   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
1224       window_.get(), gfx::Point(), HTCAPTION,
1225       aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
1226   ASSERT_TRUE(resizer.get());
1227   // Move |window| one pixel to the left of |window2|. Should snap to right and
1228   // top.
1229   resizer->Drag(CalculateDragPoint(*resizer, 119, 145), 0);
1230   EXPECT_EQ("130,160 20x30", window_->bounds().ToString());
1231
1232   // Move |window| one pixel to the right of |window2|. Should snap to left and
1233   // top.
1234   resizer->Drag(CalculateDragPoint(*resizer, 164, 145), 0);
1235   EXPECT_EQ("175,160 20x30", window_->bounds().ToString());
1236
1237   // Move |window| one pixel above |window2|. Should snap to top and left.
1238   resizer->Drag(CalculateDragPoint(*resizer, 142, 119), 0);
1239   EXPECT_EQ("150,130 20x30", window_->bounds().ToString());
1240
1241   // Move |window| one pixel above the bottom of |window2|. Should snap to
1242   // bottom and left.
1243   resizer->Drag(CalculateDragPoint(*resizer, 142, 169), 0);
1244   EXPECT_EQ("150,180 20x30", window_->bounds().ToString());
1245 }
1246
1247 // The following variants verify magnetic snapping during resize when dragging a
1248 // particular edge.
1249 TEST_F(WorkspaceWindowResizerTest, MagneticallyResize_TOP) {
1250   window_->SetBounds(gfx::Rect(100, 200, 20, 30));
1251   window2_->SetBounds(gfx::Rect(99, 179, 10, 20));
1252   window2_->Show();
1253
1254   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
1255     window_.get(), gfx::Point(), HTTOP,
1256     aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
1257   ASSERT_TRUE(resizer.get());
1258   resizer->Drag(CalculateDragPoint(*resizer, 0, 0), 0);
1259   EXPECT_EQ("100,199 20x31", window_->bounds().ToString());
1260 }
1261
1262 TEST_F(WorkspaceWindowResizerTest, MagneticallyResize_TOPLEFT) {
1263   window_->SetBounds(gfx::Rect(100, 200, 20, 30));
1264   window2_->SetBounds(gfx::Rect(99, 179, 10, 20));
1265   window2_->Show();
1266
1267   {
1268     scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
1269         window_.get(), gfx::Point(), HTTOPLEFT,
1270         aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
1271     ASSERT_TRUE(resizer.get());
1272     resizer->Drag(CalculateDragPoint(*resizer, 0, 0), 0);
1273     EXPECT_EQ("99,199 21x31", window_->bounds().ToString());
1274     resizer->RevertDrag();
1275   }
1276
1277   {
1278     window2_->SetBounds(gfx::Rect(88, 201, 10, 20));
1279     scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
1280         window_.get(), gfx::Point(), HTTOPLEFT,
1281         aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
1282     ASSERT_TRUE(resizer.get());
1283     resizer->Drag(CalculateDragPoint(*resizer, 0, 0), 0);
1284     EXPECT_EQ("98,201 22x29", window_->bounds().ToString());
1285     resizer->RevertDrag();
1286   }
1287 }
1288
1289 TEST_F(WorkspaceWindowResizerTest, MagneticallyResize_TOPRIGHT) {
1290   window_->SetBounds(gfx::Rect(100, 200, 20, 30));
1291   window2_->Show();
1292
1293   {
1294     window2_->SetBounds(gfx::Rect(111, 179, 10, 20));
1295     scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
1296         window_.get(), gfx::Point(), HTTOPRIGHT,
1297         aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
1298     ASSERT_TRUE(resizer.get());
1299     resizer->Drag(CalculateDragPoint(*resizer, 0, 0), 0);
1300     EXPECT_EQ("100,199 21x31", window_->bounds().ToString());
1301     resizer->RevertDrag();
1302   }
1303
1304   {
1305     window2_->SetBounds(gfx::Rect(121, 199, 10, 20));
1306     scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
1307         window_.get(), gfx::Point(), HTTOPRIGHT,
1308         aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
1309     ASSERT_TRUE(resizer.get());
1310     resizer->Drag(CalculateDragPoint(*resizer, 0, 0), 0);
1311     EXPECT_EQ("100,199 21x31", window_->bounds().ToString());
1312     resizer->RevertDrag();
1313   }
1314 }
1315
1316 TEST_F(WorkspaceWindowResizerTest, MagneticallyResize_RIGHT) {
1317   window_->SetBounds(gfx::Rect(100, 200, 20, 30));
1318   window2_->SetBounds(gfx::Rect(121, 199, 10, 20));
1319   window2_->Show();
1320
1321   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
1322       window_.get(), gfx::Point(), HTRIGHT,
1323       aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
1324   ASSERT_TRUE(resizer.get());
1325   resizer->Drag(CalculateDragPoint(*resizer, 0, 0), 0);
1326   EXPECT_EQ("100,200 21x30", window_->bounds().ToString());
1327 }
1328
1329 TEST_F(WorkspaceWindowResizerTest, MagneticallyResize_BOTTOMRIGHT) {
1330   window_->SetBounds(gfx::Rect(100, 200, 20, 30));
1331   window2_->Show();
1332
1333   {
1334     window2_->SetBounds(gfx::Rect(122, 212, 10, 20));
1335     scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
1336         window_.get(), gfx::Point(), HTBOTTOMRIGHT,
1337         aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
1338     ASSERT_TRUE(resizer.get());
1339     resizer->Drag(CalculateDragPoint(*resizer, 0, 0), 0);
1340     EXPECT_EQ("100,200 22x32", window_->bounds().ToString());
1341     resizer->RevertDrag();
1342   }
1343
1344   {
1345     window2_->SetBounds(gfx::Rect(111, 233, 10, 20));
1346     scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
1347         window_.get(), gfx::Point(), HTBOTTOMRIGHT,
1348         aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
1349     ASSERT_TRUE(resizer.get());
1350     resizer->Drag(CalculateDragPoint(*resizer, 0, 0), 0);
1351     EXPECT_EQ("100,200 21x33", window_->bounds().ToString());
1352     resizer->RevertDrag();
1353   }
1354 }
1355
1356 TEST_F(WorkspaceWindowResizerTest, MagneticallyResize_BOTTOM) {
1357   window_->SetBounds(gfx::Rect(100, 200, 20, 30));
1358   window2_->SetBounds(gfx::Rect(111, 233, 10, 20));
1359   window2_->Show();
1360
1361   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
1362         window_.get(), gfx::Point(), HTBOTTOM,
1363         aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
1364   ASSERT_TRUE(resizer.get());
1365   resizer->Drag(CalculateDragPoint(*resizer, 0, 0), 0);
1366   EXPECT_EQ("100,200 20x33", window_->bounds().ToString());
1367 }
1368
1369 TEST_F(WorkspaceWindowResizerTest, MagneticallyResize_BOTTOMLEFT) {
1370   window_->SetBounds(gfx::Rect(100, 200, 20, 30));
1371   window2_->Show();
1372
1373   {
1374     window2_->SetBounds(gfx::Rect(99, 231, 10, 20));
1375     scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
1376         window_.get(), gfx::Point(), HTBOTTOMLEFT,
1377         aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
1378     ASSERT_TRUE(resizer.get());
1379     resizer->Drag(CalculateDragPoint(*resizer, 0, 0), 0);
1380     EXPECT_EQ("99,200 21x31", window_->bounds().ToString());
1381     resizer->RevertDrag();
1382   }
1383
1384   {
1385     window2_->SetBounds(gfx::Rect(89, 209, 10, 20));
1386     scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
1387         window_.get(), gfx::Point(), HTBOTTOMLEFT,
1388         aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
1389     ASSERT_TRUE(resizer.get());
1390     resizer->Drag(CalculateDragPoint(*resizer, 0, 0), 0);
1391     EXPECT_EQ("99,200 21x29", window_->bounds().ToString());
1392     resizer->RevertDrag();
1393   }
1394 }
1395
1396 TEST_F(WorkspaceWindowResizerTest, MagneticallyResize_LEFT) {
1397   window2_->SetBounds(gfx::Rect(89, 209, 10, 20));
1398   window_->SetBounds(gfx::Rect(100, 200, 20, 30));
1399   window2_->Show();
1400
1401   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
1402       window_.get(), gfx::Point(), HTLEFT,
1403       aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
1404   ASSERT_TRUE(resizer.get());
1405   resizer->Drag(CalculateDragPoint(*resizer, 0, 0), 0);
1406   EXPECT_EQ("99,200 21x30", window_->bounds().ToString());
1407 }
1408
1409 // Test that the user user moved window flag is getting properly set.
1410 TEST_F(WorkspaceWindowResizerTest, CheckUserWindowMangedFlags) {
1411   window_->SetBounds(gfx::Rect( 0,  50, 400, 200));
1412
1413   std::vector<aura::Window*> no_attached_windows;
1414   // Check that an abort doesn't change anything.
1415   {
1416     scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
1417         window_.get(), gfx::Point(), HTCAPTION,
1418         aura::client::WINDOW_MOVE_SOURCE_MOUSE, no_attached_windows));
1419     ASSERT_TRUE(resizer.get());
1420     // Move it 100 to the bottom.
1421     resizer->Drag(CalculateDragPoint(*resizer, 0, 100), 0);
1422     EXPECT_EQ("0,150 400x200", window_->bounds().ToString());
1423     resizer->RevertDrag();
1424
1425     EXPECT_FALSE(wm::GetWindowState(window_.get())->bounds_changed_by_user());
1426   }
1427
1428   // Check that a completed move / size does change the user coordinates.
1429   {
1430     scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
1431         window_.get(), gfx::Point(), HTCAPTION,
1432         aura::client::WINDOW_MOVE_SOURCE_MOUSE, no_attached_windows));
1433     ASSERT_TRUE(resizer.get());
1434     // Move it 100 to the bottom.
1435     resizer->Drag(CalculateDragPoint(*resizer, 0, 100), 0);
1436     EXPECT_EQ("0,150 400x200", window_->bounds().ToString());
1437     resizer->CompleteDrag(0);
1438     EXPECT_TRUE(wm::GetWindowState(window_.get())->bounds_changed_by_user());
1439   }
1440 }
1441
1442 // Test that a window with a specified max size doesn't exceed it when dragged.
1443 TEST_F(WorkspaceWindowResizerTest, TestMaxSizeEnforced) {
1444   window_->SetBounds(gfx::Rect(0, 0, 400, 300));
1445   delegate_.set_max_size(gfx::Size(401, 301));
1446
1447   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
1448       window_.get(), gfx::Point(), HTBOTTOMRIGHT,
1449       aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
1450   resizer->Drag(CalculateDragPoint(*resizer, 2, 2), 0);
1451   EXPECT_EQ(401, window_->bounds().width());
1452   EXPECT_EQ(301, window_->bounds().height());
1453 }
1454
1455 // Test that a window with a specified max width doesn't restrict its height.
1456 TEST_F(WorkspaceWindowResizerTest, TestPartialMaxSizeEnforced) {
1457   window_->SetBounds(gfx::Rect(0, 0, 400, 300));
1458   delegate_.set_max_size(gfx::Size(401, 0));
1459
1460   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
1461       window_.get(), gfx::Point(), HTBOTTOMRIGHT,
1462       aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
1463   resizer->Drag(CalculateDragPoint(*resizer, 2, 2), 0);
1464   EXPECT_EQ(401, window_->bounds().width());
1465   EXPECT_EQ(302, window_->bounds().height());
1466 }
1467
1468 // Test that a window with a specified max size can't be snapped.
1469 TEST_F(WorkspaceWindowResizerTest, PhantomSnapMaxSize) {
1470   {
1471     // With max size not set we get a phantom window controller for dragging off
1472     // the right hand side.
1473     window_->SetBounds(gfx::Rect(0, 0, 300, 200));
1474
1475     scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
1476         window_.get(), gfx::Point(), HTCAPTION,
1477         aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
1478     EXPECT_FALSE(resizer->snap_phantom_window_controller_.get());
1479     resizer->Drag(CalculateDragPoint(*resizer, 801, 0), 0);
1480     EXPECT_TRUE(resizer->snap_phantom_window_controller_.get());
1481   }
1482   {
1483     // With max size defined, we get no phantom window.
1484     window_->SetBounds(gfx::Rect(0, 0, 300, 200));
1485     delegate_.set_max_size(gfx::Size(300, 200));
1486
1487     scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
1488         window_.get(), gfx::Point(), HTCAPTION,
1489         aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
1490     resizer->Drag(CalculateDragPoint(*resizer, 801, 0), 0);
1491     EXPECT_FALSE(resizer->snap_phantom_window_controller_.get());
1492   }
1493 }
1494
1495 TEST_F(WorkspaceWindowResizerTest, DontRewardRightmostWindowForOverflows) {
1496   UpdateDisplay("600x800");
1497   aura::Window* root = Shell::GetPrimaryRootWindow();
1498   Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets());
1499
1500   // Four 100x100 windows flush against eachother, starting at 100,100.
1501   window_->SetBounds(gfx::Rect( 100, 100, 100, 100));
1502   window2_->SetBounds(gfx::Rect(200, 100, 100, 100));
1503   window3_->SetBounds(gfx::Rect(300, 100, 100, 100));
1504   window4_->SetBounds(gfx::Rect(400, 100, 100, 100));
1505   delegate2_.set_max_size(gfx::Size(101, 0));
1506
1507   std::vector<aura::Window*> windows;
1508   windows.push_back(window2_.get());
1509   windows.push_back(window3_.get());
1510   windows.push_back(window4_.get());
1511   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
1512       window_.get(), gfx::Point(), HTRIGHT,
1513       aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows));
1514   ASSERT_TRUE(resizer.get());
1515   // Move it 51 to the left, which should contract w1 and expand w2-4.
1516   // w2 will hit its max size straight away, and in doing so will leave extra
1517   // pixels that a naive implementation may award to the rightmost window. A
1518   // fair implementation will give 25 pixels to each of the other windows.
1519   resizer->Drag(CalculateDragPoint(*resizer, -51, 0), 0);
1520   EXPECT_EQ("100,100 49x100", window_->bounds().ToString());
1521   EXPECT_EQ("149,100 101x100", window2_->bounds().ToString());
1522   EXPECT_EQ("250,100 125x100", window3_->bounds().ToString());
1523   EXPECT_EQ("375,100 125x100", window4_->bounds().ToString());
1524 }
1525
1526 TEST_F(WorkspaceWindowResizerTest, DontExceedMaxWidth) {
1527   UpdateDisplay("600x800");
1528   aura::Window* root = Shell::GetPrimaryRootWindow();
1529   Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets());
1530
1531   // Four 100x100 windows flush against eachother, starting at 100,100.
1532   window_->SetBounds(gfx::Rect( 100, 100, 100, 100));
1533   window2_->SetBounds(gfx::Rect(200, 100, 100, 100));
1534   window3_->SetBounds(gfx::Rect(300, 100, 100, 100));
1535   window4_->SetBounds(gfx::Rect(400, 100, 100, 100));
1536   delegate2_.set_max_size(gfx::Size(101, 0));
1537   delegate3_.set_max_size(gfx::Size(101, 0));
1538
1539   std::vector<aura::Window*> windows;
1540   windows.push_back(window2_.get());
1541   windows.push_back(window3_.get());
1542   windows.push_back(window4_.get());
1543   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
1544       window_.get(), gfx::Point(), HTRIGHT,
1545       aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows));
1546   ASSERT_TRUE(resizer.get());
1547   // Move it 52 to the left, which should contract w1 and expand w2-4.
1548   resizer->Drag(CalculateDragPoint(*resizer, -52, 0), 0);
1549   EXPECT_EQ("100,100 48x100", window_->bounds().ToString());
1550   EXPECT_EQ("148,100 101x100", window2_->bounds().ToString());
1551   EXPECT_EQ("249,100 101x100", window3_->bounds().ToString());
1552   EXPECT_EQ("350,100 150x100", window4_->bounds().ToString());
1553 }
1554
1555 TEST_F(WorkspaceWindowResizerTest, DontExceedMaxHeight) {
1556   UpdateDisplay("600x800");
1557   aura::Window* root = Shell::GetPrimaryRootWindow();
1558   Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets());
1559
1560   // Four 100x100 windows flush against eachother, starting at 100,100.
1561   window_->SetBounds(gfx::Rect( 100, 100, 100, 100));
1562   window2_->SetBounds(gfx::Rect(100, 200, 100, 100));
1563   window3_->SetBounds(gfx::Rect(100, 300, 100, 100));
1564   window4_->SetBounds(gfx::Rect(100, 400, 100, 100));
1565   delegate2_.set_max_size(gfx::Size(0, 101));
1566   delegate3_.set_max_size(gfx::Size(0, 101));
1567
1568   std::vector<aura::Window*> windows;
1569   windows.push_back(window2_.get());
1570   windows.push_back(window3_.get());
1571   windows.push_back(window4_.get());
1572   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
1573       window_.get(), gfx::Point(), HTBOTTOM,
1574       aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows));
1575   ASSERT_TRUE(resizer.get());
1576   // Move it 52 up, which should contract w1 and expand w2-4.
1577   resizer->Drag(CalculateDragPoint(*resizer, 0, -52), 0);
1578   EXPECT_EQ("100,100 100x48", window_->bounds().ToString());
1579   EXPECT_EQ("100,148 100x101", window2_->bounds().ToString());
1580   EXPECT_EQ("100,249 100x101", window3_->bounds().ToString());
1581   EXPECT_EQ("100,350 100x150", window4_->bounds().ToString());
1582 }
1583
1584 #if defined(OS_WIN)
1585 // RootWindow and Display can't resize on Windows Ash. http://crbug.com/165962
1586 #define MAYBE_DontExceedMinHeight DISABLED_DontExceedMinHeight
1587 #else
1588 #define MAYBE_DontExceedMinHeight DontExceedMinHeight
1589 #endif
1590
1591 TEST_F(WorkspaceWindowResizerTest, MAYBE_DontExceedMinHeight) {
1592   UpdateDisplay("600x500");
1593   aura::Window* root = Shell::GetPrimaryRootWindow();
1594   Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets());
1595
1596   // Four 100x100 windows flush against eachother, starting at 100,100.
1597   window_->SetBounds(gfx::Rect( 100, 100, 100, 100));
1598   window2_->SetBounds(gfx::Rect(100, 200, 100, 100));
1599   window3_->SetBounds(gfx::Rect(100, 300, 100, 100));
1600   window4_->SetBounds(gfx::Rect(100, 400, 100, 100));
1601   delegate2_.set_min_size(gfx::Size(0, 99));
1602   delegate3_.set_min_size(gfx::Size(0, 99));
1603
1604   std::vector<aura::Window*> windows;
1605   windows.push_back(window2_.get());
1606   windows.push_back(window3_.get());
1607   windows.push_back(window4_.get());
1608   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
1609       window_.get(), gfx::Point(), HTBOTTOM,
1610       aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows));
1611   ASSERT_TRUE(resizer.get());
1612   // Move it 52 down, which should expand w1 and contract w2-4.
1613   resizer->Drag(CalculateDragPoint(*resizer, 0, 52), 0);
1614   EXPECT_EQ("100,100 100x152", window_->bounds().ToString());
1615   EXPECT_EQ("100,252 100x99", window2_->bounds().ToString());
1616   EXPECT_EQ("100,351 100x99", window3_->bounds().ToString());
1617   EXPECT_EQ("100,450 100x50", window4_->bounds().ToString());
1618 }
1619
1620 TEST_F(WorkspaceWindowResizerTest, DontExpandRightmostPastMaxWidth) {
1621   UpdateDisplay("600x800");
1622   aura::Window* root = Shell::GetPrimaryRootWindow();
1623   Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets());
1624
1625   // Three 100x100 windows flush against eachother, starting at 100,100.
1626   window_->SetBounds(gfx::Rect( 100, 100, 100, 100));
1627   window2_->SetBounds(gfx::Rect(200, 100, 100, 100));
1628   window3_->SetBounds(gfx::Rect(300, 100, 100, 100));
1629   delegate3_.set_max_size(gfx::Size(101, 0));
1630
1631   std::vector<aura::Window*> windows;
1632   windows.push_back(window2_.get());
1633   windows.push_back(window3_.get());
1634   windows.push_back(window4_.get());
1635   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
1636       window_.get(), gfx::Point(), HTRIGHT,
1637       aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows));
1638   ASSERT_TRUE(resizer.get());
1639   // Move it 51 to the left, which should contract w1 and expand w2-3.
1640   resizer->Drag(CalculateDragPoint(*resizer, -51, 0), 0);
1641   EXPECT_EQ("100,100 49x100", window_->bounds().ToString());
1642   EXPECT_EQ("149,100 150x100", window2_->bounds().ToString());
1643   EXPECT_EQ("299,100 101x100", window3_->bounds().ToString());
1644 }
1645
1646 TEST_F(WorkspaceWindowResizerTest, MoveAttachedWhenGrownToMaxSize) {
1647   UpdateDisplay("600x800");
1648   aura::Window* root = Shell::GetPrimaryRootWindow();
1649   Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets());
1650
1651   // Three 100x100 windows flush against eachother, starting at 100,100.
1652   window_->SetBounds(gfx::Rect( 100, 100, 100, 100));
1653   window2_->SetBounds(gfx::Rect(200, 100, 100, 100));
1654   window3_->SetBounds(gfx::Rect(300, 100, 100, 100));
1655   delegate2_.set_max_size(gfx::Size(101, 0));
1656   delegate3_.set_max_size(gfx::Size(101, 0));
1657
1658   std::vector<aura::Window*> windows;
1659   windows.push_back(window2_.get());
1660   windows.push_back(window3_.get());
1661   windows.push_back(window4_.get());
1662   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
1663       window_.get(), gfx::Point(), HTRIGHT,
1664       aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows));
1665   ASSERT_TRUE(resizer.get());
1666   // Move it 52 to the left, which should contract w1 and expand and move w2-3.
1667   resizer->Drag(CalculateDragPoint(*resizer, -52, 0), 0);
1668   EXPECT_EQ("100,100 48x100", window_->bounds().ToString());
1669   EXPECT_EQ("148,100 101x100", window2_->bounds().ToString());
1670   EXPECT_EQ("249,100 101x100", window3_->bounds().ToString());
1671 }
1672
1673 #if defined(OS_WIN)
1674 // RootWindow and Display can't resize on Windows Ash. http://crbug.com/165962
1675 #define MAYBE_MainWindowHonoursMaxWidth DISABLED_MainWindowHonoursMaxWidth
1676 #else
1677 #define MAYBE_MainWindowHonoursMaxWidth MainWindowHonoursMaxWidth
1678 #endif
1679
1680 TEST_F(WorkspaceWindowResizerTest, MAYBE_MainWindowHonoursMaxWidth) {
1681   UpdateDisplay("400x800");
1682   aura::Window* root = Shell::GetPrimaryRootWindow();
1683   Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets());
1684
1685   // Three 100x100 windows flush against eachother, starting at 100,100.
1686   window_->SetBounds(gfx::Rect( 100, 100, 100, 100));
1687   window2_->SetBounds(gfx::Rect(200, 100, 100, 100));
1688   window3_->SetBounds(gfx::Rect(300, 100, 100, 100));
1689   delegate_.set_max_size(gfx::Size(102, 0));
1690
1691   std::vector<aura::Window*> windows;
1692   windows.push_back(window2_.get());
1693   windows.push_back(window3_.get());
1694   windows.push_back(window4_.get());
1695   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
1696       window_.get(), gfx::Point(), HTRIGHT,
1697       aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows));
1698   ASSERT_TRUE(resizer.get());
1699   // Move it 50 to the right, which should expand w1 and contract w2-3, as they
1700   // won't fit in the root window in their original sizes.
1701   resizer->Drag(CalculateDragPoint(*resizer, 50, 0), 0);
1702   EXPECT_EQ("100,100 102x100", window_->bounds().ToString());
1703   EXPECT_EQ("202,100 99x100", window2_->bounds().ToString());
1704   EXPECT_EQ("301,100 99x100", window3_->bounds().ToString());
1705 }
1706
1707 TEST_F(WorkspaceWindowResizerTest, MainWindowHonoursMinWidth) {
1708   UpdateDisplay("400x800");
1709   aura::Window* root = Shell::GetPrimaryRootWindow();
1710   Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets());
1711
1712   // Three 100x100 windows flush against eachother, starting at 100,100.
1713   window_->SetBounds(gfx::Rect( 100, 100, 100, 100));
1714   window2_->SetBounds(gfx::Rect(200, 100, 100, 100));
1715   window3_->SetBounds(gfx::Rect(300, 100, 100, 100));
1716   delegate_.set_min_size(gfx::Size(98, 0));
1717
1718   std::vector<aura::Window*> windows;
1719   windows.push_back(window2_.get());
1720   windows.push_back(window3_.get());
1721   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
1722       window_.get(), gfx::Point(), HTRIGHT,
1723       aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows));
1724   ASSERT_TRUE(resizer.get());
1725   // Move it 50 to the left, which should contract w1 and expand w2-3.
1726   resizer->Drag(CalculateDragPoint(*resizer, -50, 0), 0);
1727   EXPECT_EQ("100,100 98x100", window_->bounds().ToString());
1728   EXPECT_EQ("198,100 101x100", window2_->bounds().ToString());
1729   EXPECT_EQ("299,100 101x100", window3_->bounds().ToString());
1730 }
1731
1732 // The following variants test that windows are resized correctly to the edges
1733 // of the screen using touch, when touch point is off of the window border.
1734 TEST_F(WorkspaceWindowResizerTest, TouchResizeToEdge_RIGHT) {
1735   shelf_layout_manager()->SetAutoHideBehavior(SHELF_AUTO_HIDE_ALWAYS_HIDDEN);
1736
1737   InitTouchResizeWindow(gfx::Rect(100, 100, 600, kRootHeight - 200), HTRIGHT);
1738   EXPECT_EQ(gfx::Rect(100, 100, 600, kRootHeight - 200).ToString(),
1739             touch_resize_window_->bounds().ToString());
1740
1741   aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
1742                                        touch_resize_window_.get());
1743
1744   // Drag out of the right border a bit and check if the border is aligned with
1745   // the touch point.
1746   generator.GestureScrollSequence(gfx::Point(715, kRootHeight / 2),
1747                                   gfx::Point(725, kRootHeight / 2),
1748                                   base::TimeDelta::FromMilliseconds(10),
1749                                   5);
1750   EXPECT_EQ(gfx::Rect(100, 100, 625, kRootHeight - 200).ToString(),
1751             touch_resize_window_->bounds().ToString());
1752   // Drag more, but stop before being snapped to the edge.
1753   generator.GestureScrollSequence(gfx::Point(725, kRootHeight / 2),
1754                                   gfx::Point(760, kRootHeight / 2),
1755                                   base::TimeDelta::FromMilliseconds(10),
1756                                   5);
1757   EXPECT_EQ(gfx::Rect(100, 100, 660, kRootHeight - 200).ToString(),
1758             touch_resize_window_->bounds().ToString());
1759   // Drag even more to snap to the edge.
1760   generator.GestureScrollSequence(gfx::Point(760, kRootHeight / 2),
1761                                   gfx::Point(775, kRootHeight / 2),
1762                                   base::TimeDelta::FromMilliseconds(10),
1763                                   5);
1764   EXPECT_EQ(gfx::Rect(100, 100, 700, kRootHeight - 200).ToString(),
1765             touch_resize_window_->bounds().ToString());
1766 }
1767
1768 TEST_F(WorkspaceWindowResizerTest, TouchResizeToEdge_LEFT) {
1769   shelf_layout_manager()->SetAutoHideBehavior(SHELF_AUTO_HIDE_ALWAYS_HIDDEN);
1770
1771   InitTouchResizeWindow(gfx::Rect(100, 100, 600, kRootHeight - 200), HTLEFT);
1772   EXPECT_EQ(gfx::Rect(100, 100, 600, kRootHeight - 200).ToString(),
1773             touch_resize_window_->bounds().ToString());
1774
1775   aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
1776                                        touch_resize_window_.get());
1777
1778   // Drag out of the left border a bit and check if the border is aligned with
1779   // the touch point.
1780   generator.GestureScrollSequence(gfx::Point(85, kRootHeight / 2),
1781                                   gfx::Point(75, kRootHeight / 2),
1782                                   base::TimeDelta::FromMilliseconds(10),
1783                                   5);
1784   EXPECT_EQ(gfx::Rect(75, 100, 625, kRootHeight - 200).ToString(),
1785             touch_resize_window_->bounds().ToString());
1786   // Drag more, but stop before being snapped to the edge.
1787   generator.GestureScrollSequence(gfx::Point(75, kRootHeight / 2),
1788                                   gfx::Point(40, kRootHeight / 2),
1789                                   base::TimeDelta::FromMilliseconds(10),
1790                                   5);
1791   EXPECT_EQ(gfx::Rect(40, 100, 660, kRootHeight - 200).ToString(),
1792             touch_resize_window_->bounds().ToString());
1793   // Drag even more to snap to the edge.
1794   generator.GestureScrollSequence(gfx::Point(40, kRootHeight / 2),
1795                                   gfx::Point(25, kRootHeight / 2),
1796                                   base::TimeDelta::FromMilliseconds(10),
1797                                   5);
1798   EXPECT_EQ(gfx::Rect(0, 100, 700, kRootHeight - 200).ToString(),
1799             touch_resize_window_->bounds().ToString());
1800 }
1801
1802 TEST_F(WorkspaceWindowResizerTest, TouchResizeToEdge_TOP) {
1803   shelf_layout_manager()->SetAutoHideBehavior(SHELF_AUTO_HIDE_ALWAYS_HIDDEN);
1804
1805   InitTouchResizeWindow(gfx::Rect(100, 100, 600, kRootHeight - 200), HTTOP);
1806   EXPECT_EQ(gfx::Rect(100, 100, 600, kRootHeight - 200).ToString(),
1807             touch_resize_window_->bounds().ToString());
1808
1809   aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
1810                                        touch_resize_window_.get());
1811
1812   // Drag out of the top border a bit and check if the border is aligned with
1813   // the touch point.
1814   generator.GestureScrollSequence(gfx::Point(400, 85),
1815                                   gfx::Point(400, 75),
1816                                   base::TimeDelta::FromMilliseconds(10),
1817                                   5);
1818   EXPECT_EQ(gfx::Rect(100, 75, 600, kRootHeight - 175).ToString(),
1819             touch_resize_window_->bounds().ToString());
1820   // Drag more, but stop before being snapped to the edge.
1821   generator.GestureScrollSequence(gfx::Point(400, 75),
1822                                   gfx::Point(400, 40),
1823                                   base::TimeDelta::FromMilliseconds(10),
1824                                   5);
1825   EXPECT_EQ(gfx::Rect(100, 40, 600, kRootHeight - 140).ToString(),
1826             touch_resize_window_->bounds().ToString());
1827   // Drag even more to snap to the edge.
1828   generator.GestureScrollSequence(gfx::Point(400, 40),
1829                                   gfx::Point(400, 25),
1830                                   base::TimeDelta::FromMilliseconds(10),
1831                                   5);
1832   EXPECT_EQ(gfx::Rect(100, 0, 600, kRootHeight - 100).ToString(),
1833             touch_resize_window_->bounds().ToString());
1834 }
1835
1836 TEST_F(WorkspaceWindowResizerTest, TouchResizeToEdge_BOTTOM) {
1837   shelf_layout_manager()->SetAutoHideBehavior(SHELF_AUTO_HIDE_ALWAYS_HIDDEN);
1838
1839   InitTouchResizeWindow(gfx::Rect(100, 100, 600, kRootHeight - 200), HTBOTTOM);
1840   EXPECT_EQ(gfx::Rect(100, 100, 600, kRootHeight - 200).ToString(),
1841             touch_resize_window_->bounds().ToString());
1842
1843   aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
1844                                        touch_resize_window_.get());
1845
1846   // Drag out of the bottom border a bit and check if the border is aligned with
1847   // the touch point.
1848   generator.GestureScrollSequence(gfx::Point(400, kRootHeight - 85),
1849                                   gfx::Point(400, kRootHeight - 75),
1850                                   base::TimeDelta::FromMilliseconds(10),
1851                                   5);
1852   EXPECT_EQ(gfx::Rect(100, 100, 600, kRootHeight - 175).ToString(),
1853             touch_resize_window_->bounds().ToString());
1854   // Drag more, but stop before being snapped to the edge.
1855   generator.GestureScrollSequence(gfx::Point(400, kRootHeight - 75),
1856                                   gfx::Point(400, kRootHeight - 40),
1857                                   base::TimeDelta::FromMilliseconds(10),
1858                                   5);
1859   EXPECT_EQ(gfx::Rect(100, 100, 600, kRootHeight - 140).ToString(),
1860             touch_resize_window_->bounds().ToString());
1861   // Drag even more to snap to the edge.
1862   generator.GestureScrollSequence(gfx::Point(400, kRootHeight - 40),
1863                                   gfx::Point(400, kRootHeight - 25),
1864                                   base::TimeDelta::FromMilliseconds(10),
1865                                   5);
1866   EXPECT_EQ(gfx::Rect(100, 100, 600, kRootHeight - 100).ToString(),
1867             touch_resize_window_->bounds().ToString());
1868 }
1869
1870 TEST_F(WorkspaceWindowResizerTest, PhantomWindowShow) {
1871   if (!SupportsMultipleDisplays())
1872     return;
1873
1874   UpdateDisplay("500x400,500x400");
1875   window_->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60),
1876                              Shell::GetScreen()->GetPrimaryDisplay());
1877   Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
1878   EXPECT_EQ(root_windows[0], window_->GetRootWindow());
1879
1880   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
1881       window_.get(), gfx::Point(0,0), HTCAPTION,
1882       aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
1883   ASSERT_TRUE(resizer.get());
1884   EXPECT_FALSE(resizer->snap_phantom_window_controller_.get());
1885
1886   // The pointer is on the edge but not shared. The snap phantom window
1887   // controller should be non-NULL.
1888   resizer->Drag(CalculateDragPoint(*resizer, -1, 0), 0);
1889   EXPECT_TRUE(resizer->snap_phantom_window_controller_.get());
1890   PhantomWindowController* phantom_controller(
1891       resizer->snap_phantom_window_controller_.get());
1892
1893   // phantom widget only in the left screen.
1894   phantom_controller->Show(gfx::Rect(100, 100, 50, 60));
1895   EXPECT_TRUE(phantom_controller->phantom_widget_);
1896   EXPECT_FALSE(phantom_controller->phantom_widget_start_);
1897   EXPECT_EQ(
1898       root_windows[0],
1899       phantom_controller->phantom_widget_->GetNativeWindow()->GetRootWindow());
1900
1901   // Move phantom widget into the right screen. Test that 2 widgets got created.
1902   phantom_controller->Show(gfx::Rect(600, 100, 50, 60));
1903   EXPECT_TRUE(phantom_controller->phantom_widget_);
1904   EXPECT_TRUE(phantom_controller->phantom_widget_start_);
1905   EXPECT_EQ(
1906       root_windows[1],
1907       phantom_controller->phantom_widget_->GetNativeWindow()->GetRootWindow());
1908   EXPECT_EQ(
1909       root_windows[0],
1910       phantom_controller->phantom_widget_start_->GetNativeWindow()->
1911           GetRootWindow());
1912   RunAnimationTillComplete(phantom_controller->animation_.get());
1913
1914   // Move phantom widget only in the right screen. Start widget should close.
1915   phantom_controller->Show(gfx::Rect(700, 100, 50, 60));
1916   EXPECT_TRUE(phantom_controller->phantom_widget_);
1917   EXPECT_FALSE(phantom_controller->phantom_widget_start_);
1918   EXPECT_EQ(
1919       root_windows[1],
1920       phantom_controller->phantom_widget_->GetNativeWindow()->GetRootWindow());
1921   RunAnimationTillComplete(phantom_controller->animation_.get());
1922
1923   // Move phantom widget into the left screen. Start widget should open.
1924   phantom_controller->Show(gfx::Rect(100, 100, 50, 60));
1925   EXPECT_TRUE(phantom_controller->phantom_widget_);
1926   EXPECT_TRUE(phantom_controller->phantom_widget_start_);
1927   EXPECT_EQ(
1928       root_windows[0],
1929       phantom_controller->phantom_widget_->GetNativeWindow()->GetRootWindow());
1930   EXPECT_EQ(
1931       root_windows[1],
1932       phantom_controller->phantom_widget_start_->GetNativeWindow()->
1933           GetRootWindow());
1934   RunAnimationTillComplete(phantom_controller->animation_.get());
1935
1936   // Move phantom widget while in the left screen. Start widget should close.
1937   phantom_controller->Show(gfx::Rect(200, 100, 50, 60));
1938   EXPECT_TRUE(phantom_controller->phantom_widget_);
1939   EXPECT_FALSE(phantom_controller->phantom_widget_start_);
1940   EXPECT_EQ(
1941       root_windows[0],
1942       phantom_controller->phantom_widget_->GetNativeWindow()->GetRootWindow());
1943   RunAnimationTillComplete(phantom_controller->animation_.get());
1944
1945   // Move phantom widget spanning both screens with most of the window in the
1946   // right screen. Two widgets are created.
1947   phantom_controller->Show(gfx::Rect(495, 100, 50, 60));
1948   EXPECT_TRUE(phantom_controller->phantom_widget_);
1949   EXPECT_TRUE(phantom_controller->phantom_widget_start_);
1950   EXPECT_EQ(
1951       root_windows[1],
1952       phantom_controller->phantom_widget_->GetNativeWindow()->GetRootWindow());
1953   EXPECT_EQ(
1954       root_windows[0],
1955       phantom_controller->phantom_widget_start_->GetNativeWindow()->
1956           GetRootWindow());
1957   RunAnimationTillComplete(phantom_controller->animation_.get());
1958
1959   // Move phantom widget back into the left screen. Phantom widgets should swap.
1960   phantom_controller->Show(gfx::Rect(200, 100, 50, 60));
1961   EXPECT_TRUE(phantom_controller->phantom_widget_);
1962   EXPECT_TRUE(phantom_controller->phantom_widget_start_);
1963   EXPECT_EQ(
1964       root_windows[0],
1965       phantom_controller->phantom_widget_->GetNativeWindow()->GetRootWindow());
1966   EXPECT_EQ(
1967       root_windows[1],
1968       phantom_controller->phantom_widget_start_->GetNativeWindow()->
1969           GetRootWindow());
1970   RunAnimationTillComplete(phantom_controller->animation_.get());
1971
1972   // Hide phantom controller. Both widgets should close.
1973   phantom_controller->Hide();
1974   EXPECT_FALSE(phantom_controller->phantom_widget_);
1975   EXPECT_FALSE(phantom_controller->phantom_widget_start_);
1976 }
1977
1978 }  // namespace internal
1979 }  // namespace ash