/src/serenity/Userland/Libraries/LibWeb/HTML/TraversableNavigable.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2022, Andreas Kling <kling@serenityos.org> |
3 | | * |
4 | | * SPDX-License-Identifier: BSD-2-Clause |
5 | | */ |
6 | | |
7 | | #pragma once |
8 | | |
9 | | #include <AK/Vector.h> |
10 | | #include <LibWeb/HTML/Navigable.h> |
11 | | #include <LibWeb/HTML/NavigationType.h> |
12 | | #include <LibWeb/HTML/SessionHistoryTraversalQueue.h> |
13 | | #include <LibWeb/HTML/VisibilityState.h> |
14 | | #include <LibWeb/Page/Page.h> |
15 | | |
16 | | namespace Web::HTML { |
17 | | |
18 | | // https://html.spec.whatwg.org/multipage/document-sequences.html#traversable-navigable |
19 | | class TraversableNavigable final : public Navigable { |
20 | | JS_CELL(TraversableNavigable, Navigable); |
21 | | JS_DECLARE_ALLOCATOR(TraversableNavigable); |
22 | | |
23 | | public: |
24 | | static WebIDL::ExceptionOr<JS::NonnullGCPtr<TraversableNavigable>> create_a_new_top_level_traversable(JS::NonnullGCPtr<Page>, JS::GCPtr<BrowsingContext> opener, String target_name); |
25 | | static WebIDL::ExceptionOr<JS::NonnullGCPtr<TraversableNavigable>> create_a_fresh_top_level_traversable(JS::NonnullGCPtr<Page>, URL::URL const& initial_navigation_url, Variant<Empty, String, POSTResource> = Empty {}); |
26 | | |
27 | | virtual ~TraversableNavigable() override; |
28 | | |
29 | | virtual bool is_top_level_traversable() const override; |
30 | | |
31 | 0 | int current_session_history_step() const { return m_current_session_history_step; } |
32 | 0 | Vector<JS::NonnullGCPtr<SessionHistoryEntry>>& session_history_entries() { return m_session_history_entries; } |
33 | 0 | Vector<JS::NonnullGCPtr<SessionHistoryEntry>> const& session_history_entries() const { return m_session_history_entries; } |
34 | 0 | bool running_nested_apply_history_step() const { return m_running_nested_apply_history_step; } |
35 | | |
36 | 0 | VisibilityState system_visibility_state() const { return m_system_visibility_state; } |
37 | | void set_system_visibility_state(VisibilityState); |
38 | | |
39 | | struct HistoryObjectLengthAndIndex { |
40 | | u64 script_history_length; |
41 | | u64 script_history_index; |
42 | | }; |
43 | | HistoryObjectLengthAndIndex get_the_history_object_length_and_index(int) const; |
44 | | |
45 | | enum class HistoryStepResult { |
46 | | InitiatorDisallowed, |
47 | | CanceledByBeforeUnload, |
48 | | CanceledByNavigate, |
49 | | Applied, |
50 | | }; |
51 | | |
52 | | HistoryStepResult apply_the_traverse_history_step(int, Optional<SourceSnapshotParams>, JS::GCPtr<Navigable>, UserNavigationInvolvement); |
53 | | HistoryStepResult apply_the_reload_history_step(); |
54 | | enum class SynchronousNavigation : bool { |
55 | | Yes, |
56 | | No, |
57 | | }; |
58 | | HistoryStepResult apply_the_push_or_replace_history_step(int step, HistoryHandlingBehavior history_handling, SynchronousNavigation); |
59 | | HistoryStepResult update_for_navigable_creation_or_destruction(); |
60 | | |
61 | | int get_the_used_step(int step) const; |
62 | | Vector<JS::Handle<Navigable>> get_all_navigables_whose_current_session_history_entry_will_change_or_reload(int) const; |
63 | | Vector<JS::Handle<Navigable>> get_all_navigables_that_only_need_history_object_length_index_update(int) const; |
64 | | Vector<JS::Handle<Navigable>> get_all_navigables_that_might_experience_a_cross_document_traversal(int) const; |
65 | | |
66 | | Vector<int> get_all_used_history_steps() const; |
67 | | void clear_the_forward_session_history(); |
68 | | void traverse_the_history_by_delta(int delta, Optional<DOM::Document&> source_document = {}); |
69 | | |
70 | | void close_top_level_traversable(); |
71 | | void destroy_top_level_traversable(); |
72 | | |
73 | | void append_session_history_traversal_steps(JS::NonnullGCPtr<JS::HeapFunction<void()>> steps) |
74 | 0 | { |
75 | 0 | m_session_history_traversal_queue->append(steps); |
76 | 0 | } |
77 | | |
78 | | void append_session_history_synchronous_navigation_steps(JS::NonnullGCPtr<Navigable> target_navigable, JS::NonnullGCPtr<JS::HeapFunction<void()>> steps) |
79 | 0 | { |
80 | 0 | m_session_history_traversal_queue->append_sync(steps, target_navigable); |
81 | 0 | } |
82 | | |
83 | 0 | String window_handle() const { return m_window_handle; } |
84 | 0 | void set_window_handle(String window_handle) { m_window_handle = move(window_handle); } |
85 | | |
86 | | [[nodiscard]] JS::GCPtr<DOM::Node> currently_focused_area(); |
87 | | |
88 | | void paint(Web::DevicePixelRect const&, Gfx::Bitmap&, Web::PaintOptions); |
89 | | |
90 | | enum class CheckIfUnloadingIsCanceledResult { |
91 | | CanceledByBeforeUnload, |
92 | | CanceledByNavigate, |
93 | | Continue, |
94 | | }; |
95 | | CheckIfUnloadingIsCanceledResult check_if_unloading_is_canceled(Vector<JS::Handle<Navigable>> navigables_that_need_before_unload); |
96 | | |
97 | | private: |
98 | | TraversableNavigable(JS::NonnullGCPtr<Page>); |
99 | | |
100 | | virtual void visit_edges(Cell::Visitor&) override; |
101 | | |
102 | | // FIXME: Fix spec typo cancelation --> cancellation |
103 | | HistoryStepResult apply_the_history_step( |
104 | | int step, |
105 | | bool check_for_cancelation, |
106 | | Optional<SourceSnapshotParams>, |
107 | | JS::GCPtr<Navigable> initiator_to_check, |
108 | | Optional<UserNavigationInvolvement> user_involvement_for_navigate_events, |
109 | | Optional<Bindings::NavigationType> navigation_type, |
110 | | SynchronousNavigation); |
111 | | |
112 | | CheckIfUnloadingIsCanceledResult check_if_unloading_is_canceled(Vector<JS::Handle<Navigable>> navigables_that_need_before_unload, JS::GCPtr<TraversableNavigable> traversable, Optional<int> target_step, Optional<UserNavigationInvolvement> user_involvement_for_navigate_events); |
113 | | |
114 | | Vector<JS::NonnullGCPtr<SessionHistoryEntry>> get_session_history_entries_for_the_navigation_api(JS::NonnullGCPtr<Navigable>, int); |
115 | | |
116 | | [[nodiscard]] bool can_go_forward() const; |
117 | | |
118 | | // https://html.spec.whatwg.org/multipage/document-sequences.html#tn-current-session-history-step |
119 | | int m_current_session_history_step { 0 }; |
120 | | |
121 | | // https://html.spec.whatwg.org/multipage/document-sequences.html#tn-session-history-entries |
122 | | Vector<JS::NonnullGCPtr<SessionHistoryEntry>> m_session_history_entries; |
123 | | |
124 | | // FIXME: https://html.spec.whatwg.org/multipage/document-sequences.html#tn-session-history-traversal-queue |
125 | | |
126 | | // https://html.spec.whatwg.org/multipage/document-sequences.html#tn-running-nested-apply-history-step |
127 | | bool m_running_nested_apply_history_step { false }; |
128 | | |
129 | | // https://html.spec.whatwg.org/multipage/document-sequences.html#system-visibility-state |
130 | | VisibilityState m_system_visibility_state { VisibilityState::Visible }; |
131 | | |
132 | | JS::NonnullGCPtr<SessionHistoryTraversalQueue> m_session_history_traversal_queue; |
133 | | |
134 | | String m_window_handle; |
135 | | }; |
136 | | |
137 | | struct BrowsingContextAndDocument { |
138 | | JS::NonnullGCPtr<HTML::BrowsingContext> browsing_context; |
139 | | JS::NonnullGCPtr<DOM::Document> document; |
140 | | }; |
141 | | |
142 | | WebIDL::ExceptionOr<BrowsingContextAndDocument> create_a_new_top_level_browsing_context_and_document(JS::NonnullGCPtr<Page> page); |
143 | | void finalize_a_same_document_navigation(JS::NonnullGCPtr<TraversableNavigable> traversable, JS::NonnullGCPtr<Navigable> target_navigable, JS::NonnullGCPtr<SessionHistoryEntry> target_entry, JS::GCPtr<SessionHistoryEntry> entry_to_replace, HistoryHandlingBehavior); |
144 | | |
145 | | } |