1 /* 2 * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org) 3 * (C) 1999 Antti Koivisto (koivisto (at) kde.org) 4 * (C) 2001 Dirk Mueller (mueller (at) kde.org) 5 * Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010, 2011 Apple Inc. All rights reserved. 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Library General Public 9 * License as published by the Free Software Foundation; either 10 * version 2 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Library General Public License for more details. 16 * 17 * You should have received a copy of the GNU Library General Public License 18 * along with this library; see the file COPYING.LIB. If not, write to 19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 20 * Boston, MA 02110-1301, USA. 21 * 22 */ 23 24 #ifndef ContainerNode_h 25 #define ContainerNode_h 26 27 #include "bindings/v8/ExceptionStatePlaceholder.h" 28 #include "core/dom/Node.h" 29 #include "wtf/OwnPtr.h" 30 #include "wtf/Vector.h" 31 32 namespace WebCore { 33 34 class ExceptionState; 35 class FloatPoint; 36 class HTMLCollection; 37 38 namespace Private { 39 template<class GenericNode, class GenericNodeContainer> 40 void addChildNodesToDeletionQueue(GenericNode*& head, GenericNode*& tail, GenericNodeContainer&); 41 } 42 43 class NoEventDispatchAssertion { 44 public: 45 NoEventDispatchAssertion() 46 { 47 #ifndef NDEBUG 48 if (!isMainThread()) 49 return; 50 s_count++; 51 #endif 52 } 53 54 ~NoEventDispatchAssertion() 55 { 56 #ifndef NDEBUG 57 if (!isMainThread()) 58 return; 59 ASSERT(s_count); 60 s_count--; 61 #endif 62 } 63 64 #ifndef NDEBUG 65 static bool isEventDispatchForbidden() 66 { 67 if (!isMainThread()) 68 return false; 69 return s_count; 70 } 71 #endif 72 73 private: 74 #ifndef NDEBUG 75 static unsigned s_count; 76 #endif 77 }; 78 79 class ContainerNode : public Node { 80 public: 81 virtual ~ContainerNode(); 82 83 Node* firstChild() const { return m_firstChild; } 84 Node* lastChild() const { return m_lastChild; } 85 bool hasChildNodes() const { return m_firstChild; } 86 87 bool hasOneChild() const { return m_firstChild && !m_firstChild->nextSibling(); } 88 bool hasOneTextChild() const { return hasOneChild() && m_firstChild->isTextNode(); } 89 90 // ParentNode interface API 91 PassRefPtr<HTMLCollection> children(); 92 Element* firstElementChild() const; 93 Element* lastElementChild() const; 94 unsigned childElementCount() const; 95 96 unsigned childNodeCount() const; 97 Node* childNode(unsigned index) const; 98 99 void insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionState& = ASSERT_NO_EXCEPTION); 100 void replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionState& = ASSERT_NO_EXCEPTION); 101 void removeChild(Node* child, ExceptionState& = ASSERT_NO_EXCEPTION); 102 void appendChild(PassRefPtr<Node> newChild, ExceptionState& = ASSERT_NO_EXCEPTION); 103 104 // These methods are only used during parsing. 105 // They don't send DOM mutation events or handle reparenting. 106 // However, arbitrary code may be run by beforeload handlers. 107 void parserAppendChild(PassRefPtr<Node>); 108 void parserRemoveChild(Node&); 109 void parserInsertBefore(PassRefPtr<Node> newChild, Node& refChild); 110 void parserTakeAllChildrenFrom(ContainerNode&); 111 112 void removeChildren(); 113 114 void cloneChildNodes(ContainerNode* clone); 115 116 virtual void attach(const AttachContext& = AttachContext()) OVERRIDE; 117 virtual void detach(const AttachContext& = AttachContext()) OVERRIDE; 118 virtual LayoutRect boundingBox() const OVERRIDE; 119 virtual void setFocus(bool) OVERRIDE; 120 void focusStateChanged(); 121 virtual void setActive(bool = true) OVERRIDE; 122 virtual void setHovered(bool = true) OVERRIDE; 123 124 // ----------------------------------------------------------------------------- 125 // Notification of document structure changes (see core/dom/Node.h for more notification methods) 126 127 // Notifies the node that it's list of children have changed (either by adding or removing child nodes), or a child 128 // node that is of the type CDATA_SECTION_NODE, TEXT_NODE or COMMENT_NODE has changed its value. 129 virtual void childrenChanged(bool createdByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0); 130 131 void disconnectDescendantFrames(); 132 133 virtual bool childShouldCreateRenderer(const Node& child) const { return true; } 134 135 protected: 136 ContainerNode(TreeScope*, ConstructionType = CreateContainer); 137 138 template<class GenericNode, class GenericNodeContainer> 139 friend void appendChildToContainer(GenericNode& child, GenericNodeContainer&); 140 141 template<class GenericNode, class GenericNodeContainer> 142 friend void Private::addChildNodesToDeletionQueue(GenericNode*& head, GenericNode*& tail, GenericNodeContainer&); 143 144 void removeDetachedChildren(); 145 void setFirstChild(Node* child) { m_firstChild = child; } 146 void setLastChild(Node* child) { m_lastChild = child; } 147 148 private: 149 void removeBetween(Node* previousChild, Node* nextChild, Node& oldChild); 150 void insertBeforeCommon(Node& nextChild, Node& oldChild); 151 void updateTreeAfterInsertion(Node& child); 152 void willRemoveChildren(); 153 void willRemoveChild(Node& child); 154 155 inline bool checkAcceptChildGuaranteedNodeTypes(const Node& newChild, ExceptionState&) const; 156 inline bool checkAcceptChild(const Node* newChild, const Node* oldChild, ExceptionState&) const; 157 inline bool containsConsideringHostElements(const Node&) const; 158 inline bool isChildTypeAllowed(const Node& child) const; 159 160 void attachChildren(const AttachContext& = AttachContext()); 161 void detachChildren(const AttachContext& = AttachContext()); 162 163 bool getUpperLeftCorner(FloatPoint&) const; 164 bool getLowerRightCorner(FloatPoint&) const; 165 166 Node* m_firstChild; 167 Node* m_lastChild; 168 }; 169 170 #ifndef NDEBUG 171 bool childAttachedAllowedWhenAttachingChildren(ContainerNode*); 172 #endif 173 174 DEFINE_NODE_TYPE_CASTS(ContainerNode, isContainerNode()); 175 176 inline ContainerNode::ContainerNode(TreeScope* treeScope, ConstructionType type) 177 : Node(treeScope, type) 178 , m_firstChild(0) 179 , m_lastChild(0) 180 { 181 } 182 183 inline void ContainerNode::attachChildren(const AttachContext& context) 184 { 185 AttachContext childrenContext(context); 186 childrenContext.resolvedStyle = 0; 187 188 for (Node* child = firstChild(); child; child = child->nextSibling()) { 189 ASSERT(child->needsAttach() || childAttachedAllowedWhenAttachingChildren(this)); 190 if (child->needsAttach()) 191 child->attach(childrenContext); 192 } 193 } 194 195 inline void ContainerNode::detachChildren(const AttachContext& context) 196 { 197 AttachContext childrenContext(context); 198 childrenContext.resolvedStyle = 0; 199 200 for (Node* child = firstChild(); child; child = child->nextSibling()) 201 child->detach(childrenContext); 202 } 203 204 inline unsigned Node::childNodeCount() const 205 { 206 if (!isContainerNode()) 207 return 0; 208 return toContainerNode(this)->childNodeCount(); 209 } 210 211 inline Node* Node::childNode(unsigned index) const 212 { 213 if (!isContainerNode()) 214 return 0; 215 return toContainerNode(this)->childNode(index); 216 } 217 218 inline Node* Node::firstChild() const 219 { 220 if (!isContainerNode()) 221 return 0; 222 return toContainerNode(this)->firstChild(); 223 } 224 225 inline Node* Node::lastChild() const 226 { 227 if (!isContainerNode()) 228 return 0; 229 return toContainerNode(this)->lastChild(); 230 } 231 232 inline Node* Node::highestAncestor() const 233 { 234 Node* node = const_cast<Node*>(this); 235 Node* highest = node; 236 for (; node; node = node->parentNode()) 237 highest = node; 238 return highest; 239 } 240 241 // This constant controls how much buffer is initially allocated 242 // for a Node Vector that is used to store child Nodes of a given Node. 243 // FIXME: Optimize the value. 244 const int initialNodeVectorSize = 11; 245 typedef Vector<RefPtr<Node>, initialNodeVectorSize> NodeVector; 246 247 inline void getChildNodes(Node& node, NodeVector& nodes) 248 { 249 ASSERT(!nodes.size()); 250 for (Node* child = node.firstChild(); child; child = child->nextSibling()) 251 nodes.append(child); 252 } 253 254 class ChildNodesLazySnapshot { 255 WTF_MAKE_NONCOPYABLE(ChildNodesLazySnapshot); 256 WTF_MAKE_FAST_ALLOCATED; 257 public: 258 explicit ChildNodesLazySnapshot(Node& parentNode) 259 : m_currentNode(parentNode.firstChild()) 260 , m_currentIndex(0) 261 { 262 m_nextSnapshot = latestSnapshot; 263 latestSnapshot = this; 264 } 265 266 ~ChildNodesLazySnapshot() 267 { 268 latestSnapshot = m_nextSnapshot; 269 } 270 271 // Returns 0 if there is no next Node. 272 PassRefPtr<Node> nextNode() 273 { 274 if (LIKELY(!hasSnapshot())) { 275 RefPtr<Node> node = m_currentNode; 276 if (node) 277 m_currentNode = node->nextSibling(); 278 return node.release(); 279 } 280 Vector<RefPtr<Node> >& nodeVector = *m_childNodes; 281 if (m_currentIndex >= nodeVector.size()) 282 return 0; 283 return nodeVector[m_currentIndex++]; 284 } 285 286 void takeSnapshot() 287 { 288 if (hasSnapshot()) 289 return; 290 m_childNodes = adoptPtr(new Vector<RefPtr<Node> >()); 291 Node* node = m_currentNode.get(); 292 while (node) { 293 m_childNodes->append(node); 294 node = node->nextSibling(); 295 } 296 } 297 298 ChildNodesLazySnapshot* nextSnapshot() { return m_nextSnapshot; } 299 bool hasSnapshot() { return !!m_childNodes.get(); } 300 301 static void takeChildNodesLazySnapshot() 302 { 303 ChildNodesLazySnapshot* snapshot = latestSnapshot; 304 while (snapshot && !snapshot->hasSnapshot()) { 305 snapshot->takeSnapshot(); 306 snapshot = snapshot->nextSnapshot(); 307 } 308 } 309 310 private: 311 static ChildNodesLazySnapshot* latestSnapshot; 312 313 RefPtr<Node> m_currentNode; 314 unsigned m_currentIndex; 315 OwnPtr<Vector<RefPtr<Node> > > m_childNodes; // Lazily instantiated. 316 ChildNodesLazySnapshot* m_nextSnapshot; 317 }; 318 319 } // namespace WebCore 320 321 #endif // ContainerNode_h 322