/* * Copyright (c) 2022, Andreas Kling * Copyright (c) 2023, Aliaksandr Kalenik * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Web::HTML { enum class CSPNavigationType { Other, FormSubmission, }; // https://html.spec.whatwg.org/multipage/browsing-the-web.html#user-navigation-involvement enum class UserNavigationInvolvement { BrowserUI, Activation, None, }; // https://html.spec.whatwg.org/multipage/browsing-the-web.html#target-snapshot-params struct TargetSnapshotParams { SandboxingFlagSet sandboxing_flags {}; }; // https://html.spec.whatwg.org/multipage/document-sequences.html#navigable class Navigable : public JS::Cell { JS_CELL(Navigable, JS::Cell); JS_DECLARE_ALLOCATOR(Navigable); public: virtual ~Navigable() override; ErrorOr initialize_navigable(JS::NonnullGCPtr document_state, JS::GCPtr parent); Vector> child_navigables() const; bool is_traversable() const; String const& id() const { return m_id; } JS::GCPtr parent() const { return m_parent; } bool is_closing() const { return m_closing; } void set_closing(bool value) { m_closing = value; } void set_delaying_load_events(bool value); bool is_delaying_load_events() const { return m_delaying_the_load_event.has_value(); } JS::GCPtr active_session_history_entry() const { return m_active_session_history_entry; } void set_active_session_history_entry(JS::GCPtr entry) { m_active_session_history_entry = entry; } JS::GCPtr current_session_history_entry() const { return m_current_session_history_entry; } void set_current_session_history_entry(JS::GCPtr entry) { m_current_session_history_entry = entry; } Vector>& get_session_history_entries() const; void activate_history_entry(JS::GCPtr); JS::GCPtr active_document(); JS::GCPtr active_browsing_context(); JS::GCPtr active_window_proxy(); JS::GCPtr active_window(); JS::GCPtr get_the_target_history_entry(int target_step) const; String target_name() const; JS::GCPtr container() const; JS::GCPtr container_document() const; JS::GCPtr traversable_navigable() const; JS::GCPtr top_level_traversable(); virtual bool is_top_level_traversable() const { return false; } enum class WindowType { ExistingOrNone, NewAndUnrestricted, NewWithNoOpener, }; struct ChosenNavigable { JS::GCPtr navigable; WindowType window_type; }; ChosenNavigable choose_a_navigable(StringView name, TokenizedFeature::NoOpener no_opener, ActivateTab = ActivateTab::Yes); static JS::GCPtr navigable_with_active_document(JS::NonnullGCPtr); enum class Traversal { Tag }; Variant ongoing_navigation() const { return m_ongoing_navigation; } void set_ongoing_navigation(Variant ongoing_navigation); WebIDL::ExceptionOr populate_session_history_entry_document( JS::GCPtr entry, SourceSnapshotParams const& source_snapshot_params, TargetSnapshotParams const& target_snapshot_params, Optional navigation_id = {}, Variant navigation_params = Empty {}, CSPNavigationType csp_navigation_type = CSPNavigationType::Other, bool allow_POST = false, Function completion_steps = [] {}); struct NavigateParams { AK::URL const& url; JS::NonnullGCPtr source_document; Variant document_resource = Empty {}; JS::GCPtr response = nullptr; bool exceptions_enabled = false; Bindings::NavigationHistoryBehavior history_handling = Bindings::NavigationHistoryBehavior::Auto; Optional navigation_api_state = {}; Optional&> form_data_entry_list = {}; ReferrerPolicy::ReferrerPolicy referrer_policy = ReferrerPolicy::ReferrerPolicy::EmptyString; UserNavigationInvolvement user_involvement = UserNavigationInvolvement::None; }; WebIDL::ExceptionOr navigate(NavigateParams); WebIDL::ExceptionOr navigate_to_a_fragment(AK::URL const&, HistoryHandlingBehavior, UserNavigationInvolvement, Optional navigation_api_state, String navigation_id); WebIDL::ExceptionOr> evaluate_javascript_url(AK::URL const&, Origin const& new_document_origin, String navigation_id); WebIDL::ExceptionOr navigate_to_a_javascript_url(AK::URL const&, HistoryHandlingBehavior, Origin const& initiator_origin, CSPNavigationType csp_navigation_type, String navigation_id); bool allowed_by_sandboxing_to_navigate(Navigable const& target, SourceSnapshotParams const&); void reload(); // https://github.com/whatwg/html/issues/9690 [[nodiscard]] bool has_been_destroyed() const { return m_has_been_destroyed; } void set_has_been_destroyed() { m_has_been_destroyed = true; } CSSPixelPoint to_top_level_position(CSSPixelPoint); CSSPixelRect to_top_level_rect(CSSPixelRect const&); CSSPixelSize size() const { return m_size; } void set_size(CSSPixelSize); CSSPixelPoint viewport_scroll_offset() const { return m_viewport_scroll_offset; } CSSPixelRect viewport_rect() const { return { m_viewport_scroll_offset, m_size }; } void set_viewport_rect(CSSPixelRect const&); void set_needs_display(); void set_needs_display(CSSPixelRect const&); void set_is_popup(TokenizedFeature::Popup is_popup) { m_is_popup = is_popup; } // https://html.spec.whatwg.org/#rendering-opportunity [[nodiscard]] bool has_a_rendering_opportunity() const; [[nodiscard]] TargetSnapshotParams snapshot_target_snapshot_params(); struct PaintConfig { bool paint_overlay { false }; bool should_show_line_box_borders { false }; bool has_focus { false }; }; void paint(Painting::RecordingPainter&, PaintConfig); protected: Navigable(); virtual void visit_edges(Cell::Visitor&) override; // https://html.spec.whatwg.org/multipage/browsing-the-web.html#ongoing-navigation Variant m_ongoing_navigation; // https://html.spec.whatwg.org/multipage/browsers.html#is-popup TokenizedFeature::Popup m_is_popup { TokenizedFeature::Popup::No }; private: void scroll_offset_did_change(); void inform_the_navigation_api_about_aborting_navigation(); // https://html.spec.whatwg.org/multipage/document-sequences.html#nav-id String m_id; // https://html.spec.whatwg.org/multipage/document-sequences.html#nav-parent JS::GCPtr m_parent; // https://html.spec.whatwg.org/multipage/document-sequences.html#nav-current-history-entry JS::GCPtr m_current_session_history_entry; // https://html.spec.whatwg.org/multipage/document-sequences.html#nav-active-history-entry JS::GCPtr m_active_session_history_entry; // https://html.spec.whatwg.org/multipage/document-sequences.html#is-closing bool m_closing { false }; // https://html.spec.whatwg.org/multipage/document-sequences.html#delaying-load-events-mode Optional m_delaying_the_load_event; // Implied link between navigable and its container. JS::GCPtr m_container; bool m_has_been_destroyed { false }; CSSPixelSize m_size; CSSPixelPoint m_viewport_scroll_offset; }; HashTable& all_navigables(); bool navigation_must_be_a_replace(AK::URL const& url, DOM::Document const& document); void finalize_a_cross_document_navigation(JS::NonnullGCPtr, HistoryHandlingBehavior, JS::NonnullGCPtr); void perform_url_and_history_update_steps(DOM::Document& document, AK::URL new_url, Optional = {}, HistoryHandlingBehavior history_handling = HistoryHandlingBehavior::Reload); }