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/ParserContentPolicy.h"
31#include "core/html/parser/HTMLElementStack.h"
32#include "core/html/parser/HTMLFormattingElementList.h"
33#include "wtf/Noncopyable.h"
34#include "wtf/PassRefPtr.h"
35#include "wtf/RefPtr.h"
36#include "wtf/Vector.h"
37
38namespace WebCore {
39
40struct 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 toContainerNode(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
71namespace WTF {
72template<> struct VectorTraits<WebCore::HTMLConstructionSiteTask> : SimpleClassVectorTraits { };
73} // namespace WTF
74
75namespace WebCore {
76
77enum WhitespaceMode {
78    AllWhitespace,
79    NotAllWhitespace,
80    WhitespaceUnknown
81};
82
83class AtomicHTMLToken;
84class Document;
85class Element;
86class HTMLFormElement;
87
88class HTMLConstructionSite {
89    WTF_MAKE_NONCOPYABLE(HTMLConstructionSite);
90public:
91    HTMLConstructionSite(Document*, ParserContentPolicy);
92    HTMLConstructionSite(DocumentFragment*, ParserContentPolicy);
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    HTMLElementStack::ElementRecord* currentElementRecord() const { return m_openElements.topRecord(); }
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    PassRefPtr<HTMLFormElement> takeForm();
157
158    ParserContentPolicy parserContentPolicy() { return m_parserContentPolicy; }
159
160    class RedirectToFosterParentGuard {
161        WTF_MAKE_NONCOPYABLE(RedirectToFosterParentGuard);
162    public:
163        RedirectToFosterParentGuard(HTMLConstructionSite& tree)
164            : m_tree(tree)
165            , m_wasRedirectingBefore(tree.m_redirectAttachToFosterParent)
166        {
167            m_tree.m_redirectAttachToFosterParent = true;
168        }
169
170        ~RedirectToFosterParentGuard()
171        {
172            m_tree.m_redirectAttachToFosterParent = m_wasRedirectingBefore;
173        }
174
175    private:
176        HTMLConstructionSite& m_tree;
177        bool m_wasRedirectingBefore;
178    };
179
180private:
181    // In the common case, this queue will have only one task because most
182    // tokens produce only one DOM mutation.
183    typedef Vector<HTMLConstructionSiteTask, 1> TaskQueue;
184
185    void setCompatibilityMode(Document::CompatibilityMode);
186    void setCompatibilityModeFromDoctype(const String& name, const String& publicId, const String& systemId);
187
188    void attachLater(ContainerNode* parent, PassRefPtr<Node> child, bool selfClosing = false);
189
190    void findFosterSite(HTMLConstructionSiteTask&);
191
192    PassRefPtr<Element> createHTMLElement(AtomicHTMLToken*);
193    PassRefPtr<Element> createElement(AtomicHTMLToken*, const AtomicString& namespaceURI);
194
195    void mergeAttributesFromTokenIntoElement(AtomicHTMLToken*, Element*);
196    void dispatchDocumentElementAvailableIfNeeded();
197
198    Document* m_document;
199
200    // This is the root ContainerNode to which the parser attaches all newly
201    // constructed nodes. It points to a DocumentFragment when parsing fragments
202    // and a Document in all other cases.
203    ContainerNode* m_attachmentRoot;
204
205    RefPtr<HTMLStackItem> m_head;
206    RefPtr<HTMLFormElement> m_form;
207    mutable HTMLElementStack m_openElements;
208    mutable HTMLFormattingElementList m_activeFormattingElements;
209
210    TaskQueue m_taskQueue;
211
212    ParserContentPolicy m_parserContentPolicy;
213    bool m_isParsingFragment;
214
215    // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#parsing-main-intable
216    // In the "in table" insertion mode, we sometimes get into a state where
217    // "whenever a node would be inserted into the current node, it must instead
218    // be foster parented."  This flag tracks whether we're in that state.
219    bool m_redirectAttachToFosterParent;
220
221    bool m_inQuirksMode;
222};
223
224} // namespace WebCore
225
226#endif
227