ladybird/Userland/Libraries/LibWeb/HTML/BrowsingContext.h
Andreas Kling bfd354492e LibWeb: Put most LibWeb GC objects in type-specific heap blocks
With this change, we now have ~1200 CellAllocators across both LibJS and
LibWeb in a normal WebContent instance.

This gives us a minimum heap size of 4.7 MiB in the scenario where we
only have one cell allocated per type. Of course, in practice there will
be many more of each type, so the effective overhead is quite a bit
smaller than that in practice.

I left a few types unconverted to this mechanism because I got tired of
doing this. :^)
2023-11-19 22:00:48 +01:00

245 lines
8.8 KiB
C++

/*
* Copyright (c) 2018-2022, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Function.h>
#include <AK/Noncopyable.h>
#include <AK/RefPtr.h>
#include <AK/WeakPtr.h>
#include <LibGfx/Bitmap.h>
#include <LibGfx/Rect.h>
#include <LibGfx/Size.h>
#include <LibJS/Forward.h>
#include <LibJS/Heap/Cell.h>
#include <LibWeb/DOM/Position.h>
#include <LibWeb/HTML/AbstractBrowsingContext.h>
#include <LibWeb/HTML/ActivateTab.h>
#include <LibWeb/HTML/HistoryHandlingBehavior.h>
#include <LibWeb/HTML/NavigableContainer.h>
#include <LibWeb/HTML/Origin.h>
#include <LibWeb/HTML/SandboxingFlagSet.h>
#include <LibWeb/HTML/SessionHistoryEntry.h>
#include <LibWeb/HTML/TokenizedFeatures.h>
#include <LibWeb/HTML/VisibilityState.h>
#include <LibWeb/Page/EventHandler.h>
#include <LibWeb/Platform/Timer.h>
#include <LibWeb/TreeNode.h>
namespace Web::HTML {
class BrowsingContext final
: public AbstractBrowsingContext
, public Weakable<BrowsingContext> {
JS_CELL(BrowsingContext, AbstractBrowsingContext);
JS_DECLARE_ALLOCATOR(BrowsingContext);
public:
struct BrowsingContextAndDocument {
JS::NonnullGCPtr<BrowsingContext> browsing_context;
JS::NonnullGCPtr<DOM::Document> document;
};
static WebIDL::ExceptionOr<BrowsingContextAndDocument> create_a_new_browsing_context_and_document(Page& page, JS::GCPtr<DOM::Document> creator, JS::GCPtr<DOM::Element> embedder, JS::NonnullGCPtr<BrowsingContextGroup> group);
static WebIDL::ExceptionOr<BrowsingContextAndDocument> create_a_new_auxiliary_browsing_context_and_document(Page& page, JS::NonnullGCPtr<HTML::BrowsingContext> opener);
virtual ~BrowsingContext() override;
JS::NonnullGCPtr<HTML::TraversableNavigable> top_level_traversable() const;
JS::GCPtr<BrowsingContext> parent() const { return m_parent; }
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>
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;
}
bool is_top_level() const;
bool is_focused_context() const;
DOM::Document const* active_document() const;
DOM::Document* active_document();
virtual HTML::WindowProxy* window_proxy() override;
virtual HTML::WindowProxy const* window_proxy() const override;
void set_window_proxy(JS::GCPtr<WindowProxy>);
HTML::Window* active_window();
HTML::Window const* active_window() const;
Page* page() { return m_page; }
Page const* page() const { return m_page; }
Web::EventHandler& event_handler() { return m_event_handler; }
Web::EventHandler const& event_handler() const { return m_event_handler; }
void scroll_to(CSSPixelPoint);
JS::GCPtr<BrowsingContext> top_level_browsing_context() const;
enum class WindowType {
ExistingOrNone,
NewAndUnrestricted,
NewWithNoOpener,
};
struct ChosenBrowsingContext {
JS::GCPtr<AbstractBrowsingContext> browsing_context;
WindowType window_type;
};
ChosenBrowsingContext choose_a_browsing_context(StringView name, TokenizedFeature::NoOpener no_opener, ActivateTab = ActivateTab::Yes);
HTML::NavigableContainer* container() { return m_container; }
HTML::NavigableContainer const* container() const { return m_container; }
CSSPixelPoint to_top_level_position(CSSPixelPoint);
CSSPixelRect to_top_level_rect(CSSPixelRect const&);
JS::GCPtr<DOM::Position> cursor_position() const { return m_cursor_position; }
void set_cursor_position(JS::NonnullGCPtr<DOM::Position>);
bool increment_cursor_position_offset();
bool decrement_cursor_position_offset();
bool cursor_blink_state() const { return m_cursor_blink_state; }
DeprecatedString selected_text() const;
void select_all();
void did_edit(Badge<EditEventHandler>);
JS::GCPtr<DOM::Node> currently_focused_area();
Vector<JS::NonnullGCPtr<SessionHistoryEntry>>& session_history() { return m_session_history; }
Vector<JS::NonnullGCPtr<SessionHistoryEntry>> const& session_history() const { return m_session_history; }
size_t session_history_index() const { return *m_session_history_index; }
// https://html.spec.whatwg.org/multipage/dom.html#still-on-its-initial-about:blank-document
bool still_on_its_initial_about_blank_document() const;
BrowsingContextGroup* group();
void set_group(BrowsingContextGroup*);
// https://html.spec.whatwg.org/multipage/browsers.html#bcg-remove
void remove();
// https://html.spec.whatwg.org/multipage/origin.html#one-permitted-sandboxed-navigator
BrowsingContext const* the_one_permitted_sandboxed_navigator() const;
bool has_been_discarded() const { return m_has_been_discarded; }
Optional<AK::URL> const& creator_url() const { return m_creator_url; }
virtual String const& window_handle() const override { return m_window_handle; }
virtual void set_window_handle(String handle) override { m_window_handle = move(handle); }
private:
explicit BrowsingContext(Page&, HTML::NavigableContainer*);
virtual void visit_edges(Cell::Visitor&) override;
void reset_cursor_blink_cycle();
WeakPtr<Page> m_page;
Web::EventHandler m_event_handler;
// https://html.spec.whatwg.org/multipage/history.html#current-entry
SessionHistoryEntry& current_entry() { return m_session_history[*m_session_history_index]; }
SessionHistoryEntry const& current_entry() const { return m_session_history[*m_session_history_index]; }
Optional<size_t> m_session_history_index { 0 };
// https://html.spec.whatwg.org/multipage/history.html#session-history
Vector<JS::NonnullGCPtr<SessionHistoryEntry>> m_session_history;
// https://html.spec.whatwg.org/multipage/browsers.html#creator-url
Optional<AK::URL> m_creator_url;
// https://html.spec.whatwg.org/multipage/browsers.html#creator-base-url
Optional<AK::URL> m_creator_base_url;
// https://html.spec.whatwg.org/multipage/browsers.html#creator-origin
Optional<HTML::Origin> m_creator_origin;
JS::GCPtr<HTML::NavigableContainer> m_container;
// https://w3c.github.io/webdriver/#dfn-window-handles
String m_window_handle;
// https://html.spec.whatwg.org/multipage/browsers.html#browsing-context
JS::GCPtr<HTML::WindowProxy> m_window_proxy;
JS::GCPtr<DOM::Position> m_cursor_position;
RefPtr<Core::Timer> m_cursor_blink_timer;
bool m_cursor_blink_state { false };
DeprecatedString m_name;
// https://html.spec.whatwg.org/multipage/browsers.html#tlbc-group
JS::GCPtr<BrowsingContextGroup> m_group;
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;
bool m_has_been_discarded { false };
};
HTML::Origin determine_the_origin(AK::URL const& url, SandboxingFlagSet sandbox_flags, Optional<HTML::Origin> source_origin);
SandboxingFlagSet determine_the_creation_sandboxing_flags(BrowsingContext const&, JS::GCPtr<DOM::Element> embedder);
// FIXME: Find a better home for this
bool url_matches_about_blank(AK::URL const& url);
}