Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / 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 "core/dom/Document.h"
31 #include "core/dom/ParserContentPolicy.h"
32 #include "core/html/parser/HTMLElementStack.h"
33 #include "core/html/parser/HTMLFormattingElementList.h"
34 #include "wtf/Noncopyable.h"
35 #include "wtf/PassRefPtr.h"
36 #include "wtf/RefPtr.h"
37 #include "wtf/Vector.h"
38 #include "wtf/text/StringBuilder.h"
39
40 namespace blink {
41
42 struct HTMLConstructionSiteTask {
43     ALLOW_ONLY_INLINE_ALLOCATION();
44 public:
45     enum Operation {
46         Insert,
47         InsertText, // Handles possible merging of text nodes.
48         InsertAlreadyParsedChild, // Insert w/o calling begin/end parsing.
49         Reparent,
50         TakeAllChildren,
51     };
52
53     explicit HTMLConstructionSiteTask(Operation op)
54         : operation(op)
55         , selfClosing(false)
56     {
57     }
58
59     void trace(Visitor* visitor)
60     {
61         visitor->trace(parent);
62         visitor->trace(nextChild);
63         visitor->trace(child);
64     }
65
66     ContainerNode* oldParent()
67     {
68         // It's sort of ugly, but we store the |oldParent| in the |child| field
69         // of the task so that we don't bloat the HTMLConstructionSiteTask
70         // object in the common case of the Insert operation.
71         return toContainerNode(child.get());
72     }
73
74     Operation operation;
75     RefPtrWillBeMember<ContainerNode> parent;
76     RefPtrWillBeMember<Node> nextChild;
77     RefPtrWillBeMember<Node> child;
78     bool selfClosing;
79 };
80
81 } // namespace blink
82
83 WTF_ALLOW_MOVE_INIT_AND_COMPARE_WITH_MEM_FUNCTIONS(blink::HTMLConstructionSiteTask);
84
85 namespace blink {
86
87 // Note: These are intentionally ordered so that when we concatonate
88 // strings and whitespaces the resulting whitespace is ws = min(ws1, ws2).
89 enum WhitespaceMode {
90     WhitespaceUnknown,
91     NotAllWhitespace,
92     AllWhitespace,
93 };
94
95 enum FlushMode {
96     // Flush pending text. Flush queued tasks.
97     FlushAlways,
98
99     // Flush pending text if node has length limit. Flush queued tasks.
100     FlushIfAtTextLimit,
101 };
102
103 class AtomicHTMLToken;
104 class Document;
105 class Element;
106 class HTMLFormElement;
107
108 class HTMLConstructionSite final {
109     WTF_MAKE_NONCOPYABLE(HTMLConstructionSite);
110     DISALLOW_ALLOCATION();
111 public:
112     HTMLConstructionSite(Document*, ParserContentPolicy);
113     HTMLConstructionSite(DocumentFragment*, ParserContentPolicy);
114     ~HTMLConstructionSite();
115     void trace(Visitor*);
116
117     void detach();
118
119     // executeQueuedTasks empties the queue but does not flush pending text.
120     // NOTE: Possible reentrancy via JavaScript execution.
121     void executeQueuedTasks();
122
123     // flushPendingText turns pending text into queued Text insertions, but does not execute them.
124     void flushPendingText(FlushMode);
125
126     // Called before every token in HTMLTreeBuilder::processToken, thus inlined:
127     void flush(FlushMode mode)
128     {
129         if (!hasPendingTasks())
130             return;
131         flushPendingText(mode);
132         executeQueuedTasks(); // NOTE: Possible reentrancy via JavaScript execution.
133         ASSERT(mode == FlushIfAtTextLimit || !hasPendingTasks());
134     }
135
136     bool hasPendingTasks()
137     {
138         return !m_pendingText.isEmpty() || !m_taskQueue.isEmpty();
139     }
140
141     void setDefaultCompatibilityMode();
142     void processEndOfFile();
143     void finishedParsing();
144
145     void insertDoctype(AtomicHTMLToken*);
146     void insertComment(AtomicHTMLToken*);
147     void insertCommentOnDocument(AtomicHTMLToken*);
148     void insertCommentOnHTMLHtmlElement(AtomicHTMLToken*);
149     void insertHTMLElement(AtomicHTMLToken*);
150     void insertSelfClosingHTMLElement(AtomicHTMLToken*);
151     void insertFormattingElement(AtomicHTMLToken*);
152     void insertHTMLHeadElement(AtomicHTMLToken*);
153     void insertHTMLBodyElement(AtomicHTMLToken*);
154     void insertHTMLFormElement(AtomicHTMLToken*, bool isDemoted = false);
155     void insertScriptElement(AtomicHTMLToken*);
156     void insertTextNode(const String&, WhitespaceMode = WhitespaceUnknown);
157     void insertForeignElement(AtomicHTMLToken*, const AtomicString& namespaceURI);
158
159     void insertHTMLHtmlStartTagBeforeHTML(AtomicHTMLToken*);
160     void insertHTMLHtmlStartTagInBody(AtomicHTMLToken*);
161     void insertHTMLBodyStartTagInBody(AtomicHTMLToken*);
162
163     void reparent(HTMLElementStack::ElementRecord* newParent, HTMLElementStack::ElementRecord* child);
164     void reparent(HTMLElementStack::ElementRecord* newParent, HTMLStackItem* child);
165     // insertAlreadyParsedChild assumes that |child| has already been parsed (i.e., we're just
166     // moving it around in the tree rather than parsing it for the first time). That means
167     // this function doesn't call beginParsingChildren / finishParsingChildren.
168     void insertAlreadyParsedChild(HTMLStackItem* newParent, HTMLElementStack::ElementRecord* child);
169     void takeAllChildren(HTMLStackItem* newParent, HTMLElementStack::ElementRecord* oldParent);
170
171     PassRefPtrWillBeRawPtr<HTMLStackItem> createElementFromSavedToken(HTMLStackItem*);
172
173     bool shouldFosterParent() const;
174     void fosterParent(PassRefPtrWillBeRawPtr<Node>);
175
176     bool indexOfFirstUnopenFormattingElement(unsigned& firstUnopenElementIndex) const;
177     void reconstructTheActiveFormattingElements();
178
179     void generateImpliedEndTags();
180     void generateImpliedEndTagsWithExclusion(const AtomicString& tagName);
181
182     bool inQuirksMode();
183
184     bool isEmpty() const { return !m_openElements.stackDepth(); }
185     HTMLElementStack::ElementRecord* currentElementRecord() const { return m_openElements.topRecord(); }
186     Element* currentElement() const { return m_openElements.top(); }
187     ContainerNode* currentNode() const { return m_openElements.topNode(); }
188     HTMLStackItem* currentStackItem() const { return m_openElements.topStackItem(); }
189     HTMLStackItem* oneBelowTop() const { return m_openElements.oneBelowTop(); }
190     Document& ownerDocumentForCurrentNode();
191     HTMLElementStack* openElements() const { return &m_openElements; }
192     HTMLFormattingElementList* activeFormattingElements() const { return &m_activeFormattingElements; }
193     bool currentIsRootNode() { return m_openElements.topNode() == m_openElements.rootNode(); }
194
195     Element* head() const { return m_head->element(); }
196     HTMLStackItem* headStackItem() const { return m_head.get(); }
197
198     void setForm(HTMLFormElement*);
199     HTMLFormElement* form() const { return m_form.get(); }
200     PassRefPtrWillBeRawPtr<HTMLFormElement> takeForm();
201
202     ParserContentPolicy parserContentPolicy() { return m_parserContentPolicy; }
203
204     class RedirectToFosterParentGuard {
205         WTF_MAKE_NONCOPYABLE(RedirectToFosterParentGuard);
206     public:
207         RedirectToFosterParentGuard(HTMLConstructionSite& tree)
208             : m_tree(tree)
209             , m_wasRedirectingBefore(tree.m_redirectAttachToFosterParent)
210         {
211             m_tree.m_redirectAttachToFosterParent = true;
212         }
213
214         ~RedirectToFosterParentGuard()
215         {
216             m_tree.m_redirectAttachToFosterParent = m_wasRedirectingBefore;
217         }
218
219     private:
220         HTMLConstructionSite& m_tree;
221         bool m_wasRedirectingBefore;
222     };
223
224 private:
225     // In the common case, this queue will have only one task because most
226     // tokens produce only one DOM mutation.
227     typedef WillBeHeapVector<HTMLConstructionSiteTask, 1> TaskQueue;
228
229     void setCompatibilityMode(Document::CompatibilityMode);
230     void setCompatibilityModeFromDoctype(const String& name, const String& publicId, const String& systemId);
231
232     void attachLater(ContainerNode* parent, PassRefPtrWillBeRawPtr<Node> child, bool selfClosing = false);
233
234     void findFosterSite(HTMLConstructionSiteTask&);
235
236     PassRefPtrWillBeRawPtr<HTMLElement> createHTMLElement(AtomicHTMLToken*);
237     PassRefPtrWillBeRawPtr<Element> createElement(AtomicHTMLToken*, const AtomicString& namespaceURI);
238
239     void mergeAttributesFromTokenIntoElement(AtomicHTMLToken*, Element*);
240     void dispatchDocumentElementAvailableIfNeeded();
241
242     void executeTask(HTMLConstructionSiteTask&);
243     void queueTask(const HTMLConstructionSiteTask&);
244
245     RawPtrWillBeMember<Document> m_document;
246
247     // This is the root ContainerNode to which the parser attaches all newly
248     // constructed nodes. It points to a DocumentFragment when parsing fragments
249     // and a Document in all other cases.
250     RawPtrWillBeMember<ContainerNode> m_attachmentRoot;
251
252     RefPtrWillBeMember<HTMLStackItem> m_head;
253     RefPtrWillBeMember<HTMLFormElement> m_form;
254     mutable HTMLElementStack m_openElements;
255     mutable HTMLFormattingElementList m_activeFormattingElements;
256
257     TaskQueue m_taskQueue;
258
259     class PendingText final {
260         DISALLOW_ALLOCATION();
261     public:
262         PendingText()
263             : whitespaceMode(WhitespaceUnknown)
264         {
265         }
266
267         void append(PassRefPtrWillBeRawPtr<ContainerNode> newParent, PassRefPtrWillBeRawPtr<Node> newNextChild, const String& newString, WhitespaceMode newWhitespaceMode)
268         {
269             ASSERT(!parent || parent == newParent);
270             parent = newParent;
271             ASSERT(!nextChild || nextChild == newNextChild);
272             nextChild = newNextChild;
273             stringBuilder.append(newString);
274             whitespaceMode = std::min(whitespaceMode, newWhitespaceMode);
275         }
276
277         void swap(PendingText& other)
278         {
279             std::swap(whitespaceMode, other.whitespaceMode);
280             parent.swap(other.parent);
281             nextChild.swap(other.nextChild);
282             stringBuilder.swap(other.stringBuilder);
283         }
284
285         void discard()
286         {
287             PendingText discardedText;
288             swap(discardedText);
289         }
290
291         bool isEmpty()
292         {
293             // When the stringbuilder is empty, the parent and whitespace should also be "empty".
294             ASSERT(stringBuilder.isEmpty() == !parent);
295             ASSERT(!stringBuilder.isEmpty() || !nextChild);
296             ASSERT(!stringBuilder.isEmpty() || (whitespaceMode == WhitespaceUnknown));
297             return stringBuilder.isEmpty();
298         }
299
300         void trace(Visitor*);
301
302         RefPtrWillBeMember<ContainerNode> parent;
303         RefPtrWillBeMember<Node> nextChild;
304         StringBuilder stringBuilder;
305         WhitespaceMode whitespaceMode;
306     };
307
308     PendingText m_pendingText;
309
310     ParserContentPolicy m_parserContentPolicy;
311     bool m_isParsingFragment;
312
313     // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#parsing-main-intable
314     // In the "in table" insertion mode, we sometimes get into a state where
315     // "whenever a node would be inserted into the current node, it must instead
316     // be foster parented."  This flag tracks whether we're in that state.
317     bool m_redirectAttachToFosterParent;
318
319     bool m_inQuirksMode;
320 };
321
322 } // namespace blink
323
324 #endif