diff --git a/Libraries/LibWeb/CMakeLists.txt b/Libraries/LibWeb/CMakeLists.txt index d38c2f793f..ecc57417e5 100644 --- a/Libraries/LibWeb/CMakeLists.txt +++ b/Libraries/LibWeb/CMakeLists.txt @@ -656,6 +656,7 @@ set(SOURCES HTML/Plugin.cpp HTML/PluginArray.cpp HTML/PolicyContainers.cpp + HTML/POSTResource.cpp HTML/PopoverTargetAttributes.cpp HTML/PopStateEvent.cpp HTML/PotentialCORSRequest.cpp diff --git a/Libraries/LibWeb/HTML/POSTResource.cpp b/Libraries/LibWeb/HTML/POSTResource.cpp new file mode 100644 index 0000000000..0e6bee13c6 --- /dev/null +++ b/Libraries/LibWeb/HTML/POSTResource.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2026-present, the Ladybird developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include + +namespace IPC { + +template<> +ErrorOr encode(Encoder& encoder, Web::HTML::POSTResource::Directive const& directive) +{ + TRY(encoder.encode(directive.type)); + TRY(encoder.encode(directive.value)); + return {}; +} + +template<> +ErrorOr decode(Decoder& decoder) +{ + return Web::HTML::POSTResource::Directive { + .type = TRY(decoder.decode()), + .value = TRY(decoder.decode()), + }; +} + +template<> +ErrorOr encode(Encoder& encoder, Web::HTML::POSTResource const& post_resource) +{ + TRY(encoder.encode(post_resource.request_body)); + TRY(encoder.encode(post_resource.request_content_type)); + TRY(encoder.encode(post_resource.request_content_type_directives)); + return {}; +} + +template<> +ErrorOr decode(Decoder& decoder) +{ + return Web::HTML::POSTResource { + .request_body = TRY(decoder.decode>()), + .request_content_type = TRY(decoder.decode()), + .request_content_type_directives = TRY(decoder.decode>()), + }; +} + +} diff --git a/Libraries/LibWeb/HTML/POSTResource.h b/Libraries/LibWeb/HTML/POSTResource.h index 059c8b67f6..5ea4b1cd43 100644 --- a/Libraries/LibWeb/HTML/POSTResource.h +++ b/Libraries/LibWeb/HTML/POSTResource.h @@ -8,8 +8,9 @@ #include #include -#include #include +#include +#include namespace Web::HTML { @@ -31,10 +32,30 @@ struct POSTResource { RequestContentType request_content_type {}; struct Directive { - StringView type; + String type; String value; + + bool operator==(Directive const&) const = default; }; Vector request_content_type_directives {}; + + bool operator==(POSTResource const&) const = default; }; } + +namespace IPC { + +template<> +WEB_API ErrorOr encode(Encoder&, Web::HTML::POSTResource::Directive const&); + +template<> +WEB_API ErrorOr decode(Decoder&); + +template<> +WEB_API ErrorOr encode(Encoder&, Web::HTML::POSTResource const&); + +template<> +WEB_API ErrorOr decode(Decoder&); + +} diff --git a/Libraries/LibWeb/HTML/SessionHistoryEntry.cpp b/Libraries/LibWeb/HTML/SessionHistoryEntry.cpp index 4698cdbd82..dc37d608dd 100644 --- a/Libraries/LibWeb/HTML/SessionHistoryEntry.cpp +++ b/Libraries/LibWeb/HTML/SessionHistoryEntry.cpp @@ -4,6 +4,8 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include +#include #include #include #include @@ -31,3 +33,127 @@ SessionHistoryEntry::SessionHistoryEntry() } } + +template<> +ErrorOr IPC::encode(Encoder& encoder, Web::HTML::SessionHistoryEntryDescriptor const& entry) +{ + TRY(encoder.encode(entry.step)); + TRY(encoder.encode(entry.url)); + TRY(encoder.encode(entry.document_state)); + TRY(encoder.encode(entry.classic_history_api_state)); + TRY(encoder.encode(entry.navigation_api_state)); + TRY(encoder.encode(entry.navigation_api_key)); + TRY(encoder.encode(entry.navigation_api_id)); + TRY(encoder.encode(entry.scroll_restoration_mode)); + TRY(encoder.encode(entry.scroll_position_data)); + return {}; +} + +template<> +ErrorOr IPC::decode(Decoder& decoder) +{ + auto step = TRY(decoder.decode()); + auto url = TRY(decoder.decode()); + auto document_state = TRY(decoder.decode()); + auto classic_history_api_state = TRY(decoder.decode()); + auto navigation_api_state = TRY(decoder.decode()); + auto navigation_api_key = TRY(decoder.decode()); + auto navigation_api_id = TRY(decoder.decode()); + auto scroll_restoration_mode = TRY(decoder.decode()); + auto scroll_position_data = TRY(decoder.decode()); + + return Web::HTML::SessionHistoryEntryDescriptor { + .step = step, + .url = move(url), + .document_state = move(document_state), + .classic_history_api_state = move(classic_history_api_state), + .navigation_api_state = move(navigation_api_state), + .navigation_api_key = move(navigation_api_key), + .navigation_api_id = move(navigation_api_id), + .scroll_restoration_mode = scroll_restoration_mode, + .scroll_position_data = move(scroll_position_data), + }; +} + +template<> +ErrorOr IPC::encode(Encoder& encoder, Web::HTML::SessionHistoryEntryScrollPositionData const& scroll_position_data) +{ + TRY(encoder.encode(scroll_position_data.viewport_scroll_position)); + return {}; +} + +template<> +ErrorOr IPC::decode(Decoder& decoder) +{ + auto viewport_scroll_position = TRY(decoder.decode>()); + return Web::HTML::SessionHistoryEntryScrollPositionData { + .viewport_scroll_position = move(viewport_scroll_position), + }; +} + +template<> +ErrorOr IPC::encode(Encoder& encoder, Web::HTML::SessionHistoryDocumentStateDescriptor const& document_state) +{ + TRY(encoder.encode(document_state.id)); + TRY(encoder.encode(document_state.history_policy_container)); + TRY(encoder.encode(document_state.request_referrer)); + TRY(encoder.encode(document_state.request_referrer_policy)); + TRY(encoder.encode(document_state.initiator_origin)); + TRY(encoder.encode(document_state.origin)); + TRY(encoder.encode(document_state.about_base_url)); + TRY(encoder.encode(document_state.resource)); + TRY(encoder.encode(document_state.reload_pending)); + TRY(encoder.encode(document_state.ever_populated)); + TRY(encoder.encode(document_state.navigable_target_name)); + TRY(encoder.encode(document_state.nested_histories)); + return {}; +} + +template<> +ErrorOr IPC::decode(Decoder& decoder) +{ + auto id = TRY(decoder.decode()); + auto history_policy_container = TRY(decoder.decode>()); + auto request_referrer = TRY(decoder.decode()); + auto request_referrer_policy = TRY(decoder.decode()); + auto initiator_origin = TRY(decoder.decode>()); + auto origin = TRY(decoder.decode>()); + auto about_base_url = TRY(decoder.decode>()); + auto resource = TRY(decoder.decode>()); + auto reload_pending = TRY(decoder.decode()); + auto ever_populated = TRY(decoder.decode()); + auto navigable_target_name = TRY(decoder.decode()); + auto nested_histories = TRY(decoder.decode>()); + + return Web::HTML::SessionHistoryDocumentStateDescriptor { + .id = id, + .history_policy_container = move(history_policy_container), + .request_referrer = move(request_referrer), + .request_referrer_policy = request_referrer_policy, + .initiator_origin = move(initiator_origin), + .origin = move(origin), + .about_base_url = move(about_base_url), + .resource = move(resource), + .reload_pending = reload_pending, + .ever_populated = ever_populated, + .navigable_target_name = move(navigable_target_name), + .nested_histories = move(nested_histories), + }; +} + +template<> +ErrorOr IPC::encode(Encoder& encoder, Web::HTML::SessionHistoryNestedHistoryDescriptor const& nested_history) +{ + TRY(encoder.encode(nested_history.id)); + TRY(encoder.encode(nested_history.entries)); + return {}; +} + +template<> +ErrorOr IPC::decode(Decoder& decoder) +{ + auto id = TRY(decoder.decode()); + auto entries = TRY(decoder.decode>()); + + return Web::HTML::SessionHistoryNestedHistoryDescriptor { move(id), move(entries) }; +} diff --git a/Libraries/LibWeb/HTML/SessionHistoryEntry.h b/Libraries/LibWeb/HTML/SessionHistoryEntry.h index 6ed9b5f4bd..85ed387531 100644 --- a/Libraries/LibWeb/HTML/SessionHistoryEntry.h +++ b/Libraries/LibWeb/HTML/SessionHistoryEntry.h @@ -8,9 +8,16 @@ #include #include +#include +#include +#include #include +#include #include +#include #include +#include +#include namespace Web::HTML { @@ -25,6 +32,57 @@ enum class ScrollRestorationMode { Manual, }; +struct SessionHistoryNestedHistoryDescriptor; + +// IPC-friendly descriptors for the parts of session history entries and document states that can survive +// WebContent process swaps. +// +// https://html.spec.whatwg.org/multipage/browsing-the-web.html#session-history-entry +// https://html.spec.whatwg.org/multipage/browsing-the-web.html#document-state +struct SessionHistoryDocumentStateDescriptor { + // AD-HOC: The spec models shared document state by object identity. The UI-process mirror uses a stable + // descriptor ID so entries that share a document state can be reconstructed after IPC. + u64 id { 0 }; + Variant history_policy_container { DocumentState::Client::Tag }; + Fetch::Infrastructure::Request::ReferrerType request_referrer { Fetch::Infrastructure::Request::Referrer::Client }; + ReferrerPolicy::ReferrerPolicy request_referrer_policy { ReferrerPolicy::DEFAULT_REFERRER_POLICY }; + Optional initiator_origin; + Optional origin; + Optional about_base_url; + Variant resource; + bool reload_pending { false }; + bool ever_populated { false }; + String navigable_target_name; + Vector nested_histories; +}; + +// https://html.spec.whatwg.org/multipage/browsing-the-web.html#she-scroll-position +struct SessionHistoryEntryScrollPositionData { + // FIXME: Track all restorable scrollable regions. Currently only the viewport is persisted. + Optional viewport_scroll_position; + + bool operator==(SessionHistoryEntryScrollPositionData const&) const = default; +}; + +// https://html.spec.whatwg.org/multipage/browsing-the-web.html#session-history-entry +struct SessionHistoryEntryDescriptor { + i32 step { 0 }; + URL::URL url; + SessionHistoryDocumentStateDescriptor document_state; + SerializationRecord classic_history_api_state; + SerializationRecord navigation_api_state; + String navigation_api_key; + String navigation_api_id; + ScrollRestorationMode scroll_restoration_mode { ScrollRestorationMode::Auto }; + SessionHistoryEntryScrollPositionData scroll_position_data; +}; + +// https://html.spec.whatwg.org/multipage/browsing-the-web.html#nested-history +struct SessionHistoryNestedHistoryDescriptor { + String id; + Vector entries; +}; + // https://html.spec.whatwg.org/multipage/history.html#session-history-entry class SessionHistoryEntry final : public RefCounted { public: @@ -61,6 +119,9 @@ public: [[nodiscard]] ScrollRestorationMode scroll_restoration_mode() const { return m_scroll_restoration_mode; } void set_scroll_restoration_mode(ScrollRestorationMode scroll_restoration_mode) { m_scroll_restoration_mode = scroll_restoration_mode; } + [[nodiscard]] SessionHistoryEntryScrollPositionData const& scroll_position_data() const { return m_scroll_position_data; } + void set_scroll_position_data(SessionHistoryEntryScrollPositionData scroll_position_data) { m_scroll_position_data = move(scroll_position_data); } + private: // https://html.spec.whatwg.org/multipage/browsing-the-web.html#she-step // step, a non-negative integer or "pending", initially "pending". @@ -94,7 +155,8 @@ private: ScrollRestorationMode m_scroll_restoration_mode { ScrollRestorationMode::Auto }; // https://html.spec.whatwg.org/multipage/browsing-the-web.html#she-scroll-position - // FIXME: scroll position data, which is scroll position data for the document's restorable scrollable regions + // scroll position data, which is scroll position data for the document's restorable scrollable regions + SessionHistoryEntryScrollPositionData m_scroll_position_data; // https://html.spec.whatwg.org/multipage/browsing-the-web.html#she-other // FIXME: persisted user state, which is implementation-defined, initially null @@ -102,3 +164,31 @@ private: }; } + +namespace IPC { + +template<> +WEB_API ErrorOr encode(Encoder&, Web::HTML::SessionHistoryEntryDescriptor const&); + +template<> +WEB_API ErrorOr decode(Decoder&); + +template<> +WEB_API ErrorOr encode(Encoder&, Web::HTML::SessionHistoryEntryScrollPositionData const&); + +template<> +WEB_API ErrorOr decode(Decoder&); + +template<> +WEB_API ErrorOr encode(Encoder&, Web::HTML::SessionHistoryDocumentStateDescriptor const&); + +template<> +WEB_API ErrorOr decode(Decoder&); + +template<> +WEB_API ErrorOr encode(Encoder&, Web::HTML::SessionHistoryNestedHistoryDescriptor const&); + +template<> +WEB_API ErrorOr decode(Decoder&); + +} diff --git a/Libraries/LibWeb/PixelUnits.cpp b/Libraries/LibWeb/PixelUnits.cpp index 77d25c22d5..3893a776b6 100644 --- a/Libraries/LibWeb/PixelUnits.cpp +++ b/Libraries/LibWeb/PixelUnits.cpp @@ -15,6 +15,22 @@ namespace Web { namespace IPC { +template<> +ErrorOr encode(Encoder& encoder, Web::CSSPixelPoint const& value) +{ + TRY(encoder.encode(value.x().raw_value())); + TRY(encoder.encode(value.y().raw_value())); + return {}; +} + +template<> +ErrorOr decode(Decoder& decoder) +{ + auto x = TRY(decoder.decode()); + auto y = TRY(decoder.decode()); + return Web::CSSPixelPoint { Web::CSSPixels::from_raw(x), Web::CSSPixels::from_raw(y) }; +} + template<> ErrorOr encode(Encoder& encoder, Web::DevicePixelPoint const& value) { diff --git a/Libraries/LibWeb/PixelUnits.h b/Libraries/LibWeb/PixelUnits.h index dee398288e..d0e90e15c4 100644 --- a/Libraries/LibWeb/PixelUnits.h +++ b/Libraries/LibWeb/PixelUnits.h @@ -536,6 +536,11 @@ struct Formatter : Formatter { namespace IPC { +template<> +WEB_API ErrorOr encode(Encoder& encoder, Web::CSSPixelPoint const& value); +template<> +WEB_API ErrorOr decode(Decoder& decoder); + template<> WEB_API ErrorOr encode(Encoder& encoder, Web::DevicePixelPoint const& value); template<>