Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 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 | |
Ben Murdoch | df95704 | 2013-08-06 11:01:27 +0100 | [diff] [blame] | 27 | #include "bindings/v8/ExceptionStatePlaceholder.h" |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 28 | #include "core/dom/Node.h" |
Ben Murdoch | e69819b | 2013-07-17 14:56:49 +0100 | [diff] [blame] | 29 | #include "wtf/OwnPtr.h" |
| 30 | #include "wtf/Vector.h" |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 31 | |
| 32 | namespace WebCore { |
| 33 | |
Ben Murdoch | df95704 | 2013-08-06 11:01:27 +0100 | [diff] [blame] | 34 | class ExceptionState; |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 35 | class FloatPoint; |
Torne (Richard Coles) | e524955 | 2013-05-15 11:35:13 +0100 | [diff] [blame] | 36 | class HTMLCollection; |
| 37 | |
Torne (Richard Coles) | 93ac45c | 2013-05-29 14:40:20 +0100 | [diff] [blame] | 38 | typedef void (*NodeCallback)(Node*); |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 39 | |
Torne (Richard Coles) | 521d96e | 2013-06-19 11:58:24 +0100 | [diff] [blame] | 40 | namespace Private { |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 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 | |
Torne (Richard Coles) | e524955 | 2013-05-15 11:35:13 +0100 | [diff] [blame] | 90 | // ParentNode interface API |
| 91 | PassRefPtr<HTMLCollection> children(); |
| 92 | Element* firstElementChild() const; |
| 93 | Element* lastElementChild() const; |
| 94 | unsigned childElementCount() const; |
| 95 | |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 96 | unsigned childNodeCount() const; |
| 97 | Node* childNode(unsigned index) const; |
| 98 | |
Ben Murdoch | 1fad5ca | 2013-08-07 11:05:11 +0100 | [diff] [blame] | 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); |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 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 | |
Torne (Richard Coles) | 521d96e | 2013-06-19 11:58:24 +0100 | [diff] [blame] | 116 | virtual void attach(const AttachContext& = AttachContext()) OVERRIDE; |
| 117 | virtual void detach(const AttachContext& = AttachContext()) OVERRIDE; |
| 118 | virtual LayoutRect boundingBox() const OVERRIDE; |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 119 | virtual void setFocus(bool) OVERRIDE; |
| 120 | virtual void setActive(bool active = true, bool pause = false) OVERRIDE; |
| 121 | virtual void setHovered(bool = true) OVERRIDE; |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 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 | |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 130 | void disconnectDescendantFrames(); |
| 131 | |
| 132 | virtual bool childShouldCreateRenderer(const NodeRenderingContext&) const { return true; } |
| 133 | |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 134 | protected: |
Torne (Richard Coles) | 5267f70 | 2013-06-11 10:57:24 +0100 | [diff] [blame] | 135 | ContainerNode(TreeScope*, ConstructionType = CreateContainer); |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 136 | |
Torne (Richard Coles) | 93ac45c | 2013-05-29 14:40:20 +0100 | [diff] [blame] | 137 | static void queuePostAttachCallback(NodeCallback, Node*); |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 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 | |
Ben Murdoch | 591b958 | 2013-07-10 11:41:44 +0100 | [diff] [blame] | 154 | void attachChildren(const AttachContext& = AttachContext()); |
| 155 | void detachChildren(const AttachContext& = AttachContext()); |
| 156 | |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 157 | static void dispatchPostAttachCallbacks(); |
Torne (Richard Coles) | 5267f70 | 2013-06-11 10:57:24 +0100 | [diff] [blame] | 158 | |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 159 | void suspendPostAttachCallbacks(); |
| 160 | void resumePostAttachCallbacks(); |
| 161 | |
Torne (Richard Coles) | 521d96e | 2013-06-19 11:58:24 +0100 | [diff] [blame] | 162 | bool getUpperLeftCorner(FloatPoint&) const; |
| 163 | bool getLowerRightCorner(FloatPoint&) const; |
Torne (Richard Coles) | 5267f70 | 2013-06-11 10:57:24 +0100 | [diff] [blame] | 164 | |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 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 | |
Torne (Richard Coles) | 5267f70 | 2013-06-11 10:57:24 +0100 | [diff] [blame] | 188 | inline ContainerNode::ContainerNode(TreeScope* treeScope, ConstructionType type) |
| 189 | : Node(treeScope, type) |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 190 | , m_firstChild(0) |
| 191 | , m_lastChild(0) |
| 192 | { |
| 193 | } |
| 194 | |
Ben Murdoch | 591b958 | 2013-07-10 11:41:44 +0100 | [diff] [blame] | 195 | inline void ContainerNode::attachChildren(const AttachContext& context) |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 196 | { |
Ben Murdoch | 591b958 | 2013-07-10 11:41:44 +0100 | [diff] [blame] | 197 | AttachContext childrenContext(context); |
| 198 | childrenContext.resolvedStyle = 0; |
| 199 | |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 200 | for (Node* child = firstChild(); child; child = child->nextSibling()) { |
| 201 | ASSERT(!child->attached() || childAttachedAllowedWhenAttachingChildren(this)); |
| 202 | if (!child->attached()) |
Ben Murdoch | 591b958 | 2013-07-10 11:41:44 +0100 | [diff] [blame] | 203 | child->attach(childrenContext); |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 204 | } |
| 205 | } |
| 206 | |
Ben Murdoch | 591b958 | 2013-07-10 11:41:44 +0100 | [diff] [blame] | 207 | inline void ContainerNode::detachChildren(const AttachContext& context) |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 208 | { |
Ben Murdoch | 591b958 | 2013-07-10 11:41:44 +0100 | [diff] [blame] | 209 | AttachContext childrenContext(context); |
| 210 | childrenContext.resolvedStyle = 0; |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 211 | |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 212 | for (Node* child = firstChild(); child; child = child->nextSibling()) |
Ben Murdoch | 591b958 | 2013-07-10 11:41:44 +0100 | [diff] [blame] | 213 | child->detach(childrenContext); |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 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 | |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 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) |
Torne (Richard Coles) | 521d96e | 2013-06-19 11:58:24 +0100 | [diff] [blame] | 271 | : m_currentNode(parentNode->firstChild()) |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 272 | , m_currentIndex(0) |
| 273 | { |
| 274 | m_nextSnapshot = latestSnapshot; |
| 275 | latestSnapshot = this; |
| 276 | } |
| 277 | |
| 278 | ~ChildNodesLazySnapshot() |
| 279 | { |
| 280 | latestSnapshot = m_nextSnapshot; |
| 281 | } |
| 282 | |
Torne (Richard Coles) | 521d96e | 2013-06-19 11:58:24 +0100 | [diff] [blame] | 283 | // Returns 0 if there is no next Node. |
| 284 | PassRefPtr<Node> nextNode() |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 285 | { |
| 286 | if (LIKELY(!hasSnapshot())) { |
| 287 | RefPtr<Node> node = m_currentNode; |
| 288 | if (node) |
Torne (Richard Coles) | 521d96e | 2013-06-19 11:58:24 +0100 | [diff] [blame] | 289 | m_currentNode = node->nextSibling(); |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 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); |
Torne (Richard Coles) | 521d96e | 2013-06-19 11:58:24 +0100 | [diff] [blame] | 306 | node = node->nextSibling(); |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 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 | |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 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 |