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#pragma once
28
29#include "FragmentScriptingPermission.h"
30#include "HTMLElementStack.h"
31#include "HTMLFormattingElementList.h"
32#include <wtf/Noncopyable.h>
33#include <wtf/RefPtr.h>
34#include <wtf/SetForScope.h>
35#include <wtf/Vector.h>
36
37namespace WebCore {
38
39struct HTMLConstructionSiteTask {
40 enum Operation {
41 Insert,
42 InsertAlreadyParsedChild,
43 Reparent,
44 TakeAllChildrenAndReparent,
45 };
46
47 explicit HTMLConstructionSiteTask(Operation op)
48 : operation(op)
49 , selfClosing(false)
50 {
51 }
52
53 ContainerNode* oldParent()
54 {
55 // It's sort of ugly, but we store the |oldParent| in the |child| field
56 // of the task so that we don't bloat the HTMLConstructionSiteTask
57 // object in the common case of the Insert operation.
58 return downcast<ContainerNode>(child.get());
59 }
60
61 Operation operation;
62 RefPtr<ContainerNode> parent;
63 RefPtr<Node> nextChild;
64 RefPtr<Node> child;
65 bool selfClosing;
66};
67
68} // namespace WebCore
69
70namespace WTF {
71template<> struct VectorTraits<WebCore::HTMLConstructionSiteTask> : SimpleClassVectorTraits { };
72} // namespace WTF
73
74namespace WebCore {
75
76enum WhitespaceMode {
77 AllWhitespace,
78 NotAllWhitespace,
79 WhitespaceUnknown
80};
81
82class AtomicHTMLToken;
83struct CustomElementConstructionData;
84class Document;
85class Element;
86class HTMLFormElement;
87class JSCustomElementInterface;
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 executeQueuedTasks();
97
98 void setDefaultCompatibilityMode();
99 void finishedParsing();
100
101 void insertDoctype(AtomicHTMLToken&&);
102 void insertComment(AtomicHTMLToken&&);
103 void insertCommentOnDocument(AtomicHTMLToken&&);
104 void insertCommentOnHTMLHtmlElement(AtomicHTMLToken&&);
105 void insertHTMLElement(AtomicHTMLToken&&);
106 std::unique_ptr<CustomElementConstructionData> insertHTMLElementOrFindCustomElementInterface(AtomicHTMLToken&&);
107 void insertCustomElement(Ref<Element>&&, const AtomicString& localName, Vector<Attribute>&&);
108 void insertSelfClosingHTMLElement(AtomicHTMLToken&&);
109 void insertFormattingElement(AtomicHTMLToken&&);
110 void insertHTMLHeadElement(AtomicHTMLToken&&);
111 void insertHTMLBodyElement(AtomicHTMLToken&&);
112 void insertHTMLFormElement(AtomicHTMLToken&&, bool isDemoted = false);
113 void insertScriptElement(AtomicHTMLToken&&);
114 void insertTextNode(const String&, WhitespaceMode = WhitespaceUnknown);
115 void insertForeignElement(AtomicHTMLToken&&, const AtomicString& namespaceURI);
116
117 void insertHTMLHtmlStartTagBeforeHTML(AtomicHTMLToken&&);
118 void insertHTMLHtmlStartTagInBody(AtomicHTMLToken&&);
119 void insertHTMLBodyStartTagInBody(AtomicHTMLToken&&);
120
121 void reparent(HTMLElementStack::ElementRecord& newParent, HTMLElementStack::ElementRecord& 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 takeAllChildrenAndReparent(HTMLStackItem& newParent, HTMLElementStack::ElementRecord& oldParent);
127
128 Ref<HTMLStackItem> createElementFromSavedToken(HTMLStackItem&);
129
130 bool shouldFosterParent() const;
131 void fosterParent(Ref<Node>&&);
132
133 Optional<unsigned> indexOfFirstUnopenFormattingElement() const;
134 void reconstructTheActiveFormattingElements();
135
136 void generateImpliedEndTags();
137 void generateImpliedEndTagsWithExclusion(const AtomicString& tagName);
138
139 bool inQuirksMode() { return m_inQuirksMode; }
140
141 bool isEmpty() const { return !m_openElements.stackDepth(); }
142 Element& currentElement() const { return m_openElements.top(); }
143 ContainerNode& currentNode() const { return m_openElements.topNode(); }
144 HTMLStackItem& currentStackItem() const { return m_openElements.topStackItem(); }
145 HTMLStackItem* oneBelowTop() const { return m_openElements.oneBelowTop(); }
146 Document& ownerDocumentForCurrentNode();
147 HTMLElementStack& openElements() const { return m_openElements; }
148 HTMLFormattingElementList& activeFormattingElements() const { return m_activeFormattingElements; }
149 bool currentIsRootNode() { return &m_openElements.topNode() == &m_openElements.rootNode(); }
150
151 Element& head() const { return m_head->element(); }
152 HTMLStackItem* headStackItem() const { return m_head.get(); }
153
154 void setForm(HTMLFormElement*);
155 HTMLFormElement* form() const { return m_form.get(); }
156 RefPtr<HTMLFormElement> takeForm();
157
158 ParserContentPolicy parserContentPolicy() { return m_parserContentPolicy; }
159
160#if ENABLE(TELEPHONE_NUMBER_DETECTION)
161 bool isTelephoneNumberParsingEnabled() { return m_document.isTelephoneNumberParsingEnabled(); }
162#endif
163
164 class RedirectToFosterParentGuard {
165 WTF_MAKE_NONCOPYABLE(RedirectToFosterParentGuard);
166 public:
167 explicit RedirectToFosterParentGuard(HTMLConstructionSite& tree)
168 : m_redirectAttachToFosterParentChange(tree.m_redirectAttachToFosterParent, true)
169 { }
170
171 private:
172 SetForScope<bool> m_redirectAttachToFosterParentChange;
173 };
174
175 static bool isFormattingTag(const AtomicString&);
176
177private:
178 // In the common case, this queue will have only one task because most
179 // tokens produce only one DOM mutation.
180 typedef Vector<HTMLConstructionSiteTask, 1> TaskQueue;
181
182 void setCompatibilityMode(DocumentCompatibilityMode);
183 void setCompatibilityModeFromDoctype(const String& name, const String& publicId, const String& systemId);
184
185 void attachLater(ContainerNode& parent, Ref<Node>&& child, bool selfClosing = false);
186
187 void findFosterSite(HTMLConstructionSiteTask&);
188
189 RefPtr<Element> createHTMLElementOrFindCustomElementInterface(AtomicHTMLToken&, JSCustomElementInterface**);
190 Ref<Element> createHTMLElement(AtomicHTMLToken&);
191 Ref<Element> createElement(AtomicHTMLToken&, const AtomicString& namespaceURI);
192
193 void mergeAttributesFromTokenIntoElement(AtomicHTMLToken&&, Element&);
194 void dispatchDocumentElementAvailableIfNeeded();
195
196 Document& m_document;
197
198 // This is the root ContainerNode to which the parser attaches all newly
199 // constructed nodes. It points to a DocumentFragment when parsing fragments
200 // and a Document in all other cases.
201 ContainerNode& m_attachmentRoot;
202
203 RefPtr<HTMLStackItem> m_head;
204 RefPtr<HTMLFormElement> m_form;
205 mutable HTMLElementStack m_openElements;
206 mutable HTMLFormattingElementList m_activeFormattingElements;
207
208 TaskQueue m_taskQueue;
209
210 ParserContentPolicy m_parserContentPolicy;
211 bool m_isParsingFragment;
212
213 // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#parsing-main-intable
214 // In the "in table" insertion mode, we sometimes get into a state where
215 // "whenever a node would be inserted into the current node, it must instead
216 // be foster parented." This flag tracks whether we're in that state.
217 bool m_redirectAttachToFosterParent;
218
219 unsigned m_maximumDOMTreeDepth;
220
221 bool m_inQuirksMode;
222};
223
224} // namespace WebCore
225