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

Unified Diff: third_party/WebKit/Source/core/dom/ContainerNode.cpp

Issue 2229503002: Style invalidation support for :first/last/only-child. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixed review issue Created 4 years, 4 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « third_party/WebKit/Source/core/dom/ContainerNode.h ('k') | third_party/WebKit/Source/core/dom/Element.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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)
« no previous file with comments | « third_party/WebKit/Source/core/dom/ContainerNode.h ('k') | third_party/WebKit/Source/core/dom/Element.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698