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