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