blob: 86f37de9c13f6aee7f79c56958a88dc583a40fa4 [file] [log] [blame]
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001/*
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 Murdochdf957042013-08-06 11:01:27 +010027#include "bindings/v8/ExceptionStatePlaceholder.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010028#include "core/dom/Node.h"
Ben Murdoche69819b2013-07-17 14:56:49 +010029#include "wtf/OwnPtr.h"
30#include "wtf/Vector.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010031
32namespace WebCore {
33
Ben Murdochdf957042013-08-06 11:01:27 +010034class ExceptionState;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010035class FloatPoint;
Torne (Richard Coles)e5249552013-05-15 11:35:13 +010036class HTMLCollection;
37
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +010038typedef void (*NodeCallback)(Node*);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010039
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +010040namespace Private {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010041 template<class GenericNode, class GenericNodeContainer>
42 void addChildNodesToDeletionQueue(GenericNode*& head, GenericNode*& tail, GenericNodeContainer*);
43};
44
45class NoEventDispatchAssertion {
46public:
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
75private:
76#ifndef NDEBUG
77 static unsigned s_count;
78#endif
79};
80
81class ContainerNode : public Node {
82 friend class PostAttachCallbackDisabler;
83public:
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)e5249552013-05-15 11:35:13 +010090 // ParentNode interface API
91 PassRefPtr<HTMLCollection> children();
92 Element* firstElementChild() const;
93 Element* lastElementChild() const;
94 unsigned childElementCount() const;
95
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010096 unsigned childNodeCount() const;
97 Node* childNode(unsigned index) const;
98
Ben Murdoch1fad5ca2013-08-07 11:05:11 +010099 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)53e740f2013-05-09 18:38:43 +0100103
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)521d96e2013-06-19 11:58:24 +0100116 virtual void attach(const AttachContext& = AttachContext()) OVERRIDE;
117 virtual void detach(const AttachContext& = AttachContext()) OVERRIDE;
118 virtual LayoutRect boundingBox() const OVERRIDE;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100119 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)53e740f2013-05-09 18:38:43 +0100122
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)53e740f2013-05-09 18:38:43 +0100130 void disconnectDescendantFrames();
131
132 virtual bool childShouldCreateRenderer(const NodeRenderingContext&) const { return true; }
133
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100134protected:
Torne (Richard Coles)5267f702013-06-11 10:57:24 +0100135 ContainerNode(TreeScope*, ConstructionType = CreateContainer);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100136
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +0100137 static void queuePostAttachCallback(NodeCallback, Node*);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100138 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
150private:
151 void removeBetween(Node* previousChild, Node* nextChild, Node* oldChild);
152 void insertBeforeCommon(Node* nextChild, Node* oldChild);
153
Ben Murdoch591b9582013-07-10 11:41:44 +0100154 void attachChildren(const AttachContext& = AttachContext());
155 void detachChildren(const AttachContext& = AttachContext());
156
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100157 static void dispatchPostAttachCallbacks();
Torne (Richard Coles)5267f702013-06-11 10:57:24 +0100158
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100159 void suspendPostAttachCallbacks();
160 void resumePostAttachCallbacks();
161
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100162 bool getUpperLeftCorner(FloatPoint&) const;
163 bool getLowerRightCorner(FloatPoint&) const;
Torne (Richard Coles)5267f702013-06-11 10:57:24 +0100164
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100165 Node* m_firstChild;
166 Node* m_lastChild;
167};
168
169#ifndef NDEBUG
170bool childAttachedAllowedWhenAttachingChildren(ContainerNode*);
171#endif
172
173inline ContainerNode* toContainerNode(Node* node)
174{
175 ASSERT_WITH_SECURITY_IMPLICATION(!node || node->isContainerNode());
176 return static_cast<ContainerNode*>(node);
177}
178
179inline 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.
186void toContainerNode(const ContainerNode*);
187
Torne (Richard Coles)5267f702013-06-11 10:57:24 +0100188inline ContainerNode::ContainerNode(TreeScope* treeScope, ConstructionType type)
189 : Node(treeScope, type)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100190 , m_firstChild(0)
191 , m_lastChild(0)
192{
193}
194
Ben Murdoch591b9582013-07-10 11:41:44 +0100195inline void ContainerNode::attachChildren(const AttachContext& context)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100196{
Ben Murdoch591b9582013-07-10 11:41:44 +0100197 AttachContext childrenContext(context);
198 childrenContext.resolvedStyle = 0;
199
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100200 for (Node* child = firstChild(); child; child = child->nextSibling()) {
201 ASSERT(!child->attached() || childAttachedAllowedWhenAttachingChildren(this));
202 if (!child->attached())
Ben Murdoch591b9582013-07-10 11:41:44 +0100203 child->attach(childrenContext);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100204 }
205}
206
Ben Murdoch591b9582013-07-10 11:41:44 +0100207inline void ContainerNode::detachChildren(const AttachContext& context)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100208{
Ben Murdoch591b9582013-07-10 11:41:44 +0100209 AttachContext childrenContext(context);
210 childrenContext.resolvedStyle = 0;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100211
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100212 for (Node* child = firstChild(); child; child = child->nextSibling())
Ben Murdoch591b9582013-07-10 11:41:44 +0100213 child->detach(childrenContext);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100214}
215
216inline unsigned Node::childNodeCount() const
217{
218 if (!isContainerNode())
219 return 0;
220 return toContainerNode(this)->childNodeCount();
221}
222
223inline Node* Node::childNode(unsigned index) const
224{
225 if (!isContainerNode())
226 return 0;
227 return toContainerNode(this)->childNode(index);
228}
229
230inline Node* Node::firstChild() const
231{
232 if (!isContainerNode())
233 return 0;
234 return toContainerNode(this)->firstChild();
235}
236
237inline Node* Node::lastChild() const
238{
239 if (!isContainerNode())
240 return 0;
241 return toContainerNode(this)->lastChild();
242}
243
244inline 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)53e740f2013-05-09 18:38:43 +0100253// 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.
256const int initialNodeVectorSize = 11;
257typedef Vector<RefPtr<Node>, initialNodeVectorSize> NodeVector;
258
259inline 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
266class ChildNodesLazySnapshot {
267 WTF_MAKE_NONCOPYABLE(ChildNodesLazySnapshot);
268 WTF_MAKE_FAST_ALLOCATED;
269public:
270 explicit ChildNodesLazySnapshot(Node* parentNode)
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100271 : m_currentNode(parentNode->firstChild())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100272 , 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)521d96e2013-06-19 11:58:24 +0100283 // Returns 0 if there is no next Node.
284 PassRefPtr<Node> nextNode()
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100285 {
286 if (LIKELY(!hasSnapshot())) {
287 RefPtr<Node> node = m_currentNode;
288 if (node)
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100289 m_currentNode = node->nextSibling();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100290 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)521d96e2013-06-19 11:58:24 +0100306 node = node->nextSibling();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100307 }
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
322private:
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)53e740f2013-05-09 18:38:43 +0100331class PostAttachCallbackDisabler {
332public:
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
345private:
346 ContainerNode* m_node;
347};
348
349} // namespace WebCore
350
351#endif // ContainerNode_h