1 // Copyright 2015 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/display.h"
6 #include "ash/public/cpp/shell_window_ids.h"
7 #include "ash/public/cpp/window_pin_type.h"
8 #include "ash/wm/desks/desks_util.h"
9 #include "components/exo/buffer.h"
10 #include "components/exo/client_controlled_shell_surface.h"
11 #include "components/exo/data_device.h"
12 #include "components/exo/data_device_delegate.h"
13 #include "components/exo/file_helper.h"
14 #include "components/exo/shared_memory.h"
15 #include "components/exo/shell_surface.h"
16 #include "components/exo/sub_surface.h"
17 #include "components/exo/surface.h"
18 #include "components/exo/test/exo_test_base.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20 
21 #if defined(USE_OZONE)
22 #include "ui/gfx/native_pixmap.h"
23 #include "ui/ozone/public/ozone_platform.h"
24 #include "ui/ozone/public/surface_factory_ozone.h"
25 #endif
26 
27 namespace exo {
28 namespace {
29 
30 using DisplayTest = test::ExoTestBase;
31 
TEST_F(DisplayTest,CreateSurface)32 TEST_F(DisplayTest, CreateSurface) {
33   std::unique_ptr<Display> display(new Display);
34 
35   // Creating a surface should succeed.
36   std::unique_ptr<Surface> surface = display->CreateSurface();
37   EXPECT_TRUE(surface);
38 }
39 
TEST_F(DisplayTest,CreateSharedMemory)40 TEST_F(DisplayTest, CreateSharedMemory) {
41   std::unique_ptr<Display> display(new Display);
42 
43   int shm_size = 8192;
44   base::UnsafeSharedMemoryRegion shared_memory =
45       base::UnsafeSharedMemoryRegion::Create(shm_size);
46   ASSERT_TRUE(shared_memory.IsValid());
47 
48   // Creating a shared memory instance from a valid region should succeed.
49   std::unique_ptr<SharedMemory> shm1 =
50       display->CreateSharedMemory(std::move(shared_memory));
51   EXPECT_TRUE(shm1);
52 
53   // Creating a shared memory instance from a invalid region should fail.
54   std::unique_ptr<SharedMemory> shm2 =
55       display->CreateSharedMemory(base::UnsafeSharedMemoryRegion());
56   EXPECT_FALSE(shm2);
57 }
58 
59 #if defined(USE_OZONE)
60 // The test crashes: crbug.com/622724
TEST_F(DisplayTest,DISABLED_CreateLinuxDMABufBuffer)61 TEST_F(DisplayTest, DISABLED_CreateLinuxDMABufBuffer) {
62   const gfx::Size buffer_size(256, 256);
63 
64   std::unique_ptr<Display> display(new Display);
65   // Creating a prime buffer from a native pixmap handle should succeed.
66   scoped_refptr<gfx::NativePixmap> pixmap =
67       ui::OzonePlatform::GetInstance()
68           ->GetSurfaceFactoryOzone()
69           ->CreateNativePixmap(gfx::kNullAcceleratedWidget, VK_NULL_HANDLE,
70                                buffer_size, gfx::BufferFormat::RGBA_8888,
71                                gfx::BufferUsage::GPU_READ);
72   gfx::NativePixmapHandle native_pixmap_handle = pixmap->ExportHandle();
73   std::unique_ptr<Buffer> buffer1 = display->CreateLinuxDMABufBuffer(
74       buffer_size, gfx::BufferFormat::RGBA_8888,
75       std::move(native_pixmap_handle), false);
76   EXPECT_TRUE(buffer1);
77 
78   // Create a handle without a file descriptor.
79   native_pixmap_handle = pixmap->ExportHandle();
80   native_pixmap_handle.planes[0].fd.reset();
81 
82   // Creating a prime buffer using an invalid fd should fail.
83   std::unique_ptr<Buffer> buffer2 = display->CreateLinuxDMABufBuffer(
84       buffer_size, gfx::BufferFormat::RGBA_8888,
85       std::move(native_pixmap_handle), false);
86   EXPECT_FALSE(buffer2);
87 }
88 
89 // TODO(dcastagna): Add YV12 unittest once we can allocate the buffer
90 // via Ozone. crbug.com/618516
91 
92 #endif
93 
TEST_F(DisplayTest,CreateShellSurface)94 TEST_F(DisplayTest, CreateShellSurface) {
95   std::unique_ptr<Display> display(new Display);
96 
97   // Create two surfaces.
98   std::unique_ptr<Surface> surface1 = display->CreateSurface();
99   ASSERT_TRUE(surface1);
100   std::unique_ptr<Surface> surface2 = display->CreateSurface();
101   ASSERT_TRUE(surface2);
102 
103   // Create a shell surface for surface1.
104   std::unique_ptr<ShellSurface> shell_surface1 =
105       display->CreateShellSurface(surface1.get());
106   EXPECT_TRUE(shell_surface1);
107 
108   // Create a shell surface for surface2.
109   std::unique_ptr<ShellSurface> shell_surface2 =
110       display->CreateShellSurface(surface2.get());
111   EXPECT_TRUE(shell_surface2);
112 }
113 
TEST_F(DisplayTest,CreateClientControlledShellSurface)114 TEST_F(DisplayTest, CreateClientControlledShellSurface) {
115   std::unique_ptr<Display> display(new Display);
116 
117   // Create two surfaces.
118   std::unique_ptr<Surface> surface1 = display->CreateSurface();
119   ASSERT_TRUE(surface1);
120   std::unique_ptr<Surface> surface2 = display->CreateSurface();
121   ASSERT_TRUE(surface2);
122 
123   // Create a remote shell surface for surface1.
124   std::unique_ptr<ClientControlledShellSurface> shell_surface1 =
125       display->CreateClientControlledShellSurface(
126           surface1.get(), ash::kShellWindowId_SystemModalContainer,
127           2.0 /* default_scale_factor */);
128   ASSERT_TRUE(shell_surface1);
129   EXPECT_EQ(shell_surface1->scale(), 2.0);
130 
131   // Create a remote shell surface for surface2.
132   std::unique_ptr<ShellSurfaceBase> shell_surface2 =
133       display->CreateClientControlledShellSurface(
134           surface2.get(), ash::desks_util::GetActiveDeskContainerId(),
135           1.0 /* default_scale_factor */);
136   EXPECT_TRUE(shell_surface2);
137 }
138 
TEST_F(DisplayTest,CreateSubSurface)139 TEST_F(DisplayTest, CreateSubSurface) {
140   std::unique_ptr<Display> display(new Display);
141 
142   // Create child, parent and toplevel surfaces.
143   std::unique_ptr<Surface> child = display->CreateSurface();
144   ASSERT_TRUE(child);
145   std::unique_ptr<Surface> parent = display->CreateSurface();
146   ASSERT_TRUE(parent);
147   std::unique_ptr<Surface> toplevel = display->CreateSurface();
148   ASSERT_TRUE(toplevel);
149 
150   // Attempting to create a sub surface for child with child as its parent
151   // should fail.
152   EXPECT_FALSE(display->CreateSubSurface(child.get(), child.get()));
153 
154   // Create a sub surface for child.
155   std::unique_ptr<SubSurface> child_sub_surface =
156       display->CreateSubSurface(child.get(), toplevel.get());
157   EXPECT_TRUE(child_sub_surface);
158 
159   // Attempting to create another sub surface when already assigned the role of
160   // sub surface should fail.
161   EXPECT_FALSE(display->CreateSubSurface(child.get(), parent.get()));
162 
163   // Deleting the sub surface should allow a new sub surface to be created.
164   child_sub_surface.reset();
165   child_sub_surface = display->CreateSubSurface(child.get(), parent.get());
166   EXPECT_TRUE(child_sub_surface);
167 
168   std::unique_ptr<Surface> sibling = display->CreateSurface();
169   ASSERT_TRUE(sibling);
170 
171   // Create a sub surface for sibiling.
172   std::unique_ptr<SubSurface> sibling_sub_surface =
173       display->CreateSubSurface(sibling.get(), parent.get());
174   EXPECT_TRUE(sibling_sub_surface);
175 
176   // Create a shell surface for toplevel surface.
177   std::unique_ptr<ShellSurface> shell_surface =
178       display->CreateShellSurface(toplevel.get());
179   EXPECT_TRUE(shell_surface);
180 
181   // Attempting to create a sub surface when already assigned the role of
182   // shell surface should fail.
183   EXPECT_FALSE(display->CreateSubSurface(toplevel.get(), parent.get()));
184 
185   std::unique_ptr<Surface> grandchild = display->CreateSurface();
186   ASSERT_TRUE(grandchild);
187   // Create a sub surface for grandchild.
188   std::unique_ptr<SubSurface> grandchild_sub_surface =
189       display->CreateSubSurface(grandchild.get(), child.get());
190   EXPECT_TRUE(grandchild_sub_surface);
191 
192   // Attempting to create a sub surface for parent with child as its parent
193   // should fail.
194   EXPECT_FALSE(display->CreateSubSurface(parent.get(), child.get()));
195 
196   // Attempting to create a sub surface for parent with grandchild as its parent
197   // should fail.
198   EXPECT_FALSE(display->CreateSubSurface(parent.get(), grandchild.get()));
199 
200   // Create a sub surface for parent.
201   EXPECT_TRUE(display->CreateSubSurface(parent.get(), toplevel.get()));
202 }
203 
204 class TestDataDeviceDelegate : public DataDeviceDelegate {
205  public:
206   // Overriden from DataDeviceDelegate:
OnDataDeviceDestroying(DataDevice * data_device)207   void OnDataDeviceDestroying(DataDevice* data_device) override {}
OnDataOffer(DataOffer::Purpose purpose)208   DataOffer* OnDataOffer(DataOffer::Purpose purpose) override {
209     return nullptr;
210   }
OnEnter(Surface * surface,const gfx::PointF & location,const DataOffer & data_offer)211   void OnEnter(Surface* surface,
212                const gfx::PointF& location,
213                const DataOffer& data_offer) override {}
OnLeave()214   void OnLeave() override {}
OnMotion(base::TimeTicks time_stamp,const gfx::PointF & location)215   void OnMotion(base::TimeTicks time_stamp,
216                 const gfx::PointF& location) override {}
OnDrop()217   void OnDrop() override {}
OnSelection(const DataOffer & data_offer)218   void OnSelection(const DataOffer& data_offer) override {}
CanAcceptDataEventsForSurface(Surface * surface) const219   bool CanAcceptDataEventsForSurface(Surface* surface) const override {
220     return false;
221   }
222 };
223 
224 class TestFileHelper : public FileHelper {
225  public:
226   // Overriden from TestFileHelper:
TestFileHelper()227   TestFileHelper() {}
GetMimeTypeForUriList() const228   std::string GetMimeTypeForUriList() const override { return ""; }
GetUrlFromPath(const std::string & app_id,const base::FilePath & path,GURL * out)229   bool GetUrlFromPath(const std::string& app_id,
230                       const base::FilePath& path,
231                       GURL* out) override {
232     return true;
233   }
HasUrlsInPickle(const base::Pickle & pickle)234   bool HasUrlsInPickle(const base::Pickle& pickle) override { return false; }
GetUrlsFromPickle(const std::string & app_id,const base::Pickle & pickle,UrlsFromPickleCallback callback)235   void GetUrlsFromPickle(const std::string& app_id,
236                          const base::Pickle& pickle,
237                          UrlsFromPickleCallback callback) override {}
238 };
239 
TEST_F(DisplayTest,CreateDataDevice)240 TEST_F(DisplayTest, CreateDataDevice) {
241   TestDataDeviceDelegate device_delegate;
242   Display display(nullptr, nullptr, std::make_unique<TestFileHelper>());
243 
244   std::unique_ptr<DataDevice> device =
245       display.CreateDataDevice(&device_delegate);
246   EXPECT_TRUE(device.get());
247 }
248 
TEST_F(DisplayTest,PinnedAlwaysOnTopWindow)249 TEST_F(DisplayTest, PinnedAlwaysOnTopWindow) {
250   Display display;
251 
252   std::unique_ptr<Surface> surface = display.CreateSurface();
253   ASSERT_TRUE(surface);
254 
255   std::unique_ptr<ClientControlledShellSurface> shell_surface =
256       display.CreateClientControlledShellSurface(
257           surface.get(), ash::desks_util::GetActiveDeskContainerId(),
258           2.0 /* default_scale_factor */);
259   ASSERT_TRUE(shell_surface);
260   EXPECT_EQ(shell_surface->scale(), 2.0);
261 
262   // This should not crash
263   shell_surface->SetAlwaysOnTop(true);
264   shell_surface->SetPinned(ash::WindowPinType::kPinned);
265 }
266 
267 }  // namespace
268 }  // namespace exo
269