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