瀏覽代碼

Everywhere: Use IOSurface as backing store on macOS

Using mmap-allocated memory for backing stores does not allow us to
benefit from using GPU-accelerated painting, because all the performance
increase we get is mostly negated by reading the GPU-allocated texture
back into RAM, so it can be shared with the browser process.

With IOSurface, we get a framebuffer that is both shareable between
processes and can be used as underlying memory for an OpenGL/Metal
texture.

This change does not yet benefit from using IOSurface and merely wraps
them into Gfx::Bitmap to be used by the CPU painter.
Aliaksandr Kalenik 1 年之前
父節點
當前提交
c92f8ab1ea

+ 6 - 0
Ladybird/AppKit/main.mm

@@ -18,6 +18,8 @@
 #include <LibWebView/Database.h>
 #include <LibWebView/ProcessManager.h>
 #include <LibWebView/URL.h>
+#include <LibWebView/ViewImplementation.h>
+#include <LibWebView/WebContentClient.h>
 
 #import <Application/Application.h>
 #import <Application/ApplicationDelegate.h>
@@ -123,6 +125,10 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
     mach_port_server->on_receive_child_mach_port = [](auto pid, auto port) {
         WebView::ProcessManager::the().add_process(pid, move(port));
     };
+    mach_port_server->on_receive_backing_stores = [](Ladybird::MachPortServer::BackingStoresMessage message) {
+        auto view = WebView::WebContentClient::view_for_pid_and_page_id(message.pid, message.page_id);
+        view->did_allocate_iosurface_backing_stores(message.front_backing_store_id, move(message.front_backing_store_port), message.back_backing_store_id, move(message.back_backing_store_port));
+    };
 
     auto database = TRY(WebView::Database::create());
     auto cookie_jar = TRY(WebView::CookieJar::create(*database));

+ 28 - 13
Ladybird/MachPortServer.cpp

@@ -6,6 +6,7 @@
 
 #include "MachPortServer.h"
 #include <AK/Debug.h>
+#include <LibCore/Platform/MachMessageTypes.h>
 #include <LibCore/Platform/ProcessStatisticsMach.h>
 
 namespace Ladybird {
@@ -55,8 +56,7 @@ ErrorOr<void> MachPortServer::allocate_server_port()
 void MachPortServer::thread_loop()
 {
     while (!m_should_stop.load(MemoryOrder::memory_order_acquire)) {
-
-        Core::Platform::ParentPortMessage message {};
+        Core::Platform::ReceivedMachMessage message {};
 
         // Get the pid of the child from the audit trailer so we can associate the port w/it
         mach_msg_options_t const options = MACH_RCV_MSG | MACH_RCV_TRAILER_TYPE(MACH_RCV_TRAILER_AUDIT) | MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT);
@@ -68,23 +68,38 @@ void MachPortServer::thread_loop()
             break;
         }
 
-        if (message.header.msgh_id != Core::Platform::SELF_TASK_PORT_MESSAGE_ID) {
-            dbgln("Received message with id {}, ignoring", message.header.msgh_id);
+        if (message.header.msgh_id == Core::Platform::BACKING_STORE_IOSURFACES_MESSAGE_ID) {
+            auto pid = static_cast<pid_t>(message.body.parent_iosurface.trailer.msgh_audit.val[5]);
+            auto const& backing_stores_message = message.body.parent_iosurface;
+            auto front_child_port = Core::MachPort::adopt_right(backing_stores_message.front_descriptor.name, Core::MachPort::PortRight::Send);
+            auto back_child_port = Core::MachPort::adopt_right(backing_stores_message.back_descriptor.name, Core::MachPort::PortRight::Send);
+            auto const& metadata = backing_stores_message.metadata;
+            if (on_receive_backing_stores)
+                on_receive_backing_stores({ .pid = pid,
+                    .page_id = metadata.page_id,
+                    .front_backing_store_id = metadata.front_backing_store_id,
+                    .back_backing_store_id = metadata.back_backing_store_id,
+                    .front_backing_store_port = move(front_child_port),
+                    .back_backing_store_port = move(back_child_port) });
             continue;
         }
 
-        if (MACH_MSGH_BITS_LOCAL(message.header.msgh_bits) != MACH_MSG_TYPE_MOVE_SEND) {
-            dbgln("Received message with invalid local port rights {}, ignoring", MACH_MSGH_BITS_LOCAL(message.header.msgh_bits));
+        if (message.header.msgh_id == Core::Platform::SELF_TASK_PORT_MESSAGE_ID) {
+            if (MACH_MSGH_BITS_LOCAL(message.header.msgh_bits) != MACH_MSG_TYPE_MOVE_SEND) {
+                dbgln("Received message with invalid local port rights {}, ignoring", MACH_MSGH_BITS_LOCAL(message.header.msgh_bits));
+                continue;
+            }
+
+            auto const& task_port_message = message.body.parent;
+            auto pid = static_cast<pid_t>(task_port_message.trailer.msgh_audit.val[5]);
+            auto child_port = Core::MachPort::adopt_right(task_port_message.port_descriptor.name, Core::MachPort::PortRight::Send);
+            dbgln_if(MACH_PORT_DEBUG, "Received child port {:x} from pid {}", child_port.port(), pid);
+            if (on_receive_child_mach_port)
+                on_receive_child_mach_port(pid, move(child_port));
             continue;
         }
 
-        auto pid = static_cast<pid_t>(message.trailer.msgh_audit.val[5]);
-        auto child_port = Core::MachPort::adopt_right(message.port_descriptor.name, Core::MachPort::PortRight::Send);
-        dbgln_if(MACH_PORT_DEBUG, "Received child port {:x} from pid {}", child_port.port(), pid);
-
-        if (on_receive_child_mach_port)
-            on_receive_child_mach_port(pid, move(child_port));
+        dbgln("Received message with id {}, ignoring", message.header.msgh_id);
     }
 }
-
 }

+ 9 - 0
Ladybird/MachPortServer.h

@@ -31,6 +31,15 @@ public:
     bool is_initialized();
 
     Function<void(pid_t, Core::MachPort)> on_receive_child_mach_port;
+    struct BackingStoresMessage {
+        pid_t pid { -1 };
+        u64 page_id { 0 };
+        i32 front_backing_store_id { 0 };
+        i32 back_backing_store_id { 0 };
+        Core::MachPort front_backing_store_port;
+        Core::MachPort back_backing_store_port;
+    };
+    Function<void(BackingStoresMessage)> on_receive_backing_stores;
 
     ByteString const& server_port_name() const { return m_server_port_name; }
 

+ 4 - 0
Ladybird/Qt/main.cpp

@@ -150,6 +150,10 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
     mach_port_server->on_receive_child_mach_port = [](auto pid, auto port) {
         WebView::ProcessManager::the().add_process(pid, move(port));
     };
+    mach_port_server->on_receive_backing_stores = [](Ladybird::MachPortServer::BackingStoresMessage message) {
+        auto view = WebView::WebContentClient::view_for_pid_and_page_id(message.pid, message.page_id);
+        view->did_allocate_iosurface_backing_stores(message.front_backing_store_id, move(message.front_backing_store_port), message.back_backing_store_id, move(message.back_backing_store_port));
+    };
 #endif
 
     RefPtr<WebView::Database> database;

+ 2 - 1
Ladybird/WebContent/main.cpp

@@ -148,7 +148,8 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
 
 #if defined(AK_OS_MACOS)
     if (!mach_server_name.is_empty()) {
-        Core::Platform::register_with_mach_server(mach_server_name);
+        auto server_port = Core::Platform::register_with_mach_server(mach_server_name);
+        WebContent::BackingStoreManager::set_browser_mach_port(move(server_port));
     }
 #endif
 

+ 4 - 0
Userland/Libraries/LibCore/Forward.h

@@ -49,4 +49,8 @@ class UDPSocket;
 
 enum class TimerShouldFireWhenNotVisible;
 
+#ifdef AK_OS_MACH
+class MachPort;
+#endif
+
 }

+ 65 - 0
Userland/Libraries/LibCore/Platform/MachMessageTypes.h

@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2024, Andrew Kaster <akaster@serenityos.org>
+ * Copyright (c) 2024, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/Platform.h>
+
+#if !defined(AK_OS_MACH)
+#    error "This file is only available on Mach platforms"
+#endif
+
+#include <mach/mach.h>
+
+namespace Core::Platform {
+
+struct MessageBodyWithSelfTaskPort {
+    mach_msg_body_t body;
+    mach_msg_port_descriptor_t port_descriptor;
+    mach_msg_audit_trailer_t trailer;
+};
+
+struct MessageWithSelfTaskPort {
+    mach_msg_header_t header;
+    mach_msg_body_t body;
+    mach_msg_port_descriptor_t port_descriptor;
+};
+
+struct BackingStoreMetadata {
+    u64 page_id { 0 };
+    i32 back_backing_store_id { 0 };
+    i32 front_backing_store_id { 0 };
+};
+
+struct MessageBodyWithBackingStores {
+    mach_msg_body_t body;
+    mach_msg_port_descriptor_t front_descriptor;
+    mach_msg_port_descriptor_t back_descriptor;
+    BackingStoreMetadata metadata;
+    mach_msg_audit_trailer_t trailer;
+};
+
+struct MessageWithBackingStores {
+    mach_msg_header_t header;
+    mach_msg_body_t body;
+    mach_msg_port_descriptor_t front_descriptor;
+    mach_msg_port_descriptor_t back_descriptor;
+    BackingStoreMetadata metadata;
+};
+
+struct ReceivedMachMessage {
+    mach_msg_header_t header;
+    union {
+        MessageBodyWithSelfTaskPort parent;
+        MessageBodyWithBackingStores parent_iosurface;
+    } body;
+};
+
+static constexpr mach_msg_id_t SELF_TASK_PORT_MESSAGE_ID = 0x1234CAFE;
+static constexpr mach_msg_id_t BACKING_STORE_IOSURFACES_MESSAGE_ID = 0x1234CAFF;
+
+}

+ 7 - 4
Userland/Libraries/LibCore/Platform/ProcessStatisticsMach.cpp

@@ -13,6 +13,7 @@
 #include <AK/ByteString.h>
 #include <AK/Time.h>
 #include <LibCore/MachPort.h>
+#include <LibCore/Platform/MachMessageTypes.h>
 #include <LibCore/Platform/ProcessStatisticsMach.h>
 
 namespace Core::Platform {
@@ -75,17 +76,17 @@ ErrorOr<void> update_process_statistics(ProcessStatistics& statistics)
     return {};
 }
 
-void register_with_mach_server(ByteString const& server_name)
+MachPort register_with_mach_server(ByteString const& server_name)
 {
     auto server_port_or_error = Core::MachPort::look_up_from_bootstrap_server(server_name);
     if (server_port_or_error.is_error()) {
         dbgln("Failed to lookup server port: {}", server_port_or_error.error());
-        return;
+        VERIFY_NOT_REACHED();
     }
     auto server_port = server_port_or_error.release_value();
 
     // Send our own task port to the server so they can query statistics about us
-    ChildPortMessage message {};
+    MessageWithSelfTaskPort message {};
     message.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSGH_BITS_ZERO) | MACH_MSGH_BITS_COMPLEX;
     message.header.msgh_size = sizeof(message);
     message.header.msgh_remote_port = server_port.port();
@@ -101,8 +102,10 @@ void register_with_mach_server(ByteString const& server_name)
     auto const send_result = mach_msg(&message.header, MACH_SEND_MSG | MACH_SEND_TIMEOUT, message.header.msgh_size, 0, MACH_PORT_NULL, timeout, MACH_PORT_NULL);
     if (send_result != KERN_SUCCESS) {
         dbgln("Failed to send message to server: {}", mach_error_string(send_result));
-        return;
+        VERIFY_NOT_REACHED();
     }
+
+    return server_port;
 }
 
 }

+ 1 - 16
Userland/Libraries/LibCore/Platform/ProcessStatisticsMach.h

@@ -17,21 +17,6 @@
 
 namespace Core::Platform {
 
-struct ChildPortMessage {
-    mach_msg_header_t header;
-    mach_msg_body_t body;
-    mach_msg_port_descriptor_t port_descriptor;
-};
-
-struct ParentPortMessage {
-    mach_msg_header_t header;
-    mach_msg_body_t body;
-    mach_msg_port_descriptor_t port_descriptor;
-    mach_msg_audit_trailer_t trailer; // for the child's pid
-};
-
-static constexpr mach_msg_id_t SELF_TASK_PORT_MESSAGE_ID = 0x1234CAFE;
-
-void register_with_mach_server(ByteString const& server_name);
+MachPort register_with_mach_server(ByteString const& server_name);
 
 }

+ 31 - 0
Userland/Libraries/LibWebView/ViewImplementation.cpp

@@ -12,6 +12,11 @@
 #include <LibWeb/Infra/Strings.h>
 #include <LibWebView/ViewImplementation.h>
 
+#ifdef AK_OS_MACOS
+#    include <LibCore/IOSurface.h>
+#    include <LibCore/MachPort.h>
+#endif
+
 namespace WebView {
 
 ViewImplementation::ViewImplementation()
@@ -397,6 +402,32 @@ void ViewImplementation::did_allocate_backing_stores(Badge<WebContentClient>, i3
     m_client_state.back_bitmap.id = back_bitmap_id;
 }
 
+#ifdef AK_OS_MACOS
+void ViewImplementation::did_allocate_iosurface_backing_stores(i32 front_id, Core::MachPort&& front_port, i32 back_id, Core::MachPort&& back_port)
+{
+    if (m_client_state.has_usable_bitmap) {
+        // NOTE: We keep the outgoing front bitmap as a backup so we have something to paint until we get a new one.
+        m_backup_bitmap = m_client_state.front_bitmap.bitmap;
+        m_backup_bitmap_size = m_client_state.front_bitmap.last_painted_size;
+    }
+    m_client_state.has_usable_bitmap = false;
+
+    auto front_iosurface = Core::IOSurfaceHandle::from_mach_port(move(front_port));
+    auto back_iosurface = Core::IOSurfaceHandle::from_mach_port(move(back_port));
+
+    auto front_size = Gfx::IntSize { front_iosurface.width(), front_iosurface.height() };
+    auto back_size = Gfx::IntSize { back_iosurface.width(), back_iosurface.height() };
+
+    auto front_bitmap = Gfx::Bitmap::create_wrapper(Gfx::BitmapFormat::BGRA8888, front_size, front_size.width() * front_iosurface.bytes_per_element(), front_iosurface.data(), [handle = move(front_iosurface)] {});
+    auto back_bitmap = Gfx::Bitmap::create_wrapper(Gfx::BitmapFormat::BGRA8888, back_size, back_size.width() * back_iosurface.bytes_per_element(), back_iosurface.data(), [handle = move(back_iosurface)] {});
+
+    m_client_state.front_bitmap.bitmap = front_bitmap.release_value_but_fixme_should_propagate_errors();
+    m_client_state.front_bitmap.id = front_id;
+    m_client_state.back_bitmap.bitmap = back_bitmap.release_value_but_fixme_should_propagate_errors();
+    m_client_state.back_bitmap.id = back_id;
+}
+#endif
+
 void ViewImplementation::handle_resize()
 {
     client().async_set_viewport_size(page_id(), this->viewport_size());

+ 4 - 0
Userland/Libraries/LibWebView/ViewImplementation.h

@@ -12,6 +12,7 @@
 #include <AK/LexicalPath.h>
 #include <AK/Queue.h>
 #include <AK/String.h>
+#include <LibCore/Forward.h>
 #include <LibCore/Promise.h>
 #include <LibGfx/Forward.h>
 #include <LibGfx/StandardCursor.h>
@@ -118,6 +119,9 @@ public:
     void did_update_navigation_buttons_state(Badge<WebContentClient>, bool back_enabled, bool forward_enabled) const;
 
     void did_allocate_backing_stores(Badge<WebContentClient>, i32 front_bitmap_id, Gfx::ShareableBitmap const&, i32 back_bitmap_id, Gfx::ShareableBitmap const&);
+#ifdef AK_OS_MACOS
+    void did_allocate_iosurface_backing_stores(i32 front_bitmap_id, Core::MachPort&&, i32 back_bitmap_id, Core::MachPort&&);
+#endif
 
     enum class ScreenshotType {
         Visible,

+ 17 - 0
Userland/Libraries/LibWebView/WebContentClient.cpp

@@ -11,12 +11,29 @@
 
 namespace WebView {
 
+static HashTable<WebContentClient*> s_clients;
+
+Optional<ViewImplementation&> WebContentClient::view_for_pid_and_page_id(pid_t pid, u64 page_id)
+{
+    for (auto* client : s_clients) {
+        if (client->m_process_handle.pid == pid)
+            return client->view_for_page_id(page_id);
+    }
+    return {};
+}
+
 WebContentClient::WebContentClient(NonnullOwnPtr<Core::LocalSocket> socket, ViewImplementation& view)
     : IPC::ConnectionToServer<WebContentClientEndpoint, WebContentServerEndpoint>(*this, move(socket))
 {
+    s_clients.set(this);
     m_views.set(0, &view);
 }
 
+WebContentClient::~WebContentClient()
+{
+    s_clients.remove(this);
+}
+
 void WebContentClient::die()
 {
     VERIFY(on_web_content_process_crash);

+ 3 - 0
Userland/Libraries/LibWebView/WebContentClient.h

@@ -26,7 +26,10 @@ class WebContentClient final
     IPC_CLIENT_CONNECTION(WebContentClient, "/tmp/session/%sid/portal/webcontent"sv);
 
 public:
+    static Optional<ViewImplementation&> view_for_pid_and_page_id(pid_t pid, u64 page_id);
+
     WebContentClient(NonnullOwnPtr<Core::LocalSocket>, ViewImplementation&);
+    ~WebContentClient();
 
     void register_view(u64 page_id, ViewImplementation&);
     void unregister_view(u64 page_id);

+ 79 - 22
Userland/Services/WebContent/BackingStoreManager.cpp

@@ -9,8 +9,22 @@
 #include <WebContent/BackingStoreManager.h>
 #include <WebContent/PageClient.h>
 
+#ifdef AK_OS_MACOS
+#    include <LibCore/IOSurface.h>
+#    include <LibCore/MachPort.h>
+#    include <LibCore/Platform/MachMessageTypes.h>
+#endif
+
 namespace WebContent {
 
+#ifdef AK_OS_MACOS
+static Optional<Core::MachPort> s_browser_mach_port;
+void BackingStoreManager::set_browser_mach_port(Core::MachPort&& port)
+{
+    s_browser_mach_port = move(port);
+}
+#endif
+
 BackingStoreManager::BackingStoreManager(PageClient& page_client)
     : m_page_client(page_client)
 {
@@ -24,10 +38,71 @@ void BackingStoreManager::restart_resize_timer()
     m_backing_store_shrink_timer->restart();
 }
 
+void BackingStoreManager::reallocate_backing_stores(Gfx::IntSize size)
+{
+#ifdef AK_OS_MACOS
+    if (s_browser_mach_port.has_value()) {
+        auto back_iosurface = Core::IOSurfaceHandle::create(size.width(), size.height());
+        auto back_iosurface_port = back_iosurface.create_mach_port();
+
+        auto front_iosurface = Core::IOSurfaceHandle::create(size.width(), size.height());
+        auto front_iosurface_port = front_iosurface.create_mach_port();
+
+        m_front_bitmap_id = m_next_bitmap_id++;
+        m_back_bitmap_id = m_next_bitmap_id++;
+
+        m_front_bitmap = Gfx::Bitmap::create_wrapper(Gfx::BitmapFormat::BGRA8888, size, size.width() * front_iosurface.bytes_per_element(), front_iosurface.data(), [handle = move(front_iosurface)] {}).release_value();
+        m_back_bitmap = Gfx::Bitmap::create_wrapper(Gfx::BitmapFormat::BGRA8888, size, size.width() * back_iosurface.bytes_per_element(), back_iosurface.data(), [handle = move(back_iosurface)] {}).release_value();
+
+        Core::Platform::BackingStoreMetadata metadata;
+        metadata.page_id = m_page_client.m_id;
+        metadata.front_backing_store_id = m_front_bitmap_id;
+        metadata.back_backing_store_id = m_back_bitmap_id;
+
+        Core::Platform::MessageWithBackingStores message;
+
+        message.header.msgh_remote_port = s_browser_mach_port->port();
+        message.header.msgh_local_port = MACH_PORT_NULL;
+        message.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0) | MACH_MSGH_BITS_COMPLEX;
+        message.header.msgh_size = sizeof(message);
+        message.header.msgh_id = Core::Platform::BACKING_STORE_IOSURFACES_MESSAGE_ID;
+
+        message.body.msgh_descriptor_count = 2;
+
+        message.front_descriptor.name = front_iosurface_port.release();
+        message.front_descriptor.disposition = MACH_MSG_TYPE_MOVE_SEND;
+        message.front_descriptor.type = MACH_MSG_PORT_DESCRIPTOR;
+
+        message.back_descriptor.name = back_iosurface_port.release();
+        message.back_descriptor.disposition = MACH_MSG_TYPE_MOVE_SEND;
+        message.back_descriptor.type = MACH_MSG_PORT_DESCRIPTOR;
+
+        message.metadata = metadata;
+
+        mach_msg_timeout_t const timeout = 100; // milliseconds
+        auto const send_result = mach_msg(&message.header, MACH_SEND_MSG | MACH_SEND_TIMEOUT, message.header.msgh_size, 0, MACH_PORT_NULL, timeout, MACH_PORT_NULL);
+        if (send_result != KERN_SUCCESS) {
+            dbgln("Failed to send message to server: {}", mach_error_string(send_result));
+            VERIFY_NOT_REACHED();
+        }
+
+        return;
+    }
+#endif
+
+    m_front_bitmap_id = m_next_bitmap_id++;
+    m_back_bitmap_id = m_next_bitmap_id++;
+
+    m_front_bitmap = Gfx::Bitmap::create_shareable(Gfx::BitmapFormat::BGRA8888, size).release_value();
+    m_back_bitmap = Gfx::Bitmap::create_shareable(Gfx::BitmapFormat::BGRA8888, size).release_value();
+
+    m_page_client.page_did_allocate_backing_stores(m_front_bitmap_id, m_front_bitmap->to_shareable_bitmap(), m_back_bitmap_id, m_back_bitmap->to_shareable_bitmap());
+}
+
 void BackingStoreManager::resize_backing_stores_if_needed(WindowResizingInProgress window_resize_in_progress)
 {
-    auto css_pixels_viewport_rect = m_page_client.page().top_level_traversable()->viewport_rect();
-    auto viewport_size = m_page_client.page().css_to_device_rect(css_pixels_viewport_rect).size();
+    auto css_pixels_viewpor_rect = m_page_client.page().top_level_traversable()->viewport_rect();
+    auto viewport_size = m_page_client.page().css_to_device_rect(css_pixels_viewpor_rect).size();
 
     if (viewport_size.is_empty())
         return;
@@ -43,26 +118,8 @@ void BackingStoreManager::resize_backing_stores_if_needed(WindowResizingInProgre
         m_back_bitmap.clear();
     }
 
-    auto old_front_bitmap_id = m_front_bitmap_id;
-    auto old_back_bitmap_id = m_back_bitmap_id;
-
-    auto reallocate_backing_store_if_needed = [&](RefPtr<Gfx::Bitmap>& bitmap, int& id) {
-        if (!bitmap || !bitmap->size().contains(minimum_needed_size.to_type<int>())) {
-            if (auto new_bitmap_or_error = Gfx::Bitmap::create_shareable(Gfx::BitmapFormat::BGRA8888, minimum_needed_size.to_type<int>()); !new_bitmap_or_error.is_error()) {
-                bitmap = new_bitmap_or_error.release_value();
-                id = m_next_bitmap_id++;
-            }
-        }
-    };
-
-    reallocate_backing_store_if_needed(m_front_bitmap, m_front_bitmap_id);
-    reallocate_backing_store_if_needed(m_back_bitmap, m_back_bitmap_id);
-
-    auto& front_bitmap = m_front_bitmap;
-    auto& back_bitmap = m_back_bitmap;
-
-    if (m_front_bitmap_id != old_front_bitmap_id || m_back_bitmap_id != old_back_bitmap_id) {
-        m_page_client.page_did_allocate_backing_stores(m_front_bitmap_id, front_bitmap->to_shareable_bitmap(), m_back_bitmap_id, back_bitmap->to_shareable_bitmap());
+    if (!m_front_bitmap || !m_back_bitmap || !m_front_bitmap->size().contains(minimum_needed_size.to_type<int>())) {
+        reallocate_backing_stores(minimum_needed_size.to_type<int>());
     }
 }
 

+ 6 - 0
Userland/Services/WebContent/BackingStoreManager.h

@@ -6,6 +6,7 @@
 
 #pragma once
 
+#include <LibCore/Forward.h>
 #include <LibWeb/Page/Page.h>
 #include <WebContent/Forward.h>
 
@@ -13,11 +14,16 @@ namespace WebContent {
 
 class BackingStoreManager {
 public:
+#ifdef AK_OS_MACOS
+    static void set_browser_mach_port(Core::MachPort&&);
+#endif
+
     enum class WindowResizingInProgress {
         No,
         Yes
     };
     void resize_backing_stores_if_needed(WindowResizingInProgress window_resize_in_progress);
+    void reallocate_backing_stores(Gfx::IntSize);
     void restart_resize_timer();
 
     RefPtr<Gfx::Bitmap> back_bitmap() { return m_back_bitmap; }