/* * 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 #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 { GC_CELL(Navigable, JS::Cell); GC_DECLARE_ALLOCATOR(Navigable); public: virtual ~Navigable() override; using NullWithError = StringView; using NavigationParamsVariant = Variant, GC::Ref>; ErrorOr initialize_navigable(GC::Ref document_state, GC::Ptr parent); void register_navigation_observer(Badge, NavigationObserver&); void unregister_navigation_observer(Badge, NavigationObserver&); Vector> child_navigables() const; bool is_traversable() const; String const& id() const { return m_id; } GC::Ptr parent() const { return m_parent; } bool is_ancestor_of(GC::Ref) const; bool is_closing() const { return m_closing; } void set_closing(bool value) { m_closing = value; } bool is_script_closable(); void set_delaying_load_events(bool value); bool is_delaying_load_events() const { return m_delaying_the_load_event.has_value(); } GC::Ptr active_session_history_entry() const { return m_active_session_history_entry; } void set_active_session_history_entry(GC::Ptr entry) { m_active_session_history_entry = entry; } GC::Ptr current_session_history_entry() const { return m_current_session_history_entry; } void set_current_session_history_entry(GC::Ptr entry) { m_current_session_history_entry = entry; } Vector>& get_session_history_entries() const; void activate_history_entry(GC::Ptr); GC::Ptr active_document(); GC::Ptr active_browsing_context(); GC::Ptr active_window_proxy(); GC::Ptr active_window(); GC::Ptr get_the_target_history_entry(int target_step) const; String target_name() const; GC::Ptr container() const; GC::Ptr container_document() const; GC::Ptr traversable_navigable() const; GC::Ptr top_level_traversable(); virtual bool is_top_level_traversable() const { return false; } [[nodiscard]] bool is_focused() const; enum class WindowType { ExistingOrNone, NewAndUnrestricted, NewWithNoOpener, }; struct ChosenNavigable { GC::Ptr navigable; WindowType window_type; }; ChosenNavigable choose_a_navigable(StringView name, TokenizedFeature::NoOpener no_opener, ActivateTab = ActivateTab::Yes, Optional window_features = {}); static GC::Ptr navigable_with_active_document(GC::Ref); 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( GC::Ptr entry, SourceSnapshotParams const& source_snapshot_params, TargetSnapshotParams const& target_snapshot_params, Optional navigation_id = {}, NavigationParamsVariant navigation_params = Empty {}, CSPNavigationType csp_navigation_type = CSPNavigationType::Other, bool allow_POST = false, GC::Ptr> completion_steps = {}); struct NavigateParams { URL::URL const& url; GC::Ref source_document; Variant document_resource = Empty {}; GC::Ptr 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(URL::URL const&, HistoryHandlingBehavior, UserNavigationInvolvement, Optional navigation_api_state, String navigation_id); WebIDL::ExceptionOr> evaluate_javascript_url(URL::URL const&, URL::Origin const& new_document_origin, String navigation_id); WebIDL::ExceptionOr navigate_to_a_javascript_url(URL::URL const&, HistoryHandlingBehavior, URL::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; } CSSPixelPoint viewport_scroll_offset() const { return m_viewport_scroll_offset; } CSSPixelRect viewport_rect() const { return { m_viewport_scroll_offset, m_size }; } void set_viewport_size(CSSPixelSize); void perform_scroll_of_viewport(CSSPixelPoint position); void set_needs_display(InvalidateDisplayList = InvalidateDisplayList::Yes); 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(); Page& page() { return m_page; } Page const& page() const { return m_page; } String selected_text() const; void select_all(); void paste(String const&); Web::EventHandler& event_handler() { return m_event_handler; } Web::EventHandler const& event_handler() const { return m_event_handler; } protected: explicit Navigable(GC::Ref); 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 reset_cursor_blink_cycle(); 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 GC::Ptr m_parent; // https://html.spec.whatwg.org/multipage/document-sequences.html#nav-current-history-entry GC::Ptr m_current_session_history_entry; // https://html.spec.whatwg.org/multipage/document-sequences.html#nav-active-history-entry GC::Ptr 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. GC::Ptr m_container; GC::Ref m_page; HashTable> m_navigation_observers; bool m_has_been_destroyed { false }; CSSPixelSize m_size; CSSPixelPoint m_viewport_scroll_offset; Web::EventHandler m_event_handler; }; HashTable& all_navigables(); bool navigation_must_be_a_replace(URL::URL const& url, DOM::Document const& document); void finalize_a_cross_document_navigation(GC::Ref, HistoryHandlingBehavior, GC::Ref); void perform_url_and_history_update_steps(DOM::Document& document, URL::URL new_url, Optional = {}, HistoryHandlingBehavior history_handling = HistoryHandlingBehavior::Replace); UserNavigationInvolvement user_navigation_involvement(DOM::Event const&); }