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 Apple Inc. All rights reserv ed. | 5 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserv ed. |
| 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. |
| 11 * | 11 * |
| 12 * This library is distributed in the hope that it will be useful, | 12 * This library is distributed in the hope that it will be useful, |
| 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 15 * Library General Public License for more details. | 15 * Library General Public License for more details. |
| 16 * | 16 * |
| 17 * You should have received a copy of the GNU Library General Public License | 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 | 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, | 19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| 20 * Boston, MA 02110-1301, USA. | 20 * Boston, MA 02110-1301, USA. |
| 21 */ | 21 */ |
| 22 | 22 |
| 23 #include "config.h" | 23 #include "config.h" |
| 24 #include "core/dom/ContainerNode.h" | 24 #include "core/dom/ContainerNode.h" |
| 25 | 25 |
| 26 #include "bindings/v8/ExceptionMessages.h" | |
| 26 #include "bindings/v8/ExceptionState.h" | 27 #include "bindings/v8/ExceptionState.h" |
| 27 #include "bindings/v8/ExceptionStatePlaceholder.h" | 28 #include "bindings/v8/ExceptionStatePlaceholder.h" |
| 28 #include "core/dom/ChildListMutationScope.h" | 29 #include "core/dom/ChildListMutationScope.h" |
| 29 #include "core/dom/ContainerNodeAlgorithms.h" | 30 #include "core/dom/ContainerNodeAlgorithms.h" |
| 30 #include "core/dom/ElementTraversal.h" | 31 #include "core/dom/ElementTraversal.h" |
| 31 #include "core/events/EventNames.h" | 32 #include "core/events/EventNames.h" |
| 32 #include "core/dom/ExceptionCode.h" | 33 #include "core/dom/ExceptionCode.h" |
| 33 #include "core/dom/FullscreenElementStack.h" | 34 #include "core/dom/FullscreenElementStack.h" |
| 34 #include "core/events/MutationEvent.h" | 35 #include "core/events/MutationEvent.h" |
| 35 #include "core/dom/NodeRareData.h" | 36 #include "core/dom/NodeRareData.h" |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 133 return &document == document.templateDocument(); | 134 return &document == document.templateDocument(); |
| 134 } | 135 } |
| 135 | 136 |
| 136 static inline bool containsConsideringHostElements(const Node* newChild, const N ode* newParent) | 137 static inline bool containsConsideringHostElements(const Node* newChild, const N ode* newParent) |
| 137 { | 138 { |
| 138 return (newParent->isInShadowTree() || isInTemplateContent(newParent)) | 139 return (newParent->isInShadowTree() || isInTemplateContent(newParent)) |
| 139 ? newChild->containsIncludingHostElements(newParent) | 140 ? newChild->containsIncludingHostElements(newParent) |
| 140 : newChild->contains(newParent); | 141 : newChild->contains(newParent); |
| 141 } | 142 } |
| 142 | 143 |
| 143 static inline bool checkAcceptChild(ContainerNode* newParent, Node* newChild, No de* oldChild, ExceptionState& es) | 144 static inline bool checkAcceptChild(ContainerNode* newParent, Node* newChild, No de* oldChild, const String& method, ExceptionState& es) |
| 144 { | 145 { |
| 145 // Not mentioned in spec: throw NotFoundError if newChild is null | 146 // Not mentioned in spec: throw NotFoundError if newChild is null |
| 146 if (!newChild) { | 147 if (!newChild) { |
| 147 es.throwUninformativeAndGenericDOMException(NotFoundError); | 148 es.throwDOMException(NotFoundError, ExceptionMessages::failedToExecute(m ethod, "ContainerNode", "The new child element is null.")); |
|
arv (Not doing code reviews)
2013/09/26 15:23:10
Let's not use ContainerNode in any user visible me
| |
| 148 return false; | 149 return false; |
| 149 } | 150 } |
| 150 | 151 |
| 151 // Use common case fast path if possible. | 152 // Use common case fast path if possible. |
| 152 if ((newChild->isElementNode() || newChild->isTextNode()) && newParent->isEl ementNode()) { | 153 if ((newChild->isElementNode() || newChild->isTextNode()) && newParent->isEl ementNode()) { |
| 153 ASSERT(!newParent->isDocumentTypeNode()); | 154 ASSERT(!newParent->isDocumentTypeNode()); |
| 154 ASSERT(isChildTypeAllowed(newParent, newChild)); | 155 ASSERT(isChildTypeAllowed(newParent, newChild)); |
| 155 if (containsConsideringHostElements(newChild, newParent)) { | 156 if (containsConsideringHostElements(newChild, newParent)) { |
| 156 es.throwUninformativeAndGenericDOMException(HierarchyRequestError); | 157 es.throwDOMException(HierarchyRequestError, ExceptionMessages::faile dToExecute(method, "ContainerNode", "The new child element contains the parent." )); |
| 157 return false; | 158 return false; |
| 158 } | 159 } |
| 159 return true; | 160 return true; |
| 160 } | 161 } |
| 161 | 162 |
| 162 // This should never happen, but also protect release builds from tree corru ption. | 163 // This should never happen, but also protect release builds from tree corru ption. |
| 163 ASSERT(!newChild->isPseudoElement()); | 164 ASSERT(!newChild->isPseudoElement()); |
| 164 if (newChild->isPseudoElement()) { | 165 if (newChild->isPseudoElement()) { |
| 165 es.throwUninformativeAndGenericDOMException(HierarchyRequestError); | 166 es.throwDOMException(HierarchyRequestError, ExceptionMessages::failedToE xecute(method, "ContainerNode", "The new child element is a pseudo-element.")); |
| 166 return false; | 167 return false; |
| 167 } | 168 } |
| 168 | 169 |
| 169 if (containsConsideringHostElements(newChild, newParent)) { | 170 if (containsConsideringHostElements(newChild, newParent)) { |
| 170 es.throwUninformativeAndGenericDOMException(HierarchyRequestError); | 171 es.throwDOMException(HierarchyRequestError, ExceptionMessages::failedToE xecute(method, "ContainerNode", "The new child element contains the parent.")); |
| 171 return false; | 172 return false; |
| 172 } | 173 } |
| 173 | 174 |
| 174 if (oldChild && newParent->isDocumentNode()) { | 175 if (oldChild && newParent->isDocumentNode()) { |
| 175 if (!toDocument(newParent)->canReplaceChild(newChild, oldChild)) { | 176 if (!toDocument(newParent)->canReplaceChild(newChild, oldChild)) { |
| 176 es.throwUninformativeAndGenericDOMException(HierarchyRequestError); | 177 // FIXME: Adjust 'Document::canReplaceChild' to return some addition al detail (or an error message). |
| 178 es.throwDOMException(HierarchyRequestError, ExceptionMessages::faile dToExecute(method, "ContainerNode")); | |
| 177 return false; | 179 return false; |
| 178 } | 180 } |
| 179 } else if (!isChildTypeAllowed(newParent, newChild)) { | 181 } else if (!isChildTypeAllowed(newParent, newChild)) { |
| 180 es.throwUninformativeAndGenericDOMException(HierarchyRequestError); | 182 es.throwDOMException(HierarchyRequestError, ExceptionMessages::failedToE xecute(method, "ContainerNode", "Nodes of type '" + newChild->nodeName() + "' ma y not be inserted inside nodes of type '" + newParent->nodeName() + "'.")); |
| 181 return false; | 183 return false; |
| 182 } | 184 } |
| 183 | 185 |
| 184 return true; | 186 return true; |
| 185 } | 187 } |
| 186 | 188 |
| 187 static inline bool checkAcceptChildGuaranteedNodeTypes(ContainerNode* newParent, Node* newChild, ExceptionState& es) | 189 static inline bool checkAcceptChildGuaranteedNodeTypes(ContainerNode* newParent, Node* newChild, const String& method, ExceptionState& es) |
| 188 { | 190 { |
| 189 ASSERT(!newParent->isDocumentTypeNode()); | 191 ASSERT(!newParent->isDocumentTypeNode()); |
| 190 ASSERT(isChildTypeAllowed(newParent, newChild)); | 192 ASSERT(isChildTypeAllowed(newParent, newChild)); |
| 191 if (newChild->contains(newParent)) { | 193 if (newChild->contains(newParent)) { |
| 192 es.throwUninformativeAndGenericDOMException(HierarchyRequestError); | 194 es.throwDOMException(HierarchyRequestError, ExceptionMessages::failedToE xecute(method, "ContainerNode", "The new child element contains the parent.")); |
| 193 return false; | 195 return false; |
| 194 } | 196 } |
| 195 | 197 |
| 196 return true; | 198 return true; |
| 197 } | 199 } |
| 198 | 200 |
| 199 static inline bool checkAddChild(ContainerNode* newParent, Node* newChild, Excep tionState& es) | 201 static inline bool checkAddChild(ContainerNode* newParent, Node* newChild, const String& method, ExceptionState& es) |
| 200 { | 202 { |
| 201 return checkAcceptChild(newParent, newChild, 0, es); | 203 return checkAcceptChild(newParent, newChild, 0, method, es); |
| 202 } | 204 } |
| 203 | 205 |
| 204 static inline bool checkReplaceChild(ContainerNode* newParent, Node* newChild, N ode* oldChild, ExceptionState& es) | 206 static inline bool checkReplaceChild(ContainerNode* newParent, Node* newChild, N ode* oldChild, const String& method, ExceptionState& es) |
| 205 { | 207 { |
| 206 return checkAcceptChild(newParent, newChild, oldChild, es); | 208 return checkAcceptChild(newParent, newChild, oldChild, method, es); |
| 207 } | 209 } |
| 208 | 210 |
| 209 void ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, Exce ptionState& es) | 211 void ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, Exce ptionState& es) |
| 210 { | 212 { |
| 211 // Check that this node is not "floating". | 213 // Check that this node is not "floating". |
| 212 // If it is, it can be deleted as a side effect of sending mutation events. | 214 // If it is, it can be deleted as a side effect of sending mutation events. |
| 213 ASSERT(refCount() || parentOrShadowHostNode()); | 215 ASSERT(refCount() || parentOrShadowHostNode()); |
| 214 | 216 |
| 215 RefPtr<Node> protect(this); | 217 RefPtr<Node> protect(this); |
| 216 | 218 |
| 217 // insertBefore(node, 0) is equivalent to appendChild(node) | 219 // insertBefore(node, 0) is equivalent to appendChild(node) |
| 218 if (!refChild) { | 220 if (!refChild) { |
| 219 appendChild(newChild, es); | 221 appendChild(newChild, es); |
| 220 return; | 222 return; |
| 221 } | 223 } |
| 222 | 224 |
| 223 // Make sure adding the new child is OK. | 225 // Make sure adding the new child is OK. |
| 224 if (!checkAddChild(this, newChild.get(), es)) | 226 if (!checkAddChild(this, newChild.get(), "insertBefore", es)) |
| 225 return; | 227 return; |
| 226 | 228 |
| 227 // NotFoundError: Raised if refChild is not a child of this node | 229 // NotFoundError: Raised if refChild is not a child of this node |
| 228 if (refChild->parentNode() != this) { | 230 if (refChild->parentNode() != this) { |
| 229 es.throwUninformativeAndGenericDOMException(NotFoundError); | 231 es.throwDOMException(NotFoundError, ExceptionMessages::failedToExecute(" insertBefore", "ContainerNode", "The node before which the new node is to be ins erted is not a child of this node.")); |
| 230 return; | 232 return; |
| 231 } | 233 } |
| 232 | 234 |
| 233 if (refChild->previousSibling() == newChild || refChild == newChild) // noth ing to do | 235 if (refChild->previousSibling() == newChild || refChild == newChild) // noth ing to do |
| 234 return; | 236 return; |
| 235 | 237 |
| 236 RefPtr<Node> next = refChild; | 238 RefPtr<Node> next = refChild; |
| 237 | 239 |
| 238 NodeVector targets; | 240 NodeVector targets; |
| 239 collectChildrenAndRemoveFromOldParent(newChild.get(), targets, es); | 241 collectChildrenAndRemoveFromOldParent(newChild.get(), targets, es); |
| 240 if (es.hadException()) | 242 if (es.hadException()) |
| 241 return; | 243 return; |
| 242 if (targets.isEmpty()) | 244 if (targets.isEmpty()) |
| 243 return; | 245 return; |
| 244 | 246 |
| 245 // We need this extra check because collectChildrenAndRemoveFromOldParent() can fire mutation events. | 247 // We need this extra check because collectChildrenAndRemoveFromOldParent() can fire mutation events. |
| 246 if (!checkAcceptChildGuaranteedNodeTypes(this, newChild.get(), es)) | 248 if (!checkAcceptChildGuaranteedNodeTypes(this, newChild.get(), "insertBefore ", es)) |
| 247 return; | 249 return; |
| 248 | 250 |
| 249 InspectorInstrumentation::willInsertDOMNode(&document(), this); | 251 InspectorInstrumentation::willInsertDOMNode(&document(), this); |
| 250 | 252 |
| 251 ChildListMutationScope mutation(this); | 253 ChildListMutationScope mutation(this); |
| 252 for (NodeVector::const_iterator it = targets.begin(); it != targets.end(); + +it) { | 254 for (NodeVector::const_iterator it = targets.begin(); it != targets.end(); + +it) { |
| 253 Node* child = it->get(); | 255 Node* child = it->get(); |
| 254 | 256 |
| 255 // Due to arbitrary code running in response to a DOM mutation event it' s | 257 // Due to arbitrary code running in response to a DOM mutation event it' s |
| 256 // possible that "next" is no longer a child of "this". | 258 // possible that "next" is no longer a child of "this". |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 327 // Check that this node is not "floating". | 329 // Check that this node is not "floating". |
| 328 // If it is, it can be deleted as a side effect of sending mutation events. | 330 // If it is, it can be deleted as a side effect of sending mutation events. |
| 329 ASSERT(refCount() || parentOrShadowHostNode()); | 331 ASSERT(refCount() || parentOrShadowHostNode()); |
| 330 | 332 |
| 331 RefPtr<Node> protect(this); | 333 RefPtr<Node> protect(this); |
| 332 | 334 |
| 333 if (oldChild == newChild) // nothing to do | 335 if (oldChild == newChild) // nothing to do |
| 334 return; | 336 return; |
| 335 | 337 |
| 336 if (!oldChild) { | 338 if (!oldChild) { |
| 337 es.throwUninformativeAndGenericDOMException(NotFoundError); | 339 es.throwDOMException(NotFoundError, ExceptionMessages::failedToExecute(" replaceChild", "ContainerNode", "The node to be replaced is null.")); |
| 338 return; | 340 return; |
| 339 } | 341 } |
| 340 | 342 |
| 341 // Make sure replacing the old child with the new is ok | 343 // Make sure replacing the old child with the new is ok |
| 342 if (!checkReplaceChild(this, newChild.get(), oldChild, es)) | 344 if (!checkReplaceChild(this, newChild.get(), oldChild, "replaceChild", es)) |
| 343 return; | 345 return; |
| 344 | 346 |
| 345 // NotFoundError: Raised if oldChild is not a child of this node. | 347 // NotFoundError: Raised if oldChild is not a child of this node. |
| 346 if (oldChild->parentNode() != this) { | 348 if (oldChild->parentNode() != this) { |
| 347 es.throwUninformativeAndGenericDOMException(NotFoundError); | 349 es.throwDOMException(NotFoundError, ExceptionMessages::failedToExecute(" replaceChild", "ContainerNode", "The node to be replaced is not a child of this node.")); |
| 348 return; | 350 return; |
| 349 } | 351 } |
| 350 | 352 |
| 351 ChildListMutationScope mutation(this); | 353 ChildListMutationScope mutation(this); |
| 352 | 354 |
| 353 RefPtr<Node> next = oldChild->nextSibling(); | 355 RefPtr<Node> next = oldChild->nextSibling(); |
| 354 | 356 |
| 355 // Remove the node we're replacing | 357 // Remove the node we're replacing |
| 356 RefPtr<Node> removedChild = oldChild; | 358 RefPtr<Node> removedChild = oldChild; |
| 357 removeChild(oldChild, es); | 359 removeChild(oldChild, es); |
| 358 if (es.hadException()) | 360 if (es.hadException()) |
| 359 return; | 361 return; |
| 360 | 362 |
| 361 if (next && (next->previousSibling() == newChild || next == newChild)) // no thing to do | 363 if (next && (next->previousSibling() == newChild || next == newChild)) // no thing to do |
| 362 return; | 364 return; |
| 363 | 365 |
| 364 // Does this one more time because removeChild() fires a MutationEvent. | 366 // Does this one more time because removeChild() fires a MutationEvent. |
| 365 if (!checkReplaceChild(this, newChild.get(), oldChild, es)) | 367 if (!checkReplaceChild(this, newChild.get(), oldChild, "replaceChild", es)) |
| 366 return; | 368 return; |
| 367 | 369 |
| 368 NodeVector targets; | 370 NodeVector targets; |
| 369 collectChildrenAndRemoveFromOldParent(newChild.get(), targets, es); | 371 collectChildrenAndRemoveFromOldParent(newChild.get(), targets, es); |
| 370 if (es.hadException()) | 372 if (es.hadException()) |
| 371 return; | 373 return; |
| 372 | 374 |
| 373 // Does this yet another check because collectChildrenAndRemoveFromOldParent () fires a MutationEvent. | 375 // Does this yet another check because collectChildrenAndRemoveFromOldParent () fires a MutationEvent. |
| 374 if (!checkReplaceChild(this, newChild.get(), oldChild, es)) | 376 if (!checkReplaceChild(this, newChild.get(), oldChild, "replaceChild", es)) |
| 375 return; | 377 return; |
| 376 | 378 |
| 377 InspectorInstrumentation::willInsertDOMNode(&document(), this); | 379 InspectorInstrumentation::willInsertDOMNode(&document(), this); |
| 378 | 380 |
| 379 // Add the new child(ren) | 381 // Add the new child(ren) |
| 380 for (NodeVector::const_iterator it = targets.begin(); it != targets.end(); + +it) { | 382 for (NodeVector::const_iterator it = targets.begin(); it != targets.end(); + +it) { |
| 381 Node* child = it->get(); | 383 Node* child = it->get(); |
| 382 | 384 |
| 383 // Due to arbitrary code running in response to a DOM mutation event it' s | 385 // Due to arbitrary code running in response to a DOM mutation event it' s |
| 384 // possible that "next" is no longer a child of "this". | 386 // possible that "next" is no longer a child of "this". |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 444 void ContainerNode::removeChild(Node* oldChild, ExceptionState& es) | 446 void ContainerNode::removeChild(Node* oldChild, ExceptionState& es) |
| 445 { | 447 { |
| 446 // Check that this node is not "floating". | 448 // Check that this node is not "floating". |
| 447 // If it is, it can be deleted as a side effect of sending mutation events. | 449 // If it is, it can be deleted as a side effect of sending mutation events. |
| 448 ASSERT(refCount() || parentOrShadowHostNode()); | 450 ASSERT(refCount() || parentOrShadowHostNode()); |
| 449 | 451 |
| 450 RefPtr<Node> protect(this); | 452 RefPtr<Node> protect(this); |
| 451 | 453 |
| 452 // NotFoundError: Raised if oldChild is not a child of this node. | 454 // NotFoundError: Raised if oldChild is not a child of this node. |
| 453 if (!oldChild || oldChild->parentNode() != this) { | 455 if (!oldChild || oldChild->parentNode() != this) { |
| 454 es.throwUninformativeAndGenericDOMException(NotFoundError); | 456 es.throwDOMException(NotFoundError, ExceptionMessages::failedToExecute(" removeChild", "ContainerNode", "The node to be removed is not a child of this no de.")); |
| 455 return; | 457 return; |
| 456 } | 458 } |
| 457 | 459 |
| 458 RefPtr<Node> child = oldChild; | 460 RefPtr<Node> child = oldChild; |
| 459 | 461 |
| 460 document().removeFocusedElementOfSubtree(child.get()); | 462 document().removeFocusedElementOfSubtree(child.get()); |
| 461 | 463 |
| 462 if (FullscreenElementStack* fullscreen = FullscreenElementStack::fromIfExist s(&document())) | 464 if (FullscreenElementStack* fullscreen = FullscreenElementStack::fromIfExist s(&document())) |
| 463 fullscreen->removeFullScreenElementOfSubtree(child.get()); | 465 fullscreen->removeFullScreenElementOfSubtree(child.get()); |
| 464 | 466 |
| 465 // Events fired when blurring currently focused node might have moved this | 467 // Events fired when blurring currently focused node might have moved this |
| 466 // child into a different parent. | 468 // child into a different parent. |
| 467 if (child->parentNode() != this) { | 469 if (child->parentNode() != this) { |
| 468 es.throwUninformativeAndGenericDOMException(NotFoundError); | 470 es.throwDOMException(NotFoundError, ExceptionMessages::failedToExecute(" removeChild", "ContainerNode", "The node to be removed is no longer a child of t his node. Perhaps it was moved in a 'blur' event handler?")); |
| 469 return; | 471 return; |
| 470 } | 472 } |
| 471 | 473 |
| 472 willRemoveChild(child.get()); | 474 willRemoveChild(child.get()); |
| 473 | 475 |
| 474 // Mutation events might have moved this child into a different parent. | 476 // Mutation events might have moved this child into a different parent. |
| 475 if (child->parentNode() != this) { | 477 if (child->parentNode() != this) { |
| 476 es.throwUninformativeAndGenericDOMException(NotFoundError); | 478 es.throwDOMException(NotFoundError, ExceptionMessages::failedToExecute(" removeChild", "ContainerNode", "The node to be removed is no longer a child of t his node. Perhaps it was moved in response to a mutation?")); |
| 477 return; | 479 return; |
| 478 } | 480 } |
| 479 | 481 |
| 480 { | 482 { |
| 481 WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates; | 483 WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates; |
| 482 | 484 |
| 483 Node* prev = child->previousSibling(); | 485 Node* prev = child->previousSibling(); |
| 484 Node* next = child->nextSibling(); | 486 Node* next = child->nextSibling(); |
| 485 removeBetween(prev, next, child.get()); | 487 removeBetween(prev, next, child.get()); |
| 486 childrenChanged(false, prev, next, -1); | 488 childrenChanged(false, prev, next, -1); |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 588 | 590 |
| 589 void ContainerNode::appendChild(PassRefPtr<Node> newChild, ExceptionState& es) | 591 void ContainerNode::appendChild(PassRefPtr<Node> newChild, ExceptionState& es) |
| 590 { | 592 { |
| 591 RefPtr<ContainerNode> protect(this); | 593 RefPtr<ContainerNode> protect(this); |
| 592 | 594 |
| 593 // Check that this node is not "floating". | 595 // Check that this node is not "floating". |
| 594 // If it is, it can be deleted as a side effect of sending mutation events. | 596 // If it is, it can be deleted as a side effect of sending mutation events. |
| 595 ASSERT(refCount() || parentOrShadowHostNode()); | 597 ASSERT(refCount() || parentOrShadowHostNode()); |
| 596 | 598 |
| 597 // Make sure adding the new child is ok | 599 // Make sure adding the new child is ok |
| 598 if (!checkAddChild(this, newChild.get(), es)) | 600 if (!checkAddChild(this, newChild.get(), "appendChild", es)) |
| 599 return; | 601 return; |
| 600 | 602 |
| 601 if (newChild == m_lastChild) // nothing to do | 603 if (newChild == m_lastChild) // nothing to do |
| 602 return; | 604 return; |
| 603 | 605 |
| 604 NodeVector targets; | 606 NodeVector targets; |
| 605 collectChildrenAndRemoveFromOldParent(newChild.get(), targets, es); | 607 collectChildrenAndRemoveFromOldParent(newChild.get(), targets, es); |
| 606 if (es.hadException()) | 608 if (es.hadException()) |
| 607 return; | 609 return; |
| 608 | 610 |
| 609 if (targets.isEmpty()) | 611 if (targets.isEmpty()) |
| 610 return; | 612 return; |
| 611 | 613 |
| 612 // We need this extra check because collectChildrenAndRemoveFromOldParent() can fire mutation events. | 614 // We need this extra check because collectChildrenAndRemoveFromOldParent() can fire mutation events. |
| 613 if (!checkAcceptChildGuaranteedNodeTypes(this, newChild.get(), es)) | 615 if (!checkAcceptChildGuaranteedNodeTypes(this, newChild.get(), "appendChild" , es)) |
| 614 return; | 616 return; |
| 615 | 617 |
| 616 InspectorInstrumentation::willInsertDOMNode(&document(), this); | 618 InspectorInstrumentation::willInsertDOMNode(&document(), this); |
| 617 | 619 |
| 618 // Now actually add the child(ren) | 620 // Now actually add the child(ren) |
| 619 ChildListMutationScope mutation(this); | 621 ChildListMutationScope mutation(this); |
| 620 for (NodeVector::const_iterator it = targets.begin(); it != targets.end(); + +it) { | 622 for (NodeVector::const_iterator it = targets.begin(); it != targets.end(); + +it) { |
| 621 Node* child = it->get(); | 623 Node* child = it->get(); |
| 622 | 624 |
| 623 // If the child has a parent again, just stop what we're doing, because | 625 // If the child has a parent again, just stop what we're doing, because |
| (...skipping 375 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 999 return true; | 1001 return true; |
| 1000 | 1002 |
| 1001 if (node->isElementNode() && toElement(node)->shadow()) | 1003 if (node->isElementNode() && toElement(node)->shadow()) |
| 1002 return true; | 1004 return true; |
| 1003 | 1005 |
| 1004 return false; | 1006 return false; |
| 1005 } | 1007 } |
| 1006 #endif | 1008 #endif |
| 1007 | 1009 |
| 1008 } // namespace WebCore | 1010 } // namespace WebCore |
| OLD | NEW |