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

Side by Side 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: 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 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 reserved. 5 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2013 Apple Inc. All rights reserved.
6 * 6 *
7 * This library is free software; you can redistribute it and/or 7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public 8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either 9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version. 10 * version 2 of the License, or (at your option) any later version.
(...skipping 1203 matching lines...) Expand 10 before | Expand all | Expand 10 after
1214 if (element->shouldCallRecalcStyle(change)) 1214 if (element->shouldCallRecalcStyle(change))
1215 element->recalcStyle(change, lastTextNode); 1215 element->recalcStyle(change, lastTextNode);
1216 else if (element->supportsStyleSharing()) 1216 else if (element->supportsStyleSharing())
1217 styleResolver.addToStyleSharingList(*element); 1217 styleResolver.addToStyleSharingList(*element);
1218 if (element->layoutObject()) 1218 if (element->layoutObject())
1219 lastTextNode = nullptr; 1219 lastTextNode = nullptr;
1220 } 1220 }
1221 } 1221 }
1222 } 1222 }
1223 1223
1224 void ContainerNode::checkForSiblingStyleChanges(SiblingCheckType changeType, Nod e* changedNode, Node* nodeBeforeChange, Node* nodeAfterChange) 1224 void ContainerNode::checkForSiblingStyleChanges(SiblingCheckType changeType, Ele ment* changedElement, Node* nodeBeforeChange, Node* nodeAfterChange)
1225 { 1225 {
1226 if (!inActiveDocument() || document().hasPendingForcedStyleRecalc() || getSt yleChangeType() >= SubtreeStyleChange) 1226 if (!inActiveDocument() || document().hasPendingForcedStyleRecalc() || getSt yleChangeType() >= SubtreeStyleChange)
1227 return; 1227 return;
1228 1228
1229 // Forward positional selectors include nth-child, nth-of-type, first-of-typ e and only-of-type. 1229 if (!hasRareData() || !rareData()->hasRestyleFlag(ChildrenAffectedByStructur alRules))
esprehn 2016/08/08 20:07:53 hasRestyleFlag is a method on ContainerNode which
rune 2016/08/08 20:21:57 Yup. Done.
1230 // The indirect adjacent selector is the ~ selector. 1230 return;
1231 // Backward positional selectors include nth-last-child, nth-last-of-type, l ast-of-type and only-of-type. 1231
1232 // We have to invalidate everything following the insertion point in the for ward and indirect adjacent case, 1232 // Forward positional selectors include :nth-child, :nth-of-type,
1233 // and everything before the insertion point in the backward case. 1233 // :first-of-type, and only-of-type. The indirect adjacent selector is the ~
1234 // |afterChange| is 0 in the parser callback case, so we won't do any work f or the forward case if we don't have to. 1234 // selector. Backward positional selectors include :nth-last-child,
1235 // 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 1235 // :nth-last-of-type, :last-of-type, and :only-of-type. We have to
1236 // here. recalcStyle will then force a walk of the children when it sees tha t this has happened. 1236 // invalidate everything following the insertion point in the forward and
1237 // indirect adjacent case, and everything before the insertion point in the
1238 // backward case. |nodeAfterChange| is nullptr in the parser callback case,
1239 // so we won't do any work for the forward case if we don't have to.
1240 // For performance reasons we just mark the parent node as changed, since we
1241 // don't want to make childrenChanged O(n^2) by crawling all our kids here.
1242 // recalcStyle will then force a walk of the children when it sees that this
1243 // has happened.
1237 if ((childrenAffectedByForwardPositionalRules() && nodeAfterChange) 1244 if ((childrenAffectedByForwardPositionalRules() && nodeAfterChange)
1238 || (childrenAffectedByBackwardPositionalRules() && nodeBeforeChange)) { 1245 || (childrenAffectedByBackwardPositionalRules() && nodeBeforeChange)) {
1239 setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::cre ate(StyleChangeReason::SiblingSelector)); 1246 setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::cre ate(StyleChangeReason::SiblingSelector));
1240 return; 1247 return;
1241 } 1248 }
1242 1249
1243 // :first-child. In the parser callback case, we don't have to check anythin g, since we were right the first time. 1250 Element* elementAfterChange = !nodeAfterChange || nodeAfterChange->isElement Node() ? toElement(nodeAfterChange) : ElementTraversal::nextSibling(*nodeAfterCh ange);
1244 // In the DOM case, we only need to do something if |afterChange| is not 0. 1251 Element* elementBeforeChange = !nodeBeforeChange || nodeBeforeChange->isElem entNode() ? toElement(nodeBeforeChange) : ElementTraversal::previousSibling(*nod eBeforeChange);
1245 // |afterChange| is 0 in the parser case, so it works out that we'll skip th is block. 1252
1246 if (childrenAffectedByFirstChildRules() && nodeAfterChange) { 1253 if (childrenAffectedByFirstChildRules() && !elementBeforeChange && elementAf terChange && elementAfterChange->affectedByFirstChildRules()) {
1247 DCHECK_NE(changeType, FinishedParsingChildren); 1254 DCHECK_NE(changeType, FinishedParsingChildren);
1248 // Find our new first child element. 1255 elementAfterChange->pseudoStateChanged(CSSSelector::PseudoFirstChild);
1249 Element* firstChildElement = ElementTraversal::firstChild(*this); 1256 elementAfterChange->pseudoStateChanged(CSSSelector::PseudoOnlyChild);
1250
1251 // Find the first element after the change.
1252 Element* elementAfterChange = nodeAfterChange->isElementNode() ? toEleme nt(nodeAfterChange) : ElementTraversal::nextSibling(*nodeAfterChange);
1253
1254 // This is the element insertion as first child element case.
1255 if (changeType == SiblingElementInserted && elementAfterChange && firstC hildElement != elementAfterChange
1256 && (!nodeBeforeChange || !nodeBeforeChange->isElementNode()) && elem entAfterChange->affectedByFirstChildRules()) {
1257 elementAfterChange->setNeedsStyleRecalc(SubtreeStyleChange, StyleCha ngeReasonForTracing::create(StyleChangeReason::SiblingSelector));
1258 }
1259
1260 // This is the first child element removal case.
1261 if (changeType == SiblingElementRemoved && firstChildElement == elementA fterChange && firstChildElement && firstChildElement->affectedByFirstChildRules( ))
1262 firstChildElement->setNeedsStyleRecalc(SubtreeStyleChange, StyleChan geReasonForTracing::create(StyleChangeReason::SiblingSelector));
1263 } 1257 }
1264 1258
1265 // :last-child. In the parser callback case, we don't have to check anything , since we were right the first time. 1259 if (childrenAffectedByLastChildRules() && !elementAfterChange && elementBefo reChange && elementBeforeChange->affectedByLastChildRules()) {
1266 // In the DOM case, we only need to do something if |afterChange| is not 0. 1260 elementBeforeChange->pseudoStateChanged(CSSSelector::PseudoLastChild);
1267 if (childrenAffectedByLastChildRules() && nodeBeforeChange) { 1261 elementBeforeChange->pseudoStateChanged(CSSSelector::PseudoOnlyChild);
1268 // Find our new last child element.
1269 Element* lastChildElement = ElementTraversal::lastChild(*this);
1270
1271 // Find the last element before the change.
1272 Element* elementBeforeChange = nodeBeforeChange->isElementNode() ? toEle ment(nodeBeforeChange) : ElementTraversal::previousSibling(*nodeBeforeChange);
1273
1274 // This is the element insertion as last child element case.
1275 if (changeType == SiblingElementInserted && elementBeforeChange && lastC hildElement != elementBeforeChange
1276 && (!nodeAfterChange || !nodeAfterChange->isElementNode()) && elemen tBeforeChange->affectedByLastChildRules()) {
1277 elementBeforeChange->setNeedsStyleRecalc(SubtreeStyleChange, StyleCh angeReasonForTracing::create(StyleChangeReason::SiblingSelector));
1278 }
1279
1280 // 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
1281 // to match now.
1282 if ((changeType == SiblingElementRemoved || changeType == FinishedParsin gChildren) && lastChildElement == elementBeforeChange && lastChildElement && las tChildElement->affectedByLastChildRules())
1283 lastChildElement->setNeedsStyleRecalc(SubtreeStyleChange, StyleChang eReasonForTracing::create(StyleChangeReason::SiblingSelector));
1284 } 1262 }
1285 1263
1286 // For ~ and + combinators, succeeding siblings may need style invalidation 1264 // For ~ and + combinators, succeeding siblings may need style invalidation
1287 // after an element is inserted or removed. 1265 // after an element is inserted or removed.
1288 1266
1289 if (!nodeAfterChange) 1267 if (!elementAfterChange)
1290 return; 1268 return;
1291 if (changeType != SiblingElementRemoved && changeType != SiblingElementInser ted) 1269
1292 return;
1293 if (!childrenAffectedByIndirectAdjacentRules() && !childrenAffectedByDirectA djacentRules()) 1270 if (!childrenAffectedByIndirectAdjacentRules() && !childrenAffectedByDirectA djacentRules())
1294 return; 1271 return;
1295 1272
1296 Element* elementAfterChange = nodeAfterChange->isElementNode() ? toElement(n odeAfterChange) : ElementTraversal::nextSibling(*nodeAfterChange); 1273 if (changeType == SiblingElementInserted) {
1297 if (!elementAfterChange) 1274 document().styleEngine().scheduleInvalidationsForInsertedSibling(element BeforeChange, *changedElement);
1298 return; 1275 return;
1299 Element* elementBeforeChange = nullptr; 1276 }
1300 if (nodeBeforeChange)
1301 elementBeforeChange = nodeBeforeChange->isElementNode() ? toElement(node BeforeChange) : ElementTraversal::previousSibling(*nodeBeforeChange);
1302 1277
1303 if (changeType == SiblingElementInserted) 1278 DCHECK(changeType == SiblingElementRemoved);
1304 document().styleEngine().scheduleInvalidationsForInsertedSibling(element BeforeChange, *toElement(changedNode)); 1279 document().styleEngine().scheduleInvalidationsForRemovedSibling(elementBefor eChange, *changedElement, *elementAfterChange);
1305 else
1306 document().styleEngine().scheduleInvalidationsForRemovedSibling(elementB eforeChange, *toElement(changedNode), *elementAfterChange);
1307 } 1280 }
1308 1281
1309 void ContainerNode::invalidateNodeListCachesInAncestors(const QualifiedName* att rName, Element* attributeOwnerElement) 1282 void ContainerNode::invalidateNodeListCachesInAncestors(const QualifiedName* att rName, Element* attributeOwnerElement)
1310 { 1283 {
1311 if (hasRareData() && (!attrName || isAttributeNode())) { 1284 if (hasRareData() && (!attrName || isAttributeNode())) {
1312 if (NodeListsNodeData* lists = rareData()->nodeLists()) { 1285 if (NodeListsNodeData* lists = rareData()->nodeLists()) {
1313 if (ChildNodeList* childNodeList = lists->childNodeList(*this)) 1286 if (ChildNodeList* childNodeList = lists->childNodeList(*this))
1314 childNodeList->invalidateCache(); 1287 childNodeList->invalidateCache();
1315 } 1288 }
1316 } 1289 }
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
1404 return true; 1377 return true;
1405 1378
1406 if (node->isElementNode() && toElement(node)->shadow()) 1379 if (node->isElementNode() && toElement(node)->shadow())
1407 return true; 1380 return true;
1408 1381
1409 return false; 1382 return false;
1410 } 1383 }
1411 #endif 1384 #endif
1412 1385
1413 } // namespace blink 1386 } // namespace blink
OLDNEW
« 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