mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-10-27 18:40:00 +00:00
LibWeb: Keep the tokens in ListOfActiveFormattingElements
This commit is contained in:
parent
b8bbebd3ff
commit
6afd39b16a
Notes:
github-actions[bot]
2025-10-21 21:37:19 +00:00
Author: https://github.com/lpas
Commit: 6afd39b16a
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/6515
Reviewed-by: https://github.com/gmta ✅
6 changed files with 59 additions and 42 deletions
|
|
@ -2,6 +2,7 @@
|
||||||
* Copyright (c) 2020-2025, Andreas Kling <andreas@ladybird.org>
|
* Copyright (c) 2020-2025, Andreas Kling <andreas@ladybird.org>
|
||||||
* Copyright (c) 2021, Luke Wilde <lukew@serenityos.org>
|
* Copyright (c) 2021, Luke Wilde <lukew@serenityos.org>
|
||||||
* Copyright (c) 2023-2024, Shannon Booth <shannon@serenityos.org>
|
* Copyright (c) 2023-2024, Shannon Booth <shannon@serenityos.org>
|
||||||
|
* Copyright (c) 2025, Lorenz Ackermann <me@lorenzackermann.xyz>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
@ -1713,14 +1714,10 @@ Create:
|
||||||
// 8. Create: Insert an HTML element for the token for which the element entry was created, to obtain new element.
|
// 8. Create: Insert an HTML element for the token for which the element entry was created, to obtain new element.
|
||||||
VERIFY(!entry->is_marker());
|
VERIFY(!entry->is_marker());
|
||||||
|
|
||||||
// FIXME: Hold on to the real token!
|
auto new_element = insert_html_element(*entry->token);
|
||||||
auto new_element = insert_html_element(HTMLToken::make_start_tag(entry->element->local_name()));
|
|
||||||
entry->element->for_each_attribute([&](auto& name, auto& value) {
|
|
||||||
new_element->append_attribute(name, value);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 9. Replace the entry for entry in the list with an entry for new element.
|
// 9. Replace the entry for entry in the list with an entry for new element.
|
||||||
m_list_of_active_formatting_elements.entries().at(index).element = new_element;
|
m_list_of_active_formatting_elements.replace(*entry->element, new_element, *entry->token);
|
||||||
|
|
||||||
// 10. If the entry for new element in the list of active formatting elements is not the last entry in the list, return to the step labeled advance.
|
// 10. If the entry for new element in the list of active formatting elements is not the last entry in the list, return to the step labeled advance.
|
||||||
if (index != m_list_of_active_formatting_elements.entries().size() - 1)
|
if (index != m_list_of_active_formatting_elements.entries().size() - 1)
|
||||||
|
|
@ -1840,16 +1837,17 @@ HTMLParser::AdoptionAgencyAlgorithmOutcome HTMLParser::run_the_adoption_agency_a
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// 4. If innerLoopCounter is greater than 3 and node is in the list of active formatting elements,
|
// 4. If innerLoopCounter is greater than 3 and node is in the list of active formatting elements,
|
||||||
if (inner_loop_counter > 3 && m_list_of_active_formatting_elements.contains(*node)) {
|
auto node_index = m_list_of_active_formatting_elements.find_index(*node);
|
||||||
auto node_index = m_list_of_active_formatting_elements.find_index(*node);
|
if (inner_loop_counter > 3 && node_index.has_value()) {
|
||||||
if (node_index.has_value() && node_index.value() < bookmark)
|
if (node_index.value() < bookmark)
|
||||||
bookmark--;
|
bookmark--;
|
||||||
// then remove node from the list of active formatting elements.
|
// then remove node from the list of active formatting elements.
|
||||||
m_list_of_active_formatting_elements.remove(*node);
|
m_list_of_active_formatting_elements.remove(*node);
|
||||||
|
node_index = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. If node is not in the list of active formatting elements,
|
// 5. If node is not in the list of active formatting elements,
|
||||||
if (!m_list_of_active_formatting_elements.contains(*node)) {
|
if (!node_index.has_value()) {
|
||||||
// then remove node from the stack of open elements and continue.
|
// then remove node from the stack of open elements and continue.
|
||||||
m_stack_of_open_elements.remove(*node);
|
m_stack_of_open_elements.remove(*node);
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -1857,10 +1855,10 @@ HTMLParser::AdoptionAgencyAlgorithmOutcome HTMLParser::run_the_adoption_agency_a
|
||||||
|
|
||||||
// 6. Create an element for the token for which the element node was created,
|
// 6. Create an element for the token for which the element node was created,
|
||||||
// in the HTML namespace, with commonAncestor as the intended parent;
|
// in the HTML namespace, with commonAncestor as the intended parent;
|
||||||
// FIXME: hold onto the real token
|
auto& entry = m_list_of_active_formatting_elements.entries().at(node_index.value());
|
||||||
auto element = create_element_for(HTMLToken::make_start_tag(node->local_name()), Namespace::HTML, *common_ancestor);
|
auto element = create_element_for(*entry.token, Namespace::HTML, *common_ancestor);
|
||||||
// replace the entry for node in the list of active formatting elements with an entry for the new element,
|
// replace the entry for node in the list of active formatting elements with an entry for the new element,
|
||||||
m_list_of_active_formatting_elements.replace(*node, *element);
|
m_list_of_active_formatting_elements.replace(*node, *element, *entry.token);
|
||||||
// replace the entry for node in the stack of open elements with an entry for the new element,
|
// replace the entry for node in the stack of open elements with an entry for the new element,
|
||||||
m_stack_of_open_elements.replace(*node, element);
|
m_stack_of_open_elements.replace(*node, element);
|
||||||
// and let node be the new element.
|
// and let node be the new element.
|
||||||
|
|
@ -1886,8 +1884,10 @@ HTMLParser::AdoptionAgencyAlgorithmOutcome HTMLParser::run_the_adoption_agency_a
|
||||||
|
|
||||||
// 15. Create an element for the token for which formattingElement was created,
|
// 15. Create an element for the token for which formattingElement was created,
|
||||||
// in the HTML namespace, with furthestBlock as the intended parent.
|
// in the HTML namespace, with furthestBlock as the intended parent.
|
||||||
// FIXME: hold onto the real token
|
auto formatting_element_index = m_list_of_active_formatting_elements.find_index(*formatting_element);
|
||||||
auto element = create_element_for(HTMLToken::make_start_tag(formatting_element->local_name()), Namespace::HTML, *furthest_block);
|
auto& entry = m_list_of_active_formatting_elements.entries().at(formatting_element_index.value());
|
||||||
|
auto token_data = ListOfActiveFormattingElements::create_own_token(*entry.token);
|
||||||
|
auto element = create_element_for(*token_data, Namespace::HTML, *furthest_block);
|
||||||
|
|
||||||
// 16. Take all of the child nodes of furthestBlock and append them to the element created in the last step.
|
// 16. Take all of the child nodes of furthestBlock and append them to the element created in the last step.
|
||||||
for (auto& child : furthest_block->children_as_vector())
|
for (auto& child : furthest_block->children_as_vector())
|
||||||
|
|
@ -1898,11 +1898,10 @@ HTMLParser::AdoptionAgencyAlgorithmOutcome HTMLParser::run_the_adoption_agency_a
|
||||||
|
|
||||||
// 18. Remove formattingElement from the list of active formatting elements,
|
// 18. Remove formattingElement from the list of active formatting elements,
|
||||||
// and insert the new element into the list of active formatting elements at the position of the aforementioned bookmark.
|
// and insert the new element into the list of active formatting elements at the position of the aforementioned bookmark.
|
||||||
auto formatting_element_index = m_list_of_active_formatting_elements.find_index(*formatting_element);
|
|
||||||
if (formatting_element_index.has_value() && formatting_element_index.value() < bookmark)
|
if (formatting_element_index.has_value() && formatting_element_index.value() < bookmark)
|
||||||
bookmark--;
|
bookmark--;
|
||||||
m_list_of_active_formatting_elements.remove(*formatting_element);
|
m_list_of_active_formatting_elements.remove(*formatting_element);
|
||||||
m_list_of_active_formatting_elements.insert_at(bookmark, *element);
|
m_list_of_active_formatting_elements.insert_at(bookmark, *element, *token_data);
|
||||||
|
|
||||||
// 19. Remove formattingElement from the stack of open elements, and insert the new element
|
// 19. Remove formattingElement from the stack of open elements, and insert the new element
|
||||||
// into the stack of open elements immediately below the position of furthestBlock in that stack.
|
// into the stack of open elements immediately below the position of furthestBlock in that stack.
|
||||||
|
|
@ -2626,7 +2625,7 @@ void HTMLParser::handle_in_body(HTMLToken& token)
|
||||||
|
|
||||||
// Insert an HTML element for the token. Push onto the list of active formatting elements that element.
|
// Insert an HTML element for the token. Push onto the list of active formatting elements that element.
|
||||||
auto element = insert_html_element(token);
|
auto element = insert_html_element(token);
|
||||||
m_list_of_active_formatting_elements.add(*element);
|
m_list_of_active_formatting_elements.add(*element, token);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2637,7 +2636,7 @@ void HTMLParser::handle_in_body(HTMLToken& token)
|
||||||
|
|
||||||
// Insert an HTML element for the token. Push onto the list of active formatting elements that element.
|
// Insert an HTML element for the token. Push onto the list of active formatting elements that element.
|
||||||
auto element = insert_html_element(token);
|
auto element = insert_html_element(token);
|
||||||
m_list_of_active_formatting_elements.add(*element);
|
m_list_of_active_formatting_elements.add(*element, token);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2655,7 +2654,7 @@ void HTMLParser::handle_in_body(HTMLToken& token)
|
||||||
|
|
||||||
// Insert an HTML element for the token. Push onto the list of active formatting elements that element.
|
// Insert an HTML element for the token. Push onto the list of active formatting elements that element.
|
||||||
auto element = insert_html_element(token);
|
auto element = insert_html_element(token);
|
||||||
m_list_of_active_formatting_elements.add(*element);
|
m_list_of_active_formatting_elements.add(*element, token);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2020-2022, Andreas Kling <andreas@ladybird.org>
|
* Copyright (c) 2020-2022, Andreas Kling <andreas@ladybird.org>
|
||||||
|
* Copyright (c) 2025, Lorenz Ackermann <me@lorenzackermann.xyz>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
@ -20,7 +21,7 @@ void ListOfActiveFormattingElements::visit_edges(JS::Cell::Visitor& visitor)
|
||||||
|
|
||||||
void ListOfActiveFormattingElements::ensure_noahs_ark_clause(DOM::Element& element)
|
void ListOfActiveFormattingElements::ensure_noahs_ark_clause(DOM::Element& element)
|
||||||
{
|
{
|
||||||
Vector<Entry> possible_matches;
|
Vector<Entry&> possible_matches;
|
||||||
for (size_t i = m_entries.size(); i > 0;) {
|
for (size_t i = m_entries.size(); i > 0;) {
|
||||||
i--;
|
i--;
|
||||||
auto& entry = m_entries[i];
|
auto& entry = m_entries[i];
|
||||||
|
|
@ -28,7 +29,7 @@ void ListOfActiveFormattingElements::ensure_noahs_ark_clause(DOM::Element& eleme
|
||||||
break;
|
break;
|
||||||
if (entry.element->local_name() == element.local_name()
|
if (entry.element->local_name() == element.local_name()
|
||||||
&& entry.element->namespace_uri() == element.namespace_uri()
|
&& entry.element->namespace_uri() == element.namespace_uri()
|
||||||
&& entry.element->attribute_list_size() == element.attribute_list_size())
|
&& entry.token->attribute_count() == element.attribute_list_size())
|
||||||
possible_matches.append(entry);
|
possible_matches.append(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -38,7 +39,7 @@ void ListOfActiveFormattingElements::ensure_noahs_ark_clause(DOM::Element& eleme
|
||||||
// FIXME: the attributes should be compared as they where created by the parser
|
// FIXME: the attributes should be compared as they where created by the parser
|
||||||
element.for_each_attribute([&](auto& name, auto& value) {
|
element.for_each_attribute([&](auto& name, auto& value) {
|
||||||
possible_matches.remove_all_matching([&](auto& entry) {
|
possible_matches.remove_all_matching([&](auto& entry) {
|
||||||
auto attr = entry.element->get_attribute(name);
|
auto attr = entry.token->attribute(name);
|
||||||
return !attr.has_value() || attr != value;
|
return !attr.has_value() || attr != value;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -49,8 +50,19 @@ void ListOfActiveFormattingElements::ensure_noahs_ark_clause(DOM::Element& eleme
|
||||||
remove(*possible_matches.last().element);
|
remove(*possible_matches.last().element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AK::OwnPtr<HTMLToken> ListOfActiveFormattingElements::create_own_token(HTMLToken& token)
|
||||||
|
{
|
||||||
|
auto new_token = make<HTMLToken>(token.type());
|
||||||
|
new_token->set_tag_name(token.tag_name());
|
||||||
|
token.for_each_attribute([&](auto const& attribute) {
|
||||||
|
new_token->add_attribute(attribute);
|
||||||
|
return IterationDecision::Continue;
|
||||||
|
});
|
||||||
|
return new_token;
|
||||||
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/parsing.html#push-onto-the-list-of-active-formatting-elements
|
// https://html.spec.whatwg.org/multipage/parsing.html#push-onto-the-list-of-active-formatting-elements
|
||||||
void ListOfActiveFormattingElements::add(DOM::Element& element)
|
void ListOfActiveFormattingElements::add(DOM::Element& element, HTMLToken& token)
|
||||||
{
|
{
|
||||||
// 1. If there are already three elements in the list of active formatting elements after the last marker, if any, or anywhere in the list if there are no markers,
|
// 1. If there are already three elements in the list of active formatting elements after the last marker, if any, or anywhere in the list if there are no markers,
|
||||||
// that have the same tag name, namespace, and attributes as element, then remove the earliest such element from the list of active formatting elements.
|
// that have the same tag name, namespace, and attributes as element, then remove the earliest such element from the list of active formatting elements.
|
||||||
|
|
@ -58,12 +70,12 @@ void ListOfActiveFormattingElements::add(DOM::Element& element)
|
||||||
// can be paired such that the two attributes in each pair have identical names, namespaces, and values (the order of the attributes does not matter).
|
// can be paired such that the two attributes in each pair have identical names, namespaces, and values (the order of the attributes does not matter).
|
||||||
ensure_noahs_ark_clause(element);
|
ensure_noahs_ark_clause(element);
|
||||||
// 2. Add element to the list of active formatting elements.
|
// 2. Add element to the list of active formatting elements.
|
||||||
m_entries.append({ element });
|
m_entries.append({ element, create_own_token(token) });
|
||||||
}
|
}
|
||||||
|
|
||||||
void ListOfActiveFormattingElements::add_marker()
|
void ListOfActiveFormattingElements::add_marker()
|
||||||
{
|
{
|
||||||
m_entries.append({ nullptr });
|
m_entries.append({ nullptr, nullptr });
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ListOfActiveFormattingElements::contains(DOM::Element const& element) const
|
bool ListOfActiveFormattingElements::contains(DOM::Element const& element) const
|
||||||
|
|
@ -112,17 +124,20 @@ Optional<size_t> ListOfActiveFormattingElements::find_index(DOM::Element const&
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void ListOfActiveFormattingElements::replace(DOM::Element& to_remove, DOM::Element& to_add)
|
void ListOfActiveFormattingElements::replace(DOM::Element& to_remove, DOM::Element& to_add, HTMLToken& token)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < m_entries.size(); i++) {
|
for (auto& entry : m_entries) {
|
||||||
if (m_entries[i].element.ptr() == &to_remove)
|
if (entry.element.ptr() == &to_remove) {
|
||||||
m_entries[i].element = GC::make_root(to_add);
|
entry.element = GC::make_root(to_add);
|
||||||
|
entry.token = create_own_token(token);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ListOfActiveFormattingElements::insert_at(size_t index, DOM::Element& element)
|
void ListOfActiveFormattingElements::insert_at(size_t index, DOM::Element& element, HTMLToken& token)
|
||||||
{
|
{
|
||||||
m_entries.insert(index, { element });
|
m_entries.insert(index, { element, create_own_token(token) });
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include <LibWeb/DOM/Element.h>
|
#include <LibWeb/DOM/Element.h>
|
||||||
#include <LibWeb/Forward.h>
|
#include <LibWeb/Forward.h>
|
||||||
|
#include <LibWeb/HTML/Parser/HTMLToken.h>
|
||||||
|
|
||||||
namespace Web::HTML {
|
namespace Web::HTML {
|
||||||
|
|
||||||
|
|
@ -20,16 +21,17 @@ public:
|
||||||
bool is_marker() const { return !element; }
|
bool is_marker() const { return !element; }
|
||||||
|
|
||||||
GC::Ptr<DOM::Element> element;
|
GC::Ptr<DOM::Element> element;
|
||||||
|
AK::OwnPtr<HTMLToken> token;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool is_empty() const { return m_entries.is_empty(); }
|
bool is_empty() const { return m_entries.is_empty(); }
|
||||||
bool contains(DOM::Element const&) const;
|
bool contains(DOM::Element const&) const;
|
||||||
|
|
||||||
void add(DOM::Element& element);
|
void add(DOM::Element& element, HTMLToken& token);
|
||||||
void add_marker();
|
void add_marker();
|
||||||
void insert_at(size_t index, DOM::Element& element);
|
void insert_at(size_t index, DOM::Element& element, HTMLToken& token);
|
||||||
|
|
||||||
void replace(DOM::Element& to_remove, DOM::Element& to_add);
|
void replace(DOM::Element& to_remove, DOM::Element& to_add, HTMLToken& token);
|
||||||
|
|
||||||
void remove(DOM::Element&);
|
void remove(DOM::Element&);
|
||||||
|
|
||||||
|
|
@ -44,6 +46,8 @@ public:
|
||||||
|
|
||||||
void visit_edges(JS::Cell::Visitor&);
|
void visit_edges(JS::Cell::Visitor&);
|
||||||
|
|
||||||
|
static AK::OwnPtr<HTMLToken> create_own_token(HTMLToken& token);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Vector<Entry> m_entries;
|
Vector<Entry> m_entries;
|
||||||
void ensure_noahs_ark_clause(DOM::Element& element);
|
void ensure_noahs_ark_clause(DOM::Element& element);
|
||||||
|
|
|
||||||
|
|
@ -2,5 +2,5 @@ Harness status: OK
|
||||||
|
|
||||||
Found 1 tests
|
Found 1 tests
|
||||||
|
|
||||||
1 Fail
|
1 Pass
|
||||||
Fail html5lib_scripted_adoption01.html 8970fe21b551a270aa74648bb2e8b905edb54522
|
Pass html5lib_scripted_adoption01.html 8970fe21b551a270aa74648bb2e8b905edb54522
|
||||||
|
|
@ -2,5 +2,5 @@ Harness status: OK
|
||||||
|
|
||||||
Found 1 tests
|
Found 1 tests
|
||||||
|
|
||||||
1 Fail
|
1 Pass
|
||||||
Fail html5lib_scripted_ark.html b9a7cd0310cab4fd4eb77aed9149b966918e7ca2
|
Pass html5lib_scripted_ark.html b9a7cd0310cab4fd4eb77aed9149b966918e7ca2
|
||||||
|
|
@ -2,10 +2,9 @@ Harness status: OK
|
||||||
|
|
||||||
Found 9 tests
|
Found 9 tests
|
||||||
|
|
||||||
8 Pass
|
9 Pass
|
||||||
1 Fail
|
|
||||||
Pass html5lib_tricky01.html 06f0a6904729cd6a3ab91f3121c0b0eb54ee04d2
|
Pass html5lib_tricky01.html 06f0a6904729cd6a3ab91f3121c0b0eb54ee04d2
|
||||||
Fail html5lib_tricky01.html c99581b7d1d8c1cd421054891981c3fe8267e83c
|
Pass html5lib_tricky01.html c99581b7d1d8c1cd421054891981c3fe8267e83c
|
||||||
Pass html5lib_tricky01.html 09ba1d973acb46344442ea1e77a37de8736ce6e7
|
Pass html5lib_tricky01.html 09ba1d973acb46344442ea1e77a37de8736ce6e7
|
||||||
Pass html5lib_tricky01.html 9e40dd21a29521d60a43cb016f4100501ea26ec8
|
Pass html5lib_tricky01.html 9e40dd21a29521d60a43cb016f4100501ea26ec8
|
||||||
Pass html5lib_tricky01.html 23bed40fe77c77e3119528d9f77e041eeb77eebb
|
Pass html5lib_tricky01.html 23bed40fe77c77e3119528d9f77e041eeb77eebb
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue