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