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 58 Element* element() const { return toElement(m_node.get()); } 59 ContainerNode* node() const { return m_node.get(); } 60 void replaceElement(PassRefPtr<Element>); 61 62 bool isAbove(ElementRecord*) const; 63 64 ElementRecord* next() const { return m_next.get(); } 65 66 private: 67 friend class HTMLElementStack; 68 69 ElementRecord(PassRefPtr<ContainerNode>, PassOwnPtr<ElementRecord>); 70 71 PassOwnPtr<ElementRecord> releaseNext() { return m_next.release(); } 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. 80 Element* top() const 81 { 82 ASSERT(m_top->element()); 83 return m_top->element(); 84 } 85 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 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 } 179 180 181 } // namespace WebCore 182 183 #endif // HTMLElementStack_h 184