Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(154)

Side by Side Diff: third_party/WebKit/Source/core/dom/ContainerNode.cpp

Issue 2317573003: Introduce ContainerNode::insertNodeVector() to share code in insertBefore(), appendChild(), and rep… (Closed)
Patch Set: Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/WebKit/Source/core/dom/ContainerNode.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org) 3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2001 Dirk Mueller (mueller@kde.org) 4 * (C) 2001 Dirk Mueller (mueller@kde.org)
5 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2013 Apple Inc. All rights reserved. 5 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2013 Apple Inc. All rights reserved.
6 * 6 *
7 * This library is free software; you can redistribute it and/or 7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public 8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either 9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version. 10 * version 2 of the License, or (at your option) any later version.
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
143 exceptionState.throwDOMException(HierarchyRequestError, "The new child e lement contains the parent."); 143 exceptionState.throwDOMException(HierarchyRequestError, "The new child e lement contains the parent.");
144 return false; 144 return false;
145 } 145 }
146 if (!isChildTypeAllowed(newChild)) { 146 if (!isChildTypeAllowed(newChild)) {
147 exceptionState.throwDOMException(HierarchyRequestError, "Nodes of type ' " + newChild.nodeName() + "' may not be inserted inside nodes of type '" + nodeN ame() + "'."); 147 exceptionState.throwDOMException(HierarchyRequestError, "Nodes of type ' " + newChild.nodeName() + "' may not be inserted inside nodes of type '" + nodeN ame() + "'.");
148 return false; 148 return false;
149 } 149 }
150 return true; 150 return true;
151 } 151 }
152 152
153 void ContainerNode::insertNodeVector(const NodeVector& targets, Node* next, bool (ContainerNode::*mutator)(Node& child, Node* next))
tkent 2016/09/07 04:39:23 Functor is a smarter solution. But I feel functor
hayato 2016/09/07 04:56:50 I see. However, I'm afraid that `mutator` can not
tkent 2016/09/07 07:28:02 I observed no performance differences with dromaeo
154 {
155 InspectorInstrumentation::willInsertDOMNode(this);
156 for (const auto& targetNode : targets) {
157 DCHECK(targetNode);
158 {
159 EventDispatchForbiddenScope assertNoEventDispatch;
160 ScriptForbiddenScope forbidScript;
161
162 if (!(this->*mutator)(*targetNode, next))
163 break;
164 }
165
166 updateTreeAfterInsertion(*targetNode);
167 }
168
169 dispatchSubtreeModifiedEvent();
170 }
171
153 Node* ContainerNode::insertBefore(Node* newChild, Node* refChild, ExceptionState & exceptionState) 172 Node* ContainerNode::insertBefore(Node* newChild, Node* refChild, ExceptionState & exceptionState)
154 { 173 {
155 // insertBefore(node, 0) is equivalent to appendChild(node) 174 // insertBefore(node, 0) is equivalent to appendChild(node)
156 if (!refChild) { 175 if (!refChild) {
157 return appendChild(newChild, exceptionState); 176 return appendChild(newChild, exceptionState);
158 } 177 }
159 178
160 // Make sure adding the new child is OK. 179 // Make sure adding the new child is OK.
161 if (!checkAcceptChild(newChild, 0, exceptionState)) { 180 if (!checkAcceptChild(newChild, 0, exceptionState)) {
162 if (exceptionState.hadException()) 181 if (exceptionState.hadException())
(...skipping 21 matching lines...) Expand all
184 if (targets.isEmpty()) 203 if (targets.isEmpty())
185 return newChild; 204 return newChild;
186 205
187 // We need this extra check because collectChildrenAndRemoveFromOldParent() can fire mutation events. 206 // We need this extra check because collectChildrenAndRemoveFromOldParent() can fire mutation events.
188 if (!checkAcceptChildGuaranteedNodeTypes(*newChild, nullptr, exceptionState) ) { 207 if (!checkAcceptChildGuaranteedNodeTypes(*newChild, nullptr, exceptionState) ) {
189 if (exceptionState.hadException()) 208 if (exceptionState.hadException())
190 return nullptr; 209 return nullptr;
191 return newChild; 210 return newChild;
192 } 211 }
193 212
194 InspectorInstrumentation::willInsertDOMNode(this);
195
196 ChildListMutationScope mutation(*this); 213 ChildListMutationScope mutation(*this);
197 for (const auto& targetNode : targets) { 214 insertNodeVector(targets, next, &ContainerNode::insertBeforeCommonWithAdopti on);
198 DCHECK(targetNode);
199 Node& child = *targetNode;
200
201 // Due to arbitrary code running in response to a DOM mutation event it' s
202 // possible that "next" is no longer a child of "this".
203 // It's also possible that "child" has been inserted elsewhere.
204 // In either of those cases, we'll just stop.
205 if (next->parentNode() != this)
206 break;
207 if (child.parentNode())
208 break;
209
210 {
211 EventDispatchForbiddenScope assertNoEventDispatch;
212 ScriptForbiddenScope forbidScript;
213
214 treeScope().adoptIfNeeded(child);
215 insertBeforeCommon(*next, child);
216 }
217
218 updateTreeAfterInsertion(child);
219 }
220
221 dispatchSubtreeModifiedEvent();
222
223 return newChild; 215 return newChild;
224 } 216 }
225 217
218 bool ContainerNode::insertBeforeCommonWithAdoption(Node& newChild, Node* next)
219 {
220 DCHECK(next);
221 // Due to arbitrary code running in response to a DOM mutation event it's
222 // possible that "next" is no longer a child of "this".
223 // It's also possible that "child" has been inserted elsewhere. In either
224 // of those cases, we'll just stop.
225 if (next->parentNode() != this)
226 return false;
227 if (newChild.parentNode())
228 return false;
229
230 treeScope().adoptIfNeeded(newChild);
231 insertBeforeCommon(*next, newChild);
232 return true;
233 }
234
226 void ContainerNode::insertBeforeCommon(Node& nextChild, Node& newChild) 235 void ContainerNode::insertBeforeCommon(Node& nextChild, Node& newChild)
227 { 236 {
228 EventDispatchForbiddenScope assertNoEventDispatch; 237 EventDispatchForbiddenScope assertNoEventDispatch;
229 ScriptForbiddenScope forbidScript; 238 ScriptForbiddenScope forbidScript;
230 239
231 DCHECK(!newChild.parentNode()); // Use insertBefore if you need to handle re parenting (and want DOM mutation events). 240 DCHECK(!newChild.parentNode()); // Use insertBefore if you need to handle re parenting (and want DOM mutation events).
232 DCHECK(!newChild.nextSibling()); 241 DCHECK(!newChild.nextSibling());
233 DCHECK(!newChild.previousSibling()); 242 DCHECK(!newChild.previousSibling());
234 DCHECK(!newChild.isShadowRoot()); 243 DCHECK(!newChild.isShadowRoot());
235 244
236 Node* prev = nextChild.previousSibling(); 245 Node* prev = nextChild.previousSibling();
237 DCHECK_NE(m_lastChild, prev); 246 DCHECK_NE(m_lastChild, prev);
238 nextChild.setPreviousSibling(&newChild); 247 nextChild.setPreviousSibling(&newChild);
239 if (prev) { 248 if (prev) {
240 DCHECK_NE(firstChild(), nextChild); 249 DCHECK_NE(firstChild(), nextChild);
241 DCHECK_EQ(prev->nextSibling(), nextChild); 250 DCHECK_EQ(prev->nextSibling(), nextChild);
242 prev->setNextSibling(&newChild); 251 prev->setNextSibling(&newChild);
243 } else { 252 } else {
244 DCHECK(firstChild() == nextChild); 253 DCHECK(firstChild() == nextChild);
245 m_firstChild = &newChild; 254 m_firstChild = &newChild;
246 } 255 }
247 newChild.setParentOrShadowHostNode(this); 256 newChild.setParentOrShadowHostNode(this);
248 newChild.setPreviousSibling(prev); 257 newChild.setPreviousSibling(prev);
249 newChild.setNextSibling(&nextChild); 258 newChild.setNextSibling(&nextChild);
250 } 259 }
251 260
261 bool ContainerNode::appendChildCommonWithAdoption(Node& child, Node*)
262 {
263 // If the child has a parent again, just stop what we're doing, because that
264 // means someone is doing something with DOM mutation -- can't re-parent a
265 // child that already has a parent.
266 if (child.parentNode())
267 return false;
268 treeScope().adoptIfNeeded(child);
269 appendChildCommon(child);
270 return true;
271 }
272
252 void ContainerNode::appendChildCommon(Node& child) 273 void ContainerNode::appendChildCommon(Node& child)
253 { 274 {
254 child.setParentOrShadowHostNode(this); 275 child.setParentOrShadowHostNode(this);
255 276
256 if (m_lastChild) { 277 if (m_lastChild) {
257 child.setPreviousSibling(m_lastChild); 278 child.setPreviousSibling(m_lastChild);
258 m_lastChild->setNextSibling(&child); 279 m_lastChild->setNextSibling(&child);
259 } else { 280 } else {
260 setFirstChild(&child); 281 setFirstChild(&child);
261 } 282 }
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
359 if (exceptionState.hadException()) 380 if (exceptionState.hadException())
360 return nullptr; 381 return nullptr;
361 382
362 // Does this yet another check because collectChildrenAndRemoveFromOldParent () fires a MutationEvent. 383 // Does this yet another check because collectChildrenAndRemoveFromOldParent () fires a MutationEvent.
363 if (!checkAcceptChild(newChild, child, exceptionState)) { 384 if (!checkAcceptChild(newChild, child, exceptionState)) {
364 if (exceptionState.hadException()) 385 if (exceptionState.hadException())
365 return nullptr; 386 return nullptr;
366 return child; 387 return child;
367 } 388 }
368 389
369 InspectorInstrumentation::willInsertDOMNode(this); 390 if (next)
370 391 insertNodeVector(targets, next, &ContainerNode::insertBeforeCommonWithAd option);
371 // Add the new child(ren). 392 else
372 for (const auto& targetNode : targets) { 393 insertNodeVector(targets, nullptr, &ContainerNode::appendChildCommonWith Adoption);
373 DCHECK(targetNode);
374 Node& child = *targetNode;
375
376 // Due to arbitrary code running in response to a DOM mutation event it' s
377 // possible that "next" is no longer a child of "this".
378 // It's also possible that "child" has been inserted elsewhere.
379 // In either of those cases, we'll just stop.
380 if (next && next->parentNode() != this)
381 break;
382 if (child.parentNode())
383 break;
384
385 treeScope().adoptIfNeeded(child);
386
387 // Add child before "next".
388 {
389 EventDispatchForbiddenScope assertNoEventDispatch;
390 if (next)
391 insertBeforeCommon(*next, child);
392 else
393 appendChildCommon(child);
394 }
395
396 updateTreeAfterInsertion(child);
397 }
398
399 dispatchSubtreeModifiedEvent();
400 return child; 394 return child;
401 } 395 }
402 396
403 void ContainerNode::willRemoveChild(Node& child) 397 void ContainerNode::willRemoveChild(Node& child)
404 { 398 {
405 DCHECK_EQ(child.parentNode(), this); 399 DCHECK_EQ(child.parentNode(), this);
406 ChildListMutationScope(*this).willRemoveChild(child); 400 ChildListMutationScope(*this).willRemoveChild(child);
407 child.notifyMutationObserversNodeWillDetach(); 401 child.notifyMutationObserversNodeWillDetach();
408 dispatchChildRemovalEvents(child); 402 dispatchChildRemovalEvents(child);
409 ChildFrameDisconnector(child).disconnect(); 403 ChildFrameDisconnector(child).disconnect();
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after
618 if (targets.isEmpty()) 612 if (targets.isEmpty())
619 return newChild; 613 return newChild;
620 614
621 // We need this extra check because collectChildrenAndRemoveFromOldParent() can fire mutation events. 615 // We need this extra check because collectChildrenAndRemoveFromOldParent() can fire mutation events.
622 if (!checkAcceptChildGuaranteedNodeTypes(*newChild, nullptr, exceptionState) ) { 616 if (!checkAcceptChildGuaranteedNodeTypes(*newChild, nullptr, exceptionState) ) {
623 if (exceptionState.hadException()) 617 if (exceptionState.hadException())
624 return nullptr; 618 return nullptr;
625 return newChild; 619 return newChild;
626 } 620 }
627 621
628 InspectorInstrumentation::willInsertDOMNode(this);
629
630 // Now actually add the child(ren).
631 ChildListMutationScope mutation(*this); 622 ChildListMutationScope mutation(*this);
632 for (const auto& targetNode : targets) { 623 insertNodeVector(targets, nullptr, &ContainerNode::appendChildCommonWithAdop tion);
633 DCHECK(targetNode);
634 Node& child = *targetNode;
635
636 // If the child has a parent again, just stop what we're doing, because
637 // that means someone is doing something with DOM mutation -- can't re-p arent
638 // a child that already has a parent.
639 if (child.parentNode())
640 break;
641
642 {
643 EventDispatchForbiddenScope assertNoEventDispatch;
644 ScriptForbiddenScope forbidScript;
645
646 treeScope().adoptIfNeeded(child);
647 appendChildCommon(child);
648 }
649
650 updateTreeAfterInsertion(child);
651 }
652
653 dispatchSubtreeModifiedEvent();
654 return newChild; 624 return newChild;
655 } 625 }
656 626
657 void ContainerNode::parserAppendChild(Node* newChild) 627 void ContainerNode::parserAppendChild(Node* newChild)
658 { 628 {
659 DCHECK(newChild); 629 DCHECK(newChild);
660 DCHECK(!newChild->isDocumentFragment()); 630 DCHECK(!newChild->isDocumentFragment());
661 DCHECK(!isHTMLTemplateElement(this)); 631 DCHECK(!isHTMLTemplateElement(this));
662 632
663 if (!checkParserAcceptChild(*newChild)) 633 if (!checkParserAcceptChild(*newChild))
(...skipping 734 matching lines...) Expand 10 before | Expand all | Expand 10 after
1398 return true; 1368 return true;
1399 1369
1400 if (node->isElementNode() && toElement(node)->shadow()) 1370 if (node->isElementNode() && toElement(node)->shadow())
1401 return true; 1371 return true;
1402 1372
1403 return false; 1373 return false;
1404 } 1374 }
1405 #endif 1375 #endif
1406 1376
1407 } // namespace blink 1377 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/dom/ContainerNode.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698