1 | /* |
2 | * Copyright (C) 2016 Igalia S.L. |
3 | * |
4 | * Redistribution and use in source and binary forms, with or without |
5 | * modification, are permitted provided that the following conditions |
6 | * are met: |
7 | * 1. Redistributions of source code must retain the above copyright |
8 | * notice, this list of conditions and the following disclaimer. |
9 | * 2. Redistributions in binary form must reproduce the above copyright |
10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. |
12 | * |
13 | * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY |
14 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR |
17 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
18 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
20 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
21 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
23 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
24 | */ |
25 | |
26 | #include "config.h" |
27 | #include "WaylandCompositor.h" |
28 | |
29 | #if PLATFORM(WAYLAND) && USE(EGL) && !USE(WPE_RENDERER) |
30 | |
31 | #include "WebKitWaylandServerProtocol.h" |
32 | #include <EGL/egl.h> |
33 | #include <EGL/eglext.h> |
34 | #include <WebCore/GLContext.h> |
35 | #include <WebCore/PlatformDisplayWayland.h> |
36 | #include <WebCore/Region.h> |
37 | #include <gtk/gtk.h> |
38 | #include <wayland-server-protocol.h> |
39 | #include <wtf/UUID.h> |
40 | |
41 | #if USE(OPENGL_ES) |
42 | #include <GLES2/gl2.h> |
43 | #include <GLES2/gl2ext.h> |
44 | #include <WebCore/Extensions3DOpenGLES.h> |
45 | #else |
46 | #include <WebCore/Extensions3DOpenGL.h> |
47 | #include <WebCore/OpenGLShims.h> |
48 | #endif |
49 | |
50 | namespace WebKit { |
51 | using namespace WebCore; |
52 | |
53 | #if !defined(PFNEGLBINDWAYLANDDISPLAYWL) |
54 | typedef EGLBoolean (*PFNEGLBINDWAYLANDDISPLAYWL) (EGLDisplay, struct wl_display*); |
55 | #endif |
56 | |
57 | #if !defined(PFNEGLUNBINDWAYLANDDISPLAYWL) |
58 | typedef EGLBoolean (*PFNEGLUNBINDWAYLANDDISPLAYWL) (EGLDisplay, struct wl_display*); |
59 | #endif |
60 | |
61 | #if !defined(PFNEGLQUERYWAYLANDBUFFERWL) |
62 | typedef EGLBoolean (*PFNEGLQUERYWAYLANDBUFFERWL) (EGLDisplay, struct wl_resource*, EGLint attribute, EGLint* value); |
63 | #endif |
64 | |
65 | #if !defined(PFNEGLCREATEIMAGEKHRPROC) |
66 | typedef EGLImageKHR (*PFNEGLCREATEIMAGEKHRPROC) (EGLDisplay, EGLContext, EGLenum target, EGLClientBuffer, const EGLint* attribList); |
67 | #endif |
68 | |
69 | #if !defined(PFNEGLDESTROYIMAGEKHRPROC) |
70 | typedef EGLBoolean (*PFNEGLDESTROYIMAGEKHRPROC) (EGLDisplay, EGLImageKHR); |
71 | #endif |
72 | |
73 | #if !defined(PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) |
74 | typedef void (*PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES); |
75 | #endif |
76 | |
77 | static PFNEGLBINDWAYLANDDISPLAYWL eglBindWaylandDisplay; |
78 | static PFNEGLUNBINDWAYLANDDISPLAYWL eglUnbindWaylandDisplay; |
79 | static PFNEGLQUERYWAYLANDBUFFERWL eglQueryWaylandBuffer; |
80 | static PFNEGLCREATEIMAGEKHRPROC eglCreateImage; |
81 | static PFNEGLDESTROYIMAGEKHRPROC eglDestroyImage; |
82 | static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glImageTargetTexture2D; |
83 | |
84 | WaylandCompositor& WaylandCompositor::singleton() |
85 | { |
86 | static NeverDestroyed<WaylandCompositor> waylandCompositor; |
87 | return waylandCompositor; |
88 | } |
89 | |
90 | WaylandCompositor::Buffer* WaylandCompositor::Buffer::getOrCreate(struct wl_resource* resource) |
91 | { |
92 | if (struct wl_listener* listener = wl_resource_get_destroy_listener(resource, destroyListenerCallback)) { |
93 | WaylandCompositor::Buffer* buffer; |
94 | return wl_container_of(listener, buffer, m_destroyListener); |
95 | } |
96 | |
97 | return new WaylandCompositor::Buffer(resource); |
98 | } |
99 | |
100 | WaylandCompositor::Buffer::Buffer(struct wl_resource* resource) |
101 | : m_resource(resource) |
102 | { |
103 | wl_list_init(&m_destroyListener.link); |
104 | m_destroyListener.notify = destroyListenerCallback; |
105 | wl_resource_add_destroy_listener(m_resource, &m_destroyListener); |
106 | } |
107 | |
108 | WaylandCompositor::Buffer::~Buffer() |
109 | { |
110 | wl_list_remove(&m_destroyListener.link); |
111 | } |
112 | |
113 | void WaylandCompositor::Buffer::destroyListenerCallback(struct wl_listener* listener, void*) |
114 | { |
115 | WaylandCompositor::Buffer* buffer; |
116 | buffer = wl_container_of(listener, buffer, m_destroyListener); |
117 | delete buffer; |
118 | } |
119 | |
120 | void WaylandCompositor::Buffer::use() |
121 | { |
122 | m_busyCount++; |
123 | } |
124 | |
125 | void WaylandCompositor::Buffer::unuse() |
126 | { |
127 | m_busyCount--; |
128 | if (!m_busyCount) |
129 | wl_resource_queue_event(m_resource, WL_BUFFER_RELEASE); |
130 | } |
131 | |
132 | EGLImageKHR WaylandCompositor::Buffer::createImage() const |
133 | { |
134 | return static_cast<EGLImageKHR*>(eglCreateImage(PlatformDisplay::sharedDisplay().eglDisplay(), EGL_NO_CONTEXT, EGL_WAYLAND_BUFFER_WL, m_resource, nullptr)); |
135 | } |
136 | |
137 | IntSize WaylandCompositor::Buffer::size() const |
138 | { |
139 | EGLDisplay eglDisplay = PlatformDisplay::sharedDisplay().eglDisplay(); |
140 | int width, height; |
141 | eglQueryWaylandBuffer(eglDisplay, m_resource, EGL_WIDTH, &width); |
142 | eglQueryWaylandBuffer(eglDisplay, m_resource, EGL_HEIGHT, &height); |
143 | |
144 | return { width, height }; |
145 | } |
146 | |
147 | WaylandCompositor::Surface::Surface() |
148 | : m_image(EGL_NO_IMAGE_KHR) |
149 | { |
150 | } |
151 | |
152 | WaylandCompositor::Surface::~Surface() |
153 | { |
154 | setWebPage(nullptr); |
155 | |
156 | // Destroy pending frame callbacks. |
157 | auto pendingList = WTFMove(m_pendingFrameCallbackList); |
158 | for (auto* resource : pendingList) |
159 | wl_resource_destroy(resource); |
160 | auto list = WTFMove(m_frameCallbackList); |
161 | for (auto* resource : list) |
162 | wl_resource_destroy(resource); |
163 | |
164 | if (m_buffer) |
165 | m_buffer->unuse(); |
166 | } |
167 | |
168 | void WaylandCompositor::Surface::setWebPage(WebPageProxy* webPage) |
169 | { |
170 | if (m_webPage) { |
171 | flushPendingFrameCallbacks(); |
172 | flushFrameCallbacks(); |
173 | gtk_widget_remove_tick_callback(m_webPage->viewWidget(), m_tickCallbackID); |
174 | m_tickCallbackID = 0; |
175 | |
176 | if (m_webPage->makeGLContextCurrent()) { |
177 | if (m_image != EGL_NO_IMAGE_KHR) |
178 | eglDestroyImage(PlatformDisplay::sharedDisplay().eglDisplay(), m_image); |
179 | if (m_texture) |
180 | glDeleteTextures(1, &m_texture); |
181 | } |
182 | |
183 | m_image = EGL_NO_IMAGE_KHR; |
184 | m_texture = 0; |
185 | } |
186 | |
187 | m_webPage = webPage; |
188 | if (!m_webPage) |
189 | return; |
190 | |
191 | if (m_webPage->makeGLContextCurrent()) { |
192 | glGenTextures(1, &m_texture); |
193 | glBindTexture(GL_TEXTURE_2D, m_texture); |
194 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
195 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
196 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
197 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
198 | } |
199 | |
200 | m_tickCallbackID = gtk_widget_add_tick_callback(m_webPage->viewWidget(), [](GtkWidget*, GdkFrameClock*, gpointer userData) -> gboolean { |
201 | auto* surface = static_cast<Surface*>(userData); |
202 | surface->flushFrameCallbacks(); |
203 | return G_SOURCE_CONTINUE; |
204 | }, this, nullptr); |
205 | } |
206 | |
207 | void WaylandCompositor::Surface::makePendingBufferCurrent() |
208 | { |
209 | if (m_pendingBuffer == m_buffer) |
210 | return; |
211 | |
212 | if (m_buffer) |
213 | m_buffer->unuse(); |
214 | |
215 | if (m_pendingBuffer) |
216 | m_pendingBuffer->use(); |
217 | |
218 | m_buffer = m_pendingBuffer; |
219 | } |
220 | |
221 | void WaylandCompositor::Surface::attachBuffer(struct wl_resource* buffer) |
222 | { |
223 | if (m_pendingBuffer) |
224 | m_pendingBuffer = nullptr; |
225 | |
226 | if (buffer) { |
227 | auto* compositorBuffer = WaylandCompositor::Buffer::getOrCreate(buffer); |
228 | m_pendingBuffer = makeWeakPtr(*compositorBuffer); |
229 | } |
230 | } |
231 | |
232 | void WaylandCompositor::Surface::requestFrame(struct wl_resource* resource) |
233 | { |
234 | wl_resource_set_implementation(resource, nullptr, this, [](struct wl_resource* resource) { |
235 | auto* surface = static_cast<WaylandCompositor::Surface*>(wl_resource_get_user_data(resource)); |
236 | if (size_t item = surface->m_pendingFrameCallbackList.find(resource) != notFound) |
237 | surface->m_pendingFrameCallbackList.remove(item); |
238 | }); |
239 | m_pendingFrameCallbackList.append(resource); |
240 | } |
241 | |
242 | bool WaylandCompositor::Surface::prepareTextureForPainting(unsigned& texture, IntSize& textureSize) |
243 | { |
244 | if (!m_texture || m_image == EGL_NO_IMAGE_KHR) |
245 | return false; |
246 | |
247 | if (!m_webPage || !m_webPage->makeGLContextCurrent()) |
248 | return false; |
249 | |
250 | glBindTexture(GL_TEXTURE_2D, m_texture); |
251 | glImageTargetTexture2D(GL_TEXTURE_2D, m_image); |
252 | |
253 | texture = m_texture; |
254 | textureSize = m_imageSize; |
255 | return true; |
256 | } |
257 | |
258 | void WaylandCompositor::Surface::flushFrameCallbacks() |
259 | { |
260 | auto list = WTFMove(m_frameCallbackList); |
261 | for (auto* resource : list) { |
262 | wl_callback_send_done(resource, 0); |
263 | wl_resource_destroy(resource); |
264 | } |
265 | } |
266 | |
267 | void WaylandCompositor::Surface::flushPendingFrameCallbacks() |
268 | { |
269 | auto list = WTFMove(m_pendingFrameCallbackList); |
270 | for (auto* resource : list) { |
271 | wl_callback_send_done(resource, 0); |
272 | wl_resource_destroy(resource); |
273 | } |
274 | } |
275 | |
276 | void WaylandCompositor::Surface::commit() |
277 | { |
278 | if (!m_webPage || !m_webPage->makeGLContextCurrent()) { |
279 | makePendingBufferCurrent(); |
280 | flushPendingFrameCallbacks(); |
281 | return; |
282 | } |
283 | |
284 | EGLDisplay eglDisplay = PlatformDisplay::sharedDisplay().eglDisplay(); |
285 | if (m_image != EGL_NO_IMAGE_KHR) |
286 | eglDestroyImage(eglDisplay, m_image); |
287 | m_image = m_pendingBuffer->createImage(); |
288 | if (m_image == EGL_NO_IMAGE_KHR) |
289 | return; |
290 | |
291 | m_imageSize = m_pendingBuffer->size(); |
292 | |
293 | makePendingBufferCurrent(); |
294 | |
295 | m_webPage->setViewNeedsDisplay(IntRect(IntPoint::zero(), m_webPage->viewSize())); |
296 | |
297 | auto list = WTFMove(m_pendingFrameCallbackList); |
298 | m_frameCallbackList.appendVector(list); |
299 | } |
300 | |
301 | static const struct wl_surface_interface surfaceInterface = { |
302 | // destroyCallback |
303 | [](struct wl_client*, struct wl_resource* resource) |
304 | { |
305 | wl_resource_destroy(resource); |
306 | }, |
307 | // attachCallback |
308 | [](struct wl_client* client, struct wl_resource* resource, struct wl_resource* buffer, int32_t sx, int32_t sy) |
309 | { |
310 | auto* surface = static_cast<WaylandCompositor::Surface*>(wl_resource_get_user_data(resource)); |
311 | if (!surface) |
312 | return; |
313 | |
314 | EGLint format; |
315 | if (!eglQueryWaylandBuffer(PlatformDisplay::sharedDisplay().eglDisplay(), buffer, EGL_TEXTURE_FORMAT, &format) |
316 | || (format != EGL_TEXTURE_RGB && format != EGL_TEXTURE_RGBA)) |
317 | return; |
318 | |
319 | surface->attachBuffer(buffer); |
320 | }, |
321 | // damageCallback |
322 | [](struct wl_client*, struct wl_resource*, int32_t, int32_t, int32_t, int32_t) { }, |
323 | // frameCallback |
324 | [](struct wl_client* client, struct wl_resource* resource, uint32_t id) |
325 | { |
326 | auto* surface = static_cast<WaylandCompositor::Surface*>(wl_resource_get_user_data(resource)); |
327 | if (!surface) |
328 | return; |
329 | |
330 | if (struct wl_resource* callbackResource = wl_resource_create(client, &wl_callback_interface, 1, id)) |
331 | surface->requestFrame(callbackResource); |
332 | else |
333 | wl_client_post_no_memory(client); |
334 | }, |
335 | // setOpaqueRegionCallback |
336 | [](struct wl_client*, struct wl_resource*, struct wl_resource*) { }, |
337 | // setInputRegionCallback |
338 | [](struct wl_client*, struct wl_resource*, struct wl_resource*) { }, |
339 | // commitCallback |
340 | [](struct wl_client* client, struct wl_resource* resource) |
341 | { |
342 | auto* surface = static_cast<WaylandCompositor::Surface*>(wl_resource_get_user_data(resource)); |
343 | if (!surface) |
344 | return; |
345 | surface->commit(); |
346 | }, |
347 | // setBufferTransformCallback |
348 | [](struct wl_client*, struct wl_resource*, int32_t) { }, |
349 | // setBufferScaleCallback |
350 | [](struct wl_client*, struct wl_resource*, int32_t) { }, |
351 | #if WAYLAND_VERSION_MAJOR > 1 || (WAYLAND_VERSION_MAJOR == 1 && WAYLAND_VERSION_MINOR >= 10) |
352 | // damageBufferCallback |
353 | [](struct wl_client*, struct wl_resource*, int32_t, int32_t, int32_t, int32_t) { }, |
354 | #endif |
355 | }; |
356 | |
357 | static const struct wl_compositor_interface compositorInterface = { |
358 | // createSurfaceCallback |
359 | [](struct wl_client* client, struct wl_resource* resource, uint32_t id) |
360 | { |
361 | if (struct wl_resource* surfaceResource = wl_resource_create(client, &wl_surface_interface, 1, id)) { |
362 | wl_resource_set_implementation(surfaceResource, &surfaceInterface, new WaylandCompositor::Surface(), |
363 | [](struct wl_resource* resource) { |
364 | auto* surface = static_cast<WaylandCompositor::Surface*>(wl_resource_get_user_data(resource)); |
365 | delete surface; |
366 | }); |
367 | } else |
368 | wl_client_post_no_memory(client); |
369 | }, |
370 | // createRegionCallback |
371 | [](struct wl_client*, struct wl_resource*, uint32_t) { } |
372 | }; |
373 | |
374 | static const struct wl_webkitgtk_interface webkitgtkInterface = { |
375 | // bindSurfaceToPageCallback |
376 | [](struct wl_client*, struct wl_resource* resource, struct wl_resource* surfaceResource, uint32_t pageID) |
377 | { |
378 | auto* surface = static_cast<WaylandCompositor::Surface*>(wl_resource_get_user_data(surfaceResource)); |
379 | if (!surface) |
380 | return; |
381 | |
382 | auto* compositor = static_cast<WaylandCompositor*>(wl_resource_get_user_data(resource)); |
383 | compositor->bindSurfaceToWebPage(surface, makeObjectIdentifier<PageIdentifierType>(pageID)); |
384 | } |
385 | }; |
386 | |
387 | bool WaylandCompositor::initializeEGL() |
388 | { |
389 | const char* extensions = eglQueryString(PlatformDisplay::sharedDisplay().eglDisplay(), EGL_EXTENSIONS); |
390 | |
391 | if (PlatformDisplay::sharedDisplay().eglCheckVersion(1, 5)) { |
392 | eglCreateImage = reinterpret_cast<PFNEGLCREATEIMAGEKHRPROC>(eglGetProcAddress("eglCreateImage" )); |
393 | eglDestroyImage = reinterpret_cast<PFNEGLDESTROYIMAGEKHRPROC>(eglGetProcAddress("eglDestroyImage" )); |
394 | } else { |
395 | if (GLContext::isExtensionSupported(extensions, "EGL_KHR_image_base" )) { |
396 | eglCreateImage = reinterpret_cast<PFNEGLCREATEIMAGEKHRPROC>(eglGetProcAddress("eglCreateImageKHR" )); |
397 | eglDestroyImage = reinterpret_cast<PFNEGLDESTROYIMAGEKHRPROC>(eglGetProcAddress("eglDestroyImageKHR" )); |
398 | } |
399 | } |
400 | if (!eglCreateImage || !eglDestroyImage) { |
401 | WTFLogAlways("WaylandCompositor requires eglCreateImage and eglDestroyImage." ); |
402 | return false; |
403 | } |
404 | |
405 | if (GLContext::isExtensionSupported(extensions, "EGL_WL_bind_wayland_display" )) { |
406 | eglBindWaylandDisplay = reinterpret_cast<PFNEGLBINDWAYLANDDISPLAYWL>(eglGetProcAddress("eglBindWaylandDisplayWL" )); |
407 | eglUnbindWaylandDisplay = reinterpret_cast<PFNEGLUNBINDWAYLANDDISPLAYWL>(eglGetProcAddress("eglUnbindWaylandDisplayWL" )); |
408 | eglQueryWaylandBuffer = reinterpret_cast<PFNEGLQUERYWAYLANDBUFFERWL>(eglGetProcAddress("eglQueryWaylandBufferWL" )); |
409 | } |
410 | if (!eglBindWaylandDisplay || !eglUnbindWaylandDisplay || !eglQueryWaylandBuffer) { |
411 | WTFLogAlways("WaylandCompositor requires eglBindWaylandDisplayWL, eglUnbindWaylandDisplayWL and eglQueryWaylandBuffer." ); |
412 | return false; |
413 | } |
414 | |
415 | std::unique_ptr<WebCore::GLContext> eglContext = GLContext::createOffscreenContext(); |
416 | if (!eglContext) |
417 | return false; |
418 | |
419 | if (!eglContext->makeContextCurrent()) |
420 | return false; |
421 | |
422 | #if USE(OPENGL_ES) |
423 | std::unique_ptr<Extensions3DOpenGLES> glExtensions = std::make_unique<Extensions3DOpenGLES>(nullptr, false); |
424 | #else |
425 | std::unique_ptr<Extensions3DOpenGL> glExtensions = std::make_unique<Extensions3DOpenGL>(nullptr, GLContext::current()->version() >= 320); |
426 | #endif |
427 | if (glExtensions->supports("GL_OES_EGL_image" ) || glExtensions->supports("GL_OES_EGL_image_external" )) |
428 | glImageTargetTexture2D = reinterpret_cast<PFNGLEGLIMAGETARGETTEXTURE2DOESPROC>(eglGetProcAddress("glEGLImageTargetTexture2DOES" )); |
429 | |
430 | if (!glImageTargetTexture2D) { |
431 | WTFLogAlways("WaylandCompositor requires glEGLImageTargetTexture2D." ); |
432 | return false; |
433 | } |
434 | |
435 | return true; |
436 | } |
437 | |
438 | typedef struct { |
439 | GSource source; |
440 | gpointer fdTag; |
441 | struct wl_display* display; |
442 | } WaylandLoopSource; |
443 | |
444 | static const unsigned waylandLoopSourceCondition = G_IO_IN | G_IO_HUP | G_IO_ERR; |
445 | |
446 | static GSourceFuncs waylandLoopSourceFunctions = { |
447 | // prepare |
448 | [](GSource *source, int *timeout) -> gboolean |
449 | { |
450 | *timeout = -1; |
451 | auto* wlLoopSource = reinterpret_cast<WaylandLoopSource*>(source); |
452 | wl_display_flush_clients(wlLoopSource->display); |
453 | return FALSE; |
454 | }, |
455 | nullptr, // check |
456 | // dispatch |
457 | [](GSource* source, GSourceFunc callback, gpointer userData) -> gboolean |
458 | { |
459 | auto* wlLoopSource = reinterpret_cast<WaylandLoopSource*>(source); |
460 | unsigned events = g_source_query_unix_fd(source, wlLoopSource->fdTag) & waylandLoopSourceCondition; |
461 | if (events & G_IO_HUP || events & G_IO_ERR) { |
462 | WTFLogAlways("Wayland Display Event Source: lost connection to nested Wayland compositor" ); |
463 | return G_SOURCE_REMOVE; |
464 | } |
465 | |
466 | if (events & G_IO_IN) |
467 | wl_event_loop_dispatch(wl_display_get_event_loop(wlLoopSource->display), 0); |
468 | return G_SOURCE_CONTINUE; |
469 | }, |
470 | nullptr, // finalize |
471 | nullptr, // closure_callback |
472 | nullptr, // closure_marshall |
473 | }; |
474 | |
475 | static GRefPtr<GSource> createWaylandLoopSource(struct wl_display* display) |
476 | { |
477 | GRefPtr<GSource> source = adoptGRef(g_source_new(&waylandLoopSourceFunctions, sizeof(WaylandLoopSource))); |
478 | g_source_set_name(source.get(), "Nested Wayland compositor display event source" ); |
479 | |
480 | auto* wlLoopSource = reinterpret_cast<WaylandLoopSource*>(source.get()); |
481 | wlLoopSource->display = display; |
482 | wlLoopSource->fdTag = g_source_add_unix_fd(source.get(), wl_event_loop_get_fd(wl_display_get_event_loop(display)), static_cast<GIOCondition>(waylandLoopSourceCondition)); |
483 | g_source_attach(source.get(), nullptr); |
484 | |
485 | return source; |
486 | } |
487 | |
488 | WaylandCompositor::WaylandCompositor() |
489 | { |
490 | std::unique_ptr<struct wl_display, DisplayDeleter> display(wl_display_create()); |
491 | if (!display) { |
492 | WTFLogAlways("Nested Wayland compositor could not create display object" ); |
493 | return; |
494 | } |
495 | |
496 | String displayName = "webkitgtk-wayland-compositor-" + createCanonicalUUIDString(); |
497 | if (wl_display_add_socket(display.get(), displayName.utf8().data()) == -1) { |
498 | WTFLogAlways("Nested Wayland compositor could not create display socket" ); |
499 | return; |
500 | } |
501 | |
502 | WlUniquePtr<struct wl_global> compositorGlobal(wl_global_create(display.get(), &wl_compositor_interface, wl_compositor_interface.version, this, |
503 | [](struct wl_client* client, void* data, uint32_t version, uint32_t id) { |
504 | if (struct wl_resource* resource = wl_resource_create(client, &wl_compositor_interface, std::min(static_cast<int>(version), 3), id)) |
505 | wl_resource_set_implementation(resource, &compositorInterface, static_cast<WaylandCompositor*>(data), nullptr); |
506 | else |
507 | wl_client_post_no_memory(client); |
508 | })); |
509 | if (!compositorGlobal) { |
510 | WTFLogAlways("Nested Wayland compositor could not register compositor global" ); |
511 | return; |
512 | } |
513 | |
514 | WlUniquePtr<struct wl_global> webkitgtkGlobal(wl_global_create(display.get(), &wl_webkitgtk_interface, 1, this, |
515 | [](struct wl_client* client, void* data, uint32_t version, uint32_t id) { |
516 | if (struct wl_resource* resource = wl_resource_create(client, &wl_webkitgtk_interface, 1, id)) |
517 | wl_resource_set_implementation(resource, &webkitgtkInterface, static_cast<WaylandCompositor*>(data), nullptr); |
518 | else |
519 | wl_client_post_no_memory(client); |
520 | })); |
521 | if (!webkitgtkGlobal) { |
522 | WTFLogAlways("Nested Wayland compositor could not register webkitgtk global" ); |
523 | return; |
524 | } |
525 | |
526 | if (!initializeEGL()) { |
527 | WTFLogAlways("Nested Wayland compositor could not initialize EGL" ); |
528 | return; |
529 | } |
530 | |
531 | if (!eglBindWaylandDisplay(PlatformDisplay::sharedDisplay().eglDisplay(), display.get())) { |
532 | WTFLogAlways("Nested Wayland compositor could not bind nested display" ); |
533 | return; |
534 | } |
535 | |
536 | m_displayName = WTFMove(displayName); |
537 | m_display = WTFMove(display); |
538 | m_compositorGlobal = WTFMove(compositorGlobal); |
539 | m_webkitgtkGlobal = WTFMove(webkitgtkGlobal); |
540 | m_eventSource = createWaylandLoopSource(m_display.get()); |
541 | } |
542 | |
543 | bool WaylandCompositor::getTexture(WebPageProxy& webPage, unsigned& texture, IntSize& textureSize) |
544 | { |
545 | if (WeakPtr<Surface> surface = m_pageMap.get(&webPage)) |
546 | return surface->prepareTextureForPainting(texture, textureSize); |
547 | return false; |
548 | } |
549 | |
550 | void WaylandCompositor::bindSurfaceToWebPage(WaylandCompositor::Surface* surface, WebCore::PageIdentifier pageID) |
551 | { |
552 | WebPageProxy* webPage = nullptr; |
553 | for (auto* page : m_pageMap.keys()) { |
554 | if (page->pageID() == pageID) { |
555 | webPage = page; |
556 | break; |
557 | } |
558 | } |
559 | if (!webPage) |
560 | return; |
561 | |
562 | surface->setWebPage(webPage); |
563 | m_pageMap.set(webPage, makeWeakPtr(*surface)); |
564 | } |
565 | |
566 | void WaylandCompositor::registerWebPage(WebPageProxy& webPage) |
567 | { |
568 | m_pageMap.add(&webPage, nullptr); |
569 | } |
570 | |
571 | void WaylandCompositor::unregisterWebPage(WebPageProxy& webPage) |
572 | { |
573 | if (WeakPtr<Surface> surface = m_pageMap.take(&webPage)) |
574 | surface->setWebPage(nullptr); |
575 | } |
576 | |
577 | } // namespace WebKit |
578 | |
579 | #endif // PLATFORM(WAYLAND) && USE(EGL) && !USE(WPE_RENDERER) |
580 | |