2010-06-30 Eric Seidel <eric@webkit.org>
[WebKit-https.git] / WebCore / html / HTMLElementStack.cpp
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 #include "config.h"
27 #include "HTMLElementStack.h"
28
29 #include "Element.h"
30 #include <wtf/PassOwnPtr.h>
31
32 namespace WebCore {
33
34 class HTMLElementStack::ElementRecord : public Noncopyable {
35 public:
36     ElementRecord(PassRefPtr<Element> element, PassOwnPtr<ElementRecord> next)
37         : m_element(element)
38         , m_next(next)
39     {
40     }
41
42     Element* element() const { return m_element.get(); }
43     ElementRecord* next() const { return m_next.get(); }
44     PassOwnPtr<ElementRecord> releaseNext() { return m_next.release(); }
45     void setNext(PassOwnPtr<ElementRecord> next) { m_next = next; }
46
47 private:
48     RefPtr<Element> m_element;
49     OwnPtr<ElementRecord> m_next;
50 };
51
52 HTMLElementStack::HTMLElementStack()
53     : m_htmlElement(0)
54     , m_headElement(0)
55     , m_bodyElement(0)
56 {
57 }
58
59 HTMLElementStack::~HTMLElementStack()
60 {
61 }
62
63 void HTMLElementStack::popHTMLHeadElement()
64 {
65     ASSERT(top() == m_headElement);
66     m_headElement = 0;
67     popCommon();
68 }
69
70 void HTMLElementStack::pop()
71 {
72     ASSERT(!top()->hasTagName(HTMLNames::headTag));
73     popCommon();
74 }
75
76 void HTMLElementStack::pushHTMLHtmlElement(PassRefPtr<Element> element)
77 {
78     ASSERT(element->hasTagName(HTMLNames::htmlTag));
79     ASSERT(!m_htmlElement);
80     m_htmlElement = element.get();
81     pushCommon(element);
82 }
83
84 void HTMLElementStack::pushHTMLHeadElement(PassRefPtr<Element> element)
85 {
86     ASSERT(element->hasTagName(HTMLNames::headTag));
87     ASSERT(!m_headElement);
88     m_headElement = element.get();
89     pushCommon(element);
90 }
91
92 void HTMLElementStack::pushHTMLBodyElement(PassRefPtr<Element> element)
93 {
94     ASSERT(element->hasTagName(HTMLNames::bodyTag));
95     ASSERT(!m_bodyElement);
96     m_bodyElement = element.get();
97     pushCommon(element);
98 }
99
100 void HTMLElementStack::push(PassRefPtr<Element> element)
101 {
102     ASSERT(!element->hasTagName(HTMLNames::htmlTag));
103     ASSERT(!element->hasTagName(HTMLNames::headTag));
104     ASSERT(!element->hasTagName(HTMLNames::bodyTag));
105     ASSERT(m_htmlElement);
106     pushCommon(element);
107 }
108
109 Element* HTMLElementStack::top() const
110 {
111     return m_top->element();
112 }
113
114 void HTMLElementStack::removeHTMLHeadElement(Element* element)
115 {
116     ASSERT(m_headElement == element);
117     if (m_top->element() == element) {
118         popHTMLHeadElement();
119         return;
120     }
121     m_headElement = 0;
122     removeNonFirstCommon(element);
123 }
124
125 void HTMLElementStack::remove(Element* element)
126 {
127     ASSERT(!element->hasTagName(HTMLNames::headTag));
128     if (m_top->element() == element) {
129         pop();
130         return;
131     }
132     removeNonFirstCommon(element);
133 }
134
135 bool HTMLElementStack::contains(Element* element) const
136 {
137     for (ElementRecord* pos = m_top.get(); pos; pos = pos->next()) {
138         if (pos->element() == element)
139             return true;
140     }
141     return false;
142 }
143
144 bool HTMLElementStack::inScope(const AtomicString& name) const
145 {
146     // FIXME: This algorithm is wrong.
147     for (ElementRecord* pos = m_top.get(); pos; pos = pos->next()) {
148         if (pos->element()->tagQName() == name)
149             return true;
150     }
151     return false;
152 }
153
154 bool HTMLElementStack::inScope(Element* element) const
155 {
156     // FIXME: This algorithm is wrong.
157     return contains(element);
158 }
159
160 Element* HTMLElementStack::htmlElement()
161 {
162     ASSERT(m_htmlElement);
163     return m_htmlElement;
164 }
165
166 Element* HTMLElementStack::headElement()
167 {
168     ASSERT(m_headElement);
169     return m_headElement;
170 }
171
172 Element* HTMLElementStack::bodyElement()
173 {
174     ASSERT(m_bodyElement);
175     return m_bodyElement;
176 }
177
178 void HTMLElementStack::pushCommon(PassRefPtr<Element> element)
179 {
180     m_top.set(new ElementRecord(element, m_top.release()));
181     top()->beginParsingChildren();
182 }
183
184 void HTMLElementStack::popCommon()
185 {
186     ASSERT(!top()->hasTagName(HTMLNames::htmlTag));
187     ASSERT(!top()->hasTagName(HTMLNames::bodyTag));
188     top()->finishParsingChildren();
189     m_top = m_top->releaseNext();
190 }
191
192 void HTMLElementStack::removeNonFirstCommon(Element* element)
193 {
194     ASSERT(!element->hasTagName(HTMLNames::htmlTag));
195     ASSERT(!element->hasTagName(HTMLNames::bodyTag));
196     ElementRecord* pos = m_top.get();
197     ASSERT(pos->element() != element);
198     while (pos->next()) {
199         if (pos->next()->element() == element) {
200             // FIXME: Is it OK to call finishParsingChildren()
201             // when the children aren't actually finished?
202             element->finishParsingChildren();
203             pos->setNext(pos->next()->releaseNext());
204             return;
205         }
206     }
207     ASSERT_NOT_REACHED();
208 }
209
210 }