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

Side by Side Diff: Source/core/dom/Element.cpp

Issue 24350009: Reverse style resolution to avoid N^2 walk when building the render tree (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Fixing loops in Regions Created 7 years, 2 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 | Annotate | Revision Log
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 Peter Kelly (pmk@post.com) 4 * (C) 2001 Peter Kelly (pmk@post.com)
5 * (C) 2001 Dirk Mueller (mueller@kde.org) 5 * (C) 2001 Dirk Mueller (mueller@kde.org)
6 * (C) 2007 David Smith (catfish.man@gmail.com) 6 * (C) 2007 David Smith (catfish.man@gmail.com)
7 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012, 2013 Apple Inc. All rights reserved. 7 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012, 2013 Apple Inc. All rights reserved.
8 * (C) 2007 Eric Seidel (eric@webkit.org) 8 * (C) 2007 Eric Seidel (eric@webkit.org)
9 * 9 *
10 * This library is free software; you can redistribute it and/or 10 * This library is free software; you can redistribute it and/or
(...skipping 1496 matching lines...) Expand 10 before | Expand all | Expand 10 after
1507 document().styleResolver()->invalidateMatchedPropertiesCache(); 1507 document().styleResolver()->invalidateMatchedPropertiesCache();
1508 return Force; 1508 return Force;
1509 } 1509 }
1510 1510
1511 if (styleChangeType() >= SubtreeStyleChange) 1511 if (styleChangeType() >= SubtreeStyleChange)
1512 return Force; 1512 return Force;
1513 1513
1514 return max(localChange, change); 1514 return max(localChange, change);
1515 } 1515 }
1516 1516
1517 static const int maxWhitespaceChildrenToDefer = 10;
1518 typedef Vector<Text*, maxWhitespaceChildrenToDefer> DeferredWhitespaceChildren;
1519
1520 static inline void recalcWhitespaceChildrenStyle(DeferredWhitespaceChildren& whi tespaceChildren, StyleRecalcChange change)
1521 {
1522 for (int i = whitespaceChildren.size() - 1; i >= 0; --i)
1523 whitespaceChildren[i]->recalcTextStyle(change);
1524 }
1525
1517 void Element::recalcChildStyle(StyleRecalcChange change) 1526 void Element::recalcChildStyle(StyleRecalcChange change)
1518 { 1527 {
1519 ASSERT(document().inStyleRecalc()); 1528 ASSERT(document().inStyleRecalc());
1520 1529
1521 StyleResolverParentPusher parentPusher(this); 1530 StyleResolverParentPusher parentPusher(this);
1522 1531
1523 for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadow Root()) { 1532 for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadow Root()) {
1524 if (shouldRecalcStyle(change, root)) { 1533 if (shouldRecalcStyle(change, root)) {
1525 parentPusher.push(); 1534 parentPusher.push();
1526 root->recalcStyle(change); 1535 root->recalcStyle(change);
1527 } 1536 }
1528 } 1537 }
1529 1538
1530 if (shouldRecalcStyle(change, this)) 1539 if (shouldRecalcStyle(change, this))
1531 updatePseudoElement(BEFORE, change); 1540 updatePseudoElement(BEFORE, change);
1532 1541
1533 // FIXME: This check is good enough for :hover + foo, but it is not good eno ugh for :hover + foo + bar. 1542 // FIXME: This check is good enough for :hover + foo, but it is not good eno ugh for :hover + foo + bar.
1534 // For now we will just worry about the common case, since it's a lot tricki er to get the second case right 1543 // For now we will just worry about the common case, since it's a lot tricki er to get the second case right
1535 // without doing way too much re-resolution. 1544 // without doing way too much re-resolution.
1536 bool hasDirectAdjacentRules = childrenAffectedByDirectAdjacentRules(); 1545 bool hasDirectAdjacentRules = childrenAffectedByDirectAdjacentRules();
1537 bool hasIndirectAdjacentRules = childrenAffectedByForwardPositionalRules(); 1546 bool hasIndirectAdjacentRules = childrenAffectedByForwardPositionalRules();
1538 bool forceCheckOfNextElementSibling = false; 1547 bool forceCheckOfNextElementSibling = false;
1539 bool forceCheckOfAnyElementSibling = false; 1548 bool forceCheckOfAnyElementSibling = false;
1540 bool forceReattachOfAnyWhitespaceSibling = false; 1549 if (hasDirectAdjacentRules || hasIndirectAdjacentRules) {
1541 for (Node* child = firstChild(); child; child = child->nextSibling()) { 1550 for (Node* child = firstChild(); child; child = child->nextSibling()) {
1551 if (!child->isElementNode())
1552 continue;
1553 Element* element = toElement(child);
1554 bool childRulesChanged = element->needsStyleRecalc() && element->sty leChangeType() >= SubtreeStyleChange;
1555 if (forceCheckOfNextElementSibling || forceCheckOfAnyElementSibling)
1556 element->setNeedsStyleRecalc();
1557 forceCheckOfNextElementSibling = childRulesChanged && hasDirectAdjac entRules;
1558 forceCheckOfAnyElementSibling = forceCheckOfAnyElementSibling || (ch ildRulesChanged && hasIndirectAdjacentRules);
1559 }
1560 }
1561 // This loop is deliberately backwards because we use insertBefore in the re ndering tree, and want to avoid
1562 // a potentially n^2 loop to find the insertion point while resolving style. Having us start from the last
1563 // child and work our way back means in the common case, we'll find the inse rtion point in O(1) time.
1564 // Reversing this loop can lead to non-deterministic results in our code to optimize out empty whitespace
1565 // RenderTexts. We try to put off recalcing their style until the end to avo id this issue.
1566 // See crbug.com/288225
1567 DeferredWhitespaceChildren whitespaceChildren;
1568 for (Node* child = lastChild(); child; child = child->previousSibling()) {
1542 bool didReattach = false; 1569 bool didReattach = false;
1543 1570
1544 if (child->renderer())
1545 forceReattachOfAnyWhitespaceSibling = false;
1546
1547 if (child->isTextNode()) { 1571 if (child->isTextNode()) {
1548 if (forceReattachOfAnyWhitespaceSibling && toText(child)->containsOn lyWhitespace()) 1572 Text* textChild = toText(child);
1549 child->reattach(); 1573 if (textChild->containsOnlyWhitespace()) {
esprehn 2013/09/30 22:55:34 This also makes us do the string scan for whitespa
1550 else 1574 if (whitespaceChildren.size() == maxWhitespaceChildrenToDefer) {
1575 recalcWhitespaceChildrenStyle(whitespaceChildren, change);
1576 whitespaceChildren.clear();
1577 }
1578 whitespaceChildren.append(textChild);
1579 } else {
1551 didReattach = toText(child)->recalcTextStyle(change); 1580 didReattach = toText(child)->recalcTextStyle(change);
1581 }
1552 } else if (child->isElementNode()) { 1582 } else if (child->isElementNode()) {
1553 Element* element = toElement(child); 1583 Element* element = toElement(child);
1554
1555 bool childRulesChanged = element->needsStyleRecalc() && element->sty leChangeType() >= SubtreeStyleChange;
1556
1557 if (forceCheckOfNextElementSibling || forceCheckOfAnyElementSibling)
1558 element->setNeedsStyleRecalc();
1559
1560 forceCheckOfNextElementSibling = childRulesChanged && hasDirectAdjac entRules;
1561 forceCheckOfAnyElementSibling = forceCheckOfAnyElementSibling || (ch ildRulesChanged && hasIndirectAdjacentRules);
1562
1563 if (shouldRecalcStyle(change, element)) { 1584 if (shouldRecalcStyle(change, element)) {
1564 parentPusher.push(); 1585 parentPusher.push();
1565 didReattach = element->recalcStyle(change); 1586 didReattach = element->recalcStyle(change);
1566 } else if (document().styleResolver()->supportsStyleSharing(element) ) { 1587 } else if (document().styleResolver()->supportsStyleSharing(element) ) {
1567 document().styleResolver()->addToStyleSharingList(element); 1588 document().styleResolver()->addToStyleSharingList(element);
1568 } 1589 }
1569 } 1590 }
1570 1591
1571 forceReattachOfAnyWhitespaceSibling = didReattach || forceReattachOfAnyW hitespaceSibling; 1592 if (didReattach)
1593 child->reattachWhitespaceSiblings();
1572 } 1594 }
1573 1595
1596 recalcWhitespaceChildrenStyle(whitespaceChildren, change);
1597
1574 if (shouldRecalcStyle(change, this)) { 1598 if (shouldRecalcStyle(change, this)) {
1575 updatePseudoElement(AFTER, change); 1599 updatePseudoElement(AFTER, change);
1576 updatePseudoElement(BACKDROP, change); 1600 updatePseudoElement(BACKDROP, change);
1577 } 1601 }
1578 } 1602 }
1579 1603
1580 ElementShadow* Element::shadow() const 1604 ElementShadow* Element::shadow() const
1581 { 1605 {
1582 return hasRareData() ? elementRareData()->shadow() : 0; 1606 return hasRareData() ? elementRareData()->shadow() : 0;
1583 } 1607 }
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after
1733 1757
1734 // We also have to handle node removal. The parser callback case is sim ilar to node removal as well in that we need to change the last child 1758 // We also have to handle node removal. The parser callback case is sim ilar to node removal as well in that we need to change the last child
1735 // to match now. 1759 // to match now.
1736 if ((childCountDelta < 0 || finishedParsingCallback) && newLastChild == lastElementBeforeInsertion && newLastChild && (!newLastChildStyle || !newLastChi ldStyle->lastChildState())) 1760 if ((childCountDelta < 0 || finishedParsingCallback) && newLastChild == lastElementBeforeInsertion && newLastChild && (!newLastChildStyle || !newLastChi ldStyle->lastChildState()))
1737 newLastChild->setNeedsStyleRecalc(); 1761 newLastChild->setNeedsStyleRecalc();
1738 } 1762 }
1739 1763
1740 // The + selector. We need to invalidate the first element following the in sertion point. It is the only possible element 1764 // The + selector. We need to invalidate the first element following the in sertion point. It is the only possible element
1741 // that could be affected by this DOM change. 1765 // that could be affected by this DOM change.
1742 if (e->childrenAffectedByDirectAdjacentRules() && afterChange) { 1766 if (e->childrenAffectedByDirectAdjacentRules() && afterChange) {
1743 if (Node* firstElementAfterInsertion = afterChange->nextElementSibling() ) 1767 if (Node* firstElementAfterInsertion = afterChange->isElementNode() ? af terChange : afterChange->nextElementSibling())
1744 firstElementAfterInsertion->setNeedsStyleRecalc(); 1768 firstElementAfterInsertion->setNeedsStyleRecalc();
1745 } 1769 }
1746 } 1770 }
1747 1771
1748 void Element::childrenChanged(bool changedByParser, Node* beforeChange, Node* af terChange, int childCountDelta) 1772 void Element::childrenChanged(bool changedByParser, Node* beforeChange, Node* af terChange, int childCountDelta)
1749 { 1773 {
1750 ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, c hildCountDelta); 1774 ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, c hildCountDelta);
1751 if (changedByParser) 1775 if (changedByParser)
1752 checkForEmptyStyleChange(this, renderStyle()); 1776 checkForEmptyStyleChange(this, renderStyle());
1753 else 1777 else
(...skipping 1888 matching lines...) Expand 10 before | Expand all | Expand 10 after
3642 return 0; 3666 return 0;
3643 } 3667 }
3644 3668
3645 Attribute* UniqueElementData::attributeItem(unsigned index) 3669 Attribute* UniqueElementData::attributeItem(unsigned index)
3646 { 3670 {
3647 ASSERT_WITH_SECURITY_IMPLICATION(index < length()); 3671 ASSERT_WITH_SECURITY_IMPLICATION(index < length());
3648 return &m_attributeVector.at(index); 3672 return &m_attributeVector.at(index);
3649 } 3673 }
3650 3674
3651 } // namespace WebCore 3675 } // namespace WebCore
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698