blob: b863c252f2f85747e403a4a8d48d0fb6778beee5 [file] [log] [blame]
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001/*
2 * Copyright (C) 2007 Apple Inc. All rights reserved.
3 * (C) 2008 Nikolas Zimmermann <zimmermann@kde.org>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 *
20 */
21
22#ifndef ContainerNodeAlgorithms_h
23#define ContainerNodeAlgorithms_h
24
25#include "core/dom/Document.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010026#include "core/html/HTMLFrameOwnerElement.h"
27#include "core/inspector/InspectorInstrumentation.h"
Ben Murdoch591b9582013-07-10 11:41:44 +010028#include "wtf/Assertions.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010029
30namespace WebCore {
31
32class ChildNodeInsertionNotifier {
33public:
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +000034 explicit ChildNodeInsertionNotifier(ContainerNode& insertionPoint)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010035 : m_insertionPoint(insertionPoint)
36 {
37 }
38
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +000039 void notify(Node&);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010040
41private:
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +000042 void notifyDescendantInsertedIntoDocument(ContainerNode&);
43 void notifyDescendantInsertedIntoTree(ContainerNode&);
44 void notifyNodeInsertedIntoDocument(Node&);
45 void notifyNodeInsertedIntoTree(ContainerNode&);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010046
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +000047 ContainerNode& m_insertionPoint;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010048 Vector< RefPtr<Node> > m_postInsertionNotificationTargets;
49};
50
51class ChildNodeRemovalNotifier {
52public:
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +000053 explicit ChildNodeRemovalNotifier(ContainerNode& insertionPoint)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010054 : m_insertionPoint(insertionPoint)
55 {
56 }
57
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +000058 void notify(Node&);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010059
60private:
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +000061 void notifyDescendantRemovedFromDocument(ContainerNode&);
62 void notifyDescendantRemovedFromTree(ContainerNode&);
63 void notifyNodeRemovedFromDocument(Node&);
64 void notifyNodeRemovedFromTree(ContainerNode&);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010065
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +000066 ContainerNode& m_insertionPoint;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010067};
68
69namespace Private {
70
71 template<class GenericNode, class GenericNodeContainer>
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +000072 void addChildNodesToDeletionQueue(GenericNode*& head, GenericNode*& tail, GenericNodeContainer&);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010073
74}
75
76// Helper functions for TreeShared-derived classes, which have a 'Node' style interface
77// This applies to 'ContainerNode' and 'SVGElementInstance'
78template<class GenericNode, class GenericNodeContainer>
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +000079inline void removeDetachedChildrenInContainer(GenericNodeContainer& container)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010080{
81 // List of nodes to be deleted.
82 GenericNode* head = 0;
83 GenericNode* tail = 0;
84
85 Private::addChildNodesToDeletionQueue<GenericNode, GenericNodeContainer>(head, tail, container);
86
87 GenericNode* n;
88 GenericNode* next;
89 while ((n = head) != 0) {
Torne (Richard Coles)1e202182013-10-18 15:46:42 +010090 ASSERT_WITH_SECURITY_IMPLICATION(n->m_deletionHasBegun);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010091
92 next = n->nextSibling();
93 n->setNextSibling(0);
94
95 head = next;
96 if (next == 0)
97 tail = 0;
98
99 if (n->hasChildNodes())
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000100 Private::addChildNodesToDeletionQueue<GenericNode, GenericNodeContainer>(head, tail, static_cast<GenericNodeContainer&>(*n));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100101
102 delete n;
103 }
104}
105
106template<class GenericNode, class GenericNodeContainer>
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000107inline void appendChildToContainer(GenericNode& child, GenericNodeContainer& container)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100108{
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000109 child.setParentOrShadowHostNode(&container);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100110
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000111 GenericNode* lastChild = container.lastChild();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100112 if (lastChild) {
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000113 child.setPreviousSibling(lastChild);
114 lastChild->setNextSibling(&child);
115 } else {
116 container.setFirstChild(&child);
117 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100118
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000119 container.setLastChild(&child);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100120}
121
122// Helper methods for removeDetachedChildrenInContainer, hidden from WebCore namespace
123namespace Private {
124
125 template<class GenericNode, class GenericNodeContainer, bool dispatchRemovalNotification>
126 struct NodeRemovalDispatcher {
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000127 static void dispatch(GenericNode&, GenericNodeContainer&)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100128 {
129 // no-op, by default
130 }
131 };
132
133 template<class GenericNode, class GenericNodeContainer>
134 struct NodeRemovalDispatcher<GenericNode, GenericNodeContainer, true> {
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000135 static void dispatch(GenericNode& node, GenericNodeContainer& container)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100136 {
137 // Clean up any TreeScope to a removed tree.
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000138 if (Document* containerDocument = container.ownerDocument())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100139 containerDocument->adoptIfNeeded(node);
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000140 if (node.inDocument())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100141 ChildNodeRemovalNotifier(container).notify(node);
142 }
143 };
144
145 template<class GenericNode>
146 struct ShouldDispatchRemovalNotification {
147 static const bool value = false;
148 };
149
150 template<>
151 struct ShouldDispatchRemovalNotification<Node> {
152 static const bool value = true;
153 };
154
155 template<class GenericNode, class GenericNodeContainer>
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000156 void addChildNodesToDeletionQueue(GenericNode*& head, GenericNode*& tail, GenericNodeContainer& container)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100157 {
158 // We have to tell all children that their parent has died.
159 GenericNode* next = 0;
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000160 for (GenericNode* n = container.firstChild(); n; n = next) {
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100161 ASSERT_WITH_SECURITY_IMPLICATION(!n->m_deletionHasBegun);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100162
163 next = n->nextSibling();
164 n->setNextSibling(0);
165 n->setParentOrShadowHostNode(0);
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000166 container.setFirstChild(next);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100167 if (next)
168 next->setPreviousSibling(0);
169
170 if (!n->refCount()) {
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100171#if SECURITY_ASSERT_ENABLED
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100172 n->m_deletionHasBegun = true;
173#endif
174 // Add the node to the list of nodes to be deleted.
175 // Reuse the nextSibling pointer for this purpose.
176 if (tail)
177 tail->setNextSibling(n);
178 else
179 head = n;
180
181 tail = n;
182 } else {
183 RefPtr<GenericNode> protect(n); // removedFromDocument may remove remove all references to this node.
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000184 NodeRemovalDispatcher<GenericNode, GenericNodeContainer, ShouldDispatchRemovalNotification<GenericNode>::value>::dispatch(*n, container);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100185 }
186 }
187
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000188 container.setLastChild(0);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100189 }
190
191} // namespace Private
192
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000193inline void ChildNodeInsertionNotifier::notifyNodeInsertedIntoDocument(Node& node)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100194{
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000195 ASSERT(m_insertionPoint.inDocument());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100196 RefPtr<Node> protect(node);
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000197 if (Node::InsertionShouldCallDidNotifySubtreeInsertions == node.insertedInto(&m_insertionPoint))
198 m_postInsertionNotificationTargets.append(&node);
199 if (node.isContainerNode())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100200 notifyDescendantInsertedIntoDocument(toContainerNode(node));
201}
202
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000203inline void ChildNodeInsertionNotifier::notifyNodeInsertedIntoTree(ContainerNode& node)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100204{
205 NoEventDispatchAssertion assertNoEventDispatch;
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000206 ASSERT(!m_insertionPoint.inDocument());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100207
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000208 if (Node::InsertionShouldCallDidNotifySubtreeInsertions == node.insertedInto(&m_insertionPoint))
209 m_postInsertionNotificationTargets.append(&node);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100210 notifyDescendantInsertedIntoTree(node);
211}
212
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000213inline void ChildNodeInsertionNotifier::notify(Node& node)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100214{
215 ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
216
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000217 InspectorInstrumentation::didInsertDOMNode(&node);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100218
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000219 RefPtr<Document> protectDocument(node.document());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100220 RefPtr<Node> protectNode(node);
221
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000222 if (m_insertionPoint.inDocument())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100223 notifyNodeInsertedIntoDocument(node);
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000224 else if (node.isContainerNode())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100225 notifyNodeInsertedIntoTree(toContainerNode(node));
226
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100227 for (size_t i = 0; i < m_postInsertionNotificationTargets.size(); ++i) {
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000228 Node* targetNode = m_postInsertionNotificationTargets[i].get();
229 if (targetNode->inDocument())
230 targetNode->didNotifySubtreeInsertionsToDocument();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100231 }
232}
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100233
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000234inline void ChildNodeRemovalNotifier::notifyNodeRemovedFromDocument(Node& node)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100235{
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000236 ASSERT(m_insertionPoint.inDocument());
237 node.removedFrom(&m_insertionPoint);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100238
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000239 if (node.isContainerNode())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100240 notifyDescendantRemovedFromDocument(toContainerNode(node));
241}
242
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000243inline void ChildNodeRemovalNotifier::notifyNodeRemovedFromTree(ContainerNode& node)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100244{
245 NoEventDispatchAssertion assertNoEventDispatch;
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000246 ASSERT(!m_insertionPoint.inDocument());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100247
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000248 node.removedFrom(&m_insertionPoint);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100249 notifyDescendantRemovedFromTree(node);
250}
251
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000252inline void ChildNodeRemovalNotifier::notify(Node& node)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100253{
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000254 if (node.inDocument()) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100255 notifyNodeRemovedFromDocument(node);
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000256 node.document().notifyRemovePendingSheetIfNeeded();
257 } else if (node.isContainerNode())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100258 notifyNodeRemovedFromTree(toContainerNode(node));
259}
260
261class ChildFrameDisconnector {
262public:
263 enum DisconnectPolicy {
264 RootAndDescendants,
265 DescendantsOnly
266 };
267
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000268 explicit ChildFrameDisconnector(Node& root)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100269 : m_root(root)
270 {
271 }
272
273 void disconnect(DisconnectPolicy = RootAndDescendants);
274
275private:
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000276 void collectFrameOwners(Node& root);
277 void collectFrameOwners(ElementShadow&);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100278 void disconnectCollectedFrameOwners();
279
280 Vector<RefPtr<HTMLFrameOwnerElement>, 10> m_frameOwners;
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000281 Node& m_root;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100282};
283
284#ifndef NDEBUG
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000285unsigned assertConnectedSubrameCountIsConsistent(Node&);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100286#endif
287
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000288inline void ChildFrameDisconnector::collectFrameOwners(Node& root)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100289{
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000290 if (!root.connectedSubframeCount())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100291 return;
292
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000293 if (root.isHTMLElement() && root.isFrameOwnerElement())
294 m_frameOwners.append(&toHTMLFrameOwnerElement(root));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100295
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000296 for (Node* child = root.firstChild(); child; child = child->nextSibling())
297 collectFrameOwners(*child);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100298
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000299 ElementShadow* shadow = root.isElementNode() ? toElement(root).shadow() : 0;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100300 if (shadow)
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000301 collectFrameOwners(*shadow);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100302}
303
304inline void ChildFrameDisconnector::disconnectCollectedFrameOwners()
305{
306 // Must disable frame loading in the subtree so an unload handler cannot
307 // insert more frames and create loaded frames in detached subtrees.
Torne (Richard Coles)19cde672013-11-06 12:28:04 +0000308 SubframeLoadingDisabler disabler(m_root);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100309
310 for (unsigned i = 0; i < m_frameOwners.size(); ++i) {
311 HTMLFrameOwnerElement* owner = m_frameOwners[i].get();
312 // Don't need to traverse up the tree for the first owner since no
313 // script could have moved it.
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000314 if (!i || m_root.containsIncludingShadowDOM(owner))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100315 owner->disconnectContentFrame();
316 }
317}
318
319inline void ChildFrameDisconnector::disconnect(DisconnectPolicy policy)
320{
321#ifndef NDEBUG
322 assertConnectedSubrameCountIsConsistent(m_root);
323#endif
324
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000325 if (!m_root.connectedSubframeCount())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100326 return;
327
328 if (policy == RootAndDescendants)
329 collectFrameOwners(m_root);
330 else {
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000331 for (Node* child = m_root.firstChild(); child; child = child->nextSibling())
332 collectFrameOwners(*child);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100333 }
334
335 disconnectCollectedFrameOwners();
336}
337
338} // namespace WebCore
339
340#endif // ContainerNodeAlgorithms_h