LibWeb: Bring BrowsingContext::choose_a_browsing_context closer to spec
This commit is contained in:
parent
c948873c5b
commit
ff2f31bc81
Notes:
sideshowbarker
2024-07-17 04:26:38 +09:00
Author: https://github.com/IdanHo Commit: https://github.com/SerenityOS/serenity/commit/ff2f31bc81 Pull-request: https://github.com/SerenityOS/serenity/pull/16072 Reviewed-by: https://github.com/linusg ✅ Reviewed-by: https://github.com/trflynn89
3 changed files with 100 additions and 79 deletions
|
@ -651,118 +651,128 @@ JS::GCPtr<DOM::Node> BrowsingContext::currently_focused_area()
|
||||||
return candidate;
|
return candidate;
|
||||||
}
|
}
|
||||||
|
|
||||||
BrowsingContext* BrowsingContext::choose_a_browsing_context(StringView name, bool)
|
// https://html.spec.whatwg.org/#the-rules-for-choosing-a-browsing-context-given-a-browsing-context-name
|
||||||
|
BrowsingContext::ChosenBrowsingContext BrowsingContext::choose_a_browsing_context(StringView name, bool no_opener)
|
||||||
{
|
{
|
||||||
// The rules for choosing a browsing context, given a browsing context name
|
// The rules for choosing a browsing context, given a browsing context name name, a browsing context current, and
|
||||||
// name, a browsing context current, and a boolean noopener are as follows:
|
// a boolean noopener are as follows:
|
||||||
|
|
||||||
// 1. Let chosen be null.
|
// 1. Let chosen be null.
|
||||||
JS::GCPtr<BrowsingContext> chosen = nullptr;
|
JS::GCPtr<BrowsingContext> chosen = nullptr;
|
||||||
|
|
||||||
// FIXME: 2. Let windowType be "existing or none".
|
// 2. Let windowType be "existing or none".
|
||||||
|
auto window_type = WindowType::ExistingOrNone;
|
||||||
|
|
||||||
// FIXME: 3. Let sandboxingFlagSet be current's active document's active
|
// 3. Let sandboxingFlagSet be current's active document's active sandboxing flag set.
|
||||||
// sandboxing flag set.
|
auto sandboxing_flag_set = active_document()->active_sandboxing_flag_set();
|
||||||
|
|
||||||
// 4. If name is the empty string or an ASCII case-insensitive match for "_self", then set chosen to current.
|
// 4. If name is the empty string or an ASCII case-insensitive match for "_self", then set chosen to current.
|
||||||
if (name.is_empty() || name.equals_ignoring_case("_self"sv))
|
if (name.is_empty() || name.equals_ignoring_case("_self"sv)) {
|
||||||
chosen = this;
|
chosen = this;
|
||||||
|
}
|
||||||
|
|
||||||
// 5. Otherwise, if name is an ASCII case-insensitive match for "_parent",
|
// 5. Otherwise, if name is an ASCII case-insensitive match for "_parent", set chosen to current's parent browsing
|
||||||
// set chosen to current's parent browsing context, if any, and current
|
// context, if any, and current otherwise.
|
||||||
// otherwise.
|
else if (name.equals_ignoring_case("_parent"sv)) {
|
||||||
if (name.equals_ignoring_case("_parent"sv)) {
|
|
||||||
if (auto parent = this->parent())
|
if (auto parent = this->parent())
|
||||||
chosen = parent;
|
chosen = parent;
|
||||||
else
|
else
|
||||||
chosen = this;
|
chosen = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6. Otherwise, if name is an ASCII case-insensitive match for "_top", set
|
// 6. Otherwise, if name is an ASCII case-insensitive match for "_top", set chosen to current's top-level browsing
|
||||||
// chosen to current's top-level browsing context, if any, and current
|
// context, if any, and current otherwise.
|
||||||
// otherwise.
|
else if (name.equals_ignoring_case("_top"sv)) {
|
||||||
if (name.equals_ignoring_case("_top"sv)) {
|
|
||||||
chosen = &top_level_browsing_context();
|
chosen = &top_level_browsing_context();
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: 7. Otherwise, if name is not an ASCII case-insensitive match for
|
// FIXME: 7. Otherwise, if name is not an ASCII case-insensitive match for "_blank", there exists a browsing context
|
||||||
// "_blank", there exists a browsing context whose name is the same as name,
|
// whose name is the same as name, current is familiar with that browsing context, and the user agent
|
||||||
// current is familiar with that browsing context, and the user agent
|
// determines that the two browsing contexts are related enough that it is ok if they reach each other,
|
||||||
// determines that the two browsing contexts are related enough that it is
|
// set chosen to that browsing context. If there are multiple matching browsing contexts, the user agent
|
||||||
// ok if they reach each other, set chosen to that browsing context. If
|
// should set chosen to one in some arbitrary consistent manner, such as the most recently opened, most
|
||||||
// there are multiple matching browsing contexts, the user agent should set
|
// recently focused, or more closely related.
|
||||||
// chosen to one in some arbitrary consistent manner, such as the most
|
else if (!name.equals_ignoring_case("_blank"sv)) {
|
||||||
// recently opened, most recently focused, or more closely related.
|
dbgln("FIXME: Find matching browser context for name {}", name);
|
||||||
if (!name.equals_ignoring_case("_blank"sv)) {
|
|
||||||
chosen = this;
|
chosen = this;
|
||||||
} else {
|
} else {
|
||||||
// 8. Otherwise, a new browsing context is being requested, and what
|
// 8. Otherwise, a new browsing context is being requested, and what happens depends on the user agent's
|
||||||
// happens depends on the user agent's configuration and abilities — it
|
// configuration and abilities — it is determined by the rules given for the first applicable option from
|
||||||
// is determined by the rules given for the first applicable option from
|
// the following list:
|
||||||
// the following list:
|
|
||||||
dbgln("FIXME: Create a new browsing context!");
|
|
||||||
|
|
||||||
// --> If current's active window does not have transient activation and
|
// --> If current's active window does not have transient activation and the user agent has been configured to
|
||||||
// the user agent has been configured to not show popups (i.e., the
|
// not show popups (i.e., the user agent has a "popup blocker" enabled)
|
||||||
// user agent has a "popup blocker" enabled)
|
VERIFY(m_page);
|
||||||
//
|
if (!active_window()->has_transient_activation() && m_page->should_block_pop_ups()) {
|
||||||
// The user agent may inform the user that a popup has been blocked.
|
// FIXME: The user agent may inform the user that a popup has been blocked.
|
||||||
|
dbgln("Pop-up blocked!");
|
||||||
|
}
|
||||||
|
|
||||||
// --> If sandboxingFlagSet has the sandboxed auxiliary navigation
|
// --> If sandboxingFlagSet has the sandboxed auxiliary navigation browsing context flag set
|
||||||
// browsing context flag set
|
else if (sandboxing_flag_set.flags & SandboxingFlagSet::SandboxedAuxiliaryNavigation) {
|
||||||
//
|
// FIXME: The user agent may report to a developer console that a popup has been blocked.
|
||||||
// The user agent may report to a developer console that a popup has
|
dbgln("Pop-up blocked!");
|
||||||
// been blocked.
|
}
|
||||||
|
|
||||||
// --> If the user agent has been configured such that in this instance
|
// --> If the user agent has been configured such that in this instance it will create a new browsing context
|
||||||
// it will create a new browsing context
|
else if (true) { // FIXME: When is this the case?
|
||||||
//
|
// 1. Set windowType to "new and unrestricted".
|
||||||
// 1. Set windowType to "new and unrestricted".
|
window_type = WindowType::NewAndUnrestricted;
|
||||||
|
|
||||||
// 2. If current's top-level browsing context's active document's
|
// 2. If current's top-level browsing context's active document's cross-origin opener policy's value is
|
||||||
// cross-origin opener policy's value is "same-origin" or
|
// "same-origin" or "same-origin-plus-COEP", then:
|
||||||
// "same-origin-plus-COEP", then:
|
if (top_level_browsing_context().active_document()->cross_origin_opener_policy().value == CrossOriginOpenerPolicyValue::SameOrigin || top_level_browsing_context().active_document()->cross_origin_opener_policy().value == CrossOriginOpenerPolicyValue::SameOriginPlusCOEP) {
|
||||||
|
// 1. Let currentDocument be current's active document.
|
||||||
|
auto* current_document = top_level_browsing_context().active_document();
|
||||||
|
|
||||||
// 2.1. Let currentDocument be current's active document.
|
// 2. If currentDocument's origin is not same origin with currentDocument's relevant settings object's
|
||||||
|
// top-level origin, then set noopener to true, name to "_blank", and windowType to "new with no opener".
|
||||||
|
if (!current_document->origin().is_same_origin(current_document->relevant_settings_object().top_level_origin)) {
|
||||||
|
no_opener = true;
|
||||||
|
name = "_blank"sv;
|
||||||
|
window_type = WindowType::NewWithNoOpener;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 2.2. If currentDocument's origin is not same origin with
|
// 3. If noopener is true, then set chosen to the result of creating a new top-level browsing context.
|
||||||
// currentDocument's relevant settings object's top-level
|
if (no_opener) {
|
||||||
// origin, then set noopener to true, name to "_blank", and
|
chosen = HTML::BrowsingContext::create_a_new_top_level_browsing_context(*m_page);
|
||||||
// windowType to "new with no opener".
|
}
|
||||||
|
|
||||||
// 3. If noopener is true, then set chosen to the result of creating
|
// 4. Otherwise:
|
||||||
// a new top-level browsing context.
|
else {
|
||||||
|
// 1. Set chosen to the result of creating a new auxiliary browsing context with current.
|
||||||
|
// FIXME: We have no concept of auxiliary browsing context
|
||||||
|
chosen = HTML::BrowsingContext::create_a_new_top_level_browsing_context(*m_page);
|
||||||
|
|
||||||
// 4. Otherwise:
|
// 2. If sandboxingFlagSet's sandboxed navigation browsing context flag is set, then current must be
|
||||||
|
// set as chosen's one permitted sandboxed navigator.
|
||||||
|
// FIXME: We have no concept of one permitted sandboxed navigator
|
||||||
|
}
|
||||||
|
|
||||||
// 4.1. Set chosen to the result of creating a new auxiliary
|
// 5. If sandboxingFlagSet's sandbox propagates to auxiliary browsing contexts flag is set, then all the
|
||||||
// browsing context with current.
|
// flags that are set in sandboxingFlagSet must be set in chosen's popup sandboxing flag set.
|
||||||
|
// FIXME: Our BrowsingContexts do not have SandboxingFlagSets yet, only documents do
|
||||||
|
|
||||||
// 4.2. If sandboxingFlagSet's sandboxed navigation browsing
|
// 6. If name is not an ASCII case-insensitive match for "_blank", then set chosen's name to name.
|
||||||
// context flag is set, then current must be set as chosen's one
|
if (!name.equals_ignoring_case("_blank"sv))
|
||||||
// permitted sandboxed navigator.
|
chosen->set_name(name);
|
||||||
|
}
|
||||||
|
|
||||||
// 5. If sandboxingFlagSet's sandbox propagates to auxiliary
|
// --> If the user agent has been configured such that in this instance t will reuse current
|
||||||
// browsing contexts flag is set, then all the flags that are set in
|
else if (false) { // FIXME: When is this the case?
|
||||||
// sandboxingFlagSet must be set in chosen's popup sandboxing flag
|
// Set chosen to current.
|
||||||
// set.
|
chosen = *this;
|
||||||
|
}
|
||||||
|
|
||||||
// 6. If name is not an ASCII case-insensitive match for "_blank",
|
// --> If the user agent has been configured such that in this instance it will not find a browsing context
|
||||||
// then set chosen's name to name.
|
else if (false) { // FIXME: When is this the case?
|
||||||
|
// Do nothing.
|
||||||
// --> If the user agent has been configured such that in this instance
|
}
|
||||||
// it will reuse current
|
|
||||||
//
|
|
||||||
// Set chosen to current.
|
|
||||||
|
|
||||||
// --> If the user agent has been configured such that in this instance
|
|
||||||
// it will not find a browsing context
|
|
||||||
//
|
|
||||||
// Do nothing.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 9. Return chosen and windowType.
|
// 9. Return chosen and windowType.
|
||||||
return chosen;
|
return { chosen, window_type };
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/browsers.html#document-tree-child-browsing-context
|
// https://html.spec.whatwg.org/multipage/browsers.html#document-tree-child-browsing-context
|
||||||
|
|
|
@ -163,7 +163,18 @@ public:
|
||||||
|
|
||||||
BrowsingContext const& top_level_browsing_context() const { return const_cast<BrowsingContext*>(this)->top_level_browsing_context(); }
|
BrowsingContext const& top_level_browsing_context() const { return const_cast<BrowsingContext*>(this)->top_level_browsing_context(); }
|
||||||
|
|
||||||
BrowsingContext* choose_a_browsing_context(StringView name, bool noopener);
|
enum class WindowType {
|
||||||
|
ExistingOrNone,
|
||||||
|
NewAndUnrestricted,
|
||||||
|
NewWithNoOpener,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ChosenBrowsingContext {
|
||||||
|
JS::GCPtr<BrowsingContext> browsing_context;
|
||||||
|
WindowType window_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
ChosenBrowsingContext choose_a_browsing_context(StringView name, bool no_opener);
|
||||||
|
|
||||||
size_t document_tree_child_browsing_context_count() const;
|
size_t document_tree_child_browsing_context_count() const;
|
||||||
|
|
||||||
|
|
|
@ -493,7 +493,7 @@ void HTMLHyperlinkElementUtils::follow_the_hyperlink(Optional<String> hyperlink_
|
||||||
// 7. Let target be the first return value of applying the rules for
|
// 7. Let target be the first return value of applying the rules for
|
||||||
// choosing a browsing context given targetAttributeValue, source, and
|
// choosing a browsing context given targetAttributeValue, source, and
|
||||||
// noopener.
|
// noopener.
|
||||||
auto* target = source->choose_a_browsing_context(target_attribute_value, noopener);
|
auto target = source->choose_a_browsing_context(target_attribute_value, noopener).browsing_context;
|
||||||
|
|
||||||
// 8. If target is null, then return.
|
// 8. If target is null, then return.
|
||||||
if (!target)
|
if (!target)
|
||||||
|
@ -534,7 +534,7 @@ void HTMLHyperlinkElementUtils::follow_the_hyperlink(Optional<String> hyperlink_
|
||||||
// set to source.
|
// set to source.
|
||||||
// FIXME: "navigate" means implementing the navigation algorithm here:
|
// FIXME: "navigate" means implementing the navigation algorithm here:
|
||||||
// https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate
|
// https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate
|
||||||
hyperlink_element_utils_queue_an_element_task(Task::Source::DOMManipulation, [url_string, target] {
|
hyperlink_element_utils_queue_an_element_task(Task::Source::DOMManipulation, [url_string, &target] {
|
||||||
target->loader().load(url_string, FrameLoader::Type::Navigation);
|
target->loader().load(url_string, FrameLoader::Type::Navigation);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue