1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ui/aura/test/aura_test_base.h"
6#include "ui/aura/test/test_windows.h"
7#include "ui/aura/window.h"
8#include "ui/aura/window_event_dispatcher.h"
9#include "ui/compositor/layer.h"
10#include "ui/compositor/test/test_layers.h"
11#include "ui/views/view.h"
12#include "ui/views/view_constants_aura.h"
13#include "ui/views/widget/widget.h"
14
15namespace views {
16namespace {
17
18// Creates a control widget with the passed in parameters.
19// The caller takes ownership of the returned widget.
20Widget* CreateControlWidget(aura::Window* parent, const gfx::Rect& bounds) {
21  Widget::InitParams params(Widget::InitParams::TYPE_CONTROL);
22  params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
23  params.parent = parent;
24  params.bounds = bounds;
25  Widget* widget = new Widget();
26  widget->Init(params);
27  return widget;
28}
29
30// Sets the name of |window| and |window|'s layer to |name|.
31void SetWindowAndLayerName(aura::Window* window, const std::string& name) {
32  window->SetName(name);
33  window->layer()->set_name(name);
34}
35
36// Returns a string containing the name of each of the child windows (bottommost
37// first) of |parent|. The format of the string is "name1 name2 name3 ...".
38std::string ChildWindowNamesAsString(const aura::Window& parent) {
39  std::string names;
40  typedef std::vector<aura::Window*> Windows;
41  for (Windows::const_iterator it = parent.children().begin();
42       it != parent.children().end(); ++it) {
43    if (!names.empty())
44      names += " ";
45    names += (*it)->name();
46  }
47  return names;
48}
49
50typedef aura::test::AuraTestBase WindowReordererTest;
51
52// Test that views with layers and views with associated windows are reordered
53// according to the view hierarchy.
54TEST_F(WindowReordererTest, Basic) {
55  scoped_ptr<Widget> parent(CreateControlWidget(root_window(),
56                                                gfx::Rect(0, 0, 100, 100)));
57  parent->Show();
58  aura::Window* parent_window = parent->GetNativeWindow();
59
60  View* contents_view = new View();
61  parent->SetContentsView(contents_view);
62
63  // 1) Test that layers for views and layers for windows associated to a host
64  // view are stacked below the layers for any windows not associated to a host
65  // view.
66  View* v = new View();
67  v->SetPaintToLayer(true);
68  v->layer()->set_name("v");
69  contents_view->AddChildView(v);
70
71  scoped_ptr<Widget> w1(CreateControlWidget(parent_window,
72                                            gfx::Rect(0, 1, 100, 101)));
73  SetWindowAndLayerName(w1->GetNativeView(), "w1");
74  w1->Show();
75  scoped_ptr<Widget> w2(CreateControlWidget(parent_window,
76                                            gfx::Rect(0, 2, 100, 102)));
77  SetWindowAndLayerName(w2->GetNativeView(), "w2");
78  w2->Show();
79
80  EXPECT_EQ("w1 w2", ChildWindowNamesAsString(*parent_window));
81  EXPECT_EQ("v w1 w2",
82            ui::test::ChildLayerNamesAsString(*parent_window->layer()));
83
84  View* host_view2 = new View();
85  contents_view->AddChildView(host_view2);
86  w2->GetNativeView()->SetProperty(kHostViewKey, host_view2);
87  EXPECT_EQ("w2 w1", ChildWindowNamesAsString(*parent_window));
88  EXPECT_EQ("v w2 w1",
89            ui::test::ChildLayerNamesAsString(*parent_window->layer()));
90
91  View* host_view1 = new View();
92  w1->GetNativeView()->SetProperty(kHostViewKey, host_view1);
93  contents_view->AddChildViewAt(host_view1, 0);
94  EXPECT_EQ("w1 w2", ChildWindowNamesAsString(*parent_window));
95  EXPECT_EQ("w1 v w2",
96            ui::test::ChildLayerNamesAsString(*parent_window->layer()));
97
98  // 2) Test the z-order of the windows and layers as a result of reordering the
99  // views.
100  contents_view->ReorderChildView(host_view1, -1);
101  EXPECT_EQ("w2 w1", ChildWindowNamesAsString(*parent_window));
102  EXPECT_EQ("v w2 w1",
103            ui::test::ChildLayerNamesAsString(*parent_window->layer()));
104
105  contents_view->ReorderChildView(host_view2, -1);
106  EXPECT_EQ("w1 w2", ChildWindowNamesAsString(*parent_window));
107  EXPECT_EQ("v w1 w2",
108            ui::test::ChildLayerNamesAsString(*parent_window->layer()));
109
110  // 3) Test the z-order of the windows and layers as a result of reordering the
111  // views in situations where the window order remains unchanged.
112  contents_view->ReorderChildView(v, -1);
113  EXPECT_EQ("w1 w2", ChildWindowNamesAsString(*parent_window));
114  EXPECT_EQ("w1 w2 v",
115            ui::test::ChildLayerNamesAsString(*parent_window->layer()));
116
117  contents_view->ReorderChildView(host_view2, -1);
118  EXPECT_EQ("w1 w2", ChildWindowNamesAsString(*parent_window));
119  EXPECT_EQ("w1 v w2",
120            ui::test::ChildLayerNamesAsString(*parent_window->layer()));
121
122  // Work around for bug in NativeWidgetAura.
123  // TODO: fix bug and remove this.
124  parent->Close();
125}
126
127// Test that different orderings of:
128// - adding a window to a parent widget
129// - adding a "host" view to a parent widget
130// - associating the "host" view and window
131// all correctly reorder the child windows and layers.
132TEST_F(WindowReordererTest, Association) {
133  scoped_ptr<Widget> parent(CreateControlWidget(root_window(),
134                                                gfx::Rect(0, 0, 100, 100)));
135  parent->Show();
136  aura::Window* parent_window = parent->GetNativeWindow();
137
138  View* contents_view = new View();
139  parent->SetContentsView(contents_view);
140
141  aura::Window* w1 = aura::test::CreateTestWindowWithId(0,
142      parent->GetNativeWindow());
143  SetWindowAndLayerName(w1, "w1");
144
145  aura::Window* w2 = aura::test::CreateTestWindowWithId(0, NULL);
146  SetWindowAndLayerName(w2, "w2");
147
148  View* host_view2 = new View();
149
150  // 1) Test that parenting the window to the parent widget last results in a
151  //    correct ordering of child windows and layers.
152  contents_view->AddChildView(host_view2);
153  w2->SetProperty(views::kHostViewKey, host_view2);
154  EXPECT_EQ("w1", ChildWindowNamesAsString(*parent_window));
155  EXPECT_EQ("w1",
156            ui::test::ChildLayerNamesAsString(*parent_window->layer()));
157
158  parent_window->AddChild(w2);
159  EXPECT_EQ("w2 w1", ChildWindowNamesAsString(*parent_window));
160  EXPECT_EQ("w2 w1",
161            ui::test::ChildLayerNamesAsString(*parent_window->layer()));
162
163  // 2) Test that associating the window and "host" view last results in a
164  // correct ordering of child windows and layers.
165  View* host_view1 = new View();
166  contents_view->AddChildViewAt(host_view1, 0);
167  EXPECT_EQ("w2 w1", ChildWindowNamesAsString(*parent_window));
168  EXPECT_EQ("w2 w1",
169            ui::test::ChildLayerNamesAsString(*parent_window->layer()));
170
171  w1->SetProperty(views::kHostViewKey, host_view1);
172  EXPECT_EQ("w1 w2", ChildWindowNamesAsString(*parent_window));
173  EXPECT_EQ("w1 w2",
174            ui::test::ChildLayerNamesAsString(*parent_window->layer()));
175
176  // 3) Test that parenting the "host" view to the parent widget last results
177  // in a correct ordering of child windows and layers.
178  contents_view->RemoveChildView(host_view2);
179  contents_view->AddChildViewAt(host_view2, 0);
180  EXPECT_EQ("w2 w1", ChildWindowNamesAsString(*parent_window));
181  EXPECT_EQ("w2 w1",
182            ui::test::ChildLayerNamesAsString(*parent_window->layer()));
183
184  // Work around for bug in NativeWidgetAura.
185  // TODO: fix bug and remove this.
186  parent->Close();
187}
188
189// It is possible to associate a window to a view which has a parent layer
190// (other than the widget layer). In this case, the parent layer of the host
191// view and the parent layer of the associated window are different. Test that
192// the layers and windows are properly reordered in this case.
193TEST_F(WindowReordererTest, HostViewParentHasLayer) {
194  scoped_ptr<Widget> parent(CreateControlWidget(root_window(),
195                                                gfx::Rect(0, 0, 100, 100)));
196  parent->Show();
197  aura::Window* parent_window = parent->GetNativeWindow();
198
199  View* contents_view = new View();
200  parent->SetContentsView(contents_view);
201
202  // Create the following view hierarchy. (*) denotes views which paint to a
203  // layer.
204  //
205  // contents_view
206  // +-- v1
207  //     +-- v11*
208  //     +-- v12 (attached window)
209  //     +-- v13*
210  // +--v2*
211
212  View* v1 = new View();
213  contents_view->AddChildView(v1);
214
215  View* v11 = new View();
216  v11->SetPaintToLayer(true);
217  v11->layer()->set_name("v11");
218  v1->AddChildView(v11);
219
220  scoped_ptr<Widget> w(CreateControlWidget(parent_window,
221                                           gfx::Rect(0, 1, 100, 101)));
222  SetWindowAndLayerName(w->GetNativeView(), "w");
223  w->Show();
224
225  View* v12 = new View();
226  v1->AddChildView(v12);
227  w->GetNativeView()->SetProperty(kHostViewKey, v12);
228
229  View* v13 = new View();
230  v13->SetPaintToLayer(true);
231  v13->layer()->set_name("v13");
232  v1->AddChildView(v13);
233
234  View* v2 = new View();
235  v2->SetPaintToLayer(true);
236  v2->layer()->set_name("v2");
237  contents_view->AddChildView(v2);
238
239  // Test intial state.
240  EXPECT_EQ("w", ChildWindowNamesAsString(*parent_window));
241  EXPECT_EQ("v11 w v13 v2",
242            ui::test::ChildLayerNamesAsString(*parent_window->layer()));
243
244  // |w|'s layer should be stacked above |v1|'s layer.
245  v1->SetPaintToLayer(true);
246  v1->layer()->set_name("v1");
247  EXPECT_EQ("w", ChildWindowNamesAsString(*parent_window));
248  EXPECT_EQ("v1 w v2",
249            ui::test::ChildLayerNamesAsString(*parent_window->layer()));
250
251  // Test moving the host view from one view with a layer to another.
252  v2->AddChildView(v12);
253  EXPECT_EQ("w", ChildWindowNamesAsString(*parent_window));
254  EXPECT_EQ("v1 v2 w",
255            ui::test::ChildLayerNamesAsString(*parent_window->layer()));
256
257  // Work around for bug in NativeWidgetAura.
258  // TODO: fix bug and remove this.
259  parent->Close();
260}
261
262}  // namespace
263}  // namespace views
264