Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |