/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 | | } |