Index: third_party/WebKit/Source/core/dom/ContainerNode.cpp |
diff --git a/third_party/WebKit/Source/core/dom/ContainerNode.cpp b/third_party/WebKit/Source/core/dom/ContainerNode.cpp |
index 51add737ee524b0be9a5f0be4318a4bcf32130e8..d79ca295123a608636d760e440f2afc8dd9c9ea9 100644 |
--- a/third_party/WebKit/Source/core/dom/ContainerNode.cpp |
+++ b/third_party/WebKit/Source/core/dom/ContainerNode.cpp |
@@ -1221,89 +1221,62 @@ void ContainerNode::recalcDescendantStyles(StyleRecalcChange change) |
} |
} |
-void ContainerNode::checkForSiblingStyleChanges(SiblingCheckType changeType, Node* changedNode, Node* nodeBeforeChange, Node* nodeAfterChange) |
+void ContainerNode::checkForSiblingStyleChanges(SiblingCheckType changeType, Element* changedElement, Node* nodeBeforeChange, Node* nodeAfterChange) |
{ |
if (!inActiveDocument() || document().hasPendingForcedStyleRecalc() || getStyleChangeType() >= SubtreeStyleChange) |
return; |
- // Forward positional selectors include nth-child, nth-of-type, first-of-type and only-of-type. |
- // The indirect adjacent selector is the ~ selector. |
- // Backward positional selectors include nth-last-child, nth-last-of-type, last-of-type and only-of-type. |
- // We have to invalidate everything following the insertion point in the forward and indirect adjacent case, |
- // and everything before the insertion point in the backward case. |
- // |afterChange| is 0 in the parser callback case, so we won't do any work for the forward case if we don't have to. |
- // For performance reasons we just mark the parent node as changed, since we don't want to make childrenChanged O(n^2) by crawling all our kids |
- // here. recalcStyle will then force a walk of the children when it sees that this has happened. |
+ if (!hasRestyleFlag(ChildrenAffectedByStructuralRules)) |
+ return; |
+ |
+ // Forward positional selectors include :nth-child, :nth-of-type, |
+ // :first-of-type, and only-of-type. The indirect adjacent selector is the ~ |
+ // selector. Backward positional selectors include :nth-last-child, |
+ // :nth-last-of-type, :last-of-type, and :only-of-type. We have to |
+ // invalidate everything following the insertion point in the forward and |
+ // indirect adjacent case, and everything before the insertion point in the |
+ // backward case. |nodeAfterChange| is nullptr in the parser callback case, |
+ // so we won't do any work for the forward case if we don't have to. |
+ // For performance reasons we just mark the parent node as changed, since we |
+ // don't want to make childrenChanged O(n^2) by crawling all our kids here. |
+ // recalcStyle will then force a walk of the children when it sees that this |
+ // has happened. |
if ((childrenAffectedByForwardPositionalRules() && nodeAfterChange) |
|| (childrenAffectedByBackwardPositionalRules() && nodeBeforeChange)) { |
setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::SiblingSelector)); |
return; |
} |
- // :first-child. In the parser callback case, we don't have to check anything, since we were right the first time. |
- // In the DOM case, we only need to do something if |afterChange| is not 0. |
- // |afterChange| is 0 in the parser case, so it works out that we'll skip this block. |
- if (childrenAffectedByFirstChildRules() && nodeAfterChange) { |
- DCHECK_NE(changeType, FinishedParsingChildren); |
- // Find our new first child element. |
- Element* firstChildElement = ElementTraversal::firstChild(*this); |
+ Element* elementAfterChange = !nodeAfterChange || nodeAfterChange->isElementNode() ? toElement(nodeAfterChange) : ElementTraversal::nextSibling(*nodeAfterChange); |
+ Element* elementBeforeChange = !nodeBeforeChange || nodeBeforeChange->isElementNode() ? toElement(nodeBeforeChange) : ElementTraversal::previousSibling(*nodeBeforeChange); |
- // Find the first element after the change. |
- Element* elementAfterChange = nodeAfterChange->isElementNode() ? toElement(nodeAfterChange) : ElementTraversal::nextSibling(*nodeAfterChange); |
- |
- // This is the element insertion as first child element case. |
- if (changeType == SiblingElementInserted && elementAfterChange && firstChildElement != elementAfterChange |
- && (!nodeBeforeChange || !nodeBeforeChange->isElementNode()) && elementAfterChange->affectedByFirstChildRules()) { |
- elementAfterChange->setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::SiblingSelector)); |
- } |
- |
- // This is the first child element removal case. |
- if (changeType == SiblingElementRemoved && firstChildElement == elementAfterChange && firstChildElement && firstChildElement->affectedByFirstChildRules()) |
- firstChildElement->setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::SiblingSelector)); |
+ if (childrenAffectedByFirstChildRules() && !elementBeforeChange && elementAfterChange && elementAfterChange->affectedByFirstChildRules()) { |
+ DCHECK_NE(changeType, FinishedParsingChildren); |
+ elementAfterChange->pseudoStateChanged(CSSSelector::PseudoFirstChild); |
+ elementAfterChange->pseudoStateChanged(CSSSelector::PseudoOnlyChild); |
} |
- // :last-child. In the parser callback case, we don't have to check anything, since we were right the first time. |
- // In the DOM case, we only need to do something if |afterChange| is not 0. |
- if (childrenAffectedByLastChildRules() && nodeBeforeChange) { |
- // Find our new last child element. |
- Element* lastChildElement = ElementTraversal::lastChild(*this); |
- |
- // Find the last element before the change. |
- Element* elementBeforeChange = nodeBeforeChange->isElementNode() ? toElement(nodeBeforeChange) : ElementTraversal::previousSibling(*nodeBeforeChange); |
- |
- // This is the element insertion as last child element case. |
- if (changeType == SiblingElementInserted && elementBeforeChange && lastChildElement != elementBeforeChange |
- && (!nodeAfterChange || !nodeAfterChange->isElementNode()) && elementBeforeChange->affectedByLastChildRules()) { |
- elementBeforeChange->setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::SiblingSelector)); |
- } |
- |
- // This is the last child element removal case. The parser callback case is similar to node removal as well in that we need to change the last child |
- // to match now. |
- if ((changeType == SiblingElementRemoved || changeType == FinishedParsingChildren) && lastChildElement == elementBeforeChange && lastChildElement && lastChildElement->affectedByLastChildRules()) |
- lastChildElement->setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::SiblingSelector)); |
+ if (childrenAffectedByLastChildRules() && !elementAfterChange && elementBeforeChange && elementBeforeChange->affectedByLastChildRules()) { |
+ elementBeforeChange->pseudoStateChanged(CSSSelector::PseudoLastChild); |
+ elementBeforeChange->pseudoStateChanged(CSSSelector::PseudoOnlyChild); |
} |
// For ~ and + combinators, succeeding siblings may need style invalidation |
// after an element is inserted or removed. |
- if (!nodeAfterChange) |
- return; |
- if (changeType != SiblingElementRemoved && changeType != SiblingElementInserted) |
+ if (!elementAfterChange) |
return; |
+ |
if (!childrenAffectedByIndirectAdjacentRules() && !childrenAffectedByDirectAdjacentRules()) |
return; |
- Element* elementAfterChange = nodeAfterChange->isElementNode() ? toElement(nodeAfterChange) : ElementTraversal::nextSibling(*nodeAfterChange); |
- if (!elementAfterChange) |
+ if (changeType == SiblingElementInserted) { |
+ document().styleEngine().scheduleInvalidationsForInsertedSibling(elementBeforeChange, *changedElement); |
return; |
- Element* elementBeforeChange = nullptr; |
- if (nodeBeforeChange) |
- elementBeforeChange = nodeBeforeChange->isElementNode() ? toElement(nodeBeforeChange) : ElementTraversal::previousSibling(*nodeBeforeChange); |
+ } |
- if (changeType == SiblingElementInserted) |
- document().styleEngine().scheduleInvalidationsForInsertedSibling(elementBeforeChange, *toElement(changedNode)); |
- else |
- document().styleEngine().scheduleInvalidationsForRemovedSibling(elementBeforeChange, *toElement(changedNode), *elementAfterChange); |
+ DCHECK(changeType == SiblingElementRemoved); |
+ document().styleEngine().scheduleInvalidationsForRemovedSibling(elementBeforeChange, *changedElement, *elementAfterChange); |
} |
void ContainerNode::invalidateNodeListCachesInAncestors(const QualifiedName* attrName, Element* attributeOwnerElement) |