From e2740bd19d1bb8ead186476ad5bc7c4022507e1c Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Wed, 16 Aug 2023 10:58:12 +0200 Subject: [PATCH] LibWeb: Don't overwrite existing text content when flushing HTML parser If we run an inline script from the HTML parser, it may append a text node to the current insertion point. If there was text content immediately following the script element, we would previously overwrite the script-inserted text content, due to an oversight in the way we select an appropriate insertion point This patch fixes the issue by only inserting parser content into existing text nodes if they are empty. --- .../scripted-dom-insertion-during-html-parse.txt | 1 + .../scripted-dom-insertion-during-html-parse.html | 4 ++++ Userland/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp | 11 ++++++++--- 3 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 Tests/LibWeb/Text/expected/scripted-dom-insertion-during-html-parse.txt create mode 100644 Tests/LibWeb/Text/input/scripted-dom-insertion-during-html-parse.html diff --git a/Tests/LibWeb/Text/expected/scripted-dom-insertion-during-html-parse.txt b/Tests/LibWeb/Text/expected/scripted-dom-insertion-during-html-parse.txt new file mode 100644 index 0000000000..e5fc1a4a37 --- /dev/null +++ b/Tests/LibWeb/Text/expected/scripted-dom-insertion-during-html-parse.txt @@ -0,0 +1 @@ + PASS \ No newline at end of file diff --git a/Tests/LibWeb/Text/input/scripted-dom-insertion-during-html-parse.html b/Tests/LibWeb/Text/input/scripted-dom-insertion-during-html-parse.html new file mode 100644 index 0000000000..51c44c98d1 --- /dev/null +++ b/Tests/LibWeb/Text/input/scripted-dom-insertion-during-html-parse.html @@ -0,0 +1,4 @@ + + diff --git a/Userland/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp b/Userland/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp index 96747702a3..60ae51dc42 100644 --- a/Userland/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp +++ b/Userland/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp @@ -998,11 +998,16 @@ void HTMLParser::parse_generic_raw_text_element(HTMLToken& token) m_insertion_mode = InsertionMode::Text; } +static bool is_empty_text_node(DOM::Node const* node) +{ + return node && node->is_text() && static_cast(node)->data().is_empty(); +} + DOM::Text* HTMLParser::find_character_insertion_node() { auto adjusted_insertion_location = find_appropriate_place_for_inserting_node(); if (adjusted_insertion_location.insert_before_sibling) { - if (adjusted_insertion_location.insert_before_sibling->previous_sibling() && adjusted_insertion_location.insert_before_sibling->previous_sibling()->is_text()) + if (is_empty_text_node(adjusted_insertion_location.insert_before_sibling->previous_sibling())) return static_cast(adjusted_insertion_location.insert_before_sibling->previous_sibling()); auto new_text_node = realm().heap().allocate(realm(), document(), ""); adjusted_insertion_location.parent->insert_before(*new_text_node, *adjusted_insertion_location.insert_before_sibling); @@ -1010,8 +1015,8 @@ DOM::Text* HTMLParser::find_character_insertion_node() } if (adjusted_insertion_location.parent->is_document()) return nullptr; - if (adjusted_insertion_location.parent->last_child() && adjusted_insertion_location.parent->last_child()->is_text()) - return verify_cast(adjusted_insertion_location.parent->last_child()); + if (is_empty_text_node(adjusted_insertion_location.parent->last_child())) + return static_cast(adjusted_insertion_location.parent->last_child()); auto new_text_node = realm().heap().allocate(realm(), document(), ""); MUST(adjusted_insertion_location.parent->append_child(*new_text_node)); return new_text_node;