/* * Copyright (c) 2026-present, the Ladybird developers. * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include namespace WebView { // AD-HOC: The HTML Standard stores a traversable navigable's session history entries on the traversable. Ladybird // keeps an IPC-serializable mirror in the UI process so browser history survives WebContent process swaps // and crash recovery. The mirror still uses the spec's session history entry and all used history steps model. // // https://html.spec.whatwg.org/multipage/document-sequences.html#tn-session-history-entries // https://html.spec.whatwg.org/multipage/browsing-the-web.html#getting-all-used-history-steps class WEBVIEW_API TraversableSessionHistory { public: using Entry = Web::HTML::SessionHistoryEntryDescriptor; struct TraversalTarget { size_t target_step_index { 0 }; i32 target_step { 0 }; Entry const* target_top_level_entry { nullptr }; bool target_step_is_top_level_entry { false }; bool changes_top_level_entry { false }; }; enum class UpdateResult { // WebContent sent the same complete top-level traversable session // history that the UI process stores authoritatively. CompleteSnapshot, // WebContent sent a valid partial view of session history. The UI // process merged it into the authoritative history mirror, but // WebContent cannot be assumed to know or use every UI history step. MergedPartialSnapshot, // WebContent sent a snapshot that cannot describe the current UI-owned // traversable session history. InvalidSnapshot, }; bool is_empty() const { return m_entries.is_empty(); } size_t size() const { return m_entries.size(); } size_t used_step_count() const { return m_used_steps.size(); } Optional current_used_step_index() const { return m_current_used_step_index; } Optional current_top_level_entry_index() const; void clear(); void navigate(URL::URL); void navigate(URL::URL, Variant); void replace_current_entry_url(URL::URL); void replace_current_entry(URL::URL, Variant); void mark_current_entry_reload_pending(); void clear_current_entry_reload_pending(); UpdateResult update_from_web_content(Vector entries, Vector used_steps, size_t current_used_step_index); [[nodiscard]] bool did_seed_web_content_from_ui_process(Vector entries, Vector used_steps, size_t current_used_step_index); void did_seed_web_content_from_ui_process(size_t current_top_level_entry_index); [[nodiscard]] bool did_restore_web_content_to_current_step(i32 step); [[nodiscard]] bool did_apply_web_content_traversal_to_step(i32 step); void forget_web_content_state(); Vector entries() const; Vector used_steps() const; Vector web_content_known_entries() const; Vector web_content_known_used_steps() const; Optional web_content_current_step() const; bool web_content_uses_ui_step_coordinates() const { return m_web_content_uses_ui_step_coordinates; } bool web_content_history_matches_mirror() const; [[nodiscard]] bool can_go_back() const; [[nodiscard]] bool can_go_forward() const; [[nodiscard]] bool has_only_top_level_used_steps() const; [[nodiscard]] bool current_step_is_top_level_entry() const; [[nodiscard]] Optional current_step_to_restore_after_loading_top_level_entry() const; [[nodiscard]] bool web_content_can_traverse_to(TraversalTarget const&) const; [[nodiscard]] Optional traversal_target_for_delta(int delta) const; [[nodiscard]] Optional traversal_target_for_step(i32 step) const; [[nodiscard]] Optional target_step_index_for_delta(int delta) const; [[nodiscard]] Optional step_at(size_t index) const; [[nodiscard]] Entry const* current_entry() const; [[nodiscard]] Entry const* entry_at(size_t index) const; [[nodiscard]] Entry const* entry_for_step(i32 step) const; [[nodiscard]] Entry const* top_level_entry_for_step(i32 step) const; void traverse_to(size_t index); private: // https://html.spec.whatwg.org/multipage/document-sequences.html#tn-session-history-entries Vector m_entries; // https://html.spec.whatwg.org/multipage/browsing-the-web.html#getting-all-used-history-steps Vector m_used_steps; // Index of the current session history step within m_used_steps. // https://html.spec.whatwg.org/multipage/document-sequences.html#tn-current-session-history-step Optional m_current_used_step_index; // WebContent's latest current session history step, translated into the // UI-owned traversable session history's step coordinate space. // https://html.spec.whatwg.org/multipage/document-sequences.html#tn-current-session-history-step Vector m_web_content_known_entries; Vector m_web_content_known_used_steps; Optional m_web_content_current_step; // False when a partial snapshot was translated into the UI-owned step // coordinate space. In that state WebContent still uses its original step // numbers, so the UI must reseed/load instead of delegating traversal by step. bool m_web_content_uses_ui_step_coordinates { false }; }; }