Skip to content

Commit

Permalink
Avoid constructing a DocumentFragment unnecessarily in DOMParser::par…
Browse files Browse the repository at this point in the history
…seFromString()

https://bugs.webkit.org/show_bug.cgi?id=260665

Reviewed by Yusuke Suzuki.

Avoid constructing a DocumentFragment unnecessarily in DOMParser::parseFromString().
Have the HTML fast parser construct the subtree under the <body> element directly
instead.

* Source/WebCore/dom/DocumentFragment.cpp:
(WebCore::DocumentFragment::parseHTML):
* Source/WebCore/html/parser/HTMLDocumentParserFastPath.cpp:
(WebCore::HTMLFastPathParser::HTMLFastPathParser):
(WebCore::HTMLFastPathParser::parseCompleteInput):
(WebCore::tryFastParsingHTMLFragmentImpl):
(WebCore::tryFastParsingHTMLFragment):
* Source/WebCore/html/parser/HTMLDocumentParserFastPath.h:
* Source/WebCore/xml/DOMParser.cpp:
(WebCore::DOMParser::parseFromString):

Canonical link: https://commits.webkit.org/267242@main
  • Loading branch information
cdumez committed Aug 24, 2023
1 parent d4d875b commit 903209c
Show file tree
Hide file tree
Showing 4 changed files with 16 additions and 22 deletions.
4 changes: 3 additions & 1 deletion Source/WebCore/dom/DocumentFragment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,9 @@ void DocumentFragment::parseHTML(const String& source, Element& contextElement,
ASSERT(serializeFragment(*this, SerializedNodes::SubtreesOfChildren) == serializeFragment(referenceFragment, SerializedNodes::SubtreesOfChildren));
#endif
return;
}
} else if (hasChildNodes())
removeChildren();

HTMLDocumentParser::parseDocumentFragment(source, *this, contextElement, parserContentPolicy);
}

Expand Down
24 changes: 10 additions & 14 deletions Source/WebCore/html/parser/HTMLDocumentParserFastPath.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
#include "HTMLDocumentParserFastPath.h"

#include "Document.h"
#include "DocumentFragment.h"
#include "ElementAncestorIteratorInlines.h"
#include "ElementTraversal.h"
#include "FragmentScriptingPermission.h"
Expand Down Expand Up @@ -193,9 +192,9 @@ class HTMLFastPathParser {
static_assert(std::is_same_v<CharacterType, UChar> || std::is_same_v<CharacterType, LChar>);

public:
HTMLFastPathParser(CharacterSpan source, Document& document, DocumentFragment& fragment)
HTMLFastPathParser(CharacterSpan source, Document& document, ContainerNode& destinationParent)
: m_document(document)
, m_fragment(fragment)
, m_destinationParent(destinationParent)
, m_parsingBuffer(source.data(), source.size())
{
}
Expand Down Expand Up @@ -229,7 +228,7 @@ class HTMLFastPathParser {

private:
Document& m_document;
DocumentFragment& m_fragment;
ContainerNode& m_destinationParent;

StringParsingBuffer<CharacterType> m_parsingBuffer;

Expand Down Expand Up @@ -463,7 +462,7 @@ class HTMLFastPathParser {

template<typename ParentTag> void parseCompleteInput()
{
parseChildren<ParentTag>(m_fragment);
parseChildren<ParentTag>(m_destinationParent);
if (m_parsingBuffer.hasCharactersRemaining())
didFail(HTMLFastPathResult::FailedDidntReachEndOfInput);
}
Expand Down Expand Up @@ -888,23 +887,20 @@ static bool canUseFastPath(Element& contextElement, OptionSet<ParserContentPolic
}

template<typename CharacterType>
static bool tryFastParsingHTMLFragmentImpl(const std::span<const CharacterType>& source, Document& document, DocumentFragment& fragment, Element& contextElement)
static bool tryFastParsingHTMLFragmentImpl(const std::span<const CharacterType>& source, Document& document, ContainerNode& destinationParent, Element& contextElement)
{
HTMLFastPathParser parser { source, document, fragment };
bool success = parser.parse(contextElement);
if (!success && fragment.hasChildNodes())
fragment.removeChildren();
return success;
HTMLFastPathParser parser { source, document, destinationParent };
return parser.parse(contextElement);
}

bool tryFastParsingHTMLFragment(const String& source, Document& document, DocumentFragment& fragment, Element& contextElement, OptionSet<ParserContentPolicy> policy)
bool tryFastParsingHTMLFragment(const String& source, Document& document, ContainerNode& destinationParent, Element& contextElement, OptionSet<ParserContentPolicy> policy)
{
if (!canUseFastPath(contextElement, policy))
return false;

if (source.is8Bit())
return tryFastParsingHTMLFragmentImpl(source.span8(), document, fragment, contextElement);
return tryFastParsingHTMLFragmentImpl(source.span16(), document, fragment, contextElement);
return tryFastParsingHTMLFragmentImpl(source.span8(), document, destinationParent, contextElement);
return tryFastParsingHTMLFragmentImpl(source.span16(), document, destinationParent, contextElement);
}

#undef FOR_EACH_SUPPORTED_TAG
Expand Down
4 changes: 2 additions & 2 deletions Source/WebCore/html/parser/HTMLDocumentParserFastPath.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,13 @@

namespace WebCore {

class ContainerNode;
class Document;
class DocumentFragment;
class Element;

enum class ParserContentPolicy : uint8_t;

WEBCORE_EXPORT bool tryFastParsingHTMLFragment(const String& source, Document&, DocumentFragment&, Element& contextElement, OptionSet<ParserContentPolicy>);
WEBCORE_EXPORT bool tryFastParsingHTMLFragment(const String& source, Document&, ContainerNode&, Element& contextElement, OptionSet<ParserContentPolicy>);

} // namespace WebCore

6 changes: 1 addition & 5 deletions Source/WebCore/xml/DOMParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,18 +59,14 @@ ExceptionOr<Ref<Document>> DOMParser::parseFromString(const String& string, cons
document->setParserContentPolicy(parsingOptions);
bool usedFastPath = false;
if (contentType == "text/html"_s) {
auto fragment = DocumentFragment::create(document);
auto body = HTMLBodyElement::create(document);
usedFastPath = tryFastParsingHTMLFragment(string, document, fragment, body, parsingOptions);
usedFastPath = tryFastParsingHTMLFragment(string, document, body, body, parsingOptions);
if (LIKELY(usedFastPath)) {
auto html = HTMLHtmlElement::create(document);
document->appendChild(html);
auto head = HTMLHeadElement::create(document);
html->appendChild(head);
html->appendChild(body);
auto result = body->appendChild(fragment);
if (UNLIKELY(result.hasException()))
return result.releaseException();
}
}
if (!usedFastPath)
Expand Down

0 comments on commit 903209c

Please sign in to comment.