LibWeb: Don't parse inline style sheets during HTML fragment parsing

Some websites (like Reddit) like to instantiate "components" by setting
innerHTML to a huge chunk of stuff. Sometimes those huge chunks of stuff
contain inline style sheets (i.e `<style>` elements).

Before this change, we would end up parsing the CSS in those elements
multiple times, because we had no way of knowing that we were within
a fragment parser's temporary document.

This patch avoids the extra CSS parsing work by adding adding a flag to
Document that tells us it's being used by the fragment parser. Then, we
simply avoid parsing CSS for style elements in such documents. The CSS
then gets parsed immediately upon insertion into the proper DOM.
This commit is contained in:
Andreas Kling 2023-08-09 15:10:00 +02:00
parent 97ebfd9f0f
commit 22a858a0cb
Notes: sideshowbarker 2024-07-17 08:55:54 +09:00
3 changed files with 12 additions and 0 deletions

View file

@ -387,6 +387,9 @@ public:
void set_parser(Badge<HTML::HTMLParser>, HTML::HTMLParser&);
void detach_parser(Badge<HTML::HTMLParser>);
void set_is_temporary_document_for_fragment_parsing(Badge<HTML::HTMLParser>) { m_temporary_document_for_fragment_parsing = true; }
[[nodiscard]] bool is_temporary_document_for_fragment_parsing() const { return m_temporary_document_for_fragment_parsing; }
static bool is_valid_name(DeprecatedString const&);
struct PrefixAndTagName {
@ -688,6 +691,8 @@ private:
bool m_will_declaratively_refresh { false };
RefPtr<Core::Timer> m_active_refresh_timer;
bool m_temporary_document_for_fragment_parsing { false };
};
template<>

View file

@ -23,6 +23,11 @@ namespace Web::DOM {
// https://html.spec.whatwg.org/multipage/semantics.html#update-a-style-block
void StyleElementUtils::update_a_style_block(DOM::Element& style_element)
{
// OPTIMIZATION: Skip parsing CSS if we're in the middle of parsing a HTML fragment.
// The style block will be parsed upon insertion into a proper document.
if (style_element.document().is_temporary_document_for_fragment_parsing())
return;
// 1. Let element be the style element.
// 2. If element has an associated CSS style sheet, remove the CSS style sheet in question.

View file

@ -3665,6 +3665,8 @@ Vector<JS::Handle<DOM::Node>> HTMLParser::parse_html_fragment(DOM::Element& cont
auto temp_document = DOM::Document::create(context_element.realm()).release_value_but_fixme_should_propagate_errors();
temp_document->set_document_type(DOM::Document::Type::HTML);
temp_document->set_is_temporary_document_for_fragment_parsing({});
// 2. If the node document of the context element is in quirks mode, then let the Document be in quirks mode.
// Otherwise, the node document of the context element is in limited-quirks mode, then let the Document be in limited-quirks mode.
// Otherwise, leave the Document in no-quirks mode.