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