diff options
author | Luke Wilde <lukew@serenityos.org> | 2022-02-20 03:29:24 +0000 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2022-02-20 10:59:42 +0100 |
commit | 9845164f6ababac0d85e236bd954c6b88567c0a7 (patch) | |
tree | 5d2b0f5449bbae096cea6b6c5642e1c59bf74513 /Userland/Libraries | |
parent | 655f054b4fa2ed6239f61071ad1c44e85548711c (diff) | |
download | serenity-9845164f6ababac0d85e236bd954c6b88567c0a7.zip |
LibWeb: Handle markers when reconstructing active formatting elements
The entry we get from the active formatting elements list during the
Rewind step of "reconstruct the active formatting elements" can be a
marker. Previously we assumed it was not a marker, which can trigger
an assertion failure with certain malformed HTML.
If the entry in this step is a marker, the spec simply ignores it.
This is step 6 of the algorithm.
This also makes the index unsigned, as this algorithm is a no-op if
the list is empty.
Additionally, this also adds spec comments to this algorithm.
Fixes #12668.
Diffstat (limited to 'Userland/Libraries')
-rw-r--r-- | Userland/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp | 40 |
1 files changed, 25 insertions, 15 deletions
diff --git a/Userland/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp b/Userland/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp index da5f1d43a6..878fbc950b 100644 --- a/Userland/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp +++ b/Userland/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp @@ -1025,47 +1025,57 @@ void HTMLParser::handle_after_after_body(HTMLToken& token) process_using_the_rules_for(m_insertion_mode, token); } +// https://html.spec.whatwg.org/multipage/parsing.html#reconstruct-the-active-formatting-elements void HTMLParser::reconstruct_the_active_formatting_elements() { - // FIXME: This needs to care about "markers" - + // 1. If there are no entries in the list of active formatting elements, then there is nothing to reconstruct; stop this algorithm. if (m_list_of_active_formatting_elements.is_empty()) return; + // 2. If the last (most recently added) entry in the list of active formatting elements is a marker, or if it is an element that is in the stack of open elements, + // then there is nothing to reconstruct; stop this algorithm. if (m_list_of_active_formatting_elements.entries().last().is_marker()) return; if (m_stack_of_open_elements.contains(*m_list_of_active_formatting_elements.entries().last().element)) return; - ssize_t index = m_list_of_active_formatting_elements.entries().size() - 1; - RefPtr<DOM::Element> entry = m_list_of_active_formatting_elements.entries().at(index).element; - VERIFY(entry); + // 3. Let entry be the last (most recently added) element in the list of active formatting elements. + size_t index = m_list_of_active_formatting_elements.entries().size() - 1; + + // NOTE: Entry will never be null, but must be a pointer instead of a reference to allow rebinding. + auto* entry = &m_list_of_active_formatting_elements.entries().at(index); Rewind: - if (index == 0) { + // 4. Rewind: If there are no entries before entry in the list of active formatting elements, then jump to the step labeled create. + if (index == 0) goto Create; - } + // 5. Let entry be the entry one earlier than entry in the list of active formatting elements. --index; - entry = m_list_of_active_formatting_elements.entries().at(index).element; - VERIFY(entry); + entry = &m_list_of_active_formatting_elements.entries().at(index); - if (!m_stack_of_open_elements.contains(*entry)) + // 6. If entry is neither a marker nor an element that is also in the stack of open elements, go to the step labeled rewind. + if (!entry->is_marker() && !m_stack_of_open_elements.contains(*entry->element)) goto Rewind; Advance: + // 7. Advance: Let entry be the element one later than entry in the list of active formatting elements. ++index; - entry = m_list_of_active_formatting_elements.entries().at(index).element; - VERIFY(entry); + entry = &m_list_of_active_formatting_elements.entries().at(index); Create: + // 8. Create: Insert an HTML element for the token for which the element entry was created, to obtain new element. + VERIFY(!entry->is_marker()); + // FIXME: Hold on to the real token! - auto new_element = insert_html_element(HTMLToken::make_start_tag(entry->local_name())); + auto new_element = insert_html_element(HTMLToken::make_start_tag(entry->element->local_name())); - m_list_of_active_formatting_elements.entries().at(index).element = *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; - if (index != (ssize_t)m_list_of_active_formatting_elements.entries().size() - 1) + // 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) goto Advance; } |