2010-06-30 Eric Seidel <eric@webkit.org>
[WebKit-https.git] / WebCore / html / HTMLTreeBuilder.h
1 /*
2  * Copyright (C) 2010 Google, Inc. All Rights Reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GOOGLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #ifndef HTMLTreeBuilder_h
27 #define HTMLTreeBuilder_h
28
29 #include "Element.h"
30 #include "FragmentScriptingPermission.h"
31 #include "HTMLElementStack.h"
32 #include "HTMLTokenizer.h"
33 #include <wtf/Noncopyable.h>
34 #include <wtf/OwnPtr.h>
35 #include <wtf/PassOwnPtr.h>
36 #include <wtf/PassRefPtr.h>
37 #include <wtf/RefPtr.h>
38 #include <wtf/unicode/Unicode.h>
39
40 namespace WebCore {
41
42 class AtomicHTMLToken;
43 class Document;
44 class DocumentFragment;
45 class Frame;
46 class HTMLToken;
47 class HTMLDocument;
48 class LegacyHTMLTreeBuilder;
49 class Node;
50
51 class HTMLTreeBuilder : public Noncopyable {
52 public:
53     // FIXME: Replace constructors with create() functions returning PassOwnPtrs
54     HTMLTreeBuilder(HTMLTokenizer*, HTMLDocument*, bool reportErrors);
55     HTMLTreeBuilder(HTMLTokenizer*, DocumentFragment*, FragmentScriptingPermission);
56     ~HTMLTreeBuilder();
57
58     void setPaused(bool paused) { m_isPaused = paused; }
59     bool isPaused() const { return m_isPaused; }
60
61     // The token really should be passed as a const& since it's never modified.
62     void constructTreeFromToken(HTMLToken&);
63     // Must be called when parser is paused before calling the parser again.
64     PassRefPtr<Element> takeScriptToProcess(int& scriptStartLine);
65
66     // Done, close any open tags, etc.
67     void finished();
68
69     static HTMLTokenizer::State adjustedLexerState(HTMLTokenizer::State, const AtomicString& tagName, Frame*);
70
71     // FIXME: This is a dirty, rotten hack to keep HTMLFormControlElement happy
72     // until we stop using the legacy parser. DO NOT CALL THIS METHOD.
73     LegacyHTMLTreeBuilder* legacyTreeBuilder() const { return m_legacyTreeBuilder.get(); }
74
75 private:
76     // Represents HTML5 "insertion mode"
77     // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#insertion-mode
78     enum InsertionMode {
79         InitialMode,
80         BeforeHTMLMode,
81         BeforeHeadMode,
82         InHeadMode,
83         InHeadNoscriptMode,
84         AfterHeadMode,
85         InBodyMode,
86         TextMode,
87         InTableMode,
88         InTableTextMode,
89         InCaptionMode,
90         InColumnGroupMode,
91         InTableBodyMode,
92         InRowMode,
93         InCellMode,
94         InSelectMode,
95         InSelectInTableMode,
96         InForeignContentMode,
97         AfterBodyMode,
98         InFramesetMode,
99         AfterFramesetMode,
100         AfterAfterBodyMode,
101         AfterAfterFramesetMode,
102     };
103
104     void passTokenToLegacyParser(HTMLToken&);
105
106     // Specialized functions for processing the different types of tokens.
107     void processToken(AtomicHTMLToken&);
108     void processDoctypeToken(AtomicHTMLToken&);
109     void processStartTag(AtomicHTMLToken&);
110     void processEndTag(AtomicHTMLToken&);
111     void processComment(AtomicHTMLToken&);
112     void processCharacter(AtomicHTMLToken&);
113     void processEndOfFile(AtomicHTMLToken&);
114
115     // Default processing for the different insertion modes.
116     void processDefaultForInitialMode(AtomicHTMLToken&);
117     void processDefaultForBeforeHTMLMode(AtomicHTMLToken&);
118     void processDefaultForBeforeHeadMode(AtomicHTMLToken&);
119     void processDefaultForInHeadMode(AtomicHTMLToken&);
120     void processDefaultForInHeadNoscriptMode(AtomicHTMLToken&);
121     void processDefaultForAfterHeadMode(AtomicHTMLToken&);
122
123     bool processStartTagForInHead(AtomicHTMLToken&);
124
125     template<typename ChildType>
126     PassRefPtr<ChildType> attach(Node* parent, PassRefPtr<ChildType> prpChild)
127     {
128         RefPtr<ChildType> child = prpChild;
129         parent->parserAddChild(child);
130         // It's slightly unfortunate that we need to hold a reference to child
131         // here to call attach().  We should investigate whether we can rely on
132         // |parent| to hold a ref at this point.  In the common case (at least
133         // for elements), however, we'll get to use this ref in the stack of
134         // open elements.
135         child->attach();
136         return child.release();
137     };
138
139     void insertDoctype(AtomicHTMLToken&);
140     void insertComment(AtomicHTMLToken&);
141     void insertCommentOnDocument(AtomicHTMLToken&);
142     void insertHTMLHtmlElement(AtomicHTMLToken&);
143     void insertHTMLHeadElement(AtomicHTMLToken&);
144     void insertHTMLBodyElement(AtomicHTMLToken&);
145     void insertElement(AtomicHTMLToken&);
146     void insertSelfClosingElement(AtomicHTMLToken&);
147     void insertFormattingElement(AtomicHTMLToken&);
148     void insertGenericRCDATAElement(AtomicHTMLToken&);
149     void insertGenericRawTextElement(AtomicHTMLToken&);
150     void insertScriptElement(AtomicHTMLToken&);
151     void insertTextNode(AtomicHTMLToken&);
152
153     void insertHTMLStartTagBeforeHTML(AtomicHTMLToken&);
154     void insertHTMLStartTagInBody(AtomicHTMLToken&);
155
156     PassRefPtr<Element> createElement(AtomicHTMLToken&);
157     PassRefPtr<Element> createElementAndAttachToCurrent(AtomicHTMLToken&);
158
159     void mergeAttributesFromTokenIntoElement(AtomicHTMLToken&, Element*);
160
161     bool indexOfFirstUnopenFormattingElement(unsigned& firstUnopenElementIndex) const;
162     void reconstructTheActiveFormattingElements();
163     void clearActiveFormatingElementsUpToLastMarker() { }
164
165     void generateImpliedEndTags() { }
166
167     Element* currentElement() { return m_openElements.top(); }
168
169     RefPtr<Element> m_headElement;
170     RefPtr<Element> m_formElement;
171     HTMLElementStack m_openElements;
172
173     class FormattingElementEntry {
174     public:
175         FormattingElementEntry(Element* element)
176             : m_element(element)
177         {
178             ASSERT(element);
179         }
180
181         enum MarkerEntryType { MarkerEntry };
182         FormattingElementEntry(MarkerEntryType)
183         {
184         }
185
186         bool isMarker() const { return !m_element; }
187
188         Element* element() const
189         {
190             // The fact that !m_element == isMarker is an implementation detail
191             // callers should check isMarker() before calling element().
192             ASSERT(m_element);
193             return m_element.get();
194         }
195
196         void replaceElement(PassRefPtr<Element> element)
197         {
198             ASSERT(m_element); // Once a marker, always a marker.
199             m_element = element;
200         }
201
202     private:
203         RefPtr<Element> m_element;
204     };
205
206     Vector<FormattingElementEntry> m_activeFormattingElements;
207     bool m_framesetOk;
208
209     // FIXME: Implement error reporting.
210     void parseError(AtomicHTMLToken&) { }
211
212     void handleScriptStartTag();
213     void handleScriptEndTag(Element*, int scriptStartLine);
214
215     void setInsertionMode(InsertionMode value) { m_insertionMode = value; }
216     InsertionMode insertionMode() const { return m_insertionMode; }
217
218     static bool isScriptingFlagEnabled(Frame* frame);
219
220     Document* m_document; // This is only used by the m_legacyParser for now.
221     bool m_reportErrors;
222     bool m_isPaused;
223
224     InsertionMode m_insertionMode;
225     InsertionMode m_originalInsertionMode;
226
227     // HTML5 spec requires that we be able to change the state of the tokenizer
228     // from within parser actions.
229     HTMLTokenizer* m_tokenizer;
230
231     // We're re-using logic from the old LegacyHTMLTreeBuilder while this class is being written.
232     OwnPtr<LegacyHTMLTreeBuilder> m_legacyTreeBuilder;
233
234     // These members are intentionally duplicated as the first set is a hack
235     // on top of the legacy parser which will eventually be removed.
236     RefPtr<Element> m_lastScriptElement; // FIXME: Hack for <script> support on top of the old parser.
237     int m_lastScriptElementStartLine; // FIXME: Hack for <script> support on top of the old parser.
238
239     RefPtr<Element> m_scriptToProcess; // <script> tag which needs processing before resuming the parser.
240     int m_scriptToProcessStartLine; // Starting line number of the script tag needing processing.
241
242     // FIXME: FragmentScriptingPermission is a HACK for platform/Pasteboard.
243     // FragmentScriptingNotAllowed causes the Parser to remove children
244     // from <script> tags (so javascript doesn't show up in pastes).
245     FragmentScriptingPermission m_fragmentScriptingPermission;
246     bool m_isParsingFragment;
247 };
248
249 }
250
251 #endif