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 |