1/* 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) 4 * (C) 2001 Dirk Mueller (mueller@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 "ExceptionCodePlaceholder.h" 28#include "Node.h" 29 30#include <wtf/OwnPtr.h> 31#include <wtf/Vector.h> 32 33namespace WebCore { 34 35class FloatPoint; 36 37typedef void (*NodeCallback)(Node*, unsigned); 38 39namespace Private { 40 template<class GenericNode, class GenericNodeContainer> 41 void addChildNodesToDeletionQueue(GenericNode*& head, GenericNode*& tail, GenericNodeContainer*); 42}; 43 44class NoEventDispatchAssertion { 45public: 46 NoEventDispatchAssertion() 47 { 48#ifndef NDEBUG 49 if (!isMainThread()) 50 return; 51 s_count++; 52#endif 53 } 54 55 ~NoEventDispatchAssertion() 56 { 57#ifndef NDEBUG 58 if (!isMainThread()) 59 return; 60 ASSERT(s_count); 61 s_count--; 62#endif 63 } 64 65#ifndef NDEBUG 66 static bool isEventDispatchForbidden() 67 { 68 if (!isMainThread()) 69 return false; 70 return s_count; 71 } 72#endif 73 74private: 75#ifndef NDEBUG 76 static unsigned s_count; 77#endif 78}; 79 80class ContainerNode : public Node { 81 friend class PostAttachCallbackDisabler; 82public: 83 virtual ~ContainerNode(); 84 85 Node* firstChild() const { return m_firstChild; } 86 Node* lastChild() const { return m_lastChild; } 87 bool hasChildNodes() const { return m_firstChild; } 88 89 unsigned childNodeCount() const; 90 Node* childNode(unsigned index) const; 91 92 bool insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionCode& = ASSERT_NO_EXCEPTION, AttachBehavior = AttachNow); 93 bool replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionCode& = ASSERT_NO_EXCEPTION, AttachBehavior = AttachNow); 94 bool removeChild(Node* child, ExceptionCode& = ASSERT_NO_EXCEPTION); 95 bool appendChild(PassRefPtr<Node> newChild, ExceptionCode& = ASSERT_NO_EXCEPTION, AttachBehavior = AttachNow); 96 97 // These methods are only used during parsing. 98 // They don't send DOM mutation events or handle reparenting. 99 // However, arbitrary code may be run by beforeload handlers. 100 void parserAppendChild(PassRefPtr<Node>); 101 void parserRemoveChild(Node*); 102 void parserInsertBefore(PassRefPtr<Node> newChild, Node* refChild); 103 104 void removeChildren(); 105 void takeAllChildrenFrom(ContainerNode*); 106 107 void cloneChildNodes(ContainerNode* clone); 108 109 virtual void attach(const AttachContext& = AttachContext()) OVERRIDE; 110 virtual void detach(const AttachContext& = AttachContext()) OVERRIDE; 111 virtual LayoutRect boundingBox() const OVERRIDE; 112 virtual void scheduleSetNeedsStyleRecalc(StyleChangeType = FullStyleChange) OVERRIDE FINAL; 113 114 // ----------------------------------------------------------------------------- 115 // Notification of document structure changes (see Node.h for more notification methods) 116 117 // Notifies the node that it's list of children have changed (either by adding or removing child nodes), or a child 118 // node that is of the type CDATA_SECTION_NODE, TEXT_NODE or COMMENT_NODE has changed its value. 119 virtual void childrenChanged(bool createdByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0); 120 121 void attachChildren(); 122 void attachChildrenLazily(); 123 void detachChildren(); 124 void detachChildrenIfNeeded(); 125 126 void disconnectDescendantFrames(); 127 128 virtual bool childShouldCreateRenderer(const NodeRenderingContext&) const { return true; } 129 130protected: 131 ContainerNode(Document*, ConstructionType = CreateContainer); 132 133 static void queuePostAttachCallback(NodeCallback, Node*, unsigned = 0); 134 static bool postAttachCallbacksAreSuspended(); 135 136 template<class GenericNode, class GenericNodeContainer> 137 friend void appendChildToContainer(GenericNode* child, GenericNodeContainer*); 138 139 template<class GenericNode, class GenericNodeContainer> 140 friend void Private::addChildNodesToDeletionQueue(GenericNode*& head, GenericNode*& tail, GenericNodeContainer*); 141 142 void removeDetachedChildren(); 143 void setFirstChild(Node* child) { m_firstChild = child; } 144 void setLastChild(Node* child) { m_lastChild = child; } 145 146private: 147 void removeBetween(Node* previousChild, Node* nextChild, Node* oldChild); 148 void insertBeforeCommon(Node* nextChild, Node* oldChild); 149 150 static void dispatchPostAttachCallbacks(); 151 void suspendPostAttachCallbacks(); 152 void resumePostAttachCallbacks(); 153 154 bool getUpperLeftCorner(FloatPoint&) const; 155 bool getLowerRightCorner(FloatPoint&) const; 156 157 Node* m_firstChild; 158 Node* m_lastChild; 159}; 160 161#ifndef NDEBUG 162bool childAttachedAllowedWhenAttachingChildren(ContainerNode*); 163#endif 164 165inline ContainerNode* toContainerNode(Node* node) 166{ 167 ASSERT_WITH_SECURITY_IMPLICATION(!node || node->isContainerNode()); 168 return static_cast<ContainerNode*>(node); 169} 170 171inline const ContainerNode* toContainerNode(const Node* node) 172{ 173 ASSERT_WITH_SECURITY_IMPLICATION(!node || node->isContainerNode()); 174 return static_cast<const ContainerNode*>(node); 175} 176 177// This will catch anyone doing an unnecessary cast. 178void toContainerNode(const ContainerNode*); 179 180inline ContainerNode::ContainerNode(Document* document, ConstructionType type) 181 : Node(document, type) 182 , m_firstChild(0) 183 , m_lastChild(0) 184{ 185} 186 187inline void ContainerNode::attachChildren() 188{ 189 for (Node* child = firstChild(); child; child = child->nextSibling()) { 190 ASSERT(!child->attached() || childAttachedAllowedWhenAttachingChildren(this)); 191 if (!child->attached()) 192 child->attach(); 193 } 194} 195 196inline void ContainerNode::attachChildrenLazily() 197{ 198 for (Node* child = firstChild(); child; child = child->nextSibling()) 199 if (!child->attached()) 200 child->lazyAttach(); 201} 202 203inline void ContainerNode::detachChildrenIfNeeded() 204{ 205 for (Node* child = firstChild(); child; child = child->nextSibling()) { 206 if (child->attached()) 207 child->detach(); 208 } 209} 210 211inline void ContainerNode::detachChildren() 212{ 213 for (Node* child = firstChild(); child; child = child->nextSibling()) 214 child->detach(); 215} 216 217inline unsigned Node::childNodeCount() const 218{ 219 if (!isContainerNode()) 220 return 0; 221 return toContainerNode(this)->childNodeCount(); 222} 223 224inline Node* Node::childNode(unsigned index) const 225{ 226 if (!isContainerNode()) 227 return 0; 228 return toContainerNode(this)->childNode(index); 229} 230 231inline Node* Node::firstChild() const 232{ 233 if (!isContainerNode()) 234 return 0; 235 return toContainerNode(this)->firstChild(); 236} 237 238inline Node* Node::lastChild() const 239{ 240 if (!isContainerNode()) 241 return 0; 242 return toContainerNode(this)->lastChild(); 243} 244 245inline Node* Node::highestAncestor() const 246{ 247 Node* node = const_cast<Node*>(this); 248 Node* highest = node; 249 for (; node; node = node->parentNode()) 250 highest = node; 251 return highest; 252} 253 254inline bool Node::needsShadowTreeWalker() const 255{ 256 if (getFlag(NeedsShadowTreeWalkerFlag)) 257 return true; 258 ContainerNode* parent = parentOrShadowHostNode(); 259 return parent && parent->getFlag(NeedsShadowTreeWalkerFlag); 260} 261 262inline bool Node::isTreeScope() const 263{ 264 return treeScope()->rootNode() == this; 265} 266 267// This constant controls how much buffer is initially allocated 268// for a Node Vector that is used to store child Nodes of a given Node. 269// FIXME: Optimize the value. 270const int initialNodeVectorSize = 11; 271typedef Vector<RefPtr<Node>, initialNodeVectorSize> NodeVector; 272 273inline void getChildNodes(Node* node, NodeVector& nodes) 274{ 275 ASSERT(!nodes.size()); 276 for (Node* child = node->firstChild(); child; child = child->nextSibling()) 277 nodes.append(child); 278} 279 280class ChildNodesLazySnapshot { 281 WTF_MAKE_NONCOPYABLE(ChildNodesLazySnapshot); 282 WTF_MAKE_FAST_ALLOCATED; 283public: 284 explicit ChildNodesLazySnapshot(Node* parentNode) 285 : m_currentNode(parentNode->firstChild()) 286 , m_currentIndex(0) 287 { 288 m_nextSnapshot = latestSnapshot; 289 latestSnapshot = this; 290 } 291 292 ~ChildNodesLazySnapshot() 293 { 294 latestSnapshot = m_nextSnapshot; 295 } 296 297 // Returns 0 if there is no next Node. 298 PassRefPtr<Node> nextNode() 299 { 300 if (LIKELY(!hasSnapshot())) { 301 RefPtr<Node> node = m_currentNode; 302 if (node) 303 m_currentNode = node->nextSibling(); 304 return node.release(); 305 } 306 Vector<RefPtr<Node> >& nodeVector = *m_childNodes; 307 if (m_currentIndex >= nodeVector.size()) 308 return 0; 309 return nodeVector[m_currentIndex++]; 310 } 311 312 void takeSnapshot() 313 { 314 if (hasSnapshot()) 315 return; 316 m_childNodes = adoptPtr(new Vector<RefPtr<Node> >()); 317 Node* node = m_currentNode.get(); 318 while (node) { 319 m_childNodes->append(node); 320 node = node->nextSibling(); 321 } 322 } 323 324 ChildNodesLazySnapshot* nextSnapshot() { return m_nextSnapshot; } 325 bool hasSnapshot() { return !!m_childNodes.get(); } 326 327 static void takeChildNodesLazySnapshot() 328 { 329 ChildNodesLazySnapshot* snapshot = latestSnapshot; 330 while (snapshot && !snapshot->hasSnapshot()) { 331 snapshot->takeSnapshot(); 332 snapshot = snapshot->nextSnapshot(); 333 } 334 } 335 336private: 337 static ChildNodesLazySnapshot* latestSnapshot; 338 339 RefPtr<Node> m_currentNode; 340 unsigned m_currentIndex; 341 OwnPtr<Vector<RefPtr<Node> > > m_childNodes; // Lazily instantiated. 342 ChildNodesLazySnapshot* m_nextSnapshot; 343}; 344 345class PostAttachCallbackDisabler { 346public: 347 PostAttachCallbackDisabler(ContainerNode* node) 348 : m_node(node) 349 { 350 ASSERT(m_node); 351 m_node->suspendPostAttachCallbacks(); 352 } 353 354 ~PostAttachCallbackDisabler() 355 { 356 m_node->resumePostAttachCallbacks(); 357 } 358 359private: 360 ContainerNode* m_node; 361}; 362 363} // namespace WebCore 364 365#endif // ContainerNode_h 366