From e154c2c2cac482df9e390ab606fdd2049968fb69 Mon Sep 17 00:00:00 2001 From: Simon Wanner Date: Sun, 20 Mar 2022 21:26:34 +0100 Subject: [PATCH] LibWeb: Implement "has element in select scope" per-spec The HTML Specification is quite tricky in this case. Usually "have a particular element in scope" mentions "consisting of the following element types:", but in this case it's "consisting of all element types except the following:" Thanks to @AtkinsSJ for spotting this difference --- .../HTML/Parser/StackOfOpenElements.cpp | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/Userland/Libraries/LibWeb/HTML/Parser/StackOfOpenElements.cpp b/Userland/Libraries/LibWeb/HTML/Parser/StackOfOpenElements.cpp index 60367b9327..f71b35cdaf 100644 --- a/Userland/Libraries/LibWeb/HTML/Parser/StackOfOpenElements.cpp +++ b/Userland/Libraries/LibWeb/HTML/Parser/StackOfOpenElements.cpp @@ -68,9 +68,30 @@ bool StackOfOpenElements::has_in_list_item_scope(const FlyString& tag_name) cons return has_in_scope_impl(tag_name, list); } +// https://html.spec.whatwg.org/multipage/parsing.html#has-an-element-in-select-scope +// The stack of open elements is said to have a particular element in select scope +// when it has that element in the specific scope consisting of all element types except the following: +// - optgroup in the HTML namespace +// - option in the HTML namespace +// NOTE: In this case it's "all element types _except_" bool StackOfOpenElements::has_in_select_scope(const FlyString& tag_name) const { - return has_in_scope_impl(tag_name, { "option", "optgroup" }); + // https://html.spec.whatwg.org/multipage/parsing.html#has-an-element-in-the-specific-scope + for (ssize_t i = m_elements.size() - 1; i >= 0; --i) { + // 1. Initialize node to be the current node (the bottommost node of the stack). + auto& node = m_elements.at(i); + // 2. If node is the target node, terminate in a match state. + if (node.local_name() == tag_name) + return true; + // 3. Otherwise, if node is one of the element types in list, terminate in a failure state. + // NOTE: Here "list" refers to all elements except option and optgroup + if (node.local_name() != HTML::TagNames::option && node.local_name() != HTML::TagNames::optgroup) + return false; + // 4. Otherwise, set node to the previous entry in the stack of open elements and return to step 2. + } + // [4.] (This will never fail, since the loop will always terminate in the previous step if the top of the stack + // — an html element — is reached.) + VERIFY_NOT_REACHED(); } bool StackOfOpenElements::contains(const DOM::Element& element) const