LibWeb/HTML: Fire load event for non-string javascript: URLs

Corresponds to 8abe559982

The relevant test doesn't pass, so we're probably missing some other
part of this mechanism:
https://wpt.live/html/semantics/embedded-content/the-embed-element/embed-javascript-url.html
This commit is contained in:
Sam Atkins 2025-05-15 12:28:53 +01:00 committed by Shannon Booth
commit 2efad4c941
Notes: github-actions[bot] 2025-05-15 22:22:15 +00:00
8 changed files with 41 additions and 24 deletions

View file

@ -51,7 +51,7 @@ void HTMLFrameElement::inserted()
// 3. Create a new child navigable for insertedNode.
MUST(create_new_child_navigable(GC::create_function(realm().heap(), [this] {
// 4. Process the frame attributes for insertedNode, with initialInsertion set to true.
process_the_frame_attributes(true);
process_the_frame_attributes(InitialInsertion::Yes);
set_content_navigable_has_session_history_entry_and_ready_for_navigation();
})));
}
@ -91,7 +91,7 @@ void HTMLFrameElement::adjust_computed_style(CSS::ComputedProperties& style)
}
// https://html.spec.whatwg.org/multipage/obsolete.html#process-the-frame-attributes
void HTMLFrameElement::process_the_frame_attributes(bool initial_insertion)
void HTMLFrameElement::process_the_frame_attributes(InitialInsertion initial_insertion)
{
// 1. Let url be the result of running the shared attribute processing steps for iframe and frame elements given
// element and initialInsertion.
@ -102,7 +102,7 @@ void HTMLFrameElement::process_the_frame_attributes(bool initial_insertion)
return;
// 3. If url matches about:blank and initialInsertion is true, then:
if (url_matches_about_blank(*url) && initial_insertion) {
if (url_matches_about_blank(*url) && initial_insertion == InitialInsertion::Yes) {
// 1. Fire an event named load at element.
dispatch_event(DOM::Event::create(realm(), HTML::EventNames::load));
@ -110,8 +110,8 @@ void HTMLFrameElement::process_the_frame_attributes(bool initial_insertion)
return;
}
// 3. Navigate an iframe or frame given element, url, and the empty string.
navigate_an_iframe_or_frame(*url, ReferrerPolicy::ReferrerPolicy::EmptyString);
// 3. Navigate an iframe or frame given element, url, the empty string, and initialInsertion.
navigate_an_iframe_or_frame(*url, ReferrerPolicy::ReferrerPolicy::EmptyString, {}, initial_insertion);
}
}

View file

@ -30,7 +30,7 @@ private:
virtual i32 default_tab_index_value() const override;
virtual void adjust_computed_style(CSS::ComputedProperties&) override;
void process_the_frame_attributes(bool initial_insertion = false);
void process_the_frame_attributes(InitialInsertion = InitialInsertion::No);
};
}

View file

@ -93,7 +93,7 @@ void HTMLIFrameElement::post_connection()
// value and insertedNode's iframe sandboxing flag set.
// 3. Process the iframe attributes for insertedNode, with initialInsertion set to true.
process_the_iframe_attributes(true);
process_the_iframe_attributes(InitialInsertion::Yes);
if (auto navigable = content_navigable()) {
auto traversable = navigable->traversable_navigable();
@ -105,7 +105,7 @@ void HTMLIFrameElement::post_connection()
}
// https://html.spec.whatwg.org/multipage/iframe-embed-object.html#process-the-iframe-attributes
void HTMLIFrameElement::process_the_iframe_attributes(bool initial_insertion)
void HTMLIFrameElement::process_the_iframe_attributes(InitialInsertion initial_insertion)
{
if (!content_navigable())
return;
@ -152,7 +152,7 @@ void HTMLIFrameElement::process_the_iframe_attributes(bool initial_insertion)
}
// 3. If url matches about:blank and initialInsertion is true, then:
if (url_matches_about_blank(*url) && initial_insertion) {
if (url_matches_about_blank(*url) && initial_insertion == InitialInsertion::Yes) {
// 1. Run the iframe load event steps given element.
run_iframe_load_event_steps(*this);

View file

@ -55,7 +55,7 @@ private:
virtual bool supports_dimension_attributes() const override { return true; }
// https://html.spec.whatwg.org/multipage/iframe-embed-object.html#process-the-iframe-attributes
void process_the_iframe_attributes(bool initial_insertion = false);
void process_the_iframe_attributes(InitialInsertion = InitialInsertion::No);
// https://html.spec.whatwg.org/multipage/iframe-embed-object.html#current-navigation-was-lazy-loaded
bool m_current_navigation_was_lazy_loaded { false };

View file

@ -1453,7 +1453,8 @@ WebIDL::ExceptionOr<void> Navigable::navigate(NavigateParams params)
// an optional entry list or null formDataEntryList (default null),
// an optional referrer policy referrerPolicy (default the empty string),
// an optional user navigation involvement userInvolvement (default "none"),
// and an optional Element sourceElement (default null):
// an optional Element sourceElement (default null),
// and an optional boolean initialInsertion (default false):
// https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate
void Navigable::begin_navigation(NavigateParams params)
@ -1472,6 +1473,7 @@ void Navigable::begin_navigation(NavigateParams params)
auto referrer_policy = params.referrer_policy;
auto user_involvement = params.user_involvement;
auto source_element = params.source_element;
auto initial_insertion = params.initial_insertion;
auto& active_document = *this->active_document();
auto& vm = this->vm();
@ -1575,10 +1577,10 @@ void Navigable::begin_navigation(NavigateParams params)
// 19. If url's scheme is "javascript", then:
if (url.scheme() == "javascript"sv) {
// 1. Queue a global task on the navigation and traversal task source given navigable's active window to navigate to a javascript: URL given navigable, url, historyHandling, sourceSnapshotParams, initiatorOriginSnapshot, userInvolvement, and cspNavigationType.
// 1. Queue a global task on the navigation and traversal task source given navigable's active window to navigate to a javascript: URL given navigable, url, historyHandling, sourceSnapshotParams, initiatorOriginSnapshot, userInvolvement, cspNavigationType, and initialInsertion.
VERIFY(active_window());
queue_global_task(Task::Source::NavigationAndTraversal, *active_window(), GC::create_function(heap(), [this, url, history_handling, source_snapshot_params, initiator_origin_snapshot, user_involvement, csp_navigation_type, navigation_id] {
navigate_to_a_javascript_url(url, to_history_handling_behavior(history_handling), source_snapshot_params, initiator_origin_snapshot, user_involvement, csp_navigation_type, navigation_id);
queue_global_task(Task::Source::NavigationAndTraversal, *active_window(), GC::create_function(heap(), [this, url, history_handling, source_snapshot_params, initiator_origin_snapshot, user_involvement, csp_navigation_type, initial_insertion, navigation_id] {
navigate_to_a_javascript_url(url, to_history_handling_behavior(history_handling), source_snapshot_params, initiator_origin_snapshot, user_involvement, csp_navigation_type, initial_insertion, navigation_id);
}));
// 2. Return.
@ -1921,7 +1923,7 @@ GC::Ptr<DOM::Document> Navigable::evaluate_javascript_url(URL::URL const& url, U
}
// https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate-to-a-javascript:-url
void Navigable::navigate_to_a_javascript_url(URL::URL const& url, HistoryHandlingBehavior history_handling, GC::Ref<SourceSnapshotParams> source_snapshot_params, URL::Origin const& initiator_origin, UserNavigationInvolvement user_involvement, ContentSecurityPolicy::Directives::Directive::NavigationType csp_navigation_type, String navigation_id)
void Navigable::navigate_to_a_javascript_url(URL::URL const& url, HistoryHandlingBehavior history_handling, GC::Ref<SourceSnapshotParams> source_snapshot_params, URL::Origin const& initiator_origin, UserNavigationInvolvement user_involvement, ContentSecurityPolicy::Directives::Directive::NavigationType csp_navigation_type, InitialInsertion initial_insertion, String navigation_id)
{
auto& vm = this->vm();
@ -1947,8 +1949,15 @@ void Navigable::navigate_to_a_javascript_url(URL::URL const& url, HistoryHandlin
// 6. Let newDocument be the result of evaluating a javascript: URL given targetNavigable, url, initiatorOrigin, and userInvolvement.
auto new_document = evaluate_javascript_url(url, initiator_origin, user_involvement, navigation_id);
// 7. If newDocument is null, then return.
// 7. If newDocument is null:
if (!new_document) {
// 1. If initialInsertion is true and targetNavigable's active document's is initial about:blank is true,
// then run the iframe load event steps given targetNavigable's container.
if (initial_insertion == InitialInsertion::Yes && active_document()->is_initial_about_blank()) {
run_iframe_load_event_steps(as<HTMLIFrameElement>(*container()));
}
// 2. Return.
// NOTE: In this case, some JavaScript code was executed, but no new Document was created, so we will not perform a navigation.
return;
}

View file

@ -28,6 +28,11 @@
namespace Web::HTML {
enum class InitialInsertion : u8 {
Yes,
No,
};
// https://html.spec.whatwg.org/multipage/browsing-the-web.html#target-snapshot-params
struct TargetSnapshotParams {
SandboxingFlagSet sandboxing_flags {};
@ -142,6 +147,7 @@ public:
ReferrerPolicy::ReferrerPolicy referrer_policy = ReferrerPolicy::ReferrerPolicy::EmptyString;
UserNavigationInvolvement user_involvement = UserNavigationInvolvement::None;
GC::Ptr<DOM::Element> source_element = nullptr;
InitialInsertion initial_insertion = InitialInsertion::No;
void visit_edges(Cell::Visitor& visitor);
};
@ -205,7 +211,7 @@ protected:
private:
void begin_navigation(NavigateParams);
void navigate_to_a_fragment(URL::URL const&, HistoryHandlingBehavior, UserNavigationInvolvement, GC::Ptr<DOM::Element> source_element, Optional<SerializationRecord> navigation_api_state, String navigation_id);
void navigate_to_a_javascript_url(URL::URL const&, HistoryHandlingBehavior, GC::Ref<SourceSnapshotParams>, URL::Origin const& initiator_origin, UserNavigationInvolvement, ContentSecurityPolicy::Directives::Directive::NavigationType csp_navigation_type, String navigation_id);
void navigate_to_a_javascript_url(URL::URL const&, HistoryHandlingBehavior, GC::Ref<SourceSnapshotParams>, URL::Origin const& initiator_origin, UserNavigationInvolvement, ContentSecurityPolicy::Directives::Directive::NavigationType csp_navigation_type, InitialInsertion, String navigation_id);
void reset_cursor_blink_cycle();

View file

@ -195,14 +195,14 @@ HTML::WindowProxy* NavigableContainer::content_window()
}
// https://html.spec.whatwg.org/multipage/iframe-embed-object.html#shared-attribute-processing-steps-for-iframe-and-frame-elements
Optional<URL::URL> NavigableContainer::shared_attribute_processing_steps_for_iframe_and_frame(bool initial_insertion)
Optional<URL::URL> NavigableContainer::shared_attribute_processing_steps_for_iframe_and_frame(InitialInsertion initial_insertion)
{
// AD-HOC: If the element was added and immediately removed, the content navigable will be null. Don't process the
// src attribute any further.
if (!m_content_navigable)
return {};
if (initial_insertion && m_content_navigable->has_pending_navigations()) {
if (initial_insertion == InitialInsertion::Yes && m_content_navigable->has_pending_navigations()) {
return {};
}
@ -228,7 +228,7 @@ Optional<URL::URL> NavigableContainer::shared_attribute_processing_steps_for_ifr
}
// 4. If url matches about:blank and initialInsertion is true, then perform the URL and history update steps given element's content navigable's active document and url.
if (url_matches_about_blank(url) && initial_insertion) {
if (url_matches_about_blank(url) && initial_insertion == InitialInsertion::Yes) {
auto& document = *m_content_navigable->active_document();
perform_url_and_history_update_steps(document, url);
}
@ -238,7 +238,7 @@ Optional<URL::URL> NavigableContainer::shared_attribute_processing_steps_for_ifr
}
// https://html.spec.whatwg.org/multipage/iframe-embed-object.html#navigate-an-iframe-or-frame
void NavigableContainer::navigate_an_iframe_or_frame(URL::URL url, ReferrerPolicy::ReferrerPolicy referrer_policy, Optional<String> srcdoc_string)
void NavigableContainer::navigate_an_iframe_or_frame(URL::URL url, ReferrerPolicy::ReferrerPolicy referrer_policy, Optional<String> srcdoc_string, InitialInsertion initial_insertion)
{
// 1. Let historyHandling be "auto".
auto history_handling = Bindings::NavigationHistoryBehavior::Auto;
@ -252,7 +252,8 @@ void NavigableContainer::navigate_an_iframe_or_frame(URL::URL url, ReferrerPolic
// time given element's node document's relevant global object.
// 4. Navigate element's content navigable to url using element's node document, with historyHandling set to historyHandling,
// referrerPolicy set to referrerPolicy, and documentResource set to scrdocString.
// referrerPolicy set to referrerPolicy, documentResource set to srcdocString, and initialInsertion set to
// initialInsertion.
Variant<Empty, String, POSTResource> document_resource = Empty {};
if (srcdoc_string.has_value())
document_resource = srcdoc_string.value();
@ -263,6 +264,7 @@ void NavigableContainer::navigate_an_iframe_or_frame(URL::URL url, ReferrerPolic
.document_resource = document_resource,
.history_handling = history_handling,
.referrer_policy = referrer_policy,
.initial_insertion = initial_insertion,
}));
}

View file

@ -51,10 +51,10 @@ protected:
virtual void visit_edges(Cell::Visitor&) override;
// https://html.spec.whatwg.org/multipage/iframe-embed-object.html#shared-attribute-processing-steps-for-iframe-and-frame-elements
Optional<URL::URL> shared_attribute_processing_steps_for_iframe_and_frame(bool initial_insertion);
Optional<URL::URL> shared_attribute_processing_steps_for_iframe_and_frame(InitialInsertion initial_insertion);
// https://html.spec.whatwg.org/multipage/iframe-embed-object.html#navigate-an-iframe-or-frame
void navigate_an_iframe_or_frame(URL::URL url, ReferrerPolicy::ReferrerPolicy referrer_policy, Optional<String> srcdoc_string = {});
void navigate_an_iframe_or_frame(URL::URL url, ReferrerPolicy::ReferrerPolicy referrer_policy, Optional<String> srcdoc_string = {}, InitialInsertion = InitialInsertion::No);
WebIDL::ExceptionOr<void> create_new_child_navigable(GC::Ptr<GC::Function<void()>> after_session_history_update = {});