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: Source/core/dom/Element.cpp

Issue 15871005: Avoid N^2 walk placing renderers when building the render tree (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Adding a mitigation for the perf regression to Element::recalcStyle. Created 7 years, 5 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
« no previous file with comments | « Source/core/dom/Element.h ('k') | Source/core/dom/ScriptElement.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 1411 matching lines...) Expand 10 before | Expand all | Expand 10 after
1422 // is needed, but for now just assume a layout will be required. The diff code 1422 // is needed, but for now just assume a layout will be required. The diff code
1423 // in RenderObject::setStyle would need to be factored out so th at it could be reused. 1423 // in RenderObject::setStyle would need to be factored out so th at it could be reused.
1424 renderer()->setNeedsLayoutAndPrefWidthsRecalc(); 1424 renderer()->setNeedsLayoutAndPrefWidthsRecalc();
1425 } 1425 }
1426 return true; 1426 return true;
1427 } 1427 }
1428 } 1428 }
1429 return false; 1429 return false;
1430 } 1430 }
1431 1431
1432 PassRefPtr<RenderStyle> Element::styleForRenderer() 1432 PassRefPtr<RenderStyle> Element::styleForRenderer(int childIndex)
1433 { 1433 {
1434 if (hasCustomStyleCallbacks()) { 1434 if (hasCustomStyleCallbacks()) {
1435 if (RefPtr<RenderStyle> style = customStyleForRenderer()) 1435 if (RefPtr<RenderStyle> style = customStyleForRenderer())
1436 return style.release(); 1436 return style.release();
1437 } 1437 }
1438 1438
1439 return originalStyleForRenderer(); 1439 return originalStyleForRenderer(childIndex);
1440 } 1440 }
1441 1441
1442 PassRefPtr<RenderStyle> Element::originalStyleForRenderer() 1442 PassRefPtr<RenderStyle> Element::originalStyleForRenderer(int childIndex)
1443 { 1443 {
1444 return document()->styleResolver()->styleForElement(this); 1444 return document()->styleResolver()->styleForElement(this, childIndex);
1445 } 1445 }
1446 1446
1447 void Element::recalcStyle(StyleChange change) 1447 void Element::recalcStyle(StyleChange change, int childIndex)
1448 { 1448 {
1449 ASSERT(document()->inStyleRecalc()); 1449 ASSERT(document()->inStyleRecalc());
1450 1450
1451 if (hasCustomStyleCallbacks()) 1451 if (hasCustomStyleCallbacks())
1452 willRecalcStyle(change); 1452 willRecalcStyle(change);
1453 1453
1454 // Ref currentStyle in case it would otherwise be deleted when setting the n ew style in the renderer. 1454 // Ref currentStyle in case it would otherwise be deleted when setting the n ew style in the renderer.
1455 RefPtr<RenderStyle> currentStyle(renderStyle()); 1455 RefPtr<RenderStyle> currentStyle(renderStyle());
1456 bool hasParentStyle = parentNodeForRenderingAndStyle() ? static_cast<bool>(p arentNodeForRenderingAndStyle()->renderStyle()) : false; 1456 bool hasParentStyle = parentNodeForRenderingAndStyle() ? static_cast<bool>(p arentNodeForRenderingAndStyle()->renderStyle()) : false;
1457 bool hasDirectAdjacentRules = childrenAffectedByDirectAdjacentRules(); 1457 bool hasDirectAdjacentRules = childrenAffectedByDirectAdjacentRules();
1458 bool hasIndirectAdjacentRules = childrenAffectedByForwardPositionalRules(); 1458 bool hasIndirectAdjacentRules = childrenAffectedByForwardPositionalRules();
1459 1459
1460 if ((change > NoChange || needsStyleRecalc())) { 1460 if ((change > NoChange || needsStyleRecalc())) {
1461 if (hasRareData()) 1461 if (hasRareData())
1462 elementRareData()->resetComputedStyle(); 1462 elementRareData()->resetComputedStyle();
1463 } 1463 }
1464 if (hasParentStyle && (change >= Inherit || needsStyleRecalc())) { 1464 if (hasParentStyle && (change >= Inherit || needsStyleRecalc())) {
1465 StyleChange localChange = Detach; 1465 StyleChange localChange = Detach;
1466 RefPtr<RenderStyle> newStyle; 1466 RefPtr<RenderStyle> newStyle;
1467 if (currentStyle) { 1467 if (currentStyle) {
1468 // FIXME: This still recalcs style twice when changing display types , but saves 1468 // FIXME: This still recalcs style twice when changing display types , but saves
1469 // us from recalcing twice when going from none -> anything else whi ch is more 1469 // us from recalcing twice when going from none -> anything else whi ch is more
1470 // common, especially during lazy attach. 1470 // common, especially during lazy attach.
1471 newStyle = styleForRenderer(); 1471 newStyle = styleForRenderer(childIndex);
1472 localChange = Node::diff(currentStyle.get(), newStyle.get(), documen t()); 1472 localChange = Node::diff(currentStyle.get(), newStyle.get(), documen t());
1473 } else if (attached() && isActiveInsertionPoint(this)) { 1473 } else if (attached() && isActiveInsertionPoint(this)) {
1474 // Active InsertionPoints will never have renderers so there's no re ason to 1474 // Active InsertionPoints will never have renderers so there's no re ason to
1475 // reattach them repeatedly once they're already attached. 1475 // reattach them repeatedly once they're already attached.
1476 localChange = change; 1476 localChange = change;
1477 } 1477 }
1478 if (localChange == Detach) { 1478 if (localChange == Detach) {
1479 AttachContext reattachContext; 1479 AttachContext reattachContext;
1480 reattachContext.resolvedStyle = newStyle.get(); 1480 reattachContext.resolvedStyle = newStyle.get();
1481 reattach(reattachContext); 1481 reattach(reattachContext);
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
1525 } 1525 }
1526 1526
1527 if (shouldRecalcStyle(change, this)) 1527 if (shouldRecalcStyle(change, this))
1528 updatePseudoElement(BEFORE, change); 1528 updatePseudoElement(BEFORE, change);
1529 1529
1530 // FIXME: This check is good enough for :hover + foo, but it is not good eno ugh for :hover + foo + bar. 1530 // FIXME: This check is good enough for :hover + foo, but it is not good eno ugh for :hover + foo + bar.
1531 // For now we will just worry about the common case, since it's a lot tricki er to get the second case right 1531 // For now we will just worry about the common case, since it's a lot tricki er to get the second case right
1532 // without doing way too much re-resolution. 1532 // without doing way too much re-resolution.
1533 bool forceCheckOfNextElementSibling = false; 1533 bool forceCheckOfNextElementSibling = false;
1534 bool forceCheckOfAnyElementSibling = false; 1534 bool forceCheckOfAnyElementSibling = false;
1535 for (Node *n = firstChild(); n; n = n->nextSibling()) { 1535 int indexForChild = 0;
1536 if (hasDirectAdjacentRules || hasIndirectAdjacentRules) {
1537 for (Node *n = firstChild(); n; n = n->nextSibling()) {
1538 ++indexForChild;
1539 if (!n->isElementNode())
1540 continue;
1541 Element* element = toElement(n);
1542 bool childRulesChanged = element->needsStyleRecalc() && element->sty leChangeType() == FullStyleChange;
1543 if ((forceCheckOfNextElementSibling || forceCheckOfAnyElementSibling ))
1544 element->setNeedsStyleRecalc();
1545 forceCheckOfNextElementSibling = childRulesChanged && hasDirectAdjac entRules;
1546 forceCheckOfAnyElementSibling = forceCheckOfAnyElementSibling || (ch ildRulesChanged && hasIndirectAdjacentRules);
1547 }
1548 }
1549 // FIXME: Reversing the loop we call recalcStyle avoids an N^2 walk through the DOM to find the next renderer
1550 // to insert before. The logic in NodeRenderingContext should be improved to make this unnecessary.
1551 for (Node *n = lastChild(); n; n = n->previousSibling()) {
1552 --indexForChild;
1536 if (n->isTextNode()) { 1553 if (n->isTextNode()) {
1537 toText(n)->recalcTextStyle(change); 1554 toText(n)->recalcTextStyle(change);
1538 continue; 1555 continue;
1539 } 1556 }
1540 if (!n->isElementNode()) 1557 if (!n->isElementNode())
1541 continue; 1558 continue;
1542 Element* element = toElement(n); 1559 Element* element = toElement(n);
1543 bool childRulesChanged = element->needsStyleRecalc() && element->styleCh angeType() == FullStyleChange;
1544 if ((forceCheckOfNextElementSibling || forceCheckOfAnyElementSibling))
1545 element->setNeedsStyleRecalc();
1546 if (shouldRecalcStyle(change, element)) { 1560 if (shouldRecalcStyle(change, element)) {
1547 parentPusher.push(); 1561 parentPusher.push();
1548 element->recalcStyle(change); 1562 element->recalcStyle(change, max(indexForChild + 1, 0));
1549 } 1563 }
1550 forceCheckOfNextElementSibling = childRulesChanged && hasDirectAdjacentR ules;
1551 forceCheckOfAnyElementSibling = forceCheckOfAnyElementSibling || (childR ulesChanged && hasIndirectAdjacentRules);
1552 } 1564 }
1553 1565
1554 if (shouldRecalcStyle(change, this)) 1566 if (shouldRecalcStyle(change, this))
1555 updatePseudoElement(AFTER, change); 1567 updatePseudoElement(AFTER, change);
1556 1568
1557 clearNeedsStyleRecalc(); 1569 clearNeedsStyleRecalc();
1558 clearChildNeedsStyleRecalc(); 1570 clearChildNeedsStyleRecalc();
1559 1571
1560 if (hasCustomStyleCallbacks()) 1572 if (hasCustomStyleCallbacks())
1561 didRecalcStyle(change); 1573 didRecalcStyle(change);
(...skipping 2004 matching lines...) Expand 10 before | Expand all | Expand 10 after
3566 return 0; 3578 return 0;
3567 } 3579 }
3568 3580
3569 Attribute* UniqueElementData::attributeItem(unsigned index) 3581 Attribute* UniqueElementData::attributeItem(unsigned index)
3570 { 3582 {
3571 ASSERT_WITH_SECURITY_IMPLICATION(index < length()); 3583 ASSERT_WITH_SECURITY_IMPLICATION(index < length());
3572 return &m_attributeVector.at(index); 3584 return &m_attributeVector.at(index);
3573 } 3585 }
3574 3586
3575 } // namespace WebCore 3587 } // namespace WebCore
OLDNEW
« no previous file with comments | « Source/core/dom/Element.h ('k') | Source/core/dom/ScriptElement.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698