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 | 5 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2013 Apple Inc. All rights |
| 6 * reserved. | 6 * reserved. |
| 7 * | 7 * |
| 8 * This library is free software; you can redistribute it and/or | 8 * This library is free software; you can redistribute it and/or |
| 9 * modify it under the terms of the GNU Library General Public | 9 * modify it under the terms of the GNU Library General Public |
| 10 * License as published by the Free Software Foundation; either | 10 * License as published by the Free Software Foundation; either |
| (...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 259 public: | 259 public: |
| 260 inline void operator()(ContainerNode& container, Node& child, Node*) const { | 260 inline void operator()(ContainerNode& container, Node& child, Node*) const { |
| 261 container.treeScope().adoptIfNeeded(child); | 261 container.treeScope().adoptIfNeeded(child); |
| 262 container.appendChildCommon(child); | 262 container.appendChildCommon(child); |
| 263 } | 263 } |
| 264 }; | 264 }; |
| 265 | 265 |
| 266 Node* ContainerNode::insertBefore(Node* newChild, | 266 Node* ContainerNode::insertBefore(Node* newChild, |
| 267 Node* refChild, | 267 Node* refChild, |
| 268 ExceptionState& exceptionState) { | 268 ExceptionState& exceptionState) { |
| 269 // https://dom.spec.whatwg.org/#concept-node-pre-insert | |
| 270 | |
| 271 // insertBefore(node, 0) is equivalent to appendChild(node) | 269 // insertBefore(node, 0) is equivalent to appendChild(node) |
| 272 if (!refChild) | 270 if (!refChild) |
| 273 return appendChild(newChild, exceptionState); | 271 return appendChild(newChild, exceptionState); |
| 274 | 272 |
| 275 // Make sure adding the new child is OK. | 273 // Make sure adding the new child is OK. |
| 276 if (!checkAcceptChild(newChild, 0, exceptionState)) | 274 if (!checkAcceptChild(newChild, 0, exceptionState)) |
| 277 return newChild; | 275 return newChild; |
| 278 DCHECK(newChild); | 276 DCHECK(newChild); |
| 279 | 277 |
| 280 // NotFoundError: Raised if refChild is not a child of this node | 278 // NotFoundError: Raised if refChild is not a child of this node |
| 281 if (refChild->parentNode() != this) { | 279 if (refChild->parentNode() != this) { |
| 282 exceptionState.throwDOMException(NotFoundError, | 280 exceptionState.throwDOMException(NotFoundError, |
| 283 "The node before which the new node is to " | 281 "The node before which the new node is to " |
| 284 "be inserted is not a child of this " | 282 "be inserted is not a child of this " |
| 285 "node."); | 283 "node."); |
| 286 return nullptr; | 284 return nullptr; |
| 287 } | 285 } |
| 288 | 286 |
| 289 // 3. If reference child is node, set it to node’s next sibling. | 287 // Nothing to do. |
| 290 if (refChild == newChild) { | 288 if (refChild->previousSibling() == newChild || refChild == newChild) |
| 291 refChild = newChild->nextSibling(); | 289 return newChild; |
| 292 if (!refChild) | |
| 293 return appendChild(newChild, exceptionState); | |
| 294 } | |
| 295 | 290 |
| 296 NodeVector targets; | 291 NodeVector targets; |
| 297 if (!collectChildrenAndRemoveFromOldParentWithCheck( | 292 if (!collectChildrenAndRemoveFromOldParentWithCheck( |
| 298 refChild, nullptr, *newChild, targets, exceptionState)) | 293 refChild, nullptr, *newChild, targets, exceptionState)) |
| 299 return newChild; | 294 return newChild; |
| 300 | 295 |
| 301 ChildListMutationScope mutation(*this); | 296 ChildListMutationScope mutation(*this); |
| 302 insertNodeVector(targets, refChild, AdoptAndInsertBefore()); | 297 insertNodeVector(targets, refChild, AdoptAndInsertBefore()); |
| 303 return newChild; | 298 return newChild; |
| 304 } | 299 } |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 389 DCHECK_EQ(newChild->connectedSubframeCount(), 0u); | 384 DCHECK_EQ(newChild->connectedSubframeCount(), 0u); |
| 390 ChildListMutationScope(*this).childAdded(*newChild); | 385 ChildListMutationScope(*this).childAdded(*newChild); |
| 391 } | 386 } |
| 392 | 387 |
| 393 notifyNodeInserted(*newChild, ChildrenChangeSourceParser); | 388 notifyNodeInserted(*newChild, ChildrenChangeSourceParser); |
| 394 } | 389 } |
| 395 | 390 |
| 396 Node* ContainerNode::replaceChild(Node* newChild, | 391 Node* ContainerNode::replaceChild(Node* newChild, |
| 397 Node* oldChild, | 392 Node* oldChild, |
| 398 ExceptionState& exceptionState) { | 393 ExceptionState& exceptionState) { |
| 399 // https://dom.spec.whatwg.org/#concept-node-replace | 394 if (oldChild == newChild) // Nothing to do. |
| 395 return oldChild; | |
| 400 | 396 |
| 401 if (!oldChild) { | 397 if (!oldChild) { |
| 402 exceptionState.throwDOMException(NotFoundError, | 398 exceptionState.throwDOMException(NotFoundError, |
| 403 "The node to be replaced is null."); | 399 "The node to be replaced is null."); |
| 404 return nullptr; | 400 return nullptr; |
| 405 } | 401 } |
| 406 | 402 |
| 407 // Make sure replacing the old child with the new is OK. | 403 // Make sure replacing the old child with the new is OK. |
| 408 if (!checkAcceptChild(newChild, oldChild, exceptionState)) | 404 if (!checkAcceptChild(newChild, oldChild, exceptionState)) |
| 409 return oldChild; | 405 return oldChild; |
| 410 | 406 |
| 411 // NotFoundError: Raised if oldChild is not a child of this node. | 407 // NotFoundError: Raised if oldChild is not a child of this node. |
| 412 if (oldChild->parentNode() != this) { | 408 if (oldChild->parentNode() != this) { |
| 413 exceptionState.throwDOMException( | 409 exceptionState.throwDOMException( |
| 414 NotFoundError, "The node to be replaced is not a child of this node."); | 410 NotFoundError, "The node to be replaced is not a child of this node."); |
| 415 return nullptr; | 411 return nullptr; |
| 416 } | 412 } |
| 417 | 413 |
| 418 ChildListMutationScope mutation(*this); | 414 ChildListMutationScope mutation(*this); |
| 419 // 7. Let reference child be child’s next sibling. | |
| 420 Node* next = oldChild->nextSibling(); | 415 Node* next = oldChild->nextSibling(); |
| 421 // 8. If reference child is node, set it to node’s next sibling. | |
| 422 if (next == newChild) | |
| 423 next = newChild->nextSibling(); | |
| 424 | 416 |
| 425 // TODO(tkent): According to the specification, we should remove |newChild| | 417 // Remove the node we're replacing. |
| 426 // from its parent here, and create a separated mutation record for it. | |
| 427 // Refer to imported/wpt/dom/nodes/MutationObserver-childList.html. | |
| 428 | |
| 429 // 12. If child’s parent is not null, run these substeps: | |
| 430 // 1. Set removedNodes to a list solely containing child. | |
| 431 // 2. Remove child from its parent with the suppress observers flag set. | |
| 432 removeChild(oldChild, exceptionState); | 418 removeChild(oldChild, exceptionState); |
| 433 if (exceptionState.hadException()) | 419 if (exceptionState.hadException()) |
| 434 return nullptr; | 420 return nullptr; |
| 435 | 421 |
| 422 if (next && (next->previousSibling() == newChild || | |
| 423 next == newChild)) // nothing to do | |
| 424 return oldChild; | |
| 425 | |
| 436 // Does this one more time because removeChild() fires a MutationEvent. | 426 // Does this one more time because removeChild() fires a MutationEvent. |
| 437 if (!checkAcceptChild(newChild, oldChild, exceptionState)) | 427 if (!checkAcceptChild(newChild, oldChild, exceptionState)) |
| 438 return oldChild; | 428 return oldChild; |
| 439 | 429 |
| 440 NodeVector targets; | 430 NodeVector targets; |
| 441 if (!collectChildrenAndRemoveFromOldParentWithCheck(next, oldChild, *newChild, | 431 if (!collectChildrenAndRemoveFromOldParentWithCheck(next, oldChild, *newChild, |
| 442 targets, exceptionState)) | 432 targets, exceptionState)) |
| 443 return oldChild; | 433 return oldChild; |
| 444 | 434 |
| 445 if (next) | 435 if (next) |
| (...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 652 dispatchSubtreeModifiedEvent(); | 642 dispatchSubtreeModifiedEvent(); |
| 653 } | 643 } |
| 654 | 644 |
| 655 Node* ContainerNode::appendChild(Node* newChild, | 645 Node* ContainerNode::appendChild(Node* newChild, |
| 656 ExceptionState& exceptionState) { | 646 ExceptionState& exceptionState) { |
| 657 // Make sure adding the new child is ok | 647 // Make sure adding the new child is ok |
| 658 if (!checkAcceptChild(newChild, 0, exceptionState)) | 648 if (!checkAcceptChild(newChild, 0, exceptionState)) |
| 659 return newChild; | 649 return newChild; |
| 660 DCHECK(newChild); | 650 DCHECK(newChild); |
| 661 | 651 |
| 652 if (newChild == m_lastChild) // nothing to do | |
| 653 return newChild; | |
| 654 | |
| 662 NodeVector targets; | 655 NodeVector targets; |
| 663 if (!collectChildrenAndRemoveFromOldParentWithCheck( | 656 if (!collectChildrenAndRemoveFromOldParentWithCheck( |
| 664 nullptr, nullptr, *newChild, targets, exceptionState)) | 657 nullptr, nullptr, *newChild, targets, exceptionState)) |
| 665 return newChild; | 658 return newChild; |
| 666 | 659 |
| 667 ChildListMutationScope mutation(*this); | 660 ChildListMutationScope mutation(*this); |
| 668 insertNodeVector(targets, nullptr, AdoptAndAppendChild()); | 661 insertNodeVector(targets, nullptr, AdoptAndAppendChild()); |
| 669 return newChild; | 662 return newChild; |
| 670 } | 663 } |
| 671 | 664 |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 759 notifyNodeRemoved(*shadowRoot); | 752 notifyNodeRemoved(*shadowRoot); |
| 760 } | 753 } |
| 761 } | 754 } |
| 762 | 755 |
| 763 DISABLE_CFI_PERF | 756 DISABLE_CFI_PERF |
| 764 void ContainerNode::attachLayoutTree(const AttachContext& context) { | 757 void ContainerNode::attachLayoutTree(const AttachContext& context) { |
| 765 AttachContext childrenContext(context); | 758 AttachContext childrenContext(context); |
| 766 childrenContext.resolvedStyle = nullptr; | 759 childrenContext.resolvedStyle = nullptr; |
| 767 | 760 |
| 768 for (Node* child = firstChild(); child; child = child->nextSibling()) { | 761 for (Node* child = firstChild(); child; child = child->nextSibling()) { |
| 769 #if DCHECK_IS_ON() | |
| 770 DCHECK(child->needsAttach() || | |
| 771 childAttachedAllowedWhenAttachingChildren(this)); | |
|
esprehn
2017/02/13 22:19:41
Lets add this back?
nainar
2017/02/14 03:42:08
Done.
| |
| 772 #endif | |
| 773 if (child->needsAttach()) | 762 if (child->needsAttach()) |
| 774 child->attachLayoutTree(childrenContext); | 763 child->attachLayoutTree(childrenContext); |
| 775 } | 764 } |
| 776 | 765 |
| 777 clearChildNeedsStyleRecalc(); | 766 clearChildNeedsStyleRecalc(); |
| 778 clearChildNeedsReattachLayoutTree(); | 767 clearChildNeedsReattachLayoutTree(); |
| 779 Node::attachLayoutTree(context); | 768 Node::attachLayoutTree(context); |
| 780 } | 769 } |
| 781 | 770 |
| 782 void ContainerNode::detachLayoutTree(const AttachContext& context) { | 771 void ContainerNode::detachLayoutTree(const AttachContext& context) { |
| (...skipping 490 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1273 } | 1262 } |
| 1274 | 1263 |
| 1275 void ContainerNode::setRestyleFlag(DynamicRestyleFlags mask) { | 1264 void ContainerNode::setRestyleFlag(DynamicRestyleFlags mask) { |
| 1276 DCHECK(isElementNode() || isShadowRoot()); | 1265 DCHECK(isElementNode() || isShadowRoot()); |
| 1277 ensureRareData().setRestyleFlag(mask); | 1266 ensureRareData().setRestyleFlag(mask); |
| 1278 } | 1267 } |
| 1279 | 1268 |
| 1280 void ContainerNode::recalcDescendantStyles(StyleRecalcChange change) { | 1269 void ContainerNode::recalcDescendantStyles(StyleRecalcChange change) { |
| 1281 DCHECK(document().inStyleRecalc()); | 1270 DCHECK(document().inStyleRecalc()); |
| 1282 DCHECK(change >= UpdatePseudoElements || childNeedsStyleRecalc()); | 1271 DCHECK(change >= UpdatePseudoElements || childNeedsStyleRecalc()); |
| 1283 DCHECK(!needsStyleRecalc()); | |
|
esprehn
2017/02/13 22:19:41
ditto
nainar
2017/02/14 03:42:08
This information isn't true anymore. We are retain
| |
| 1284 | 1272 |
| 1285 // This loop is deliberately backwards because we use insertBefore in the | 1273 // This loop is deliberately backwards because we use insertBefore in the |
| 1286 // layout tree, and want to avoid a potentially n^2 loop to find the insertion | 1274 // layout tree, and want to avoid a potentially n^2 loop to find the insertion |
| 1287 // point while resolving style. Having us start from the last child and work | 1275 // point while resolving style. Having us start from the last child and work |
| 1288 // our way back means in the common case, we'll find the insertion point in | 1276 // our way back means in the common case, we'll find the insertion point in |
| 1289 // O(1) time. See crbug.com/288225 | 1277 // O(1) time. See crbug.com/288225 |
| 1290 StyleResolver& styleResolver = document().ensureStyleResolver(); | 1278 StyleResolver& styleResolver = document().ensureStyleResolver(); |
| 1291 Text* lastTextNode = nullptr; | 1279 Text* lastTextNode = nullptr; |
| 1292 for (Node* child = lastChild(); child; child = child->previousSibling()) { | 1280 for (Node* child = lastChild(); child; child = child->previousSibling()) { |
| 1293 if (child->isTextNode()) { | 1281 if (child->isTextNode()) { |
| 1294 toText(child)->recalcTextStyle(change, lastTextNode); | 1282 toText(child)->recalcTextStyle(change, lastTextNode); |
| 1295 lastTextNode = toText(child); | 1283 lastTextNode = toText(child); |
| 1296 } else if (child->isElementNode()) { | 1284 } else if (child->isElementNode()) { |
| 1297 Element* element = toElement(child); | 1285 Element* element = toElement(child); |
| 1298 if (element->shouldCallRecalcStyle(change)) | 1286 if (element->shouldCallRecalcStyle(change)) |
| 1299 element->recalcStyle(change, lastTextNode); | 1287 element->recalcStyle(change, lastTextNode); |
| 1300 else if (element->supportsStyleSharing()) | 1288 else if (element->supportsStyleSharing()) |
| 1301 styleResolver.addToStyleSharingList(*element); | 1289 styleResolver.addToStyleSharingList(*element); |
| 1302 if (element->layoutObject()) | 1290 if (element->layoutObject()) |
| 1303 lastTextNode = nullptr; | 1291 lastTextNode = nullptr; |
| 1304 } | 1292 } |
| 1305 } | 1293 } |
| 1306 } | 1294 } |
| 1307 | 1295 |
| 1296 void ContainerNode::rebuildChildrenLayoutTrees() { | |
| 1297 DCHECK(!needsReattachLayoutTree()); | |
| 1298 | |
| 1299 for (Node* child = lastChild(); child; child = child->previousSibling()) { | |
| 1300 if (child->needsReattachLayoutTree() || | |
| 1301 child->childNeedsReattachLayoutTree()) { | |
| 1302 if (child->isTextNode()) | |
| 1303 toText(child)->rebuildTextLayoutTree(); | |
| 1304 else if (child->isElementNode()) | |
| 1305 toElement(child)->rebuildLayoutTree(); | |
| 1306 } | |
| 1307 } | |
| 1308 clearNeedsStyleRecalc(); | |
| 1309 // This is done in ContainerNode::attachLayoutTree but will never be cleared | |
| 1310 // if we don't enter ContainerNode::attachLayoutTree so we do it here. | |
| 1311 clearChildNeedsStyleRecalc(); | |
| 1312 clearChildNeedsReattachLayoutTree(); | |
| 1313 } | |
| 1314 | |
| 1308 void ContainerNode::checkForSiblingStyleChanges(SiblingCheckType changeType, | 1315 void ContainerNode::checkForSiblingStyleChanges(SiblingCheckType changeType, |
| 1309 Element* changedElement, | 1316 Element* changedElement, |
| 1310 Node* nodeBeforeChange, | 1317 Node* nodeBeforeChange, |
| 1311 Node* nodeAfterChange) { | 1318 Node* nodeAfterChange) { |
| 1312 if (!inActiveDocument() || document().hasPendingForcedStyleRecalc() || | 1319 if (!inActiveDocument() || document().hasPendingForcedStyleRecalc() || |
| 1313 getStyleChangeType() >= SubtreeStyleChange) | 1320 getStyleChangeType() >= SubtreeStyleChange) |
| 1314 return; | 1321 return; |
| 1315 | 1322 |
| 1316 if (!hasRestyleFlag(ChildrenAffectedByStructuralRules)) | 1323 if (!hasRestyleFlag(ChildrenAffectedByStructuralRules)) |
| 1317 return; | 1324 return; |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1477 return true; | 1484 return true; |
| 1478 | 1485 |
| 1479 if (node->isElementNode() && toElement(node)->shadow()) | 1486 if (node->isElementNode() && toElement(node)->shadow()) |
| 1480 return true; | 1487 return true; |
| 1481 | 1488 |
| 1482 return false; | 1489 return false; |
| 1483 } | 1490 } |
| 1484 #endif | 1491 #endif |
| 1485 | 1492 |
| 1486 } // namespace blink | 1493 } // namespace blink |
| OLD | NEW |