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 typedef void (*NodeCallback)(Node*); 39 40 namespace Private { 41 template<class GenericNode, class GenericNodeContainer> 42 void addChildNodesToDeletionQueue(GenericNode*& head, GenericNode*& tail, GenericNodeContainer*); 43 }; 44 45 class NoEventDispatchAssertion { 46 public: 47 NoEventDispatchAssertion() 48 { 49 #ifndef NDEBUG 50 if (!isMainThread()) 51 return; 52 s_count++; 53 #endif 54 } 55 56 ~NoEventDispatchAssertion() 57 { 58 #ifndef NDEBUG 59 if (!isMainThread()) 60 return; 61 ASSERT(s_count); 62 s_count--; 63 #endif 64 } 65 66 #ifndef NDEBUG 67 static bool isEventDispatchForbidden() 68 { 69 if (!isMainThread()) 70 return false; 71 return s_count; 72 } 73 #endif 74 75 private: 76 #ifndef NDEBUG 77 static unsigned s_count; 78 #endif 79 }; 80 81 class ContainerNode : public Node { 82 friend class PostAttachCallbackDisabler; 83 public: 84 virtual ~ContainerNode(); 85 86 Node* firstChild() const { return m_firstChild; } 87 Node* lastChild() const { return m_lastChild; } 88 bool hasChildNodes() const { return m_firstChild; } 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, AttachBehavior = AttachNow); 100 void replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionState& = ASSERT_NO_EXCEPTION, AttachBehavior = AttachNow); 101 void removeChild(Node* child, ExceptionState& = ASSERT_NO_EXCEPTION); 102 void appendChild(PassRefPtr<Node> newChild, ExceptionState& = ASSERT_NO_EXCEPTION, AttachBehavior = AttachNow); 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 111 void removeChildren(); 112 void takeAllChildrenFrom(ContainerNode*); 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 virtual void setActive(bool active = true, bool pause = false) OVERRIDE; 121 virtual void setHovered(bool = true) OVERRIDE; 122 123 // ----------------------------------------------------------------------------- 124 // Notification of document structure changes (see core/dom/Node.h for more notification methods) 125 126 // Notifies the node that it's list of children have changed (either by adding or removing child nodes), or a child 127 // node that is of the type CDATA_SECTION_NODE, TEXT_NODE or COMMENT_NODE has changed its value. 128 virtual void childrenChanged(bool createdByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0); 129 130 void disconnectDescendantFrames(); 131 132 virtual bool childShouldCreateRenderer(const NodeRenderingContext&) const { return true; } 133 134 protected: 135 ContainerNode(TreeScope*, ConstructionType = CreateContainer); 136 137 static void queuePostAttachCallback(NodeCallback, Node*); 138 static bool postAttachCallbacksAreSuspended(); 139 140 template<class GenericNode, class GenericNodeContainer> 141 friend void appendChildToContainer(GenericNode* child, GenericNodeContainer*); 142 143 template<class GenericNode, class GenericNodeContainer> 144 friend void Private::addChildNodesToDeletionQueue(GenericNode*& head, GenericNode*& tail, GenericNodeContainer*); 145 146 void removeDetachedChildren(); 147 void setFirstChild(Node* child) { m_firstChild = child; } 148 void setLastChild(Node* child) { m_lastChild = child; } 149 150 private: 151 void removeBetween(Node* previousChild, Node* nextChild, Node* oldChild); 152 void insertBeforeCommon(Node* nextChild, Node* oldChild); 153 154 void attachChildren(const AttachContext& = AttachContext()); 155 void detachChildren(const AttachContext& = AttachContext()); 156 157 static void dispatchPostAttachCallbacks(); 158 159 void suspendPostAttachCallbacks(); 160 void resumePostAttachCallbacks(); 161 162 bool getUpperLeftCorner(FloatPoint&) const; 163 bool getLowerRightCorner(FloatPoint&) const; 164 165 Node* m_firstChild; 166 Node* m_lastChild; 167 }; 168 169 #ifndef NDEBUG 170 bool childAttachedAllowedWhenAttachingChildren(ContainerNode*); 171 #endif 172 173 inline ContainerNode* toContainerNode(Node* node) 174 { 175 ASSERT_WITH_SECURITY_IMPLICATION(!node || node->isContainerNode()); 176 return static_cast<ContainerNode*>(node); 177 } 178 179 inline const ContainerNode* toContainerNode(const Node* node) 180 { 181 ASSERT_WITH_SECURITY_IMPLICATION(!node || node->isContainerNode()); 182 return static_cast<const ContainerNode*>(node); 183 } 184 185 // This will catch anyone doing an unnecessary cast. 186 void toContainerNode(const ContainerNode*); 187 188 inline ContainerNode::ContainerNode(TreeScope* treeScope, ConstructionType type) 189 : Node(treeScope, type) 190 , m_firstChild(0) 191 , m_lastChild(0) 192 { 193 } 194 195 inline void ContainerNode::attachChildren(const AttachContext& context) 196 { 197 AttachContext childrenContext(context); 198 childrenContext.resolvedStyle = 0; 199 200 for (Node* child = firstChild(); child; child = child->nextSibling()) { 201 ASSERT(!child->attached() || childAttachedAllowedWhenAttachingChildren(this)); 202 if (!child->attached()) 203 child->attach(childrenContext); 204 } 205 } 206 207 inline void ContainerNode::detachChildren(const AttachContext& context) 208 { 209 AttachContext childrenContext(context); 210 childrenContext.resolvedStyle = 0; 211 212 for (Node* child = firstChild(); child; child = child->nextSibling()) 213 child->detach(childrenContext); 214 } 215 216 inline unsigned Node::childNodeCount() const 217 { 218 if (!isContainerNode()) 219 return 0; 220 return toContainerNode(this)->childNodeCount(); 221 } 222 223 inline Node* Node::childNode(unsigned index) const 224 { 225 if (!isContainerNode()) 226 return 0; 227 return toContainerNode(this)->childNode(index); 228 } 229 230 inline Node* Node::firstChild() const 231 { 232 if (!isContainerNode()) 233 return 0; 234 return toContainerNode(this)->firstChild(); 235 } 236 237 inline Node* Node::lastChild() const 238 { 239 if (!isContainerNode()) 240 return 0; 241 return toContainerNode(this)->lastChild(); 242 } 243 244 inline Node* Node::highestAncestor() const 245 { 246 Node* node = const_cast<Node*>(this); 247 Node* highest = node; 248 for (; node; node = node->parentNode()) 249 highest = node; 250 return highest; 251 } 252 253 // This constant controls how much buffer is initially allocated 254 // for a Node Vector that is used to store child Nodes of a given Node. 255 // FIXME: Optimize the value. 256 const int initialNodeVectorSize = 11; 257 typedef Vector<RefPtr<Node>, initialNodeVectorSize> NodeVector; 258 259 inline void getChildNodes(Node* node, NodeVector& nodes) 260 { 261 ASSERT(!nodes.size()); 262 for (Node* child = node->firstChild(); child; child = child->nextSibling()) 263 nodes.append(child); 264 } 265 266 class ChildNodesLazySnapshot { 267 WTF_MAKE_NONCOPYABLE(ChildNodesLazySnapshot); 268 WTF_MAKE_FAST_ALLOCATED; 269 public: 270 explicit ChildNodesLazySnapshot(Node* parentNode) 271 : m_currentNode(parentNode->firstChild()) 272 , m_currentIndex(0) 273 { 274 m_nextSnapshot = latestSnapshot; 275 latestSnapshot = this; 276 } 277 278 ~ChildNodesLazySnapshot() 279 { 280 latestSnapshot = m_nextSnapshot; 281 } 282 283 // Returns 0 if there is no next Node. 284 PassRefPtr<Node> nextNode() 285 { 286 if (LIKELY(!hasSnapshot())) { 287 RefPtr<Node> node = m_currentNode; 288 if (node) 289 m_currentNode = node->nextSibling(); 290 return node.release(); 291 } 292 Vector<RefPtr<Node> >& nodeVector = *m_childNodes; 293 if (m_currentIndex >= nodeVector.size()) 294 return 0; 295 return nodeVector[m_currentIndex++]; 296 } 297 298 void takeSnapshot() 299 { 300 if (hasSnapshot()) 301 return; 302 m_childNodes = adoptPtr(new Vector<RefPtr<Node> >()); 303 Node* node = m_currentNode.get(); 304 while (node) { 305 m_childNodes->append(node); 306 node = node->nextSibling(); 307 } 308 } 309 310 ChildNodesLazySnapshot* nextSnapshot() { return m_nextSnapshot; } 311 bool hasSnapshot() { return !!m_childNodes.get(); } 312 313 static void takeChildNodesLazySnapshot() 314 { 315 ChildNodesLazySnapshot* snapshot = latestSnapshot; 316 while (snapshot && !snapshot->hasSnapshot()) { 317 snapshot->takeSnapshot(); 318 snapshot = snapshot->nextSnapshot(); 319 } 320 } 321 322 private: 323 static ChildNodesLazySnapshot* latestSnapshot; 324 325 RefPtr<Node> m_currentNode; 326 unsigned m_currentIndex; 327 OwnPtr<Vector<RefPtr<Node> > > m_childNodes; // Lazily instantiated. 328 ChildNodesLazySnapshot* m_nextSnapshot; 329 }; 330 331 class PostAttachCallbackDisabler { 332 public: 333 PostAttachCallbackDisabler(ContainerNode* node) 334 : m_node(node) 335 { 336 ASSERT(m_node); 337 m_node->suspendPostAttachCallbacks(); 338 } 339 340 ~PostAttachCallbackDisabler() 341 { 342 m_node->resumePostAttachCallbacks(); 343 } 344 345 private: 346 ContainerNode* m_node; 347 }; 348 349 } // namespace WebCore 350 351 #endif // ContainerNode_h 352