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