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