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 HTMLElementStack_h
28 #define HTMLElementStack_h
29 
30 #include "Element.h"
31 #include "HTMLNames.h"
32 #include <wtf/Forward.h>
33 #include <wtf/Noncopyable.h>
34 #include <wtf/OwnPtr.h>
35 #include <wtf/PassOwnPtr.h>
36 #include <wtf/RefPtr.h>
37 
38 namespace WebCore {
39 
40 class ContainerNode;
41 class DocumentFragment;
42 class Element;
43 class QualifiedName;
44 
45 // NOTE: The HTML5 spec uses a backwards (grows downward) stack.  We're using
46 // more standard (grows upwards) stack terminology here.
47 class HTMLElementStack {
48     WTF_MAKE_NONCOPYABLE(HTMLElementStack); WTF_MAKE_FAST_ALLOCATED;
49 public:
50     HTMLElementStack();
51     ~HTMLElementStack();
52 
53     class ElementRecord {
54         WTF_MAKE_NONCOPYABLE(ElementRecord);
55     public:
56         ~ElementRecord(); // Public for ~PassOwnPtr()
57 
element()58         Element* element() const { return toElement(m_node.get()); }
node()59         ContainerNode* node() const { return m_node.get(); }
60         void replaceElement(PassRefPtr<Element>);
61 
62         bool isAbove(ElementRecord*) const;
63 
next()64         ElementRecord* next() const { return m_next.get(); }
65 
66     private:
67         friend class HTMLElementStack;
68 
69         ElementRecord(PassRefPtr<ContainerNode>, PassOwnPtr<ElementRecord>);
70 
releaseNext()71         PassOwnPtr<ElementRecord> releaseNext() { return m_next.release(); }
setNext(PassOwnPtr<ElementRecord> next)72         void setNext(PassOwnPtr<ElementRecord> next) { m_next = next; }
73 
74         RefPtr<ContainerNode> m_node;
75         OwnPtr<ElementRecord> m_next;
76     };
77 
78     // Inlining this function is a (small) performance win on the parsing
79     // benchmark.
top()80     Element* top() const
81     {
82         ASSERT(m_top->element());
83         return m_top->element();
84     }
85 
topNode()86     ContainerNode* topNode() const
87     {
88         ASSERT(m_top->node());
89         return m_top->node();
90     }
91 
92     Element* oneBelowTop() const;
93     ElementRecord* topRecord() const;
94     Element* bottom() const;
95     ElementRecord* find(Element*) const;
96     ElementRecord* topmost(const AtomicString& tagName) const;
97 
98     void insertAbove(PassRefPtr<Element>, ElementRecord*);
99 
100     void push(PassRefPtr<Element>);
101     void pushRootNode(PassRefPtr<ContainerNode>);
102     void pushHTMLHtmlElement(PassRefPtr<Element>);
103     void pushHTMLHeadElement(PassRefPtr<Element>);
104     void pushHTMLBodyElement(PassRefPtr<Element>);
105 
106     void pop();
107     void popUntil(const AtomicString& tagName);
108     void popUntil(Element*);
109     void popUntilPopped(const AtomicString& tagName);
110     void popUntilPopped(Element*);
111     void popUntilNumberedHeaderElementPopped();
112     void popUntilTableScopeMarker(); // "clear the stack back to a table context" in the spec.
113     void popUntilTableBodyScopeMarker(); // "clear the stack back to a table body context" in the spec.
114     void popUntilTableRowScopeMarker(); // "clear the stack back to a table row context" in the spec.
115     void popUntilForeignContentScopeMarker();
116     void popHTMLHeadElement();
117     void popHTMLBodyElement();
118     void popAll();
119 
120     void remove(Element*);
121     void removeHTMLHeadElement(Element*);
122 
123     bool contains(Element*) const;
124     bool contains(const AtomicString& tagName) const;
125 
126     bool inScope(Element*) const;
127     bool inScope(const AtomicString& tagName) const;
128     bool inScope(const QualifiedName&) const;
129     bool inListItemScope(const AtomicString& tagName) const;
130     bool inListItemScope(const QualifiedName&) const;
131     bool inTableScope(const AtomicString& tagName) const;
132     bool inTableScope(const QualifiedName&) const;
133     bool inButtonScope(const AtomicString& tagName) const;
134     bool inButtonScope(const QualifiedName&) const;
135     bool inSelectScope(const AtomicString& tagName) const;
136     bool inSelectScope(const QualifiedName&) const;
137 
138     bool hasOnlyHTMLElementsInScope() const;
139     bool hasNumberedHeaderElementInScope() const;
140 
141     bool hasOnlyOneElement() const;
142     bool secondElementIsHTMLBodyElement() const;
143 
144     Element* htmlElement() const;
145     Element* headElement() const;
146     Element* bodyElement() const;
147 
148     ContainerNode* rootNode() const;
149 
150 #ifndef NDEBUG
151     void show();
152 #endif
153 
154 private:
155     void pushCommon(PassRefPtr<ContainerNode>);
156     void pushRootNodeCommon(PassRefPtr<ContainerNode>);
157     void popCommon();
158     void removeNonTopCommon(Element*);
159 
160     OwnPtr<ElementRecord> m_top;
161 
162     // We remember the root node, <head> and <body> as they are pushed. Their
163     // ElementRecords keep them alive. The root node is never popped.
164     // FIXME: We don't currently require type-specific information about
165     // these elements so we haven't yet bothered to plumb the types all the
166     // way down through createElement, etc.
167     ContainerNode* m_rootNode;
168     Element* m_headElement;
169     Element* m_bodyElement;
170 };
171 
isInHTMLNamespace(Node * node)172 inline bool isInHTMLNamespace(Node* node)
173 {
174     // A DocumentFragment takes the place of the document element when parsing
175     // fragments and should be considered in the HTML namespace.
176     return node->namespaceURI() == HTMLNames::xhtmlNamespaceURI
177         || node->nodeType() == Node::DOCUMENT_FRAGMENT_NODE
178         || node->nodeType() == Node::SHADOW_ROOT_NODE; // FIXME: Does this also apply to ShadowRoot?
179 }
180 
181 
182 } // namespace WebCore
183 
184 #endif // HTMLElementStack_h
185