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

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

Issue 2473743003: Call Element::rebuildLayoutTree from Document::updateStyle directly (Closed)
Patch Set: Fix failures due to information not being retained correctly for detachLayoutTree() in Text::reatta… Created 3 years, 10 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
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 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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698