diff options
author | Idan Horowitz <idan.horowitz@gmail.com> | 2022-11-15 02:00:27 +0200 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2022-11-15 21:48:19 +0000 |
commit | ff2f31bc81df4505209be7fdb46d770b6f6e2098 (patch) | |
tree | df3dfb2b7d9cba3a2871b36c9ee6fc718aac702b /Userland/Libraries | |
parent | c948873c5be9567405a0e293d9c37119156b41a1 (diff) | |
download | serenity-ff2f31bc81df4505209be7fdb46d770b6f6e2098.zip |
LibWeb: Bring BrowsingContext::choose_a_browsing_context closer to spec
Diffstat (limited to 'Userland/Libraries')
-rw-r--r-- | Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp | 186 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/HTML/BrowsingContext.h | 13 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/HTML/HTMLHyperlinkElementUtils.cpp | 4 |
3 files changed, 112 insertions, 91 deletions
diff --git a/Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp b/Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp index 67cb6e1eca..d2e9306306 100644 --- a/Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp +++ b/Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp @@ -651,118 +651,128 @@ JS::GCPtr<DOM::Node> BrowsingContext::currently_focused_area() 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 - // name, a browsing context current, and a boolean noopener are as follows: + // The rules for choosing a browsing context, given a browsing context name name, a browsing context current, and + // a boolean noopener are as follows: // 1. Let chosen be null. 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 - // sandboxing flag set. + // 3. Let sandboxingFlagSet be current's active document's active 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. - if (name.is_empty() || name.equals_ignoring_case("_self"sv)) + if (name.is_empty() || name.equals_ignoring_case("_self"sv)) { chosen = this; + } - // 5. Otherwise, if name is an ASCII case-insensitive match for "_parent", - // set chosen to current's parent browsing context, if any, and current - // otherwise. - if (name.equals_ignoring_case("_parent"sv)) { + // 5. Otherwise, if name is an ASCII case-insensitive match for "_parent", set chosen to current's parent browsing + // context, if any, and current otherwise. + else if (name.equals_ignoring_case("_parent"sv)) { if (auto parent = this->parent()) chosen = parent; else chosen = this; } - // 6. Otherwise, if name is an ASCII case-insensitive match for "_top", set - // chosen to current's top-level browsing context, if any, and current - // otherwise. - if (name.equals_ignoring_case("_top"sv)) { + // 6. Otherwise, if name is an ASCII case-insensitive match for "_top", set chosen to current's top-level browsing + // context, if any, and current otherwise. + else if (name.equals_ignoring_case("_top"sv)) { chosen = &top_level_browsing_context(); } - // FIXME: 7. Otherwise, if name is not an ASCII case-insensitive match for - // "_blank", there exists a browsing context whose name is the same as name, - // 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, set chosen to that browsing context. If - // there are multiple matching browsing contexts, the user agent should set - // chosen to one in some arbitrary consistent manner, such as the most - // recently opened, most recently focused, or more closely related. - if (!name.equals_ignoring_case("_blank"sv)) { + // FIXME: 7. Otherwise, if name is not an ASCII case-insensitive match for "_blank", there exists a browsing context + // whose name is the same as name, 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, + // set chosen to that browsing context. If there are multiple matching browsing contexts, the user agent + // should set chosen to one in some arbitrary consistent manner, such as the most recently opened, most + // recently focused, or more closely related. + else if (!name.equals_ignoring_case("_blank"sv)) { + dbgln("FIXME: Find matching browser context for name {}", name); chosen = this; } else { - // 8. Otherwise, a new browsing context is being requested, and what - // happens depends on the user agent's configuration and abilities — it - // is determined by the rules given for the first applicable option from - // the following list: - dbgln("FIXME: Create a new browsing context!"); - - // --> If current's active window does not have transient activation and - // the user agent has been configured to not show popups (i.e., the - // user agent has a "popup blocker" enabled) - // - // The user agent may inform the user that a popup has been blocked. - - // --> If sandboxingFlagSet has the sandboxed auxiliary navigation - // browsing context flag set - // - // The user agent may report to a developer console that a popup has - // been blocked. - - // --> If the user agent has been configured such that in this instance - // it will create a new browsing context - // - // 1. Set windowType to "new and unrestricted". - - // 2. If current's top-level browsing context's active document's - // cross-origin opener policy's value is "same-origin" or - // "same-origin-plus-COEP", then: - - // 2.1. Let currentDocument be current's active document. - - // 2.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". - - // 3. If noopener is true, then set chosen to the result of creating - // a new top-level browsing context. - - // 4. Otherwise: - - // 4.1. Set chosen to the result of creating a new auxiliary - // browsing context with current. - - // 4.2. If sandboxingFlagSet's sandboxed navigation browsing - // context flag is set, then current must be set as chosen's one - // permitted sandboxed navigator. - - // 5. If sandboxingFlagSet's sandbox propagates to auxiliary - // browsing contexts flag is set, then all the flags that are set in - // sandboxingFlagSet must be set in chosen's popup sandboxing flag - // set. - - // 6. If name is not an ASCII case-insensitive match for "_blank", - // then set chosen's name to name. - - // --> 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. + // 8. Otherwise, a new browsing context is being requested, and what happens depends on the user agent's + // configuration and abilities — it is determined by the rules given for the first applicable option from + // the following list: + + // --> If current's active window does not have transient activation and the user agent has been configured to + // not show popups (i.e., the user agent has a "popup blocker" enabled) + VERIFY(m_page); + if (!active_window()->has_transient_activation() && m_page->should_block_pop_ups()) { + // 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 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. + dbgln("Pop-up blocked!"); + } + + // --> If the user agent has been configured such that in this instance it will create a new browsing context + else if (true) { // FIXME: When is this the case? + // 1. Set windowType to "new and unrestricted". + window_type = WindowType::NewAndUnrestricted; + + // 2. If current's top-level browsing context's active document's cross-origin opener policy's value is + // "same-origin" or "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. 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; + } + } + + // 3. If noopener is true, then set chosen to the result of creating a new top-level browsing context. + if (no_opener) { + chosen = HTML::BrowsingContext::create_a_new_top_level_browsing_context(*m_page); + } + + // 4. Otherwise: + 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); + + // 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 + } + + // 5. If sandboxingFlagSet's sandbox propagates to auxiliary browsing contexts flag is set, then all the + // 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 + + // 6. If name is not an ASCII case-insensitive match for "_blank", then set chosen's name to name. + if (!name.equals_ignoring_case("_blank"sv)) + chosen->set_name(name); + } + + // --> If the user agent has been configured such that in this instance t will reuse current + else if (false) { // FIXME: When is this the case? + // Set chosen to current. + chosen = *this; + } + + // --> If the user agent has been configured such that in this instance it will not find a browsing context + else if (false) { // FIXME: When is this the case? + // Do nothing. + } } // 9. Return chosen and windowType. - return chosen; + return { chosen, window_type }; } // https://html.spec.whatwg.org/multipage/browsers.html#document-tree-child-browsing-context diff --git a/Userland/Libraries/LibWeb/HTML/BrowsingContext.h b/Userland/Libraries/LibWeb/HTML/BrowsingContext.h index 64953a5638..32a7bfd6fb 100644 --- a/Userland/Libraries/LibWeb/HTML/BrowsingContext.h +++ b/Userland/Libraries/LibWeb/HTML/BrowsingContext.h @@ -163,7 +163,18 @@ public: 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; diff --git a/Userland/Libraries/LibWeb/HTML/HTMLHyperlinkElementUtils.cpp b/Userland/Libraries/LibWeb/HTML/HTMLHyperlinkElementUtils.cpp index 794cb51453..43858ad2b4 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLHyperlinkElementUtils.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLHyperlinkElementUtils.cpp @@ -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 // choosing a browsing context given targetAttributeValue, source, and // 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. if (!target) @@ -534,7 +534,7 @@ void HTMLHyperlinkElementUtils::follow_the_hyperlink(Optional<String> hyperlink_ // set to source. // FIXME: "navigate" means implementing the navigation algorithm here: // 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); }); } |