| /* |
| * Copyright (C) 2010 Google, Inc. All Rights Reserved. |
| * Copyright (C) 2011 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC. OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #pragma once |
| |
| #include "Document.h" |
| #include "FragmentScriptingPermission.h" |
| #include "HTMLElementStack.h" |
| #include "HTMLFormattingElementList.h" |
| #include <wtf/FixedVector.h> |
| #include <wtf/Noncopyable.h> |
| #include <wtf/RefPtr.h> |
| #include <wtf/SetForScope.h> |
| #include <wtf/Vector.h> |
| |
| namespace WebCore { |
| |
| struct AtomStringWithCode { |
| AtomString string; |
| uint64_t code { 0 }; |
| }; |
| |
| } |
| |
| namespace WTF { |
| template<> struct VectorTraits<WebCore::AtomStringWithCode> : SimpleClassVectorTraits { }; |
| } |
| |
| namespace WebCore { |
| |
| struct HTMLConstructionSiteTask { |
| enum Operation { |
| Insert, |
| InsertAlreadyParsedChild, |
| Reparent, |
| TakeAllChildrenAndReparent, |
| }; |
| |
| explicit HTMLConstructionSiteTask(Operation op) |
| : operation(op) |
| , selfClosing(false) |
| { |
| } |
| |
| ContainerNode* oldParent() |
| { |
| // It's sort of ugly, but we store the |oldParent| in the |child| field |
| // of the task so that we don't bloat the HTMLConstructionSiteTask |
| // object in the common case of the Insert operation. |
| return downcast<ContainerNode>(child.get()); |
| } |
| |
| Operation operation; |
| RefPtr<ContainerNode> parent; |
| RefPtr<Node> nextChild; |
| RefPtr<Node> child; |
| bool selfClosing; |
| }; |
| |
| } // namespace WebCore |
| |
| namespace WTF { |
| template<> struct VectorTraits<WebCore::HTMLConstructionSiteTask> : SimpleClassVectorTraits { }; |
| } // namespace WTF |
| |
| namespace WebCore { |
| |
| enum WhitespaceMode { |
| AllWhitespace, |
| NotAllWhitespace, |
| WhitespaceUnknown |
| }; |
| |
| class AtomHTMLToken; |
| struct CustomElementConstructionData; |
| class Document; |
| class Element; |
| class HTMLFormElement; |
| class JSCustomElementInterface; |
| class WhitespaceCache; |
| |
| class HTMLConstructionSite { |
| WTF_MAKE_NONCOPYABLE(HTMLConstructionSite); |
| public: |
| HTMLConstructionSite(Document&, ParserContentPolicy, unsigned maximumDOMTreeDepth); |
| HTMLConstructionSite(DocumentFragment&, ParserContentPolicy, unsigned maximumDOMTreeDepth); |
| ~HTMLConstructionSite(); |
| |
| void executeQueuedTasks(); |
| |
| void setDefaultCompatibilityMode(); |
| void finishedParsing(); |
| |
| void insertDoctype(AtomHTMLToken&&); |
| void insertComment(AtomHTMLToken&&); |
| void insertCommentOnDocument(AtomHTMLToken&&); |
| void insertCommentOnHTMLHtmlElement(AtomHTMLToken&&); |
| void insertHTMLElement(AtomHTMLToken&&); |
| std::unique_ptr<CustomElementConstructionData> insertHTMLElementOrFindCustomElementInterface(AtomHTMLToken&&); |
| void insertCustomElement(Ref<Element>&&, const AtomString& localName, Vector<Attribute>&&); |
| void insertSelfClosingHTMLElement(AtomHTMLToken&&); |
| void insertFormattingElement(AtomHTMLToken&&); |
| void insertHTMLHeadElement(AtomHTMLToken&&); |
| void insertHTMLBodyElement(AtomHTMLToken&&); |
| void insertHTMLFormElement(AtomHTMLToken&&, bool isDemoted = false); |
| void insertScriptElement(AtomHTMLToken&&); |
| void insertTextNode(const String&, WhitespaceMode = WhitespaceUnknown); |
| void insertForeignElement(AtomHTMLToken&&, const AtomString& namespaceURI); |
| |
| void insertHTMLHtmlStartTagBeforeHTML(AtomHTMLToken&&); |
| void insertHTMLHtmlStartTagInBody(AtomHTMLToken&&); |
| void insertHTMLBodyStartTagInBody(AtomHTMLToken&&); |
| |
| void reparent(HTMLElementStack::ElementRecord& newParent, HTMLElementStack::ElementRecord& child); |
| // insertAlreadyParsedChild assumes that |child| has already been parsed (i.e., we're just |
| // moving it around in the tree rather than parsing it for the first time). That means |
| // this function doesn't call beginParsingChildren / finishParsingChildren. |
| void insertAlreadyParsedChild(HTMLStackItem& newParent, HTMLElementStack::ElementRecord& child); |
| void takeAllChildrenAndReparent(HTMLStackItem& newParent, HTMLElementStack::ElementRecord& oldParent); |
| |
| HTMLStackItem createElementFromSavedToken(const HTMLStackItem&); |
| |
| bool shouldFosterParent() const; |
| void fosterParent(Ref<Node>&&); |
| |
| std::optional<unsigned> indexOfFirstUnopenFormattingElement() const; |
| void reconstructTheActiveFormattingElements(); |
| |
| void generateImpliedEndTags(); |
| void generateImpliedEndTagsWithExclusion(const AtomString& tagName); |
| |
| bool inQuirksMode() { return m_inQuirksMode; } |
| |
| bool isEmpty() const { return !m_openElements.stackDepth(); } |
| Element& currentElement() const { return m_openElements.top(); } |
| ContainerNode& currentNode() const { return m_openElements.topNode(); } |
| HTMLStackItem& currentStackItem() const { return m_openElements.topStackItem(); } |
| HTMLStackItem* oneBelowTop() const { return m_openElements.oneBelowTop(); } |
| Document& ownerDocumentForCurrentNode(); |
| HTMLElementStack& openElements() const { return m_openElements; } |
| HTMLFormattingElementList& activeFormattingElements() const { return m_activeFormattingElements; } |
| bool currentIsRootNode() { return &m_openElements.topNode() == &m_openElements.rootNode(); } |
| |
| Element& head() const { return m_head.element(); } |
| HTMLStackItem& headStackItem() { return m_head; } |
| |
| void setForm(HTMLFormElement*); |
| HTMLFormElement* form() const { return m_form.get(); } |
| RefPtr<HTMLFormElement> takeForm(); |
| |
| ParserContentPolicy parserContentPolicy() { return m_parserContentPolicy; } |
| |
| #if ENABLE(TELEPHONE_NUMBER_DETECTION) |
| bool isTelephoneNumberParsingEnabled() { return m_document.isTelephoneNumberParsingEnabled(); } |
| #endif |
| |
| class RedirectToFosterParentGuard { |
| WTF_MAKE_NONCOPYABLE(RedirectToFosterParentGuard); |
| public: |
| explicit RedirectToFosterParentGuard(HTMLConstructionSite& tree) |
| : m_redirectAttachToFosterParentChange(tree.m_redirectAttachToFosterParent, true) |
| { } |
| |
| private: |
| SetForScope<bool> m_redirectAttachToFosterParentChange; |
| }; |
| |
| static bool isFormattingTag(const AtomString&); |
| |
| private: |
| // In the common case, this queue will have only one task because most |
| // tokens produce only one DOM mutation. |
| typedef Vector<HTMLConstructionSiteTask, 1> TaskQueue; |
| |
| void setCompatibilityMode(DocumentCompatibilityMode); |
| void setCompatibilityModeFromDoctype(const String& name, const String& publicId, const String& systemId); |
| |
| void attachLater(ContainerNode& parent, Ref<Node>&& child, bool selfClosing = false); |
| |
| void findFosterSite(HTMLConstructionSiteTask&); |
| |
| RefPtr<Element> createHTMLElementOrFindCustomElementInterface(AtomHTMLToken&, JSCustomElementInterface**); |
| Ref<Element> createHTMLElement(AtomHTMLToken&); |
| Ref<Element> createElement(AtomHTMLToken&, const AtomString& namespaceURI); |
| |
| void mergeAttributesFromTokenIntoElement(AtomHTMLToken&&, Element&); |
| void dispatchDocumentElementAvailableIfNeeded(); |
| |
| Document& m_document; |
| |
| // This is the root ContainerNode to which the parser attaches all newly |
| // constructed nodes. It points to a DocumentFragment when parsing fragments |
| // and a Document in all other cases. |
| ContainerNode& m_attachmentRoot; |
| |
| HTMLStackItem m_head; |
| RefPtr<HTMLFormElement> m_form; |
| mutable HTMLElementStack m_openElements; |
| mutable HTMLFormattingElementList m_activeFormattingElements; |
| |
| TaskQueue m_taskQueue; |
| |
| ParserContentPolicy m_parserContentPolicy; |
| bool m_isParsingFragment; |
| |
| // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#parsing-main-intable |
| // In the "in table" insertion mode, we sometimes get into a state where |
| // "whenever a node would be inserted into the current node, it must instead |
| // be foster parented." This flag tracks whether we're in that state. |
| bool m_redirectAttachToFosterParent; |
| |
| unsigned m_maximumDOMTreeDepth; |
| |
| bool m_inQuirksMode; |
| |
| WhitespaceCache& m_whitespaceCache; |
| }; |
| |
| class WhitespaceCache { |
| WTF_MAKE_FAST_ALLOCATED; |
| public: |
| WhitespaceCache() |
| : m_atoms(maximumCachedStringLength) |
| { |
| } |
| |
| AtomString lookup(const String&, WhitespaceMode); |
| |
| private: |
| template<WhitespaceMode> uint64_t codeForString(const String&); |
| |
| constexpr static uint64_t overflowWhitespaceCode = static_cast<uint64_t>(-1); |
| constexpr static size_t maximumCachedStringLength = 128; |
| |
| FixedVector<AtomStringWithCode> m_atoms; |
| }; |
| |
| } // namespace WebCore |