Coverage Report

Created: 2026-02-14 08:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/serenity/Userland/Libraries/LibWeb/HTML/Navigable.h
Line
Count
Source
1
/*
2
 * Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
3
 * Copyright (c) 2023, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
4
 *
5
 * SPDX-License-Identifier: BSD-2-Clause
6
 */
7
8
#pragma once
9
10
#include <AK/HashTable.h>
11
#include <AK/String.h>
12
#include <LibJS/Heap/Cell.h>
13
#include <LibWeb/Bindings/NavigationPrototype.h>
14
#include <LibWeb/DOM/DocumentLoadEventDelayer.h>
15
#include <LibWeb/Forward.h>
16
#include <LibWeb/HTML/ActivateTab.h>
17
#include <LibWeb/HTML/HistoryHandlingBehavior.h>
18
#include <LibWeb/HTML/NavigationParams.h>
19
#include <LibWeb/HTML/POSTResource.h>
20
#include <LibWeb/HTML/SandboxingFlagSet.h>
21
#include <LibWeb/HTML/SourceSnapshotParams.h>
22
#include <LibWeb/HTML/StructuredSerialize.h>
23
#include <LibWeb/HTML/TokenizedFeatures.h>
24
#include <LibWeb/Page/EventHandler.h>
25
#include <LibWeb/PixelUnits.h>
26
#include <LibWeb/XHR/FormDataEntry.h>
27
28
namespace Web::HTML {
29
30
enum class CSPNavigationType {
31
    Other,
32
    FormSubmission,
33
};
34
35
// https://html.spec.whatwg.org/multipage/browsing-the-web.html#user-navigation-involvement
36
enum class UserNavigationInvolvement {
37
    BrowserUI,
38
    Activation,
39
    None,
40
};
41
42
// https://html.spec.whatwg.org/multipage/browsing-the-web.html#target-snapshot-params
43
struct TargetSnapshotParams {
44
    SandboxingFlagSet sandboxing_flags {};
45
};
46
47
// https://html.spec.whatwg.org/multipage/document-sequences.html#navigable
48
class Navigable : public JS::Cell {
49
    JS_CELL(Navigable, JS::Cell);
50
    JS_DECLARE_ALLOCATOR(Navigable);
51
52
public:
53
    virtual ~Navigable() override;
54
55
    using NullWithError = StringView;
56
    using NavigationParamsVariant = Variant<Empty, NullWithError, JS::NonnullGCPtr<NavigationParams>, JS::NonnullGCPtr<NonFetchSchemeNavigationParams>>;
57
58
    ErrorOr<void> initialize_navigable(JS::NonnullGCPtr<DocumentState> document_state, JS::GCPtr<Navigable> parent);
59
60
    void register_navigation_observer(Badge<NavigationObserver>, NavigationObserver&);
61
    void unregister_navigation_observer(Badge<NavigationObserver>, NavigationObserver&);
62
63
    Vector<JS::Handle<Navigable>> child_navigables() const;
64
65
    bool is_traversable() const;
66
67
0
    String const& id() const { return m_id; }
68
0
    JS::GCPtr<Navigable> parent() const { return m_parent; }
69
    bool is_ancestor_of(JS::NonnullGCPtr<Navigable>) const;
70
71
0
    bool is_closing() const { return m_closing; }
72
0
    void set_closing(bool value) { m_closing = value; }
73
74
    void set_delaying_load_events(bool value);
75
0
    bool is_delaying_load_events() const { return m_delaying_the_load_event.has_value(); }
76
77
0
    JS::GCPtr<SessionHistoryEntry> active_session_history_entry() const { return m_active_session_history_entry; }
78
0
    void set_active_session_history_entry(JS::GCPtr<SessionHistoryEntry> entry) { m_active_session_history_entry = entry; }
79
0
    JS::GCPtr<SessionHistoryEntry> current_session_history_entry() const { return m_current_session_history_entry; }
80
0
    void set_current_session_history_entry(JS::GCPtr<SessionHistoryEntry> entry) { m_current_session_history_entry = entry; }
81
82
    Vector<JS::NonnullGCPtr<SessionHistoryEntry>>& get_session_history_entries() const;
83
84
    void activate_history_entry(JS::GCPtr<SessionHistoryEntry>);
85
86
    JS::GCPtr<DOM::Document> active_document();
87
    JS::GCPtr<BrowsingContext> active_browsing_context();
88
    JS::GCPtr<WindowProxy> active_window_proxy();
89
    JS::GCPtr<Window> active_window();
90
91
    JS::GCPtr<SessionHistoryEntry> get_the_target_history_entry(int target_step) const;
92
93
    String target_name() const;
94
95
    JS::GCPtr<NavigableContainer> container() const;
96
    JS::GCPtr<DOM::Document> container_document() const;
97
98
    JS::GCPtr<TraversableNavigable> traversable_navigable() const;
99
    JS::GCPtr<TraversableNavigable> top_level_traversable();
100
101
0
    virtual bool is_top_level_traversable() const { return false; }
102
103
    [[nodiscard]] bool is_focused() const;
104
105
    enum class WindowType {
106
        ExistingOrNone,
107
        NewAndUnrestricted,
108
        NewWithNoOpener,
109
    };
110
111
    struct ChosenNavigable {
112
        JS::GCPtr<Navigable> navigable;
113
        WindowType window_type;
114
    };
115
116
    ChosenNavigable choose_a_navigable(StringView name, TokenizedFeature::NoOpener no_opener, ActivateTab = ActivateTab::Yes, Optional<TokenizedFeature::Map const&> window_features = {});
117
118
    static JS::GCPtr<Navigable> navigable_with_active_document(JS::NonnullGCPtr<DOM::Document>);
119
120
    enum class Traversal {
121
        Tag
122
    };
123
124
0
    Variant<Empty, Traversal, String> ongoing_navigation() const { return m_ongoing_navigation; }
125
    void set_ongoing_navigation(Variant<Empty, Traversal, String> ongoing_navigation);
126
127
    WebIDL::ExceptionOr<void> populate_session_history_entry_document(
128
        JS::GCPtr<SessionHistoryEntry> entry,
129
        SourceSnapshotParams const& source_snapshot_params,
130
        TargetSnapshotParams const& target_snapshot_params,
131
        Optional<String> navigation_id = {},
132
        NavigationParamsVariant navigation_params = Empty {},
133
        CSPNavigationType csp_navigation_type = CSPNavigationType::Other,
134
        bool allow_POST = false,
135
        JS::GCPtr<JS::HeapFunction<void()>> completion_steps = {});
136
137
    struct NavigateParams {
138
        URL::URL const& url;
139
        JS::NonnullGCPtr<DOM::Document> source_document;
140
        Variant<Empty, String, POSTResource> document_resource = Empty {};
141
        JS::GCPtr<Fetch::Infrastructure::Response> response = nullptr;
142
        bool exceptions_enabled = false;
143
        Bindings::NavigationHistoryBehavior history_handling = Bindings::NavigationHistoryBehavior::Auto;
144
        Optional<SerializationRecord> navigation_api_state = {};
145
        Optional<Vector<XHR::FormDataEntry>&> form_data_entry_list = {};
146
        ReferrerPolicy::ReferrerPolicy referrer_policy = ReferrerPolicy::ReferrerPolicy::EmptyString;
147
        UserNavigationInvolvement user_involvement = UserNavigationInvolvement::None;
148
    };
149
150
    WebIDL::ExceptionOr<void> navigate(NavigateParams);
151
152
    WebIDL::ExceptionOr<void> navigate_to_a_fragment(URL::URL const&, HistoryHandlingBehavior, UserNavigationInvolvement, Optional<SerializationRecord> navigation_api_state, String navigation_id);
153
154
    WebIDL::ExceptionOr<JS::GCPtr<DOM::Document>> evaluate_javascript_url(URL::URL const&, URL::Origin const& new_document_origin, String navigation_id);
155
    WebIDL::ExceptionOr<void> navigate_to_a_javascript_url(URL::URL const&, HistoryHandlingBehavior, URL::Origin const& initiator_origin, CSPNavigationType csp_navigation_type, String navigation_id);
156
157
    bool allowed_by_sandboxing_to_navigate(Navigable const& target, SourceSnapshotParams const&);
158
159
    void reload();
160
161
    // https://github.com/whatwg/html/issues/9690
162
0
    [[nodiscard]] bool has_been_destroyed() const { return m_has_been_destroyed; }
163
0
    void set_has_been_destroyed() { m_has_been_destroyed = true; }
164
165
    CSSPixelPoint to_top_level_position(CSSPixelPoint);
166
    CSSPixelRect to_top_level_rect(CSSPixelRect const&);
167
168
0
    CSSPixelSize size() const { return m_size; }
169
170
0
    CSSPixelPoint viewport_scroll_offset() const { return m_viewport_scroll_offset; }
171
0
    CSSPixelRect viewport_rect() const { return { m_viewport_scroll_offset, m_size }; }
172
    void set_viewport_size(CSSPixelSize);
173
    void perform_scroll_of_viewport(CSSPixelPoint position);
174
175
    void set_needs_display();
176
    void set_needs_display(CSSPixelRect const&);
177
178
0
    void set_is_popup(TokenizedFeature::Popup is_popup) { m_is_popup = is_popup; }
179
180
    // https://html.spec.whatwg.org/#rendering-opportunity
181
    [[nodiscard]] bool has_a_rendering_opportunity() const;
182
183
    [[nodiscard]] TargetSnapshotParams snapshot_target_snapshot_params();
184
185
0
    [[nodiscard]] bool needs_repaint() const { return m_needs_repaint; }
186
187
    struct PaintConfig {
188
        bool paint_overlay { false };
189
        bool should_show_line_box_borders { false };
190
        bool has_focus { false };
191
    };
192
    void record_display_list(Painting::DisplayListRecorder& display_list_recorder, PaintConfig);
193
194
0
    Page& page() { return m_page; }
195
0
    Page const& page() const { return m_page; }
196
197
    String selected_text() const;
198
    void select_all();
199
    void paste(String const&);
200
201
0
    Web::EventHandler& event_handler() { return m_event_handler; }
202
0
    Web::EventHandler const& event_handler() const { return m_event_handler; }
203
204
protected:
205
    explicit Navigable(JS::NonnullGCPtr<Page>);
206
207
    virtual void visit_edges(Cell::Visitor&) override;
208
209
    // https://html.spec.whatwg.org/multipage/browsing-the-web.html#ongoing-navigation
210
    Variant<Empty, Traversal, String> m_ongoing_navigation;
211
212
    // https://html.spec.whatwg.org/multipage/browsers.html#is-popup
213
    TokenizedFeature::Popup m_is_popup { TokenizedFeature::Popup::No };
214
215
private:
216
    void reset_cursor_blink_cycle();
217
218
    void scroll_offset_did_change();
219
220
    void inform_the_navigation_api_about_aborting_navigation();
221
222
    // https://html.spec.whatwg.org/multipage/document-sequences.html#nav-id
223
    String m_id;
224
225
    // https://html.spec.whatwg.org/multipage/document-sequences.html#nav-parent
226
    JS::GCPtr<Navigable> m_parent;
227
228
    // https://html.spec.whatwg.org/multipage/document-sequences.html#nav-current-history-entry
229
    JS::GCPtr<SessionHistoryEntry> m_current_session_history_entry;
230
231
    // https://html.spec.whatwg.org/multipage/document-sequences.html#nav-active-history-entry
232
    JS::GCPtr<SessionHistoryEntry> m_active_session_history_entry;
233
234
    // https://html.spec.whatwg.org/multipage/document-sequences.html#is-closing
235
    bool m_closing { false };
236
237
    // https://html.spec.whatwg.org/multipage/document-sequences.html#delaying-load-events-mode
238
    Optional<DOM::DocumentLoadEventDelayer> m_delaying_the_load_event;
239
240
    // Implied link between navigable and its container.
241
    JS::GCPtr<NavigableContainer> m_container;
242
243
    JS::NonnullGCPtr<Page> m_page;
244
245
    HashTable<JS::NonnullGCPtr<NavigationObserver>> m_navigation_observers;
246
247
    bool m_has_been_destroyed { false };
248
249
    CSSPixelSize m_size;
250
    CSSPixelPoint m_viewport_scroll_offset;
251
252
    bool m_needs_repaint { false };
253
254
    Web::EventHandler m_event_handler;
255
};
256
257
HashTable<Navigable*>& all_navigables();
258
259
bool navigation_must_be_a_replace(URL::URL const& url, DOM::Document const& document);
260
void finalize_a_cross_document_navigation(JS::NonnullGCPtr<Navigable>, HistoryHandlingBehavior, JS::NonnullGCPtr<SessionHistoryEntry>);
261
void perform_url_and_history_update_steps(DOM::Document& document, URL::URL new_url, Optional<SerializationRecord> = {}, HistoryHandlingBehavior history_handling = HistoryHandlingBehavior::Replace);
262
UserNavigationInvolvement user_navigation_involvement(DOM::Event const&);
263
264
}