LibWeb: Make Web::Page GC-allocated

This is a first step towards removing the various Page& and Page*
we have littering the engine with "trust me bro" safety guarantees.

Co-Authored-By: Andreas Kling <kling@serenityos.org>
This commit is contained in:
Shannon Booth 2023-12-04 21:57:13 +13:00 committed by Andreas Kling
parent 6e6f3a9a8f
commit 0ae5c070c7
Notes: sideshowbarker 2024-07-17 02:29:45 +09:00
8 changed files with 65 additions and 30 deletions

View file

@ -23,13 +23,25 @@
namespace Web {
Page::Page(PageClient& client)
JS::NonnullGCPtr<Page> Page::create(JS::VM& vm, JS::NonnullGCPtr<PageClient> page_client)
{
return vm.heap().allocate_without_realm<Page>(page_client);
}
Page::Page(JS::NonnullGCPtr<PageClient> client)
: m_client(client)
{
}
Page::~Page() = default;
void Page::visit_edges(JS::Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_top_level_traversable);
visitor.visit(m_client);
}
HTML::BrowsingContext& Page::focused_context()
{
if (m_focused_context)
@ -56,13 +68,13 @@ void Page::load_html(StringView html)
Gfx::Palette Page::palette() const
{
return m_client.palette();
return m_client->palette();
}
// https://w3c.github.io/csswg-drafts/cssom-view-1/#web-exposed-screen-area
CSSPixelRect Page::web_exposed_screen_area() const
{
auto device_pixel_rect = m_client.screen_rect();
auto device_pixel_rect = m_client->screen_rect();
auto scale = client().device_pixels_per_css_pixel();
return {
device_pixel_rect.x().value() / scale,
@ -74,7 +86,7 @@ CSSPixelRect Page::web_exposed_screen_area() const
CSS::PreferredColorScheme Page::preferred_color_scheme() const
{
return m_client.preferred_color_scheme();
return m_client->preferred_color_scheme();
}
CSSPixelPoint Page::device_to_css_point(DevicePixelPoint point) const
@ -210,12 +222,12 @@ static ResponseType spin_event_loop_until_dialog_closed(PageClient& client, Opti
void Page::did_request_alert(String const& message)
{
m_pending_dialog = PendingDialog::Alert;
m_client.page_did_request_alert(message);
m_client->page_did_request_alert(message);
if (!message.is_empty())
m_pending_dialog_text = message;
spin_event_loop_until_dialog_closed(m_client, m_pending_alert_response);
spin_event_loop_until_dialog_closed(*m_client, m_pending_alert_response);
}
void Page::alert_closed()
@ -230,12 +242,12 @@ void Page::alert_closed()
bool Page::did_request_confirm(String const& message)
{
m_pending_dialog = PendingDialog::Confirm;
m_client.page_did_request_confirm(message);
m_client->page_did_request_confirm(message);
if (!message.is_empty())
m_pending_dialog_text = message;
return spin_event_loop_until_dialog_closed(m_client, m_pending_confirm_response);
return spin_event_loop_until_dialog_closed(*m_client, m_pending_confirm_response);
}
void Page::confirm_closed(bool accepted)
@ -250,12 +262,12 @@ void Page::confirm_closed(bool accepted)
Optional<String> Page::did_request_prompt(String const& message, String const& default_)
{
m_pending_dialog = PendingDialog::Prompt;
m_client.page_did_request_prompt(message, default_);
m_client->page_did_request_prompt(message, default_);
if (!message.is_empty())
m_pending_dialog_text = message;
return spin_event_loop_until_dialog_closed(m_client, m_pending_prompt_response);
return spin_event_loop_until_dialog_closed(*m_client, m_pending_prompt_response);
}
void Page::prompt_closed(Optional<String> response)
@ -273,11 +285,11 @@ void Page::dismiss_dialog()
case PendingDialog::None:
break;
case PendingDialog::Alert:
m_client.page_did_request_accept_dialog();
m_client->page_did_request_accept_dialog();
break;
case PendingDialog::Confirm:
case PendingDialog::Prompt:
m_client.page_did_request_dismiss_dialog();
m_client->page_did_request_dismiss_dialog();
break;
}
}
@ -290,7 +302,7 @@ void Page::accept_dialog()
case PendingDialog::Alert:
case PendingDialog::Confirm:
case PendingDialog::Prompt:
m_client.page_did_request_accept_dialog();
m_client->page_did_request_accept_dialog();
break;
}
}
@ -301,7 +313,7 @@ void Page::did_request_color_picker(WeakPtr<HTML::HTMLInputElement> target, Colo
m_pending_non_blocking_dialog = PendingNonBlockingDialog::ColorPicker;
m_pending_non_blocking_dialog_target = move(target);
m_client.page_did_request_color_picker(current_color);
m_client->page_did_request_color_picker(current_color);
}
}

View file

@ -1,7 +1,8 @@
/*
* Copyright (c) 2020-2021, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2020-2023, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2021-2022, Linus Groh <linusg@serenityos.org>
* Copyright (c) 2022, Sam Atkins <atkinssj@serenityos.org>
* Copyright (c) 2023, Shannon Booth <shannon@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -36,12 +37,14 @@ namespace Web {
class PageClient;
class Page : public Weakable<Page> {
AK_MAKE_NONCOPYABLE(Page);
AK_MAKE_NONMOVABLE(Page);
class Page final
: public JS::Cell
, public Weakable<Page> {
JS_CELL(Page, JS::Cell);
public:
explicit Page(PageClient&);
static JS::NonnullGCPtr<Page> create(JS::VM&, JS::NonnullGCPtr<PageClient>);
~Page();
PageClient& client() { return m_client; }
@ -152,13 +155,16 @@ public:
bool pdf_viewer_supported() const { return m_pdf_viewer_supported; }
private:
explicit Page(JS::NonnullGCPtr<PageClient>);
virtual void visit_edges(Visitor&) override;
JS::GCPtr<HTML::HTMLMediaElement> media_context_menu_element();
PageClient& m_client;
JS::NonnullGCPtr<PageClient> m_client;
WeakPtr<HTML::BrowsingContext> m_focused_context;
JS::Handle<HTML::TraversableNavigable> m_top_level_traversable;
JS::GCPtr<HTML::TraversableNavigable> m_top_level_traversable;
// FIXME: Enable this by default once CORS preflight checks are supported.
bool m_same_origin_policy_enabled { false };

View file

@ -57,7 +57,7 @@ private:
ErrorOr<NonnullRefPtr<SVGDecodedImageData>> SVGDecodedImageData::create(Page& host_page, AK::URL const& url, ByteBuffer data)
{
auto page_client = SVGPageClient::create(Bindings::main_thread_vm(), host_page);
auto page = make<Page>(*page_client);
auto page = Page::create(Bindings::main_thread_vm(), *page_client);
page_client->m_svg_page = page.ptr();
page->set_top_level_traversable(MUST(Web::HTML::TraversableNavigable::create_a_fresh_top_level_traversable(*page, AK::URL("about:blank"))));
JS::NonnullGCPtr<HTML::Navigable> navigable = page->top_level_traversable();
@ -98,10 +98,10 @@ ErrorOr<NonnullRefPtr<SVGDecodedImageData>> SVGDecodedImageData::create(Page& ho
MUST(document->append_child(*svg_root));
return adopt_nonnull_ref_or_enomem(new (nothrow) SVGDecodedImageData(move(page), move(page_client), move(document), move(svg_root)));
return adopt_nonnull_ref_or_enomem(new (nothrow) SVGDecodedImageData(page, move(page_client), move(document), move(svg_root)));
}
SVGDecodedImageData::SVGDecodedImageData(NonnullOwnPtr<Page> page, JS::Handle<SVGPageClient> page_client, JS::Handle<DOM::Document> document, JS::Handle<SVG::SVGSVGElement> root_element)
SVGDecodedImageData::SVGDecodedImageData(JS::NonnullGCPtr<Page> page, JS::Handle<SVGPageClient> page_client, JS::Handle<DOM::Document> document, JS::Handle<SVG::SVGSVGElement> root_element)
: m_page(move(page))
, m_page_client(move(page_client))
, m_document(move(document))

View file

@ -32,12 +32,12 @@ public:
private:
class SVGPageClient;
SVGDecodedImageData(NonnullOwnPtr<Page>, JS::Handle<SVGPageClient>, JS::Handle<DOM::Document>, JS::Handle<SVG::SVGSVGElement>);
SVGDecodedImageData(JS::NonnullGCPtr<Page>, JS::Handle<SVGPageClient>, JS::Handle<DOM::Document>, JS::Handle<SVG::SVGSVGElement>);
RefPtr<Gfx::Bitmap> render(Gfx::IntSize) const;
mutable RefPtr<Gfx::ImmutableBitmap> m_immutable_bitmap;
NonnullOwnPtr<Page> m_page;
JS::Handle<Page> m_page;
JS::Handle<SVGPageClient> m_page_client;
JS::Handle<DOM::Document> m_document;

View file

@ -8,6 +8,7 @@
#include <LibGfx/ShareableBitmap.h>
#include <LibGfx/SystemTheme.h>
#include <LibWeb/Bindings/MainThreadVM.h>
#include <LibWeb/CSS/SystemColor.h>
#include <LibWeb/Cookie/ParsedCookie.h>
#include <LibWeb/DOM/Attr.h>
@ -46,7 +47,7 @@ JS::NonnullGCPtr<PageClient> PageClient::create(JS::VM& vm, PageHost& page_host,
PageClient::PageClient(PageHost& owner, u64 id)
: m_owner(owner)
, m_page(make<Web::Page>(*this))
, m_page(Web::Page::create(Web::Bindings::main_thread_vm(), *this))
, m_id(id)
{
setup_palette();
@ -56,6 +57,12 @@ PageClient::PageClient(PageHost& owner, u64 id)
});
}
void PageClient::visit_edges(JS::Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_page);
}
ConnectionFromClient& PageClient::client() const
{
return m_owner.client();

View file

@ -61,6 +61,8 @@ public:
private:
PageClient(PageHost&, u64 id);
virtual void visit_edges(JS::Cell::Visitor&) override;
// ^PageClient
virtual bool is_connection_open() const override;
virtual Gfx::Palette palette() const override;
@ -131,7 +133,7 @@ private:
ConnectionFromClient& client() const;
PageHost& m_owner;
NonnullOwnPtr<Web::Page> m_page;
JS::NonnullGCPtr<Web::Page> m_page;
RefPtr<Gfx::PaletteImpl> m_palette_impl;
Web::DevicePixelRect m_screen_rect;
Web::DevicePixelSize m_content_size;

View file

@ -5,6 +5,7 @@
*/
#include <LibJS/Runtime/VM.h>
#include <LibWeb/Bindings/MainThreadVM.h>
#include <WebWorker/ConnectionFromClient.h>
#include <WebWorker/PageHost.h>
@ -75,9 +76,15 @@ void PageHost::request_file(Web::FileRequest request)
PageHost::PageHost(ConnectionFromClient& client)
: m_client(client)
, m_page(make<Web::Page>(*this))
, m_page(Web::Page::create(Web::Bindings::main_thread_vm(), *this))
{
setup_palette();
}
void PageHost::visit_edges(JS::Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_page);
}
}

View file

@ -33,11 +33,12 @@ public:
private:
explicit PageHost(ConnectionFromClient&);
virtual void visit_edges(JS::Cell::Visitor&) override;
void setup_palette();
ConnectionFromClient& m_client;
NonnullOwnPtr<Web::Page> m_page;
JS::NonnullGCPtr<Web::Page> m_page;
RefPtr<Gfx::PaletteImpl> m_palette_impl;
};