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 "ui/ozone/platform/wayland/common/wayland_util.h"
6 
7 #include <xdg-shell-client-protocol.h>
8 #include <xdg-shell-unstable-v6-client-protocol.h>
9 
10 #include "ui/base/hit_test.h"
11 #include "ui/ozone/platform/wayland/host/wayland_connection.h"
12 #include "ui/ozone/platform/wayland/host/wayland_shm_buffer.h"
13 #include "ui/ozone/platform/wayland/host/wayland_surface.h"
14 #include "ui/ozone/platform/wayland/host/wayland_window.h"
15 
16 namespace wl {
17 
18 namespace {
19 
20 const SkColorType kColorType = kBGRA_8888_SkColorType;
21 
IdentifyDirectionStable(int hittest)22 uint32_t IdentifyDirectionStable(int hittest) {
23   uint32_t direction = 0;
24   switch (hittest) {
25     case HTBOTTOM:
26       direction = xdg_toplevel_resize_edge::XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM;
27       break;
28     case HTBOTTOMLEFT:
29       direction =
30           xdg_toplevel_resize_edge::XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT;
31       break;
32     case HTBOTTOMRIGHT:
33       direction =
34           xdg_toplevel_resize_edge::XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT;
35       break;
36     case HTLEFT:
37       direction = xdg_toplevel_resize_edge::XDG_TOPLEVEL_RESIZE_EDGE_LEFT;
38       break;
39     case HTRIGHT:
40       direction = xdg_toplevel_resize_edge::XDG_TOPLEVEL_RESIZE_EDGE_RIGHT;
41       break;
42     case HTTOP:
43       direction = xdg_toplevel_resize_edge::XDG_TOPLEVEL_RESIZE_EDGE_TOP;
44       break;
45     case HTTOPLEFT:
46       direction = xdg_toplevel_resize_edge::XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT;
47       break;
48     case HTTOPRIGHT:
49       direction = xdg_toplevel_resize_edge::XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT;
50       break;
51     default:
52       direction = xdg_toplevel_resize_edge::XDG_TOPLEVEL_RESIZE_EDGE_NONE;
53       break;
54   }
55   return direction;
56 }
57 
IdentifyDirectionV6(int hittest)58 uint32_t IdentifyDirectionV6(int hittest) {
59   uint32_t direction = 0;
60   switch (hittest) {
61     case HTBOTTOM:
62       direction =
63           zxdg_toplevel_v6_resize_edge::ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM;
64       break;
65     case HTBOTTOMLEFT:
66       direction = zxdg_toplevel_v6_resize_edge::
67           ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM_LEFT;
68       break;
69     case HTBOTTOMRIGHT:
70       direction = zxdg_toplevel_v6_resize_edge::
71           ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM_RIGHT;
72       break;
73     case HTLEFT:
74       direction =
75           zxdg_toplevel_v6_resize_edge::ZXDG_TOPLEVEL_V6_RESIZE_EDGE_LEFT;
76       break;
77     case HTRIGHT:
78       direction =
79           zxdg_toplevel_v6_resize_edge::ZXDG_TOPLEVEL_V6_RESIZE_EDGE_RIGHT;
80       break;
81     case HTTOP:
82       direction =
83           zxdg_toplevel_v6_resize_edge::ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP;
84       break;
85     case HTTOPLEFT:
86       direction =
87           zxdg_toplevel_v6_resize_edge::ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP_LEFT;
88       break;
89     case HTTOPRIGHT:
90       direction =
91           zxdg_toplevel_v6_resize_edge::ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP_RIGHT;
92       break;
93     default:
94       direction =
95           zxdg_toplevel_v6_resize_edge::ZXDG_TOPLEVEL_V6_RESIZE_EDGE_NONE;
96       break;
97   }
98   return direction;
99 }
100 
101 }  // namespace
102 
IdentifyDirection(const ui::WaylandConnection & connection,int hittest)103 uint32_t IdentifyDirection(const ui::WaylandConnection& connection,
104                            int hittest) {
105   if (connection.shell())
106     return IdentifyDirectionStable(hittest);
107   DCHECK(connection.shell_v6());
108   return IdentifyDirectionV6(hittest);
109 }
110 
DrawBitmap(const SkBitmap & bitmap,ui::WaylandShmBuffer * out_buffer)111 bool DrawBitmap(const SkBitmap& bitmap, ui::WaylandShmBuffer* out_buffer) {
112   DCHECK(out_buffer);
113   DCHECK(out_buffer->GetMemory());
114   DCHECK_EQ(out_buffer->size(), gfx::Size(bitmap.width(), bitmap.height()));
115 
116   auto* mapped_memory = out_buffer->GetMemory();
117   auto size = out_buffer->size();
118   sk_sp<SkSurface> sk_surface = SkSurface::MakeRasterDirect(
119       SkImageInfo::Make(size.width(), size.height(), kColorType,
120                         kOpaque_SkAlphaType),
121       mapped_memory, out_buffer->stride());
122 
123   if (!sk_surface)
124     return false;
125 
126   // The |bitmap| contains ARGB image, so update our wl_buffer, which is
127   // backed by a SkSurface.
128   SkRect damage;
129   bitmap.getBounds(&damage);
130 
131   // Clear to transparent in case |bitmap| is smaller than the canvas.
132   auto* canvas = sk_surface->getCanvas();
133   canvas->clear(SK_ColorTRANSPARENT);
134   canvas->drawBitmapRect(bitmap, damage, nullptr);
135   return true;
136 }
137 
ReadDataFromFD(base::ScopedFD fd,std::vector<uint8_t> * contents)138 void ReadDataFromFD(base::ScopedFD fd, std::vector<uint8_t>* contents) {
139   DCHECK(contents);
140   uint8_t buffer[1 << 10];  // 1 kB in bytes.
141   ssize_t length;
142   while ((length = read(fd.get(), buffer, sizeof(buffer))) > 0)
143     contents->insert(contents->end(), buffer, buffer + length);
144 }
145 
TranslateBoundsToParentCoordinates(const gfx::Rect & child_bounds,const gfx::Rect & parent_bounds)146 gfx::Rect TranslateBoundsToParentCoordinates(const gfx::Rect& child_bounds,
147                                              const gfx::Rect& parent_bounds) {
148   return gfx::Rect(
149       (child_bounds.origin() - parent_bounds.origin().OffsetFromOrigin()),
150       child_bounds.size());
151 }
152 
TranslateBoundsToTopLevelCoordinates(const gfx::Rect & child_bounds,const gfx::Rect & parent_bounds)153 gfx::Rect TranslateBoundsToTopLevelCoordinates(const gfx::Rect& child_bounds,
154                                                const gfx::Rect& parent_bounds) {
155   return gfx::Rect(
156       (child_bounds.origin() + parent_bounds.origin().OffsetFromOrigin()),
157       child_bounds.size());
158 }
159 
ToWaylandTransform(gfx::OverlayTransform transform)160 wl_output_transform ToWaylandTransform(gfx::OverlayTransform transform) {
161   switch (transform) {
162     case gfx::OVERLAY_TRANSFORM_NONE:
163       return WL_OUTPUT_TRANSFORM_NORMAL;
164     case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL:
165       return WL_OUTPUT_TRANSFORM_FLIPPED;
166     case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL:
167       return WL_OUTPUT_TRANSFORM_FLIPPED_180;
168     case gfx::OVERLAY_TRANSFORM_ROTATE_90:
169       return WL_OUTPUT_TRANSFORM_90;
170     case gfx::OVERLAY_TRANSFORM_ROTATE_180:
171       return WL_OUTPUT_TRANSFORM_180;
172     case gfx::OVERLAY_TRANSFORM_ROTATE_270:
173       return WL_OUTPUT_TRANSFORM_270;
174     default:
175       break;
176   }
177   NOTREACHED();
178   return WL_OUTPUT_TRANSFORM_NORMAL;
179 }
180 
ApplyWaylandTransform(const gfx::Rect & rect,const gfx::Size & bounds,wl_output_transform transform)181 gfx::Rect ApplyWaylandTransform(const gfx::Rect& rect,
182                                 const gfx::Size& bounds,
183                                 wl_output_transform transform) {
184   gfx::Rect result = rect;
185   switch (transform) {
186     case WL_OUTPUT_TRANSFORM_NORMAL:
187       break;
188     case WL_OUTPUT_TRANSFORM_FLIPPED:
189       result.set_x(bounds.width() - rect.x() - rect.width());
190       break;
191     case WL_OUTPUT_TRANSFORM_FLIPPED_90:
192       result.set_x(rect.y());
193       result.set_y(rect.x());
194       result.set_width(rect.height());
195       result.set_height(rect.width());
196       break;
197     case WL_OUTPUT_TRANSFORM_FLIPPED_180:
198       result.set_y(bounds.height() - rect.y() - rect.height());
199       break;
200     case WL_OUTPUT_TRANSFORM_FLIPPED_270:
201       result.set_x(bounds.height() - rect.y() - rect.height());
202       result.set_y(bounds.width() - rect.x() - rect.width());
203       result.set_width(rect.height());
204       result.set_height(rect.width());
205       break;
206     case WL_OUTPUT_TRANSFORM_90:
207       result.set_x(rect.y());
208       result.set_y(bounds.width() - rect.x() - rect.width());
209       result.set_width(rect.height());
210       result.set_height(rect.width());
211       break;
212     case WL_OUTPUT_TRANSFORM_180:
213       result.set_x(bounds.width() - rect.x() - rect.width());
214       result.set_y(bounds.height() - rect.y() - rect.height());
215       break;
216     case WL_OUTPUT_TRANSFORM_270:
217       result.set_x(bounds.height() - rect.y() - rect.height());
218       result.set_y(rect.x());
219       result.set_width(rect.height());
220       result.set_height(rect.width());
221       break;
222     default:
223       NOTREACHED();
224       break;
225   }
226   return result;
227 }
228 
ApplyWaylandTransform(const gfx::Size & size,wl_output_transform transform)229 gfx::Size ApplyWaylandTransform(const gfx::Size& size,
230                                 wl_output_transform transform) {
231   gfx::Size result = size;
232   switch (transform) {
233     case WL_OUTPUT_TRANSFORM_NORMAL:
234     case WL_OUTPUT_TRANSFORM_FLIPPED:
235     case WL_OUTPUT_TRANSFORM_FLIPPED_180:
236     case WL_OUTPUT_TRANSFORM_180:
237       break;
238     case WL_OUTPUT_TRANSFORM_FLIPPED_90:
239     case WL_OUTPUT_TRANSFORM_FLIPPED_270:
240     case WL_OUTPUT_TRANSFORM_90:
241     case WL_OUTPUT_TRANSFORM_270:
242       result.set_width(size.height());
243       result.set_height(size.width());
244       break;
245     default:
246       NOTREACHED();
247       break;
248   }
249   return result;
250 }
251 
IsMenuType(ui::PlatformWindowType type)252 bool IsMenuType(ui::PlatformWindowType type) {
253   return type == ui::PlatformWindowType::kMenu ||
254          type == ui::PlatformWindowType::kPopup;
255 }
256 
RootWindowFromWlSurface(wl_surface * surface)257 ui::WaylandWindow* RootWindowFromWlSurface(wl_surface* surface) {
258   if (!surface)
259     return nullptr;
260   auto* wayland_surface = static_cast<ui::WaylandSurface*>(
261       wl_proxy_get_user_data(reinterpret_cast<wl_proxy*>(surface)));
262   if (!wayland_surface)
263     return nullptr;
264   return wayland_surface->root_window();
265 }
266 
TranslateWindowBoundsToParentDIP(ui::WaylandWindow * window,ui::WaylandWindow * parent_window)267 gfx::Rect TranslateWindowBoundsToParentDIP(ui::WaylandWindow* window,
268                                            ui::WaylandWindow* parent_window) {
269   DCHECK(window);
270   DCHECK(parent_window);
271   DCHECK_EQ(window->buffer_scale(), parent_window->buffer_scale());
272   DCHECK_EQ(window->ui_scale(), parent_window->ui_scale());
273   return gfx::ScaleToRoundedRect(
274       wl::TranslateBoundsToParentCoordinates(window->GetBounds(),
275                                              parent_window->GetBounds()),
276       1.0 / window->buffer_scale());
277 }
278 
279 }  // namespace wl
280