1/*
2 * Copyright (C) 2012 Company 100, 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 HTMLStackItem_h
27#define HTMLStackItem_h
28
29#include "AtomicHTMLToken.h"
30#include "Element.h"
31#include "HTMLNames.h"
32#include "MathMLNames.h"
33#include "SVGNames.h"
34
35#include <wtf/RefCounted.h>
36#include <wtf/RefPtr.h>
37#include <wtf/text/AtomicString.h>
38
39namespace WebCore {
40
41class ContainerNode;
42
43class HTMLStackItem : public RefCounted<HTMLStackItem> {
44public:
45    enum ItemType {
46        ItemForContextElement,
47        ItemForDocumentFragmentNode
48    };
49
50    // Used by document fragment node and context element.
51    static PassRefPtr<HTMLStackItem> create(PassRefPtr<ContainerNode> node, ItemType type)
52    {
53        return adoptRef(new HTMLStackItem(node, type));
54    }
55
56    // Used by HTMLElementStack and HTMLFormattingElementList.
57    static PassRefPtr<HTMLStackItem> create(PassRefPtr<ContainerNode> node, AtomicHTMLToken* token, const AtomicString& namespaceURI = HTMLNames::xhtmlNamespaceURI)
58    {
59        return adoptRef(new HTMLStackItem(node, token, namespaceURI));
60    }
61
62    Element* element() const { return toElement(m_node.get()); }
63    ContainerNode* node() const { return m_node.get(); }
64
65    bool isDocumentFragmentNode() const { return m_isDocumentFragmentNode; }
66    bool isElementNode() const { return !m_isDocumentFragmentNode; }
67
68    const AtomicString& namespaceURI() const { return m_namespaceURI; }
69    const AtomicString& localName() const { return m_tokenLocalName; }
70
71    const Vector<Attribute>& attributes() const { ASSERT(m_tokenLocalName); return m_tokenAttributes; }
72    Attribute* getAttributeItem(const QualifiedName& attributeName)
73    {
74        ASSERT(m_tokenLocalName);
75        return findAttributeInVector(m_tokenAttributes, attributeName);
76    }
77
78    bool hasLocalName(const AtomicString& name) const { return m_tokenLocalName == name; }
79    bool hasTagName(const QualifiedName& name) const { return m_tokenLocalName == name.localName() && m_namespaceURI == name.namespaceURI(); }
80
81    bool matchesHTMLTag(const AtomicString& name) const { return m_tokenLocalName == name && m_namespaceURI == HTMLNames::xhtmlNamespaceURI; }
82    bool matchesHTMLTag(const QualifiedName& name) const { return m_tokenLocalName == name && m_namespaceURI == HTMLNames::xhtmlNamespaceURI; }
83
84    bool causesFosterParenting()
85    {
86        return hasTagName(HTMLNames::tableTag)
87            || hasTagName(HTMLNames::tbodyTag)
88            || hasTagName(HTMLNames::tfootTag)
89            || hasTagName(HTMLNames::theadTag)
90            || hasTagName(HTMLNames::trTag);
91    }
92
93    bool isInHTMLNamespace() const
94    {
95        // A DocumentFragment takes the place of the document element when parsing
96        // fragments and should be considered in the HTML namespace.
97        return namespaceURI() == HTMLNames::xhtmlNamespaceURI
98            || isDocumentFragmentNode(); // FIXME: Does this also apply to ShadowRoot?
99    }
100
101    bool isNumberedHeaderElement() const
102    {
103        return hasTagName(HTMLNames::h1Tag)
104            || hasTagName(HTMLNames::h2Tag)
105            || hasTagName(HTMLNames::h3Tag)
106            || hasTagName(HTMLNames::h4Tag)
107            || hasTagName(HTMLNames::h5Tag)
108            || hasTagName(HTMLNames::h6Tag);
109    }
110
111    bool isTableBodyContextElement() const
112    {
113        return hasTagName(HTMLNames::tbodyTag)
114            || hasTagName(HTMLNames::tfootTag)
115            || hasTagName(HTMLNames::theadTag);
116    }
117
118    // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#special
119    bool isSpecialNode() const
120    {
121        if (hasTagName(MathMLNames::miTag)
122            || hasTagName(MathMLNames::moTag)
123            || hasTagName(MathMLNames::mnTag)
124            || hasTagName(MathMLNames::msTag)
125            || hasTagName(MathMLNames::mtextTag)
126            || hasTagName(MathMLNames::annotation_xmlTag)
127            || hasTagName(SVGNames::foreignObjectTag)
128            || hasTagName(SVGNames::descTag)
129            || hasTagName(SVGNames::titleTag))
130            return true;
131        if (isDocumentFragmentNode())
132            return true;
133        if (!isInHTMLNamespace())
134            return false;
135        const AtomicString& tagName = localName();
136        return tagName == HTMLNames::addressTag
137            || tagName == HTMLNames::appletTag
138            || tagName == HTMLNames::areaTag
139            || tagName == HTMLNames::articleTag
140            || tagName == HTMLNames::asideTag
141            || tagName == HTMLNames::baseTag
142            || tagName == HTMLNames::basefontTag
143            || tagName == HTMLNames::bgsoundTag
144            || tagName == HTMLNames::blockquoteTag
145            || tagName == HTMLNames::bodyTag
146            || tagName == HTMLNames::brTag
147            || tagName == HTMLNames::buttonTag
148            || tagName == HTMLNames::captionTag
149            || tagName == HTMLNames::centerTag
150            || tagName == HTMLNames::colTag
151            || tagName == HTMLNames::colgroupTag
152            || tagName == HTMLNames::commandTag
153            || tagName == HTMLNames::ddTag
154            || tagName == HTMLNames::detailsTag
155            || tagName == HTMLNames::dirTag
156            || tagName == HTMLNames::divTag
157            || tagName == HTMLNames::dlTag
158            || tagName == HTMLNames::dtTag
159            || tagName == HTMLNames::embedTag
160            || tagName == HTMLNames::fieldsetTag
161            || tagName == HTMLNames::figcaptionTag
162            || tagName == HTMLNames::figureTag
163            || tagName == HTMLNames::footerTag
164            || tagName == HTMLNames::formTag
165            || tagName == HTMLNames::frameTag
166            || tagName == HTMLNames::framesetTag
167            || isNumberedHeaderElement()
168            || tagName == HTMLNames::headTag
169            || tagName == HTMLNames::headerTag
170            || tagName == HTMLNames::hgroupTag
171            || tagName == HTMLNames::hrTag
172            || tagName == HTMLNames::htmlTag
173            || tagName == HTMLNames::iframeTag
174            || tagName == HTMLNames::imgTag
175            || tagName == HTMLNames::inputTag
176            || tagName == HTMLNames::isindexTag
177            || tagName == HTMLNames::liTag
178            || tagName == HTMLNames::linkTag
179            || tagName == HTMLNames::listingTag
180            || tagName == HTMLNames::mainTag
181            || tagName == HTMLNames::marqueeTag
182            || tagName == HTMLNames::menuTag
183            || tagName == HTMLNames::metaTag
184            || tagName == HTMLNames::navTag
185            || tagName == HTMLNames::noembedTag
186            || tagName == HTMLNames::noframesTag
187            || tagName == HTMLNames::noscriptTag
188            || tagName == HTMLNames::objectTag
189            || tagName == HTMLNames::olTag
190            || tagName == HTMLNames::pTag
191            || tagName == HTMLNames::paramTag
192            || tagName == HTMLNames::plaintextTag
193            || tagName == HTMLNames::preTag
194            || tagName == HTMLNames::scriptTag
195            || tagName == HTMLNames::sectionTag
196            || tagName == HTMLNames::selectTag
197            || tagName == HTMLNames::styleTag
198            || tagName == HTMLNames::summaryTag
199            || tagName == HTMLNames::tableTag
200            || isTableBodyContextElement()
201            || tagName == HTMLNames::tdTag
202#if ENABLE(TEMPLATE_ELEMENT)
203            || tagName == HTMLNames::templateTag
204#endif
205            || tagName == HTMLNames::textareaTag
206            || tagName == HTMLNames::thTag
207            || tagName == HTMLNames::titleTag
208            || tagName == HTMLNames::trTag
209            || tagName == HTMLNames::ulTag
210            || tagName == HTMLNames::wbrTag
211            || tagName == HTMLNames::xmpTag;
212    }
213
214private:
215    HTMLStackItem(PassRefPtr<ContainerNode> node, ItemType type)
216        : m_node(node)
217    {
218        switch (type) {
219        case ItemForDocumentFragmentNode:
220            m_isDocumentFragmentNode = true;
221            break;
222        case ItemForContextElement:
223            m_tokenLocalName = m_node->localName();
224            m_namespaceURI = m_node->namespaceURI();
225            m_isDocumentFragmentNode = false;
226            break;
227        }
228    }
229
230    HTMLStackItem(PassRefPtr<ContainerNode> node, AtomicHTMLToken* token, const AtomicString& namespaceURI = HTMLNames::xhtmlNamespaceURI)
231        : m_node(node)
232        , m_tokenLocalName(token->name())
233        , m_tokenAttributes(token->attributes())
234        , m_namespaceURI(namespaceURI)
235        , m_isDocumentFragmentNode(false)
236    {
237    }
238
239    RefPtr<ContainerNode> m_node;
240
241    AtomicString m_tokenLocalName;
242    Vector<Attribute> m_tokenAttributes;
243    AtomicString m_namespaceURI;
244    bool m_isDocumentFragmentNode;
245};
246
247} // namespace WebCore
248
249#endif // HTMLStackItem_h
250