Changeset 166303 in webkit
- Timestamp:
- Mar 26, 2014, 11:35:55 AM (11 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r166301 r166303 1 2014-03-26 Antti Koivisto <antti@apple.com> 2 3 Render tree construction is O(N^2) in number of siblings 4 https://bugs.webkit.org/show_bug.cgi?id=129065 5 6 Reviewed by Darin Adler. 7 8 * perf/sibling-renderer-On2-expected.txt: Added. 9 * perf/sibling-renderer-On2.html: Added. 10 11 The test doesn't use magnitude-perf.js as this requires a relatively long-running test function and 12 it seemed unsuitable for that. 13 1 14 2014-03-26 Zoltan Horvath <zoltan@webkit.org> 2 15 -
trunk/Source/WebCore/ChangeLog
r166302 r166303 1 2014-03-26 Antti Koivisto <antti@apple.com> 2 3 Render tree construction is O(N^2) in number of siblings 4 https://bugs.webkit.org/show_bug.cgi?id=129065 5 6 Reviewed by Darin Adler. 7 8 When adding a new renderer to the tree we would search for the correct render tree 9 position by traversing DOM children forward to find something that already has a renderer. 10 In common case there is no such renderer. This would be repeated for each inserted renderer 11 leading to O(n^2) in respect to child node count. 12 13 This patch caches the computed render tree insertion position and passes it to siblings. 14 Until the cached position is reached it can be used for all new renderers. 15 16 Test: perf/sibling-renderer-On2.html 17 18 * style/StyleResolveTree.cpp: 19 (WebCore::Style::RenderTreePosition::parent): 20 (WebCore::Style::RenderTreePosition::RenderTreePosition): 21 (WebCore::Style::RenderTreePosition::canInsert): 22 (WebCore::Style::RenderTreePosition::insert): 23 (WebCore::Style::RenderTreePosition::computeNextSibling): 24 (WebCore::Style::RenderTreePosition::invalidateNextSibling): 25 (WebCore::Style::styleForElement): 26 (WebCore::Style::elementInsideRegionNeedsRenderer): 27 (WebCore::Style::createRendererIfNeeded): 28 (WebCore::Style::createTextRendererIfNeeded): 29 (WebCore::Style::attachTextRenderer): 30 (WebCore::Style::updateTextRendererAfterContentChange): 31 (WebCore::Style::attachChildren): 32 (WebCore::Style::attachDistributedChildren): 33 (WebCore::Style::attachShadowRoot): 34 (WebCore::Style::attachBeforeOrAfterPseudoElementIfNeeded): 35 (WebCore::Style::attachRenderTree): 36 (WebCore::Style::resolveLocal): 37 (WebCore::Style::resolveTextNode): 38 (WebCore::Style::resolveShadowTree): 39 (WebCore::Style::updateBeforeOrAfterPseudoElement): 40 (WebCore::Style::resolveTree): 41 1 42 2014-03-26 Commit Queue <commit-queue@webkit.org> 2 43 -
trunk/Source/WebCore/style/StyleResolveTree.cpp
r166173 r166303 5 5 * (C) 2001 Dirk Mueller (mueller@kde.org) 6 6 * (C) 2007 David Smith (catfish.man@gmail.com) 7 * Copyright (C) 2004 , 2005, 2006, 2007, 2008, 2009, 2010, 2012, 2013Apple Inc. All rights reserved.7 * Copyright (C) 2004-2010, 2012-2014 Apple Inc. All rights reserved. 8 8 * (C) 2007 Eric Seidel (eric@webkit.org) 9 9 * … … 62 62 enum DetachType { NormalDetach, ReattachDetach }; 63 63 64 static void attachRenderTree(Element&, ContainerNode& renderingParentNode, PassRefPtr<RenderStyle>); 65 static void attachTextRenderer(Text&, ContainerNode& renderingParentNode); 64 class RenderTreePosition { 65 public: 66 RenderTreePosition(RenderElement* parent); 67 RenderTreePosition(RenderElement* parent, RenderObject* nextSibling); 68 69 RenderElement* parent() { return m_parent; } 70 71 void insert(RenderObject&); 72 bool canInsert(RenderElement&) const; 73 bool canInsert(RenderText&) const; 74 75 void computeNextSibling(const Node&, ContainerNode& renderingParentNode); 76 void invalidateNextSibling(const RenderObject&); 77 78 private: 79 RenderElement* m_parent; 80 RenderObject* m_nextSibling; 81 bool m_hasValidNextSibling; 82 #if !ASSERT_DISABLED 83 unsigned m_assertionLimitCounter; 84 #endif 85 }; 86 87 static void attachRenderTree(Element&, ContainerNode& renderingParentNode, RenderTreePosition&, PassRefPtr<RenderStyle>); 88 static void attachTextRenderer(Text&, ContainerNode& renderingParentNode, RenderTreePosition&); 66 89 static void detachRenderTree(Element&, DetachType); 67 static void resolveTextNode(Text&, ContainerNode& renderingParentNode );68 static void resolveTree(Element&, ContainerNode& renderingParentNode, Change);90 static void resolveTextNode(Text&, ContainerNode& renderingParentNode, RenderTreePosition&); 91 static void resolveTree(Element&, ContainerNode& renderingParentNode, RenderTreePosition&, Change); 69 92 70 93 Change determineChange(const RenderStyle* s1, const RenderStyle* s2) … … 152 175 } 153 176 177 RenderTreePosition::RenderTreePosition(RenderElement* parent) 178 : m_parent(parent) 179 , m_nextSibling(nullptr) 180 , m_hasValidNextSibling(false) 181 #if !ASSERT_DISABLED 182 , m_assertionLimitCounter(0) 183 #endif 184 { 185 } 186 187 RenderTreePosition::RenderTreePosition(RenderElement* parent, RenderObject* nextSibling) 188 : m_parent(parent) 189 , m_nextSibling(nextSibling) 190 , m_hasValidNextSibling(true) 191 #if !ASSERT_DISABLED 192 , m_assertionLimitCounter(0) 193 #endif 194 { 195 } 196 197 bool RenderTreePosition::canInsert(RenderElement& renderer) const 198 { 199 ASSERT(m_parent); 200 ASSERT(!renderer.parent()); 201 return m_parent->isChildAllowed(renderer, renderer.style()); 202 } 203 204 bool RenderTreePosition::canInsert(RenderText& renderer) const 205 { 206 ASSERT(m_parent); 207 ASSERT(!renderer.parent()); 208 return m_parent->isChildAllowed(renderer, m_parent->style()); 209 } 210 211 void RenderTreePosition::insert(RenderObject& renderer) 212 { 213 ASSERT(m_parent); 214 ASSERT(m_hasValidNextSibling); 215 m_parent->addChild(&renderer, m_nextSibling); 216 } 217 218 void RenderTreePosition::computeNextSibling(const Node& node, ContainerNode& renderingParentNode) 219 { 220 ASSERT(!node.renderer()); 221 if (m_hasValidNextSibling) { 222 // Stop validating at some point so the assert doesn't make us O(N^2) on debug builds. 223 ASSERT(++m_assertionLimitCounter > 20 || nextSiblingRenderer(node, renderingParentNode) == m_nextSibling); 224 return; 225 } 226 m_nextSibling = nextSiblingRenderer(node, renderingParentNode); 227 m_hasValidNextSibling = true; 228 } 229 230 void RenderTreePosition::invalidateNextSibling(const RenderObject& siblingRenderer) 231 { 232 if (!m_hasValidNextSibling) 233 return; 234 if (m_nextSibling == &siblingRenderer) 235 m_hasValidNextSibling = false; 236 } 237 154 238 static bool shouldCreateRenderer(const Element& element, const ContainerNode& renderingParent) 155 239 { … … 166 250 } 167 251 168 static PassRef<RenderStyle> styleForElement(Element& element, RenderStyle& parentStyle) 169 { 170 if (element.hasCustomStyleResolveCallbacks()) { 171 if (RefPtr<RenderStyle> style = element.customStyleForRenderer(parentStyle)) 252 static PassRef<RenderStyle> styleForElement(Element& element, ContainerNode& renderingParentNode) 253 { 254 RenderStyle* parentStyle = renderingParentNode.renderStyle(); 255 if (element.hasCustomStyleResolveCallbacks() && parentStyle) { 256 if (RefPtr<RenderStyle> style = element.customStyleForRenderer(*parentStyle)) 172 257 return style.releaseNonNull(); 173 258 } 174 return element.document().ensureStyleResolver().styleForElement(&element, &parentStyle);259 return element.document().ensureStyleResolver().styleForElement(&element, parentStyle); 175 260 } 176 261 177 262 // Check the specific case of elements that are children of regions but are flowed into a flow thread themselves. 178 static bool elementInsideRegionNeedsRenderer(Element& element, constContainerNode& renderingParentNode, RefPtr<RenderStyle>& style)263 static bool elementInsideRegionNeedsRenderer(Element& element, ContainerNode& renderingParentNode, RefPtr<RenderStyle>& style) 179 264 { 180 265 #if ENABLE(CSS_REGIONS) … … 188 273 189 274 if (!style) 190 style = styleForElement(element, *renderingParentNode.renderStyle());275 style = styleForElement(element, renderingParentNode); 191 276 192 277 // Children of this element will only be allowed to be flowed into other flow-threads if display is NOT none. … … 216 301 #endif 217 302 218 static void createRendererIfNeeded(Element& element, ContainerNode& renderingParentNode, PassRefPtr<RenderStyle> resolvedStyle)303 static void createRendererIfNeeded(Element& element, ContainerNode& renderingParentNode, RenderTreePosition& renderTreePosition, PassRefPtr<RenderStyle> resolvedStyle) 219 304 { 220 305 ASSERT(!element.renderer()); … … 228 313 229 314 if (!style) 230 style = styleForElement(element, *renderingParentNode.renderStyle());315 style = styleForElement(element, renderingParentNode); 231 316 232 317 RenderNamedFlowThread* parentFlowRenderer = 0; … … 238 323 return; 239 324 240 RenderElement* parentRenderer; 241 RenderObject* nextRenderer; 242 if (parentFlowRenderer) { 243 parentRenderer = parentFlowRenderer; 244 nextRenderer = parentFlowRenderer->nextRendererForElement(element); 245 } else { 246 // FIXME: Make this path Element only, handle the root special case separately. 247 parentRenderer = renderingParentNode.renderer(); 248 nextRenderer = nextSiblingRenderer(element, renderingParentNode); 249 } 325 renderTreePosition.computeNextSibling(element, renderingParentNode); 326 327 RenderTreePosition insertionPosition = parentFlowRenderer 328 ? RenderTreePosition(parentFlowRenderer, parentFlowRenderer->nextRendererForElement(element)) 329 : renderTreePosition; 250 330 251 331 RenderElement* newRenderer = element.createElementRenderer(style.releaseNonNull()).leakPtr(); 252 332 if (!newRenderer) 253 333 return; 254 if (! parentRenderer->isChildAllowed(*newRenderer, newRenderer->style())) {334 if (!insertionPosition.canInsert(*newRenderer)) { 255 335 newRenderer->destroy(); 256 336 return; … … 259 339 // Make sure the RenderObject already knows it is going to be added to a RenderFlowThread before we set the style 260 340 // for the first time. Otherwise code using inRenderFlowThread() in the styleWillChange and styleDidChange will fail. 261 newRenderer->setFlowThreadState( parentRenderer->flowThreadState());341 newRenderer->setFlowThreadState(insertionPosition.parent()->flowThreadState()); 262 342 263 343 // Code below updateAnimations() can depend on Element::renderer() already being set. … … 273 353 Document& document = element.document(); 274 354 if (document.webkitIsFullScreen() && document.webkitCurrentFullScreenElement() == &element) { 275 newRenderer = RenderFullScreen::wrapRenderer(newRenderer, parentRenderer, document);355 newRenderer = RenderFullScreen::wrapRenderer(newRenderer, insertionPosition.parent(), document); 276 356 if (!newRenderer) 277 357 return; … … 279 359 #endif 280 360 // Note: Adding newRenderer instead of renderer(). renderer() may be a child of newRenderer. 281 parentRenderer->addChild(newRenderer, nextRenderer);361 insertionPosition.insert(*newRenderer); 282 362 } 283 363 … … 368 448 } 369 449 370 static void createTextRendererIfNeeded(Text& textNode, ContainerNode& renderingParentNode )450 static void createTextRendererIfNeeded(Text& textNode, ContainerNode& renderingParentNode, RenderTreePosition& renderTreePosition) 371 451 { 372 452 ASSERT(!textNode.renderer()); … … 374 454 if (!textRendererIsNeeded(textNode, renderingParentNode)) 375 455 return; 376 RenderElement& parentRenderer = *renderingParentNode.renderer(); 377 const auto& style = parentRenderer.style(); 378 379 auto newRenderer = textNode.createTextRenderer(style); 456 457 auto newRenderer = textNode.createTextRenderer(*renderingParentNode.renderStyle()); 380 458 ASSERT(newRenderer); 381 459 382 if (!parentRenderer.isChildAllowed(*newRenderer, style)) 460 renderTreePosition.computeNextSibling(textNode, renderingParentNode); 461 462 if (!renderTreePosition.canInsert(*newRenderer)) 383 463 return; 384 464 385 465 // Make sure the RenderObject already knows it is going to be added to a RenderFlowThread before we set the style 386 466 // for the first time. Otherwise code using inRenderFlowThread() in the styleWillChange and styleDidChange will fail. 387 newRenderer->setFlowThreadState(parentRenderer.flowThreadState()); 388 389 RenderObject* nextRenderer = nextSiblingRenderer(textNode, renderingParentNode); 467 newRenderer->setFlowThreadState(renderTreePosition.parent()->flowThreadState()); 468 390 469 textNode.setRenderer(newRenderer.get()); 391 470 // Parent takes care of the animations, no need to call setAnimatableStyle. 392 parentRenderer.addChild(newRenderer.leakPtr(), nextRenderer);393 } 394 395 void attachTextRenderer(Text& textNode, ContainerNode& renderingParent )396 { 397 createTextRendererIfNeeded(textNode, renderingParent );471 renderTreePosition.insert(*newRenderer.leakPtr()); 472 } 473 474 void attachTextRenderer(Text& textNode, ContainerNode& renderingParentNode, RenderTreePosition& renderTreePosition) 475 { 476 createTextRendererIfNeeded(textNode, renderingParentNode, renderTreePosition); 398 477 399 478 textNode.clearNeedsStyleRecalc(); … … 414 493 415 494 bool hadRenderer = textNode.renderer(); 416 resolveTextNode(textNode, *renderingParentNode); 495 496 RenderTreePosition renderTreePosition(renderingParentNode->renderer()); 497 resolveTextNode(textNode, *renderingParentNode, renderTreePosition); 417 498 418 499 if (hadRenderer && textNode.renderer()) … … 420 501 } 421 502 422 static void attachChildren(ContainerNode& current, ContainerNode& renderingParentNode )503 static void attachChildren(ContainerNode& current, ContainerNode& renderingParentNode, RenderTreePosition& renderTreePosition) 423 504 { 424 505 for (Node* child = current.firstChild(); child; child = child->nextSibling()) { 425 506 ASSERT((!child->renderer() || child->inNamedFlow()) || current.shadowRoot()); 426 if (child->renderer()) 507 if (child->renderer()) { 508 renderTreePosition.invalidateNextSibling(*child->renderer()); 427 509 continue; 510 } 428 511 if (child->isTextNode()) { 429 attachTextRenderer(*toText(child), renderingParentNode );512 attachTextRenderer(*toText(child), renderingParentNode, renderTreePosition); 430 513 continue; 431 514 } 432 515 if (child->isElementNode()) 433 attachRenderTree(*toElement(child), renderingParentNode, nullptr);434 } 435 } 436 437 static void attachDistributedChildren(InsertionPoint& insertionPoint, ContainerNode& renderingParentNode )516 attachRenderTree(*toElement(child), renderingParentNode, renderTreePosition, nullptr); 517 } 518 } 519 520 static void attachDistributedChildren(InsertionPoint& insertionPoint, ContainerNode& renderingParentNode, RenderTreePosition& renderTreePosition) 438 521 { 439 522 if (ShadowRoot* shadowRoot = insertionPoint.containingShadowRoot()) … … 441 524 442 525 for (Node* current = insertionPoint.firstDistributed(); current; current = insertionPoint.nextDistributedTo(current)) { 526 if (current->renderer()) 527 renderTreePosition.invalidateNextSibling(*current->renderer()); 443 528 if (current->isTextNode()) { 444 529 if (current->renderer()) 445 530 continue; 446 attachTextRenderer(*toText(current), renderingParentNode );531 attachTextRenderer(*toText(current), renderingParentNode, renderTreePosition); 447 532 continue; 448 533 } … … 451 536 if (currentElement.renderer()) 452 537 detachRenderTree(currentElement); 453 attachRenderTree(currentElement, renderingParentNode, nullptr);538 attachRenderTree(currentElement, renderingParentNode, renderTreePosition, nullptr); 454 539 } 455 540 } 456 541 // Use actual children as fallback content. 457 542 if (!insertionPoint.hasDistribution()) 458 attachChildren(insertionPoint, renderingParentNode );543 attachChildren(insertionPoint, renderingParentNode, renderTreePosition); 459 544 } 460 545 461 546 static void attachShadowRoot(ShadowRoot& shadowRoot) 462 547 { 463 attachChildren(shadowRoot, *shadowRoot.hostElement()); 548 ASSERT(shadowRoot.hostElement()); 549 550 RenderTreePosition renderTreePosition(shadowRoot.hostElement()->renderer()); 551 attachChildren(shadowRoot, *shadowRoot.hostElement(), renderTreePosition); 464 552 465 553 shadowRoot.clearNeedsStyleRecalc(); … … 508 596 } 509 597 510 static void attachBeforeOrAfterPseudoElementIfNeeded(Element& current, PseudoId pseudoId )598 static void attachBeforeOrAfterPseudoElementIfNeeded(Element& current, PseudoId pseudoId, RenderTreePosition& renderTreePosition) 511 599 { 512 600 if (!needsPseudoElement(current, pseudoId)) … … 514 602 RefPtr<PseudoElement> pseudoElement = PseudoElement::create(current, pseudoId); 515 603 setBeforeOrAfterPseudoElement(current, pseudoElement, pseudoId); 516 attachRenderTree(*pseudoElement, current, nullptr);517 } 518 519 static void attachRenderTree(Element& current, ContainerNode& renderingParentNode, PassRefPtr<RenderStyle> resolvedStyle)604 attachRenderTree(*pseudoElement, current, renderTreePosition, nullptr); 605 } 606 607 static void attachRenderTree(Element& current, ContainerNode& renderingParentNode, RenderTreePosition& renderTreePosition, PassRefPtr<RenderStyle> resolvedStyle) 520 608 { 521 609 PostResolutionCallbackDisabler callbackDisabler(current.document()); … … 525 613 current.willAttachRenderers(); 526 614 527 createRendererIfNeeded(current, renderingParentNode, re solvedStyle);615 createRendererIfNeeded(current, renderingParentNode, renderTreePosition, resolvedStyle); 528 616 529 617 if (current.parentElement() && current.parentElement()->isInCanvasSubtree()) 530 618 current.setIsInCanvasSubtree(true); 531 619 532 attachBeforeOrAfterPseudoElementIfNeeded(current, BEFORE);533 534 620 StyleResolverParentPusher parentPusher(¤t); 621 622 RenderTreePosition childRenderTreePosition(current.renderer()); 623 attachBeforeOrAfterPseudoElementIfNeeded(current, BEFORE, childRenderTreePosition); 535 624 536 625 if (ShadowRoot* shadowRoot = current.shadowRoot()) { … … 541 630 542 631 if (isInsertionPoint(current)) 543 attachDistributedChildren(toInsertionPoint(current), renderingParentNode );632 attachDistributedChildren(toInsertionPoint(current), renderingParentNode, renderTreePosition); 544 633 else 545 attachChildren(current, current );634 attachChildren(current, current, childRenderTreePosition); 546 635 547 636 current.clearNeedsStyleRecalc(); … … 551 640 cache->updateCacheAfterNodeIsAttached(¤t); 552 641 553 attachBeforeOrAfterPseudoElementIfNeeded(current, AFTER );642 attachBeforeOrAfterPseudoElementIfNeeded(current, AFTER, childRenderTreePosition); 554 643 555 644 current.updateFocusAppearanceAfterAttachIfNeeded(); … … 653 742 } 654 743 655 static Change resolveLocal(Element& current, ContainerNode& renderingParentNode, Change inheritedChange)744 static Change resolveLocal(Element& current, ContainerNode& renderingParentNode, RenderTreePosition& renderTreePosition, Change inheritedChange) 656 745 { 657 746 Change localChange = Detach; … … 661 750 Document& document = current.document(); 662 751 if (currentStyle && current.styleChangeType() != ReconstructRenderTree) { 663 newStyle = styleForElement(current, *renderingParentNode.renderStyle());752 newStyle = styleForElement(current, renderingParentNode); 664 753 localChange = determineChange(currentStyle.get(), newStyle.get()); 665 754 } … … 667 756 if (current.renderer() || current.inNamedFlow()) 668 757 detachRenderTree(current, ReattachDetach); 669 attachRenderTree(current, renderingParentNode, newStyle.release());758 attachRenderTree(current, renderingParentNode, renderTreePosition, newStyle.release()); 670 759 invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded(current); 671 760 … … 699 788 } 700 789 701 void resolveTextNode(Text& text, ContainerNode& renderingParentNode )790 void resolveTextNode(Text& text, ContainerNode& renderingParentNode, RenderTreePosition& renderTreePosition) 702 791 { 703 792 text.clearNeedsStyleRecalc(); … … 714 803 if (!needsRenderer) 715 804 return; 716 attachTextRenderer(text, renderingParentNode );805 attachTextRenderer(text, renderingParentNode, renderTreePosition); 717 806 invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded(text); 718 807 } 719 808 720 static void resolveShadowTree(ShadowRoot& shadowRoot, Style::Change change) 721 { 809 static void resolveShadowTree(ShadowRoot& shadowRoot, Element& host, Style::Change change) 810 { 811 ASSERT(shadowRoot.hostElement() == &host); 812 RenderTreePosition renderTreePosition(host.renderer()); 722 813 for (Node* child = shadowRoot.firstChild(); child; child = child->nextSibling()) { 814 if (child->renderer()) 815 renderTreePosition.invalidateNextSibling(*child->renderer()); 723 816 if (child->isTextNode() && child->needsStyleRecalc()) { 724 resolveTextNode(*toText(child), *shadowRoot.hostElement());817 resolveTextNode(*toText(child), host, renderTreePosition); 725 818 continue; 726 819 } 727 820 if (child->isElementNode()) 728 resolveTree(*toElement(child), *shadowRoot.hostElement(), change);821 resolveTree(*toElement(child), host, renderTreePosition, change); 729 822 } 730 823 … … 733 826 } 734 827 735 static void updateBeforeOrAfterPseudoElement(Element& current, Change change, PseudoId pseudoId )828 static void updateBeforeOrAfterPseudoElement(Element& current, Change change, PseudoId pseudoId, RenderTreePosition& renderTreePosition) 736 829 { 737 830 if (PseudoElement* existingPseudoElement = beforeOrAfterPseudoElement(current, pseudoId)) { 738 831 if (needsPseudoElement(current, pseudoId)) 739 resolveTree(*existingPseudoElement, current, current.needsStyleRecalc() ? Force : change);832 resolveTree(*existingPseudoElement, current, renderTreePosition, current.needsStyleRecalc() ? Force : change); 740 833 else 741 834 clearBeforeOrAfterPseudoElement(current, pseudoId); 742 835 return; 743 836 } 744 attachBeforeOrAfterPseudoElementIfNeeded(current, pseudoId );837 attachBeforeOrAfterPseudoElementIfNeeded(current, pseudoId, renderTreePosition); 745 838 } 746 839 … … 797 890 #endif // PLATFORM(IOS) 798 891 799 void resolveTree(Element& current, ContainerNode& renderingParentNode, Change change)892 void resolveTree(Element& current, ContainerNode& renderingParentNode, RenderTreePosition& renderTreePosition, Change change) 800 893 { 801 894 ASSERT(change != Detach); … … 818 911 819 912 if (hasParentStyle && (change >= Inherit || current.needsStyleRecalc())) 820 change = resolveLocal(current, renderingParentNode, change);913 change = resolveLocal(current, renderingParentNode, renderTreePosition, change); 821 914 822 915 if (change != Detach) { … … 826 919 if (change >= Inherit || shadowRoot->childNeedsStyleRecalc() || shadowRoot->needsStyleRecalc()) { 827 920 parentPusher.push(); 828 resolveShadowTree(*shadowRoot, c hange);921 resolveShadowTree(*shadowRoot, current, change); 829 922 } 830 923 } 831 924 832 updateBeforeOrAfterPseudoElement(current, change, BEFORE); 925 RenderTreePosition childRenderTreePosition(current.renderer()); 926 updateBeforeOrAfterPseudoElement(current, change, BEFORE, childRenderTreePosition); 833 927 834 928 // FIXME: This check is good enough for :hover + foo, but it is not good enough for :hover + foo + bar. … … 838 932 bool forceCheckOfAnyElementSibling = false; 839 933 for (Node* child = current.firstChild(); child; child = child->nextSibling()) { 934 if (child->renderer()) 935 childRenderTreePosition.invalidateNextSibling(*child->renderer()); 840 936 if (child->isTextNode() && child->needsStyleRecalc()) { 841 resolveTextNode(*toText(child), current );937 resolveTextNode(*toText(child), current, childRenderTreePosition); 842 938 continue; 843 939 } … … 850 946 if (change >= Inherit || childElement->childNeedsStyleRecalc() || childElement->needsStyleRecalc()) { 851 947 parentPusher.push(); 852 resolveTree(*childElement, current, ch ange);948 resolveTree(*childElement, current, childRenderTreePosition, change); 853 949 } 854 950 forceCheckOfNextElementSibling = childRulesChanged && hasDirectAdjacentRules; … … 856 952 } 857 953 858 updateBeforeOrAfterPseudoElement(current, change, AFTER );954 updateBeforeOrAfterPseudoElement(current, change, AFTER, childRenderTreePosition); 859 955 } 860 956 … … 891 987 if (change < Inherit && !documentElement->childNeedsStyleRecalc() && !documentElement->needsStyleRecalc()) 892 988 return; 893 resolveTree(*documentElement, document, change); 989 RenderTreePosition renderTreePosition(document.renderView()); 990 resolveTree(*documentElement, document, renderTreePosition, change); 894 991 } 895 992
Note:
See TracChangeset
for help on using the changeset viewer.