LibWeb: Update "window open steps" to current spec

Corresponds to https://github.com/whatwg/html/pull/10683

As part of this, I noticed we incorrectly were setting the "is popup"
flag on the Navigable instead of the BrowsingContext. I've fixed that
and removed the erroneous flag from Navigable.
This commit is contained in:
Sam Atkins 2024-11-27 16:51:12 +00:00 committed by Andreas Kling
parent b83f015c70
commit 70c8535b8a
Notes: github-actions[bot] 2024-11-30 11:23:36 +00:00
2 changed files with 49 additions and 31 deletions

View file

@ -177,8 +177,6 @@ public:
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;
@ -202,9 +200,6 @@ protected:
// https://html.spec.whatwg.org/multipage/browsing-the-web.html#ongoing-navigation
Variant<Empty, Traversal, String> 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();

View file

@ -146,14 +146,42 @@ WebIDL::ExceptionOr<GC::Ptr<WindowProxy>> Window::window_open_steps(StringView u
if (target_navigable == nullptr)
return nullptr;
// 14. If noopener is true or windowType is "new with no opener", then return null.
// 17. If noopener is true or windowType is "new with no opener", then return null.
if (no_opener == TokenizedFeature::NoOpener::Yes || window_type == Navigable::WindowType::NewWithNoOpener)
return nullptr;
// 15. Return targetNavigable's active WindowProxy.
// 18. Return targetNavigable's active WindowProxy.
return target_navigable->active_window_proxy();
}
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#get-noopener-for-window-open
static TokenizedFeature::NoOpener get_noopener_for_window_open(DOM::Document const& source_document, TokenizedFeature::Map const& tokenized_features, URL::URL url)
{
// 1. If url's scheme is "blob":
if (url.scheme() == "blob"sv) {
// 1. Let blobOrigin be url's blob URL entry's environment's origin.
auto blob_origin = url.blob_url_entry()->environment_origin;
// 2. Let topLevelOrigin be sourceDocument's relevant settings object's top-level origin.
auto top_level_origin = source_document.relevant_settings_object().top_level_origin;
// 3. If blobOrigin is not same site with topLevelOrigin, then return true.
if (!blob_origin.is_same_site(top_level_origin))
return TokenizedFeature::NoOpener::Yes;
}
// 2. Let noopener be false.
auto noopener = TokenizedFeature::NoOpener::No;
// 3. If tokenizedFeatures["noopener"] exists, then set noopener to the result of parsing tokenizedFeatures["noopener"] as a boolean feature.
if (auto value = tokenized_features.get("noopener"sv); value.has_value()) {
noopener = parse_boolean_feature<TokenizedFeature::NoOpener>(*value);
}
// 4. Return noopener.
return noopener;
}
// https://html.spec.whatwg.org/multipage/window-object.html#window-open-steps
WebIDL::ExceptionOr<Window::OpenedWindow> Window::window_open_steps_internal(StringView url, StringView target, StringView features)
{
@ -184,49 +212,43 @@ WebIDL::ExceptionOr<Window::OpenedWindow> Window::window_open_steps_internal(Str
// 6. Let tokenizedFeatures be the result of tokenizing features.
auto tokenized_features = tokenize_open_features(features);
// 7. Let noopener and noreferrer be false.
auto no_opener = TokenizedFeature::NoOpener::No;
// 7. Let noreferrer be false.
auto no_referrer = TokenizedFeature::NoReferrer::No;
// 8. If tokenizedFeatures["noopener"] exists, then:
if (auto no_opener_feature = tokenized_features.get("noopener"sv); no_opener_feature.has_value()) {
// 1. Set noopener to the result of parsing tokenizedFeatures["noopener"] as a boolean feature.
no_opener = parse_boolean_feature<TokenizedFeature::NoOpener>(*no_opener_feature);
// 2. Remove tokenizedFeatures["noopener"].
tokenized_features.remove("noopener"sv);
}
// 9. If tokenizedFeatures["noreferrer"] exists, then:
// 8. If tokenizedFeatures["noreferrer"] exists, then set noreferrer to the result of parsing tokenizedFeatures["noreferrer"] as a boolean feature.
if (auto no_referrer_feature = tokenized_features.get("noreferrer"sv); no_referrer_feature.has_value()) {
// 1. Set noreferrer to the result of parsing tokenizedFeatures["noreferrer"] as a boolean feature.
no_referrer = parse_boolean_feature<TokenizedFeature::NoReferrer>(*no_referrer_feature);
// 2. Remove tokenizedFeatures["noreferrer"].
tokenized_features.remove("noreferrer"sv);
}
// 10. Let referrerPolicy be the empty string.
// 9. Let noopener be the result of getting noopener for window open with sourceDocument, tokenizedFeatures, and urlRecord.
// FIXME: Is it safe to assume url_record has a value here?
auto no_opener = get_noopener_for_window_open(source_document, tokenized_features, *url_record);
// 10. Remove tokenizedFeatures["noopener"] and tokenizedFeatures["noreferrer"].
tokenized_features.remove("noopener"sv);
tokenized_features.remove("noreferrer"sv);
// 11. Let referrerPolicy be the empty string.
auto referrer_policy = ReferrerPolicy::ReferrerPolicy::EmptyString;
// 11. If noreferrer is true, then set noopener to true and set referrerPolicy to "no-referrer".
// 12. If noreferrer is true, then set noopener to true and set referrerPolicy to "no-referrer".
if (no_referrer == TokenizedFeature::NoReferrer::Yes) {
no_opener = TokenizedFeature::NoOpener::Yes;
referrer_policy = ReferrerPolicy::ReferrerPolicy::NoReferrer;
}
// 12. Let targetNavigable and windowType be the result of applying the rules for choosing a navigable given target, sourceDocument's node navigable, and noopener.
// 13. Let targetNavigable and windowType be the result of applying the rules for choosing a navigable given target, sourceDocument's node navigable, and noopener.
VERIFY(source_document.navigable());
auto [target_navigable, window_type] = source_document.navigable()->choose_a_navigable(target, no_opener, ActivateTab::Yes, tokenized_features);
// 13. If targetNavigable is null, then return null.
// 14. If targetNavigable is null, then return null.
if (target_navigable == nullptr)
return OpenedWindow {};
// 14. If windowType is either "new and unrestricted" or "new with no opener", then:
// 15. If windowType is either "new and unrestricted" or "new with no opener", then:
if (window_type == Navigable::WindowType::NewAndUnrestricted || window_type == Navigable::WindowType::NewWithNoOpener) {
// 1. Set the target browsing context's is popup to the result of checking if a popup window is requested, given tokenizedFeatures.
target_navigable->set_is_popup(check_if_a_popup_window_is_requested(tokenized_features));
// 1. Set targetNavigable's active browsing context's is popup to the result of checking if a popup window is requested, given tokenizedFeatures.
target_navigable->active_browsing_context()->set_is_popup(check_if_a_popup_window_is_requested(tokenized_features));
// 2. Set up browsing context features for target browsing context given tokenizedFeatures. [CSSOMVIEW]
// NOTE: This is implemented in choose_a_navigable when creating the top level traversable.
@ -249,7 +271,7 @@ WebIDL::ExceptionOr<Window::OpenedWindow> Window::window_open_steps_internal(Str
TRY(target_navigable->navigate({ .url = url_record.release_value(), .source_document = source_document, .exceptions_enabled = true, .referrer_policy = referrer_policy }));
}
}
// 15. Otherwise:
// 16. Otherwise:
else {
// 1. If urlRecord is not null, then navigate targetNavigable to urlRecord using sourceDocument, with referrerPolicy set to referrerPolicy and exceptionsEnabled set to true.
if (url_record.has_value())
@ -260,6 +282,7 @@ WebIDL::ExceptionOr<Window::OpenedWindow> Window::window_open_steps_internal(Str
target_navigable->active_browsing_context()->set_opener_browsing_context(source_document.browsing_context());
}
// NOTE: Steps 17 and 18 are implemented in window_open_steps().
return OpenedWindow { target_navigable, no_opener, window_type };
}