1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-14 08:54:58 +00:00

LibWeb: Make BrowsingContext GC-allocated

(And BrowsingContextGroup had to come along for the ride as well.)
This solves a number of nasty reference cycles between browsing
contexts, history items, and their documents.
This commit is contained in:
Andreas Kling 2022-10-17 11:06:50 +02:00
parent 2898701459
commit 83c5ff57d8
15 changed files with 225 additions and 44 deletions

View file

@ -79,7 +79,7 @@
namespace Web::DOM {
// https://html.spec.whatwg.org/multipage/origin.html#obtain-browsing-context-navigation
static NonnullRefPtr<HTML::BrowsingContext> obtain_a_browsing_context_to_use_for_a_navigation_response(
static JS::NonnullGCPtr<HTML::BrowsingContext> obtain_a_browsing_context_to_use_for_a_navigation_response(
HTML::BrowsingContext& browsing_context,
HTML::SandboxingFlagSet sandbox_flags,
HTML::CrossOriginOpenerPolicy navigation_coop,
@ -130,7 +130,7 @@ JS::NonnullGCPtr<Document> Document::create_and_initialize(Type type, String con
// given navigationParams's browsing context, navigationParams's final sandboxing flag set,
// navigationParams's cross-origin opener policy, and navigationParams's COOP enforcement result.
auto browsing_context = obtain_a_browsing_context_to_use_for_a_navigation_response(
navigation_params.browsing_context,
*navigation_params.browsing_context,
navigation_params.final_sandboxing_flag_set,
navigation_params.cross_origin_opener_policy,
navigation_params.coop_enforcement_result);
@ -330,6 +330,8 @@ void Document::visit_edges(Cell::Visitor& visitor)
visitor.visit(m_pending_parsing_blocking_script.ptr());
visitor.visit(m_history.ptr());
visitor.visit(m_browsing_context);
visitor.visit(m_applets);
visitor.visit(m_anchors);
visitor.visit(m_images);
@ -2051,10 +2053,10 @@ HTML::PolicyContainer Document::policy_container() const
}
// https://html.spec.whatwg.org/multipage/browsers.html#list-of-the-descendant-browsing-contexts
Vector<NonnullRefPtr<HTML::BrowsingContext>> Document::list_of_descendant_browsing_contexts() const
Vector<JS::Handle<HTML::BrowsingContext>> Document::list_of_descendant_browsing_contexts() const
{
// 1. Let list be an empty list.
Vector<NonnullRefPtr<HTML::BrowsingContext>> list;
Vector<JS::Handle<HTML::BrowsingContext>> list;
// 2. For each browsing context container container,
// whose nested browsing context is non-null and whose shadow-including root is d, in shadow-including tree order:
@ -2063,7 +2065,7 @@ Vector<NonnullRefPtr<HTML::BrowsingContext>> Document::list_of_descendant_browsi
// of this document's browsing context.
if (browsing_context()) {
browsing_context()->for_each_in_subtree([&](auto& context) {
list.append(context);
list.append(JS::make_handle(const_cast<HTML::BrowsingContext&>(context)));
return IterationDecision::Continue;
});
}

View file

@ -416,7 +416,7 @@ public:
HTML::PolicyContainer policy_container() const;
// https://html.spec.whatwg.org/multipage/browsers.html#list-of-the-descendant-browsing-contexts
Vector<NonnullRefPtr<HTML::BrowsingContext>> list_of_descendant_browsing_contexts() const;
Vector<JS::Handle<HTML::BrowsingContext>> list_of_descendant_browsing_contexts() const;
// https://html.spec.whatwg.org/multipage/window-object.html#discard-a-document
void discard();

View file

@ -92,21 +92,21 @@ HTML::Origin determine_the_origin(BrowsingContext const& browsing_context, Optio
}
// https://html.spec.whatwg.org/multipage/browsers.html#creating-a-new-top-level-browsing-context
NonnullRefPtr<BrowsingContext> BrowsingContext::create_a_new_top_level_browsing_context(Web::Page& page)
JS::NonnullGCPtr<BrowsingContext> BrowsingContext::create_a_new_top_level_browsing_context(Web::Page& page)
{
// 1. Let group be the result of creating a new browsing context group.
auto group = BrowsingContextGroup::create_a_new_browsing_context_group(page);
// 2. Return group's browsing context set[0].
return *group->browsing_context_set().begin();
return *(*group->browsing_context_set().begin());
}
// https://html.spec.whatwg.org/multipage/browsers.html#creating-a-new-browsing-context
NonnullRefPtr<BrowsingContext> BrowsingContext::create_a_new_browsing_context(Page& page, JS::GCPtr<DOM::Document> creator, JS::GCPtr<DOM::Element> embedder, BrowsingContextGroup&)
JS::NonnullGCPtr<BrowsingContext> BrowsingContext::create_a_new_browsing_context(Page& page, JS::GCPtr<DOM::Document> creator, JS::GCPtr<DOM::Element> embedder, BrowsingContextGroup&)
{
// 1. Let browsingContext be a new browsing context.
BrowsingContextContainer* container = (embedder && is<BrowsingContextContainer>(*embedder)) ? static_cast<BrowsingContextContainer*>(embedder.ptr()) : nullptr;
auto browsing_context = adopt_ref(*new BrowsingContext(page, container));
auto browsing_context = Bindings::main_thread_vm().heap().allocate_without_realm<BrowsingContext>(page, container);
// 2. Let unsafeContextCreationTime be the unsafe shared current time.
[[maybe_unused]] auto unsafe_context_creation_time = HighResolutionTime::unsafe_shared_current_time();
@ -125,7 +125,7 @@ NonnullRefPtr<BrowsingContext> BrowsingContext::create_a_new_browsing_context(Pa
SandboxingFlagSet sandbox_flags;
// 5. Let origin be the result of determining the origin given browsingContext, about:blank, sandboxFlags, and browsingContext's creator origin.
auto origin = determine_the_origin(browsing_context, AK::URL("about:blank"), sandbox_flags, browsing_context->m_creator_origin);
auto origin = determine_the_origin(*browsing_context, AK::URL("about:blank"), sandbox_flags, browsing_context->m_creator_origin);
// FIXME: 6. Let permissionsPolicy be the result of creating a permissions policy given browsingContext and origin. [PERMISSIONSPOLICY]
@ -240,7 +240,7 @@ NonnullRefPtr<BrowsingContext> BrowsingContext::create_a_new_browsing_context(Pa
document->completely_finish_loading();
// 24. Return browsingContext.
return browsing_context;
return *browsing_context;
}
BrowsingContext::BrowsingContext(Page& page, HTML::BrowsingContextContainer* container)
@ -261,6 +261,22 @@ BrowsingContext::BrowsingContext(Page& page, HTML::BrowsingContextContainer* con
BrowsingContext::~BrowsingContext() = default;
void BrowsingContext::visit_edges(Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
for (auto& entry : m_session_history)
visitor.visit(entry.document);
visitor.visit(m_container);
visitor.visit(m_window_proxy);
visitor.visit(m_group);
visitor.visit(m_parent);
visitor.visit(m_first_child);
visitor.visit(m_last_child);
visitor.visit(m_next_sibling);
visitor.visit(m_previous_sibling);
}
void BrowsingContext::did_edit(Badge<EditEventHandler>)
{
reset_cursor_blink_cycle();
@ -446,7 +462,7 @@ Gfx::IntRect BrowsingContext::to_top_level_rect(Gfx::IntRect const& a_rect)
Gfx::IntPoint BrowsingContext::to_top_level_position(Gfx::IntPoint const& a_position)
{
auto position = a_position;
for (auto* ancestor = parent(); ancestor; ancestor = ancestor->parent()) {
for (auto ancestor = parent(); ancestor; ancestor = ancestor->parent()) {
if (ancestor->is_top_level())
break;
if (!ancestor->container())
@ -657,7 +673,7 @@ BrowsingContext* BrowsingContext::choose_a_browsing_context(StringView name, boo
// name, a browsing context current, and a boolean noopener are as follows:
// 1. Let chosen be null.
BrowsingContext* chosen = nullptr;
JS::GCPtr<BrowsingContext> chosen = nullptr;
// FIXME: 2. Let windowType be "existing or none".
@ -672,7 +688,7 @@ BrowsingContext* BrowsingContext::choose_a_browsing_context(StringView name, boo
// set chosen to current's parent browsing context, if any, and current
// otherwise.
if (name.equals_ignoring_case("_parent"sv)) {
if (auto* parent = this->parent())
if (auto parent = this->parent())
chosen = parent;
else
chosen = this;
@ -872,13 +888,13 @@ void BrowsingContext::remove()
VERIFY(group());
// 2. Let group be browsingContext's group.
NonnullRefPtr<BrowsingContextGroup> group = *this->group();
JS::NonnullGCPtr<BrowsingContextGroup> group = *this->group();
// 3. Set browsingContext's group to null.
set_group(nullptr);
// 4. Remove browsingContext from group's browsing context set.
group->browsing_context_set().remove(*this);
group->browsing_context_set().remove(this);
// 5. If group's browsing context set is empty, then remove group from the user agent's browsing context group set.
// NOTE: This is done by ~BrowsingContextGroup() when the refcount reaches 0.
@ -1281,7 +1297,7 @@ Vector<JS::Handle<DOM::Document>> BrowsingContext::document_family() const
for (auto& entry : m_session_history) {
if (!entry.document)
continue;
if (documents.set(entry.document.ptr()) == AK::HashSetResult::ReplacedExistingEntry)
if (documents.set(const_cast<DOM::Document*>(entry.document.ptr())) == AK::HashSetResult::ReplacedExistingEntry)
continue;
for (auto& context : entry.document->list_of_descendant_browsing_contexts()) {
for (auto& document : context->document_family()) {
@ -1367,4 +1383,56 @@ void BrowsingContext::close()
discard();
}
void BrowsingContext::append_child(JS::NonnullGCPtr<BrowsingContext> child)
{
VERIFY(!child->m_parent);
if (m_last_child)
m_last_child->m_next_sibling = child;
child->m_previous_sibling = m_last_child;
child->m_parent = this;
m_last_child = child;
if (!m_first_child)
m_first_child = m_last_child;
}
void BrowsingContext::remove_child(JS::NonnullGCPtr<BrowsingContext> child)
{
VERIFY(child->m_parent.ptr() == this);
if (m_first_child == child)
m_first_child = child->m_next_sibling;
if (m_last_child == child)
m_last_child = child->m_previous_sibling;
if (child->m_next_sibling)
child->m_next_sibling->m_previous_sibling = child->m_previous_sibling;
if (child->m_previous_sibling)
child->m_previous_sibling->m_next_sibling = child->m_next_sibling;
child->m_next_sibling = nullptr;
child->m_previous_sibling = nullptr;
child->m_parent = nullptr;
}
JS::GCPtr<BrowsingContext> BrowsingContext::first_child() const
{
return m_first_child;
}
JS::GCPtr<BrowsingContext> BrowsingContext::next_sibling() const
{
return m_next_sibling;
}
bool BrowsingContext::is_ancestor_of(BrowsingContext const& other) const
{
for (auto ancestor = other.parent(); ancestor; ancestor = ancestor->parent()) {
if (ancestor == this)
return true;
}
return false;
}
}

View file

@ -13,6 +13,7 @@
#include <LibGfx/Bitmap.h>
#include <LibGfx/Rect.h>
#include <LibGfx/Size.h>
#include <LibJS/Heap/Cell.h>
#include <LibWeb/DOM/Position.h>
#include <LibWeb/HTML/BrowsingContextContainer.h>
#include <LibWeb/HTML/HistoryHandlingBehavior.h>
@ -26,13 +27,83 @@
namespace Web::HTML {
class BrowsingContext : public TreeNode<BrowsingContext> {
class BrowsingContext final
: public JS::Cell
, public Weakable<BrowsingContext> {
JS_CELL(BrowsingContext, JS::Cell);
public:
static NonnullRefPtr<BrowsingContext> create_a_new_browsing_context(Page&, JS::GCPtr<DOM::Document> creator, JS::GCPtr<DOM::Element> embedder, BrowsingContextGroup&);
static NonnullRefPtr<BrowsingContext> create_a_new_top_level_browsing_context(Page&);
static JS::NonnullGCPtr<BrowsingContext> create_a_new_browsing_context(Page&, JS::GCPtr<DOM::Document> creator, JS::GCPtr<DOM::Element> embedder, BrowsingContextGroup&);
static JS::NonnullGCPtr<BrowsingContext> create_a_new_top_level_browsing_context(Page&);
~BrowsingContext();
JS::GCPtr<BrowsingContext> parent() const { return m_parent; }
void append_child(JS::NonnullGCPtr<BrowsingContext>);
void remove_child(JS::NonnullGCPtr<BrowsingContext>);
JS::GCPtr<BrowsingContext> first_child() const;
JS::GCPtr<BrowsingContext> next_sibling() const;
bool is_ancestor_of(BrowsingContext const&) const;
template<typename Callback>
IterationDecision for_each_in_inclusive_subtree(Callback callback) const
{
if (callback(*this) == IterationDecision::Break)
return IterationDecision::Break;
for (auto child = first_child(); child; child = child->next_sibling()) {
if (child->for_each_in_inclusive_subtree(callback) == IterationDecision::Break)
return IterationDecision::Break;
}
return IterationDecision::Continue;
}
template<typename Callback>
IterationDecision for_each_in_inclusive_subtree(Callback callback)
{
if (callback(*this) == IterationDecision::Break)
return IterationDecision::Break;
for (auto child = first_child(); child; child = child->next_sibling()) {
if (child->for_each_in_inclusive_subtree(callback) == IterationDecision::Break)
return IterationDecision::Break;
}
return IterationDecision::Continue;
}
template<typename Callback>
void for_each_child(Callback callback) const
{
for (auto node = first_child(); node; node = node->next_sibling())
callback(*node);
}
template<typename Callback>
void for_each_child(Callback callback)
{
for (auto node = first_child(); node; node = node->next_sibling())
callback(*node);
}
template<typename Callback>
IterationDecision for_each_in_subtree(Callback callback) const
{
for (auto child = first_child(); child; child = child->next_sibling()) {
if (child->for_each_in_inclusive_subtree(callback) == IterationDecision::Break)
return IterationDecision::Break;
}
return IterationDecision::Continue;
}
template<typename Callback>
IterationDecision for_each_in_subtree(Callback callback)
{
for (auto child = first_child(); child; child = child->next_sibling()) {
if (child->for_each_in_inclusive_subtree(callback) == IterationDecision::Break)
return IterationDecision::Break;
}
return IterationDecision::Continue;
}
class ViewportClient {
public:
virtual ~ViewportClient() = default;
@ -178,6 +249,8 @@ public:
private:
explicit BrowsingContext(Page&, HTML::BrowsingContextContainer*);
virtual void visit_edges(Cell::Visitor&) override;
void reset_cursor_blink_cycle();
void scroll_offset_did_change();
@ -204,12 +277,12 @@ private:
// https://html.spec.whatwg.org/multipage/browsers.html#creator-origin
Optional<HTML::Origin> m_creator_origin;
WeakPtr<HTML::BrowsingContextContainer> m_container;
JS::GCPtr<HTML::BrowsingContextContainer> m_container;
Gfx::IntSize m_size;
Gfx::IntPoint m_viewport_scroll_offset;
// https://html.spec.whatwg.org/multipage/browsers.html#browsing-context
JS::Handle<HTML::WindowProxy> m_window_proxy;
JS::GCPtr<HTML::WindowProxy> m_window_proxy;
DOM::Position m_cursor_position;
RefPtr<Platform::Timer> m_cursor_blink_timer;
@ -221,10 +294,16 @@ private:
String m_name;
// https://html.spec.whatwg.org/multipage/browsers.html#tlbc-group
RefPtr<BrowsingContextGroup> m_group;
JS::GCPtr<BrowsingContextGroup> m_group;
// https://html.spec.whatwg.org/multipage/interaction.html#system-visibility-state
VisibilityState m_system_visibility_state { VisibilityState::Hidden };
JS::GCPtr<BrowsingContext> m_parent;
JS::GCPtr<BrowsingContext> m_first_child;
JS::GCPtr<BrowsingContext> m_last_child;
JS::GCPtr<BrowsingContext> m_next_sibling;
JS::GCPtr<BrowsingContext> m_previous_sibling;
};
HTML::Origin determine_the_origin(BrowsingContext const& browsing_context, Optional<AK::URL> url, SandboxingFlagSet sandbox_flags, Optional<HTML::Origin> invocation_origin);

View file

@ -31,6 +31,12 @@ BrowsingContextContainer::BrowsingContextContainer(DOM::Document& document, DOM:
BrowsingContextContainer::~BrowsingContextContainer() = default;
void BrowsingContextContainer::visit_edges(Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_nested_browsing_context);
}
// https://html.spec.whatwg.org/multipage/browsers.html#creating-a-new-nested-browsing-context
void BrowsingContextContainer::create_new_nested_browsing_context()
{
@ -142,7 +148,7 @@ void BrowsingContextContainer::shared_attribute_processing_steps_for_iframe_and_
// 3. If there exists an ancestor browsing context of element's nested browsing context
// whose active document's URL, ignoring fragments, is equal to url, then return.
if (m_nested_browsing_context) {
for (auto* ancestor = m_nested_browsing_context->parent(); ancestor; ancestor = ancestor->parent()) {
for (auto ancestor = m_nested_browsing_context->parent(); ancestor; ancestor = ancestor->parent()) {
VERIFY(ancestor->active_document());
if (ancestor->active_document()->url().equals(url, AK::URL::ExcludeFragment::Yes))
return;

View file

@ -31,6 +31,8 @@ public:
protected:
BrowsingContextContainer(DOM::Document&, DOM::QualifiedName);
virtual void visit_edges(Cell::Visitor&) override;
// https://html.spec.whatwg.org/multipage/iframe-embed-object.html#shared-attribute-processing-steps-for-iframe-and-frame-elements
void shared_attribute_processing_steps_for_iframe_and_frame(bool initial_insertion);
@ -39,7 +41,7 @@ protected:
void create_new_nested_browsing_context();
RefPtr<BrowsingContext> m_nested_browsing_context;
JS::GCPtr<BrowsingContext> m_nested_browsing_context;
private:
virtual bool is_browsing_context_container() const override { return true; }

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibWeb/Bindings/MainThreadVM.h>
#include <LibWeb/HTML/BrowsingContext.h>
#include <LibWeb/HTML/BrowsingContextGroup.h>
@ -27,21 +28,28 @@ BrowsingContextGroup::~BrowsingContextGroup()
user_agent_browsing_context_group_set().remove(this);
}
void BrowsingContextGroup::visit_edges(Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
for (auto& context : m_browsing_context_set)
visitor.visit(context);
}
// https://html.spec.whatwg.org/multipage/browsers.html#creating-a-new-browsing-context-group
NonnullRefPtr<BrowsingContextGroup> BrowsingContextGroup::create_a_new_browsing_context_group(Web::Page& page)
JS::NonnullGCPtr<BrowsingContextGroup> BrowsingContextGroup::create_a_new_browsing_context_group(Web::Page& page)
{
// 1. Let group be a new browsing context group.
// 2. Append group to the user agent's browsing context group set.
auto group = adopt_ref(*new BrowsingContextGroup(page));
auto group = Bindings::main_thread_vm().heap().allocate_without_realm<BrowsingContextGroup>(page);
// 3. Let browsingContext be the result of creating a new browsing context with null, null, and group.
auto browsing_context = BrowsingContext::create_a_new_browsing_context(page, nullptr, nullptr, group);
auto browsing_context = BrowsingContext::create_a_new_browsing_context(page, nullptr, nullptr, *group);
// 4. Append browsingContext to group.
group->append(move(browsing_context));
// 5. Return group.
return group;
return *group;
}
// https://html.spec.whatwg.org/multipage/browsers.html#bcg-append
@ -50,7 +58,7 @@ void BrowsingContextGroup::append(BrowsingContext& browsing_context)
VERIFY(browsing_context.is_top_level());
// 1. Append browsingContext to group's browsing context set.
m_browsing_context_set.set(browsing_context);
m_browsing_context_set.set(&browsing_context);
// 2. Set browsingContext's group to group.
browsing_context.set_group(this);

View file

@ -8,14 +8,16 @@
#include <AK/HashMap.h>
#include <AK/NonnullRefPtr.h>
#include <AK/RefCounted.h>
#include <LibJS/Heap/Cell.h>
#include <LibWeb/Forward.h>
namespace Web::HTML {
class BrowsingContextGroup : public RefCounted<BrowsingContextGroup> {
class BrowsingContextGroup final : public JS::Cell {
JS_CELL(BrowsingContextGroup, JS::Cell);
public:
static NonnullRefPtr<BrowsingContextGroup> create_a_new_browsing_context_group(Page&);
static JS::NonnullGCPtr<BrowsingContextGroup> create_a_new_browsing_context_group(Page&);
~BrowsingContextGroup();
Page* page() { return m_page; }
@ -30,8 +32,10 @@ public:
private:
explicit BrowsingContextGroup(Web::Page&);
virtual void visit_edges(Cell::Visitor&) override;
// https://html.spec.whatwg.org/multipage/browsers.html#browsing-context-group-set
OrderedHashTable<NonnullRefPtr<BrowsingContext>> m_browsing_context_set;
OrderedHashTable<BrowsingContext*> m_browsing_context_set;
WeakPtr<Page> m_page;
};

View file

@ -47,7 +47,7 @@ struct NavigationParams {
Optional<Environment> reserved_environment;
// the browsing context to be navigated (or discarded, if a browsing context group switch occurs)
NonnullRefPtr<HTML::BrowsingContext> browsing_context;
JS::Handle<HTML::BrowsingContext> browsing_context;
// a history handling behavior
HistoryHandlingBehavior history_handling { HistoryHandlingBehavior::Default };

View file

@ -32,6 +32,7 @@ EnvironmentSettingsObject::~EnvironmentSettingsObject()
void EnvironmentSettingsObject::visit_edges(Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(target_browsing_context);
for (auto& promise : m_about_to_be_notified_rejected_promises_list)
visitor.visit(promise);
}

View file

@ -33,7 +33,7 @@ struct Environment {
Origin top_level_origin;
// https://html.spec.whatwg.org/multipage/webappapis.html#concept-environment-target-browsing-context
RefPtr<BrowsingContext> target_browsing_context;
JS::GCPtr<BrowsingContext> target_browsing_context;
// FIXME: An active service worker https://html.spec.whatwg.org/multipage/webappapis.html#concept-environment-active-service-worker

View file

@ -30,7 +30,7 @@ struct SessionHistoryEntry {
AK::URL url;
// document, a Document or null
WeakPtr<DOM::Document> document;
JS::GCPtr<DOM::Document> document;
// serialized state, which is serialized state or null, initially null
Optional<String> serialized_state;
@ -49,7 +49,7 @@ struct SessionHistoryEntry {
// FIXME: persisted user state, which is implementation-defined, initially null
// NOTE: This is where we could remember the state of form controls, for example.
WeakPtr<BrowsingContext> original_source_browsing_context;
JS::GCPtr<BrowsingContext> original_source_browsing_context;
};
}

View file

@ -13,7 +13,7 @@ namespace Web {
Page::Page(PageClient& client)
: m_client(client)
{
m_top_level_browsing_context = HTML::BrowsingContext::create_a_new_top_level_browsing_context(*this);
m_top_level_browsing_context = JS::make_handle(*HTML::BrowsingContext::create_a_new_top_level_browsing_context(*this));
}
Page::~Page() = default;
@ -95,4 +95,14 @@ bool Page::handle_keyup(KeyCode key, unsigned modifiers, u32 code_point)
return focused_context().event_handler().handle_keyup(key, modifiers, code_point);
}
HTML::BrowsingContext& Page::top_level_browsing_context()
{
return *m_top_level_browsing_context;
}
HTML::BrowsingContext const& Page::top_level_browsing_context() const
{
return *m_top_level_browsing_context;
}
}

View file

@ -17,6 +17,7 @@
#include <LibGfx/Forward.h>
#include <LibGfx/Palette.h>
#include <LibGfx/StandardCursor.h>
#include <LibJS/Heap/Handle.h>
#include <LibWeb/CSS/PreferredColorScheme.h>
#include <LibWeb/Forward.h>
#include <LibWeb/Loader/FileRequest.h>
@ -36,8 +37,8 @@ public:
PageClient& client() { return m_client; }
PageClient const& client() const { return m_client; }
HTML::BrowsingContext& top_level_browsing_context() { return *m_top_level_browsing_context; }
HTML::BrowsingContext const& top_level_browsing_context() const { return *m_top_level_browsing_context; }
HTML::BrowsingContext& top_level_browsing_context();
HTML::BrowsingContext const& top_level_browsing_context() const;
HTML::BrowsingContext& focused_context();
HTML::BrowsingContext const& focused_context() const { return const_cast<Page*>(this)->focused_context(); }
@ -74,7 +75,7 @@ public:
private:
PageClient& m_client;
RefPtr<HTML::BrowsingContext> m_top_level_browsing_context;
JS::Handle<HTML::BrowsingContext> m_top_level_browsing_context;
WeakPtr<HTML::BrowsingContext> m_focused_context;
// FIXME: Enable this by default once CORS preflight checks are supported.

View file

@ -83,7 +83,7 @@ void LabelablePaintable::handle_associated_label_mouseup(Badge<Layout::Label>)
{
// NOTE: Handling the click may run arbitrary JS, which could disappear this node.
NonnullRefPtr protected_this = *this;
NonnullRefPtr protected_browsing_context = browsing_context();
JS::NonnullGCPtr protected_browsing_context { browsing_context() };
set_being_pressed(false);
}