Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 18 additions & 19 deletions Libraries/LibWeb/DOM/Document.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,7 @@ WebIDL::ExceptionOr<GC::Ref<Document>> Document::create_and_initialize(Type type
document->m_about_base_url = navigation_params.about_base_url;
document->set_url(*creation_url);
document->m_readiness = HTML::DocumentReadyState::Loading;
document->set_allow_declarative_shadow_roots(true);
document->set_allow_declarative_shadow_roots(HTML::HTMLParser::AllowDeclarativeShadowRoots::Yes);
document->set_custom_element_registry(realm.create<HTML::CustomElementRegistry>(realm));

document->m_window = window;
Expand Down Expand Up @@ -595,12 +595,7 @@ Document::~Document() = default;
void Document::set_temporary_document_for_fragment_parsing(Badge<HTML::HTMLParser>)
{
// https://html.spec.whatwg.org/multipage/parsing.html#html-fragment-parsing-algorithm
// AD-HOC: The HTML fragment parsing algorithm stages nodes in a temporary document before returning them.
// Treat that document as disconnected so post-connection steps happen only after the fragment is inserted
// into the context document.
// Spec issue: https://github.com/whatwg/html/issues/11023
m_temporary_document_for_fragment_parsing = true;
set_is_connected(false);
}

void Document::set_style_invalidation_counter_dump_interval(Optional<u64> interval)
Expand Down Expand Up @@ -1055,16 +1050,23 @@ WebIDL::ExceptionOr<Document*> Document::open(Optional<String> const&, Optional<
// 15. Set document to no-quirks mode.
set_quirks_mode(QuirksMode::No);

// 16. Create a new HTML parser and associate it with document. This is a script-created parser (meaning that it can be closed by the document.open() and document.close() methods, and that the tokenizer will wait for an explicit call to document.close() before emitting an end-of-file token). The encoding confidence is irrelevant.
// 16. Create an HTML parser whose allow declarative shadow roots is document's allow declarative shadow roots, and
// associate it with document. This is a script-created parser (meaning that it can be closed by the document.open()
// and document.close() methods, and that the tokenizer will wait for an explicit call to document.close() before
// emitting an end-of-file token). The encoding confidence is irrelevant.
m_parser = HTML::HTMLParser::create_for_scripting(*this);
m_parser->set_allow_declarative_shadow_roots(allow_declarative_shadow_roots());

// 17. Set the insertion point to point at just before the end of the input stream (which at this point will be empty).
m_parser->tokenizer().update_insertion_point();

// 18. Update the current document readiness of document to "loading".
// 18. Set the parser's allow declarative shadow roots to true.
m_parser->set_allow_declarative_shadow_roots(HTML::HTMLParser::AllowDeclarativeShadowRoots::Yes);

// 19. Update the current document readiness of document to "loading".
update_readiness(HTML::DocumentReadyState::Loading);

// 19. Return document.
// 20. Return document.
return this;
}

Expand Down Expand Up @@ -5456,11 +5458,6 @@ GC::Ref<DOM::Document> Document::appropriate_template_contents_owner_document()
if (document_type() == Type::HTML)
new_document->set_document_type(Type::HTML);

// AD-HOC: Copy over the "allow declarative shadow roots" flag, otherwise no elements inside templates will
// be able to have declarative shadow roots.
// Spec issue: https://github.com/whatwg/html/issues/11955
new_document->set_allow_declarative_shadow_roots(allow_declarative_shadow_roots());

// 3. Set document's associated inert template document to newDocument.
m_associated_inert_template_document = new_document;
}
Expand Down Expand Up @@ -7599,7 +7596,7 @@ Vector<GC::Root<Range>> Document::find_matching_text(String const& query, CaseSe
}

// https://dom.spec.whatwg.org/#document-allow-declarative-shadow-roots
bool Document::allow_declarative_shadow_roots() const
HTML::HTMLParser::AllowDeclarativeShadowRoots Document::allow_declarative_shadow_roots() const
{
return m_allow_declarative_shadow_roots;
}
Expand Down Expand Up @@ -7930,7 +7927,7 @@ void Document::unfullscreen_element(GC::Ref<Element> element)
}

// https://dom.spec.whatwg.org/#document-allow-declarative-shadow-roots
void Document::set_allow_declarative_shadow_roots(bool allow)
void Document::set_allow_declarative_shadow_roots(HTML::HTMLParser::AllowDeclarativeShadowRoots allow)
{
m_allow_declarative_shadow_roots = allow;
}
Expand All @@ -7941,11 +7938,13 @@ void Document::parse_html_from_a_string(Utf16View html)
// 1. Set document's type to "html".
set_document_type(DOM::Document::Type::HTML);

// 2. Create an HTML parser parser, associated with document.
// 2. Let parser be a new HTML parser whose allow declarative shadow roots is document's allow declarative shadow roots,
// associated with document.
// 3. Place html into the input stream for parser. The encoding confidence is irrelevant.
// FIXME: We don't have the concept of encoding confidence yet.
auto scripting_mode = is_scripting_enabled() ? HTML::ParserScriptingMode::Normal : HTML::ParserScriptingMode::Disabled;
auto parser = HTML::HTMLParser::create_for_decoded_string(*this, html, scripting_mode, "UTF-8"sv);
parser->set_allow_declarative_shadow_roots(allow_declarative_shadow_roots());

// 4. Start parser and let it run until it has consumed all the characters just inserted into the input stream.
parser->run(as<HTML::Window>(HTML::relevant_global_object(*this)).associated_document().url());
Expand All @@ -7971,7 +7970,7 @@ WebIDL::ExceptionOr<GC::Root<DOM::Document>> Document::parse_html_unsafe(JS::VM&
document->set_content_type("text/html"_string);

// 3. Set document's allow declarative shadow roots to true.
document->set_allow_declarative_shadow_roots(true);
document->set_allow_declarative_shadow_roots(HTML::HTMLParser::AllowDeclarativeShadowRoots::Yes);

// 4. Parse HTML from a string given document and compliantHTML.
document->parse_html_from_a_string(compliant_html.utf16_view());
Expand All @@ -7980,7 +7979,7 @@ WebIDL::ExceptionOr<GC::Root<DOM::Document>> Document::parse_html_unsafe(JS::VM&
auto& associated_document = as<HTML::Window>(realm.global_object()).associated_document();
document->set_origin(associated_document.origin());

// 5. Return document.
// 4. Return document.
return document;
}

Expand Down
7 changes: 4 additions & 3 deletions Libraries/LibWeb/DOM/Document.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
#include <LibWeb/HTML/DocumentReadyState.h>
#include <LibWeb/HTML/Focus.h>
#include <LibWeb/HTML/PaintConfig.h>
#include <LibWeb/HTML/Parser/HTMLParser.h>
#include <LibWeb/HTML/PreloadEntry.h>
#include <LibWeb/HTML/SandboxingFlagSet.h>
#include <LibWeb/HTML/Scripting/ScriptRegistry.h>
Expand Down Expand Up @@ -612,8 +613,8 @@ class WEB_API Document
bool is_fully_active() const;
bool is_active() const;

[[nodiscard]] bool allow_declarative_shadow_roots() const;
void set_allow_declarative_shadow_roots(bool);
[[nodiscard]] HTML::HTMLParser::AllowDeclarativeShadowRoots allow_declarative_shadow_roots() const;
void set_allow_declarative_shadow_roots(HTML::HTMLParser::AllowDeclarativeShadowRoots allow_declarative_shadow_roots);

GC::Ref<HTML::History> history();
GC::Ref<HTML::History> history() const;
Expand Down Expand Up @@ -1605,7 +1606,7 @@ class WEB_API Document
GC::Ptr<HTML::HTMLDialogElement> m_dialog_pointerdown_target;

// https://dom.spec.whatwg.org/#document-allow-declarative-shadow-roots
bool m_allow_declarative_shadow_roots { false };
HTML::HTMLParser::AllowDeclarativeShadowRoots m_allow_declarative_shadow_roots { HTML::HTMLParser::AllowDeclarativeShadowRoots::No };

// https://w3c.github.io/selection-api/#dfn-has-scheduled-selectionchange-event
bool m_has_scheduled_selectionchange_event { false };
Expand Down
4 changes: 3 additions & 1 deletion Libraries/LibWeb/DOM/DocumentLoading.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,8 @@ static WebIDL::ExceptionOr<GC::Ref<DOM::Document>> load_html_document(HTML::Navi
}));
}

// 3. Otherwise, create an HTML parser and associate it with the document.
// 3. Otherwise, create an HTML parser whose allow declarative shadow roots is true and associate it with document.
//
// Each task that the networking task source places on the task queue while fetching runs must then fill the
// parser's input byte stream with the fetched bytes and cause the HTML parser to perform the appropriate
// processing of the input stream.
Expand All @@ -141,6 +142,7 @@ static WebIDL::ExceptionOr<GC::Ref<DOM::Document>> load_html_document(HTML::Navi
else {
auto body = GC::Ref { *navigation_params.response->body() };
auto parser = HTML::IncrementalDocumentParser::create(document, body, navigation_params.response->url().value(), Fetch::Infrastructure::extract_mime_type(navigation_params.response->header_list()));
parser->set_allow_declarative_shadow_roots(HTML::HTMLParser::AllowDeclarativeShadowRoots::Yes);
parser->start();
}

Expand Down
67 changes: 28 additions & 39 deletions Libraries/LibWeb/DOM/Element.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
#include <LibWeb/DOM/Attr.h>
#include <LibWeb/DOM/DOMTokenList.h>
#include <LibWeb/DOM/Document.h>
#include <LibWeb/DOM/DocumentFragment.h>
#include <LibWeb/DOM/Element.h>
#include <LibWeb/DOM/ElementFactory.h>
#include <LibWeb/DOM/HTMLCollection.h>
Expand Down Expand Up @@ -1523,27 +1524,29 @@ WebIDL::ExceptionOr<void> Element::set_inner_html(TrustedTypes::TrustedHTMLOrStr
TrustedTypes::InjectionSink::Element_innerHTML,
TrustedTypes::Script.to_string()));

// 2. Let context be this.
DOM::Node* context = this;
// 2. Let target be this.
Variant<GC::Ref<Element>, GC::Ref<DocumentFragment>> target = GC::Ref { *this };

// 3. Let fragment be the result of invoking the fragment parsing algorithm steps with context and compliantString.
auto fragment = TRY(as<Element>(*context).parse_fragment(compliant_string.utf16_view()));

// 4. If context is a template element, then set context to the template element's template contents (a DocumentFragment).
auto* template_element = as_if<HTML::HTMLTemplateElement>(*context);
// 3. If target is a template element, then set target to the template element's template contents (a DocumentFragment).
auto* template_element = as_if<HTML::HTMLTemplateElement>(*this);
if (template_element)
context = template_element->content();
target = template_element->content();

// 4. Let fragment be the result of invoking the fragment parsing algorithm steps with target and compliantString.
auto fragment = TRY(parse_fragment(target, compliant_string.utf16_view()));

// 5. Replace all with fragment within context.
context->replace_all(fragment);
// 5. Replace all with fragment within target.
target.visit([&](auto node) {
node->replace_all(fragment);
});

// NOTE: We don't invalidate style & layout for <template> elements since they don't affect rendering.
if (!template_element) {
context->set_needs_style_update(true);
set_needs_style_update(true);

if (context->is_connected()) {
if (is_connected()) {
// NOTE: Since the DOM has changed, we have to rebuild the layout tree.
context->set_needs_layout_tree_update(true, DOM::SetNeedsLayoutTreeUpdateReason::ElementSetInnerHTML);
set_needs_layout_tree_update(true, DOM::SetNeedsLayoutTreeUpdateReason::ElementSetInnerHTML);
}
}

Expand Down Expand Up @@ -2650,32 +2653,18 @@ bool Element::is_actually_disabled() const
}

// https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#fragment-parsing-algorithm-steps
WebIDL::ExceptionOr<GC::Ref<DOM::DocumentFragment>> Element::parse_fragment(Utf16View markup, HTML::ParserScriptingMode scripting_mode)
WebIDL::ExceptionOr<GC::Ref<DOM::DocumentFragment>> Element::parse_fragment(Variant<GC::Ref<Element>, GC::Ref<DocumentFragment>> target, Utf16View markup, HTML::ParserScriptingMode scripting_mode)
{
// 1. Assert: scriptingMode is either Inert or Fragment.
VERIFY(scripting_mode == HTML::ParserScriptingMode::Inert || scripting_mode == HTML::ParserScriptingMode::Fragment);

// 2. Let newChildren be null.
Vector<GC::Root<Node>> new_children;

// 3. If context's node document is an XML document, then set newChildren to the result of invoking the XML fragment parsing algorithm given context and markup.
if (document().is_xml_document()) {
new_children = TRY(XMLFragmentParser::parse_xml_fragment(*this, markup));
}
// 4. Otherwise, set newChildren to the result of invoking the HTML fragment parsing algorithm given context, markup, false, and scriptingMode.
else {
new_children = TRY(HTML::HTMLParser::parse_html_fragment(*this, markup, HTML::HTMLParser::AllowDeclarativeShadowRoots::No, scripting_mode));
}

// 5. Let fragment be a new DocumentFragment whose node document is context's node document.
auto fragment = realm().create<DOM::DocumentFragment>(document());

// 6. For each node of newChildren, in tree order: append node to fragment.
for (auto& child : new_children)
TRY(fragment->append_child(*child));
// 2. If target's node document is an XML document, then return the result of invoking the XML fragment parsing
// algorithm given target and markup.
if (target.visit([](auto node) { return node->document().is_xml_document(); }))
return XMLFragmentParser::parse_xml_fragment(target, markup);

// 7. Return fragment.
return fragment;
// 3. Return the result of invoking the HTML fragment parsing algorithm given context, markup, false, and scriptingMode.
return HTML::HTMLParser::parse_html_fragment(target, markup, HTML::HTMLParser::AllowDeclarativeShadowRoots::No, scripting_mode);
}

// https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-element-outerhtml
Expand Down Expand Up @@ -2712,7 +2701,7 @@ WebIDL::ExceptionOr<void> Element::set_outer_html(TrustedTypes::TrustedHTMLOrStr
parent = TRY(create_element(document(), HTML::TagNames::body, Namespace::HTML));

// 6. Let fragment be the result of invoking the fragment parsing algorithm steps given parent and compliantString.
auto fragment = TRY(as<Element>(*parent).parse_fragment(compliant_string.utf16_view()));
auto fragment = TRY(Element::parse_fragment(GC::Ref { as<Element>(*parent) }, compliant_string.utf16_view()));

// 6. Replace this with fragment within this's parent.
TRY(this->parent()->replace_child(fragment, *this));
Expand Down Expand Up @@ -2773,7 +2762,7 @@ WebIDL::ExceptionOr<void> Element::insert_adjacent_html(String const& position,
}

// 5. Let fragment be the result of invoking the fragment parsing algorithm steps with context and compliantString.
auto fragment = TRY(as<Element>(*context).parse_fragment(compliant_string.utf16_view()));
auto fragment = TRY(Element::parse_fragment(GC::Ref { as<Element>(*context) }, compliant_string.utf16_view()));

// 6. Use the first matching item from this list:

Expand Down Expand Up @@ -4877,12 +4866,12 @@ WebIDL::ExceptionOr<void> Element::set_html_unsafe(TrustedTypes::TrustedHTMLOrSt
TrustedTypes::Script.to_string()));

// 2. Let target be this's template contents if this is a template element; otherwise this.
DOM::Node* target = this;
Variant<GC::Ref<DOM::Element>, GC::Ref<DOM::DocumentFragment>> target = GC::Ref { *this };
if (is<HTML::HTMLTemplateElement>(*this))
target = as<HTML::HTMLTemplateElement>(*this).content().ptr();
target = as<HTML::HTMLTemplateElement>(*this).content();

// 3. Unsafe set HTML given target, this, and compliantHTML.
TRY(target->unsafely_set_html(*this, compliant_html.utf16_view()));
TRY(unsafely_set_html(target, compliant_html.utf16_view()));

return {};
}
Expand Down
2 changes: 1 addition & 1 deletion Libraries/LibWeb/DOM/Element.h
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ class WEB_API Element
CSS::StyleSheetList& document_or_shadow_root_style_sheets();
ElementByIdMap& document_or_shadow_root_element_by_id_map();

WebIDL::ExceptionOr<GC::Ref<DOM::DocumentFragment>> parse_fragment(Utf16View markup, HTML::ParserScriptingMode = HTML::ParserScriptingMode::Inert);
static WebIDL::ExceptionOr<GC::Ref<DOM::DocumentFragment>> parse_fragment(Variant<GC::Ref<Element>, GC::Ref<DocumentFragment>> target, Utf16View markup, HTML::ParserScriptingMode = HTML::ParserScriptingMode::Inert);

[[nodiscard]] GC::Ptr<Element const> element_to_inherit_style_from(Optional<CSS::PseudoElement>) const;

Expand Down
21 changes: 8 additions & 13 deletions Libraries/LibWeb/DOM/Node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2309,21 +2309,16 @@ WebIDL::ExceptionOr<Utf16String> Node::serialize_fragment(HTML::RequireWellForme
}

// https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#unsafely-set-html
WebIDL::ExceptionOr<void> Node::unsafely_set_html(Element& context_element, Utf16View html)
WebIDL::ExceptionOr<void> Node::unsafely_set_html(Variant<GC::Ref<Element>, GC::Ref<DocumentFragment>> target, Utf16View html)
{
// 1. Let newChildren be the result of the HTML fragment parsing algorithm given contextElement, html, and true.
auto new_children = TRY(HTML::HTMLParser::parse_html_fragment(context_element, html, HTML::HTMLParser::AllowDeclarativeShadowRoots::Yes));
// FIXME: Update for sanitizer API.
// 7. Let fragment be the result of invoking the HTML fragment parsing algorithm given target, html, true, and scriptingMode.
auto fragment = TRY(HTML::HTMLParser::parse_html_fragment(target, html, HTML::HTMLParser::AllowDeclarativeShadowRoots::Yes));

// 2. Let fragment be a new DocumentFragment whose node document is contextElement’s node document.
auto fragment = realm().create<DocumentFragment>(context_element.document());

// 3. For each node in newChildren, append node to fragment.
for (auto& child : new_children)
// I don't know if this can throw here, but let's be safe.
(void)TRY(fragment->append_child(*child));

// 4. Replace all with fragment within contextElement.
replace_all(fragment);
// 9. Replace all with fragment within target.
target.visit([&](auto node) {
node->replace_all(fragment);
});

return {};
}
Expand Down
2 changes: 1 addition & 1 deletion Libraries/LibWeb/DOM/Node.h
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ class WEB_API Node : public EventTarget

WebIDL::ExceptionOr<Utf16String> serialize_fragment(HTML::RequireWellFormed, FragmentSerializationMode = FragmentSerializationMode::Inner) const;

WebIDL::ExceptionOr<void> unsafely_set_html(Element&, Utf16View);
WebIDL::ExceptionOr<void> unsafely_set_html(Variant<GC::Ref<Element>, GC::Ref<DocumentFragment>>, Utf16View);

void replace_all(GC::Ptr<Node>);
void string_replace_all(Utf16String);
Expand Down
2 changes: 1 addition & 1 deletion Libraries/LibWeb/DOM/Range.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1345,7 +1345,7 @@ WebIDL::ExceptionOr<GC::Ref<DocumentFragment>> Range::create_contextual_fragment
}

// 7. Return the result of invoking the fragment parsing algorithm steps with element, compliantString, and Fragment.
return element->parse_fragment(compliant_string.utf16_view(), HTML::ParserScriptingMode::Fragment);
return Element::parse_fragment(GC::Ref { *element }, compliant_string.utf16_view(), HTML::ParserScriptingMode::Fragment);
}

}
Loading