1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-24 22:27:42 +00:00

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
8 changed files with 65 additions and 30 deletions

View file

@ -23,13 +23,25 @@
namespace Web { 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) : m_client(client)
{ {
} }
Page::~Page() = default; 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() HTML::BrowsingContext& Page::focused_context()
{ {
if (m_focused_context) if (m_focused_context)
@ -56,13 +68,13 @@ void Page::load_html(StringView html)
Gfx::Palette Page::palette() const 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 // https://w3c.github.io/csswg-drafts/cssom-view-1/#web-exposed-screen-area
CSSPixelRect Page::web_exposed_screen_area() const 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(); auto scale = client().device_pixels_per_css_pixel();
return { return {
device_pixel_rect.x().value() / scale, device_pixel_rect.x().value() / scale,
@ -74,7 +86,7 @@ CSSPixelRect Page::web_exposed_screen_area() const
CSS::PreferredColorScheme Page::preferred_color_scheme() 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 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) void Page::did_request_alert(String const& message)
{ {
m_pending_dialog = PendingDialog::Alert; m_pending_dialog = PendingDialog::Alert;
m_client.page_did_request_alert(message); m_client->page_did_request_alert(message);
if (!message.is_empty()) if (!message.is_empty())
m_pending_dialog_text = message; 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() void Page::alert_closed()
@ -230,12 +242,12 @@ void Page::alert_closed()
bool Page::did_request_confirm(String const& message) bool Page::did_request_confirm(String const& message)
{ {
m_pending_dialog = PendingDialog::Confirm; m_pending_dialog = PendingDialog::Confirm;
m_client.page_did_request_confirm(message); m_client->page_did_request_confirm(message);
if (!message.is_empty()) if (!message.is_empty())
m_pending_dialog_text = message; 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) 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_) Optional<String> Page::did_request_prompt(String const& message, String const& default_)
{ {
m_pending_dialog = PendingDialog::Prompt; 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()) if (!message.is_empty())
m_pending_dialog_text = message; 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) void Page::prompt_closed(Optional<String> response)
@ -273,11 +285,11 @@ void Page::dismiss_dialog()
case PendingDialog::None: case PendingDialog::None:
break; break;
case PendingDialog::Alert: case PendingDialog::Alert:
m_client.page_did_request_accept_dialog(); m_client->page_did_request_accept_dialog();
break; break;
case PendingDialog::Confirm: case PendingDialog::Confirm:
case PendingDialog::Prompt: case PendingDialog::Prompt:
m_client.page_did_request_dismiss_dialog(); m_client->page_did_request_dismiss_dialog();
break; break;
} }
} }
@ -290,7 +302,7 @@ void Page::accept_dialog()
case PendingDialog::Alert: case PendingDialog::Alert:
case PendingDialog::Confirm: case PendingDialog::Confirm:
case PendingDialog::Prompt: case PendingDialog::Prompt:
m_client.page_did_request_accept_dialog(); m_client->page_did_request_accept_dialog();
break; 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 = PendingNonBlockingDialog::ColorPicker;
m_pending_non_blocking_dialog_target = move(target); 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) 2021-2022, Linus Groh <linusg@serenityos.org>
* Copyright (c) 2022, Sam Atkins <atkinssj@serenityos.org> * Copyright (c) 2022, Sam Atkins <atkinssj@serenityos.org>
* Copyright (c) 2023, Shannon Booth <shannon@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
@ -36,12 +37,14 @@ namespace Web {
class PageClient; class PageClient;
class Page : public Weakable<Page> { class Page final
AK_MAKE_NONCOPYABLE(Page); : public JS::Cell
AK_MAKE_NONMOVABLE(Page); , public Weakable<Page> {
JS_CELL(Page, JS::Cell);
public: public:
explicit Page(PageClient&); static JS::NonnullGCPtr<Page> create(JS::VM&, JS::NonnullGCPtr<PageClient>);
~Page(); ~Page();
PageClient& client() { return m_client; } PageClient& client() { return m_client; }
@ -152,13 +155,16 @@ public:
bool pdf_viewer_supported() const { return m_pdf_viewer_supported; } bool pdf_viewer_supported() const { return m_pdf_viewer_supported; }
private: private:
explicit Page(JS::NonnullGCPtr<PageClient>);
virtual void visit_edges(Visitor&) override;
JS::GCPtr<HTML::HTMLMediaElement> media_context_menu_element(); JS::GCPtr<HTML::HTMLMediaElement> media_context_menu_element();
PageClient& m_client; JS::NonnullGCPtr<PageClient> m_client;
WeakPtr<HTML::BrowsingContext> m_focused_context; 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. // FIXME: Enable this by default once CORS preflight checks are supported.
bool m_same_origin_policy_enabled { false }; 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) 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_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_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")))); 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(); 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)); 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(move(page))
, m_page_client(move(page_client)) , m_page_client(move(page_client))
, m_document(move(document)) , m_document(move(document))

View file

@ -32,12 +32,12 @@ public:
private: private:
class SVGPageClient; 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; RefPtr<Gfx::Bitmap> render(Gfx::IntSize) const;
mutable RefPtr<Gfx::ImmutableBitmap> m_immutable_bitmap; mutable RefPtr<Gfx::ImmutableBitmap> m_immutable_bitmap;
NonnullOwnPtr<Page> m_page; JS::Handle<Page> m_page;
JS::Handle<SVGPageClient> m_page_client; JS::Handle<SVGPageClient> m_page_client;
JS::Handle<DOM::Document> m_document; JS::Handle<DOM::Document> m_document;

View file

@ -8,6 +8,7 @@
#include <LibGfx/ShareableBitmap.h> #include <LibGfx/ShareableBitmap.h>
#include <LibGfx/SystemTheme.h> #include <LibGfx/SystemTheme.h>
#include <LibWeb/Bindings/MainThreadVM.h>
#include <LibWeb/CSS/SystemColor.h> #include <LibWeb/CSS/SystemColor.h>
#include <LibWeb/Cookie/ParsedCookie.h> #include <LibWeb/Cookie/ParsedCookie.h>
#include <LibWeb/DOM/Attr.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) PageClient::PageClient(PageHost& owner, u64 id)
: m_owner(owner) : m_owner(owner)
, m_page(make<Web::Page>(*this)) , m_page(Web::Page::create(Web::Bindings::main_thread_vm(), *this))
, m_id(id) , m_id(id)
{ {
setup_palette(); 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 ConnectionFromClient& PageClient::client() const
{ {
return m_owner.client(); return m_owner.client();

View file

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

View file

@ -5,6 +5,7 @@
*/ */
#include <LibJS/Runtime/VM.h> #include <LibJS/Runtime/VM.h>
#include <LibWeb/Bindings/MainThreadVM.h>
#include <WebWorker/ConnectionFromClient.h> #include <WebWorker/ConnectionFromClient.h>
#include <WebWorker/PageHost.h> #include <WebWorker/PageHost.h>
@ -75,9 +76,15 @@ void PageHost::request_file(Web::FileRequest request)
PageHost::PageHost(ConnectionFromClient& client) PageHost::PageHost(ConnectionFromClient& client)
: m_client(client) : m_client(client)
, m_page(make<Web::Page>(*this)) , m_page(Web::Page::create(Web::Bindings::main_thread_vm(), *this))
{ {
setup_palette(); 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: private:
explicit PageHost(ConnectionFromClient&); explicit PageHost(ConnectionFromClient&);
virtual void visit_edges(JS::Cell::Visitor&) override;
void setup_palette(); void setup_palette();
ConnectionFromClient& m_client; ConnectionFromClient& m_client;
NonnullOwnPtr<Web::Page> m_page; JS::NonnullGCPtr<Web::Page> m_page;
RefPtr<Gfx::PaletteImpl> m_palette_impl; RefPtr<Gfx::PaletteImpl> m_palette_impl;
}; };