1/* 2 * Copyright (C) 2010 Google, Inc. All Rights Reserved. 3 * Copyright (C) 2011 Apple Inc. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC. OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#ifndef HTMLConstructionSite_h 28#define HTMLConstructionSite_h 29 30#include "FragmentScriptingPermission.h" 31#include "HTMLElementStack.h" 32#include "HTMLFormattingElementList.h" 33#include "NotImplemented.h" 34#include <wtf/Noncopyable.h> 35#include <wtf/PassRefPtr.h> 36#include <wtf/RefPtr.h> 37#include <wtf/Vector.h> 38 39namespace WebCore { 40 41struct HTMLConstructionSiteTask { 42 enum Operation { 43 Insert, 44 InsertAlreadyParsedChild, 45 Reparent, 46 TakeAllChildren, 47 }; 48 49 explicit HTMLConstructionSiteTask(Operation op) 50 : operation(op) 51 , selfClosing(false) 52 { 53 } 54 55 ContainerNode* oldParent() 56 { 57 // It's sort of ugly, but we store the |oldParent| in the |child| field 58 // of the task so that we don't bloat the HTMLConstructionSiteTask 59 // object in the common case of the Insert operation. 60 return toContainerNode(child.get()); 61 } 62 63 Operation operation; 64 RefPtr<ContainerNode> parent; 65 RefPtr<Node> nextChild; 66 RefPtr<Node> child; 67 bool selfClosing; 68}; 69 70} // namespace WebCore 71 72namespace WTF { 73template<> struct VectorTraits<WebCore::HTMLConstructionSiteTask> : SimpleClassVectorTraits { }; 74} // namespace WTF 75 76namespace WebCore { 77 78enum WhitespaceMode { 79 AllWhitespace, 80 NotAllWhitespace, 81 WhitespaceUnknown 82}; 83 84class AtomicHTMLToken; 85class Document; 86class Element; 87class HTMLFormElement; 88 89class HTMLConstructionSite { 90 WTF_MAKE_NONCOPYABLE(HTMLConstructionSite); 91public: 92 HTMLConstructionSite(Document*, ParserContentPolicy, unsigned maximumDOMTreeDepth); 93 HTMLConstructionSite(DocumentFragment*, ParserContentPolicy, unsigned maximumDOMTreeDepth); 94 ~HTMLConstructionSite(); 95 96 void detach(); 97 void executeQueuedTasks(); 98 99 void setDefaultCompatibilityMode(); 100 void finishedParsing(); 101 102 void insertDoctype(AtomicHTMLToken*); 103 void insertComment(AtomicHTMLToken*); 104 void insertCommentOnDocument(AtomicHTMLToken*); 105 void insertCommentOnHTMLHtmlElement(AtomicHTMLToken*); 106 void insertHTMLElement(AtomicHTMLToken*); 107 void insertSelfClosingHTMLElement(AtomicHTMLToken*); 108 void insertFormattingElement(AtomicHTMLToken*); 109 void insertHTMLHeadElement(AtomicHTMLToken*); 110 void insertHTMLBodyElement(AtomicHTMLToken*); 111 void insertHTMLFormElement(AtomicHTMLToken*, bool isDemoted = false); 112 void insertScriptElement(AtomicHTMLToken*); 113 void insertTextNode(const String&, WhitespaceMode = WhitespaceUnknown); 114 void insertForeignElement(AtomicHTMLToken*, const AtomicString& namespaceURI); 115 116 void insertHTMLHtmlStartTagBeforeHTML(AtomicHTMLToken*); 117 void insertHTMLHtmlStartTagInBody(AtomicHTMLToken*); 118 void insertHTMLBodyStartTagInBody(AtomicHTMLToken*); 119 120 void reparent(HTMLElementStack::ElementRecord& newParent, HTMLElementStack::ElementRecord& child); 121 void reparent(HTMLElementStack::ElementRecord& newParent, HTMLStackItem& child); 122 // insertAlreadyParsedChild assumes that |child| has already been parsed (i.e., we're just 123 // moving it around in the tree rather than parsing it for the first time). That means 124 // this function doesn't call beginParsingChildren / finishParsingChildren. 125 void insertAlreadyParsedChild(HTMLStackItem& newParent, HTMLElementStack::ElementRecord& child); 126 void takeAllChildren(HTMLStackItem& newParent, HTMLElementStack::ElementRecord& oldParent); 127 128 PassRefPtr<HTMLStackItem> createElementFromSavedToken(HTMLStackItem*); 129 130 bool shouldFosterParent() const; 131 void fosterParent(PassRefPtr<Node>); 132 133 bool indexOfFirstUnopenFormattingElement(unsigned& firstUnopenElementIndex) const; 134 void reconstructTheActiveFormattingElements(); 135 136 void generateImpliedEndTags(); 137 void generateImpliedEndTagsWithExclusion(const AtomicString& tagName); 138 139 bool inQuirksMode(); 140 141 bool isEmpty() const { return !m_openElements.stackDepth(); } 142 HTMLElementStack::ElementRecord* currentElementRecord() const { return m_openElements.topRecord(); } 143 Element* currentElement() const { return m_openElements.top(); } 144 ContainerNode* currentNode() const { return m_openElements.topNode(); } 145 HTMLStackItem* currentStackItem() const { return m_openElements.topStackItem(); } 146 HTMLStackItem* oneBelowTop() const { return m_openElements.oneBelowTop(); } 147 Document* ownerDocumentForCurrentNode(); 148 HTMLElementStack* openElements() const { return &m_openElements; } 149 HTMLFormattingElementList* activeFormattingElements() const { return &m_activeFormattingElements; } 150 bool currentIsRootNode() { return m_openElements.topNode() == m_openElements.rootNode(); } 151 152 Element* head() const { return m_head->element(); } 153 HTMLStackItem* headStackItem() const { return m_head.get(); } 154 155 void setForm(HTMLFormElement*); 156 HTMLFormElement* form() const { return m_form.get(); } 157 PassRefPtr<HTMLFormElement> takeForm(); 158 159 ParserContentPolicy parserContentPolicy() { return m_parserContentPolicy; } 160 161 class RedirectToFosterParentGuard { 162 WTF_MAKE_NONCOPYABLE(RedirectToFosterParentGuard); 163 public: 164 RedirectToFosterParentGuard(HTMLConstructionSite& tree) 165 : m_tree(tree) 166 , m_wasRedirectingBefore(tree.m_redirectAttachToFosterParent) 167 { 168 m_tree.m_redirectAttachToFosterParent = true; 169 } 170 171 ~RedirectToFosterParentGuard() 172 { 173 m_tree.m_redirectAttachToFosterParent = m_wasRedirectingBefore; 174 } 175 176 private: 177 HTMLConstructionSite& m_tree; 178 bool m_wasRedirectingBefore; 179 }; 180 181private: 182 // In the common case, this queue will have only one task because most 183 // tokens produce only one DOM mutation. 184 typedef Vector<HTMLConstructionSiteTask, 1> TaskQueue; 185 186 void setCompatibilityMode(Document::CompatibilityMode); 187 void setCompatibilityModeFromDoctype(const String& name, const String& publicId, const String& systemId); 188 189 void attachLater(ContainerNode* parent, PassRefPtr<Node> child, bool selfClosing = false); 190 191 void findFosterSite(HTMLConstructionSiteTask&); 192 193 PassRefPtr<Element> createHTMLElement(AtomicHTMLToken*); 194 PassRefPtr<Element> createElement(AtomicHTMLToken*, const AtomicString& namespaceURI); 195 196 void mergeAttributesFromTokenIntoElement(AtomicHTMLToken*, Element*); 197 void dispatchDocumentElementAvailableIfNeeded(); 198 199 Document* m_document; 200 201 // This is the root ContainerNode to which the parser attaches all newly 202 // constructed nodes. It points to a DocumentFragment when parsing fragments 203 // and a Document in all other cases. 204 ContainerNode* m_attachmentRoot; 205 206 RefPtr<HTMLStackItem> m_head; 207 RefPtr<HTMLFormElement> m_form; 208 mutable HTMLElementStack m_openElements; 209 mutable HTMLFormattingElementList m_activeFormattingElements; 210 211 TaskQueue m_taskQueue; 212 213 ParserContentPolicy m_parserContentPolicy; 214 bool m_isParsingFragment; 215 216 // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#parsing-main-intable 217 // In the "in table" insertion mode, we sometimes get into a state where 218 // "whenever a node would be inserted into the current node, it must instead 219 // be foster parented." This flag tracks whether we're in that state. 220 bool m_redirectAttachToFosterParent; 221 222 unsigned m_maximumDOMTreeDepth; 223 224 bool m_inQuirksMode; 225}; 226 227} // namespace WebCore 228 229#endif 230