1 // Copyright 2018 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 "components/exo/fullscreen_shell_surface.h"
6
7 #include "base/bind.h"
8 #include "components/exo/buffer.h"
9 #include "components/exo/shell_surface_util.h"
10 #include "components/exo/sub_surface.h"
11 #include "components/exo/surface.h"
12 #include "components/exo/test/exo_test_base_views.h"
13 #include "components/exo/wm_helper.h"
14 #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 #include "ui/accessibility/ax_enums.mojom.h"
17 #include "ui/accessibility/ax_node_data.h"
18 #include "ui/accessibility/ax_tree_id.h"
19 #include "ui/aura/env.h"
20 #include "ui/aura/window.h"
21 #include "ui/compositor/compositor.h"
22 #include "ui/gfx/buffer_types.h"
23 #include "ui/views/widget/widget.h"
24
25 namespace exo {
26 namespace {
27
28 using FullscreenShellSurfaceTest = test::ExoTestBaseViews;
29
CreateGpuMemoryBuffer(const gfx::Size & size,gfx::BufferFormat format)30 std::unique_ptr<gfx::GpuMemoryBuffer> CreateGpuMemoryBuffer(
31 const gfx::Size& size,
32 gfx::BufferFormat format) {
33 return aura::Env::GetInstance()
34 ->context_factory()
35 ->GetGpuMemoryBufferManager()
36 ->CreateGpuMemoryBuffer(size, format, gfx::BufferUsage::GPU_READ,
37 gpu::kNullSurfaceHandle);
38 }
39
DestroyFullscreenShellSurface(std::unique_ptr<FullscreenShellSurface> * fullscreen_surface)40 void DestroyFullscreenShellSurface(
41 std::unique_ptr<FullscreenShellSurface>* fullscreen_surface) {
42 fullscreen_surface->reset();
43 }
44
Close(int * close_call_count)45 void Close(int* close_call_count) {
46 (*close_call_count)++;
47 }
48
TEST_F(FullscreenShellSurfaceTest,SurfaceDestroyedCallback)49 TEST_F(FullscreenShellSurfaceTest, SurfaceDestroyedCallback) {
50 std::unique_ptr<Surface> surface(new Surface);
51 std::unique_ptr<FullscreenShellSurface> fullscreen_surface(
52 new FullscreenShellSurface());
53 fullscreen_surface->SetSurface(surface.get());
54
55 fullscreen_surface->set_surface_destroyed_callback(base::BindOnce(
56 &DestroyFullscreenShellSurface, base::Unretained(&fullscreen_surface)));
57
58 // Change the surface so the commit has an actual change otherwise it triggers
59 // a DCHECK during frame submission.
60 surface->SetViewport(gfx::Size(64, 64));
61 surface->Commit();
62
63 EXPECT_TRUE(fullscreen_surface.get());
64 surface.reset();
65 EXPECT_FALSE(fullscreen_surface.get());
66 }
67
TEST_F(FullscreenShellSurfaceTest,CloseCallback)68 TEST_F(FullscreenShellSurfaceTest, CloseCallback) {
69 gfx::Size buffer_size(64, 64);
70 std::unique_ptr<Buffer> buffer(new Buffer(
71 CreateGpuMemoryBuffer(buffer_size, gfx::BufferFormat::RGBA_8888)));
72 std::unique_ptr<Surface> surface(new Surface);
73 std::unique_ptr<FullscreenShellSurface> fullscreen_surface(
74 new FullscreenShellSurface());
75 fullscreen_surface->SetSurface(surface.get());
76
77 int close_call_count = 0;
78 fullscreen_surface->set_close_callback(
79 base::BindRepeating(&Close, base::Unretained(&close_call_count)));
80
81 surface->Attach(buffer.get());
82 surface->Commit();
83
84 EXPECT_EQ(0, close_call_count);
85 fullscreen_surface->Close();
86 EXPECT_EQ(1, close_call_count);
87 }
88
TEST_F(FullscreenShellSurfaceTest,ShouldShowWindowTitle)89 TEST_F(FullscreenShellSurfaceTest, ShouldShowWindowTitle) {
90 std::unique_ptr<Surface> surface(new Surface);
91 std::unique_ptr<FullscreenShellSurface> fullscreen_surface(
92 new FullscreenShellSurface());
93 fullscreen_surface->SetSurface(surface.get());
94
95 EXPECT_FALSE(fullscreen_surface->ShouldShowWindowTitle());
96 }
97
TEST_F(FullscreenShellSurfaceTest,SetApplicationId)98 TEST_F(FullscreenShellSurfaceTest, SetApplicationId) {
99 gfx::Size buffer_size(64, 64);
100 std::unique_ptr<Buffer> buffer(new Buffer(
101 CreateGpuMemoryBuffer(buffer_size, gfx::BufferFormat::RGBA_8888)));
102 std::unique_ptr<Surface> surface(new Surface);
103 std::unique_ptr<FullscreenShellSurface> fullscreen_surface(
104 new FullscreenShellSurface());
105 fullscreen_surface->SetSurface(surface.get());
106
107 EXPECT_TRUE(fullscreen_surface->GetWidget());
108 fullscreen_surface->SetApplicationId("test-id");
109
110 surface->Attach(buffer.get());
111 surface->Commit();
112 aura::Window* window = fullscreen_surface->GetWidget()->GetNativeWindow();
113 EXPECT_EQ("test-id", *GetShellApplicationId(window));
114 fullscreen_surface->SetApplicationId("test");
115 EXPECT_EQ("test", *GetShellApplicationId(window));
116
117 fullscreen_surface->SetApplicationId(nullptr);
118 EXPECT_EQ(nullptr, GetShellApplicationId(window));
119 }
120
TEST_F(FullscreenShellSurfaceTest,SetStartupId)121 TEST_F(FullscreenShellSurfaceTest, SetStartupId) {
122 gfx::Size buffer_size(64, 64);
123 std::unique_ptr<Buffer> buffer(new Buffer(
124 CreateGpuMemoryBuffer(buffer_size, gfx::BufferFormat::RGBA_8888)));
125 std::unique_ptr<Surface> surface(new Surface);
126 std::unique_ptr<FullscreenShellSurface> fullscreen_surface(
127 new FullscreenShellSurface());
128 fullscreen_surface->SetSurface(surface.get());
129
130 EXPECT_TRUE(fullscreen_surface->GetWidget());
131 fullscreen_surface->SetStartupId("test-id");
132
133 surface->Attach(buffer.get());
134 surface->Commit();
135 aura::Window* window = fullscreen_surface->GetWidget()->GetNativeWindow();
136 EXPECT_EQ("test-id", *GetShellStartupId(window));
137 fullscreen_surface->SetStartupId("test");
138 EXPECT_EQ("test", *GetShellStartupId(window));
139
140 fullscreen_surface->SetStartupId(nullptr);
141 EXPECT_EQ(nullptr, GetShellStartupId(window));
142 }
143
TEST_F(FullscreenShellSurfaceTest,Maximize)144 TEST_F(FullscreenShellSurfaceTest, Maximize) {
145 gfx::Size buffer_size(64, 64);
146 std::unique_ptr<Buffer> buffer(new Buffer(
147 CreateGpuMemoryBuffer(buffer_size, gfx::BufferFormat::RGBA_8888)));
148 std::unique_ptr<Surface> surface(new Surface);
149 std::unique_ptr<FullscreenShellSurface> fullscreen_surface(
150 new FullscreenShellSurface());
151 fullscreen_surface->SetSurface(surface.get());
152
153 surface->Attach(buffer.get());
154 surface->Commit();
155 fullscreen_surface->Maximize();
156 EXPECT_TRUE(fullscreen_surface->GetWidget()->IsMaximized());
157 }
158
TEST_F(FullscreenShellSurfaceTest,Minimize)159 TEST_F(FullscreenShellSurfaceTest, Minimize) {
160 gfx::Size buffer_size(64, 64);
161 std::unique_ptr<Buffer> buffer(new Buffer(
162 CreateGpuMemoryBuffer(buffer_size, gfx::BufferFormat::RGBA_8888)));
163 std::unique_ptr<Surface> surface(new Surface);
164 std::unique_ptr<FullscreenShellSurface> fullscreen_surface(
165 new FullscreenShellSurface());
166 fullscreen_surface->SetSurface(surface.get());
167
168 surface->Attach(buffer.get());
169 surface->Commit();
170 fullscreen_surface->Minimize();
171 EXPECT_TRUE(fullscreen_surface->GetWidget()->IsMinimized());
172 }
173
TEST_F(FullscreenShellSurfaceTest,Bounds)174 TEST_F(FullscreenShellSurfaceTest, Bounds) {
175 aura::Window* root_window =
176 WMHelper::GetInstance()->GetRootWindowForNewWindows();
177 gfx::Rect new_root_bounds(10, 10, 100, 100);
178 root_window->SetBounds(new_root_bounds);
179
180 gfx::Size buffer_size(64, 64);
181 std::unique_ptr<Buffer> buffer(new Buffer(
182 CreateGpuMemoryBuffer(buffer_size, gfx::BufferFormat::RGBA_8888)));
183 std::unique_ptr<Surface> surface(new Surface);
184 std::unique_ptr<FullscreenShellSurface> fullscreen_surface(
185 new FullscreenShellSurface());
186 fullscreen_surface->SetSurface(surface.get());
187
188 surface->Attach(buffer.get());
189 surface->Commit();
190 gfx::Rect fullscreen_bounds =
191 fullscreen_surface->GetWidget()->GetWindowBoundsInScreen();
192 gfx::Rect expected_bounds(new_root_bounds.size());
193 EXPECT_EQ(fullscreen_bounds, expected_bounds);
194 }
195
TEST_F(FullscreenShellSurfaceTest,BoundsWithPartiallyOffscreenSubSurface)196 TEST_F(FullscreenShellSurfaceTest, BoundsWithPartiallyOffscreenSubSurface) {
197 aura::Window* root_window =
198 WMHelper::GetInstance()->GetRootWindowForNewWindows();
199 gfx::Rect new_root_bounds(10, 10, 100, 100);
200 gfx::Rect expected_bounds(new_root_bounds.size());
201 root_window->SetBounds(new_root_bounds);
202
203 gfx::Size buffer_size(100, 100);
204 auto buffer = std::make_unique<Buffer>(
205 CreateGpuMemoryBuffer(buffer_size, gfx::BufferFormat::RGBA_8888));
206 auto parent = std::make_unique<Surface>();
207 auto fullscreen_surface = std::make_unique<FullscreenShellSurface>();
208 fullscreen_surface->SetSurface(parent.get());
209
210 parent->Attach(buffer.get());
211 parent->Commit();
212 EXPECT_EQ(fullscreen_surface->GetWidget()->GetWindowBoundsInScreen(),
213 expected_bounds);
214 EXPECT_EQ(parent->window()->bounds(), expected_bounds);
215
216 auto surface = std::make_unique<Surface>();
217 auto sub_surface = std::make_unique<SubSurface>(surface.get(), parent.get());
218 surface->Attach(buffer.get());
219 sub_surface->SetPosition(gfx::Point(-50, -50));
220
221 parent->Commit();
222 // Make sure the sub-surface doesn't affect the Fullscreen Shell's Window
223 // size/position.
224 EXPECT_EQ(fullscreen_surface->GetWidget()->GetWindowBoundsInScreen(),
225 expected_bounds);
226 // The root surface should also have the same position/size as before.
227 EXPECT_EQ(parent->window()->bounds(), expected_bounds);
228 }
229
TEST_F(FullscreenShellSurfaceTest,SetAXChildTree)230 TEST_F(FullscreenShellSurfaceTest, SetAXChildTree) {
231 std::unique_ptr<Surface> surface(new Surface);
232 std::unique_ptr<FullscreenShellSurface> fullscreen_surface(
233 new FullscreenShellSurface());
234 fullscreen_surface->SetSurface(surface.get());
235 ui::AXNodeData node_data;
236 fullscreen_surface->GetAccessibleNodeData(&node_data);
237 EXPECT_FALSE(
238 node_data.HasStringAttribute(ax::mojom::StringAttribute::kChildTreeId));
239
240 ui::AXTreeID tree_id = ui::AXTreeID::CreateNewAXTreeID();
241 fullscreen_surface->SetChildAxTreeId(tree_id);
242 fullscreen_surface->GetAccessibleNodeData(&node_data);
243 EXPECT_TRUE(
244 node_data.HasStringAttribute(ax::mojom::StringAttribute::kChildTreeId));
245 }
246
TEST_F(FullscreenShellSurfaceTest,SwapSurface)247 TEST_F(FullscreenShellSurfaceTest, SwapSurface) {
248 std::unique_ptr<Surface> surface(new Surface);
249 std::unique_ptr<FullscreenShellSurface> fullscreen_surface(
250 new FullscreenShellSurface());
251 fullscreen_surface->SetSurface(surface.get());
252 fullscreen_surface->SetEnabled(true);
253 fullscreen_surface->set_surface_destroyed_callback(base::BindOnce(
254 &DestroyFullscreenShellSurface, base::Unretained(&fullscreen_surface)));
255 EXPECT_EQ(surface.get(), fullscreen_surface->root_surface());
256 std::unique_ptr<Surface> surface2(new Surface);
257 fullscreen_surface->SetSurface(surface2.get());
258 EXPECT_EQ(surface2.get(), fullscreen_surface->root_surface());
259 EXPECT_NE(surface.get(), fullscreen_surface->root_surface());
260 // RootWindow->FullscreenShellSurface->FullscreenShellSurfaceHost->ExoSurface
261 EXPECT_EQ(1ul, WMHelper::GetInstance()
262 ->GetRootWindowForNewWindows()
263 ->children()[0]
264 ->children()[0]
265 ->children()
266 .size());
267 }
268
TEST_F(FullscreenShellSurfaceTest,RemoveSurface)269 TEST_F(FullscreenShellSurfaceTest, RemoveSurface) {
270 std::unique_ptr<Surface> surface(new Surface);
271 std::unique_ptr<FullscreenShellSurface> fullscreen_surface(
272 new FullscreenShellSurface());
273 fullscreen_surface->SetSurface(surface.get());
274 fullscreen_surface->SetEnabled(true);
275 fullscreen_surface->set_surface_destroyed_callback(base::BindOnce(
276 &DestroyFullscreenShellSurface, base::Unretained(&fullscreen_surface)));
277 EXPECT_EQ(surface.get(), fullscreen_surface->root_surface());
278 fullscreen_surface->SetSurface(nullptr);
279 EXPECT_FALSE(fullscreen_surface->root_surface());
280 // RootWindow->FullscreenShellSurface->FullscreenShellSurfaceHost->null
281 EXPECT_EQ(0ul, WMHelper::GetInstance()
282 ->GetRootWindowForNewWindows()
283 ->children()[0]
284 ->children()[0]
285 ->children()
286 .size());
287 }
288
289 } // namespace
290 } // namespace exo
291