X-Git-Url: http://git.webkit.org/?p=WebKit-https.git;a=blobdiff_plain;f=WebCore%2Fhtml%2FHTMLElementStack.cpp;h=d1a1752bd3c457d32a3ed686e8d81263ab7eff28;hp=70761c6e20432fa8110bbce1c8a3d39d4bd0b14f;hb=6eff49aa6ffcab45490fa065bc041b14046f968e;hpb=ef98f505ca0de980447ae02f7f664a4b2df3ac57 diff --git a/WebCore/html/HTMLElementStack.cpp b/WebCore/html/HTMLElementStack.cpp index 70761c6e..d1a1752 100644 --- a/WebCore/html/HTMLElementStack.cpp +++ b/WebCore/html/HTMLElementStack.cpp @@ -38,23 +38,79 @@ namespace WebCore { using namespace HTMLNames; -class HTMLElementStack::ElementRecord : public Noncopyable { -public: - ElementRecord(PassRefPtr element, PassOwnPtr next) - : m_element(element) - , m_next(next) - { - } +namespace { + +inline bool isScopeMarker(Element* element) +{ + return element->hasTagName(appletTag) + || element->hasTagName(buttonTag) + || element->hasTagName(captionTag) +#if ENABLE(SVG_FOREIGN_OBJECT) + || element->hasTagName(SVGNames::foreignObjectTag) +#endif + || element->hasTagName(htmlTag) + || element->hasTagName(marqueeTag) + || element->hasTagName(objectTag) + || element->hasTagName(tableTag) + || element->hasTagName(tdTag) + || element->hasTagName(thTag); +} + +inline bool isListItemScopeMarker(Element* element) +{ + return isScopeMarker(element) + || element->hasTagName(olTag) + || element->hasTagName(ulTag); +} + +inline bool isTableScopeMarker(Element* element) +{ + return element->hasTagName(tableTag) + || element->hasTagName(htmlTag); +} + +inline bool isTableBodyScopeMarker(Element* element) +{ + return element->hasTagName(tbodyTag) + || element->hasTagName(tfootTag) + || element->hasTagName(theadTag) + || element->hasTagName(htmlTag); +} - Element* element() const { return m_element.get(); } - ElementRecord* next() const { return m_next.get(); } - PassOwnPtr releaseNext() { return m_next.release(); } - void setNext(PassOwnPtr next) { m_next = next; } +inline bool isTableRowScopeMarker(Element* element) +{ + return element->hasTagName(trTag) + || element->hasTagName(htmlTag); +} -private: - RefPtr m_element; - OwnPtr m_next; -}; +} + +HTMLElementStack::ElementRecord::ElementRecord(PassRefPtr element, PassOwnPtr next) + : m_element(element) + , m_next(next) +{ + ASSERT(m_element); +} + +HTMLElementStack::ElementRecord::~ElementRecord() +{ +} + +void HTMLElementStack::ElementRecord::replaceElement(PassRefPtr element) +{ + ASSERT(element); + // FIXME: Should this call finishParsingChildren? + m_element = element; +} + +bool HTMLElementStack::ElementRecord::isAbove(ElementRecord* other) const +{ + for (ElementRecord* below = next(); below; below = below->next()) { + if (below == other) + return true; + } + return false; +} HTMLElementStack::HTMLElementStack() : m_htmlElement(0) @@ -87,6 +143,12 @@ void HTMLElementStack::pop() popCommon(); } +void HTMLElementStack::popUntilElementWithNamespace(const AtomicString& namespaceURI) +{ + while (top()->namespaceURI() != namespaceURI) + pop(); +} + void HTMLElementStack::popUntil(const AtomicString& tagName) { while (!top()->hasLocalName(tagName)) { @@ -96,14 +158,48 @@ void HTMLElementStack::popUntil(const AtomicString& tagName) } } +void HTMLElementStack::popUntilPopped(const AtomicString& tagName) +{ + popUntil(tagName); + pop(); +} + void HTMLElementStack::popUntil(Element* element) { while (top() != element) pop(); } +void HTMLElementStack::popUntilPopped(Element* element) +{ + popUntil(element); + pop(); +} + +void HTMLElementStack::popUntilTableScopeMarker() +{ + // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#clear-the-stack-back-to-a-table-context + while (!isTableScopeMarker(top())) + pop(); +} + +void HTMLElementStack::popUntilTableBodyScopeMarker() +{ + // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#clear-the-stack-back-to-a-table-body-context + while (!isTableBodyScopeMarker(top())) + pop(); +} + +void HTMLElementStack::popUntilTableRowScopeMarker() +{ + // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#clear-the-stack-back-to-a-table-row-context + while (!isTableRowScopeMarker(top())) + pop(); +} + void HTMLElementStack::pushHTMLHtmlElement(PassRefPtr element) { + ASSERT(!m_top); // should always be the bottom of the stack. ASSERT(element->hasTagName(HTMLNames::htmlTag)); ASSERT(!m_htmlElement); m_htmlElement = element.get(); @@ -135,11 +231,56 @@ void HTMLElementStack::push(PassRefPtr element) pushCommon(element); } +void HTMLElementStack::insertAbove(PassRefPtr element, ElementRecord* recordBelow) +{ + ASSERT(element); + ASSERT(recordBelow); + ASSERT(m_top); + ASSERT(!element->hasTagName(HTMLNames::htmlTag)); + ASSERT(!element->hasTagName(HTMLNames::headTag)); + ASSERT(!element->hasTagName(HTMLNames::bodyTag)); + ASSERT(m_htmlElement); + if (recordBelow == m_top) { + push(element); + return; + } + + for (ElementRecord* recordAbove = m_top.get(); recordAbove; recordAbove = recordAbove->next()) { + if (recordAbove->next() != recordBelow) + continue; + + recordAbove->setNext(new ElementRecord(element, recordAbove->releaseNext())); + recordAbove->next()->element()->beginParsingChildren(); + return; + } + ASSERT_NOT_REACHED(); +} + +HTMLElementStack::ElementRecord* HTMLElementStack::topRecord() const +{ + ASSERT(m_top); + return m_top.get(); +} + Element* HTMLElementStack::top() const { + ASSERT(m_top->element()); return m_top->element(); } +Element* HTMLElementStack::oneBelowTop() const +{ + // We should never be calling this if it could be 0. + ASSERT(m_top); + ASSERT(m_top->next()); + return m_top->next()->element(); +} + +Element* HTMLElementStack::bottom() const +{ + return htmlElement(); +} + void HTMLElementStack::removeHTMLHeadElement(Element* element) { ASSERT(m_headElement == element); @@ -148,7 +289,7 @@ void HTMLElementStack::removeHTMLHeadElement(Element* element) return; } m_headElement = 0; - removeNonFirstCommon(element); + removeNonTopCommon(element); } void HTMLElementStack::remove(Element* element) @@ -158,53 +299,33 @@ void HTMLElementStack::remove(Element* element) pop(); return; } - removeNonFirstCommon(element); + removeNonTopCommon(element); } -bool HTMLElementStack::contains(Element* element) const +HTMLElementStack::ElementRecord* HTMLElementStack::find(Element* element) const { for (ElementRecord* pos = m_top.get(); pos; pos = pos->next()) { if (pos->element() == element) - return true; + return pos; } - return false; + return 0; } -namespace { - -inline bool isScopeMarker(const Element* element) +HTMLElementStack::ElementRecord* HTMLElementStack::topmost(const AtomicString& tagName) const { - return element->hasTagName(appletTag) - || element->hasTagName(captionTag) - || element->hasTagName(appletTag) - || element->hasTagName(htmlTag) - || element->hasTagName(tableTag) - || element->hasTagName(tdTag) - || element->hasTagName(thTag) - || element->hasTagName(buttonTag) - || element->hasTagName(marqueeTag) - || element->hasTagName(objectTag) -#if ENABLE(SVG_FOREIGN_OBJECT) - || element->hasTagName(SVGNames::foreignObjectTag) -#endif - ; + for (ElementRecord* pos = m_top.get(); pos; pos = pos->next()) { + if (pos->element()->hasLocalName(tagName)) + return pos; + } + return 0; } -inline bool isListItemScopeMarker(const Element* element) -{ - return isScopeMarker(element) - || element->hasTagName(olTag) - || element->hasTagName(ulTag); -} -inline bool isTableScopeMarker(const Element* element) +bool HTMLElementStack::contains(Element* element) const { - return element->hasTagName(htmlTag) - || element->hasTagName(tableTag); -} - + return !!find(element); } -template +template bool inScopeCommon(HTMLElementStack::ElementRecord* top, const AtomicString& targetTag) { for (HTMLElementStack::ElementRecord* pos = top; pos; pos = pos->next()) { @@ -218,6 +339,19 @@ bool inScopeCommon(HTMLElementStack::ElementRecord* top, const AtomicString& tar return false; } +bool HTMLElementStack::hasOnlyHTMLElementsInScope() const +{ + for (ElementRecord* record = m_top.get(); record; record = record->next()) { + Element* element = record->element(); + if (element->namespaceURI() != xhtmlNamespaceURI) + return false; + if (isScopeMarker(element)) + return true; + } + ASSERT_NOT_REACHED(); // is always on the stack and is a scope marker. + return true; +} + bool HTMLElementStack::inScope(Element* targetElement) const { for (ElementRecord* pos = m_top.get(); pos; pos = pos->next()) { @@ -236,29 +370,47 @@ bool HTMLElementStack::inScope(const AtomicString& targetTag) const return inScopeCommon(m_top.get(), targetTag); } +bool HTMLElementStack::inScope(const QualifiedName& tagName) const +{ + // FIXME: Is localName() right for non-html elements? + return inScope(tagName.localName()); +} + bool HTMLElementStack::inListItemScope(const AtomicString& targetTag) const { return inScopeCommon(m_top.get(), targetTag); } +bool HTMLElementStack::inListItemScope(const QualifiedName& tagName) const +{ + // FIXME: Is localName() right for non-html elements? + return inListItemScope(tagName.localName()); +} + bool HTMLElementStack::inTableScope(const AtomicString& targetTag) const { return inScopeCommon(m_top.get(), targetTag); } -Element* HTMLElementStack::htmlElement() +bool HTMLElementStack::inTableScope(const QualifiedName& tagName) const +{ + // FIXME: Is localName() right for non-html elements? + return inTableScope(tagName.localName()); +} + +Element* HTMLElementStack::htmlElement() const { ASSERT(m_htmlElement); return m_htmlElement; } -Element* HTMLElementStack::headElement() +Element* HTMLElementStack::headElement() const { ASSERT(m_headElement); return m_headElement; } -Element* HTMLElementStack::bodyElement() +Element* HTMLElementStack::bodyElement() const { ASSERT(m_bodyElement); return m_bodyElement; @@ -266,6 +418,7 @@ Element* HTMLElementStack::bodyElement() void HTMLElementStack::pushCommon(PassRefPtr element) { + ASSERT(m_htmlElement); m_top.set(new ElementRecord(element, m_top.release())); top()->beginParsingChildren(); } @@ -279,13 +432,12 @@ void HTMLElementStack::popCommon() m_top = m_top->releaseNext(); } -void HTMLElementStack::removeNonFirstCommon(Element* element) +void HTMLElementStack::removeNonTopCommon(Element* element) { ASSERT(!element->hasTagName(HTMLNames::htmlTag)); ASSERT(!element->hasTagName(HTMLNames::bodyTag)); - ElementRecord* pos = m_top.get(); - ASSERT(pos->element() != element); - while (pos->next()) { + ASSERT(top() != element); + for (ElementRecord* pos = m_top.get(); pos; pos = pos->next()) { if (pos->next()->element() == element) { // FIXME: Is it OK to call finishParsingChildren() // when the children aren't actually finished? @@ -297,4 +449,14 @@ void HTMLElementStack::removeNonFirstCommon(Element* element) ASSERT_NOT_REACHED(); } +#ifndef NDEBUG + +void HTMLElementStack::show() +{ + for (ElementRecord* record = m_top.get(); record; record = record->next()) + record->element()->showNode(); +} + +#endif + }